本文档是将《Windows环境下32位汇编语言程序设计(典藏版)》第4章汇编代码部分转换成对应的C语言代码,并对C语言代码如何使用WINAPI进行部分补充。
第94页 FirstWindow.c 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77// include 文件定义
// 全局变量(对应汇编语言“数据段”的概念)
HINSTANCE hInstance;
HWND hWinMain;
LPCSTR szClassName = "MyClass";
LPCSTR szCaptionMain = "My first Window !";
LPCSTR szText = "Win32 Assembly, Simple and powerful !";
// 函数声明
LRESULT CALLBACK _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI _WinMain();
// 主函数,子系统选择windows
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
return _WinMain();
}
// 函数定义
LRESULT CALLBACK _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
/* 窗口过程 回调函数*/
switch(uMsg)
{
case WM_PAINT:
{
PAINTSTRUCT stPs;
RECT stRect;
HDC hDc;
hDc = BeginPaint(hWnd, &stPs);
GetClientRect(hWnd,&stRect);
DrawTextA(hDc,szText,-1,&stRect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hWnd, &stPs);
}
break;
case WM_CLOSE:
DestroyWindow(hWinMain);
PostQuitMessage(NULL);
break;
default:
return DefWindowProcA(hWnd,uMsg,wParam,lParam);
}
return 0;
}
int WINAPI _WinMain()
{
WNDCLASSEXA stWndClass;
MSG stMsg;
hInstance = GetModuleHandleA(NULL);
RtlZeroMemory(&stWndClass,sizeof(stWndClass));
// 注册窗口类
stWndClass.hCursor = LoadCursorA(0,IDC_ARROW);
stWndClass.hInstance = hInstance;
stWndClass.cbSize = sizeof(WNDCLASSEX);
stWndClass.style = CS_HREDRAW | CS_VREDRAW;
stWndClass.lpfnWndProc = _ProcWinMain;
stWndClass.hbrBackground = COLOR_WINDOW + 1;
stWndClass.lpszClassName = szClassName;
RegisterClassExA(&stWndClass);
// 建立并显示窗口
hWinMain = CreateWindowExA(WS_EX_CLIENTEDGE,szClassName,szCaptionMain,WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,NULL,hInstance,NULL);
ShowWindow(hWinMain,SW_SHOWNORMAL);
UpdateWindow(hWinMain);
// 消息循环
while(1)
{
if(GetMessageA(&stMsg,NULL,0,0) == 0)
break;
TranslateMessage(&stMsg);
DispatchMessageA(&stMsg);
}
return 0;
}1
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd);
1
2
3
4// 定义ANSI字符串
LPCSTR strANSI = "Hello World!";
// 定义UNICODE字符串,注意字符串前要加上L
LPCWSTR strUNICODE = L"Hello World!"1
typedef unsigned long DWORD;
调用涉及字符串的WINAPI,要注意调用对应的函数。一般情况下,需要ANSI字符串的API以A结尾,需要UNICODE字符串的API以W结尾。例如MessageBox就有两个版本: 1
2MessageBoxA(NULL,"Hello World!","VLSMB",MB_OK);
MessageBoxW(NULL,L"Hello World!",L"VLSMB",MB_OK);
另外,C语言代码中有些函数前面的WINAPI、CALLBACK必须要有,这个是函数的调用约定。函数的调用约定是指函数的参数传递方式。C语言的默认调用约定是cdecall而WINAPI几乎都是stdcall,因此你定义的窗口的回调函数必须是stdcall。WINAPI和CALLBACK都是__stcall的宏定义,这两个之间替换无所谓,以下回调函数的写法都正确: 1
2
3LRESULT CALLBACK _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT WINAPI _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT __stdcall _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
99页 GetModuleHandle的用法:(这本书中所有函数都是用A版本的函数,因此作者并没有显示写出来) 1
2
3
4
5
6// 函数声明
HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName);
// 获取User32.dll的句柄
LPCSTR szUserDll = "User32.dll";
HINSTANCE hUserDllHandle = GetModuleHandleA(szUserDll);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16typedef struct WNDCLASSEXA {
UINT cbSize; // 结构的字节数
/* Win 3.x */
UINT style; // 类风格
WNDPROC lpfnWndProc; // 窗口过程的地址
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance; // 所属的实例句柄
HICON hIcon; // 窗口图标
HCURSOR hCursor; // 窗口光标
HBRUSH hbrBackground; // 背景色
LPCSTR lpszMenuName; // 窗口菜单
LPCSTR lpszClassName; // 类名字符串
/* Win 4.0 */
HICON hIconSm; // 小图标
}1
2
3
4
5
6
7
8
9
10WNDCLASSEXA stWndClass;
RtlZeroMemory(&stWndClass,sizeof(stWndClass));
stWndClass.hCursor = LoadCursorA(0,IDC_ARROW);
stWndClass.hInstance = hInstance;
stWndClass.cbSize = sizeof(WNDCLASSEX);
stWndClass.style = CS_HREDRAW | CS_VREDRAW;
stWndClass.lpfnWndProc = _ProcWinMain;
stWndClass.hbrBackground = COLOR_WINDOW + 1;
stWndClass.lpszClassName = szClassName;
RegisterClassExA(&stWndClass);1
2
3
4// 获取刷子句柄
stWndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
// 直接使用颜色
stWndClass.hbrBackground = COLOR_WINDOW + 1;1
HWND WINAPI CreateWindowExA(DWORD dwExStyle,LPCSTR lpClassName,LPCSTR lpWindowName,DWORD dwStyle,int X,int Y,int nWidth,int nHeight,HWND hWndParent,HMENU hMenu,HINSTANCE hInstance,LPVOID lpParam);
1
2
3hWinMain = CreateWindowExA(WS_EX_CLIENTEDGE,szClassName,szCaptionMain,WS_OVERLAPPEDWINDOW,100,100,600,400,NULL,NULL,hInstance,NULL);
ShowWindow(hWinMain,SW_SHOWNORMAL);
UpdateWindow(hWinMain);1
2CreateWindowExA(NULL,"button","&OK",WS_CHILD | WS_VISIBLE,10,10,65,22,hWnd,1,hInstance,NULL);
// OK前面加的&不是取地址的意思,不加这个符号也可以。这个过程需要父窗口提供的窗口句柄hWnd和进程实例hInstance
消息循环的一般形式: 1
2
3
4
5
6
7
8
9// 这个TRUE是windows.h提供的,C语言中没有C++的true和false关键字。你也可以用1和0替代。
MSG stMsg;
while(TRUE)
{
if(GetMessageA(&stMsg,NULL,0,0) == 0)
break;
TranslateMessage(&stMsg);
DispatchMessageA(&stMsg);
}1
2
3
4
5
6
7
8typedef struct MSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}1
BOOL WINAPI GetMessageA(LPMSG lpMsg,HWND hWnd,wMsgFilterMin,UINT wMsgFilterMax);
1
typedef MSG* LPMSG;
其他形式的消息循环: 1
2
3
4
5
6
7int dwQuitFlag=0;
/* CreateWindowA(...);
ShowWindow(...);
UpdateWindow(...);
*/
while(!dwQuitFlag);
ExitProcess(NULL);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16MSG stMsg;
// ...
while(TRUE)
{
if(PeekMessageA(&stMsg,NULL,0,0,PM_REMOVE))
{
if(stMsg.message==WM_QUIT)
break;
TranslateMessage(&stMsg);
DispatchMessageA(&stMsg);
}
else
{
// 做其他工作
}
}
窗口过程(回调函数)必须遵循规定的格式,回调函数的地址是必须的,因此必须为stdcall调用约定。 1
2// 函数声明
LRESULT CALLBACK _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19LRESULT CALLBACK _ProcWinMain(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_XXX:
// 处理WM_XXX消息
break;
case WM_YYY:
// 处理WM_YYY消息
break;
case WM_CLOSE:
DestroyWindow(hWinMain);
PostQuitMessage(NULL);
break;
default:
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
}
return 0;
}
PostMessageA和SendMessageA的声明: 1
2BOOL WINAPI PostMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);
LRESULT WINAPI SendMessageA(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);1
2
3
4
5
6
7
8
9
10
11
12case WM_SETTEXT:
{
char szBuffer[256];
// WINAPI里需要用\r\n同时在一起才能换行
LPCSTR szReceive = "Receive WM_SETTEXT message\r\nparam: %08x\r\ntext: \"%s\"\r\n";
LPCSTR szCaptionMain = "Receive Message";
// wsprintfA和sprintf效果和用法相似,UNICODE字符串需要用wsprintfW
wsprintfA(szBuffer,szReceive,lParam,lParam);
MessageBoxA(hWnd,szBuffer,szCaptionMain,MB_OK);
}
break;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
char szBuffer[256];
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
HWND hWnd = FindWindowA("MyClass",NULL);
LPCSTR szText = "Text send to other windows";
if(hWnd)
{
wsprintfA(szBuffer,"Press OK to start SendMessage, param: %08x!",szText);
MessageBoxA(NULL,szBuffer,"SendMessage",MB_OK);
SendMessageA(hWnd,WM_SETTEXT,0,szText);
MessageBoxA(NULL,"SendMessage returned!","SendMessage",MB_OK);
}
else
{
MessageBoxA(NULL,"Receive Message Window not found!","SendMessage",MB_OK);
}
return 0;
}1
HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
COPYDATASTRUCT的定义: 1
2
3
4
5typedef struct COPYDATASTRUCT {
ULONG_PTR dwData; // 附加字段
DWORD cbData; // 数据长度
PVOID lpData; // 数据位置指针
};1
2
3
4
5
6
7COPYDATASTRUCT stCopyData;
/*
stCopyData.dwData = ?
stCopyData.cbData = ?
stCopyData.lpData = ?
*/
SendMessage(hDestWnd,WM_COPYDATA,hWnd,&stCopyData);