先看源程序:
#include<windows.h> //包含窗口头文件
LRESULT CALLBACK WinProc(HWND,UINT,WPARAM,LPARAM); //消息处理函数
BOOL InitApplication(HINSTANCE); //初始化应用程序窗口结构,注册窗口
BOOL InitInstance(HINSTANCE,int); //创建窗口,并显示他
char* wintitle="Welcome to my first window program"; //定义窗口标题
HINSTANCE hInst; //应用程序实例句柄
HWND hWnd; //窗口句柄
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd) //程序入口
{
MSG msg; //定义消息
if(!InitApplication(hInstance))
{
return 0;
}
if(!InitInstance(hInstance,nShowCmd))
{
return 0;
}
while(GetMessage(&msg,NULL,0,0)) //从消息队列获得消息
{
TranslateMessage(&msg); //解释消息
DispatchMessage(&msg); //发派消息
}
return msg.wParam;
}
BOOL InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc; //定义并初始化窗口结构
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); //窗口背景
wc.hCursor=LoadCursor(hInstance,IDC_ARROW); //鼠标形状
wc.hIcon=LoadIcon(hInstance,IDI_APPLICATION); //程序图标
wc.hInstance=hInstance;
wc.lpfnWndProc=WinProc; //关联到消息回调函数
wc.lpszMenuName=NULL; //无菜单
wc.style=CS_HREDRAW | CS_VREDRAW; //窗口重绘风格
wc.lpszClassName="HelloWin"; //窗口类名
if(!RegisterClass(&wc)) //注册窗口
{
return FALSE;
}
return TRUE;
}
BOOL InitInstance(HINSTANCE hInstance,int nCmdShow)
{
hInst=hInstance;
hWnd=CreateWindow("HelloWin",wintitle,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL); //创建窗口
if(!hWnd)
return FALSE;
ShowWindow(hWnd,nCmdShow); //显示窗口
UpdateWindow(hWnd); //更新窗口,强制显示
return TRUE;
}
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch(message)
{
case WM_PAINT: //窗口绘制消息
hdc=BeginPaint(hwnd,&ps); //开始绘制
TextOut(hdc,0,0,"Welcome to the window sdk",strlen("Welcome to the window sdk"));
EndPaint(hwnd,&ps); //结束绘制
break;
case WM_DESTROY: //程序退出消息
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,message,wParam,lParam);//其他消息有系统默认处理
}
return 0;
}
在这个程序里,我们可以看出一个SDK程序的大概流程,简单说有四步:
1。主WinMain函数,他相当于c语言中的main函数,
2。窗口结构的初始化,注册,创建,显示
3。开始进入消息循环,取得消息,解释消息,发派消息
4。对被发派的消息进行响应,这就由我们的WinProc来完成
在这个程序中,我们用到了如下的一些SDK函数:
WinMain:程序入口函数,对于他的返回值WINAPI以及后面回调函数中的CALLBACK其本质都是一样的只是声明的形式不同:在宏定义中可以找到
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define APIENTRY WINAPI
#define APIPRIVATE __stdcall
#define PASCAL __stdcall
__stdcall
按从右至左的顺序压参数入栈,由被调用者把参数弹出栈。对于 C 函数或者变量,修饰名以下划线为前缀,然后是函数名,然后是符号“@”及参数的字节数,如函数int func(int a, double b)的修饰名是_func@12。对于 C++ 函数,则有所不同。所有的Win32 API函数都遵循该约定。
参数的入栈顺序 清栈
__cdecl 编译器默认,从右向左 调用函数
__fastcall 一些参数被放入ECX,EDX中, 被调用函数
其它参数从右向左
__stdcall 从右向左 被调用函数
LoadIcon,LoadCursor:装载系统定义的图标,光标资源,
GetStockObject:取得一个堆对象,返回值为VOID*,这里需要一个画刷,来刷背景色,所以需要强制转换为(HBRUSH)类型
RegisterClass,RegisterClassEx:注册已经初始化的窗口结构。
CreateWindow:创建窗口,其中第一个参数必须与先前注册的窗口类名称一致,不然创建失败。第三个参数一般为WS_OVERLAPPEDWINDOW,第4,5,6,7个参数表示窗口的位置,大小,CW——USEDEFAULT表示由系统指定。
ShowWindow:参数为非0显示窗口,参数为0隐藏窗口
UpdateWindow:用来强制显示窗口,由于系统缓慢,窗口已经调用了ShowWindow,但是却没有显示在屏幕上,往往通过调用这个函数来立即显示,隐藏他
PostQuitMessage:发送退出程序的消息。参数为0,这样当下次GetMessage时,会因为取得0而退出while循环(个人理解)
GetMessage: 用来从消息队列中取得消息,参数msg用来保存取得的消息内容,第二个参数用来指定消息来源于哪个窗口句柄,后面三个参数可以分别设置为NULL,0,0具体说明见MSDN
TranslateMessage:他只有一个参数MSG,把GetMessage取得的消息翻译成能被回调函数理解的形式
DispatchMessage:把消息发派到消息处理回调函数。
用到的一些结构和类:可以从MSDN里看到很多基本数据类型
HWND:窗口句柄,
HINSTANCE:实例句柄
LPARAM,WPARAM:专用的消息参数
WNDCLASS,WNDCLASSEX:窗口结构
MSG:消息结构
用到的一些消息:
WM_PAINT:重绘窗口的消息
WM_DESTROY:退出程序的消息
学习后练习:
1。修改程序窗口标题,
2。修改窗口客户区显示内容。
3。修改窗口显示位置,大小
4。修改窗口图标,光标,背景。
5。在窗口中绘制一条直线,(MoveTo,LineTo)
6。在消息回调函数中添加一个感兴趣的消息,并进行消息处理,比如鼠标,按键