[LIB] LV_EX - update on 2016-04-28

Post your working scripts, libraries and tools
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

[LIB] LV_EX - update on 2016-04-28

03 Jan 2014, 05:15

Additional functions for GUI ListView controls.

Primarily [CLASS] version released on the old forum -> board/topic/80686-class-guilistviewex-added-functions-for-gui-listviews/.

Well, this is a !!! LIB !!! version of my originally released CLASS_GuiListViewEx. I added some more functions, most of them are intended to be used primarily in Report view.
ChangeLog
LV_EX.png
I only did some quick testing, so you might find some issues or bugs. If so, report them here, please.

Code: Select all

; ======================================================================================================================
; Namespace:      LV_EX
; Function:       Some additional functions to use with AHK ListView controls.
; Tested with:    AHK 1.1.20.03 (A32/U32/U64)
; Tested on:      Win 8.1 (x64)
; Changelog:
;     1.1.01.00/2016-04-28(just me     -  added LV_EX_GroupGetState contributed by Pulover.
;     1.1.00.00/2015-03-13/just me     -  added basic tile view support (suggested by toralf),
;                                         added basic (XP compatible) group view support,
;                                         revised code and made some minor changes.
;     1.0.00.00/2013-12-30/just me     -  initial release.
; Notes:
;     In terms of Microsoft
;        Item     stands for the whole row or the first column of the row
;        SubItem  stands for the second to last column of a row
;     All functions require the handle of the ListView (HWND). You get this handle using the 'Hwnd' option when
;     creating the control per 'Gui, Add, HwndHwndOfLV ...' or using 'GuiControlGet, HwndOfLV, Hwnd, MyListViewVar'
;     after control creation.
; Credits:
;     LV_EX tile view functions:
;        Initial idea by segalion (old forum: /board/topic/80754-listview-with-multiline-in-report-mode-help/)
;        based on code from Fabio Lucarelli (http://users.skynet.be/oleole/ListView_Tiles.htm).
; ======================================================================================================================
; This software is provided 'as-is', without any express or implied warranty.
; In no event will the authors be held liable for any damages arising from the use of this software.
; ======================================================================================================================
; ======================================================================================================================
; LV_EX_CalcViewSize - Calculates the approximate width and height required to display a given number of items.
; ======================================================================================================================
LV_EX_CalcViewSize(HLV, Rows := 0) {
   ; LVM_APPROXIMATEVIEWRECT = 0x1040 -> http://msdn.microsoft.com/en-us/library/bb774883(v=vs.85).aspx
   SendMessage, 0x1040, % (Rows - 1), 0, , % "ahk_id " . HLV
   Return {W: (ErrorLevel & 0xFFFF), H: (ErrorLevel >> 16) & 0xFFFF}
}
; ======================================================================================================================
; LV_EX_EnableGroupView - Enables or disables whether the items in a list-view control display as a group.
; ======================================================================================================================
LV_EX_EnableGroupView(HLV, Enable := True) {
   ; LVM_ENABLEGROUPVIEW = 0x109D -> msdn.microsoft.com/en-us/library/bb774900(v=vs.85).aspx
   SendMessage, 0x109D, % (!!Enable), 0, , % "ahk_id " . HLV
   Return (ErrorLevel >> 31) ? 0 : 1
}
; ======================================================================================================================
; LV_EX_FindString - Searches the first column for an item containing the specified string.
; ======================================================================================================================
LV_EX_FindString(HLV, Str, Start := 0, Partial := False) {
   ; LVM_FINDITEM -> http://msdn.microsoft.com/en-us/library/bb774903(v=vs.85).aspx
   Static LVM_FINDITEM := A_IsUnicode ? 0x1053 : 0x100D ; LVM_FINDITEMW : LVM_FINDITEMA
   Static LVFISize := 40
   VarSetCapacity(LVFI, LVFISize, 0) ; LVFINDINFO
   Flags := 0x0002 ; LVFI_STRING
   If (Partial)
      Flags |= 0x0008 ; LVFI_PARTIAL
   NumPut(Flags, LVFI, 0, "UInt")
   NumPut(&Str,  LVFI, A_PtrSize, "Ptr")
   SendMessage, % LVM_FINDITEM, % (Start - 1), % &LVFI, , % "ahk_id " . HLV
   Return (ErrorLevel > 0x7FFFFFFF ? 0 : ErrorLevel + 1)
}
; ======================================================================================================================
; LV_EX_FindStringEx - Searches all columns or the specified column for a subitem containing the specified string.
; ======================================================================================================================
LV_EX_FindStringEx(HLV, Str, Column := 0, Start := 0, Partial := False) {
   Len := StrLen(Str)
   Row := Col := 0
   ControlGet, ItemList, List, , , % "ahk_id " . HLV
   Loop, Parse, ItemList, `n
   {
      If (A_Index > Start) {
         Row := A_Index
         Columns := StrSplit(A_LoopField, "`t")
         If (Column + 0) > 0 {
            If (Partial) {
               If (SubStr(Columns[Column], 1, Len) = Str)
                  Col := Column
            }
            Else {
               If (Columns[Column] = Str)
                  Col := Column
            }
         }
         Else {
            For Index, ColumnText In Columns {
               If (Partial) {
                  If (SubStr(ColumnText, 1, Len) = Str)
                     Col := Index
               }
               Else {
                  If (ColumnText = Str)
                     Col := Index
               }
            } Until (Col > 0)
         }
      }
   } Until (Col > 0)
   Return (Col > 0) ? {Row: Row, Col: Column} : 0
}
; ======================================================================================================================
; LV_EX_GetColumnOrder - Gets the current left-to-right order of columns in a list-view control.
; ======================================================================================================================
LV_EX_GetColumnOrder(HLV) {
   ; LVM_GETCOLUMNORDERARRAY = 0x103B -> http://msdn.microsoft.com/en-us/library/bb774913(v=vs.85).aspx
   SendMessage, 0x1200, 0, 0, , % "ahk_id " . LV_EX_GetHeader(HLV) ; HDM_GETITEMCOUNT
   If (ErrorLevel > 0x7FFFFFFF)
      Return False
   Cols := ErrorLevel
   VarSetCapacity(COA, Cols * 4, 0)
   SendMessage, 0x103B, % Cols, % &COA, , % "ahk_id " . HLV
   If (ErrorLevel = 0) || !(ErrorLevel + 0)
      Return False
   ColArray := []
   Loop, %Cols%
      ColArray[A_Index] := NumGet(COA, 4 * (A_Index - 1), "Int") + 1
   Return ColArray
}
; ======================================================================================================================
; LV_EX_GetColumnWidth - Gets the width of a column in report or list view.
; ======================================================================================================================
LV_EX_GetColumnWidth(HLV, Column) {
   ; LVM_GETCOLUMNWIDTH = 0x101D -> http://msdn.microsoft.com/en-us/library/bb774915(v=vs.85).aspx
   SendMessage, 0x101D, % (Column - 1), 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GetExtendedStyle - Gets the extended styles that are currently in use for a given list-view control.
; ======================================================================================================================
LV_EX_GetExtendedStyle(HLV) {
   ; LVM_GETEXTENDEDLISTVIEWSTYLE = 0x1037 -> http://msdn.microsoft.com/en-us/library/bb774923(v=vs.85).aspx
   SendMessage, 0x1037, 0, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GetGroup - Gets the ID of the group the list-view item belongs to.
; ======================================================================================================================
LV_EX_GetGroup(HLV, Row) {
   ; LVM_GETITEMA = 0x1005 -> http://msdn.microsoft.com/en-us/library/bb774953(v=vs.85).aspx
   Static OffGroupID := 28 + (A_PtrSize * 3)
   LV_EX_LVITEM(LVITEM, 0x00000100, Row) ; LVIF_GROUPID
   SendMessage, 0x1005, 0, % &LVITEM, , % "ahk_id " . HLV
   Return NumGet(LVITEM, OffGroupID, "UPtr")
}
; ======================================================================================================================
; LV_EX_GetHeader - Retrieves the handle of the header control used by the list-view control.
; ======================================================================================================================
LV_EX_GetHeader(HLV) {
   ; LVM_GETHEADER = 0x101F -> http://msdn.microsoft.com/en-us/library/bb774937(v=vs.85).aspx
   SendMessage, 0x101F, 0, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GetIconSpacing - Determines the spacing between icons in the icon view.
; ======================================================================================================================
LV_EX_GetIconSpacing(HLV, ByRef CX, BYREF CY) {
   ; LVM_GETITEMSPACING = 0x1033 -> http://msdn.microsoft.com/en-us/library/bb761051(v=vs.85).aspx
   CX := CY := 0
   SendMessage, 0x1033, 0, 0, , % "ahk_id " . HLV
   CX := ErrorLevel & 0xFFFF, CY := ErrorLevel >> 16
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GetItemParam - Retrieves the value of the item's lParam field.
; ======================================================================================================================
LV_EX_GetItemParam(HLV, Row) {
   ; LVM_GETITEM -> http://msdn.microsoft.com/en-us/library/bb774953(v=vs.85).aspx
   Static LVM_GETITEM := A_IsUnicode ? 0x104B : 0x1005 ; LVM_GETITEMW : LVM_GETITEMA
   Static OffParam := 24 + (A_PtrSize * 2)
   LV_EX_LVITEM(LVITEM, 0x00000004, Row) ; LVIF_PARAM
   SendMessage, % LVM_GETITEM, 0, % &LVITEM, , % "ahk_id " . HLV
   Return NumGet(LVITEM, OffParam, "UPtr")
}
; ======================================================================================================================
; LV_EX_GetItemRect - Retrieves the bounding rectangle for all or part of an item in the current view.
; ======================================================================================================================
LV_EX_GetItemRect(HLV, Row := 1, LVIR := 0, Byref RECT := "") {
   ; LVM_GETITEMRECT = 0x100E -> http://msdn.microsoft.com/en-us/library/bb761049(v=vs.85).aspx
   VarSetCapacity(RECT, 16, 0)
   NumPut(LVIR, RECT, 0, "Int")
   SendMessage, 0x100E, % (Row - 1), % &RECT, , % "ahk_id " . HLV
   If (ErrorLevel = 0)
      Return False
   Result := {}
   Result.X := NumGet(RECT,  0, "Int")
   Result.Y := NumGet(RECT,  4, "Int")
   Result.R := NumGet(RECT,  8, "Int")
   Result.B := NumGet(RECT, 12, "Int")
   Result.W := Result.R - Result.X
   Result.H := Result.B - Result.Y
   Return Result
}
; ======================================================================================================================
; LV_EX_GetItemState - Retrieves the state of a list-view item.
; ======================================================================================================================
LV_EX_GetItemState(HLV, Row) {
   ; LVM_GETITEMSTATE = 0x102C -> http://msdn.microsoft.com/en-us/library/bb761053(v=vs.85).aspx
   Static LVIS := {Cut: 0x04, DropHilited: 0x08, Focused: 0x01, Selected: 0x02, Checked: 0x2000}
   SendMessage, 0x102C, % (Row - 1), 0xFFFF, , % "ahk_id " . HLV ; all states
   States := ErrorLevel
   Result := {}
   For Key, Value In LVIS
      Result[Key] := States & Value
   Return Result
}
; ======================================================================================================================
; LV_EX_GetRowHeight - Gets the height of the specified row.
; ======================================================================================================================
LV_EX_GetRowHeight(HLV, Row := 1) {
   Return LV_EX_GetItemRect(HLV, Row).H
}
; ======================================================================================================================
; LV_EX_GetRowsPerPage - Calculates the number of items that can fit vertically in the visible area of a list-view
;                        control when in list or report view. Only fully visible items are counted.
; ======================================================================================================================
LV_EX_GetRowsPerPage(HLV) {
   ; LVM_GETCOUNTPERPAGE = 0x1028 -> http://msdn.microsoft.com/en-us/library/bb774917(v=vs.85).aspx
   SendMessage, 0x1028, 0, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GetSubItemRect - Retrieves information about the bounding rectangle for a subitem in a list-view control.
; ======================================================================================================================
LV_EX_GetSubItemRect(HLV, Column, Row := 1, LVIR := 0, ByRef RECT := "") {
   ; LVM_GETSUBITEMRECT = 0x1038 -> http://msdn.microsoft.com/en-us/library/bb761075(v=vs.85).aspx
   VarSetCapacity(RECT, 16, 0)
   NumPut(LVIR, RECT, 0, "Int")
   NumPut(Column - 1, RECT, 4, "Int")
   SendMessage, 0x1038, % (Row - 1), % &RECT, , % "ahk_id " . HLV
   If (ErrorLevel = 0)
      Return False
   If (Column = 1) && ((LVIR = 0) || (LVIR = 3))
      NumPut(NumGet(RECT, 0, "Int") + LV_EX_GetColumnWidth(HLV, 1), RECT, 8, "Int")
   Result := {}
   Result.X := NumGet(RECT,  0, "Int"), Result.Y := NumGet(RECT,  4, "Int")
   Result.R := NumGet(RECT,  8, "Int"), Result.B := NumGet(RECT, 12, "Int")
   Result.W := Result.R - Result.X,     Result.H := Result.B - Result.Y
   Return Result
}
; ======================================================================================================================
; LV_EX_GetSubItemText - Retrieves the text of the specified item and subitem.
; ======================================================================================================================
LV_EX_GetSubItemText(HLV, Row, Column := 1, MaxChars := 257) {
   ; LVM_GETITEMTEXT -> http://msdn.microsoft.com/en-us/library/bb761055(v=vs.85).aspx
   Static LVM_GETITEMTEXT := A_IsUnicode ? 0x1073 : 0x102D ; LVM_GETITEMTEXTW : LVM_GETITEMTEXTA
   Static OffText := 16 + A_PtrSize
   Static OffTextMax := OffText + A_PtrSize
   VarSetCapacity(ItemText, MaxChars << !!A_IsUnicode, 0)
   LV_EX_LVITEM(LVITEM, , Row, Column)
   NumPut(&ItemText, LVITEM, OffText, "Ptr")
   NumPut(MaxChars, LVITEM, OffTextMax, "Int")
   SendMessage, % LVM_GETITEMTEXT, % (Row - 1), % &LVITEM, , % "ahk_id " . HLV
   VarSetCapacity(ItemText, -1)
   Return ItemText
}
; ======================================================================================================================
; LV_EX_GetTileViewLines - Retrieves the maximum number of additional text lines in each tile, not counting the title.
; ======================================================================================================================
LV_EX_GetTileViewLines(HLV) {
   ; LVM_GETTILEVIEWINFO = 0x10A3 -> http://msdn.microsoft.com/en-us/library/bb774768(v=vs.85).aspx
   Static SizeLVTVI := 40
   Static OffLines := 20
   VarSetCapacity(LVTVI, SizeLVTVI, 0)   ; LVTILEVIEWINFO
   NumPut(SizeLVTVI, LVTVI, 0, "UInt")   ; cbSize
   NumPut(0x00000002, LVTVI, 4, "UInt")  ; dwMask = LVTVIM_COLUMNS
   SendMessage, 0x10A3, 0, % &LVTVI, , % "ahk_id " . HLV ; LVM_GETTILEVIEWINFO
   Lines := NumGet(LVTVI, OffLines, "Int")
   Return (Lines > 0 ? --Lines : 0)
}
; ======================================================================================================================
; LV_EX_GetTopIndex - Retrieves the index of the topmost visible item when in list or report view.
; ======================================================================================================================
LV_EX_GetTopIndex(HLV) {
   ; LVM_GETTOPINDEX = 0x1027 -> http://msdn.microsoft.com/en-us/library/bb761087(v=vs.85).aspx
   SendMessage, 0x1027, 0, 0, , % "ahk_id " . HLV
   Return (ErrorLevel + 1)
}
; ======================================================================================================================
; LV_EX_GetView - Retrieves the current view of a list-view control.
; ======================================================================================================================
LV_EX_GetView(HLV) {
   ; LVM_GETVIEW = 0x108F -> http://msdn.microsoft.com/en-us/library/bb761091(v=vs.85).aspx
   Static Views := {0x00: "Icon", 0x01: "Report", 0x02: "IconSmall", 0x03: "List", 0x04: "Tile"}
   SendMessage, 0x108F, 0, 0, , % "ahk_id " . HLV
   Return Views[ErrorLevel]
}
; ======================================================================================================================
; LV_EX_GroupGetState - Get group states (requires Win Vista+ for most states).
; ======================================================================================================================
LV_EX_GroupGetState(HLV, GroupID, ByRef Collapsed := "", ByRef Collapsible := "", ByRef Focused := "", ByRef Hidden := ""
                  , ByRef NoHeader := "", ByRef Normal := "", ByRef Selected := "") {
   ; LVM_GETGROUPINFO = 0x1095 -> msdn.microsoft.com/en-us/library/bb774932(v=vs.85).aspx
   Static OS := DllCall("GetVersion", "UChar")
   Static LVGS5 := {Collapsed: 0x01, Hidden: 0x02, Normal: 0x00}
   Static LVGS6 := {Collapsed: 0x01, Collapsible: 0x08, Focused: 0x10, Hidden: 0x02, NoHeader: 0x04, Normal: 0x00, Selected: 0x20}
   Static LVGF := 0x04 ; LVGF_STATE
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
   Static OffStateMask := 8 + (A_PtrSize * 3) + 8
   Static OffState := OffStateMask + 4
   SetStates := 0
   LVGS := OS > 5 ? LVGS6 : LVGS5
   For Each, State In LVGS
      SetStates |= State
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(LVGF, LVGROUP, 4, "UInt")
   NumPut(SetStates, LVGROUP, OffStateMask, "UInt")
   SendMessage, 0x1095, %GroupID%, &LVGROUP, , % "ahk_id " . HLV
   States := NumGet(&LVGROUP, OffState, "UInt")
   For Each, State in LVGS
      %Each% := States & State ? True : False
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupInsert - Inserts a group into a list-view control.
; ======================================================================================================================
LV_EX_GroupInsert(HLV, GroupID, Header, Align := "", Index := -1) {
   ; LVM_INSERTGROUP = 0x1091 -> msdn.microsoft.com/en-us/library/bb761103(v=vs.85).aspx
   Static Alignment := {1: 1, 2: 2, 4: 4, C: 2, L: 1, R: 4}
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
   Static OffHeader := 8
   Static OffGroupID := OffHeader + (A_PtrSize * 3) + 4
   Static OffAlign := OffGroupID + 12
   Static LVGF := 0x11 ; LVGF_GROUPID | LVGF_HEADER | LVGF_STATE
   Static LVGF_ALIGN := 0x00000008
   Align := (A := Alignment[SubStr(Align, 1, 1)]) ? A : 0
   Mask := LVGF | (Align ? LVGF_ALIGN : 0)
   PHeader := A_IsUnicode ? &Header : LV_EX_PWSTR(Header, WHeader)
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(Mask, LVGROUP, 4, "UInt")
   NumPut(PHeader, LVGROUP, OffHeader, "Ptr")
   NumPut(GroupID, LVGROUP, OffGroupID, "Int")
   NumPut(Align, LVGROUP, OffAlign, "UInt")
   SendMessage, 0x1091, %Index%, % &LVGROUP, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupRemove - Removes a group from a list-view control.
; ======================================================================================================================
LV_EX_GroupRemove(HLV, GroupID) {
   ; LVM_REMOVEGROUP = 0x1096 -> msdn.microsoft.com/en-us/library/bb761149(v=vs.85).aspx
   SendMessage, 0x10A0, %GroupID%, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupRemoveAll - Removes all groups from a list-view control.
; ======================================================================================================================
LV_EX_GroupRemoveAll(HLV) {
   ; LVM_REMOVEALLGROUPS = 0x10A0 -> msdn.microsoft.com/en-us/library/bb761147(v=vs.85).aspx
   SendMessage, 0x10A0, 0, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupSetState - Set group state (requires Win Vista+ for most states).
; ======================================================================================================================
LV_EX_GroupSetState(HLV, GroupID, States*) {
   ; LVM_SETGROUPINFO = 0x1093 -> msdn.microsoft.com/en-us/library/bb761167(v=vs.85).aspx
   Static OS := DllCall("GetVersion", "UChar")
   Static LVGS5 := {Collapsed: 0x01, Hidden: 0x02, Normal: 0x00, 0: 0, 1: 1, 2: 2}
   Static LVGS6 := {Collapsed: 0x01, Collapsible: 0x08, Focused: 0x10, Hidden: 0x02, NoHeader: 0x04, Normal: 0x00
                 , Selected: 0x20, 0: 0, 1: 1, 2: 2, 4: 4, 8: 8, 16: 16, 32: 32}
   Static LVGF := 0x04 ; LVGF_STATE
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
   Static OffStateMask := 8 + (A_PtrSize * 3) + 8
   Static OffState := OffStateMask + 4
   SetStates := 0
   LVGS := OS > 5 ? LVGS6 : LVGS5
   For Each, State In States {
      If !LVGS.HasKey(State)
         Return False
      SetStates |= LVGS[State]
   }
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(LVGF, LVGROUP, 4, "UInt")
   NumPut(SetStates, LVGROUP, OffStateMask, "UInt")
   NumPut(SetStates, LVGROUP, OffState, "UInt")
   SendMessage, 0x1093, %GroupID%, % &LVGROUP, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_HasGroup - Determines whether the list-view control has a specified group.
; ======================================================================================================================
LV_EX_HasGroup(HLV, GroupID) {
   ; LVM_HASGROUP = 0x10A1 -> msdn.microsoft.com/en-us/library/bb761097(v=vs.85).aspx
   SendMessage, 0x10A1, %GroupID%, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_IsGroupViewEnabled - Checks whether the list-view control has group view enabled.
; ======================================================================================================================
LV_EX_IsGroupViewEnabled(HLV) {
   ; LVM_ISGROUPVIEWENABLED = 0x10AF -> msdn.microsoft.com/en-us/library/bb761133(v=vs.85).aspx
   SendMessage, 0x10AF, 0, 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_IsRowChecked - Indicates if a row in the list-view control is checked.
; ======================================================================================================================
LV_EX_IsRowChecked(HLV, Row) {
   Return LV_EX_GetItemState(HLV, Row).Checked
}
; ======================================================================================================================
; LV_EX_IsRowFocused - Indicates if a row in the list-view control is focused.
; ======================================================================================================================
LV_EX_IsRowFocused(HLV, Row) {
   Return LV_EX_GetItemState(HLV, Row).Focused
}
; ======================================================================================================================
; LV_EX_IsRowSelected - Indicates if a row in the list-view control is selected.
; ======================================================================================================================
LV_EX_IsRowSelected(HLV, Row) {
   Return LV_EX_GetItemState(HLV, Row).Selected
}
; ======================================================================================================================
; LV_EX_IsRowVisible - Indicates if a row in the list-view control is visible.
; ======================================================================================================================
LV_EX_IsRowVisible(HLV, Row) {
   ; LVM_ISITEMVISIBLE = 0x10B6 -> http://msdn.microsoft.com/en-us/library/bb761135(v=vs.85).aspx
   SendMessage, 0x10B6, % (Row - 1), 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; CommCtrl.h:
; // These next to methods make it easy to identify an item that can be repositioned
; // within listview. For example: Many developers use the lParam to store an identifier that is
; // unique. Unfortunatly, in order to find this item, they have to iterate through all of the items
; // in the listview. Listview will maintain a unique identifier.  The upper bound is the size of a DWORD.
; ======================================================================================================================
; LV_EX_MapIDToIndex - Maps the ID of an item to an index.
; ======================================================================================================================
LV_EX_MapIDToIndex(HLV, ID) {
   ; LVM_MAPIDTOINDEX = 0x10B5 -> http://msdn.microsoft.com/en-us/library/bb761137(v=vs.85).aspx
   SendMessage, 0x10B5, % ID, 0, , % "ahk_id " . HLV
   Return (ErrorLevel + 1)
}
; ======================================================================================================================
; LV_EX_MapIndexToID - Maps the index of an item to an unique ID.
; ======================================================================================================================
LV_EX_MapIndexToID(HLV, Index) {
   ; LVM_MAPINDEXTOID = 0x10B4 -> http://msdn.microsoft.com/en-us/library/bb761139(v=vs.85).aspx
   SendMessage, 0x10B4, % (Index - 1), 0, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_RedrawRows - Forces a list-view control to redraw a range of items.
; ======================================================================================================================
LV_EX_RedrawRows(HLV, First := 0, Last := "") {
   ; LVM_REDRAWITEMS = 0x1015 -> http://msdn.microsoft.com/en-us/library/bb761145(v=vs.85).aspx
   If (First > 0) {
      If (Last = "")
         Last := First
   }
   Else {
      First := LV_EX_GetTopIndex(HLV)
      Last := First + LV_EX_GetRowsPerPage(HLV) - 1
   }
   SendMessage, 0x1015, % (First - 1), % (Last - 1), , % "ahk_id " . HLV
   If (ErrorLevel)
      Return DllCall("User32.dll\UpdateWindow", "Ptr", HLV, "UInt")
   Return False
}
; ======================================================================================================================
; LV_EX_SetBkImage - Sets the background image in a list-view control.
; ======================================================================================================================
LV_EX_SetBkImage(HLV, ImgPath, Width := "", Height := "") {
   ; LVM_SETBKIMAGEA := 0x1044 -> http://msdn.microsoft.com/en-us/library/bb761155(v=vs.85).aspx
   Static XAlign := {C: 50, L: 0, R: 100}, YAlign := {B: 100, C: 50, T: 0}
   Static KnownCtrls := []
   Static OSVERSION := DllCall("Kernel32.dll\GetVersion", "UInt") & 0xFF
   HBITMAP := 0
   If (ImgPath) && FileExist(ImgPath) {
      If (Width = "") && (Height = "") {
         VarSetCapacity(RECT, 16, 0)
         DllCall("User32.dll\GetClientRect", "Ptr", HLV, "Ptr", &RECT)
         Width := NumGet(RECT, 8, "Int"), Height := NumGet(RECT, 12, "Int")
      }
      HMOD := DllCall("Kernel32.dll\LoadLibrary", "Str", "Gdiplus.dll", "UPtr")
      VarSetCapacity(SI, 24, 0), NumPut(1, SI, "UInt")
      DllCall("Gdiplus.dll\GdiplusStartup", "PtrP", Token, "Ptr", &SI, "Ptr", 0)
      DllCall("Gdiplus.dll\GdipCreateBitmapFromFile", "WStr", ImgPath, "PtrP", Bitmap)
      DllCall("Gdiplus.dll\GdipCreateHBITMAPFromBitmap", "Ptr", Bitmap, "PtrP", HBITMAP, "UInt", 0x00FFFFFF)
      DllCall("Gdiplus.dll\GdipDisposeImage", "Ptr", Bitmap)
      DllCall("Gdiplus.dll\GdiplusShutdown", "Ptr", Token)
      DllCall("Kernel32.dll\FreeLibrary", "Ptr", HMOD)
      HBITMAP := DllCall("User32.dll\CopyImage"
                       , "Ptr", HBITMAP, "UInt", 0, "Int", Width, "Int", Height, "UInt", 0x2008, "UPtr")
      If !(HBITMAP)
         Return False
   }
   ; Set extended style LVS_EX_DOUBLEBUFFER to avoid drawing issues
   If !KnownCtrls.HasKey(HLV) {
      LV_EX_SetExtendedStyle(HLV, 0x00010000, 0x00010000) ; LVS_EX_DOUBLEBUFFER = 0x00010000
      KnownCtrls[HLV] := True
   }
   Flags := 0x10000000 ; LVBKIF_TYPE_WATERMARK
   If (HBITMAP) && (OSVERSION >= 6) ; LVBKIF_FLAG_ALPHABLEND prevents that the image will be shown on WinXP
      Flags |= 0x20000000 ; LVBKIF_FLAG_ALPHABLEND
   LVBKIMAGESize :=  A_PtrSize = 8 ? 40 : 24
   VarSetCapacity(LVBKIMAGE, LVBKIMAGESize, 0)
   NumPut(Flags, LVBKIMAGE, 0, "UInt")
   NumPut(HBITMAP, LVBKIMAGE, A_PtrSize, "UPtr")
   SendMessage, 0x1044, 0, % &LVBKIMAGE, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetColumnOrder - Sets the left-to-right order of columns in a list-view control.
; ======================================================================================================================
LV_EX_SetColumnOrder(HLV, ColArray) {
   ; LVM_SETCOLUMNORDERARRAY = 0x103A -> http://msdn.microsoft.com/en-us/library/bb761161(v=vs.85).aspx
   Cols := ColArray.MaxIndex()
   VarSetCapacity(COA, Cols * 4, 0)
   For I, C In ColArray
      NumPut(C - 1, COA, (I - 1) * 4, "Int")
   SendMessage, 0x103A, % Cols, % &COA, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetExtendedStyle - Sets extended styles in list-view controls.
; ======================================================================================================================
LV_EX_SetExtendedStyle(HLV, StyleMsk, Styles) {
   ; LVM_SETEXTENDEDLISTVIEWSTYLE = 0x1036 -> http://msdn.microsoft.com/en-us/library/bb761165(v=vs.85).aspx
   SendMessage, 0x1036, % StyleMsk, % Styles, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetGroup - Assigns a list-view item to an existing group.
; ======================================================================================================================
LV_EX_SetGroup(HLV, Row, GroupID) {
   ; LVM_SETITEMA = 0x1006 -> http://msdn.microsoft.com/en-us/library/bb761186(v=vs.85).aspx
   Static OffGroupID := 28 + (A_PtrSize * 3)
   LV_EX_LVITEM(LVITEM, 0x00000100, Row) ; LVIF_GROUPID
   NumPut(GroupID, LVITEM, OffGroupID, "UPtr")
   SendMessage, 0x1006, 0, % &LVITEM, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetIconSpacing - Sets the spacing between icons in the icon view.
; ======================================================================================================================
LV_EX_SetIconSpacing(HLV, CX, CY) {
   ; LVM_SETICONSPACING = 0x1035 -> http://msdn.microsoft.com/en-us/library/bb761176(v=vs.85).aspx
   If (CX < 4) && (CX <> -1)
      CX := 4
   If (CY < 4) && (CY <> -1)
      CY := 4
   SendMessage, 0x1035, 0, % (CX & 0xFFFF) | ((CY & 0xFFFF) << 16), , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetItemIndent - Sets the indent of the first column to the specified number of icon widths.
; ======================================================================================================================
LV_EX_SetItemIndent(HLV, Row, NumIcons) {
   ; LVM_SETITEMA = 0x1006 -> http://msdn.microsoft.com/en-us/library/bb761186(v=vs.85).aspx
   Static OffIndent := 24 + (A_PtrSize * 3)
   LV_EX_LVITEM(LVITEM, 0x00000010, Row) ; LVIF_INDENT
   NumPut(NumIcons, LVITEM, OffIndent, "Int")
   SendMessage, 0x1006, 0, % &LVITEM, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetItemParam - Sets the lParam field of the item to the specified value.
; ======================================================================================================================
LV_EX_SetItemParam(HLV, Row, Value) {
   ; LVM_SETITEMA = 0x1006 -> http://msdn.microsoft.com/en-us/library/bb761186(v=vs.85).aspx
   Static OffParam := 24 + (A_PtrSize * 2)
   LV_EX_LVITEM(LVITEM, 0x00000004, Row) ; LVIF_PARAM
   NumPut(Value, LVITEM, OffParam, "UPtr")
   SendMessage, 0x1006, 0, % &LVITEM, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetSubItemImage - Assigns an image from the list-view's image list to this subitem.
; ======================================================================================================================
LV_EX_SetSubItemImage(HLV, Row, Column, Index) {
   ; LVM_SETITEMA = 0x1006 -> http://msdn.microsoft.com/en-us/library/bb761186(v=vs.85).aspx
   Static KnownCtrls := []
   Static OffImage := 20 + (A_PtrSize * 2)
   If !KnownCtrls.HasKey(HLV) {
      LV_EX_SetExtendedStyle(HLV, 0x00000002, 0x00000002) ; LVS_EX_SUBITEMIMAGES = 0x00000002
      KnownCtrls[HLV] := True
   }
   LV_EX_LVITEM(LVITEM, 0x00000002, Row, Column) ; LVIF_IMAGE
   NumPut(Index - 1, LVITEM, OffImage, "Int")
   SendMessage, 0x1006, 0, % &LVITEM, , % "ahk_id " . HLV
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SetTileInfo - Sets the additional columns displayed for this tile, and the order of those columns.
; ======================================================================================================================
LV_EX_SetTileInfo(HLV, Row, Columns*) {
   ; Row      : The 1-based row number. If you specify a number less than 1, the tile info will be set for all rows.
   ; Colomns* : Array of column indices, specifying which columns are displayed for this item, and the order of those
   ;            columns. Indices should be greater than 1, because column 1, the item name, is already displayed.
   ; LVM_SETTILEINFO = 0x10A4 -> http://msdn.microsoft.com/en-us/library/bb761210(v=vs.85).aspx
   Static SizeLVTI := (4 * 2) + (A_PtrSize * 2)
   Static OffItem := 4
   Static OffCols := 8
   Static OffColArr := OffCols + A_PtrSize
   ColCount := (CC := Columns.MaxIndex()) = "" ? 0 : CC
   Lines := LV_EX_GetTileViewLines(HLV)
   If ((Row = 0) && (ColCount <> Lines)) || ((Row <> 0) && (ColCount >= Lines))
      LV_EX_SetTileViewLines(HLV, ColCount)
   VarSetCapacity(ColArr, 4 * (ColCount + 1), 0)
   Addr := &ColArr
   For I, Column In Columns
      Addr := NumPut(Column - 1, Addr + 0, "UInt")
   VarSetCapacity(LVTI, SizeLVTI, 0)       ; LVTILEINFO
   NumPut(SizeLVTI, LVTI, 0, "UInt")       ; cbSize
   NumPut(ColCount, LVTI, OffCols, "UInt") ; cColumns
   NumPut(&ColArr, LVTI, OffColArr, "Ptr") ; puColumns
   If (Row > 0) {
      NumPut(Row - 1, LVTI, OffItem, "Int") ; iItem
      SendMessage, 0x10A4, 0, % &LVTI, , % "ahk_id " . HLV ; LVM_SETTILEINFO
      Return ErrorLevel
   }
   SendMessage, 0x1004, 0, 0, , % "ahk_id " . HLV ; LVM_GETITEMCOUNT
   Loop, % ErrorLevel {
      NumPut(A_Index - 1, LVTI, OffItem, "Int") ; iItem
      SendMessage, 0x10A4, 0, % &LVTI, , % "ahk_id " . HLV ; LVM_SETTILEINFO
      If !(ErrorLevel)
         Return ErrorLevel
   }
   Return True
}
; ======================================================================================================================
; LV_EX_SetTileViewLines - Sets the maximum number of additional text lines in each tile, not counting the title.
; ======================================================================================================================
LV_EX_SetTileViewLines(HLV, Lines) {
   ; Lines : Maximum number of text lines in each item label, not counting the title.
   ; LVM_GETTILEVIEWINFO = 0x10A3 -> http://msdn.microsoft.com/en-us/library/bb761083(v=vs.85).aspx
   ; LVM_SETTILEVIEWINFO = 0x10A2 -> http://msdn.microsoft.com/en-us/library/bb761212(v=vs.85).aspx
   ; One line is added internally because the item might be wrapped to two lines!
   Static SizeLVTVI := 40
   Static OffLines := 20
   If (Lines > 0)
      Lines++
   VarSetCapacity(LVTVI, SizeLVTVI, 0)     ; LVTILEVIEWINFO
   NumPut(SizeLVTVI, LVTVI, 0, "UInt")     ; cbSize
   NumPut(0x00000003, LVTVI, 4, "UInt")    ; dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS
   NumPut(Lines, LVTVI, OffLines, "Int") ; c_lines: max lines below first line
   SendMessage, 0x10A2, 0, % &LVTVI, , % "ahk_id " . HLV ; LVM_SETTILEVIEWINFO
   Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_SubItemHitTest - Gets the column (subitem) at the passed coordinates or the position of the mouse cursor.
; ======================================================================================================================
LV_EX_SubItemHitTest(HLV, X := -1, Y := -1) {
   ; LVM_SUBITEMHITTEST = 0x1039 -> http://msdn.microsoft.com/en-us/library/bb761229(v=vs.85).aspx
   VarSetCapacity(LVHTI, 24, 0) ; LVHITTESTINFO
   If (X = -1) || (Y = -1) {
      DllCall("User32.dll\GetCursorPos", "Ptr", &LVHTI)
      DllCall("User32.dll\ScreenToClient", "Ptr", HLV, "Ptr", &LVHTI)
   }
   Else {
      NumPut(X, LVHTI, 0, "Int")
      NumPut(Y, LVHTI, 4, "Int")
   }
   SendMessage, 0x1039, 0, % &LVHTI, , % "ahk_id " . HLV
   Return (ErrorLevel > 0x7FFFFFFF ? 0 : NumGet(LVHTI, 16, "Int") + 1)
}
; ======================================================================================================================
; ======================================================================================================================
; Function for internal use ============================================================================================
; ======================================================================================================================
; ======================================================================================================================
LV_EX_LVITEM(ByRef LVITEM, Mask := 0, Row := 1, Col := 1) {
   Static LVITEMSize := 48 + (A_PtrSize * 3)
   VarSetCapacity(LVITEM, LVITEMSize, 0)
   NumPut(Mask, LVITEM, 0, "UInt"), NumPut(Row - 1, LVITEM, 4, "Int"), NumPut(Col - 1, LVITEM, 8, "Int")
}
; ----------------------------------------------------------------------------------------------------------------------
LV_EX_PWSTR(Str, ByRef WSTR) { ; ANSI to Unicode
   VarSetCapacity(WSTR, StrPut(Str, "UTF-16") * 2, 0)
   StrPut(Str, &WSTR, "UTF-16")
   Return &WSTR
}
:arrow: Sources at GitHub.
:arrow: Docs at GitHub.
:arrow: Download from GitHub.
Last edited by just me on 28 Apr 2016, 08:24, edited 2 times in total.
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2015-03-13

13 Mar 2015, 05:42

* Update 1.1.00.00 *
rajat
Posts: 8
Joined: 07 Feb 2014, 13:35

Re: [LIB] LV_EX - update on 2015-03-13

31 Jul 2015, 10:19

This is an awesome set of functions mate, many thanks!
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2015-03-13

17 Dec 2015, 09:15

@just me

I haven't been able to figure out the right combination of commands to create a collapsible listview group but set that group to initially be collapsed. Setting the state to Collapsible makes it expanded but setting it to Collapsed makes it so you can't expand it. Help plz :)
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2015-03-13

17 Dec 2015, 10:43

The LV_EX_GroupSetState() function replaces all states with the passed states.

Code: Select all

LV_EX_GroupSetState(HLV, GrouID, "Collapsible")
includes the Normal (expanded) state implicitely, because its value is 0x00.

Code: Select all

LV_EX_GroupSetState(HLV, GrouID, "Collapsed")
will remove the Collapsible state.

Code: Select all

LV_EX_GroupSetState(HLV, GrouID, "Collapsed", "Collapsible")
will set both states.
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2015-03-13

17 Dec 2015, 11:19

Ahhhh, is that what the States* means? That any parameters after that all are States?
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2015-03-13

17 Dec 2015, 11:49

Correct!
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2015-03-13

18 Dec 2015, 12:15

More help needed. So I currently have a listview with 2 groups, the first has the header hidden and the second is now set to be collapsible but initially collapsed. What I now want to do is scroll the listview to the bottom should the user expand the second group. I first need to find a way to determine how to track the user's movements and clicks/double clicks. It seems none of the built in A_* variables give any useful info when the header is double clicked or the Arrow is clicked to expand the group.

As for the scrolling, I was looking at checking for LVM_GETGROUPSTATE but not sure if that's what I need to be using. Does this look even remotely correct?

Code: Select all

; ======================================================================================================================
; LV_EX_GetGroupState - Gets the state of a group by group ID
; ======================================================================================================================
LV_EX_GetGroupState(HLV, GroupID) {
   ; LVM_GETGROUPSTATE = 0x105C -> https://msdn.microsoft.com/en-us/library/bb774936(v=vs.85).aspx
   ; LVGS_COLLAPSED = 0x00000001
   SendMessage, 0x105C, %GroupID%, 0x00000001, , % "ahk_id " . HLV
   Return ErrorLevel
}
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2015-03-13

18 Dec 2015, 12:36

Oh wait! That function works actually. It only checks for LVGS_COLLAPSED := 0x00000001 though. Not sure if there is a way to check for all applied states.

So now I just need to figure out how to check if they double clicked on the group header, and if so, check the state of LVGS_COLLAPSED and if it is not collapsed, scroll to the bottom.
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2015-03-13

06 Jan 2016, 11:46

Thoughts on this function?

Code: Select all

; ======================================================================================================================
; LV_EX_GetGroupHeader - Gets the header text of a group by group ID
; ======================================================================================================================
LV_EX_GetGroupHeader(HLV, GroupID) {
   ; LVM_GETGROUPINFO = 0x1095
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
   Static OffHeader := 8
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   SendMessage, 0x1095, %GroupID%, % &LVGROUP, , % "ahk_id " . HLV
   Return NumGet(LVGROUP, OffHeader, "Ptr")
}
The message is returning successfully because ErrorLevel is getting set to the GroupID but I'm having trouble correctly extracting the header text. Wonder if I need to make use of the LV_EX_PWSTR(Str, ByRef WSTR) function.
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2015-03-13

07 Jan 2016, 02:52

It's a bug and will be fixed. Thanks for reporting!
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2015-03-13

07 Jan 2016, 04:52

Haha, I thought it would be a part of my lib, but it isn't. It's faulty, though. So I'll fix your function.
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2015-03-13

07 Jan 2016, 05:17

Code: Select all

; ======================================================================================================================
; LV_EX_GetGroupHeader - Gets the header text of a group by group ID
; ======================================================================================================================
LV_EX_GetGroupHeader(HLV, GroupID, MaxChars := 1024) {
   ; LVM_GETGROUPINFO = 0x1095
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
   Static LVGF_HEADER := 0x00000001
   Static OffHeader := 8
   Static OffHeaderMax := 8 + A_PtrSize
   VarSetCapacity(HeaderText, MaxChars * 2, 0)
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(LVGF_HEADER, LVGROUP, 4, "UInt")
   NumPut(&HeaderText, LVGROUP, OffHeader, "Ptr")
   NumPut(MaxChars, LVGROUP, OffHeaderMax, "Int")
   SendMessage, 0x1095, %GroupID%, % &LVGROUP, , % "ahk_id " . HLV
   Return StrGet(&HeaderText, MaxChars, "UTF-16")
}
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2015-03-13

07 Jan 2016, 07:58

just me wrote:Haha, I thought it would be a part of my lib, but it isn't. It's faulty, though. So I'll fix your function.
I think its a great addition to your library. I really can't call it my function seeing as I tried piecing it together based on your work. And then you ended up fixing it anyhow!

I do just want to tell you that all your work here is brilliant. I've learned a lot from deciphering your work. Bravo!
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2016-04-28

28 Apr 2016, 07:59

*Update 1.1.01.00* (Added LV_EX_GroupGetState() contributed by Pulover)
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2016-04-28

28 Apr 2016, 08:26

Took the chance and added LV_EX_GroupGetHeader() as suggested by kczx3 above, too.
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2016-04-28

10 May 2016, 12:46

So I'm looking into trying to extend the functionality that LV_EX has. They are quite a few parameters to the LVGROUP structure, albeit only supported on newer OS versions, that I'm interested in. Of particular interest, is the Task Link which is clickable text in the group header that sends a LVN_LINKCLICK notification via WM_NOTIFY. I attempted to add another parameter to LV_EX_GroupIsnert() but am not seeing any results from it.

Code: Select all

; ======================================================================================================================
; LV_EX_GroupInsert - Inserts a group into a list-view control.
; ======================================================================================================================
LV_EX_GroupInsert(HLV, GroupID, Header, Align := "", Index := -1, Task := "") {
   ; LVM_INSERTGROUP = 0x1091 -> msdn.microsoft.com/en-us/library/bb761103(v=vs.85).aspx
   Static Alignment := {1: 1, 2: 2, 4: 4, C: 2, L: 1, R: 4}
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 8)
   Static OffHeader := 8
   Static OffGroupID := OffHeader + (A_PtrSize * 3) + 4
   Static OffAlign := OffGroupID + 12
   Static OffTask := OffAlign + (A_PtrSize * 3)
   Static LVGF := 0x11 ; LVGF_GROUPID | LVGF_HEADER | LVGF_STATE
   Static LVGF_ALIGN := 0x00000008
   Static LVGF_TASK := 0x00000200
   Align := (A := Alignment[SubStr(Align, 1, 1)]) ? A : 0
   Mask := LVGF | (Align ? LVGF_ALIGN : 0) | (Task ? LVGF_TASK : 0)
   PHeader := A_IsUnicode ? &Header : LV_EX_PWSTR(Header, WHeader)
   PTask := A_IsUnicode ? &Task : LV_EX_PWSTR(Task, WTask)
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(Mask, LVGROUP, 4, "UInt")
   NumPut(PHeader, LVGROUP, OffHeader, "Ptr")
   NumPut(GroupID, LVGROUP, OffGroupID, "Int")
   NumPut(Align, LVGROUP, OffAlign, "UInt")
   NumPut(PTask, LVGROUP, OffTask, "Ptr")
   SendMessage, 0x1091, %Index%, % &LVGROUP, , % "ahk_id " . HLV
   Return ErrorLevel
}
I tried getting the offsets correct by talking with GeekDude in the IRC chat. Not sure if those are off or if there is a mystery puzzle piece I am missing. I also contemplated making a new function to handle this by mimicking LV_EX_GroupSetState() but this also fails to function properly.

Code: Select all

; ======================================================================================================================
; LV_EX_GroupSetTask - Set group Task
; ======================================================================================================================
LV_EX_GroupSetTask(HLV, GroupID, Task := "") {
   ; LVM_SETGROUPINFO = 0x1093 -> msdn.microsoft.com/en-us/library/bb761167(v=vs.85).aspx
   Static LVGF_TASK := 0x00000200 ;LVGF_TASK
   Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 8)
   Static OffTask := 72
   PTask := A_IsUnicode ? &Task : LV_EX_PWSTR(Task, WTask)
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(LVGF_TASK, LVGROUP, 4, "UInt")
   NumPut(PTask, LVGROUP, OffTask, "Ptr")
   SendMessage, 0x1093, %GroupID%, % &LVGROUP, , % "ahk_id " . HLV
   Return ErrorLevel
}
Lastly, my concern is monitoring for this notification. I make use of Class_LV_Colors in nearly all ListViews that I make which also monitors WM_NOTIFY, I believe. I don't think I could use both then and monitor the notifications from each.

I'd like to try and pick this up myself so if there are any hints you may have to offer that would be helpful. The more I learn the less I have to ask you ;). As always, thanks!
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2016-04-28

11 May 2016, 09:50

Hi kczx3,

the structure size of the extended LVGROUP version for Vista+ is not correct. I corrected your LV_EX_GroupSetTask() function and it is working for me:

Code: Select all

; ======================================================================================================================
; LV_EX_GroupSetTask - Set group Task
; ======================================================================================================================
LV_EX_GroupSetTask(HLV, GroupID, Task := "") {
   ; LVM_SETGROUPINFO = 0x1093 -> msdn.microsoft.com/en-us/library/bb761167(v=vs.85).aspx
   Static LVGF_TASK := 0x00000200 ;LVGF_TASK
   Static SizeOfLVGROUP := (4 * 10) + (A_PtrSize * 14)
   Static OffTask := (4 * 6) + (A_PtrSize * 6)
   PTask := A_IsUnicode ? &Task : LV_EX_PWSTR(Task, WTask)
   VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
   NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
   NumPut(LVGF_TASK, LVGROUP, 4, "UInt")
   NumPut(PTask, LVGROUP, OffTask, "Ptr")
   SendMessage, 0x1093, %GroupID%, % &LVGROUP, , % "ahk_id " . HLV
   Return ErrorLevel
}
Related to WM_NOTIFY -> LVN_LINKCLICK I think that you can monitor it with an own function if you use a function object. The default message handler of LV_Colors() does not touch LVN_LINKCLICK notifications, so both should work But it possibly might cause the well-known freezing issue.
User avatar
kczx3
Posts: 640
Joined: 06 Oct 2015, 21:39

Re: [LIB] LV_EX - update on 2016-04-28

12 May 2016, 09:12

Well, I think I'm getting there... Last bit is to get the iSubItem from the NMLINK structure so that I know what group's link was clicked. Assumption would be that my offsets are again incorrect.

Code: Select all

ON_LVN_LINKCLICK(w, l, msg, hwnd)
{
	Global IMLV_LView, AMLV_LView
	; lParam is a pointer to a NMLINK structure containing NMHDR and LITEM structures
	; -> http://msdn.microsoft.com/en-us/library/bb760714%28VS.85%29.aspx
	Static LVN_LINKCLICK := -184
	Static NMHDRSize := A_PtrSize * 3
	Static MAX_LINKID_TEXT := 48
	Static L_MAX_URL_LENGTH := (2048 + 32 + 3) ; 3 : sizeof("://"))
	Static LITEMSize := (A_PtrSize * 4) + ((MAX_LINKID_TEXT + L_MAX_URL_LENGTH) * 2)
	Static iSubItem := LITEMSize + A_PtrSize
	If ((HCTL := NumGet(L + 0, 0, "UPtr")) = IMLV_LView OR HCTL = AMLV_LView)
	{
		code := NumGet(L + (A_PtrSize * 2), 0, "Int")
		If (code = -184)
			ToolTip, % NumGet(L + iSubItem, "Int")
		Else
			Return
	}
}
just me
Posts: 5515
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: [LIB] LV_EX - update on 2016-04-28

13 May 2016, 09:33

Well, your assumption was right. ;)

I corrected the offset. You didn't add the size of the leading NMHDR structure. Also, the first 4 fields of the LITEM structure as well as iItem and iSubItem are 4 bytes long (Uint/Int), and the iItem field following the LITEM structure has to be aligned to a DWORD boundary, so 2 extra bytes must be added:

Code: Select all

ON_LVN_LINKCLICK(W, L, Msg, hWnd)
{
	Global IMLV_LView, AMLV_LView
	; lParam is a pointer to a NMLVLINK structure. The identifier of the group containing the link is in the iSubItem member.
	; -> msdn.microsoft.com/en-us/library/bb774851%28v=vs.85%29.aspx
	Static MAX_LINKID_TEXT := 48
	Static L_MAX_URL_LENGTH := 2048 + 32 + 3 ; 3 = sizeof("://"))
	Static NMHDRSize := A_PtrSize * 3
	Static LITEMSize := (4 * 4) + ((MAX_LINKID_TEXT + L_MAX_URL_LENGTH) * 2)
	Static OffSubItem := NMHDRSize + LITEMSize + 6 ; 2 bytes alignment + 4 bytes iItem
	If ((HCTL := NumGet(L + 0, 0, "UPtr")) = IMLV_LView) OR (HCTL = AMLV_LView)
	{
		Code := NumGet(L + (A_PtrSize * 2), "Int")
		If (Code = -184) ; LVN_LINKCLICK
			ToolTip, % "GroupID: " . NumGet(L + OffSubItem, "Int")
		Else
			Return
	}
}

Return to “Scripts and Functions”

Who is online

Users browsing this forum: 42td and 28 guests