win32 最基本編程和應用程序框架


現在市場上出現了很多應用程序框架,比如窗體程序,如MFC,.net framwork , VB , delphi,舉不勝數。

其實,這些並不是開發windows應用程序必需的東西,windows在底層是爲我們開放了一套API函數庫,使用這套函數庫,其實我們也能構建出一套功能強健的windows應用程序。

下面,我重點說明一下windows的窗口應用程序,其實,windows窗口程序的核心就是窗口,一個windows窗口應用程序是由無數的窗口構成。

比如MFC裏面,一個按鈕或者一個列表,一個文本框控件,其實就是主窗口的一個子窗口,子窗口和主窗口一樣,有消息處理和可以擁有其子窗口。

我們用C++,調用win32 API,用vs 6.0去編譯,寫一個最基本的win32應用程序,轉到用例中,說明一個最基本的windows窗口程序的基本原理。


      #include <windows.h>
      #include <windowsx.h>
      //函數聲明
      BOOL InitWindow( HINSTANCE hInstance, int nCmdShow );
      LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM
      lParam );
      //*******************************************************************
      //函數:WinMain()
      //功能:Win32應用程序入口函數。創建主窗口,處理消息循環
      //*******************************************************************
      int PASCAL WinMain( HINSTANCE hInstance, //當前實例句柄
      HINSTANCE hPrevInstance, //前一個實例句柄
      LPSTR lpCmdLine, //命令行字符
      int nCmdShow) //窗口顯示方式
      {
      MSG msg;
      //創建主窗口
      if ( !InitWindow( hInstance, nCmdShow ) )
      return FALSE;
      //進入消息循環:
      //從該應用程序的消息隊列中檢取消息,送到消息處理過程,
      //當檢取到WM_QUIT消息時,退出消息循環。
      while (GetMessage(&msg, NULL, 0, 0))
      {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
      }
      //程序結束
      return msg.wParam;
      }
      //******************************************************************
      //函數:InitWindow()
      //功能:創建窗口。
      //******************************************************************
      static BOOL InitWindow( HINSTANCE hInstance, int nCmdShow )
      {
      HWND hwnd; //窗口句柄
      WNDCLASS wc; //窗口類結構
      //填充窗口類結構
      wc.style = CS_VREDRAW | CS_HREDRAW;
      wc.lpfnWndProc = (WNDPROC)WinProc;
      wc.cbClsExtra = 0;
      wc.cbWndExtra = 0;
      wc.hInstance = hInstance;
      wc.hIcon = LoadIcon( hInstance, IDI_APPLICATION );
      wc.hCursor = LoadCursor( NULL, IDC_ARROW );
      wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
      wc.lpszMenuName = NULL;
      wc.lpszClassName = "EasyWin";
      //註冊窗口類
      RegisterClass( &wc );
      //創建主窗口
      hwnd = CreateWindow(
      "EasyWin", //窗口類名稱
      "一個基本的Win32程序", //窗口標題
      WS_OVERLAPPEDWINDOW, //窗口風格,定義爲普通型
      100, //窗口位置的x座標
      100, //窗口位置的y座標
      400, //窗口的寬度
      300, //窗口的高度
      NULL, //父窗口句柄
      NULL, //菜單句柄
      hInstance, //應用程序實例句柄
      NULL ); //窗口創建數據指針
      if( !hwnd ) return FALSE;
      //顯示並更新窗口
      ShowWindow( hwnd, nCmdShow );
      UpdateWindow( hwnd );
      return TRUE;
      }
      //******************************************************************
      //函數:WinProc()
      //功能:處理主窗口消息
      //******************************************************************
      LRESULT CALLBACK WinProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM
      lParam )
      {
      switch( message )
      {
      case WM_KEYDOWN://擊鍵消息
      switch( wParam )
      {
      case VK_ESCAPE:
      MessageBox(hWnd,"ESC鍵按下了!","Keyboard",MB_OK);
      break;
      }
      break;
      case WM_RBUTTONDOWN://鼠標消息
      {
      MessageBox(hWnd,"鼠標右鍵按下了!","Mouse",MB_OK);
      break;
      }
      case WM_PAINT://窗口重畫消息
      {
      char hello[]="你好,hello world !";
      HDC hdc;
      PAINTSTRUCT ps;
      hdc=BeginPaint( hWnd,&ps ); //取得設備環境句柄
      SetTextColor(hdc, RGB(0,0,255)); //設置文字顏色
      TextOut( hdc, 20, 10, hello, strlen(hello) );//輸出文字
  
      EndPaint( hWnd, &ps ); //釋放資源
      break;
      }
      case WM_DESTROY://退出消息
      PostQuitMessage( 0 );//調用退出函數
      break;
      }
      //調用缺省消息處理過程
      return DefWindowProc(hWnd, message, wParam, lParam);
      }

 

