- 1、API与SDK
- 2、窗口与句柄
- 3、消息与消息队列
- 3.1 消息
- 3.2 消息队列
- 3.3 进队消息和不进队消息
- 4、WinMain函数
- 4.1 WinMain函数的定义
- 4.2 窗口的创建
- 4.2.1 设计一个窗口类
- 4.2.2 注册窗口类
- 4.2.3 创建窗口
- 4.2.4 显示及更新窗口
- 4.3 消息循环
- 4.4 编写窗口过程函数
- 5、动手写第一个Windows程序
- 6、小结
1、API与SDK
-
API
Windows操作系统提供了各种各样的函数,以方便我们开发Windows应用程序。这些函数是Windows操作系统提供给应用程序编程的接口(Application Programming Interface)API。 -
SDK
那么什么是SDK呢?SDK实际上是开发所需资源的一个集合。
假如我们要开发呼叫中心,在购买语音卡的同时,厂商就会提供语音卡的SDK开发包,以方便我们对语音卡的编程操作,这个开发包通常会包含语音卡的API函数库、帮助文档、使用手册、辅助工具等资源。
2、窗口与句柄
一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、可调边框,有的还有滚动条。
在 Windows 应用程序中,窗口是通过窗口句柄(HWND)来标识的。我们要对某个窗口进行操作,首先就要得到这个窗口的句柄。
句柄(HANDLE)是 Windows 程序中一个重要的概念,使用也非常频繁。
句柄包括如下:
- 窗口句柄(HWND)
- 图标句柄(HICON)
- 光标句柄(HCURSOR)
- 刷句柄(HBRUSH)
Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,然后应用程序从消息队列中取出消息并进行响应。在这个处理过程中,操作系统也会给应用程序“发送消息”。所谓“发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。
3.1 消息在 Windows 程序中,消息是由 MSG 结构体来表示的。
typedef struct tagMSG {
HWND hwnd; //表示消息所属的窗口
UINT message; //指定了消息的标识符
WPARAM wParam; //指定消息的附加信息
LPARAM lParam; //指定消息的附加信息
DWORD time; //投递到消息队列中的时间
POINT pt; //鼠标的当前位置
#ifdef _MAC
DWORD lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;
3.2 消息队列
每一个 Windows 应用程序开始执行后,系统都会为该程序创建一个消息队列,这个消息队列用来存放该程序创建的窗口的消息。Windows 将产生的消息依次放到消息队列中,而应用程序则通过一个消息循环不断地从消息队列中取出消息,并进行响应。这种消息机制,就是 Windows程序运行的机制。
3.3 进队消息和不进队消息进队的消息将由系统放入到应用程序的消息队列中,然后由应用程序取出并发送。不进队的消息在系统调用窗口过程时直接发送给窗口。不管是进队消息还是不进队消息,最终都由系统调用窗口过程函数对消息进行处理。
4、WinMain函数WinMain 是 Windows程序的入口点函数,与 DOS 程序的入口点函数 main 的作用相同,当 WinMain 函数结束或返回时,Windows 应用程序结束。
一个完整的Win32程序实现步骤:
- WinMain函数的定义
- 创建一个窗口
- 进行消息循环
- 编写窗口过程函数
int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state );4.2 窗口的创建
创建一个完整的窗口,需要经过下面几个操作步骤:
- 设计一个窗口类;
- 注册窗口类;
- 创建窗口;
- 显示及更新窗口。
typedef struct _WNDCLASS {
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HANDLE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCTSTR lpszMenuName;
LPCTSTR lpszClassName;
} WNDCLASS;
4.2.2 注册窗口类
ATOM RegisterClass(CONST WNDCLASS *lpWndClass);4.2.3 创建窗口
HWND CreateWindow( LPCTSTR lpClassName, // pointer to registered class name LPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window HMENU hMenu, // handle to menu or child-window identifier HANDLE hInstance, // handle to application instance LPVOID lpParam // pointer to window-creation data );4.2.4 显示及更新窗口
(1)显示窗口
BOOL ShowWindow( HWND hWnd, // handle to window int nCmdShow // show state );
(2)更新窗口
BOOL UpdateWindow( HWND hWnd // handle to window );4.3 消息循环
在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。要从消息队列中取出消息,我们需要调用 GetMessage()函数,该函数的原型声明如下:
BOOL GetMessage( LPMSG lpMsg, // address of structure with message HWND hWnd, // handle of window UINT wMsgFilterMin, // first message UINT wMsgFilterMax // last message );
//通常我们编写的消息循环代码如下:
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg); //用于将虚拟键消息转换为字符消息
DispatchMessage(&msg); //分派一个消息到窗口过程
}
Windows应用程序的消息处理机制
- 操作系统接收到应用程序的窗口消息,将消息投递到该应用程序的消息队列中。
- 应用程序在消息循环中调用 GetMessage 函数从消息队列中取出一条一条的消息。取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用 TranslateMessage 产生新的消息。
- 应用程序调用 DispatchMessage,将消息回传给操作系统。消息是由 MSG 结构体对象来表示的,其中就包含了接收消息的窗口的句柄。因此,DispatchMessage 函数总能进行正确的传递。
- 系统利用 WNDCLASS 结构体的 lpfnWndProc 成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理(即“系统给应用程序发送了消息”)。
以上就是 Windows 应用程序的消息处理过程。
在完成上述步骤后,剩下的工作就是编写一个窗口过程函数,用于处理发送给窗口的消息。一个 Windows 应用程序的主要代码部分就集中在窗口过程函数中。在 MSDN 中可以查到窗口过程函数的声明形式,如下所示:
LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter );5、动手写第一个Windows程序
修改项目属性
#include6、小结#include LRESULT CALLBACK WinSunProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); int WINAPI WinMain( HINSTANCE hInstance, // handle to current instance HINSTANCE hPrevInstance, // handle to previous instance LPSTR lpCmdLine, // command line int nCmdShow // show state ) { //设计一个窗口类 WNDCLASS wndcls; wndcls.cbClsExtra = 0; wndcls.cbWndExtra = 0; wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); wndcls.hCursor = LoadCursor(NULL, IDC_CROSS); wndcls.hIcon = LoadIcon(NULL, IDI_ERROR); wndcls.hInstance = hInstance; //应用程序实例句柄由 WinMain 函数传进来 wndcls.lpfnWndProc = WinSunProc; wndcls.lpszClassName = "sunxin2006"; wndcls.lpszMenuName = NULL; wndcls.style = CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); //创建窗口,定义一个变量用来保存成功创建窗口后返回的句柄 HWND hwnd; hwnd = CreateWindow("sunxin2006", "http://www.sunxin.org", WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL); //显示及刷新窗口 ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); //定义消息结构体,开始消息循环 MSG msg; BOOL bRet; while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) { if (bRet == -1) { return -1; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } return msg.wParam; } //编写窗口过程函数 LRESULT CALLBACK WinSunProc( HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { switch (uMsg) { case WM_CHAR: char szChar[20]; sprintf_s(szChar, "char code is %d", wParam); MessageBox(hwnd, szChar, "char", 0); break; case WM_LBUTTONDOWN: MessageBox(hwnd, "mouse clicked", "message", 0); HDC hdc; hdc = GetDC(hwnd); //不能在响应 WM_PAINT 消息时调用 TextOut(hdc, 0, 50, "程序员之家", strlen("程序员之家")); //ReleaseDC(hwnd,hdc); break; case WM_PAINT: HDC hDC; PAINTSTRUCT ps; hDC = BeginPaint(hwnd, &ps); //BeginPaint 只能在响应 WM_PAINT 消息时调用 TextOut(hDC, 0, 0, "http://www.sunxin.org", strlen("http://www.sunxin.org")); EndPaint(hwnd, &ps); break; case WM_CLOSE: if (IDYES == MessageBox(hwnd, "是否真的结束?", "message", MB_YESNO)) { DestroyWindow(hwnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } return 0; }
创建一个 Win32 应用程序的步骤。
- 编写 WinMain 函数,可以在 MSDN 上查找并复制。
- 设计窗口类(WNDCLASS)。
- 注册窗口类。
- 创建窗口。
- 显示并更新窗口。
- 编写消息循环。
- 编写窗口过程函数。窗口过程函数的语法,可通过 MSDN 查看 WNDCLASS 的lpfnWndProc 成员变量,在这个成员的解释中可查到。



