什么是消息循環,一個簡單的win32程序如何運行?


  預備知識

1.什么是句柄? (HANDLE)

在win32編程中有各種句柄,那么什么是句柄呢?

#define DECLARE_HANDLE(name)

struct name##_

{

  int unused;

};

typedef struct name_* name;

例如HDC的定義

#define DECLARE_HANDLE(HDC)

struct HDC_

{

  int unused;

};

typedef struct HDC_ * HDC 

當一個函數需要HWND類型參數的時候,你就不能傳遞HDC,因為類型不匹配。

總結:1.一個窗口句柄本質上是一個void * 2.win32編程中有特別多不同類型的窗口句柄,所以我們就把他們定義成不同的類型。例如HDC就是 HDC_*類型,HWND就是HWND_*類型。這樣能避免參數類型錯誤。

2.calling convention 函數調用約定

  這些現象通常是出現在C和C++的代碼混合使用的情況下或在C++程序中使用第三方的庫的情況下(不是用C++語言開發的),其實這都是函數調用約定(Calling Convention)和函數名修飾(Decorated Name)規則惹的禍。函數調用方式決定了函數參數入棧的順序,是由調用者函數還是被調用函數負責清除棧中的參數等問題,而函數名修飾規則決定了編譯器使用何種名字修飾方式來區分不同的函數,如果函數之間的調用約定不匹配或者名字修飾不匹配就會產生以上的問題

C (__cdecl )
The same constraints apply to the 32-bit world  as in the 16-bit world. The parameters are pushed from right to left (so that the first parameter is nearest to top-of-stack), and the caller cleans the parameters. Function names are decorated by a leading underscore.
 
This is the calling convention used for Win32, with exceptions for variadic functions (which necessarily use __cdecl) and a very few functions that use __fastcall. Parameters are pushed from right to left [ corrected 10:18am] and the callee cleans the stack. Function names are decorated by a leading underscore and a trailing @-sign followed by the number of bytes of parameters taken by the function.
 
variadic functions:  In  computer programming, a  variadic function is a  function of indefinite  arity
 
The first two parameters are passed in ECX and EDX, with the remainder passed on the stack as in __stdcall. Again, the callee cleans the stack. Function names are decorated by a leading @-sign and a trailing @-sign followed by the number of bytes of parameters taken by the function (including the register parameters).
 
The first parameter (which is the "this" parameter) is passed in ECX, with the remainder passed on the stack as in __stdcall. Once again, the callee cleans the stack. Function names are decorated by the C++ compiler in an extraordinarily complicated mechanism that encodes the types of each of the parameters, among other things. This is necessary because C++ permits function overloading, so a complex decoration scheme must be used so that the various overloads have different decorated names.
 
  完成一個簡單的win32程序
1.和所有的控制台程序都需要的一個main函數一樣,win32程序需要一個WinMain()函數
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
它有4個參數
hInstance:當前應用程序的句柄,一般是exe或者dll文件
hPrevInstance: win16編程需要的參數,在win32編程中一直為NULL
lpCmdLine:命令行參數
nCmdShow: ShowWindow()函數需要的參數。
2.創建一個窗口需要窗口類。窗口類描述窗口的窗口名稱、Icon、背景顏色、彈出方式等等窗口的特征。
WNDCLASS wc; //窗口類
然后我們初始化窗口類:

wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = LoadIcon(NULL, IDI_ASTERISK);
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.lpszClassName = szClassName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;

3.窗口函數WNDPROC。

窗口類初始化中有一個(WNDPROC)WndProc窗口函數。窗口函數就是窗口對各種消息的處理函數(鼠標點擊消息,鍵盤消息)。

我們使用switch case 結構來處理消息。

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
//The PAINTSTRUCT structure contains information for an application.
//This information can be used to paint the client area of a window owned by that application.
PAINTSTRUCT ps;
//The RECT structure defines the coordinates of the upper-left and lower-right corners of a rectangle.
RECT rect;

  switch(msg)
  {
  case WM_CREATE:
    PlaySound (L"hello.wav", NULL, SND_FILENAME | SND_ASYNC) ;
  break;
  case WM_PAINT:
    hdc = BeginPaint (hwnd, &ps);
    GetClientRect (hwnd, &rect) ;
    DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
    EndPaint(hwnd, &ps);
  break;
  case WM_CLOSE:
    DestroyWindow(hwnd);
  break;
  case WM_DESTROY:
    PostQuitMessage(0);
  break;
  default:
    return DefWindowProc(hwnd, msg, wParam, lParam);
  }
  return 0;
}

4.創建窗口

HWND hWnd;  //創建窗口返回的句柄。如果不是NULL則創建成功。

hWnd = CreateWindow(szClassName, L"HelloWorld", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 650, 400, NULL, NULL, hInstance, NULL);

5.顯示窗口

ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

6.消息循環

while(GetMessage(&msg, NULL, 0, 0) > 0)
{
  TranslateMessage(&msg);
  DispatchMessage(&msg);
}

 

  什么是消息循環,它如何工作?

1.消息循環調用while循環中的GetMessage()函數,GetMessage()函數在消息隊列中尋找消息。如果沒有消息,程序就一直“停”在while循環中。

2.當一個消息進入消息隊列時,比如你點擊鼠標觸發了一個消息。GetMessage()函數返回一個大於0的值,表示這個消息正在被處理,並給msg結構體賦值。

(WM_QUIT消息 GetMessage()函數返回0,如果產生錯誤 GetMessage()函數負值)。

3.我們獲得msg這個消息結構體,傳遞給TranslateMessage()函數,TranslateMessage()函數將虛擬的鼠標,鍵盤消息轉化成WM_開頭的字符串消息。

4.我們將字符串消息傳遞給DispatchMessage()函數。DispatchMessage()函數將會查找是那個窗口產生的消息,並且調用該窗口的窗口函數來處理。

我們將傳遞窗口的句柄,msg,wParam,lParam給窗口函數。

5.在窗口處理函數中,將檢查消息(該消息是WM_那種消息?),並在特定的case中處理。如果沒有這個消息的分類,則在DefWindowProc()函數中,默認處理。

6.一旦處理完消息,窗口處理函數返回,DispatchMessage()函數返回。程序又去消息隊列中尋找下一個消息(返回最初始的狀態)。

 

更多win32學習: http://www.winprog.org/tutorial/

 

完整代碼: https://github.com/Superxy/Win32/blob/master/SimpleWindow/SimpleWindow/SimpleWindow.cpp 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM