C++——Windows 程序開發

       開發 Windows API的Windows程序,需要編寫兩個函數。一個是Winmain()函數,程序的執行從這裏開始,基本的初始化工作也在這裏完成。另一個是WindowProc()函數,該函數由Windows調用,用來給應用程序傳遞消息。Winmain與WindowProc函數通過調用系統的API與Windows通信,如圖所示:

1 Winmain函數

Winmain()函數等價於控制檯的程序中的main()函數,Winmain()函數的原型如下:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow);

   (1) WINAPI是一個Windows定義的宏,將使系統以特定於Windows API函數的特種方式處理函數名和實參。

   (2) hInstance是指向某個實例的的句柄。

   (3) hPrevInstance是16位操作系統繼承下來的,現在的操作系統可以將這位始終設爲空。

   (4) lpCmdLine是指向某個字符串的指針,該字符串包括啓動程序的命令行字符。

   (5) nCmdShow決定着被創建窗口的外觀。

程序中的Winmain()函數需要做以下四件事情:

   (1) 指定程序窗口種類

   (2) 創建窗口

   (3) 初始化窗口

   (4) 處理部分消息

1.1 指定程序窗口

Windows使用WNDCLASSEX來包含用來指定窗口的數據,WNDCLASSEX 結構用於註冊窗口類,WNDCLASSEX的結構定義如下:

struct WNDCLASSEX {

UINT cbSize;                           // WNDCLASSEX 的大小

UINT style;                              //窗口類的樣式,它的值可以是窗口樣式值的任意組合

WNDPROC lpfnWndProc;      //指向窗口處理消息的函數的指針

int cbClsExtra;                        //允許請求Windows在內部爲特別用途提供額外空間,常用初始化爲0

int cbWndExtra;                     //允許請求Windows在內部爲特別用途提供額外空間,常用初始化爲0

HINSTANCE hInstance;        //當前應用程序的實例句柄

HICON hIcon;                       //最小化時的應用程序

HCURSOR hCursor;            //窗口使用的光標

HBRUSH hbrBackground;   //窗口客戶區的背景色

LPCTSTR lpszMenuName;  //定義窗口菜單的資源名稱;如果窗口沒有菜單,則定義爲NULL

LPCTSTR lpszClassName;  //指向窗口類的指針,LPSTR類型

HICON hIconSm;                 //小圖標的句柄,在任務欄顯示的圖標

};

1.2 創建程序窗口

將WNDCLASSEX結構的所有成員都設置爲所需的值後,下一步是把相關情況告訴Windows。使用RegisterClassEx()來完成這件事。假定WNDCLASSEX的對象是WindowsClass,則相應的語句如下所示:

RegisterClassEx(&WindowsClass);//註冊窗口類

接下來是創建窗口,由createWindow()函數完成。

HWND hWnd;                                       //窗體句柄

 hWnd = CreateWindow(
    szAppName,                                                 // the window class name
    _T("A Basic Window the Hard Way"),          //標題欄文本
    WS_OVERLAPPEDWINDOW,                    // 創建後的窗體樣式
    CW_USEDEFAULT,                                     // 窗體位置
    CW_USEDEFAULT,                                     // 左上角位置座標
    CW_USEDEFAULT,                                     // 窗體長度
    CW_USEDEFAULT,                                     // 窗體高度
    nullptr,                                     // 如果不是父窗體設置爲空
    nullptr,                                     // 沒有菜單設置爲空
    hInstance,                                   // Program Instance handle
    nullptr                                      // No window creation data
    );

在調用CreateWindow()函數後,被創建的窗口現在已經存在,但是還沒有顯示在屏幕上。需要調用另一個Windows API函數將該窗口顯示出來:

 ShowWindow(hWnd, nCmdShow); 

第一個參數是CreateWindow()函數返回的句柄。第二個參數是給Winmain()傳遞的nCmdShow值,它指出在屏幕顯示窗口的方式。

1.3 初始化程序窗口

在調用 ShowWindow()函數後,該窗口將出現在屏幕上,但仍然沒有應用程序的內容。繪製工作區的最好方法是把繪製工作區的代碼放入WindowProc()函數,並使Windows給程序發送請求重畫工作區的消息。調用另一個Windows API函數UpdateWindow(),請求Windows給程序發送一條重畫窗口工作區的消息。調用該函數的窗口如下:

UpdateWindow(hwnd);

1.4 處理Windows消息

Windows有兩種消息:一種是排隊消息,Winmain()從隊列中提取這些消息進行處理,稱爲消息循環;另一種是致使Windows直接調用WindowsProc()函數的非排隊消息。我們在Winmain()函數的消息循環中所作的事情是從Windows爲應用程序排好的消息隊列中提取一條消息,然後請求Windows調用WindowsProc()函數來處理該消息。

while (GetMessage(&msg, nullptr, 0, 0) == TRUE) // Get any messages
  {
    TranslateMessage(&msg);                      // Translate the message
    DispatchMessage(&msg);                       // Dispatch the message
  }
  • GetMessage()——從隊列中檢索一條消息
  • TranslateMessage()——對檢索的消息執行必要的轉換
  • DispatchMessage()——使Windows調用應用程序的WindowProc()函數來處理消息

2 處理Windows消息

使Windows以我們希望的方式運行的所有代碼都在程序的消息處理部分——WindowProc()函數

2.1 WindowProc()函數

WindowProc()函數的原型如下:

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam);

可以使用WINAPI替代CALLBACK,但後者更好地表達出這個函數的作用。每個參數的意義如下:
HWND hWnd : 一個句柄,事件引起消息發生的窗口
UINT message: 消息的ID,指出消息類型的32爲整數值
WPARAM wParam : 32位值,包含附加信息,決定於消息的種類
LPARAM lParam: 32位值

2.2 解碼Windows消息

switch (message)                               // Process selected messages
  {
  case WM_PAINT:    

  //繪製窗口工作區的代碼

   break;

case WM_LBUTTONDOWN:

//處理鼠標左鍵按下時的事件

break;

case WM_LBUTTONUP:

  //處理鼠標釋放時的事件

 break;

......

case WM_DESTROY:                               // Window is being destroyed
   //退出窗口
 break;

default:

//其他默認語句

}

3 完整程序代碼

 

#include <windows.h>
#include <tchar.h>

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message,
  WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX WindowClass;                        // Structure to hold our window's attributes

  static LPCTSTR szAppName { _T("OFWin") };      // Define window class name
  HWND hWnd;                                     // Window handle
  MSG msg;                                       // Windows message structure

  WindowClass.cbSize = sizeof(WNDCLASSEX);       // Set structure size

  // Redraw the window if the size changes
  WindowClass.style = CS_HREDRAW | CS_VREDRAW;

  // Define the message handling function
  WindowClass.lpfnWndProc = WindowProc;

  WindowClass.cbClsExtra = 0;                    // No extra bytes after the window class
  WindowClass.cbWndExtra = 0;                    // structure or the window instance

  WindowClass.hInstance = hInstance;             // Application instance handle

  // Set default application icon
  WindowClass.hIcon = LoadIcon(nullptr, IDI_APPLICATION);

  // Set window cursor to be the standard arrow
  WindowClass.hCursor = LoadCursor(nullptr, IDC_ARROW);

  // Set gray brush for background color
  WindowClass.hbrBackground = static_cast<HBRUSH>(GetStockObject(GRAY_BRUSH));

  WindowClass.lpszMenuName = nullptr;            // No menu
  WindowClass.lpszClassName = szAppName;         // Set class name
  WindowClass.hIconSm = nullptr;                 // Default small icon

  // Now register our window class
  RegisterClassEx(&WindowClass);

  // Now we can create the window
  hWnd = CreateWindow(
    szAppName,                                   // the window class name
    _T("A Basic Window the Hard Way"),           // The window title
    WS_OVERLAPPEDWINDOW,                         // Window style as overlapped
    CW_USEDEFAULT,                               // Default screen position of upper left
    CW_USEDEFAULT,                               // corner of our window as x,y.
    CW_USEDEFAULT,                               // Default window size width ...
    CW_USEDEFAULT,                               // ... and height
    nullptr,                                     // No parent window
    nullptr,                                     // No menu
    hInstance,                                   // Program Instance handle
    nullptr                                      // No window creation data
    );

  ShowWindow(hWnd, nCmdShow);                    // Display the window
  UpdateWindow(hWnd);                            // Redraw window client area 

  // The message loop
  while (GetMessage(&msg, nullptr, 0, 0) == TRUE) // Get any messages
  {
    TranslateMessage(&msg);                      // Translate the message
    DispatchMessage(&msg);                       // Dispatch the message
  }

  return static_cast<int>(msg.wParam);           // End, so return to Windows
}


LRESULT CALLBACK WindowProc(HWND hWnd, UINT message,
  WPARAM wParam, LPARAM lParam)
{

  switch (message)                               // Process selected messages
  {
  case WM_PAINT:                                 // Message is to redraw the window
    HDC hDC;
    PAINTSTRUCT PaintSt;                         // Structure defining area to be drawn
    hDC = BeginPaint(hWnd, &PaintSt) ;           // Prepare to draw the window

    // Get upper left and lower right of client area
    RECT aRect;                                  // A working rectangle
    GetClientRect(hWnd, &aRect);

    SetBkMode(hDC, TRANSPARENT);                 // Set text background mode

    // Now draw the text in the window client area
    DrawText(
      hDC,                                       // Device context handle
      _T("But, soft! What light through yonder window breaks?"),
      -1,                                        // Indicate null terminated string
      &aRect,                                    // Rectangle in which text is to be drawn
      DT_SINGLELINE |                            // Text format - single line
      DT_CENTER |                                //             - centered in the line
      DT_VCENTER);                               //             - line centered in aRect

    EndPaint(hWnd, &PaintSt);                    // Terminate window redraw operation
    return 0;

  case WM_DESTROY:                               // Window is being destroyed
    PostQuitMessage(0);
    return 0;
  }
  return DefWindowProc(hWnd, message, wParam, lParam);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章