Подтвердить что ты не робот

Диалоги Windows API без использования файлов ресурсов

Я пытаюсь создать диалоговое окно с использованием С++ и API окон, но я не хочу, чтобы диалог определялся в файле ресурсов. Я не могу найти ничего хорошего в этом в Интернете, ни один из примеров, которые я прочитал, по-видимому, не определяет программный диалог.

Кто-нибудь знает, как это сделать? Простой пример в порядке, я пока не делаю с ним ничего сложного.

4b9b3361

Ответ 2

Раймонд Чен написал несколько постов о менеджере диалогов:

Ответ 3

Если все, что вы хотите сделать, это показать окно с элементами управления, можно создать окно без использования файлов ресурсов/сценариев (.rc).

Это не то же самое, что диалог, но это может быть проще, чем создавать диалог программно.

Сначала несколько замечаний о том, как это сделать:

  • Вместо того, чтобы создавать диалог в файле rc, вы можете вручную использовать CreateWindow (или CreateWindowEx) для создания дочерних окон главного окна. (для .NET WinForms программистов, эти окна, как Control с).

  • Этот процесс вообще не будет графическим (вам нужно будет вручную ввести местоположение и размер каждого окна), но я думаю, что это может быть отличным способом понять, как создаются диалоги под капотом.

  • Отсутствие реального диалога имеет ряд недостатков, а именно то, что вкладка не будет работать при переключении между элементами управления.


О примере:

  • В этом примере показано диалоговое окно с двумя кнопками, поле редактирования (программисты .NET winforms думают об этом как TextBox) и флажок.

Screenshot of window

Он был протестирован в следующих условиях:

  • x86 build
  • x64 build
  • Unicode build (определены UNICODE и _UNICODE)
  • _UNICODE не в _UNICODE (UNICODE и _UNICODE не определены)
  • Построен с помощью компилятора Visual Studio C
  • Построен с помощью компилятора Visual Studio C++
  • ОС: Windows 10 64 бит

Теперь для кода:

Обратите внимание, что было добавлено большое количество комментариев, чтобы попытаться документировать функции окон, я рекомендую скопировать/вставить это в текстовый редактор, для достижения наилучших результатов.

// This sample will work either with or without UNICODE, it looks like it 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 UNOCODE.
#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 WndProc, the dialog 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 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 necesary 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 };
    mainWindowClass.lpszClassName = TEXT("JRH.MainWindow"); // you can set the main window name to anything, but typically you should prefix custom window classes with something that makes it unique.
    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/

дальнейшее чтение

Встроенный набор оконных классов довольно ограничен, поэтому вам может быть интересно узнать, как вы можете определять свои собственные оконные классы (" Control s") с помощью winapi, см. Статьи ниже:

ПРИМЕЧАНИЕ. Первоначально я хотел, чтобы этот пост был посвящен программному созданию диалогов. Из-за ошибки с моей стороны я не осознавал, что нельзя просто "показать" окно в виде диалога. К сожалению, я не смог заставить работать установку, упомянутую Раймондом Ченом.

Ответ 4

Взгляните на этот toolkit, который описывает, как создавать диалоги без файлов ресурсов. Это в WTL, однако я уверен, что вы можете разобрать внутренности, чтобы достичь того же самого, используя API win32.

Ответ 6

Салам, Привет,  здесь вы можете найти, как использовать диалоговые окна Windows API без использования файлов ресурсов.  Учебник Winapi (C Win32 API, No MFC): http://zetcode.com/gui/winapi/