一个简单的C语言SDK风格windows窗口
此程序生成一个窗口,并再窗口的左上角绘制一个椭圆来响应WM_PAINT消息。
///////////////////////////////////////////////////////////////////
#include <windows.h>
LONG WINAPI WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,int nCmdShow)
{
WNDCLASS wc;
HWND hwnd;
MSG msg;
wc.style=0;
wc.lpfnWndProc=(WNDPROC)WndProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=hInstance;
wc.hIcon=LoadIcon(NULL,IDI_WINLOGO);
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName=NULL;
wc.lpszClassName="MyWndClass";
RegisterClass(&wc);
hwnd=CreateWindow(
"MyWndClass",
"SDK Application",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_DESKTOP,
NULL,
hInstance,
NULL
);
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,
LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
switch(message)
{
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
Ellipse(hdc,0,0,200,100);
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}
///////////////////////////////////////////////////////////////////
WinMain首先调用API函数RegisterClass来注册一个窗口类。窗口类定义了窗口的重要特性,如窗口过程地址,默认背景颜色以及图标等。这些属性通过填写一个WNDCLASS结构的字段值来定义,随后将传递给RegisterClass。当应用程序生成一个窗口时,它必须指定一个窗口类,在该类能被使用之前,必须先对其进行注册。这就是为什么RegisteClass在程序的开始即被调用的原因。
一旦WNDCLASS被注册,WinMain将调用最重要的CreateWindow函数来生成应用程序的窗口。传递给CreateWindow的第1个参数是WNDCLASS的名字,窗口将由此生成窗口。第2个参数是将在窗口的标题栏中显示的文本。第3个参数指定窗口样式。WS_OVERLAPPEDWINDOW是一个常用的样式,它生成一个顶层窗口,该窗口带有可调整大小的边框、一个标题栏、一个系统菜单及最小化、最大化和关闭窗口按钮。
接下来的第4个参数指定了窗口的初始位置和大小。CW_USEDEFAULT用来告诉Windows使用默认值。最后4个参数依次指定:该窗口的父窗口的句柄(HWND_DESKTOP用作应用程序的主窗口的父窗口);与窗口关联的菜单的句柄;应用程序的实例句柄(一个用来让程序员区分是程序自身还是模块DLL的值);以及一个指向特定应用程序的窗口生成数据的指针。
由于生成时没使用WS_VISIBLE,所以CreateWindow生成的窗口在屏幕上最初是不可见的。(如果使用WS_VISIBLE,则它应该在CreateWindow函数的调用中与WS_OVERLAPPEDWINDOW结合应用。)因此在WinMain中,紧随CreateWindow后面的是一对ShowWindow和UpdateWindow函数的调用,它们使窗口可见并确保WM_PAINT消息处理程序立刻被调用。
接下来是消息循环。为了检索并调度消息,WinMain执行一个简单的反复调用GetMessage、TranslateMessage和DispatchMessage这3个API函数的while循环语句。GetMessage检查消息队列。如果某个消息是有效的,则它将从队列中被删除并复制到msg,否则,GetMessage将停留在消息队列上直到消息有效。msg是结构MSG的一个实例,其字段包含相关的消息参数,倒如消息ID和消息被放置在队列中的时间。TranslateMessage函数将一个指示字符键的键盘消息转换为更容易使用的WM_CHAR消息,DispatchMessage函数则将消息发送给窗口过程。消息循环一直执行到CreatMessage函数返回0值时结束。而此情形只有在WM_QUIT消息从消息队列中被检索到时才发生。这时WinMain结束,程序终止运行。
由DispatchMessage函数调度的消息将生成对窗口过程WndProc的调用。上面的示例程序只是处理了两个消息类型:WM_PAINT和WM_DESTROY;所有其他消息被传递给了DefWindowProe函数进行默认处理。在switch-case块中将检查message参数传递来的消息ID,并且执行相应的消息处理程序。在绘制开始以前,WM_PAINT处理程序将调用API函数BeginPaint来获得一个设备环境句柄,当绘制完成后,API函数EndPaint将释放该句柄。在两函数之间.API函数Ellipse绘制了一个200像素宽、100像素高的椭圆。设备环境句柄是一个具有奥妙功能的东西,它允许Windows应用程序在屏幕上绘图。没有它,像Elllpse这样的函数就不能工作。
WM_DESTROY处理程序调用PostQuitMessage API函数给消息队列发送一个WM_QUIT消息,并最终促使程序停止运行。在WM_DESTROY消息被发送给窗口之后,紧接着窗口就被撤消了。当接收到一个WM_DESTROY消息时,顶层窗口必须调用PostQuitMessage函数,否则消息循环不会停止,程序也就永远不会结束。