?? 031.txt
字號:
pWin32_Find_Data 是WIN32_FIND_DATA 型的結(jié)構(gòu)體變量的地址,WIN32_FIND_DATA型的結(jié)構(gòu)體變量將用來保存返回的文件的信息。
如果沒有找到匹配的文件,該函數(shù)將在eax中返回INVALID_HANDLE_VALUE 。否則將返回一個搜索句柄,您可以用該句柄在FindNextFile函數(shù)中來搜索下一個符合條件的文件。
.if eax!=INVALID_HANDLE_VALUE
mov FHandle,eax
xor edi,edi
如果找到了一個文件,我們在一個變量中保存搜索句柄,并把寄存器edi清零,該寄存器將用作項目的索引號。
.while eax!=0
test finddata.dwFileAttributes,FILE_ATTRIBUTE_DIRECTORY
.if ZERO?
在本課中,我們將不處理文件夾,所以我們檢查dwFileAttributes成員變量的值是否有FILE_ATTRIBUTE_DIRECTORY 標(biāo)志,如果有,我們就忽略掉它,然后調(diào)用FindNextFile。
invoke ShowFileInfo,edi, addr finddata
inc edi
.endif
invoke FindNextFile,FHandle,addr finddata
.endw
我們調(diào)用ShowFileInfo函數(shù)包文件的名稱和大小信息加到列表視圖控件中去。然后讓edi寄存器加一來增加項目的行號。最后我們調(diào)用FindNextFile函數(shù)在當(dāng)前文件夾中繼續(xù)搜索文件一直到該函數(shù)返回0為止(這意味著沒有可供搜索的文件了)。
invoke FindClose,FHandle
.endif
ret
FillFileInfo endp
當(dāng)前文件夾中的文件枚舉完畢后,我們必須關(guān)閉搜索句柄。
先在我們看一下ShowFileInfo函數(shù)。該函數(shù)由兩個參數(shù),一個是項目的索引號(也即行號),另一個是WIN32_FIND_DATA型結(jié)構(gòu)體變量的地址。
ShowFileInfo proc uses edi row:DWORD, lpFind:DWORD
LOCAL lvi:LV_ITEM
LOCAL buffer[20]:BYTE
mov edi,lpFind
assume edi:ptr WIN32_FIND_DATA
把WIN32_FIND_DATA 型結(jié)構(gòu)體變量的值放到寄存器edi中。
mov lvi.imask,LVIF_TEXT+LVIF_PARAM
push row
pop lvi.iItem
mov lvi.iSubItem,0
我們將傳遞項目的名稱和lParam的值,所以我們在iMask中放入標(biāo)志位LVIF_TEXT 和LVIF_PARAM。接下來我們在iItem中放入傳遞進(jìn)來的行號,另外由于這是主項目我們必須設(shè)置iSubItem的值等于0。
lea eax,[edi].cFileName
mov lvi.pszText,eax
push row
pop lvi.lParam
我們現(xiàn)在要把標(biāo)簽字符串的地址,在這里也就是WIN32_FIND_DATA 型結(jié)構(gòu)體變量中的文件的名稱放到pszText中。由于我們要完成對項目的排序,所以必須設(shè)置lParam的值,我把它設(shè)成行號值,這樣我們可以根據(jù)索引值來查詢項目。
invoke SendMessage,hList, LVM_INSERTITEM,0, addr lvi
設(shè)置完所有LV_ITEM型變量中的值后,我們發(fā)送LVM_INSERTITEM消息給列表視圖控件來把項目插入到其中。
mov lvi.imask,LVIF_TEXT
inc lvi.iSubItem
invoke wsprintf,addr buffer, addr template,[edi].nFileSizeLow
lea eax,buffer
mov lvi.pszText,eax
我們將把子項目插入到第二列。一個子項目只能有一個標(biāo)簽。這樣我們在iMask中指定LVIF_TEXT標(biāo)志位。接著我們指定子項目所在的列,本例中我們通過將iSubItem加一使得該值等于1。標(biāo)簽值是文件的大小,為了轉(zhuǎn)換成文本我們調(diào)用wsprintf函數(shù),然后把文本的地址放到pszText中去。
invoke SendMessage,hList,LVM_SETITEM, 0,addr lvi
assume edi:nothing
ret
ShowFileInfo endp
當(dāng)LV_ITEM型變量中的值設(shè)定好之后,我們向列表視圖控件發(fā)送LVM_SETITEM消息,并一同把LV_ITEM變量的地址傳過去。注意:發(fā)送的消息是LV_ITEM而不是LVM_INSERTITEM,因為我們插入的是子項目,子項目不是真正的項目而是主項目的屬性。所以我們這時是在設(shè)定項目的屬性,而不是加入一個項目。
當(dāng)所有的項目都插入到列表視圖控件后,我們設(shè)定它的文本和背景顏色。
RGB 255,255,255
invoke SendMessage,hList,LVM_SETTEXTCOLOR,0,eax
RGB 0,0,0
invoke SendMessage,hList,LVM_SETBKCOLOR,0,eax
RGB 0,0,0
invoke SendMessage,hList,LVM_SETTEXTBKCOLOR,0,eax
我們用RGB(R---Red G---Green B---Blue)來把三色轉(zhuǎn)換并放到eax中。我們通過發(fā)送LVM_SETTEXTCOLOR 和 LVM_SETTEXTBKCOLOR 消息來設(shè)定文本的前景和背景色。
invoke GetMenu,hWnd
mov hMenu,eax
invoke CheckMenuRadioItem,hMenu,IDM_ICON,IDM_LIST, IDM_REPORT,MF_CHECKED
我們將讓用戶通過菜單來選擇它想要的顯示方式。這樣我們必須先得到菜單的句柄。我了讓用戶跟蹤當(dāng)前的視圖,我們在菜單中放入一組單選按鈕。我們可以調(diào)用CheckMenuRadioItem函數(shù),該函數(shù)將把一個單選按鈕放到一個菜單項前。
注意我們創(chuàng)建列表視圖控件時把它的寬度和高度都設(shè)成為0。當(dāng)父窗口改變大小時,它將同時改變大小。這樣我們可以讓列表視圖總是隨著主窗口改變。子我們的例子中,我們讓列表視圖填充整個客戶區(qū)。
.elseif uMsg==WM_SIZE
mov eax,lParam
mov edx,eax
and eax,0ffffh
shr edx,16
invoke MoveWindow,hList, 0, 0, eax,edx,TRUE
當(dāng)父窗口接收到了WM_SIZE消息后,lParam的底字部分包含了客戶區(qū)新的寬和高。讓后我們調(diào)用MoveWindow來改變列表視圖控件的大小使得它覆蓋整個的客戶區(qū)。
當(dāng)用戶通過菜單選擇了一種選擇方式,我們必須相應(yīng)地改變列表視圖中的顯示方式。我們調(diào)用SetWindowLong函數(shù)來設(shè)定新的風(fēng)格。
.elseif uMsg==WM_COMMAND
.if lParam==0
invoke GetWindowLong,hList,GWL_STYLE
and eax,not LVS_TYPEMASK
首先得到當(dāng)前的風(fēng)格,然后清除舊的風(fēng)格。LVS_TYPEMASK 是LVS_ICON+LVS_SMALLICON+LVS_LIST+LVS_REPORT四種風(fēng)格的集合。這樣當(dāng)我們用當(dāng)前的風(fēng)格“與”“not LVS_TYPEMASK”就等于清除了當(dāng)前的顯示風(fēng)格。
在設(shè)計菜單時,我們使用了一些小技巧。我們包顯示風(fēng)格的常數(shù)串當(dāng)作菜單的ID號。
IDM_ICON equ LVS_ICON
IDM_SMALLICON equ LVS_SMALLICON
IDM_LIST equ LVS_LIST
IDM_REPORT equ LVS_REPORT
這樣當(dāng)父窗口接收到WM_COMMAND消息時,希望顯示的風(fēng)格值會當(dāng)成菜單的ID號傳遞過來。
mov edx,wParam
and edx,0FFFFh
在wParam中的低字部分是欲顯示的風(fēng)格,我們所需要做的只是把高字部分清0。
push edx
or eax,edx
我們把希望顯示的風(fēng)格加到列表視圖的風(fēng)格中去(已經(jīng)去除了舊的風(fēng)格)。
invoke SetWindowLong,hList,GWL_STYLE,eax
調(diào)用SetWindowLong函數(shù)來設(shè)定新的風(fēng)格。
pop edx
invoke CheckMenuRadioItem,hMenu,IDM_ICON,IDM_LIST, edx,MF_CHECKED
.endif
我們需要在被選擇的顯示方式前放入單選按鈕。如果要排序,我們必須處理WM_NOTIFY消息。
.elseif uMsg==WM_NOTIFY
push edi
mov edi,lParam
assume edi:ptr NMHDR
mov eax,[edi].hwndFrom
.if eax==hList
當(dāng)我們接收到了WM_NOTIFY 消息后,lParam包含了指向NMHDR型結(jié)構(gòu)體變量的指針。我們通過把列表視圖控件的值和NMHDR型結(jié)構(gòu)體變量中的hwndFrom成員變量的值比較來判斷,如果相等的話我們就可以確定消息是列表視圖控件發(fā)送的。
.if [edi].code==LVN_COLUMNCLICK
assume edi:ptr NM_LISTVIEW
如果通知消息是列表視圖控件發(fā)送的,我們檢測該消息是否是LVN_COLUMNCLICK。如果是,它意味著用戶點擊了列標(biāo)題條。在接收到LVN_COLUMNCLICK消息后,我們假設(shè)lParam參數(shù)包含NM_LISTVIEW型結(jié)構(gòu)體變量的指針,NM_LISTVIEW型結(jié)構(gòu)體是NMHDR型結(jié)構(gòu)體的擴(kuò)展。我們需要知道用戶單擊了那一列,在iSubItem中的值即是列號,列的編號是從0開始的。
.if [edi].iSubItem==1
.if SizeSortOrder==0 || SizeSortOrder==2
在這里iSubItem的值是1,它表示用戶點擊的是第二列,即文件的大小。我們用狀態(tài)變量來保持當(dāng)前的排序順序。0代表不用排序,1代表升序,2代表降序。如果該列中的項目/子項目以前沒有排序或為降序,我們就把它設(shè)成升序。
invoke SendMessage,hList,LVM_SORTITEMS,1,addr CompareFunc
我們發(fā)送消息LVM_SORTITEMS給列表視圖控件,在wParam中傳遞1,在lParam中傳遞比較函數(shù)的參數(shù)。注意wParam中的值是用戶定義的,用戶可以按自己的需要來解釋,這里我們把它用作排序的方法。我們先來看看比較函數(shù):
CompareFunc proc uses edi lParam1:DWORD, lParam2:DWORD, SortType:DWORD
LOCAL buffer[256]:BYTE
LOCAL buffer1[256]:BYTE
LOCAL lvi:LV_ITEM
mov lvi.imask,LVIF_TEXT
lea eax,buffer
mov lvi.pszText,eax
mov lvi.cchTextMax,256
列表視圖控件將傳遞需要比較的兩個項目的lParam(LV_ITEM型結(jié)構(gòu)體變量的成員變量)比較函數(shù)。您還記得嗎?我們在lParam中放置了醒目的索引號。這樣我們利用這些索引號查詢列表視圖來得到項目信息。我們需要的消息是項目/子項目的標(biāo)簽文本。為此我們準(zhǔn)備好LV_ITEM 型結(jié)構(gòu)體變量并在iMask中設(shè)置標(biāo)志位LVIF_TEXT ,在pszText中設(shè)置緩沖區(qū)的地址,在cchTextMax中設(shè)置緩沖區(qū)的大小。
.if SortType==1
mov lvi.iSubItem,1
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam1,addr lvi
如果SortType的值為1或2,我們知道點擊了那一列,1代表根據(jù)文件的大小按升序排列所有的項目。2的意思相反。這樣我們指定iSubItem為1(代表文件大小列)然后發(fā)送LVM_GETITEMTEXT 消息給列表視圖控件來得到在項目的標(biāo)簽文本串。
invoke String2Dword,addr buffer
mov edi,eax
調(diào)用子定義的String2Dword函數(shù)來把字符串轉(zhuǎn)換成一個DWORD值。它將在eax中返回轉(zhuǎn)換后的值,我們把它保存在edi中以便以后比較用。
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam2,addr lvi
invoke String2Dword,addr buffer
sub edi,eax
mov eax,edi
對lParam2 中的值做同樣的操作。當(dāng)我們得到了兩個文件的大小后,就可以比較它們了。比較的規(guī)則如下:
如果第一個項目放在前面,在eax中返回一個負(fù)值
如果第二個項目放在前面,在eax中返回一個正值
如果相等,在eax中返回0
在我們這里,我們想按升序排列,所以我們只要簡單地將第二個項目的文件大小減去第一個項目的文件大小,然后返回放在eax中的值。
.elseif SortType==3
mov lvi.iSubItem,0
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam1,addr lvi
invoke lstrcpy,addr buffer1,addr buffer
invoke SendMessage,hList,LVM_GETITEMTEXT,lParam2,addr lvi
invoke lstrcmpi,addr buffer1,addr buffer
當(dāng)用戶點擊文件名字列時,我們必須比較文件的名字。我們先得到文件的名字,然后調(diào)用lstrcmpi函數(shù)來比較,然后只要簡單返回lstrcmpi的值,因為該函數(shù)比較使用的規(guī)則和我們的相同。
當(dāng)項目排序后,我們調(diào)用UpdateParam函數(shù)來更新所有項目的lParam的值來反應(yīng)出最新的改變。
invoke UpdatelParam
mov SizeSortOrder,1
該函數(shù)簡單地枚舉列表視圖中所有的項目并且把它們lParam更新成項目的索引號。
.elseif [edi].code==NM_DBLCLK
invoke ShowCurrentFocus
.endif
如果用戶雙擊某個項目時,我們將顯示一個消息框,上面有該項目的有關(guān)標(biāo)簽值。我們必須檢查NMHDR 中的code值是否是 NM_DBLCLK。如果是,我們就得到它的標(biāo)簽值并顯示在一個消息框中。
ShowCurrentFocus proc
LOCAL lvi:LV_ITEM
LOCAL buffer[256]:BYTE
invoke SendMessage,hList,LVM_GETNEXTITEM,-1, LVNI_FOCUSED
我們是增么怎么知道某個項目被雙擊的呢?當(dāng)單擊或雙擊某個項目時,它的狀態(tài)被設(shè)成“焦點”。即使有多個項目被選中,也僅有一個項目有焦點。我們的工作就是去找到那個有焦點的項目。我們發(fā)送LVM_GETNEXTITEM消息給列表視圖控件,在lParam中指定期望的狀態(tài)。如果wParam中時-1的話,表示要搜索所有的項目。有焦點的項目第索引號在eax中返回。
mov lvi.iItem,eax
mov lvi.iSubItem,0
mov lvi.imask,LVIF_TEXT
lea eax,buffer
mov lvi.pszText,eax
mov lvi.cchTextMax,256
invoke SendMessage,hList,LVM_GETITEM,0,addr lvi
發(fā)送LVM_GETITEM消息來得到標(biāo)簽。
invoke MessageBox,0, addr buffer,addr AppName,MB_OK
最后我們在一個消息框中顯示標(biāo)簽。
如果想在列表視圖控件中顯示圖標(biāo),您可以閱讀關(guān)于樹型視圖控件的課程。它們的步驟基本上是一樣的。
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -