預設目錄:
第一部分:WinSDK
第二部分:MFC類基礎,C++程序編寫規范介紹
第三部分:MFC基於對話框程序
第四部分:Dll動態鏈接庫
第五部分:COM組件基礎
第六部分:COM組件幾個常用技術:IDispatch,可連接對象.
第七部分:COM組件的應用,以及MFC的COM編寫
第一部分:WinSDK
學習VC已近一年了,回顧我的學習歷史真是相當的艱苦。既沒有老師教,圖書館裡也沒有好書可看。為了買到好書,身上的銀子幾近花光,不得不過節衣縮食的生活。近些日來動起自己寫寫什麼的打算,一來可以對自己的學習狀況進行總結。二來,請教高手,可以幫忙指出錯漏之處。三來,說不定會對初學者們有所幫助, 最起碼也可以練練文筆。
OK。談正事喽。首先MFC(Microsoft Foundation Class)是一種用來構建Win32程序的類庫,但究其根本的話,是基於Windows老祖宗—Windows SDK,其歷史可以追溯到Window 3.x時代。它整個構架是由C來編寫的。更重要的是它的程序結構至今還是Win32程序的根本。因此,在學習VC的過程中,理解其程序結構是編寫Win32程序的根本。
下面,就是一個WinSDK程序的示例(摘自侯先生的《深入淺出MFC》,在侯捷站點上有其此書的繁體電子版)
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
if (!hPrevInstance)
if (!InitApplication(hInstance))
return (FALSE)
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage (&msg);
}
return (msg.wParam);
}
BOOL InitApplication(HINSTANCE hInstance)
{
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, "jjhouricon");
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = "GenericMenu";
wc.lpszClassName = "MyWindow";
return (RegisterClass(&wc));
}
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
hWnd = CreateWindow("MyWindow","This is Windows SDK",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
if (hWnd == NULL)
return (FALSE);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return (TRUE);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowPro(hWnd, message, wParam, lParam);
}
return 0;
}
首先,在C語言中的入口函數是main函數,在Win32程序中則是WinMain。其原型是
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int CmdShow)
第一個參數是hInstance,是所傳進來的值是此程序的當前程序實例句柄。什麼叫實例呢?當你運行兩次同一個Windows程序時,屏幕上會出現兩個一模一樣的窗口;這時我們就說這個程序就被生成了兩個實例。再舉一個例子,在你眼前擱仨蘋果,其時這個仨蘋果就是蘋果這一大類的三個實例。按照這個思路說實例就是一個抽象概念中的實體存在。那麼嚴格來說其時我們所編寫的並不是這個程序,而是這個程序的邏輯。而程序實例則是按照這個我們編寫的邏輯所生成的實體結果。而句柄就是用來代表實例的,它是一個32位的值。每一個實例都對就著一個32位的值,而這個值就被稱為句柄。不知道我說明白沒有。這裡的Instance就是當前程序被實例化後的句柄。而且屬於同一個實例中的資源是共享的。第二個參數hPreInstance則代表上一個(前一個)程序實例句柄,在Win32程序中這個值總為空(為零),第三個參數是lpCmdLine,這是一個字符串,記錄著啟動程序時的命令行,起著C中main函數的(argc,argv)的作用.最後nCmdShow則表示這個程序的窗口是否被顯示出來。
在主函數中,第一個要執行的函數就是InitApplication(),語句如下:
if (!InitApplication(hInstance))
return (FALSE);
這個函數所起的作用是注冊窗口類。注冊窗口類的意思就是告訴系統將我們的提供的圖標,菜單,消息處理函數,光標聯系起來成為一個窗口類,為後面的顯示窗口作准備。在InitApplication()函數中使用RegisterClass()來注冊窗口。如果成功則返回true,否則返回false。其唯一的參數是一個WNDCLASS結構。其中各字段功能如下:(關於具體值請查看MSDN)
style 指定窗口風格,譬如例子所舉的CS_HREDRAW表示當水平長度發生改變時,重畫整個窗口。 LpfnWndProc 指定窗口的消息處理函數,其函數的原型必須是
LRESULT CALLBACK WndProcName(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
WndProcName這一名字是隨便起的.
hInstance 標識該窗口屬於哪個程序實例.
hIcon 標識該窗口圖標的圖標句柄
hCurosr 標識該窗口光標的光標句柄
hbrBackground 標識該窗口的背景畫筆.
lpszClassName 為這個窗口類所起的名字,為後來建立窗口引用窗口類所用。
當注冊窗口類成功後就可以建立窗口了。主函數調用InitInstance()來建立窗口.在InitInstance()函數中使用CreateWindow();來建立窗口,其中第一個參數就是窗口類的名稱,則注冊窗口類時lpszClassName字段中的內容。如果成功則返回句柄,句柄代表剛剛建立好的窗口(實例)。否則的話返回的句柄為空。當建立好窗口的並不立即顯示,還需用ShowWindow來使系統顯示窗口,其參數就是一個窗口句柄(HWND)。看吧,在WinSDK中都是句柄來標識任何東西的(程序,窗口,圖標,光標,文件等等)。然後再使用UpdateWindow()讓窗口在屏幕上重繪一遍,使其真正顯示出來。最後返回true.
接著就是WinSDK中重要一節消息循環:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage (&msg);
}
在每個程序實例中系統都會給配置了一個消息隊列,當消息產生後(譬如:刷新WM_PAINT,鼠標移動WM_MOSEMVOE,鍵盤某個鍵被按下WM_KEYDOWN等等),就會將其放入隊列尾部。程序這裡用了一個while循環,這就是著名的消息循環了。GetMessage()在隊列頭部取出一條消息放入第一參數msg中,如果不是WM_QUIT (退出程序消息)消息則返回true,如果是WM_QUIT則返回false,結束循環。循環中第一個函數TranslateMessage()是鍵盤轉換函數,其功能是將虛擬鍵消息轉換成字符消息:
*WM_KEYDOWN/WM_KEYUP組合成一個WM_CHAR或WM_DEADCHAR消息
*WM_SYSKEYDOWN/WM_SYSKEYUP組合成一個WM_SYSCHAR或WM_SYSDEADCHAR消息。
並將組合成的消息放到隊列當中去,等以後處理。
DispatchMessage()函數是將消息傳送給相應的窗口消息處理函數中去。在MSG結構中有一個HWND字段它記錄著產生消息的窗口,DispatchMessage會查找這個HWND句柄屬於哪個窗口類,並將消息傳入這個窗口類所聯系的消息處理函數(在WNDCLASS結構中LpfnWndProc字段所指向的函數)中去。這樣它就完成了它的消息分配工作。在上面示例程序中,只注冊了一個窗口類。所以所有消息都是由這個窗口類的窗口實例所產生的,因此所有的消息都會被傳入WinProc中去了。
在消息處理函數的入口參數中,是標識一條消息的主要信息,hWnd發生消息的源窗口,message消息的類型表示發生了什麼消息,wParam,lParam與消息捆綁來的信息。因為在C\C++中類型是可以自由轉換的,所以根據不同消息,其裡面的內容是不一致。在消息處理函數中一般上是用switch/case語句來實現不同消息不同處理的。相信大家一看就明白怎麼回事了。
關於message中的信息在VC98\Include\WinUSER.h(參考行數1292)中有詳細的定義,各個消息的涵義可在MSDN中查到。
以上,就是我所知道的WinSDK所有東西。如果有什麼錯誤和遺漏之處,請寫信給我:[email protected];QQ:63068279。
(第一部分完)