[Win32]創建模態窗口


http://www.cnblogs.com/zplutor/archive/2011/02/20/1958973.html

Win32編程中,如果要顯示一個模態窗口,一般是先創建對話框模板,然后使用DialogBox來顯示對話框。這種做法很簡單,但存在一個問題:對話框是以資源的形式保存在可執行文件中的,如果可執行文件沒有進行加殼處理的話,任何人都可以通過ExeScope等資源修改工具修改對話框的內容,這對於含有版權信息的“關於”對話框來說是非常危險的,懷有不良目的的人只需進行簡單的操作就可以將一個軟件變成是自己的。

 

保護軟件的版權信息不被修改有很多種方法,在這里我想說的一種方法是用代碼來創建“關於”對話框的內容,在運行時才創建這個對話框,而不是通過對話框模板早早就創建好。既然不使用對話框模板,那就不能使用DialogBox函數來顯示模態的對話框了,所以這種方法的一個難點就是如何不使用DialogBox來創建一個模態的窗口。本文的重點在於如何解決這個難點,而不在於如何在運行時創建窗口的內容。

 

通過查閱MSDN,可以知道DialogBox實際上是一個宏,它調用DialogBoxParam函數來創建對話框。而后者通過CreateWindowEx函數創建窗口,然后disables父窗口,並開啟一個新的消息循環來處理對話框的消息。我們可以自己實現這個過程。

 

首先創建一個父窗口:

#include <windows.h>
#include "resource.h"

LRESULT CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void DisplayModelDialog(HWND hParent);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {

    WNDCLASS wndclass;
    wndclass.style = CS_HREDRAW | CS_VREDRAW;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpfnWndProc = DialogProc;
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = TEXT("Dialog");

    RegisterClass(&wndclass);
  
    wndclass.lpfnWndProc = WndProc;
    wndclass.lpszMenuName = TEXT("Menu");
    wndclass.lpszClassName = TEXT("Parent");
     
    RegisterClass(&wndclass);
    
    HWND hwnd = CreateWindow(
    TEXT("Parent"), 
    TEXT("Parent"),
        WS_OVERLAPPEDWINDOW,
    CW_USEDEFAULT, 
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    NULL, 
    NULL, 
    hInstance, 
    NULL);
    
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    
    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0)) {
    
         TranslateMessage(&msg);
         DispatchMessage(&msg);
    }
    return msg.wParam;
}


LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

    switch (message) {

    case WM_COMMAND:
        if (LOWORD(wParam) == ID_FILE_DIALOG) {
        DisplayModelDialog(hwnd);
        }
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

WinMain函數的開頭注冊了兩個窗口類,第一個“Dialog”窗口類是供模態窗口使用的,它使用DialogProc窗口過程;第二個“Parent”窗口是供父窗口使用的,它使用WndProc窗口過程。

 

父窗口含有一個名為“Menu”的菜單,該菜單有一個“Dialog”菜單項,點擊這個菜單項之后調用DisplayModelDialog函數來顯示模態的窗口。

 

DisplayModelDialog函數是顯示模態窗口的關鍵,下面是它的實現代碼:

void DisplayModelDialog(HWND hParent) {

    EnableWindow(hParent, FALSE);

    HWND hDlg = CreateWindow(
    TEXT("Dialog"),
    TEXT("Dialog"),
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    hParent,
    NULL,
    (HINSTANCE)GetWindowLong(hParent, GWL_HINSTANCE),
    NULL);

    ShowWindow(hDlg, SW_SHOW);
    UpdateWindow(hDlg);

    MSG msg;

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

    TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    EnableWindow(hParent, TRUE);
    SetForegroundWindow(hParent);
}

LRESULT CALLBACK DialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {

    switch (message) {

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

上面的代碼看上去幾乎就是一個新的Windows應用程序,不同的地方在於,函數的開頭和結尾增加了對EnableWindowSetForegroundWindow的調用。如果沒有對SetForegroundWindow的調用,在關閉模態窗口之后父窗口會最小化。

 

運行程序,點擊菜單上的Dialog項,就可以彈出一個模態窗口,點擊父窗口任意位置,模態窗口會閃爍,就像模態對話框的行為一樣。現在,可以修改模態窗口的樣式,並處理WM_CREATE消息在窗口中增加內容了。

 


免責聲明!

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



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