首先,放上一个程序:
#include <windows.h>
LRESULT CALLBACK Wndproc (HWND, UNIT, WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdline, int iCmdShow)
{
static TCHAR szAppName[] = TEXT(“HelloWin”);
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = wndproc;
wndclass.cbClsExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
if (!RegisterClass (&wndclass)) //put the pointer which points to wndclass into RegisterClass
{
MessageBox (NULL, TEXT("This program requires Windows NT!"), szAppname, MB_ICONERROR);
return 0;
}
hwnd = CreatWindow( szAppName, //set the exact feature of windows chuangkou, and send it to hwnd
TEXT("The Hello Program"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow (hwnd, iCmdshow);
UpdateWindow (hwnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
LRESULT CALLBACK WndProc (HWND hwnd, UNIT message, WPARAM wparam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WMCREATE:
playground (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);
return 0;
case MWM_PAINT:
hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rect);
DrawText (hdc, TEXT ("Hello, window98!"), -1, &rect, DT_SINGLELINE | DT_CENTER |DT_VCENTER);
EndPaint (hwnd, &ps);
return 0;
case MWM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowproc (hwnd, message, wParam, lParam);
}
其中,WINDCLASS的参数
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
移动或调整窗口高度/宽度时候,重新绘制整个窗口 - wndclass.cbCLlsExtra, windlass.cbWndExtra
额外空间 - wndclass.hInstance
实例句柄,将WINAPI WinMain中的第一个自动生成的参数拷贝过来即可 - wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
- wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
- wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
- wndclass.lpszMenuName = NULL;
菜单 - wndclass.lpszClassName = szAppName; //其值是一个事先定义的字符串
窗口类的命名
WINDCLASS设定了基本属性,而CreatWindow来设定更个性化特征
消息机制
窗口的诞生
给winclass窗口类结构的各个成员赋值——将指向窗口类的指针用RegisterClass注册窗口类——可以使用CreateWindow来生成一个窗口实例(窗口已经在内存中存储,因此会返回一个句柄)——调用ShowWindow显示窗口——UpdateWindow更新窗口()——消息循环!!!
——————————————————————————————————————————
Windows是一个事件驱动,基于消息的操作系统。Windows强调的是事件触发,并且事件之间是无序的。
Window在接收到一些事件触发后就会将事件转化为对应的消息,将其投放在消息队列中
系统会根据消息的所有者,将系统消息进行下放各个应用程序的应用队列里。
Q:怎么知道哪个消息属于哪个窗口呢
A:以下是MSG类型结构变量msg的定义
typedef struct tagMSG {
HWND hwnd; //指定接受消息的窗口句柄,滑动鼠标后所滞留的窗口
UINT message; //用于标识信息的数字
WPARAM wParam;
LPARAM lParam;
DWORD time; //消息进入消息队列的时间
POINT pt; //POINT是另外一种结构,是用来获取鼠标具体位置,来填充窗口句柄?
#ifdef _MAC
DWORD lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
POINT的定义
typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;
开启消息循环的GetMessage函数用于从消息队列中对信息进行检索:
GetMessage (&msg, NULL, 0, 0)
该调用将一个指向msg的MSG结构变量的指针传给Windows。其第二,第三和第四个参数均为NULL和0,表明该程序希望获取由该程序所创建的所有窗口的信息。
如果从消息队列中检索到的信息的message字段不等于WM_QUIT(0x0012),则GetMessage将返回一个非0值(程序退出),否则返回0。
如果不是0,则进行翻译和分配
GetMessage (&msg, NULL, 0, 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg); //将msg结构返回给Windows
}
Windows用从消息队列中获得的下一条消息来填充消息结构的各个字段!!!
接下来Windows会将这条消息发送给合适的窗口过程来处理,windows调用了窗口过程。在处理完消息后,将控制权转回给Windows,后者还将为DispatchMessage调用服务。直到接收到VM_QUIT。
消息机制Extra
消息队列是FIFO的形式
先进入的消息会先出来
VM_PAINT, VM_TIMER, WM_QUIT 属于特例。操作系统会把它们时刻放在消息队列的最后,让其他的消息先执行,如VM_PAINT如果放在前面,会一直重新绘制窗口。
消息其实会分为队列化消息和非队列化消息。非队列消息优先级高于队列化消息,会先执行非队列消息。