簡體   English   中英

Windows API 對話框不使用資源文件

[英]Windows API dialogs without using resource files

我正在嘗試使用 C++ 和 windows API 創建一個對話框,但我不希望在資源文件中定義該對話框。 我在 web 上找不到任何好的內容,而且我讀過的所有示例似乎都沒有以編程方式定義對話框。

我怎樣才能做到這一點?

一個簡單的例子就可以了。 我還沒有做任何復雜的事情。

如果您只想顯示帶有控件的 window,則可以在不使用資源 (.rc) 文件/腳本的情況下創建 window。

這與對話框不同,但它可能比以編程方式創建對話框更容易。

首先,關於如何完成的一些注意事項:

  • 您可以手動使用CreateWindow (或CreateWindowEx )來創建主 window 的子 windows,而不是在 rc 文件中設計對話框。 (對於 .NET Windows Forms程序員,這些Control程序員是一樣的)。

  • 這個過程根本不是圖形化的(您需要手動輸入每個窗口的位置和大小),但我認為這是了解如何在后台創建對話框的好方法。

  • 不使用真正的對話框有一些缺點,即在控件之間切換時該選項卡將不起作用。


關於示例:

  • 此示例具有一個帶有兩個按鈕的對話框、一個編輯框(.NET Windows Forms 程序員會認為它是一個TextBox )和一個復選框。

窗口截圖

它已經在以下條件下進行了測試:

  • x86 構建
  • x64 構建
  • Unicode 構建( UNICODE_UNICODE定義)
  • 非 Unicode 版本( UNICODE_UNICODE
  • 使用 Visual Studio 的 C 編譯器構建
  • 使用 Visual Studio 的 C++ 編譯器構建
  • 操作系統:Windows 10 64 位

現在看代碼:

請注意,已添加大量注釋以嘗試記錄 windows 功能,我建議將其復制/粘貼到文本編輯器中,以獲得最佳效果。

// This sample will work either with or without UNICODE, it looks like
// it's recommended now to use UNICODE for all new code, but I left
// the ANSI option in there just to get the absolute maximum amount
// of compatibility.
//
// Note that UNICODE and _UNICODE go together, unfortunately part
// of the Windows API uses _UNICODE, and part of it uses UNICODE.
//
// tchar.h, for example, makes heavy use of _UNICODE, and windows.h
// makes heavy use of UNICODE.
#define UNICODE
#define _UNICODE
//#undef UNICODE
//#undef _UNICODE

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

// I made this struct to more conveniently store the
// positions / size of each window in the dialog
typedef struct SizeAndPos_s
{
    int x, y, width, height;
} SizeAndPos_t;

// Typically these would be #defines, but there
// is no reason to not make them constants
const WORD ID_btnHELLO = 1;
const WORD ID_btnQUIT = 2;
const WORD ID_CheckBox = 3;
const WORD ID_txtEdit = 4;
const WORD ID_btnShow = 5;

//                                    x,      y,      width,  height
const SizeAndPos_t mainWindow   =   { 150,    150,    300,    300 };

const SizeAndPos_t btnHello     =   { 20,     50,     80,     25 };
const SizeAndPos_t btnQuit      =   { 120,    50,     80,     25 };
const SizeAndPos_t chkCheck     =   { 20,     90,     185,    35 };

const SizeAndPos_t txtEdit      =   { 20,     150,    150,    20 };
const SizeAndPos_t btnShow      =   { 180,    150,    80,     25 };

HWND txtEditHandle = NULL;

// hwnd:    All window processes are passed the handle of the window
//         that they belong to in hwnd.
// msg:     Current message (e.g., WM_*) from the OS.
// wParam:  First message parameter, note that these are more or less
//          integers, but they are really just "data chunks" that
//          you are expected to memcpy as raw data to float, etc.
// lParam:  Second message parameter, same deal as above.
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{

    switch (msg)
    {

    case WM_CREATE:
        // Create the buttons
        //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

        // Note that the "parent window" is the dialog itself. Since we are
        // in the dialog's WndProc, the dialog's handle is passed into hwnd.
        //
        //CreateWindow( lpClassName,        lpWindowName,       dwStyle,                                x,          y,          nWidth,         nHeight,            hWndParent,     hMenu,              hInstance,      lpParam
        //CreateWindow( windowClassName,    initial text,       style (flags),                          xPos,       yPos,       width,          height,             parentHandle,   menuHandle,         instanceHandle, param);
        CreateWindow(   TEXT("Button"),     TEXT("Hello"),      WS_VISIBLE | WS_CHILD,                  btnHello.x, btnHello.y, btnHello.width, btnHello.height,    hwnd,           (HMENU)ID_btnHELLO, NULL,           NULL);

        CreateWindow(   TEXT("Button"),     TEXT("Quit"),       WS_VISIBLE | WS_CHILD,                  btnQuit.x,  btnQuit.y,  btnQuit.width,  btnQuit.height,     hwnd,           (HMENU)ID_btnQUIT,  NULL,           NULL);

        // Create a checkbox
        //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        CreateWindow(  TEXT("button"),      TEXT("CheckBox"),   WS_VISIBLE | WS_CHILD | BS_CHECKBOX,    chkCheck.x, chkCheck.y, chkCheck.width, chkCheck.height,    hwnd,           (HMENU)ID_CheckBox, NULL,           NULL);

        // Create an edit box (single line text editing), and a button to show the text
        //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
        //Handle        = CreateWindow(windowClassName,    windowName,           style,                              xPos,       yPos,       width,          height,             parentHandle,   menuHandle,         instanceHandle, param);
        txtEditHandle   = CreateWindow(TEXT("Edit"),       TEXT("Initial Text"), WS_CHILD | WS_VISIBLE | WS_BORDER,  txtEdit.x,  txtEdit.y,  txtEdit.width,  txtEdit.height,     hwnd,           (HMENU)ID_txtEdit,  NULL,           NULL);

        //CreateWindow( windowClassName,    windowName,         style,                                  xPos,      yPos,      width,          height,           parentHandle,   menuHandle,         instanceHandle, param);
        CreateWindow(   TEXT("Button"),     TEXT("Show"),       WS_VISIBLE | WS_CHILD,                  btnShow.x, btnShow.y, btnShow.width, btnShow.height,    hwnd,           (HMENU)ID_btnShow,  NULL,           NULL);

        // Create an Updown control. Note that this control will allow you to type in non-number characters, but it will not affect the state of the control

        break;

    // For more information about WM_COMMAND, see
    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647591(v=vs.85).aspx
    case WM_COMMAND:

        // The LOWORD of wParam identifies which control sent
        // the WM_COMMAND message. The WM_COMMAND message is
        // sent when the button has been clicked.
        if (LOWORD(wParam) == ID_btnHELLO)
        {
            MessageBox(hwnd, TEXT("Hello!"), TEXT("Hello"), MB_OK);
        }
        else if (LOWORD(wParam) == ID_btnQUIT)
        {
            PostQuitMessage(0);
        }
        else if (LOWORD(wParam) == ID_CheckBox)
        {
            UINT checked = IsDlgButtonChecked(hwnd, ID_CheckBox);

            if (checked)
            {
                CheckDlgButton(hwnd, ID_CheckBox, BST_UNCHECKED);
                MessageBox(hwnd, TEXT("The checkbox has been unchecked."), TEXT("CheckBox Event"), MB_OK);
            }
            else
            {
                CheckDlgButton(hwnd, ID_CheckBox, BST_CHECKED);
                MessageBox(hwnd, TEXT("The checkbox has been checked."), TEXT("CheckBox Event"), MB_OK);
            }
        }
        else if (LOWORD(wParam) == ID_btnShow)
        {
               int textLength_WithNUL = GetWindowTextLength(txtEditHandle) + 1;
               // WARNING: If you are compiling this for C, please remember to remove the (TCHAR*) cast.
               TCHAR* textBoxText = (TCHAR*) malloc(sizeof(TCHAR) * textLength_WithNUL);

               GetWindowText(txtEditHandle, textBoxText, textLength_WithNUL);

               MessageBox(hwnd, textBoxText, TEXT("Here's what you typed"), MB_OK);

               free(textBoxText);
        }
        break;

    case WM_DESTROY:

        PostQuitMessage(0);
        break;
    }

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


// hInstance: This handle refers to the running executable
// hPrevInstance: Not used. See https://blogs.msdn.microsoft.com/oldnewthing/20040615-00/?p=38873
// lpCmdLine: Command line arguments.
// nCmdShow: a flag that says whether the main application window
//           will be minimized, maximized, or shown normally.
//
// Note that it's necessary to use _tWinMain to make it
// so that command line arguments will work, both
// with and without UNICODE / _UNICODE defined.
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    MSG  msg;
    WNDCLASS mainWindowClass = { 0 };

    // You can set the main window name to anything, but
    // typically you should prefix custom window classes
    // with something that makes it unique.
    mainWindowClass.lpszClassName = TEXT("JRH.MainWindow");

    mainWindowClass.hInstance = hInstance;
    mainWindowClass.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    mainWindowClass.lpfnWndProc = WndProc;
    mainWindowClass.hCursor = LoadCursor(0, IDC_ARROW);

    RegisterClass(&mainWindowClass);

    // Notes:
    // - The classname identifies the TYPE of the window. Not a C type.
    //   This is a (TCHAR*) ID that Windows uses internally.
    // - The window name is really just the window text, this is
    //   commonly used for captions, including the title
    //   bar of the window itself.
    // - parentHandle is considered the "owner" of this
    //   window. MessageBoxes can use HWND_MESSAGE to
    //   free them of any window.
    // - menuHandle: hMenu specifies the child-window identifier,
    //               an integer value used by a dialog box
    //               control to notify its parent about events.
    //               The application determines the child-window
    //               identifier; it must be unique for all
    //               child windows with the same parent window.

    //CreateWindow( windowClassName,                windowName,             style,                            xPos,         yPos,       width,              height,            parentHandle,   menuHandle,  instanceHandle, param);
    CreateWindow(   mainWindowClass.lpszClassName,  TEXT("Main Window"),    WS_OVERLAPPEDWINDOW | WS_VISIBLE, mainWindow.x, mainWindow.y, mainWindow.width, mainWindow.height, NULL,           0,           hInstance,      NULL);

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

    return (int)msg.wParam;
}

// This code is based roughly on tutorial code present at  http://zetcode.com/gui/winapi/

進一步閱讀

The builtin set of window classes are rather limited, so you might be curious as to how you can define your own window classes (" Control s") using the Windows API, see the articles below:

注意:我最初打算在這篇文章中介紹以編程方式創建對話框。 由於我的錯誤,我沒有意識到您不能只是將 window 作為對話框“顯示”。 不幸的是,我無法讓 Raymond Chen 提到的設置正常工作。

在這里您可以找到如何在不使用資源文件的情況下使用 Windows API 對話框。

The Windows API (only the C Win32 API, noMFC ) tutorial:

Windows API教程

看看這個工具包,它描述了如何在沒有資源文件的情況下創建對話框。

它在 WTL 中。 但是,我確信您可以直接使用 Win32 API 來分離內部結構以實現相同的目標。

嘗試在MSDN中搜索“內存中的對話框模板”。

例如,請參見: 對話框

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM