📄 tut31.html
字号:
assume edi:nothing <br>
ret <br>
ShowFileInfo endp <br>
</font></p>
<p><font face="MS Sans Serif" size="-1">When all necessary fields in<font color="#CCFFCC"><b>
LV_ITEM</b></font> are filled, we send <font color="#CCFFCC"><b>LVM_SETITEM</b></font>
message to the listview control, passing to it the address of the <font color="#CCFFCC"><b>LV_ITEM</b></font>
structure. Note that we use <font color="#CCFFCC"><b>LVM_SETITEM</b></font>,
not <font color="#CCFFCC"><b>LVM_INSERTITEM</b></font> because a subitem is
considered as a property of an item. Thus we *set* the property of the item,
not inserting a new item.</font></p>
<p><font face="MS Sans Serif" size="-1">When all items are inserted into the listview
control, we set the text and background colors of the listview control.</font></p>
<p><font face="Fixedsys"> 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 </font></p>
<p><font face="MS Sans Serif" size="-1">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 <font color="#CCFFCC"><b>LVM_SETTEXTCOLOR
</b></font>and <font color="#CCFFCC"><b>LVM_SETTEXTBKCOLOR</b></font> messages.
We set the background color of the listview control by sending <font color="#CCFFCC"><b>LVM_SETBKCOLOR</b></font>
message to the listview control.</font></p>
<p><font face="Fixedsys"> invoke GetMenu,hWnd <br>
mov hMenu,eax <br>
invoke CheckMenuRadioItem,hMenu,IDM_ICON,IDM_LIST, IDM_REPORT,MF_CHECKED
</font></p>
<p><font face="MS Sans Serif" size="-1">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 <font color="#FFFFCC"><b>CheckMenuRadioItem</b></font>. This function
will put a radio button before a menu item.</font></p>
<p><font face="MS Sans Serif" size="-1">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.</font></p>
<p><font face="Fixedsys"> .elseif uMsg==WM_SIZE<br>
</font><font face="Fixedsys">mov eax,lParam <br>
mov edx,eax <br>
and eax,0ffffh <br>
shr edx,16 <br>
invoke MoveWindow,hList, 0, 0, eax,edx,TRUE </font></p>
<p><font face="MS Sans Serif" size="-1">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<font color="#FFFFCC"><b> MoveWindow</b></font>
to resize the listview control to cover the whole client area of the parent
window.</font></p>
<p><font face="MS Sans Serif" size="-1">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 <font color="#FFFFCC"><b>SetWindowLong</b></font>.</font></p>
<p><font face="Fixedsys"> .elseif uMsg==WM_COMMAND <br>
.if lParam==0 <br>
invoke GetWindowLong,hList,GWL_STYLE <br>
and eax,not LVS_TYPEMASK </font></p>
<p><font face="MS Sans Serif" size="-1">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. <font color="#CCFFCC"><b>LVS_TYPEMASK</b></font> is
a constant that is the combined value of all 4 view style constants (<font color="#CCFFCC"><b>LVS_ICON+LVS_SMALLICON+LVS_LIST+LVS_REPORT</b></font>).
Thus when we perform <font color="#FFCCCC"><b>and</b></font> operation on the
current style flags with the value "not LVS_TYPEMASK", it amounts
to clearing away the current view style.</font></p>
<p><font face="MS Sans Serif" size="-1">In designing the menu, I cheat a little.
I use the view style constants as the menu IDs.</font></p>
<p><font face="Fixedsys">IDM_ICON equ LVS_ICON <br>
IDM_SMALLICON equ LVS_SMALLICON <br>
IDM_LIST equ LVS_LIST <br>
IDM_REPORT equ LVS_REPORT </font></p>
<p><font face="MS Sans Serif" size="-1">Thus when the parent window receives WM_COMMAND
message, the desired view style is in the low word of wParam as the menu ID.</font></p>
<p><font face="Fixedsys"> mov edx,wParam <br>
and edx,0FFFFh </font></p>
<p><font face="MS Sans Serif" size="-1">We have the desired view style in the
low word of wParam. All we have to do is to zero out the high word.</font></p>
<p><font face="Fixedsys"> push edx <br>
or eax,edx </font></p>
<p><font face="MS Sans Serif" size="-1">And add the desired view style to the
existing styles (minus the current view style) of the listview control.</font></p>
<p><font face="Fixedsys"> invoke SetWindowLong,hList,GWL_STYLE,eax
</font></p>
<p><font face="MS Sans Serif" size="-1">And set the new styles with <font color="#FFFFCC"><b>SetWindowLong</b></font>.</font></p>
<p><font face="Fixedsys"> pop edx <br>
invoke CheckMenuRadioItem,hMenu,IDM_ICON,IDM_LIST,
edx,MF_CHECKED <br>
.endif </font></p>
<p><font face="MS Sans Serif" size="-1">We also need to put the radio button in
front of the selected view menu item. Thus we call <font color="#FFFFCC"><b>CheckMenuRadioItem</b></font>,
passing the current view style (double as menu ID) to it.</font></p>
<p><font face="MS Sans Serif" size="-1">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 <font color="#CCFFCC"><b>WM_NOTIFY</b></font> message.</font></p>
<p><font face="Fixedsys"> .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 </font></p>
<p><font face="MS Sans Serif" size="-1">When we receive <font color="#CCFFCC"><b>WM_NOTIFY</b></font>
message, lParam contains the pointer to an <font color="#CCFFCC"><b>NMHDR</b></font>
structure. We can check if this message is from the listview control by comparing
the<font color="#FFFFCC"><b> hwndFrom</b></font> member of <font color="#CCFFCC"><b>NMHDR</b></font>
to the handle to the listview control. If they match, we can assume that the
notification came from the listview control.</font></p>
<p><font face="Fixedsys"> .if [edi].code==LVN_COLUMNCLICK
<br>
assume edi:ptr NM_LISTVIEW </font></p>
<p><font face="MS Sans Serif" size="-1">If the notification is from the listview
control, we check if the code is <font color="#CCFFCC"><b>LVN_COLUMNCLICK</b></font>.
If it is, it means the user clicks on a column header. In the case that the
code is <font color="#CCFFCC"><b>LVN_COLUMNCLICK</b></font>, we can assume that
lParam contains the pointer to an <font color="#CCFFCC"><b>NM_LISTVIEW</b></font>
structure which is a superset of the <font color="#CCFFCC"><b>NMHDR</b></font>
structure. We then need to know on which column header the user clicks. Examination
of <font color="#FFFFCC"><b>iSubItem</b></font> member reveals this info. The
value in iSubItem can be treated as the column number, starting from 0.</font></p>
<p><font face="Fixedsys"> .if [edi].iSubItem==1
<br>
.if SizeSortOrder==0
|| SizeSortOrder==2 </font></p>
<p><font face="MS Sans Serif" size="-1">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.</font></p>
<p><font face="Fixedsys">
invoke SendMessage,hList,LVM_SORTITEMS,1,addr CompareFunc </font></p>
<p><font face="Fixedsys"> </font><font face="MS Sans Serif" size="-1">We send
<font color="#CCFFCC"><b>LVM_SORTITEMS</b></font> 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.</font></p>
<p><font face="Fixedsys">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 </font></p>
<p><font face="MS Sans Serif" size="-1">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<font color="#CCFFCC"><b> LV_ITEM</b></font>
structure for such purpose, specifying <font color="#CCFFCC"><b>LVIF_TEXT</b></font>
in <font color="#FFFFCC"><b>imask</b></font> and the address of the buffer in
<font color="#FFFFCC"><b>pszText</b></font> and the size of the buffer in <font color="#FFFFCC"><b>cchTextMax</b></font>.</font></p>
<p><font face="Fixedsys"> .if SortType==1 <br>
mov lvi.iSubItem,1 <br>
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam1,addr lvi
</font></p>
<p><font face="MS Sans Serif" size="-1">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<font color="#FFFFCC"><b>
iSubItem</b></font> as 1 ( to specify the size column) and send <font color="#CCFFCC"><b>LVM_GETITEMTEXT</b></font>
message to the listview control to obtain the label (size string) of the subitem.</font></p>
<p><font face="Fixedsys"> invoke String2Dword,addr buffer <br>
mov edi,eax </font></p>
<p><font face="MS Sans Serif" size="-1">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.</font></p>
<p><font face="Fixedsys"> invoke SendMessage,hList,LVM_GETITEMTEXT,lParam2,addr
lvi <br>
invoke String2Dword,addr buffer <br>
sub edi,eax <br>
mov eax,edi </font></p>
<p><font face="MS Sans Serif" size="-1">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:</font></p>
<ul>
<li><font face="MS Sans Serif" size="-1">If the first item should precede the
other, you must return a negative value in eax</font></li>
<li><font face="MS Sans Serif" size="-1">If the second item should precede the
first one, you must return a positive value in eax</font></li>
<li><font face="MS Sans Serif" size="-1">If both items are equal, you must return
zero in eax.</font></li>
</ul>
<p><font face="MS Sans Serif" size="-1">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.</font></p>
<p><font face="Fixedsys"> .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>
</font></p>
<p><font face="MS Sans Serif" size="-1">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.</font></p>
<p><font face="MS Sans Serif" size="-1"> When the items were sorted, we need to
update the lParam values of all items to reflect the new indexes by calling
UpdatelParam function.</font></p>
<p><font face="Fixedsys">
invoke UpdatelParam <br>
mov SizeSortOrder,1
</font></p>
<p><font face="MS Sans Serif" size="-1">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.</font></p>
<p><font face="Fixedsys"> .elseif [edi].code==NM_DBLCLK
<br>
invoke ShowCurrentFocus <br>
.endif </font></p>
<p><font face="MS Sans Serif" size="-1">When the user double-clicks at an item,
we want to display a message box w
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -