Announcement

Collapse
No announcement yet.

ListView Header Item format flags SortUp, SortDown

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • ListView Header Item format flags SortUp, SortDown

    I have a DDT program with a (DDT) ListView (report mode).

    After a bit of spellunking, I came up with an API solution for the
    header sort arrow indicators that so many have already posted about.

    Unfortunately, it doesn't work visually, although the format bits are being set.
    The initial bits are &h4002 [text, centered] and subsequently, the
    &h0400 bit is also set (sortup). However, there is no change visually.

    I am on a Windows 7 Prof 64-bit PC.
    I use the classic (i.e. non-Aero) theme.
    I do not have a manifest and don't understand them anyway.
    I use the PB (v10.4) includes.

    Any thoughts on how to get this (relatively) simple code to work?
    I don't want to get involved with bitmaps/images etc.

    Code:
    '-----------------------------------------------------------------------'
    ' Set LV header sort indicator arrow                                    '
    '-----------------------------------------------------------------------'
    
    Sub LVSetArrowRL(idx as long, arrow as long)
    
        local    lvh as dword, hdi as HDItem
    
        lvh = SendMessage(GetDlgItem(rmLstDlg, %rmList), %LVM_GetHeader, 0, 0)
    
        hdi.mask = %HDI_Format
        SendMessage(lvh, %HDM_GetItem, idx-1, VarPtr(hdi))
    
        select case as long arrow
        case 0: hdi.fmt =  hdi.fmt and not(%HDF_SortUp or %HDF_SortDown)
        case 1: hdi.fmt = (hdi.fmt and not(%HDF_SortUp or %HDF_SortDown)) or %HDF_SortUp
        case 2: hdi.fmt = (hdi.fmt and not(%HDF_SortUp or %HDF_SortDown)) or %HDF_SortDown
        end select
    
        SendMessage(lvh, %HDM_SetItem, idx-1, VarPtr(hdi))
    
    End Sub
    Cheers, Mike.
    Last edited by Mike Simmonds; 28 Dec 2015, 12:23 AM.
    There are only two speeds for computers: fast enough, and too bloody slow.
    And there are 10 types of programmer -- those that know binary, and those that don't.

  • #2
    Hi Mike

    The Listview control is one of a set of windows that are implemented by the common control library, Comctl32.dll.

    Various versions of ComCtrl32.dll have been distributed with the operating system over time. See MSDN for more info.
    For example, Windows 7 ships with both Version 5 and Version 6 ComCtl32.dll

    In the code that you posted, you are using equates (%HDF_SortUp, %HDF_SortDown) which have meaning only in Version 6 and above.

    For that to work, your code needs to ensure that Version 6 is being used. That is achieved by referencing a 'manifest' file.
    Typically the manifest file is embedded in your executable's resource.

    See PBWin10 help for
    Code:
    #RESOURCE MANIFEST,     1, "filespec.XML"
    Rgds, Dave

    Comment


    • #3
      You might start by querying the success/fail of the HDM_SETITEM call.

      Return Value

      Returns nonzero upon success, or zero otherwise.
      Alternately, the listview may be getting redrawn or not redrawn at a time other than you think it is or isn't.

      There are examples of listview sort arrows here; even if you don't want to get involved with image files, that code might give you some ideas as to "when " you should be changing the header image and/or any followup actions (eg forced redraw) required. (Insufficient code shown).

      MCM

      Comment


      • #4
        Thank you both.

        @Dave I was aware of the version specific nature of the common controls.
        and was 'afraid' that by default, a lower version was chosen.
        I had hoped that with Win7 (for me; it's a personal project) ver 6 would be used.
        Looks like I will have to look into the (apparently unneccesarily complicated) world of manifests.
        [What are all the magic numbers therin and how does MS expect us to derive them?]

        @MCM Haven't got that far yet. I just wanted a proof of concept before
        adding sorted columns to the LV's.
        I had considered some sort of refresh/redraw, but could not see any messages in the MSDN for LV/Header.
        Perhaps I overlooked them.

        Cheers, Mike.
        Last edited by Mike Simmonds; 28 Dec 2015, 08:18 AM.
        There are only two speeds for computers: fast enough, and too bloody slow.
        And there are 10 types of programmer -- those that know binary, and those that don't.

        Comment


        • #5
          I had considered some sort of refresh/redraw, but could not see any messages in the MSDN for LV/Header.
          Perhaps I overlooked them.
          It might take forever to find it what you need at MSDN. Use 'Search' here instead.

          Me, I'd try "advanced" search, Source Code Forum, subject only, keyword 'sort'

          No, it ain't Google(r), but "searchable" titles and "all relevant" keywords on posts make it pretty useful.

          (That's why I often "update" thread titles. "Help" or "Problem" is IMO not a terribly 'searchable' title.)

          MCM

          Comment


          • #6
            I stole a manifest file as per Dave's advice.
            (From the forum.)

            The good news is that I get programmable arrows.
            The bad news is that they are centered above the text.
            In normal use, only one arrow will show.



            I tried HDF_Bitmap_On_Right, but it did not make a difference.

            If getting the arrows on the right is 'complicated', I will live with it.
            But any further advice?

            Cheers, Mike.
            Attached Files
            Last edited by Mike Simmonds; 28 Dec 2015, 09:20 AM.
            There are only two speeds for computers: fast enough, and too bloody slow.
            And there are 10 types of programmer -- those that know binary, and those that don't.

            Comment


            • #7
              Hey Mike,

              You will have success with HDF_Bitmap_On_Right
              if you attribute an imagelist to your listview, this, with or without a manifest.

              Pierre

              Attached Files
              Last edited by Pierre Bellisle; 28 Dec 2015, 12:59 PM.

              Comment


              • #8
                Hi Pierre,

                I do not want images or bitmaps of my own; I was hoping that the
                'bitmap on right' flag would move the system sortup/down arrows for me.

                I have never used an imagelist and do not want to detour just now, so
                I will accept the sort arrow above and centred.

                It's only a personal app anyway but my OCD thing woke up.

                Thanks for taking an interrest though.

                Cheers, Mike.
                There are only two speeds for computers: fast enough, and too bloody slow.
                And there are 10 types of programmer -- those that know binary, and those that don't.

                Comment


                • #9
                  No problem Mike.

                  For those who might be interested, here is some code that use 3 differents icons for each of the 6 columns. Arrows, triangles, dots...
                  SortUp, SortDown, and sort on item.lParam value are used.

                  Looks better with a Manifest-Comctl32-V6.

                  Pierre

                  Code:
                  #COMPILE EXE '#Win Win 8.04#
                  #INCLUDE "Win32Api.inc"
                  #INCLUDE "CommCtrl.inc"
                  #INCLUDE "ComDlg32.inc"
                  #RESOURCE "Resource.pbr" 'For better look but remOut if no Resource/Manifest, Comctl32.dll V6
                   
                  $AppName = "ListView header icon - The dance"
                   
                  %Listview           = 201
                  %StatusBar          = 301
                  %ListViewItemMaxLen = 240
                   
                  %HDSIL_NORMAL       = 0
                  %HDSIL_STATE        = 1
                  %HDF_SORTUP         = &H00000400 'Comctl32.dll Version 6.00. Draws an up-arrow
                  %HDF_SORTDOWN       = &H00000200 'Comctl32.dll Version 6.00. Draws a down-arrow
                   
                  GLOBAL hDlg      AS DWORD
                  GLOBAL hListview AS DWORD
                  '_____________________________________________________________________________________________
                   
                  FUNCTION ListViewInit() AS LONG
                   LOCAL ListViewColumn AS LV_COLUMN
                   LOCAL ListViewItem   AS LV_ITEM
                   LOCAL zBuffer        AS ASCIIZ * %ListViewItemMaxLen
                   LOCAL sBuffer        AS STRING
                   LOCAL ExStyle        AS DWORD
                   LOCAL Row            AS LONG
                   LOCAL RowCount       AS LONG
                   LOCAL Col            AS LONG
                   LOCAL ColumnCount    AS LONG
                   LOCAL IsertionPos    AS LONG
                   
                   sBuffer = "Carlos"   & $TAB & "Arneaud" & $TAB & "Black" & $TAB & "002" & $TAB & "France"  & $TAB & "Mars"    & $CRLF & _
                             "Béatrice" & $TAB & "Arneaud" & $TAB & "White" & $TAB & "001" & $TAB & "Canada"  & $TAB & "Uranus"  & $CRLF & _
                             "Anatole"  & $TAB & "Beene"   & $TAB & "Black" & $TAB & "008" & $TAB & "U.S.A."  & $TAB & "Mercure" & $CRLF & _
                             "Daniel"   & $TAB & "Beene"   & $TAB & "White" & $TAB & "006" & $TAB & "Congo"   & $TAB & "Jupiter" & $CRLF & _
                             "Émile"    & $TAB & "Beene"   & $TAB & "Black" & $TAB & "001" & $TAB & "U.K."    & $TAB & "Venus"
                   
                   RowCount = PARSECOUNT(sBuffer, $CRLF)
                   DIM RowArray(0 TO RowCount - 1)AS STRING
                   PARSE sBuffer, RowArray(), $CRLF
                   ColumnCount = PARSECOUNT(RowArray(0), $TAB)
                   
                   hListview = GetDlgItem(hDlg, %Listview)
                   ExStyle = %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES OR %LVS_EX_HEADERDRAGDROP
                   SendMessage(hListview, %LVM_SETEXTENDEDLISTVIEWSTYLE, ExStyle, ExStyle)
                   
                   'Set column headers.
                   ListViewColumn.mask    = %LVCF_FMT OR %LVCF_TEXT OR %LVCF_SUBITEM
                   ListViewColumn.fmt     = %LVCFMT_LEFT
                   ListViewColumn.pszText = VARPTR(zBuffer)
                   ListViewColumn.iOrder  = 0
                   
                   zBuffer = "First name" : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                   zBuffer = "Last name"  : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                   zBuffer = "Color"      : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                   zBuffer = "Number"     : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                   zBuffer = "Country"    : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                   zBuffer = "Planet"     : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn))
                   
                   'Set data.
                   ListViewItem.pszText = VARPTR(zBuffer)
                   FOR Row = 0 TO RowCount - 1
                     FOR Col= 0 TO ColumnCount - 1
                       zBuffer = PARSE$(RowArray(Row), $TAB, Col+ 1)
                       ListViewItem.iSubItem = Col
                       IF Col= 0 THEN
                         ListViewItem.iItem  = Row
                         ListViewItem.lParam = Row
                         ListViewItem.mask   = %LVIF_TEXT OR %LVIF_PARAM
                         IsertionPos = SendMessage(hListview, %LVM_INSERTITEM, 0, VARPTR(ListViewItem)) 'IsertionPos needed if listview have LVS_SORTASCENDING/LVS_SORTDESCENDING
                       ELSE
                         ListViewItem.iItem = IsertionPos 'Needed if listview have LVS_SORTASCENDING/LVS_SORTDESCENDING
                         ListViewItem.mask  = %LVIF_TEXT
                         SendMessage(hListview, %LVM_SETITEM, 0, VARPTR(ListViewItem))
                       END IF
                     NEXT
                   NEXT
                   
                   'Size columns
                   FOR Col= 0 TO ColumnCount - 1
                     SendMessage(hListview, %LVM_SETCOLUMNWIDTH, Col, 95) 'Static size
                     'SendMessage(hListview, %LVM_SETCOLUMNWIDTH, Col, MAKLNG(%LVSCW_AUTOSIZE, 0)) 'Auto size on column data
                     'SendMessage(hListview, %LVM_SETCOLUMNWIDTH, Col, MAKLNG(%LVSCW_AUTOSIZE_USEHEADER, 0)) 'Auto size on header
                   NEXT
                   
                  END FUNCTION
                  '________________________________________________________________________________________
                   
                  FUNCTION ListViewSort(BYVAL LvItemIndex1 AS LONG, BYVAL LvItemIndex2 AS LONG, BYVAL Col AS DWORD) AS LONG
                   LOCAL  LvItem1       AS LV_ITEM
                   LOCAL  LvItem2       AS LV_ITEM
                   LOCAL  zItem1        AS ASCIIZ * %ListViewItemMaxLen
                   LOCAL  zItem2        AS ASCIIZ * %ListViewItemMaxLen
                   LOCAL  SortDirection AS LONG
                   
                   IF (Col AND %HDF_SORTDOWN) THEN 'HDF_SORTDOWN, 0x200 is good for up to 512 columns
                     SortDirection = -1
                   ELSEIF (Col AND %HDF_SORTUP) THEN 'HDF_SORTUP, 0x400
                     SortDirection = 1
                   ELSE
                     SortDirection = 0 'Use lParam to sort
                   END IF
                   Col = Col AND &H000000FF 'Discard possible HDF_SORTDOWN = 0x200 or HDF_SORTUP = 0x400
                   
                   LvItem1.iItem      = LvItemIndex1
                   LvItem1.iSubItem   = Col
                   LvItem1.pszText    = VARPTR(zItem1)
                   LvItem1.cchTextMax = %ListViewItemMaxLen 'SIZEOF(zItem1)
                   LvItem1.mask       = %LVIF_TEXT OR %LVIF_PARAM
                   SendMessage(hListView, %LVM_GETITEM, 0, VARPTR(LvItem1))
                   
                   LvItem2.iItem      = LvItemIndex2
                   LvItem2.iSubItem   = Col
                   LvItem2.pszText    = VARPTR(zItem2)
                   LvItem2.cchTextMax = %ListViewItemMaxLen 'SIZEOF(zItem2)
                   LvItem2.mask       = %LVIF_TEXT OR %LVIF_PARAM
                   SendMessage(hListView, %LVM_GETITEM, 0, VARPTR(LvItem2))
                   
                   'SortDirection = 0
                   IF SortDirection = 0 THEN
                     FUNCTION = LvItem1.lParam - LvItem2.lParam
                   ELSE
                     'The comparison function must return a negative value if the first item should precede the second,
                     'a positive value if the first item should follow the second, or zero if the two items are equivalent.
                     FUNCTION = SortDirection * LStrCmpi(zItem1, zItem2) 'Accent, ligature œ æ, and case insensitive, etc...
                   END IF
                   
                  END FUNCTION
                  '______________________________________________________________________________
                   
                  SUB SetHeaderIcons(hListview AS DWORD, ColumnToSort AS LONG, ImageIndex AS LONG)
                   LOCAL  HeaderItem   AS HD_ITEM
                   LOCAL  hHeader      AS DWORD
                   LOCAL  ColumnIndex  AS LONG
                   STATIC IconIdOffset AS LONG
                   
                   'Get handle of list view so we can then get handle of header
                   hHeader = SendMessage(hListview, %LVM_GETHEADER, 0, 0)
                   
                   'Set the format and image for each header
                   FOR ColumnIndex = 0 TO SendMessage(hHeader, %HDM_GETITEMCOUNT, 0, 0) - 1
                     IF ColumnIndex = ColumnToSort - 1 THEN
                   
                       'This is the column being sorted on so set it to use an image
                       HeaderItem.mask = %HDI_FORMAT OR %HDI_IMAGE
                   
                       'HeaderItem.fmt  = %HDF_STRING OR %HDF_IMAGE 'Arrow at left
                       HeaderItem.fmt  = %HDF_STRING OR %HDF_IMAGE OR %HDF_BITMAP_ON_RIGHT 'Arrow at right
                   
                       'Set the up/down image index from the imagelist attached to the header
                       'ColumnToSort =  1 = image 0 v
                       'ColumnToSort = -1 = image 1 ^
                       'ColumnToSort =  0 = image 2 based on lParam
                       HeaderItem.iImage = ImageIndex + (ColumnToSort - 1) * 3  '0, 1, 2...
                     ELSE
                       'This isn't the column being sorted on so set it to text only
                       HeaderItem.mask   = %HDI_FORMAT 'OR %HDF_IMAGE
                       HeaderItem.fmt    = %HDF_STRING
                       HeaderItem.iImage = %I_IMAGENONE
                     END IF
                   
                     'Apply changes
                     SendMessage(hHeader, %HDM_SETITEM, ColumnIndex, VARPTR(HeaderItem))
                   
                   NEXT
                   INCR IconIdOffset
                   IF IconIdOffset = 3 THEN IconIdOffset = 0
                   
                  END SUB
                  '______________________________________________________________________________
                   
                  CALLBACK FUNCTION DlgProc
                   LOCAL  pNotifyListview AS NM_LISTVIEW POINTER
                   LOCAL  HeaderItem      AS HDITEM
                   STATIC hListviewHeader AS DWORD
                   LOCAL  ImageIndex      AS LONG
                   STATIC SubItemIndex    AS LONG
                   STATIC SortDir         AS LONG
                   STATIC hImageList      AS DWORD
                   LOCAL  hIcon           AS DWORD
                   LOCAL  ColumnToSort    AS LONG
                   
                   SELECT CASE CBMSG
                   
                     CASE %WM_INITDIALOG
                       ListViewInit()
                       hListviewHeader = SendMessage(hListview, %LVM_GETHEADER, 0, BYVAL 0)
                   
                       hImageList = ImageList_Create(16, 16, %ILC_MASK OR %ILC_COLOR32, 18, 3)
                       'ImageList_SetBkColor(hImageList, %CLR_NONE)
                   
                       'To use icon from files...
                       'hIcon = LoadImage  (BYVAL %NULL, "SortAscending.ico", %IMAGE_ICON, 16, 16, %LR_LOADFROMFILE) 'Load from an .ico file
                       'hIcon = LoadImage  (BYVAL %NULL, "SortDescending.ico", %IMAGE_ICON, 16, 16, %LR_LOADFROMFILE) 'Load from an .ico file
                   
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\AuxiliaryDisplayCpl.dll", 6) 'Up like the one from Comctl32.dll V6
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\AuxiliaryDisplayCpl.dll", 12) 'Down like the one from Comctl32.dll V6
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 49) 'Blank icon
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                   
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 246) 'Up white triangle with blue border
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 247) 'Down  white triangle with blue border
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 131) 'Red x
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                   
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\xpsrchvw.exe", 5) 'Up big blue arrow
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\xpsrchvw.exe", 7) 'Down big blue arrow
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 144) 'Red check
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                   
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ipsmsnap.dll", 1) 'Up black arrow
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ipsmsnap.dll", 2) 'Down black arrow
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\imageres.dll", 218) 'Red [X] close button
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                   
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\FXSRESM.dll", 19) 'Up little black arrow
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\FXSRESM.dll", 20) 'Down little black arrow
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 219) 'Red interdiction circle
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                   
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ActionCenterCPL.dll", 1) 'Green dot
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ActionCenterCPL.dll", 3) 'Red dot
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                       hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ActionCenterCPL.dll", 2) 'Yellow dot
                       ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                   
                       SendMessage(hListviewHeader, %HDM_SETIMAGELIST, %HDSIL_NORMAL, hImageList)
                       ColumnToSort = 1
                       SetHeaderIcons(hListview, ColumnToSort, 2)
                   
                     CASE %WM_NOTIFY 'Notification
                       pNotifyListview = CBLPARAM
                       IF @pNotifyListview.hdr.hwndFrom = hListView THEN 'Is it the listview
                         IF @pNotifyListview.hdr.code = %LVN_COLUMNCLICK THEN 'Column header click
                           IF @pNotifyListview.iSubItem <> -1 THEN 'Valid column
                   
                             HeaderItem.mask = %HDI_FORMAT 'Ask for sort arrow
                             SendMessage(hListviewHeader, %HDM_GETITEM, SubItemIndex, VARPTR(HeaderItem)) 'Gets previous header HDI_FORMAT info
                             HeaderItem.fmt = HeaderItem.fmt AND &HFFFFF9FF 'Remove HDF_SORTDOWN (0x200) / HDF_SORTUP 0x400) arrow
                             SendMessage(hListviewHeader, %HDM_SETITEM, SubItemIndex, VARPTR(HeaderItem)) 'Update previous header arrow
                             SendMessage(hListviewHeader, %HDM_GETITEM, @pNotifyListview.iSubItem, VARPTR(HeaderItem)) 'Gets current column header HDI_FORMAT info
                             IF SubItemIndex <> @pNotifyListview.iSubItem THEN
                               SortDir = %HDF_SORTUP 'Click on new column so sort ascend
                               ImageIndex   = 0
                             ELSE
                               IF SortDir = 0 THEN
                                 SortDir = %HDF_SORTUP
                                 ImageIndex   = 0
                               ELSEIF  (SortDir AND %HDF_SORTUP) THEN
                                 SortDir = %HDF_SORTDOWN
                                 ImageIndex   = 1
                               ELSE
                                 SortDir = 0 'Will sort on .lParam
                                 ImageIndex   = 2
                               END IF
                             END IF
                             SubItemIndex = @pNotifyListview.iSubItem 'Set SubItemIndex to current column that will become previous column for next sort
                             ColumnToSort = 1 + @pNotifyListview.iSubItem
                             SetHeaderIcons(hListview, ColumnToSort, ImageIndex)
                             SendMessage(hListView, %LVM_SORTITEMSEX, SubItemIndex OR SortDir, CODEPTR(ListViewSort)) 'Sort listview
                   
                           END IF
                         END IF
                       END IF
                   
                     CASE %WM_SIZE
                       SetWindowPos(hListview, %NULL, 2, 2, LOWRD(CBLPARAM) - 4, HIWRD(CBLPARAM) - 4, %SWP_NOZORDER)
                   
                     CASE %WM_DESTROY
                       ImageList_Destroy(hImageList)
                   
                   END SELECT
                   
                  END FUNCTION
                  '______________________________________________________________________________
                   
                  FUNCTION PBMAIN()
                   LOCAL hIcon AS DWORD
                   
                   DIALOG FONT "Segoe UI", 9
                   DIALOG NEW %HWND_DESKTOP, $AppName, , , 333, 80, %WS_CAPTION OR _
                   %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_SYSMENU OR %WS_THICKFRAME, 0 TO hDlg
                   
                   hIcon = ExtractIcon(GetModuleHandle(""), "wmploc.dll", 24)
                   SetClassLong(hDlg, %GCL_HICON, hIcon)
                   SendMessage(hDlg, %WM_SETICON, %ICON_SMALL, hIcon)
                   
                   CONTROL ADD "SysListView32", hDlg, %Listview, "SysListView321", 27, 18, 285, 186, _
                   %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %LVS_REPORT OR _
                   %LVS_SHOWSELALWAYS, %WS_EX_LEFT OR %WS_EX_RIGHTSCROLLBAR
                   
                   DIALOG SHOW MODAL hDlg CALL DlgProc
                   
                   DestroyIcon(hIcon)
                   
                  END FUNCTION
                  '______________________________________________________________________________
                  '
                  Last edited by Pierre Bellisle; 22 Apr 2016, 05:06 PM.

                  Comment


                  • #10
                    Hi Pierre,
                    Thank you (really, a big big thank you) for your listview demo!

                    It seems to capture everything someone might want to do with
                    a listview in 300 lines of code (complete).
                    And a nice little tutorial on imagelists too.

                    And thank you too for the comments (in English yet!).
                    Without those, the demo would have been practically useless (for me at least).

                    I am definately going to steal ... I mean adopt ... this for my app.

                    Thanks also for finding all those icons in the system files,
                    many of which I have not heard about.

                    BTW, I changed the "SysListView32" to PB's internal "ListView" with
                    no (apparent) changes to the functioning of the program.
                    I also changed static hIcon to local with no bad effects.
                    I don't really like statics in the winproc as sometimes they are used
                    for more than one control.

                    One final (OCD) niggle. Is there a way to get the icon to 'hug' the right
                    rather than being immediately after the text?
                    Padding the text would seem to interfere with (header inclusive) auto-sizing.

                    Cheers, Mike.
                    Last edited by Mike Simmonds; 29 Dec 2015, 06:53 PM.
                    There are only two speeds for computers: fast enough, and too bloody slow.
                    And there are 10 types of programmer -- those that know binary, and those that don't.

                    Comment


                    • #11
                      Hey,

                      Steal all you need. My jail has no door. Just a roof for rainy days. :-)

                      There is a lot of icons in Windows system folder.
                      If not already aware, you may use a tool like IconsExtract to get them.

                      For the icon to hug the separator at right, you will have to use an ownerdrawn listview.
                      I think that Börje have a nice example somewhere in the forum.

                      Pierre

                      [Added: I replaced many unneeded STATIC with LOCAL]
                      Last edited by Pierre Bellisle; 29 Dec 2015, 07:49 PM.

                      Comment


                      • #12
                        That last sounds like too much work that will push it over the edge.

                        Again, a big thanks for your concisely wrapped up knowledge on listviews.

                        Cheers, Mike.
                        There are only two speeds for computers: fast enough, and too bloody slow.
                        And there are 10 types of programmer -- those that know binary, and those that don't.

                        Comment


                        • #13
                          I was thinking about your padding idea.
                          Maybe you could do something with GetTextExtentPoint32 and HDM_GETITEMRECT to calculate the padding lenght.

                          I also saw HDM_SETBITMAPMARGIN wich looks very promising...
                          I may experiment with this in the future...

                          Pierre

                          Comment


                          • #14
                            Hi Pierre,

                            Please don't spend any more time on my account, it is good enough
                            (very good indeed) as it is.

                            Cheers, Mike.
                            There are only two speeds for computers: fast enough, and too bloody slow.
                            And there are 10 types of programmer -- those that know binary, and those that don't.

                            Comment


                            • #15
                              Hey Mike,

                              One last, I was curious about padding.
                              Code is not completed, more work to do but I'll stop here.
                              This program shows that your idea is quite feasible.
                              I did subclass the ListView to access the header dividor movement to calculate proper padding...

                              Keyword to look for: SpaceChar, HDM_SETBITMAPMARGIN, HDN_BEGINTRACK, LVM_GETSTRINGWIDTH

                              Check the variable SpaceChar to alternate from an hyphen to a space.

                              Have fun. :-)

                              Pierre


                              Code:
                               
                              #COMPILE EXE '#Win Win 8.04#
                              #INCLUDE "Win32Api.inc"
                              #INCLUDE "CommCtrl.inc"
                              #INCLUDE "ComDlg32.inc"
                              #RESOURCE "SomeResource.pbr" 'RemOut if you do not want a manifest
                               
                              $AppName = "ListView header icon - The dance"
                               
                              %Listview           = 201
                              %StatusBar          = 301
                              %ListViewItemMaxLen = 240
                               
                              %HDSIL_NORMAL       = 0
                              %HDSIL_STATE        = 1
                              %HDF_SORTUP         = &H00000400 'Comctl32.dll Version 6.00. Draws an up-arrow
                              %HDF_SORTDOWN       = &H00000200 'Comctl32.dll Version 6.00. Draws a down-arrow
                               
                              GLOBAL hDlg            AS DWORD
                              GLOBAL hListview       AS DWORD
                              GLOBAL hListViewHeader AS DWORD
                              GLOBAL pListViewProc   AS DWORD
                              '_____________________________________________________________________________________________
                               
                              FUNCTION ListViewInit() AS LONG
                               LOCAL ListViewColumn AS LV_COLUMN
                               LOCAL ListViewItem   AS LV_ITEM
                               LOCAL zBuffer        AS ASCIIZ * %ListViewItemMaxLen
                               LOCAL sBuffer        AS STRING
                               LOCAL ExStyle        AS DWORD
                               LOCAL Row            AS LONG
                               LOCAL RowCount       AS LONG
                               LOCAL Col            AS LONG
                               LOCAL ColumnCount    AS LONG
                               LOCAL IsertionPos    AS LONG
                               
                               sBuffer = "Carlos"   & $TAB & "Arneaud" & $TAB & "Black" & $TAB & "002" & $TAB & "France"  & $TAB & "Mars"    & $CRLF & _
                                         "Béatrice" & $TAB & "Arneaud" & $TAB & "White" & $TAB & "001" & $TAB & "Canada"  & $TAB & "Uranus"  & $CRLF & _
                                         "Anatole"  & $TAB & "Beene"   & $TAB & "Black" & $TAB & "008" & $TAB & "U.S.A."  & $TAB & "Mercure" & $CRLF & _
                                         "Daniel"   & $TAB & "Beene"   & $TAB & "White" & $TAB & "006" & $TAB & "Congo"   & $TAB & "Jupiter" & $CRLF & _
                                         "Émile"    & $TAB & "Beene"   & $TAB & "Black" & $TAB & "001" & $TAB & "U.K."    & $TAB & "Venus"
                               
                               RowCount = PARSECOUNT(sBuffer, $CRLF)
                               DIM RowArray(0 TO RowCount - 1)AS STRING
                               PARSE sBuffer, RowArray(), $CRLF
                               ColumnCount = PARSECOUNT(RowArray(0), $TAB)
                               
                               hListview = GetDlgItem(hDlg, %Listview)
                               ExStyle = %LVS_EX_FULLROWSELECT OR %LVS_EX_GRIDLINES OR %LVS_EX_HEADERDRAGDROP
                               SendMessage(hListview, %LVM_SETEXTENDEDLISTVIEWSTYLE, ExStyle, ExStyle)
                               
                               'Set column headers.
                               ListViewColumn.mask    = %LVCF_FMT OR %LVCF_TEXT OR %LVCF_SUBITEM
                               ListViewColumn.fmt     = %LVCFMT_LEFT
                               ListViewColumn.pszText = VARPTR(zBuffer)
                               ListViewColumn.iOrder  = 0
                               
                               zBuffer = "First name" : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                               zBuffer = "Last name"  : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                               zBuffer = "Color"      : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                               zBuffer = "Number"     : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                               zBuffer = "Country"    : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn)) : INCR ListViewColumn.iOrder
                               zBuffer = "Planet"     : SendMessage(hListview, %LVM_INSERTCOLUMN, ListViewColumn.iOrder, VARPTR(ListViewColumn))
                               
                               'Set data.
                               ListViewItem.pszText = VARPTR(zBuffer)
                               FOR Row = 0 TO RowCount - 1
                                 FOR Col= 0 TO ColumnCount - 1
                                   zBuffer = PARSE$(RowArray(Row), $TAB, Col+ 1)
                                   ListViewItem.iSubItem = Col
                                   IF Col= 0 THEN
                                     ListViewItem.iItem  = Row
                                     ListViewItem.lParam = Row
                                     ListViewItem.mask   = %LVIF_TEXT OR %LVIF_PARAM
                                     IsertionPos = SendMessage(hListview, %LVM_INSERTITEM, 0, VARPTR(ListViewItem)) 'IsertionPos needed if listview have LVS_SORTASCENDING/LVS_SORTDESCENDING
                                   ELSE
                                     ListViewItem.iItem = IsertionPos 'Needed if listview have LVS_SORTASCENDING/LVS_SORTDESCENDING
                                     ListViewItem.mask  = %LVIF_TEXT
                                     SendMessage(hListview, %LVM_SETITEM, 0, VARPTR(ListViewItem))
                                   END IF
                                 NEXT
                               NEXT
                               
                               'Size columns
                               FOR Col= 0 TO ColumnCount - 1
                                 SendMessage(hListview, %LVM_SETCOLUMNWIDTH, Col, 95) 'Static size
                                 'SendMessage(hListview, %LVM_SETCOLUMNWIDTH, Col, MAKLNG(%LVSCW_AUTOSIZE, 0)) 'Auto size on column data
                                 'SendMessage(hListview, %LVM_SETCOLUMNWIDTH, Col, MAKLNG(%LVSCW_AUTOSIZE_USEHEADER, 0)) 'Auto size on header
                               NEXT
                               
                              END FUNCTION
                              '________________________________________________________________________________________
                               
                              FUNCTION ListViewSort(BYVAL LvItemIndex1 AS LONG, BYVAL LvItemIndex2 AS LONG, BYVAL Col AS DWORD) AS LONG
                               STATIC LvItem1       AS LV_ITEM
                               STATIC LvItem2       AS LV_ITEM
                               STATIC zItem1        AS ASCIIZ * %ListViewItemMaxLen
                               STATIC zItem2        AS ASCIIZ * %ListViewItemMaxLen
                               STATIC SortDirection AS LONG
                               
                               IF (Col AND %HDF_SORTDOWN) THEN 'HDF_SORTDOWN, 0x200 is good for up to 512 columns
                                 SortDirection = -1
                               ELSEIF (Col AND %HDF_SORTUP) THEN 'HDF_SORTUP, 0x400
                                 SortDirection = 1
                               ELSE
                                 SortDirection = 0 'Use lParam to sort
                               END IF
                               Col = Col AND &H000000FF 'Discard possible HDF_SORTDOWN = 0x200 or HDF_SORTUP = 0x400
                               
                               LvItem1.iItem      = LvItemIndex1
                               LvItem1.iSubItem   = Col
                               LvItem1.pszText    = VARPTR(zItem1)
                               LvItem1.cchTextMax = %ListViewItemMaxLen 'SIZEOF(zItem1)
                               LvItem1.mask       = %LVIF_TEXT OR %LVIF_PARAM
                               SendMessage(hListView, %LVM_GETITEM, 0, VARPTR(LvItem1))
                               
                               LvItem2.iItem      = LvItemIndex2
                               LvItem2.iSubItem   = Col
                               LvItem2.pszText    = VARPTR(zItem2)
                               LvItem2.cchTextMax = %ListViewItemMaxLen 'SIZEOF(zItem2)
                               LvItem2.mask       = %LVIF_TEXT OR %LVIF_PARAM
                               SendMessage(hListView, %LVM_GETITEM, 0, VARPTR(LvItem2))
                               
                               'SortDirection = 0
                               IF SortDirection = 0 THEN
                                 FUNCTION = LvItem1.lParam - LvItem2.lParam
                               ELSE
                                 'The comparison function must return a negative value if the first item should precede the second,
                                 'a positive value if the first item should follow the second, or zero if the two items are equivalent.
                                 FUNCTION = SortDirection * LStrCmpi(zItem1, zItem2) 'Accent, ligature œ æ, and case insensitive, etc...
                               END IF
                               
                              END FUNCTION
                              '______________________________________________________________________________
                               
                              FUNCTION ListViewProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS LONG, _ 'ListView control subclass
                                                    BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                               LOCAL pHeaderInfo AS NMHEADER POINTER
                               LOCAL HeaderItem  AS HD_ITEM POINTER
                               
                               SELECT CASE wMsg
                                 CASE %WM_NOTIFY
                                   pHeaderInfo = lParam
                                   IF @pHeaderInfo.hdr.hwndFrom = hListViewHeader THEN 'Message from listview header
                                     SELECT CASE @pHeaderInfo.hdr.code
                               
                                       CASE %HDN_BEGINTRACKW, %HDN_TRACKW, %HDN_ENDTRACKW, %HDN_ITEMCHANGINGW, %HDN_ITEMCHANGEDW
                                         'HDN_BEGINTRACK https://msdn.microsoft.com/en-us/library/windows/desktop/bb775263%28v=vs.85%29.aspx
                                         IF @pHeaderInfo.pItem THEN 'Optionnal HDITEM structure pointer
                                           HeaderItem = @pHeaderInfo.pItem
                                           IF (@HeaderItem.mask AND %HDI_WIDTH) THEN
                                             SetWindowText(hDlg, "col =" & STR$(@pHeaderInfo.iItem) & ", x =" & STR$(@HeaderItem.cxy))
                                             LOCAL lvCol       AS LVCOLUMN
                                             LOCAL sText       AS STRING
                                             LOCAL StringWidth AS LONG
                                             LOCAL SpaceWidth  AS LONG
                                             LOCAL SpaceChar   AS STRING
                                             LOCAL ChrCount    AS LONG
                               
                                             SpaceChar        = $SPC 'Calculate the pixel lenght of a space ( ) or a dash (-)
                                             SpaceChar        = "-" 'Rem this line
                                             SpaceWidth       = SendMessage(hListview, %LVM_GETSTRINGWIDTH, 0, STRPTR(SpaceChar))
                               
                                             sText            = NUL$(%MAX_PATH)
                                             lvCol.mask       = %LVCF_TEXT
                                             lvCol.pszText    = STRPTR(sText)
                                             lvCol.cchTextMax = LEN(sText)
                                             SendMessage(hListview, %LVM_GETCOLUMN, @pHeaderInfo.iItem, VARPTR(lvCol)) 'Get column text
                                             sText = RTRIM$(sText, ANY $NUL & $SPC & SpaceChar)
                                             'SetWindowText(hDlg, BYVAL STRPTR(sText))
                               
                                             StringWidth = SendMessage(hListview, %LVM_GETSTRINGWIDTH, 0, STRPTR(sText))
                                             'LVM_GETSTRINGWIDTH https://msdn.microsoft.com/en-us/library/windows/desktop/bb761073%28v=vs.85%29.aspx
                                             'SetWindowText(hDlg, "StringWidth =" & STR$(StringWidth))
                               
                                             ChrCount = (@HeaderItem.cxy - StringWidth) / SpaceWidth - 8 '-8 This will need improovement
                                             'SetWindowText(hDlg, "ChrCount =" & STR$(ChrCount))
                                             sText = sText & STRING$(ChrCount, SpaceChar)
                                             lvCol.iSubItem   = @pHeaderInfo.iItem
                                             lvCol.mask       = %LVCF_TEXT OR %LVCF_SUBITEM
                                             sText            = UCODE$(sText & $NUL) 'Internal listview header is always unicode
                                             lvCol.pszText    = STRPTR(sText)
                                             SendMessage(hListview, %LVM_SETCOLUMNW, @pHeaderInfo.iItem, VARPTR(lvCol))
                                           END IF
                                         END IF
                                     END SELECT
                                   END IF
                               
                               END SELECT
                               
                               FUNCTION = CallWindowProc(pListViewProc, hWnd, wMsg, wParam, lParam)
                               
                              END FUNCTION
                              '______________________________________________________________________________
                               
                              SUB SetHeaderIcons(hListview AS DWORD, ColumnToSort AS LONG, ImageIndex AS LONG)
                               LOCAL HeaderItem  AS HD_ITEM
                               LOCAL hHeader     AS DWORD
                               LOCAL ColumnIndex AS LONG
                               
                               'Get handle of list view so we can then get handle of header
                               hHeader = SendMessage(hListview, %LVM_GETHEADER, 0, 0)
                               
                               LOCAL OldMargin AS LONG
                               OldMargin = SendMessage(hHeader, %HDM_SETBITMAPMARGIN, 2, 0) 'Reduce surronding margin to 2 pix
                               'HDM_SETBITMAPMARGIN https://msdn.microsoft.com/en-us/library/windows/desktop/bb775357%28v=vs.85%29.aspx
                               
                               'Set the format and image for each header
                               FOR ColumnIndex = 0 TO SendMessage(hHeader, %HDM_GETITEMCOUNT, 0, 0) - 1
                                 IF ColumnIndex = ColumnToSort - 1 THEN
                               
                                   'This is the column being sorted on so set it to use an image
                                   HeaderItem.mask = %HDI_FORMAT OR %HDI_IMAGE
                               
                                   'HeaderItem.fmt  = %HDF_STRING OR %HDF_IMAGE 'Arrow at left
                                   HeaderItem.fmt  = %HDF_STRING OR %HDF_IMAGE OR %HDF_BITMAP_ON_RIGHT 'Arrow at right
                               
                                   'Set the up/down image index from the imagelist attached to the header
                                   'ColumnToSort =  1 = image 0 v
                                   'ColumnToSort = -1 = image 1 ^
                                   'ColumnToSort =  0 = image 2 based on lParam
                                   HeaderItem.iImage = ImageIndex + (ColumnToSort - 1) * 3  '0, 1, 2...
                                 ELSE
                                   'This isn't the column being sorted on so set it to text only
                                   HeaderItem.mask   = %HDI_FORMAT 'OR %HDF_IMAGE
                                   HeaderItem.fmt    = %HDF_STRING
                                   HeaderItem.iImage = %I_IMAGENONE
                                 END IF
                               
                                 'Apply changes
                                 SendMessage(hHeader, %HDM_SETITEM, ColumnIndex, VARPTR(HeaderItem))
                               
                               NEXT
                               
                              END SUB
                              '______________________________________________________________________________
                               
                              CALLBACK FUNCTION DlgProc
                               LOCAL  pNotifyListview AS NM_LISTVIEW POINTER
                               LOCAL  HeaderItem      AS HDITEM
                               LOCAL  ImageIndex      AS LONG
                               STATIC SubItemIndex    AS LONG
                               STATIC SortDir         AS LONG
                               STATIC hImageList      AS DWORD
                               STATIC hIcon           AS DWORD
                               STATIC ColumnToSort    AS LONG
                               
                               SELECT CASE CBMSG
                               
                                 CASE %WM_INITDIALOG
                                   ListViewInit()
                                   hListviewHeader = SendMessage(hListview, %LVM_GETHEADER, 0, BYVAL 0)
                                   pListViewProc   = SetWindowLong(hListView, %GWL_WNDPROC, CODEPTR(ListViewProc))
                               
                                   hImageList = ImageList_Create(16, 16, %ILC_MASK OR %ILC_COLOR32, 18, 3)
                                   'ImageList_SetBkColor(hImageList, %CLR_NONE)
                               
                                   'To use .ico from files...
                                   'hIcon = LoadImage  (BYVAL %NULL, "SortAscending.ico", %IMAGE_ICON, 16, 16, %LR_LOADFROMFILE) 'Load from an .ico file
                                   'hIcon = LoadImage  (BYVAL %NULL, "SortDescending.ico", %IMAGE_ICON, 16, 16, %LR_LOADFROMFILE) 'Load from an .ico file
                               
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\AuxiliaryDisplayCpl.dll", 6) 'Up like the one from Comctl32.dll V6
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\AuxiliaryDisplayCpl.dll", 12) 'Down like the one from Comctl32.dll V6
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 49) 'Blank icon
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                               
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 246) 'Up white triangle with blue border
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 247) 'Down  white triangle with blue border
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 131) 'Red x
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                               
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\xpsrchvw.exe", 5) 'Up big blue arrow
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\xpsrchvw.exe", 7) 'Down big blue arrow
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 144) 'Red check
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                               
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ipsmsnap.dll", 1) 'Up black arrow
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ipsmsnap.dll", 2) 'Down black arrow
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\imageres.dll", 218) 'Red [X] close button
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                               
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\FXSRESM.dll", 19) 'Up little black arrow
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\FXSRESM.dll", 20) 'Down little black arrow
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\shell32.dll", 219) 'Red interdiction circle
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                               
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ActionCenterCPL.dll", 1) 'Green dot
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ActionCenterCPL.dll", 3) 'Red dot
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                                   hIcon = ExtractIcon(BYVAL %NULL, "C:\Windows\system32\ActionCenterCPL.dll", 2) 'Yellow dot
                                   ImageList_AddIcon(hImageList, hIcon) : DeleteObject(hIcon)
                               
                                   SendMessage(hListviewHeader, %HDM_SETIMAGELIST, %HDSIL_NORMAL, hImageList)
                                   ColumnToSort = 1
                                   SetHeaderIcons(hListview, ColumnToSort, 2)
                               
                                 CASE %WM_NOTIFY 'Notification
                                   pNotifyListview = CBLPARAM
                                   IF @pNotifyListview.hdr.hwndFrom = hListView THEN 'Is it the listview
                                     IF @pNotifyListview.hdr.code = %LVN_COLUMNCLICK THEN 'Column header click
                                       IF @pNotifyListview.iSubItem <> -1 THEN 'Valid column
                               
                                         HeaderItem.mask = %HDI_FORMAT 'Ask for sort arrow
                                         SendMessage(hListviewHeader, %HDM_GETITEM, SubItemIndex, VARPTR(HeaderItem)) 'Gets previous header HDI_FORMAT info
                                         HeaderItem.fmt = HeaderItem.fmt AND &HFFFFF9FF 'Remove HDF_SORTDOWN (0x200) / HDF_SORTUP 0x400) arrow
                                         SendMessage(hListviewHeader, %HDM_SETITEM, SubItemIndex, VARPTR(HeaderItem)) 'Update previous header arrow
                                         SendMessage(hListviewHeader, %HDM_GETITEM, @pNotifyListview.iSubItem, VARPTR(HeaderItem)) 'Gets current column header HDI_FORMAT info
                                         IF SubItemIndex <> @pNotifyListview.iSubItem THEN
                                           SortDir = %HDF_SORTUP 'Click on new column so sort ascend
                                           ImageIndex   = 0
                                         ELSE
                                           IF SortDir = 0 THEN
                                             SortDir = %HDF_SORTUP
                                             ImageIndex   = 0
                                           ELSEIF  (SortDir AND %HDF_SORTUP) THEN
                                             SortDir = %HDF_SORTDOWN
                                             ImageIndex   = 1
                                           ELSE
                                             SortDir = 0 'Will sort on .lParam
                                             ImageIndex   = 2
                                           END IF
                                         END IF
                                         SubItemIndex = @pNotifyListview.iSubItem 'Set SubItemIndex to current column that will become previous column for next sort
                                         ColumnToSort = 1 + @pNotifyListview.iSubItem
                                         SetHeaderIcons(hListview, ColumnToSort, ImageIndex)
                                         SendMessage(hListView, %LVM_SORTITEMSEX, SubItemIndex OR SortDir, CODEPTR(ListViewSort)) 'Sort listview
                               
                                       END IF
                                     END IF
                                   END IF
                               
                                 CASE %WM_SIZE
                                   SetWindowPos(hListview, %NULL, 2, 2, LOWRD(CBLPARAM) - 4, HIWRD(CBLPARAM) - 4, %SWP_NOZORDER)
                               
                                 CASE %WM_DESTROY
                                   ImageList_Destroy(hImageList)
                                   IF pListViewProc THEN SetWindowLong(hListView, %GWL_WNDPROC, pListViewProc)
                               
                               END SELECT
                               
                              END FUNCTION
                              '______________________________________________________________________________
                               
                              FUNCTION PBMAIN()
                               LOCAL hIcon AS DWORD
                               
                               DIALOG FONT "Segoe UI", 9
                               DIALOG NEW %HWND_DESKTOP, $AppName, , , 333, 80, %WS_CAPTION OR _
                               %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_SYSMENU OR %WS_THICKFRAME, 0 TO hDlg
                               
                               hIcon = ExtractIcon(GetModuleHandle(""), "wmploc.dll", 24)
                               SetClassLong(hDlg, %GCL_HICON, hIcon)
                               SendMessage(hDlg, %WM_SETICON, %ICON_SMALL, hIcon)
                               
                               CONTROL ADD "SysListView32", hDlg, %Listview, "SysListView321", 27, 18, 285, 186, _
                               %WS_CHILD OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %LVS_REPORT OR _
                               %LVS_SHOWSELALWAYS, %WS_EX_LEFT OR %WS_EX_RIGHTSCROLLBAR
                               
                               DIALOG SHOW MODAL hDlg CALL DlgProc
                               
                               DestroyIcon(hIcon)
                               
                              END FUNCTION
                              '______________________________________________________________________________
                              '

                              Comment


                              • #16
                                Originally posted by Pierre Bellisle View Post
                                There is a lot of icons in Windows system folder.
                                If not already aware, you may use a tool like IconsExtract to get them.
                                I downloaded IconsExtract from nirsoft, and it is, indeed, a very useful tool.

                                But there is something that I just can't understand ...

                                The icon numbers hardcoded in you code obviously work (on my system too),
                                but in the IconsExtract program, the numbers are often very different.
                                E.g. AuxilaryDisplayCpl does not have index 6 and index 12 is an alarm clock.
                                Idx 15 to 26 are all various triangle up/down arrows

                                Is it IconsExtract that is screwing up the numbers?

                                EDIT: PeView for AuxilaryDisplayCpl.dll does show that there are icons for 1 to 26. It is IconsExtract that is not showing them (I did not set any filters).

                                Regards, Mike.
                                Last edited by Mike Simmonds; 31 Dec 2015, 04:40 AM.
                                There are only two speeds for computers: fast enough, and too bloody slow.
                                And there are 10 types of programmer -- those that know binary, and those that don't.

                                Comment


                                • #17
                                  I see, I did suggest NirSoft's IconsExtract because they make good freewares.
                                  I tryed it and saw what you mean. They start at 1 instead of 0 and show #1 then jump to show #10 - #26 missing #2 to #9.
                                  If I remember well, those missing ones are probably blank incons entry.
                                  I guess it's not really meant for programmers.

                                  To be honest, I use a modification of Colin Glenn's Icon Browser
                                  My code is not clean enough to post but Colin's original stuff work pretty well.
                                  I think there is a forum thread about good icon utilities. I will tell if I find it.

                                  Pierre

                                  Added: If Gary reads this, he might have a good idea on whats good on the net about this...
                                  Last edited by Pierre Bellisle; 31 Dec 2015, 10:10 AM.

                                  Comment


                                  • #18
                                    Thanks.

                                    As far as IconsExtract goes, it is (apparently) listing the ICONGROUP's
                                    rather than the ICONS.

                                    It is pretty moot anyway, as I copied the numbers out of your sample code.

                                    Thanks, Mike.
                                    There are only two speeds for computers: fast enough, and too bloody slow.
                                    And there are 10 types of programmer -- those that know binary, and those that don't.

                                    Comment

                                    Working...
                                    X