本人为初学者,水平有限,写blog主要为了记录自己学习的轨迹,代码介绍参考msdn,如有错误或者疏漏敬请各位批评指正,感谢您的阅读!
1.对Windows编程的基本认识
最简单的Windows编程时调用一些windows中的用户态的API,大多是User32.dll GDI32.dll这两个库文件中的函数。
MFC是一个类库(class libraries),以C++类的形式封装了Windows的API,并且包含一个应用程序框架,以减少开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。MFC是WINAPI与C++的结合,它不仅仅是一个页面开发系统,内含很多类的作用并不是一个界面类,不实现对一个窗口对象的控制,有一些是在windows内部处理的类。
2.对基本框架的理解过程
笔者在了解了基本的c语言知识之后,尝试阅读基本的框架代码。
每一个c语言的程序都有着自己的main函数,而based win32 的程序,有着WinMain function,作为程序的入口点,基本代码如下?
int CALLBACK WinMain(
_In_ HINSTANCE hInstance, //handle to the current instance
_In_ HINSTANCE hPrevInstance, //handle to the previous instance
_In_ LPSTR lpCmdLine, // command line of the application
_In_ int nCmdShow // control how the window to be shown
);
在winmain里,创建WNDCLASSEX的struct,其包含了一个窗口的基本信息,基本代码如下
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
之后需要注册窗口(其意义有点类似于在主程序之前写函数定义),基本代码如下
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
我们在注册窗口之后就可以创建窗口了,CREATEWINDOW返回值是一个HWND,handle to the window,用来跟踪窗口。
static TCHAR szWindowClass[] = _T("win32app");
static TCHAR szTitle[] = _T("Win32 Guided Tour Application");
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
500, 100,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Win32 Guided Tour"),
NULL);
return 1;
}
之后我们显示这个窗口,并让其可以update
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
接下来添加消息循环从消息队列里检索窗口相关的消息,接收到的消息送给WndProc处理
window application是基于消息的程序设计模式,用事件去驱动编程模式。所谓消息循环实际上就是从消息队列里接收消息,检索消息,发送给WndProc的程序循环。
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int) msg.wParam;
除此之外,还需要一个windows procedure function ,我们习惯叫它WndProc,基本代码如下
LRESULT CALLBACK WndProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
在windows程序内,事件发生,WinProc用来对事件作出处理响应(handle an event)。里面的pattern近似于一个switch 里面有多个case,根据收到的消息做出不同的响应。
示例如下:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// 初始化窗体
InitGame(hWnd, wParam, lParam);
break;
case WM_KEYDOWN:
// 键盘按下事件
KeyDown(hWnd, wParam, lParam);
break;
case WM_KEYUP:
// 键盘松开事件
KeyUp(hWnd, wParam, lParam);
break;
case WM_MOUSEMOVE:
// 鼠标移动事件
MouseMove(hWnd, wParam, lParam);
break;
case WM_LBUTTONDOWN:
// 鼠标左键按下事件
LButtonDown(hWnd, wParam, lParam);
break;
case WM_LBUTTONUP:
// 鼠标左键松开事件
LButtonUp(hWnd, wParam, lParam);
break;
case WM_TIMER:
// 定时器事件
if (currentStage != NULL && currentStage->timerOn) TimerUpdate(hWnd, wParam, lParam);
break;
case WM_PAINT:
// 绘图
Paint(hWnd);
break;
case WM_DESTROY:
//退出
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
3.little? pieces
(1)双缓冲绘图
笔者在学习中碰到的WndProc中WM_PAINT 函数,里面涉及到双缓冲绘图。
因为在WM_PAINT 中,进行图形的绘制时,程序的响应相当频繁,每一次执行OnEraseBKgnd的过程都要擦除原先屏幕上的图像,接着用背景色进行填充,最后再重新绘制。这不仅会引起绘制耗时太长的问题,也会导致绘图过程中屏幕上出现闪烁的现象。因此,我们想到,先将图片绘制到内存缓冲区当中,之后利用BitBlt,将其copy到屏幕上。BitBlt的执行速度很快,所以这很好的实现了将图片整体显示在屏幕上的效果。示例代码如下
void Paint(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hdc_window = BeginPaint(hWnd, &ps);
HDC hdc_memBuffer = CreateCompatibleDC(hdc_window);
HDC hdc_loadBmp = CreateCompatibleDC(hdc_window);
//初始化缓存
HBITMAP blankBmp = CreateCompatibleBitmap(hdc_window, WINDOW_WIDTH, WINDOW_HEIGHT);
SelectObject(hdc_memBuffer, blankBmp);
// 绘制背景到缓存
SelectObject(hdc_loadBmp, bmp_Background);
BitBlt(hdc_memBuffer, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, hdc_loadBmp, 0, 0, SRCCOPY);
//need to do
// 最后将所有的信息绘制到屏幕上
BitBlt(hdc_window, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, hdc_memBuffer, 0, 0, SRCCOPY);
// 回收资源所占的内存(非常重要)
DeleteObject(blankBmp);
DeleteDC(hdc_memBuffer);
DeleteDC(hdc_loadBmp);
// 结束绘制
EndPaint(hWnd, &ps);
}
待更新......
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
|