開文序

Win32 和 MFC,其實之前一直都有碰過,

只是到後來都是寫一些資料分析、數值分析的程式

都用 Console 介面去完成,從來沒想過特別寫成 Window 介面

在此先再強調一些別人特別常問的事..

Q1 : 學 Win32 好 還是學 MFC 好?

我建議是學 Win32, MFC 之後會很快上手, 如果您是工作上趕著用的話, 可以先買一本 MFC 聖經, 摸熟後也一定要再回頭學 Win32

Q2 : 我沒有程式底子適合學 Win32/MFC 嗎?

請先學 C++ 吧..

Q3 : 我只有學過 C,不會C++,適合學 Win32/MFC 嗎?

如果只學過 C 沒學過 C++, 請先直接看 C++ 中的類別、繼承、複載等關係單元

還有例外處理單元

正文

1. Win32 程式設計概念 : Win32 主要是拿來刻視窗用的, 裡面提供一狗票 API, 當然還有很多的 "觀念性" 東西要學,  特別是 "訊息" 與 "處理" 的概念,說穿了,早期的 C/C++ 程式進入點是 int main(), 而 win32 程式進入點變成了 int WINAPI WinMain(.......),   (還找得到進入點算不錯了..),  請記住一件事, win32 以後是以 "設計視窗程式" 為主的, 既然是視窗程式, 免不了一定會有所謂的 "訊息處理",  訊息的種類少說也是上百種,  建立視窗(WM_CREATE)、改變視窗大小(WM_SIZE)、拖曳檔案(WM_DRAG)... 一狗票,

以下所提及的也是重要的二大重點 (1) 建立視窗  (2) 視窗訊息的處理

2. 視窗結構體 - WNDCLASSEX :  先聲明, 如果你還不知道什麼叫 "類別(class)", 那代表你該先學學 C++, in32 裡面常用的視窗結構體就是 WNDCLASSEX, 定義如下

typedef struct {
    UINT cbSize;
    UINT style;
    WNDPROC lpfnWndProc;
    int cbClsExtra;
    int cbWndExtra;
    HINSTANCE hInstance;
    HICON hIcon;
    HCURSOR hCursor;
    HBRUSH hbrBackground;
    LPCTSTR lpszMenuName;
    LPCTSTR lpszClassName;
    HICON hIconSm;
} WNDCLASSEX, *PWNDCLASSEX;

(1) cbSize: 這個變數的大小, 常以 sizoef(WNDCLASSEX) 表示
(2) style : 視窗的樣式, 這部份可設定的很多, 常以  CS_HREDRAW | CS_VREDRAW 表示
 (3)  lpfnWndProc : 這是一個函數指標, 要先事先寫好一個處理視窗訊息的函數, 這個指標再指過去
 (4) cbClsExtra : 設 0
 (5) cbWndExtra : 設 0 
 (6) hInstance : 代表視窗的一個句柄 (說實話, handle 怎麼翻我是真的不會), 你可以把它想像成, OS會把每個視窗一個數字,  而這個數字我們就用 HANDLE 去管理它, HANDLE hInstance 便是告訴你 OS 給這個視窗的編號 
(7) hIcon, hIconSm : 你視窗出現的 Icon
 (8) hCursor: 在你視窗裡面所使用的 mouse 形狀
(9) hbrBackground : 設定視窗的背景顏色
(10) lpszMenuName: 設定 Menu 的名稱, 如果沒有 Menu , 設為 NULL,
(11) lpszClassName : 設定這個視窗的 Class Name

3. 設定完結構體後之步驟
    (1) 註冊(RegisterClassEx) - 設定完 WNDCLSSEX 後, 調用 RegisterClassEx 函數, 向系統註冊視窗類別, 成功時傳回 TRUE, 失敗傳回 FALSE
(2) 顯示視窗(ShowWindow) - 注意, 以上之動作都是在背後默默執行, 等到這些動作都 OK 的時候, 再進行視窗顯示之動作, ShowWindow() 函數裡有
SW_SHOWNORMAL, SW_HIDE, SW_MAXIMIZED, SW_MINIMIZED 等值可用, 下面用 SW_SHOWNORMAL
   (3) 立即更新一次視窗(UpdateWindow) - 當以上動作都做完時, 先更新一次視窗, 
   (4) 訊息處理 - 
(4.1) GetMessage - 取得對此視窗造成之訊息
(4.2) TranslateMessage - 將這些訊息傳送出去
(4.3) DispatchMessage - 將這些訊息解碼處理
上面都只是函數字面上的意思, 實作上大多是這麼做