這個程序有三個最基本的函數,一個是WinMain,一個是WinProc,一個是InitWindow。

WinMain是函數的主入口函數,hInstance是本進程的句柄,它主要用來以後作參數傳遞給需要調用的函數,不知道的朋友可以先不管它。
lpCmdLine是別人打開使應用程序的時候,傳進來的參數,一般雙擊運行的程序,使參數爲空指針。
但假如是像在命令行裏輸入一個ping 61.144.56.101這樣打開ping應用程序,61.144.56.101就是作爲參數傳遞的。
nCmdShow爲窗體顯示方式,在這裏可以先不管。


再來看看InitWindow,InitWindow是我們自己定義的函數,並不是windows自有的函數,在main函數裏,我們調用了InitWindow這個函數。
首先我們來看看,InitWindow這個函數將前面的兩個參數hInstance和nCmdShow傳了進來,這兩個參數是註冊窗體時所必需的。
WNDCLASS wc,其實就是創建一個窗口類,這是windows創建窗口程序最基本的類,他有的參數假如大家不知道,可以去查msdn,這裏不再討論。

接着我們使用RegisterClass( &wc )註冊這個窗口類,然後調用CreateWindow創建一個窗口,它的原型如下:

HWND CreateWindow(
  LPCTSTR lpClassName,
  LPCTSTR lpWindowName,
  DWORD dwStyle,
  int x,
  int y,
  int nWidth,
  int nHeight,
  HWND hWndParent,
  HMENU hMenu,
  HANDLE hInstance,
  PVOID lpParam
);

其中,hWndParent爲父窗口的句柄,假如 hWndParent不爲空,代表爲某一個父窗口創建一個子窗口。
其函數的參數我不一一說明了,其中我們最關心的就是他的返回值,是一個HWND類型的句柄,保存好這個返回後的句柄,以作以後調用。

我們再來回過頭來看看窗口類WNDCLASS 的lpfnWndProc屬性,其實它是一個回調函數指針,指向一個自定義函數,當windows窗口消息產生後,windows內核會自動調用此函數。
注意WM_PAINT消息是我們必需處理的消息,在這個消息裏面,我們要用windows自帶的繪圖方法,將需要顯示的內容繪製出來,這個消息在你們改變窗口大小,最大化,最小化的很多時候都會觸發,假如不在這個消息裏面寫東西,那麼創建的窗口將會空白一片。
lpfnWndProc指向的回調函數一個非常重要的函數,比如我們創建了一個用於作按鈕的子窗口,那麼WM_LBUTTONDOWN左鍵點擊消息就很重要的,用於響應其點擊事件。又比如製作一個文本框輸入窗口,那麼WM_KEYDOWN和WM_PAINT消息是很重要的,我們可以在用戶按下鍵盤的時候,用繪圖方法將用戶的輸入繪製出來。

我們的WinProc函數,裏面有一些消息的處理例子,當然,這個的消息類型還有很多,那裏只是極少的一部分。


最後,我們看到main函數裏面有個死循環,那是要讓主線程處於等待狀態,讓它永遠地執行下去,不結束其生命週期,直到收到退出消息後,此循環才結束。


這樣,我們已經創建了一個windows最簡單的窗口程序,但是,這是遠遠不夠的,真正的應用中,我們還必須去處理unicode,多字節字符,多線程,線程同步,IO模型,完成端口這些東西。有興趣的朋友可以看看windows核心編程這本書,的確是一本好書。


大的開發框架,大如mfc,其實也是基於這些最基本的程序開發出來的。假如你不想打包龐大的mfc或者.net framwork框架,假如你有能力,不想依賴於框架,想更加靈活的寫程序,假如你想做綠化版,那麼純淨的win 32程序就是首選。窗口、子控件它們其實就是都由CreateWindow,WinProc構成,在WinProc的WM_PAINT規劃你的顯示,在其他消息裏處理你的邏輯。

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