孫鑫VC講座筆記–WINDOWS程式內部運行原理

來源:互聯網
上載者:User

聲明:

        本人最近也在看孫老師的視頻,為了加強理解,所以想一些讀書筆記。但是在CSDN上一搜尋,發現已經有朋友做了相關筆記。根據物件導向的“繼承”觀點,為瞭解決勞動力,所以我打算在他們的基礎上添加、修改。應該不涉及著作權什麼的東東吧?!

        我在BLOG.CSDN.NET/LEWISLAU上搜尋了下 ,有兩位朋寫了相關筆記(而且都是一樣的)。不知道誰才是原作者,所以列出兩位BLOG地址:

http://blog.csdn.net/hhitjsj021                                http://blog.csdn.net/d007879

以後我會在前輩的基礎上修改、發文!呵呵!繼承嘛!

 

 

 

 

windows程式設計是種事件驅動方式的程式設計,主要基於訊息的。當使用者需要完成某種功能時,需要調用OS某種支援,然後OS將使用者的需要封裝成訊息,並投入到訊息佇列中,最後應用程式從訊息佇列中取走訊息並進行響應。

 

MSG Structure

--------------------------------------------------------------------------------

The MSG structure contains message information from a thread's message queue.

Syntax

typedef struct {
    HWND hwnd;   //指示一個視窗的控制代碼,改訊息和那個視窗相關聯。
    UINT message;  //具體的訊息,用無符號整形表示
    WPARAM wParam; //關於訊息的附加參數
    LPARAM lParam; //同上
    DWORD time; //32位整數,表示訊息被投遞出去的時間
    POINT pt; //表示游標位置
} MSG, *PMSG;

 控制代碼,資源的標識,作業系統通過控制代碼指到資源。常見的控制代碼有表徵圖控制代碼(HICON),游標控制代碼(HCURSOR),視窗控制代碼(HWND),應用程式控制代碼(HINSTANCE)
 
例如:當按下按鍵會發送出WM_CHAR訊息   通過訊息的附加參數,儲存對應的ASCII碼,即可知道按下的是那個鍵。

 

 

訊息佇列:
每個應用程式OS都為它建立一個訊息佇列,訊息佇列是個先進先出的緩衝區,其中每個元素都是一個訊息,OS將產生的每個訊息按先後順序放進訊息佇列中,應用程式總是取走當前訊息佇列中的第一條訊息,應用程式取走訊息後便知道使用者的操作和程式的狀態,然後對其處理即訊息響應,訊息響應通過編碼實現。

使用VC編程除了良好的C基礎外還需要掌握兩方面:
一,訊息本身。不同訊息所代表的使用者操作和應用程式的狀態。
二,對於某個特定的訊息來說,要讓OS執行某個特定的功能去響應訊息。

Window程式入口:
int WINAPI WinMain(
  HINSTANCE hInstance,  // 當前案例控制代碼。
  HINSTANCE hPrevInstance,  // 先前案例控制代碼。
  LPSTR lpCmdLine,      // 命令列指標
  int nCmdShow          // (視窗)顯示的狀態
);
說明:WinMain函數是Windows程式進入點函數,由OS調用,當OS啟動應用程式的時候,winmain函數的參數由OS傳遞的。

 

建立一個完整的視窗需要經過下面四個操作步驟:
一,設計一個視窗類別;如:WNDCLASS wndcls;
二,註冊視窗類別;    如:RegisterClass(&wndcls);
三,建立視窗;      如:CreateWindow(),CreateWindowEX();
四,顯示及更新視窗。如:ShowWindow(),UpdateWindow();
說明:建立視窗的時候一定要基於已經註冊的視窗類別.

 

 

Windows提供的視窗類別:
typedef struct  WNDCLASS {
    UINT    style;        //視窗的類型
    WNDPROC lpfnWndProc;  //視窗過程函數指標(回呼函數)
    int     cbClsExtra; //視窗類別附加位元組,為該類視窗所共用。通常0。
    int     cbWndExtra; //視窗附加位元組。通常設為0。
    HANDLE  hInstance;  //當前應用程式案例控制代碼。
    HICON   hIcon;      //表徵圖控制代碼 LoadIcon();
    HCURSOR hCursor;    //游標控制代碼 LoadCursor();
    HBRUSH  hbrBackground; //畫刷控制代碼 (HBRUSH)GetStockObject();
    LPCTSTR lpszMenuName;  //菜單名字
    LPCTSTR lpszClassName; //類的名字
} WNDCLASS,*PWNDCLASS;

視窗類別型style為一個變數,該變數每一位對應著一種特性。對應為1時,有該種特性;對應為0時,無該種特性。為了方便記憶,用一些宏對應一些特徵,通過取反(~)和相與(&)可以取消一些特性。  通常設定為"CS_HREDRAW | CS_VREDRAW"表示垂直重繪和水平重繪。

