这两天学习了列表框的使用,同样令人头疼的问题就是列表框的消息(都是这个复杂的消息,水太深),我在用ResEdit编辑资源文件的时候,在行为那一行好多属性有的不知道怎么用,刚开始就简单的加上了几个表面需要实现的几个控件:两个列表框(listbox),两个按钮(pushbutton,defpushbutton),一个文本框(ltext),一个竖向滚动条。第一个列表框(IDC_LISTBOX1)因为是单选的,不需要定义多选属性(LBS_MULTIPLESEL:允许多选,如果不定义的话则是单选列表框),当时就因为这个属性搞得程序的可执行文件,选中列表框2的一些项目,再点击“查看”按钮,程序出错退出的情况。在编写资源文件的时候,WS_TABSTOP这个属性就是允许使用Tab键在每个控件之间切换(顺序就是在资源文件中定义的先后顺序),有一点疑问的是 button类控件IDOK 不用定义WS_TABSTOP 就能有Tab停留位?其他的控件都需要定义WS_TABSTOP 才可以拥有Tab停留位,我感觉应该是windows已经定义好了。下面看一下资源文件源代码:
// Generated by ResEdit 1.6.6
// Copyright (C) 2006-2015
// http://www.resedit.net
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#define IDD_DIALOG1 1
#define IDI_ICON1 103
#define IDC_LISTBOX1 100
#define IDC_LISTBOX2 101
#define IDC_RESET 104
#define IDC_TEXT1 102
//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG1 DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SETFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU
CAPTION "列表框控件示例"
FONT 9, "宋体"
{
LISTBOX IDC_LISTBOX1 , 7, 9, 48, 65, WS_TABSTOP | WS_VSCROLL | LBS_NOINTEGRALHEIGHT | LBS_SORT | LBS_NOTIFY, WS_EX_DLGMODALFRAME
LISTBOX IDC_LISTBOX2, 70, 9, 107, 65, WS_TABSTOP | LBS_STANDARD | LBS_MULTIPLESEL, WS_EX_DLGMODALFRAME
LTEXT "", IDC_TEXT1 , 4, 82, 25, 12, WS_TABSTOP | SS_LEFT, WS_EX_LEFT
PUSHBUTTON "复位", IDC_RESET, 105, 79, 31, 14, 0,WS_EX_LEFT
DEFPUSHBUTTON "查看", IDOK, 149, 79, 33, 14, 0, WS_DISABLED
}
//
// Icon resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDI_ICON1 ICON "icon2.ico"
下面看一下 程序实现代码注意做注释的地方,这些是比较有意思的地方:
.386
.model flat,stdcall
option casemap:none
;--------------------------------------------------------------
;include文件
;--------------------------------------------------------------
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
;--------------------------------------------------------------
;等值定义
;--------------------------------------------------------------
IDD_DIALOG1 equ 1
IDI_ICON1 equ 103
IDC_LISTBOX1 equ 100
IDC_LISTBOX2 equ 101
IDC_RESET equ 104
IDC_TEXT1 equ 102
;--------------------------------------------------------------
;数据段
;--------------------------------------------------------------
.data?
hInstance dd ?
.const
szText1 db '项目1',0
szText2 db '项目2',0
szText3 db '项目3',0
szPath db '*.*',0 ;此处的标号的含义很有意思
szMessage db '选择结果:%s',0 ;注意此种显示方式
szTitle db '您的选择',0
szSelect db '您选择了以下项目:',0
szReturn db 0dh,0ah,0
;--------------------------------------------------------------
;代码段
;--------------------------------------------------------------
.code
;--------------------------------------------------------------
_ProcDlgMain proc uses ebx edi esi hWnd,wMsg,wParam,lParam
LOCAL @szBuffer[128] :byte
LOCAL @szBuffer1[128] :byte
LOCAL @szTextBuffer[2048] :byte
LOCAL @dwCount
mov eax,wMsg
.if eax == WM_CLOSE
invoke EndDialog,hWnd,NULL
.elseif eax == WM_INITDIALOG
invoke LoadIcon,hInstance,IDI_ICON1
invoke SendMessage,hWnd,WM_SETICON,ICON_BIG,eax
;---------------------------------------------------------------
;初始化列表框
;---------------------------------------------------------------
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX1,LB_ADDSTRING,0,addr szText1
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX1,LB_ADDSTRING,0,addr szText2
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX1,LB_ADDSTRING,0,addr szText3
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX2,LB_DIR,DDL_ARCHIVE or DDL_DRIVES or DDL_DIRECTORY,addr szPath
;---------------------------------------------------------------
.elseif eax == WM_COMMAND
mov eax,wParam
.if ax == IDOK
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX2,LB_GETSELCOUNT,0,0
mov @dwCount,eax
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX2,LB_GETSELITEMS,128/4,addr @szBuffer ;此处忘记 addr 。。。
invoke lstrcpy,addr @szTextBuffer,addr szSelect
lea esi,@szBuffer
.while @dwCount
lodsd
lea ecx,@szBuffer1 ;此处需要品味
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX2,LB_GETTEXT,eax,ecx
invoke lstrcat,addr @szTextBuffer,addr szReturn
invoke lstrcat,addr @szTextBuffer,addr @szBuffer1
dec @dwCount
.endw
invoke MessageBox,hWnd,addr @szTextBuffer,addr szTitle,MB_OK
.elseif ax == IDC_RESET
invoke SendDlgItemMessage,hWnd,IDC_LISTBOX2,LB_SETSEL,FALSE,-1
.elseif ax == IDC_LISTBOX1
shr eax,16
.if ax == LBN_SELCHANGE
;-----------------------------------------------------------------
;将鼠标点击结果显示在文本框中
;-----------------------------------------------------------------
invoke SendMessage,lParam,LB_GETCURSEL,0,0
lea ecx,@szBuffer
invoke SendMessage,lParam,LB_GETTEXT,eax,ecx
invoke SetDlgItemText,hWnd,IDC_TEXT1,addr @szBuffer
;-----------------------------------------------------------------
;双击项目则弹出对话框
;-----------------------------------------------------------------
.elseif ax == LBN_DBLCLK
invoke SendMessage,lParam,LB_GETCURSEL,0,0
lea ecx,@szBuffer
invoke SendMessage,lParam,LB_GETTEXT,eax,ecx
invoke wsprintf,addr @szBuffer1,addr szMessage,addr @szBuffer
invoke MessageBox,hWnd,addr @szBuffer1,addr szTitle,MB_OK
.endif
;-----------------------------------------------------------------
.elseif ax == IDC_LISTBOX2
shr eax,16
.if ax == LBN_SELCHANGE
invoke SendMessage,lParam,LB_GETSELCOUNT,0,0
mov ebx,eax
invoke GetDlgItem,hWnd,IDOK
invoke EnableWindow,eax,ebx ;此处有意思
.endif
.endif
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
_ProcDlgMain endp
;------------------------------------------------------------------
start:
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke DialogBoxParam,hInstance,IDD_DIALOG1,NULL,offset _ProcDlgMain,NULL
invoke ExitProcess,NULL
;------------------------------------------------------------------
end start
关于程序代码实现过程中需要注意的就是3个API函数,和几个陌生的语句,和几个变量的理解:
首先是:lodsd
这个命令还是第一次接触,功能是:
是以esi为首地址,每次(注意这个每次,我在写代码理解的时候就理解错了,纠结了好久,没正确理解在程序处理点击查看按钮的操作,记住是每次拷贝,而不是一次性拷贝)拷贝4个字节,把这4个字节放到eax中,然后esi自动+4,
然后是:hInstance,hWnd,handle (不知道其他人是否纠结过这个问题:在编写WIN32汇编程序的时候总有一个全局变量hInstance,在每个API函数的参数中基本都会出现这个hWnd参数,这个问题对于我这种初学者来说确实会有疑问,这家伙是干什么的,怎么哪都有他,他就没有个具体的定义?)这里来总结一下:
HINSTANCE是应用程序实例句柄,
HWND是窗口对象句柄,
HANDLE是任意对象的句柄,
CWnd是MFC中的窗口类。
下面介绍一下几个API函数:
LsTrcpy()
功能:
该函数复制一个字符串到缓冲区
原型:
LPTSTR lstrcpy(LPTSTR lpString1,LPCTSTR lpString2);
参数:
lpString1:指向接收由参数lpString2指向字符串内容的缓冲区。缓冲区必须足够大来容纳字符串,还包括最后的NULL终止符。
lpString2:指向待复制的以NULL为终止符的字符串。
返回值:若函数运行成功,返回值是缓冲区的指针;若函数运行失败,返回值是NULL。
Lstrcat()
功能:
该函数将一个字符串附加在另一个字符串后面。
原型:
LPTSTR lstrcat(LPTSTR lpString1,LPCTSTR lpString2);
参数:
lpString1:一个以NULL为终止符字符串指针。这个缓冲区必须足够大能包含两个字符串。
lpString2:一个以NULL为终止符字符串指针,它将追加在由lpString1中指定。这个缓冲区必须足够大能包含两个字符串。
返回值:若函数运行成功,返回值指向缓冲区;若失败,则返回值为NULL。
SetDlgItemText()
功能:
该函数设置对话框中控件的文本和标题
原型:
BOOLSetDlgltemText(HWND hDlg,int nlDDlgltem,LPCTSTR IpString);
参数:
hDlg:指定含有控件的对话框。
nlDDlgltem:标识带有将被设置的标题和文本的控件。
IpString:指向一个以NULL结尾的字符串指针,该字符串指针包含了将被复制到控件的文本。
返回值:
如果函数调用成功,则返回值为非零值。如果函数调用失败,则返回值为零。