Я пытаюсь создать диалоговое окно с помощью C++ и API Windows, но мне не нужно, чтобы диалоговое окно определялось в файле ресурсов. Я не могу найти ничего хорошего в Интернете, и ни один из примеров, которые я прочитал, похоже, не определяет диалоговое окно программно.
Как я могу это сделать?
Простой пример подойдет. Ничего сложного пока не делаю.
Я хочу иметь возможность изменять его во время выполнения.
другая причина, на мой взгляд, любой может открыть ваш исполняемый файл и изучить ваши ресурсы, а также может редактировать его, изменять свойства !! Я хочу, чтобы это было скрыто
@ BrianR.Bondy Ну, раз уж вы спросили, мне, честно говоря, было просто любопытно посмотреть, есть ли способ создавать графические интерфейсы в winapi, используя только язык C. Ради интереса я исследую, как .NET построен поверх winapi для создания Windows Forms, и я просто решил начать как можно более низкоуровнево и вручную; концептуально понять, что такое окно на самом деле.





Взгляните на этот инструментарий, который описывает, как создавать диалоги без файлов ресурсов.
Это в WTL. Однако я уверен, что вы можете разделить внутреннее устройство, чтобы добиться того же, используя Win32 API напрямую.
Раймонд Чен написал несколько сообщений о диспетчере диалогов:
Попробуйте поискать в MSDN "шаблоны диалогов в памяти".
См. Это, например: Диалоговые окна
Примечание. Нет прямого примера того, как это сделать на связанной странице, это просто список функций, которые вы можете использовать для этого.
Здесь вы можете узнать, как использовать диалоги Windows API без использования файлов ресурсов.
Руководство по Windows API (только C Win32 API, без MFC):
Пока что это единственный ответ, который, кажется, действительно предоставляет код для использования CreateWindow вместо файла rc.
... однако, как я узнал в своем ответе, диалог, созданный с помощью CreateWindow, не ведет себя точно так же, как диалог, созданный с помощью редактора диалогов VS. Штопать.
Если все, что вы хотите сделать, это показать окно с элементами управления, можно создать окно без использования файлов / сценариев ресурсов (.rc).
Это не то же самое, что диалог, но это может быть проще, чем создание диалога программным способом.
Вместо разработки диалогового окна в файле rc вы можете вручную использовать CreateWindow (или CreateWindowEx) для создания дочерних окон главного окна. (для программистов .NET Windows Forms эти окна похожи на Controls).
Этот процесс вообще не будет графическим (вам нужно будет вручную ввести расположение и размер каждого окна), но я думаю, что это может быть отличным способом понять, как диалоги создаются под капотом.
У неиспользования реального диалога есть некоторые недостатки, а именно эта вкладка не будет работать при переключении между элементами управления.
TextBox) и флажок.Он был протестирован в следующих условиях:
UNICODE и _UNICODE)UNICODE и _UNICODE не определены)Обратите внимание, что было добавлено большое количество комментариев, чтобы попытаться задокументировать функции 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/
Встроенный набор оконных классов довольно ограничен, поэтому вам может быть любопытно, как вы можете определить свои собственные классы окон («Controls») с помощью Windows API, см. Статьи ниже:
NOTE: I originally intended this post to cover the creation of dialogs programmatically. Due to a mistake on my part I didn't realize that you can't just "show" a window as a dialog. Unfortunately I wasn't able to get the setup mentioned by Raymond Chen working.
Грамматические придирки: я не знаю, правильно ли говорить «В winapi» или «In winapi». Также это, вероятно, само собой разумеется, но будьте осторожны с программированием на winapi, что бы вы ни делали, не смешивайте версии функций unicode и non-unicode. Вы можете просто использовать все функции W-формы и забыть о (винтажной) совместимости с ANSI. Я был слишком большим задротом, чтобы не упомянуть совместимость с ANSI. Также функции winapi, как правило, не очень терпимы к неправильным типам дескрипторов, передаваемых в них, например, не передают hInstance во что-то, ожидающее HWND.
Обновление: возможно отобразить диалоговое окно в виде окна (например, пример HEXCALC Чарльза Петцольда в Программе Windows, 5-е издание, глава 11), но это не то же самое, что отображение диалогового окна, и, опять же, оно, к сожалению, имеет некоторые серьезные ограничения.
почему вы против наличия файла rc?