Win32 Application的第一个例子

来源:互联网 发布:淘宝黑名单在哪里 编辑:程序博客网 时间:2024/05/21 19:36

Win32 Application的第一个例子

VC 6中新建一个Win32 Application,在Source Files中新建一个C++源文件WinMain.cpp,代码如下所示:

#include "stdafx.h"

HWND hWnd=NULL; // 保存 Windows 分配给程序的窗口句柄,它是全局的

LRESULT APIENTRY MyWndProc(HWND,UINT,WPARAM,LPARAM);
void MyMsgLoop();


int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{

char clsName[]="myWnd";
WNDCLASS wc;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
wc.lpfnWndProc = MyWndProc;
wc.cbClsExtra = 0L;
wc.cbWndExtra = 0L;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);
wc.lpszMenuName = NULL;
wc.lpszClassName = clsName;

RegisterClass(&wc);

hWnd = CreateWindow(clsName,"主窗口",
   WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
   100, 100,400, 300,NULL,NULL,hInstance,NULL); // 创建窗口
ShowWindow( hWnd, SW_SHOWDEFAULT ); // 显示窗口
UpdateWindow( hWnd );   // 刷新窗口
MyMsgLoop();     // 进入消息循环
return 0;
}

LRESULT APIENTRY MyWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam ) {// 消息处理
switch(message) {
case WM_CREATE:  // 当收到建立窗口的消息时,进行处理...
  //MessageBox(NULL,"窗口创建的时候","消息提示",MB_OK|MB_ICONEXCLAMATION);
   return 0;
   break;
case WM_CLOSE:  // 当收到关闭窗口的消息时,进行处理...
   MessageBox(NULL,"窗口要关闭了","消息提示",MB_OK|MB_ICONEXCLAMATION); 
   PostQuitMessage(0);
   return 0;
   break;
case WM_SIZE:    // 当窗口尺寸变化时,进行处理...
   MessageBox(NULL,"窗口尺寸发生变化了","消息提示",MB_OK|MB_ICONEXCLAMATION);
   return 0;
   break;
case WM_DESTROY: // 当退出消息的时候,进行处理...
   MessageBox(NULL,"退出消息了","消息提示",MB_OK|MB_ICONEXCLAMATION); 
   PostQuitMessage(0);
   return 0;
   break;
case WM_KEYUP:  // 当收到按ESC键的消息时,(如果当前是全屏模式,必须要加入退出方式)
   switch (wParam) {
   case VK_ESCAPE:
    MessageBox(NULL,"按ESC键了","消息提示",MB_OK|MB_ICONEXCLAMATION); 
    PostQuitMessage(0);
    return 0;
    break;
   } 
   default:
    break;
}
return (DefWindowProc(hWnd, message, wParam, lParam));
}

void MyMsgLoop() { 
MSG msg; 
BOOL receiveMessage;
PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
while(msg.message != WM_QUIT) { // 消息循环
   receiveMessage = PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE);
   if(receiveMessage) { // 有消息
    TranslateMessage(&msg);
    DispatchMessage(&msg);
   }
}
}

通过这个简单的例子,理解Windows基于消息映射的机制。

先从主函数WinMain开始看。

因为要创建一个Windows窗体,所以首先需要注册一个Windows类,因为调用CreateWindow函数的时候,需要根据注册的Windows类的信息来创建一个窗体的。

Windows定义了一个WNDCLASS结构,用来描述一个Windows窗体类的信息,定义如下所示:

typedef struct _WNDCLASS { 
    UINT    style; 
    WNDPROC lpfnWndProc; 
    int     cbClsExtra; 
    int     cbWndExtra; 
    HANDLE hInstance; 
    HICON   hIcon; 
    HCURSOR hCursor; 
    HBRUSH hbrBackground; 
    LPCTSTR lpszMenuName; 
    LPCTSTR lpszClassName; 
} WNDCLASS;

关于WNDCLASS结构的各个成员变量的含义,可以查看MSDN了解。在上面的程序中,直接设置WNDCLASS结构变量wc的成员:

wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW; // 窗体风格
wc.lpfnWndProc = MyWndProc; //   窗体进程的指针,上面程序中定义了MyWndProc这个进程
wc.cbClsExtra = 0L;
wc.cbWndExtra = 0L;
wc.hInstance = hInstance; // 窗体进程实例的句柄,通过WinMain主函数传递进来
wc.hIcon = NULL;
wc.hCursor = NULL;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); // 背景画刷,也就是窗口显示背景颜色
wc.lpszMenuName = NULL;
wc.lpszClassName = clsName; // 注册的Windows类名称