HICON可以由LoadIcon 賦值(它有兩個參數HINSTANCE和LPCTSTR,通常第一個參數為空白,只對第二個參數賦值,即表徵圖的ID)
HCURSOR同HICON
HBRUSH 使用GetStockObject函數,它可以用來擷取筆、畫刷、字元、調試板的畫刷。使用時要用HBRUSH做一直強制轉化。因為GetStockObject傳回值和HBRUSH不同。

視窗類別註冊:
ATOM RegisterClass(
  CONST WNDCLASS *lpWndClass   // address of structure with class
                              // data
);
//注意,是使用地址符

 

建立視窗:
HWND CreateWindow(
  LPCTSTR lpClassName,  //註冊視窗類別名,用引號
  LPCTSTR lpWindowName, //視窗標題,用引號
  DWORD dwStyle,        //視窗類別型(風格)通常為(WS_OVERLAPPEDWINDOW)
  int x,                // 視窗X座標
  int y,                // 視窗X座標
  int nWidth,           // 寬度
  int nHeight,          // 高度
  HWND hWndParent,      // 指向父視窗的控制代碼
  HMENU hMenu,          // 菜單控制代碼
  HANDLE hInstance,     // 當前執行個體的控制代碼,由WINMAIN傳遞
  LPVOID lpParam        // WM_CREATE附加參數傳入指標
);
建立視窗的時候會發送WM_CREATE訊息

顯示和更新視窗視窗:
BOOL ShowWindow(
  HWND hWnd,     // handle to window
  int nCmdShow   // show state of window
);
BOOL UpdateWindow(
  HWND hWnd   // handle of window  送出WM_PAINT訊息
);

訊息迴圈
MSG msg;
while(GetMessage(&msg,...))    //從訊息佇列中取出一條訊息
{
 TranslateMessage(&msg); //進行訊息(如鍵盤訊息)轉化。轉化過程不會影響原訊息,只會建立新的訊息。
 DispatchMessage(&msg); //指派訊息到視窗的回呼函數處理,(OS調用視窗回呼函數進行處理)。
}

BOOL GetMessage(
  LPMSG lpMsg,         // 訊息結構體變數
  HWND hWnd,           // 控制代碼,那個一個視窗?為NULL則為所有視窗控制代碼
  UINT wMsgFilterMin,  // 最小訊息值,為0時返回所有訊息
  UINT wMsgFilterMax   // 最大訊息值
);

 

回調原理:當應用程式受到給某個視窗的訊息時,就應調用某一函數來處理這條訊息。這一訊息有作業系統自動完成。

註:函數名可以用以表示函數代碼的首地址(函數指標),額外資料通常為0。

視窗過程函數(回呼函數)原型:
LRESULT CALLBACK WindowProc(  //這裡WindowProc是個代號名字。
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);
說明:兩種函數呼叫慣例(__stdcall 和 __cdecl):
#define CALLBACK    __stdcall
//__stdcall 標準調用預定,是PASCAL 呼叫慣例,象DELPHI使用的就是標準呼叫慣例
#define WINAPIV     __cdecl 
// __cdecl 是C 語言形式的呼叫慣例。
主要區別:函數參數行程順序 和 對堆棧的清除上。
問題:除了那些可變參數的函數調用外,其餘的一般都是__stdcall約定。但 C/C++編譯默然的是__cdecl約定。所以如果在VC等環境中調用__stdcall約定的函數,必須要在函式宣告的時加上 __stdcall 修飾符,以便對這個函數的調用是使用__stdcall約定(如使用DELPHI編寫的DLL時候)。
(VC中可通過這途徑修改:project|settings..|c/c++|...)
在視窗過程函數中通過一組switch語句來對訊息進行處理:
如:
LRESULT CALLBACK WindowProc( 
  HWND hwnd,
  UINT uMsg,
  WPARAM wParam,
  LPARAM lParam  
)
{
    switch(uMsg)
    {
 case WM_PAINT:
  ...
  break;
 case ...
  break;
 case WM_CLOSE:
  //DestroyWindow(hwnd);
   //銷毀視窗,並發送WM_DESTROY訊息。
  break;
 case WM_DESTROY:
  //PostQuitMessage(0);
  //發送WM_QUIT訊息到訊息佇列中,請求終止。
         //GetMessage()取到WM_QUIT訊息後,返回0,退出訊息循                //   環,從而終止應用程式。
  break;
 default:
  return DefWindowProc(hwnd,uMsg,wParam,lParam);
 //用預設的視窗過程處理我們不感興趣的訊息(其它訊息)。
 //這是必須的。
    }//switch
 return 0;
}//WindowProc

 響應WM_DESTROY,調用PostQuitMessage(int)結束進程。它會投遞一個WM_QUIT訊息對訊息佇列中。當訊息迴圈的GetMessage取到WM_QUIT訊息,則返回0,程式結束。
 另外對於不感興趣的訊息要景象預設的處理,使用DefWindowProc()內為視窗的參數。

 

關於DC控制代碼擷取:
a)使用BeginPaint(),EndPaint()對。注意只能在響應WM_PAINT訊息時使用。
b)使用GetDc(),ReleaseDC()對。注意他們不能在響應WM_PAINT中使用

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.