090908(星期二):学习MFC

来源:互联网 发布:mac os x 好用吗 编辑:程序博客网 时间:2024/05/21 22:04

一、win32程序基础

Windows程序必须在开始之前做些初始化工作,CreateWindow之前把窗口的外貌和行为在WNDCLASS里设置好,并进行注册:RegisterClass(&wc)

CreateWindow只是创建窗口,之后再利用ShowWindow进行显示。

 

RegisterClass封装在InitApplication函数中,

CreateWindow封装在InitInstance函数中。这样的封装方式主要是出于历史原因,Windows3.x时代,窗口类只需要注册一次就可以供多个实例instance使用。在MFC在,Init的两个函数封装为CWinApp类的两个虚函数。

 

int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

   LPSTR lpCmdLine, int nCmdShow)

{

    MSG msg;

 

    UNREFERENCED_PARAMETER(lpCmdLine); // 避免編譯時的警告

 

    if (!hPrevInstance)

        if (!InitApplication(hInstance))

            return (FALSE);

 

    if (!InitInstance(hInstance, nCmdShow))

        return (FALSE);

 

//初始化完成后,winmain进入消息循环:

    while (GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);

        DispatchMessage(&msg); // 分发到个窗口的WndProc中处理。

    }

 

    return (msg.wParam); // 傳回 PostQuitMessage 的參數

}

 

 

另外,MFC程序的入口函数,在MFC/SRC/APPMODULE.cpp

extern "C" int WINAPI

_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

       LPTSTR lpCmdLine, int nCmdShow)

{

       // call shared/exported WinMain

       return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);

}

 

二、Message Map的雏形

消息处理的最原始函数:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,

   WPARAM wParam, LPARAM lParam)

{

    int wmId, wmEvent;

 

    switch (message) {

        case WM_COMMAND:

            wmId = LOWORD(wParam);

            wmEvent = HIWORD(wParam);

            switch (wmId)

            {

                case IDM_ABOUT:

                    DialogBox(_hInst,

                    "AboutBox", // 對話盒資源名稱

                    hWnd, // 父視窗

                    (DLGPROC)About // 對話盒函式名稱

                    );

                    break;

 

                case IDM_EXIT:

                // 使用者想結束程式。處理方式與 WM_CLOSE 相同。

                    DestroyWindow (hWnd);

                    break;

 

                default:

                return (DefWindowProc(hWnd, message, wParam, lParam));

            }

            break;

 

        case WM_DESTROY: // 視窗已經被摧毀 (程式即將結束)

            PostQuitMessage(0);

            break;

        default:

            return (DefWindowProc(hWnd, message, wParam, lParam));

    }

    return (0);

}

 

大量的switch case语句,可扩展性不好。

是否可以更加模块化呢?定义一个MSGMAP_ENTRY的结构和dim宏:

struct MSGMAP_ENTRY {

UINT nMessage;

LONG (*pfn)(HWND, UINT, WPARAM, LPARAM);

};

#define dim(x) (sizeof(x) / sizeof(x[0]))

 

定义数组:

// 分别是消息和这个消息的处理函数

struct MSGMAP_ENTRY _messageEntries[] =

{

    WM_CREATE, OnCreate,

    WM_PAINT, OnPaint,

    WM_SIZE, OnSize,

    WM_COMMAND, OnCommand,

    WM_SETFOCUS, OnSetFocus,

    WM_CLOSE, OnClose,

    WM_DESTROY, OnDestroy,

} ;

 

这样以来大量switchWndProc函数可以变成:

LRESULT CALLBACK WndProc(HWND hWnd, UINT message,

                            WPARAM wParam, LPARAM lParam)

{

    int i;

    for(i=0; i < dim(_messageEntries); i++) { // 遍历对照表,找到就给对应的处理函数,时间复杂度一点都不会增加

        if (message == _messageEntries[i].nMessage)

            return((*_messageEntries[i].pfn)(hWnd, message, wParam, lParam));

    }

    return(DefWindowProc(hWnd, message, wParam, lParam));

}

于是WndProc就不需要对用户公开了,有新的消息及其处理,直接加在_messageEntries[]数组之中。

 

 

三、dialogue的运行

doModelmodeless

 

1,  dialog template,在rc文档中定义的外观属性

2,  dialog procedure,类似WndProc

 

 

四、Windows程序的生存过程

1,初始化时,CreateWindow创建一个Window

2WinMain函数不断的消息循环,使用GetMessage在消息队列中获取Msg

3,  获取后DispatchMessage,传给对应的WndProc函数;

4,  重复23

5,  当按下Close命令时,送出WM_CLOSE,进入WndProcDefWindowProc处理;

6,  DefWindowProc收到WM_CLOSE调用DestroyWindow销毁窗口,同时送出WM_DESTROY;

7,  PostQuitMessage

8,  PostQuitMessage消息送出WM_QUITWinMainWinMain退出消息循环。

 

原创粉丝点击