while(GetMessage(...)) // 無窮迴圈去等待/取得訊息
{
TranslateMessage(....); // 將取得之訊息傳出去
Dispatchmessage(....); // 將取得之訊息進行解碼
}


當然, 我們還有一個步驟沒做, 就是編寫 "處理訊息的函數"
4. 處理訊息函數
   處理訊息的函數長得都差不多 -

LRESULT CALLBACK 訊息函數名稱(HWND hWnd,
UINT msg, WPARAM wParam, LPARAM );
   注意,上面可以改的真的也只有 訊息函數名稱,引數內容為固定
   而裡面的寫法基本上大同小異

   LRESULT CALLBACK 訊息函數名稱(HWND hWnd, 
UINT msg, WPARAM wParam, LPARAM lParam)
{
           switch(msg)
          {
                 case  訊息1(如WM_CREATE) :
                           ...... 
break;
case 訊息2 (如 WM_PAINT) ;
.........
break;
                 ......
......
default:
// 剩下沒做的, 叫 DefWindowProc 這個裡面就有的函數幫我們做
return DefWindowProc(hWnd, msg, wParam, lParam);
           }
           return 0;

}

5. 架構大致上上面都說明完畢, 還有一些參數、訊息定義, 不適合在這篇說完
往後會再進行補充, 若有興趣知道, 也歡迎回覆討論, 以下為完整之程式碼
請參考..


// ========================================
// filename: Hello.cpp
// author  : Edison.Shih.
// Date    : 2010.2.24
// Complier: VC 6.0
// ========================================

#include <windows.h>

// ========================================
// function declare

LRESULT CALLBACK MainProc(HWND hwnd,
                                      UINT msg,
                                      WPARAM wParam,
                                      LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance,
                              HINSTANCE hPrevInstance,
                              LPSTR lPCmdLine,
                              int nShowCmd);

// ========================================
// WinMain function
int WINAPI WinMain(HINSTANCE hInstance,
                              HINSTANCE hPrevInstance,
                              LPSTR lPCmdLine,
                              int nShowCmd)
{
      WNDCLASSEX wcx;
      HWND hwnd;
      MSG      msg;

      TCHAR ClsName[100] = ("Class Name");

      //填充視窗類別 wcx     
      wcx.cbClsExtra = 0;
      wcx.cbWndExtra = 0;
      wcx.cbSize = sizeof(wcx);
      wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
      wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
      wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
      wcx.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
      wcx.hInstance = hInstance;
      wcx.lpfnWndProc = MainProc;
      wcx.lpszClassName = ClsName;
      wcx.lpszMenuName = NULL;
      wcx.style = CS_HREDRAW | CS_VREDRAW;
     

      if(!RegisterClassEx(&wcx)) {
            MessageBox(NULL,("Register Fail."),MB_OK,NULL);           
            return 1;
      }


      hwnd = CreateWindow(
        "Class Name",
        "Title Name",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL,
        NULL,
        hInstance,
        NULL
    );


      if(!hwnd){
            MessageBox(NULL,("CreateWindow Fail."), MB_OK, NULL);
            return 1;
      }


      ShowWindow(hwnd, SW_SHOW);
      UpdateWindow(hwnd);

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

      return (int)(msg.wParam);
}


// ========================================
// map message function

LRESULT WINAPI CALLBACK MainProc(HWND hwnd,
                                                 UINT msg,
                                                 WPARAM wParam,
                                                 LPARAM lParam)
{
      // for WM_PAINT variable
      HDC hdc;
      PAINTSTRUCT ps;

      // message process
      switch(msg)
      {
      case WM_CREATE: // 視窗建立時
            break;

      case WM_PAINT: // 繪圖管理
            hdc = BeginPaint(hwnd, &ps);
            TextOut(hdc,0,0,("Hello,World"),strlen(("Hello,World")));
            EndPaint(hwnd, &ps);
            break;

      case WM_DESTROY: // 視窗毀滅時
            PostQuitMessage(0);
            break;

      case WM_SIZE: // 視窗改變大小時
            MessageBox(NULL, "change size..", MB_OK, NULL);
            break;

      default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
      }
      return 0;
}


// ========================================

最後,若對程式碼或概念有問題

歡迎回覆討論

arrow
arrow
    全站熱搜

    Edison 發表在 痞客邦 留言(10) 人氣()