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)
3、消息与消息队列
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函数的定义
- 创建一个窗口
- 进行消息循环
- 编写窗口过程函数
4.1 WinMain函数的定义
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
);
4.2 窗口的创建
创建一个完整的窗口,需要经过下面几个操作步骤:
- 设计一个窗口类;
- 注册窗口类;
- 创建窗口;
- 显示及更新窗口。
4.2.1 设计一个窗口类
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,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HANDLE hInstance,
LPVOID lpParam
);
4.2.4 显示及更新窗口
(1)显示窗口
BOOL ShowWindow(
HWND hWnd,
int nCmdShow
);
(2)更新窗口
BOOL UpdateWindow(
HWND hWnd
);
4.3 消息循环
在创建窗口、显示窗口、更新窗口后,我们需要编写一个消息循环,不断地从消息队列中取出消息,并进行响应。要从消息队列中取出消息,我们需要调用 GetMessage()函数,该函数的原型声明如下:
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Windows应用程序的消息处理机制
- 操作系统接收到应用程序的窗口消息,将消息投递到该应用程序的消息队列中。
- 应用程序在消息循环中调用 GetMessage 函数从消息队列中取出一条一条的消息。取出消息后,应用程序可以对消息进行一些预处理,例如,放弃对某些消息的响应,或者调用 TranslateMessage 产生新的消息。
- 应用程序调用 DispatchMessage,将消息回传给操作系统。消息是由 MSG 结构体对象来表示的,其中就包含了接收消息的窗口的句柄。因此,DispatchMessage 函数总能进行正确的传递。
- 系统利用 WNDCLASS 结构体的 lpfnWndProc 成员保存的窗口过程函数的指针调用窗口过程,对消息进行处理(即“系统给应用程序发送了消息”)。
以上就是 Windows 应用程序的消息处理过程。
4.4 编写窗口过程函数
在完成上述步骤后,剩下的工作就是编写一个窗口过程函数,用于处理发送给窗口的消息。一个 Windows 应用程序的主要代码部分就集中在窗口过程函数中。在 MSDN 中可以查到窗口过程函数的声明形式,如下所示:
LRESULT CALLBACK WindowProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
5、动手写第一个Windows程序
修改项目属性
#include <windows.h>
#include <stdio.h>
LRESULT CALLBACK WinSunProc(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
);
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
)
{
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;
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,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
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);
TextOut(hdc, 0, 50, "程序员之家", strlen("程序员之家"));
break;
case WM_PAINT:
HDC hDC;
PAINTSTRUCT ps;
hDC = BeginPaint(hwnd, &ps);
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;
}
6、小结
创建一个 Win32 应用程序的步骤。
- 编写 WinMain 函数,可以在 MSDN 上查找并复制。
- 设计窗口类(WNDCLASS)。
- 注册窗口类。
- 创建窗口。
- 显示并更新窗口。
- 编写消息循环。
- 编写窗口过程函数。窗口过程函数的语法,可通过 MSDN 查看 WNDCLASS 的lpfnWndProc 成员变量,在这个成员的解释中可查到。
|