首先:我们看一些简单的名词简写
API: Application Programming Interface 应用程序接口
SDK: Software Development Kit 名义为软件的开发工具,实际上也包括一些程序代码
MFC:Microsoft Foundation Classes 微软基础类库
DLL:Dynamic Link Library 动态链接库(长见识的一点,并不是只有.dll文件才是动态链接库文件,实际上.exe, .fon, .mod, .drv, .ocx都是)
GUI:Graphics User Interface图形用户界面
SDI:Simple Document Interface 简单的文件接口
UI:User Interface 用户界面
接下来讨论一下一个标准的Windows程序的基本框架:
我们都知道,windows系统是基于消息驱动的系统,即通过消息队列传递到每一个窗口去处理消息相应事件的。所以,一个标准的windows程序:
Step 1 : Windows.h文件包含
Step 2: 窗口过程WndProc,关于窗口过程函数,有一点值得关注的是,他是一个callback函数,也就是它自身提供的是一个回调函数,Windows Programming Model这样设计的原因是Windows系统方便自身可能也会调用你的函数,比如(窗口刷新)。
Step 3:WinMain中要实现的主要工作就是窗口注册和创建
,显示刷新,消息循环处理
窗口主函数WinMain其中主要的就是消息循环部分
一个简单的消息循环如下:
MSG msg = { 0 };
While (msg.message != WM_QUIT)
{
if (PeekMessage(&Msg, 0, 0, 0, PM_REMOVE))//应用程序以此获取对消息队列操作权利,并获取属于自己的消息
{
TranslateMessage(&Msg); //消息解析()
DispatchMessage(&Msg); //消息派发(通过USER模块发送到窗口函数)
}
Else
{
//TODO:
}
}
其中有两个消息抓取函数:GetMessage和PeekMassage,两个函数都是从消息队列抓取消息,如果抓不到,程序的主线程将会被操作系统挂起,当操作系统再次处理该线程的时候,发现消息队列中仍然是空的,那么这两个函数的操作就有些不同了;
GetMessage:如同大禹治水,过家门而不入。
PeekMessage:继续取回资源控制权,使得程序继续执行一段时间,也就是else里面做的事情了。
一个完成的例子:
Step Function:
#
include .h>
#define MAIN_CLASS_NAME TEXT("mainclass")
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE iPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int cx = GetSystemMetrics(SM_CXSCREEN);
int cy = GetSystemMetrics(SM_CYSCREEN);
cx = (cx - 800) / 2;
cy = (cy - 600) / 2;
WNDCLASSEX wndClass = { 0 };
wndClass.cbClsExtra = 0;
wndClass.cbSize = sizeof(WNDCLASSEX);
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = NULL;
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hInstance = hInstance;
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = MAIN_CLASS_NAME;
wndClass.lpszMenuName = NULL;
wndClass.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wndClass))
{
MessageBoxA(NULL, "Class registration faild!", "Error", 0);
return -1;
}
HWND Hwnd = CreateWindowEx(NULL, MAIN_CLASS_NAME, TEXT("test window"),
WS_OVERLAPPEDWINDOW , (cx), cy,
800, 600, NULL,
NULL, hInstance, NULL);
if (!Hwnd)
{
MessageBoxA(NULL, "HWND created faild!", "Erorr", NULL);
return -1;
}
MoveWindow(Hwnd, cx, cy, 800, 600, true);
ShowWindow(Hwnd, nCmdShow);
UpdateWindow(Hwnd);
MSG Msg = { 0 };
while (Msg.message != WM_QUIT)
{
if (PeekMessage(&Msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
break;
case WM_PAINT:
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
下面是一个关于Windows和窗口程序消息活动图:从图中可以看出,消息从用户获取到后,通过消息队列发送到该相应窗口,然后做消息处理工作的
一个基于界面的窗口程序是由UI和代码两部分完成的,如下,就是一个Windows SDK程序开发的全过程:
说完上面,我们关注一下其他的:
消息映射(message map),从《深入浅出MFC》中,有一个关于类似MFC的消息映射机制:
所以这样的话,窗口函数就可以设计成这样的:
以及对子窗口命令处理和其他函数处理就可以这样:
从而实现了WndProc以及OnCommand函数永远不用管他中间的操作,只需要处理其消息对应的消息函数就可以,比如想处理关于WM_PAINT消息,只需要重载其OnPaint函数即可。
对话框:
Windows对话框分为两种,一种是model对话框,其意在于“另其父窗口无效,直到对话框结束”,另一种是modeless对话框,其意在于父窗口于对话框同时运行。
窗口的生命周期:
从上,我们可以看出窗口运行的整个过程,如下:
.RC文件:
RC文件是一个以文字描述资源的文件,常用的有ICON、CUSOR、BITMAP等。这类文字描述资源需要RC编译器编译成二进制代码才能使用。