《深入浅出mfc》 第1章 笔记
需要什么函数库(.lib)
windows支持动态链接库,应用程序所调用 的windows api 函数是在“执行期间“才链接上的。Windows程序调用 可以分为 C Runtimes以及windows api 大概两部分。早期的C Runtimes并不支持动态链接,vc++ 4.0之后已经支持。并且在32位已不在拥有small/medium/large等内存模式之分。
LIBC.lib:这是c Runtime函数库的静态版本
MSVCRT.lib:这是 c Runtime函数的动态库版本(MSVCRT40.dll)的import函数库。程序运行期间必须有MSVCRT40.dll在场。
另一组函数Windows Api由操作系统本身提供(GDI32.dll、USER32.DLL,Kernel32.DLL)。虽说动态链接库是在执行期间发生的。但是链接器仍需要先为调用者准备一些适当的信息。这些适当的信息放在”import函数库”,32位的windows的三大模块对应的 import函数库分别为GDI32.lib user32.lib kernel32.lib。
消息映射的雏形
《windows程序设计》里面的消息循环(WndPorc) switch case 语句 如下
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
为了把窗口函数设计一旬模块化,一般化。下面是一种做法。
//首先定义一个MSGMAP_ENTRY结构和一个dim宏 struct MSGMAP_ENTRY { UINT nMessage; LONG (*pfn)(HWND ,UINT,WPARAM,LPARAM); }; #define dim(x) (sizeof(x)/sizeof(x[0])) //把欲处理的消息以及消息处理全程关联性建立起来 struct MSGMAP_ENTRY _messageEntries[] = { WM_CREATE,OnCreate, WM_PAINT,OnPaint, WM_SIZE,OnSize, WM_COMMAND,OnCommand, WM_SETFOCUS,OnSetFocus, WM_CLOSE,OnClose, WM_DESTROY,OnDestroy }; //Command-ID 与处理全程之间对照表格 struct MSGMAP_ENTRY _commandEntries[] = { IDM_ABOUT,OnAbout, IDM_EXIT,OnExit }; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int i; for(i = 0;i < dim(_messageEntries);i++) if(message == _messageEntries[i].nMessage) return (*_messageEntries[i].pfn)(hWnd,message,wParam,lParam); return DefWindowProc(hWnd,message,wParam,lParam); } LONG OnCommand(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { for(int i =0;i<dim(_commandEntries);i++) if(LOWORD(wParam) == _commandEntries[i].nMessage) return (*_commandEntries[i].pfn)(hWnd,message,wParam,lParam); return DefWindowProc(hWnd,message,wParam,lParam); } LONG OnCreate(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { } LONG OnAbout(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { } ...
这样WndPorc和OnCommand永远不变。每当处理新消息的时候给结构体里面加元素就行了
Windows 程序的生与死
空间时间的处理OnIdle
空间时间是指”系统中没以任何消息等待处理“的时间。空间时间常常发生,不要认为你鼠标移动时产生一大堆WM_MOUSEMOVE消息,事实上夹杂在每一个WM_MOUSEMOVE之间就可能存在许多空间时间。毕竟,计算机速度超乎想象。
后台工作最适宜在空闲时间做,传送sdk程序如果要处理空间时间,可以以下循环取代WinMain中的消息循环。
while(TRUE) { if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if(mes.message == WM_QUIT) break; TranslateMessage(&msg); DispatchMessage(&msg) } else OnIdle(); }
什么是 C Runtime 函数库的多线程版本
当 C Runtime函数库与20世纪70年代出来时 pc 容量很少,多任务是个新奇观念,更别提多线程了。因此当时产品基础所演化的 c runtime函数库在多线程的表现上出现了严重问题。无法被多线程程序调用 。
利用更种同步机制 如 critcal section mutex semaphore event 可以重新开发一套支持多线程的runtime 函数库。问题是加上这样的能力可能导致程序代码大小和执行效率都遭受不良的波及----即使你只激活了一个线程。
VC++的折衷方案是提供两种版本的 c runtime函数库。一种版本给单线程使用,一种版本给多线程程序使用。多线程版本的重大改变是第一、变量加errno者现在变成每个线程拥有一个,第二、多线程版本中的数据结构同步机制加以保护 。
Vc++一共有六个 c runtime函数库产品供您选择
- Single-Threaded(static) libc.lib
- Mutithreaded(static) libcmt.lib
- mutithread dll msvcrt.lib
- debug single-threaded(static) libcd.lib
- debug mutithreaded(static) libcmtd.lib
- debug mutithread dll msvcrtd.lib
VC++编译器提供以下选项,让我们决定使用哪一个 c runtime函数库
- /ML Single-threaded(static)
- /MT Mutithread (static)
- /MD Mutithread dll (dynamic import libray)
- /MLD debug single-thread(static)
- /MTD debug mutithread(static)
- /MDD debug mutithread dll(dynamic import libray)