接下来,调用RegisterClass函数进行注册:

RegisterClass(&wc);

该API函数声明如下:

ATOM RegisterClass(
CONST WNDCLASS
 *lpWndClass   // 指向WINDCLASS类实例的指针
);

如果注册成功,返回ATOM类型,也就是WORD类型,也就是无符号短整型,如下所示:

typedef unsigned short      WORD;

注册完成之后,具备了创建一个窗体的信息,开始调用API函数CreateWindow来进行窗体的创建工作,上述程序中创建如下所示:

hWnd = CreateWindow(clsName,"主窗口",
   WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
   100, 100,400, 300,NULL,NULL,hInstance,NULL); // 创建窗口

窗体创建成功以后,会返回这个窗体的一个句柄,赋给定义的全局的HWND hWnd。关于CreateWindow函数,声明如下:

HWND CreateWindow(
LPCTSTR
 lpClassName// 注册的类的指针
LPCTSTR lpWindowName// 窗体名称字符串指针
DWORD dwStyle,        // 窗体风格
int x,                // 窗体显示位置的水平x坐标
int y,                // 窗体显示位置的垂直y坐标
int nWidth,           // 窗体宽度
int nHeight,          // 窗体高度
HWND hWndParent,      // 父窗口的句柄
HMENU hMenu,          // 菜单句柄
HANDLE hInstance,     // 应用程序实例的句柄
LPVOID lpParam        // 窗体创建信息的指针
);

获取到了创建成功之后的窗体的句柄,然后根据这个返回的句柄来显示这个成功创建的窗体,程序中调用API函数ShowWindow进行显示:

ShowWindow( hWnd, SW_SHOWDEFAULT ); // 显示窗体

其中,ShowWindow函数的声明如下:

BOOL ShowWindow(
HWND
 hWnd,     // 窗体句柄
  int nCmdShow   // 窗体的状态
);

其中,窗体的状态nCmdShow取值可以是如下所示的值:

SW_FORCEMINIMIZE
SW_HIDE Hides
SW_MAXIMIZE
SW_MINIMIZE
SW_RESTORE
SW_SHOW
SW_SHOWDEFAULT
SW_SHOWMAXIMIZED
SW_SHOWMINIMIZED
SW_SHOWMINNOACTIVE
SW_SHOWNA
SW_SHOWNOACTIVATE
SW_SHOWNORMAL

这样,一个窗体就显示出来了,窗体的客户区内是空的。

UpdateWindow函数用于更新窗口,该函数更新窗口的时候会向指定的窗体的进程发送消息,如果被更新的客户区为空,说明窗体没有接收到消息。

最后,调用了自定义了MyMsgLoop函数,进入消息循环。这时,窗体进入一种等待状态,等待消息的来到,然后在该函数中对不同类型的消息进行处理。

我们看一下MyWndProc函数的实现,它是窗口进程,用来根据窗体接收到的消息并进行处理。窗口进程函数的声明如下所示:

LRESULT CALLBACK WindowProc(
HWND
 hwnd,      // handle to window
UINT uMsg,      // message identifier
WPARAM wParam// first message parameter
LPARAM lParam   // second message parameter
);

可以自定义自己的窗口进程函数,包含上述四个参数。然后根据消息进行选择处理方式。

上述程序中,给出了几种典型的消息,你可以根据需要在case语句中实现处理的过程,处理完成之后,返回DefWindowProc(hWnd, message, wParam, lParam),这时是一个默认的窗口进程函数,可以处理任何Windows消息。

函数MyMsgLoop主要对消息进行管理的,其中,调用PeekMessage函数会检查线程消息队列,根据指定的消息的结构并从消息队列中取出消息,而且,可以设定消息在被PeekMessage函数处理完成以后,是否保留在线程消息队列中,从PeekMessage函数的声明来看:

BOOL PeekMessage(
LPMSG
 lpMsg,         // pointer to structure for message
HWND hWnd,           // handle to window
UINT wMsgFilterMin// first message
UINT wMsgFilterMax// last message
UINT wRemoveMsg      // removal flags
);

最后一个参数wRemoveMsg表示是否在调用PeekMessage函数处理之后从线程消息队列中移除,它有两个取值:

PM_NOREMOVE
PM_REMOVE

对该程序进行编译,运行,显示出一个窗体,如图所示:

根据在MyWndProc函数中定义的窗口进程,可以通过向窗体传递不同类型的消息,来看case语句中对应的输出,有助于理解Windows的消息机制。

原创粉丝点击