Icon - Displays single items with a large icon and optional text label.
Small icon - same as Icon view but displays a small icon.
Report - Displays data in different columns.
List - Displays a list with small icons.
and with newer versions of Windows, different layouts.
I will break up this tutorial into a few parts. This will be part one, and we will discuss loading the listview, adding columns, displaying icons from the System Imagelist,
displaying a watermark, and deleting selected items.
The following is from MASM32 so all members of structures might not be present, more info on the listview can be found here
You can create a listview control with CreateWindow/Ex and pass it the class name of SysListView32 or you can create one in a resource file, I will use a resource file here.
The listview control has quite a few structures to interact with it for different things, we will be using LVBKIMAGE, LVCOLUMN, LVITEM, and LVHITTESTINFO.
LVBKIMAGE: (Used with LVM_GETBKIMAGE and LVM_SETBKIMAGE - Get/Set Listview background image)
LVBKIMAGEA STRUCT ulFlags DWORD ? hbm DWORD ? pszImage DWORD ? cchImageMax DWORD ? xOffsetPercent DWORD ? yOffsetPercent DWORD ? LVBKIMAGEA ENDS
This structure is used to display a watermark or background image. A funny thing with MS, they say hbm is NOT used but I will show how to use it.
Flags usually tell Windows what you are doing with the control, setting info or getting info.
ulFlags:
- LVBKIF_SOURCE_NONE - This is self explanatory, the listview has no background image. You use this member to remove a background image.
- LVBKIF_SOURCE_HBITMAP - hbm is a handle to a bitmap.
- LVBKIF_SOURCE_URL - pszImage contains the URL or file path of the image. File path is in format file://driveletter/pathtofile/filename.bmp
- LVBKIF_STYLE_NORMAL - background image is displayed normally.
- LVBKIF_STYLE_TILE - image will be tiled to fit entire background of listview.
- LVBKIF_FLAG_TILEOFFSET - sets the coords of the first tile.
- LVBKIF_TYPE_WATERMARK - displays the image as a watermark in the bottom right corner.
- LVBKIF_FLAG_ALPHABLEND - tells listview the bitmap contains a valid alpha channel.
hbm:
Handle of the bitmap to use for the watermark
pszImage:
Address of NULL terminated string containing the path of the image to use.
cchImageMax:
Size of buffer in pszImage. Used only when retrieving the path from listview.
xOffsetPercent:
Horizontal offset % of image. Version 6 of the comctl32.dll uses pixels instead.
yOffsetPercent:
Same as xOffsetPercent but Vertical.
LVCOLUMN: (Used with LVM_GETCOLUMN, LVM_SETCOLUMN, LVM_INSERTCOLUMN, LVM_DELETECOLUMN)
LV_COLUMN STRUCT imask DWORD ? fmt DWORD ? lx DWORD ? pszText DWORD ? cchTextMax DWORD ? iSubItem DWORD ? iImage DWORD ? iOrder DWORD ? LV_COLUMN ENDS
This structure is used to insert/delete columns and get info about columns in listview report mode.
imask: (Tells which structure members contain information)
- LVCF_FMT
- LVCF_WIDTH
- LVCF_TEXT
- LVCF_SUBITEM
- LVCF_IMAGE
- LVCF_ORDER
- LVCF_MINWIDTH
- LVCF_DEFAULTWIDTH
- LVCF_IDEALWIDTH
fmt: (Alignment of header text of columns)
- LVCFMT_LEFT
- LVCFMT_RIGHT
- LVCFMT_CENTER
- LVCFMT_JUSTIFYMASK
- LVCFMT_IMAGE
- LVCFMT_BITMAP_ON_RIGHT
- LVCFMT_COL_HAS_IMAGES
- LVCFMT_FIXED_WIDTH
- LVCFMT_NO_DPI_SCALE
- LVCFMT_FIXED_RATIO
- LVCFMT_LINE_BREAK
- LVCFMT_FILL
- LVCFMT_WRAP
- LVCFMT_NO_TITLE
- LVCFMT_SPLITBUTTON
lx:
Width of colum in pixels
pszText:
Pointer to a NULL terminated string to display as the column text or pointer to buffer to receive text when getting column text.
cchTextMax:
Size of pszText buffer when receiving text.
iSubItem:
Index of subitem to associate with columns
iImage:
zero based index of the image to display from image list
iOrder:
Zero based column offset (zero indicates leftmost column)
LVITEM: (Used with LVM_GETITEM, LVM_SETITEM, LVM_INSERTITEM, and LVM_DELETEITEM )
LV_ITEM STRUCT imask DWORD ? iItem DWORD ? iSubItem DWORD ? state DWORD ? stateMask DWORD ? pszText DWORD ? cchTextMax DWORD ? iImage DWORD ? lParam DWORD ? iIndent DWORD ? LV_ITEM ENDS
imask: (Which members contain data or which members are being requested)
LVIF_DI_SETITEM - Used with a Virtual listview, OS stores info and does not request it again.
LVIF_IMAGE
LVIF_INDENT
LVIF_NORECOMPUTE - Used with a Virtual listview, listview will not send LVN_GETDISPINFO instead pszText will contain LPSTR_TEXTCALLBACK
LVIF_PARAM
LVIF_STATE
LVIF_TEXT
iItem:
Zero based index of item structure info is for.
iSubItem:
One based index of subitem or zero if working with an item
Column1 Column2 Column3 iItem=0/iSubitem=0 iItem=0/iSubitem=1 iItem=0/iSubitem=2 iItem=1/iSubitem=0 iItem=1/iSubitem=1 iItem=1/iSubitem=2 iItem=2/iSubitem=0 iItem=2/iSubitem=1 iItem=2/iSubitem=2 iItem=3/iSubitem=0 iItem=3/iSubitem=1 iItem=3/iSubitem=2
state:
State of item, overlay image, and state image.
stateMask:
Specifies which bits of the state flag we are interested in.
pszText:
Pointer to a NULL terminated string to display as the item text or pointer to buffer to receive text when getting item text.
cchTextMax:
Size of pszText buffer when receiving text.
iImage:
Zero based index of image in image list to display for item.
lParam:
Item value used with LVM_SORTITEMS, if not using then lParam is just a DWORD sized variable.
iIndent:
Indent width of item. Each indent is the width of an image. 1 = indent 1 image width, 2 = indent 2 image widths etc... Only valid for items not subitems
LVHITTESTINFO: (Used with LVM_HITTEST and LVM_SUBITEMHITTEST - members receive info)
LV_HITTESTINFO STRUCT pt POINT <> flags DWORD ? iItem DWORD ? iSubItem DWORD ? LV_HITTESTINFO ENDS
pt:
Client coords to hit test on.
flags: (variable that will hold the result of a Hit Test)
LVHT_ABOVE
LVHT_BELOW
LVHT_NOWHERE
LVHT_ONITEMICON
LVHT_ONITEMLABEL
LVHT_ONITEMSTATEICON
LVHT_TOLEFT
LVHT_TORIGHT
iItem:
This will be the index of matching item, if hit testing on a subitem, this will be subitems parent index
iSubItem:
Index of subitem. Will be zero for a parent item
Listview.asm
invoke CoInitialize, 0
call InitSysImageList
; Make sure we can theme our app
invoke LoadLibrary, offset szuxtheme
.if eax !=0
mov hThemeLib, eax
invoke GetProcAddress, eax, offset szThemeProc
mov hThemeProc, eax
.else
mov hThemeLib, FALSE
.endif
invoke GetModuleHandle, NULL
mov hInst, eax
invoke DialogBoxParam, eax, IDD_MAIN, HWND_DESKTOP, offset ProcMainDlg, NULL
invoke CoUninitialize
invoke ImageList_Destroy, himlReport
.if hThemeLib
invoke FreeLibrary, hThemeLib
.endif
invoke ExitProcess, 0
To display background images, the listview uses COM so we must make sure the COM library is initialized for our thread with CoInitialize. Although this does not seem to be needed on my Win7 machine, we do it to be compatible with earlier versions of Windows.
In order for all controls in our window to look "uniform" on XP and above, we "Theme" our window. We do this by trying to load the uxtheme.dll, if we can load it, then it is on the users system so get the address of the EnableThemeDialogTexture procedure.
Before we exit, we free up what we created.
InitSysImageList proc
invoke LoadLibrary, offset szShell32
xchg eax, ebx
invoke GetProcAddress, ebx, FILEICONINIT
.if eax !=0
push TRUE
call eax ; FileIconInit
.endif
invoke GetProcAddress, ebx, SHELL_GETIMAGELISTS
.if eax !=0
push offset himlSysSm
push offset himlSysLg
call eax ; Shell_GetImageLists
.endif
ret
InitSysImageList endp
Sure, you could use SHGetFileInfo to get a handle to the system imagelist, but it will not contain all images. This is where our InitSysImageList proc comes in.
FileIconInit is only available on NT and must be called by ordinal - 660, it just initializes the system image list for us.
Next we call Shell_GetImageLists which returns the handle for the large and small system imagelists - ordinal 71
Now that we have handles to the large and small system imagelists, we can use almost all ImageList_ API calls. I say almost all because you should NEVER add or remove icons from the system imagelist nor should you ever delete the system imagelist.
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
LoadNormalIcons proc Count:DWORD
push ebx
push esi
push edi
push ebp
mov edi, himlSysLg
mov esi, hLVIcon
invoke ImageList_GetImageCount, edi
xchg eax, ebx
dec dword ptr [esp + 20]
mov ebp, offset lvi
mov (LVITEM ptr[ebp]).imask, LVIF_IMAGE
mov Counter, 0
NextIcon:
invoke ImageList_GetIcon, edi, ebx, 0
test eax, eax
jz BadHandle
invoke DestroyIcon, eax
invoke GetDlgItemInt, hMain, TOTAL_GOOD_ICONS_STC, NULL, FALSE
inc eax
invoke SetDlgItemInt, hMain, TOTAL_GOOD_ICONS_STC, eax, FALSE
mov (LVITEM ptr[ebp]).iItem, ebx
mov (LVITEM ptr[ebp]).iImage, ebx
invoke SendMessage, esi, LVM_INSERTITEM, 0, ebp
jmp @F
BadHandle:
inc dword ptr [esp + 20]
mov ecx, [esp + 20]
invoke SetDlgItemInt, hMain, TOTAL_BAD_ICONS_STC, ecx, FALSE
@@:
invoke SetDlgItemInt, hMain, TOTAL_ICONS_STC, Counter, FALSE
inc Counter
dec ebx
jns NextIcon
invoke InvalidateRect, hMain, NULL, FALSE
pop ebp
pop edi
pop esi
pop ebx
ret 4
LoadNormalIcons endp
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
This turns off the creation of Prologue and Epilogue code. Any procedures following this, will not have Pro/Epilogue code created.
LoadNormalIcons is where we will enumerate the icons in the system imagelist and add to the listview.
mov edi, himlSysLg
mov esi, hLVIcon
invoke ImageList_GetImageCount, edi
xchg eax, ebx
dec dword ptr [esp + 20]
mov ebp, offset lvi
mov (LVITEM ptr[ebp]).imask, LVIF_IMAGE
mov Counter, 0
We are setting edi to the handle of the large system image listview
esi will be the handle of the Icon listview.
Then we get the count of icons in the imagelist and save the count to ebx
Since I want to use ebp in code, I won't use "locals", instead I pushed a param on the stack and will use that [esp + 20]. This will be our var that will hold the number of bad icon handles.
Next we will move the address of the lvi structure into ebp and tell the listview to expect an index of the icon to display.
Counter is the current index of iItem
NextIcon:
invoke ImageList_GetIcon, edi, ebx, 0
test eax, eax
jz BadHandle
invoke DestroyIcon, eax
invoke GetDlgItemInt, hMain, TOTAL_GOOD_ICONS_STC, NULL, FALSE
inc eax
invoke SetDlgItemInt, hMain, TOTAL_GOOD_ICONS_STC, eax, FALSE
mov (LVITEM ptr[ebp]).iItem, ebx
mov (LVITEM ptr[ebp]).iImage, ebx
invoke SendMessage, esi, LVM_INSERTITEM, 0, ebp
jmp @F
BadHandle:
inc dword ptr [esp + 20]
mov ecx, [esp + 20]
invoke SetDlgItemInt, hMain, TOTAL_BAD_ICONS_STC, ecx, FALSE
@@:
invoke SetDlgItemInt, hMain, TOTAL_ICONS_STC, Counter, FALSE
inc Counter
dec ebx
jns NextIcon
This is our loop to enumerate the icons in the system imagelist.
I do not know why, but there some images that are black in my system imagelist, so I call ImageList_GetIcon to get the handle of the icon at the current index, and if the handle is zero I skip it
and increase our bad handle counter at [esp + 20]. We are responsible for freeing the returned icon handle, so we do that with DestroyIcon.
Next, we get the int being displayed for total good icons, and increase the value and redisplay it.
Next, we set iItem and iImage to current value in ebx and display it in the listview with LVM_INSERTITEM.
BadHandle is where we increase our counter and the total bad handle count display.
Once we are done loading the listview, we force a redraw to display the watermark correctly.
GetMetrics proc
push ebx
push esi
push edi
push ebp
mov lvi2.imask, LVIF_TEXT
xor ebx, ebx
mov esi, offset szLabel
mov edi, offset szDesc
lea ebp, iIndex
NextItem:
mov lvi2.iSubItem, 0
mov lvi2.iItem, ebx
mov eax, [esi + 4 * ebx]
mov lvi2.pszText, eax
invoke SendMessage, hLVReport, LVM_INSERTITEM, 0, offset lvi2
inc lvi2.iSubItem
mov eax, [edi + 4 * ebx]
mov lvi2.pszText, eax
invoke SendMessage, hLVReport, LVM_SETITEM, 0, offset lvi2
push [ebp + 4 * ebx]
call GetSystemMetrics
invoke wsprintf, offset lpBuffer, offset szFormat, eax
inc lvi2.iSubItem
mov lvi2.pszText, offset lpBuffer
invoke SendMessage, hLVReport, LVM_SETITEM, 0, offset lvi2
inc ebx
cmp ebx, NUMLINES
jna NextItem
invoke SendMessage, hLVReport, LVM_SETCOLUMNWIDTH, 0, LVSCW_AUTOSIZE_USEHEADER
invoke SendMessage, hLVReport, LVM_SETCOLUMNWIDTH, 1, LVSCW_AUTOSIZE_USEHEADER
invoke SendMessage, hLVReport, LVM_SETCOLUMNWIDTH, 2, LVSCW_AUTOSIZE_USEHEADER
pop ebp
pop edi
pop esi
pop ebx
ret
GetMetrics endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
We have 3 arrays, 2 are arrays of pointers to strings (szLabel, and szDesc) and an array of dwords (iIndex) that are constants for GetSystemMetrics.
In our loop (NextItem), we loop through eacy array item displaying the string. The 3rd array contained in ebp, we pass the value to GetSystemMetrics, convert the return to a string, and display.
The last 3 invokes are the interesting bit. When you pass a listview in report mode the message LVM_SETCOLUMNWIDTH, and use the special value - LVSCW_AUTOSIZE_USEHEADER, the listview will autosize each column
to fit its longest string, for the last column, it will fill the rest of the listview width.
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
This turns back on the default Pro/Epilogue.
Dialog Procedures.asm
ProcTabIcon:
mov lvbi.ulFlags, LVBKIF_TYPE_WATERMARK
invoke LoadImage, NULL, offset szLVBitmap, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION or LR_LOADFROMFILE
mov lvbi.hbm, eax
invoke SendMessage, hLVIcon, LVM_SETBKIMAGE, 0, addr lvbi
invoke SendMessage, hLVIcon, LVM_SETIMAGELIST, LVSIL_NORMAL, himlSysLg
invoke SendMessage, hLVIcon, LVM_SETIMAGELIST, LVSIL_SMALL, himlSysSm
invoke SendMessage, hLVIcon, LVM_SETEXTENDEDLISTVIEWSTYLE, LVS_EX_DOUBLEBUFFER, LVS_EX_DOUBLEBUFFER
Here we are setting the watermark for the listview.Tell the listview we want a watermark with the flag LVBKIF_TYPE_WATERMARK.
You can use a bitmap from the resource section, or from a file. Here we are using a file. szLVBitmap == dic.bmp and it is in the apps directory. Load with LoadImage, put the returned handle into the hbm member
of LVBKIMAGE and set it with SendMessage. The listview takes ownership of the bitmap, so no need to delete the handle.
For our Icon listview, we need to set the large and small imageists to it. I also set an extended listview style of Double Buffer, so the images won't flicker when scrolling.
What is not shown here and is VERY IMPORTANT, is to tell the listview to "share imagelists" (since we are using the system imagelist), by setting the LVS_SHAREIMAGELISTS style bit in the resource file as I did, or use that style setting when using CreateWindowEx.
If we don't use this style, then once the listview is destroyed, it will destroy the imagelist also.
There are 3 radio buttons that will change the "views" of the listview. We change the view with the message LVM_SETVIEW.
ProcTabReport:
Right click an item in the Report view listview and a menu will show up to allow you to delete an item.
That popup is created with the following:
invoke CreatePopupMenu xchg eax, esi mov hReportPopup, esi invoke AppendMenu, esi, MF_POPUP, IDM_DELETE, offset szDelete
we use the ID IDM_DELETE to handle the menu selection in WM_COMMAND.
.elseif eax == WM_NOTIFY
.if wParam == LSV_REPORT
mov edi, lParam
mov ecx, (NMHDR ptr[edi]).code
.if ecx == NM_RCLICK
invoke GetCursorPos, addr pt
invoke ScreenToClient, (NMHDR ptr [edi]).hwndFrom, addr pt
push pt.x
pop lvhti.pt.x
push pt.y
pop lvhti.pt.y
invoke SendMessage, (NMHDR ptr [edi]).hwndFrom, LVM_HITTEST, 0, addr lvhti
test eax, eax
js @F
mov dwItemIndex, eax
invoke GetCursorPos, addr pt
invoke TrackPopupMenu, hReportPopup, TPM_LEFTBUTTON, pt.x, pt.y, NULL, hWin, NULL
.endif
.endif
@@:
To show the right click popup menu, we handle the WM_NOTIFY and check to see if the message is from our listview. If it is, then we check for the NM_RCLICK code. Once we receive this code, we call GetCursor pos then convert the POINT coords to client coords and pass these converted coords to this listview to get the index of the item that was right clicked. We save that index to the variable dwItemIndex so we know which item to, well, delete.
We get the Cursor position again and display the right click menu with TrackPopUpMenu and we use TPM_LEFTBUTTON, I do this because I only want the left mouse button to "fire" the menu selection.

This should help get started understanding the Listview control. As usual, exe and full source is attatched. Modify, learn, and just have fun with it!
Attached File(s)
-
Listview.zip (18.47K)
Number of downloads: 242
This post has been edited by GunnerInc: 31 March 2012 - 06:11 PM







MultiQuote




|