📄 lion-tutorial31.htm
字号:
<p> mov lvi.imask,LVIF_TEXT+LVIF_PARAM <br>
push row <br>
pop lvi.iItem <br>
mov lvi.iSubItem,0 </p>
<p>We will supply the label of the item and the value in lParam so we put <b>LVIF_TEXT</b>
and <b>LVIF_PARAM</b> flags into imask. Next we set the iItem to the row number
passed to the function and since this is the main item, we must filliSubItem
with 0 (column 0).</p>
<p> lea eax,[edi].cFileName <br>
mov lvi.pszText,eax <br>
push row <br>
pop lvi.lParam </p>
<p>Next we put the address of the label, in this case, the name of the file in
<b>WIN32_FIND_DATA</b> structure, into <b>pszText</b>. Because we will implement
sorting in the listview control, we must fill <b>lParam</b> with a value. I
choose to put the row number into this member so I can retrieve the item info
by its index.</p>
<p> invoke SendMessage,hList, LVM_INSERTITEM,0, addr lvi </p>
<p>When all necessary fields in <b>LV_ITEM</b> are filled, we send <b>LVM_INSERTITEM</b>
message to the listview control to insert the item into it. </p>
<p> mov lvi.imask,LVIF_TEXT <br>
inc lvi.iSubItem <br>
invoke wsprintf,addr buffer, addr template,[edi].nFileSizeLow <br>
lea eax,buffer <br>
mov lvi.pszText,eax </p>
<p>We will set the subitem associated with the item just inserted into the second
column. A subitem can only have a label. Thus we specify <b>LVIF_TEXT</b> in
imask. Then we specify the column that the subitem should reside in <b>iSubItem</b>.
In this case, we set it to 1 by incrementing <b>iSubItem</b>. The label we will
use is the size of the file. However, we must convert it to a string first by
calling <b>wsprintf</b>. Then we put the address of the string into <b>pszText</b>.
</p>
<p> invoke SendMessage,hList,LVM_SETITEM, 0,addr lvi <br>
assume edi:nothing <br>
ret <br>
ShowFileInfo endp <br>
</p>
<p>When all necessary fields in<b> LV_ITEM</b> are filled, we send <b>LVM_SETITEM</b>
message to the listview control, passing to it the address of the <b>LV_ITEM</b>
structure. Note that we use <b>LVM_SETITEM</b>, not <b>LVM_INSERTITEM</b> because
a subitem is considered as a property of an item. Thus we *set* the property
of the item, not inserting a new item.</p>
<p>When all items are inserted into the listview control, we set the text and
background colors of the listview control.</p>
<p> RGB 255,255,255 <br>
invoke SendMessage,hList,LVM_SETTEXTCOLOR,0,eax <br>
RGB 0,0,0 <br>
invoke SendMessage,hList,LVM_SETBKCOLOR,0,eax <br>
RGB 0,0,0 <br>
invoke SendMessage,hList,LVM_SETTEXTBKCOLOR,0,eax </p>
<p>I use RGB macro to convert the red, green,blue values into eax and use it to
specify the color we need. We set the foreground and background colors of the
text with <b>LVM_SETTEXTCOLOR </b>and <b>LVM_SETTEXTBKCOLOR</b> messages. We
set the background color of the listview control by sending <b>LVM_SETBKCOLOR</b>
message to the listview control.</p>
<p> invoke GetMenu,hWnd <br>
mov hMenu,eax <br>
invoke CheckMenuRadioItem,hMenu,IDM_ICON,IDM_LIST, IDM_REPORT,MF_CHECKED
</p>
<p>We will let the user chooses the views he wants via the menu. Thus we must
obtain the menu handle first. To help the user track the current view, we put
a radio button system in our menu. The menu item that reflects the current view
will be preceded by a radio button. That's why we call <b>CheckMenuRadioItem</b>.
This function will put a radio button before a menu item.</p>
<p>Note that we create the listview control with width and height equal to 0.
It will be resized later whenever the parent window is resized. This way, we
can ensure that the size of the listview control will always match that of the
parent window. In our example, we want the listview control to fill the whole
client area of the parent window.</p>
<p> .elseif uMsg==WM_SIZE<br>
mov eax,lParam <br>
mov edx,eax <br>
and eax,0ffffh <br>
shr edx,16 <br>
invoke MoveWindow,hList, 0, 0, eax,edx,TRUE </p>
<p>When the parent window receives WM_SIZE message, the low word of lParam contains
the new width of the client area and the high word the new height. Then we call<b>
MoveWindow</b> to resize the listview control to cover the whole client area
of the parent window.</p>
<p>When the user selects a view in the menu. We must change the view in the listview
control accordingly. We accomplish this by setting a new style in the listview
control with <b>SetWindowLong</b>.</p>
<p> .elseif uMsg==WM_COMMAND <br>
.if lParam==0 <br>
invoke GetWindowLong,hList,GWL_STYLE <br>
and eax,not LVS_TYPEMASK </p>
<p>The first thing we do is to obtain the current styles of the listview control.
Then we clear the old view style from the returned style flags. <b>LVS_TYPEMASK</b>
is a constant that is the combined value of all 4 view style constants (<b>LVS_ICON+LVS_SMALLICON+LVS_LIST+LVS_REPORT</b>).
Thus when we perform <b>and</b> operation on the current style flags with the
value "not LVS_TYPEMASK", it amounts to clearing away the current
view style.</p>
<p>In designing the menu, I cheat a little. I use the view style constants as
the menu IDs.</p>
<p>IDM_ICON equ LVS_ICON <br>
IDM_SMALLICON equ LVS_SMALLICON <br>
IDM_LIST equ LVS_LIST <br>
IDM_REPORT equ LVS_REPORT </p>
<p>Thus when the parent window receives WM_COMMAND message, the desired view style
is in the low word of wParam as the menu ID.</p>
<p> mov edx,wParam <br>
and edx,0FFFFh </p>
<p>We have the desired view style in the low word of wParam. All we have to do
is to zero out the high word.</p>
<p> push edx <br>
or eax,edx </p>
<p>And add the desired view style to the existing styles (minus the current view
style) of the listview control.</p>
<p> invoke SetWindowLong,hList,GWL_STYLE,eax </p>
<p>And set the new styles with <b>SetWindowLong</b>.</p>
<p> pop edx <br>
invoke CheckMenuRadioItem,hMenu,IDM_ICON,IDM_LIST,
edx,MF_CHECKED <br>
.endif </p>
<p>We also need to put the radio button in front of the selected view menu item.
Thus we call <b>CheckMenuRadioItem</b>, passing the current view style (double
as menu ID) to it.</p>
<p>When the user clicks on the column headers in the report view, we want to sort
the items in the listview control. We must respond to <b>WM_NOTIFY</b> message.</p>
<p> .elseif uMsg==WM_NOTIFY <br>
push edi <br>
mov edi,lParam <br>
assume edi:ptr NMHDR <br>
mov eax,[edi].hwndFrom <br>
.if eax==hList </p>
<p>When we receive <b>WM_NOTIFY</b> message, lParam contains the pointer to an
<b>NMHDR</b> structure. We can check if this message is from the listview control
by comparing the<b> hwndFrom</b> member of <b>NMHDR</b> to the handle to the
listview control. If they match, we can assume that the notification came from
the listview control.</p>
<p> .if [edi].code==LVN_COLUMNCLICK <br>
assume edi:ptr NM_LISTVIEW </p>
<p>If the notification is from the listview control, we check if the code is <b>LVN_COLUMNCLICK</b>.
If it is, it means the user clicks on a column header. In the case that the
code is <b>LVN_COLUMNCLICK</b>, we can assume that lParam contains the pointer
to an <b>NM_LISTVIEW</b> structure which is a superset of the <b>NMHDR</b> structure.
We then need to know on which column header the user clicks. Examination of
<b>iSubItem</b> member reveals this info. The value in iSubItem can be treated
as the column number, starting from 0.</p>
<p> .if [edi].iSubItem==1 <br>
.if SizeSortOrder==0
|| SizeSortOrder==2 </p>
<p>In the case iSubItem is 1, it means the user clicks on the second column, size.
We use state variables to keep the current status of the sorting order. 0 means
"no sorting yet", 1 means "sort ascending", 2 means "sort
descending". If the items/subitems in the column are not sorted before,
or sorted descending, we set the sorting order to ascending.</p>
<p> invoke
SendMessage,hList,LVM_SORTITEMS,1,addr CompareFunc </p>
<p>We send <b>LVM_SORTITEMS</b> message to the listview control, passing 1 in
wParam and the address of our comparison function in lParam. Note that the value
in wParam is user-defined, you can use it in any way you like. I use it as the
sorting method in this example. We will take a look at the comparison function
first.</p>
<p>CompareFunc proc uses edi lParam1:DWORD, lParam2:DWORD, SortType:DWORD <br>
LOCAL buffer[256]:BYTE <br>
LOCAL buffer1[256]:BYTE <br>
LOCAL lvi:LV_ITEM <br>
<br>
mov lvi.imask,LVIF_TEXT <br>
lea eax,buffer <br>
mov lvi.pszText,eax <br>
mov lvi.cchTextMax,256 </p>
<p>In the comparison function, the listview control will pass lParams (in LV_ITEM)
of the two items it needs to compare to us in lParam1 and lParam2. You'll recall
that we put the index of the item in lParam. Thus we can obtain information
about the items by querying the listview control using the indexes. The info
we need is the labels of the items/subitems being sorted. Thus we prepare an<b>
LV_ITEM</b> structure for such purpose, specifying <b>LVIF_TEXT</b> in <b>imask</b>
and the address of the buffer in <b>pszText</b> and the size of the buffer in
<b>cchTextMax</b>.</p>
<p> .if SortType==1 <br>
mov lvi.iSubItem,1 <br>
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam1,addr lvi
</p>
<p>If the value in SortType is 1 or 2, we know that the size column is clicked.
1 means sort the items according to their sizes in ascending order. 2 means
the reverse. Thus we specify<b> iSubItem</b> as 1 ( to specify the size column)
and send <b>LVM_GETITEMTEXT</b> message to the listview control to obtain the
label (size string) of the subitem.</p>
<p> invoke String2Dword,addr buffer <br>
mov edi,eax </p>
<p>Covert the size string into a dword value with String2Dword which is the function
I wrote. It returns the dword value in eax. We store it in edi for comparison
later.</p>
<p> invoke SendMessage,hList,LVM_GETITEMTEXT,lParam2,addr lvi
<br>
invoke String2Dword,addr buffer <br>
sub edi,eax <br>
mov eax,edi </p>
<p>Do likewise with the value in lParam2. When we have the sizes of the two files,
we can then compare them.<br>
The rule of the comparison function is as follows:</p>
<ul>
<li>If the first item should precede the other, you must return a negative value
in eax</li>
<li>If the second item should precede the first one, you must return a positive
value in eax</li>
<li>If both items are equal, you must return zero in eax.</li>
</ul>
<p>In this case, we want to sort the items according to their sizes in ascending
order. Thus we can simply subtract the size of the first item with that of the
second one and return the result in eax.</p>
<p> .elseif SortType==3 <br>
mov lvi.iSubItem,0 <br>
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam1,addr lvi
<br>
invoke lstrcpy,addr buffer1,addr buffer <br>
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam2,addr lvi
<br>
invoke lstrcmpi,addr buffer1,addr buffer <br>
</p>
<p>In case the user clicks the filename column, we must compare the names of the
files. We first obtain the filenames and then compare them with lstrcmpi function.
We can return the return value of lstrcmpi without any modification since it
also uses the same rule of comparison, eg. negative value in eax if the first
string is less than the second string.</p>
<p> When the items were sorted, we need to update the lParam values of all items
to reflect the new indexes by calling UpdatelParam function.</p>
<p> invoke UpdatelParam
<br>
mov SizeSortOrder,1
</p>
<p>This function simply enumerates all items in the listview control and updates
the values in lParam with the new indexes. We need to do this else the next
sort will not work as expected because our assumption is that the value in lParam
is the index of the item.</p>
<p> .elseif [edi].code==NM_DBLCLK <br>
invoke ShowCurrentFocus <br>
.endif </p>
<p>When the user double-clicks at an item, we want to display a message box with
the label of the item on it. We must check if the code in <b>NMHDR</b> is <b>NM_DBLCLK</b>.
If it is, we can proceed to obtain the label and display it in a message box.</p>
<p>ShowCurrentFocus proc <br>
LOCAL lvi:LV_ITEM <br>
LOCAL buffer[256]:BYTE <br>
<br>
invoke SendMessage,hList,LVM_GETNEXTITEM,-1, LVNI_FOCUSED</p>
<p>How do we know which item is double-clicked? When an item is clicked or double-clicked,
its state is set to "focused". Even if many items are hilited (selected),
only one of them has got the focus. Our job than is to find the item that has
the focus. We do this by sending <b>LVM_GETNEXTITEM</b> message to the listview
control, specifying the desired state in lParam. -1 in wParam means search all
items. The index of the item is returned in eax.</p>
<p> mov lvi.iItem,eax <br>
mov lvi.iSubItem,0 <br>
mov lvi.imask,LVIF_TEXT <br>
lea eax,buffer <br>
mov lvi.pszText,eax <br>
mov lvi.cchTextMax,256 <br>
invoke SendMessage,hList,LVM_GETITEM,0,addr lvi </p>
<p>We then proceed to obtain the label by sending<b> LVM_GETITEM</b> message to
the listview control.</p>
<p> invoke MessageBox,0, addr buffer,addr AppName,MB_OK </p>
<p>Lastly, we display the label in a message box.</p>
<p>If you want to know how to use icons in the listview control, you can read
about it in my treeview tutorial. The steps are just about the same.<strong>
</strong></p>
<hr size="1">
<div align="center"> This article come from Iczelion's asm page, Welcom to <a href="http://asm.yeah.net">http://asm.yeah.net</a></div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -