How to create Modeless Dialog Box without using .rc file or resource.h?

Trying to create a Modeless Dialog Box without using the Resource file (.rc) or resource.h...

User clicks menu item which calls case 'ID_HELP_ABOUT' in WndProc.

Following code then executes under WndProc:

1
2
3
4
5
6
hDialog = CreateDialog(GetModuleHandle(NULL), L"About", hWnd, AboutDlgProc);

if(hDialog == NULL)
{
MessageBox(hWnd, L"hDialog handle returned NULL", L"ERROR", MB_OK);
}


It always returns NULL value for the handle hDialog.

What am I doing wrong?

I've tried placing the same code just before the message handling loop and still get the same error.

Is it because I'm not using the Resource Editor and therefore haven't 'created' a Dialog Box yet?
Last edited on
Get extended error information by calling GetLastError so you can know what the reason is.

That said, there is a macro CreateDialogA (and CreateDialogW) which takes these parameters, but not a function returning hDialog.

Maybe you really need CreateDialogParamA or CreateDialogParamW?

Look them up in the Microsoft Docs to understand.
I can help you out by giving you a convenience method for descriptive error checking:
You can use it as shown below to get a message box describing an error!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
//
// Includes
//
#include <sdkddkver.h>
#include <Windows.h>
#include <cstring>		// std::strrchr
#include <string>		// std::string std::wstring
#include <comdef.h>		// _com_error
#include <codecvt>		// string conversion std::wstring_convert and std::codecvt_utf8

//
// helper macros
//
#ifdef UNICODE
	typedef std::wstring string;
#else
	typedef std::string string;
#endif // UNICODE

// conditionaly use string or wide string
#ifdef UNICODE
// converto to wide string
#define to_string std::to_wstring
#else
// convert to ANSI string
#define to_string std::to_string
#endif // UNICODE

// Show only file name instead of full path
#define __FILENAME__ (std::strrchr(__FILE__, '\\') ? std::strrchr(__FILE__, '\\') + 1 : __FILE__)

//
// converts string or const char* to wstring
//
std::wstring stringToWstring(const std::string& t_str)
{
	//setup converter
	typedef std::codecvt_utf8<wchar_t> convert_type;
	std::wstring_convert<convert_type, wchar_t> converter;

	//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
	return converter.from_bytes(t_str);
}

//
// Format error code into a string and show message box
// COM and System errors
//
void ShowError(const char* file, int line, HRESULT hr = S_OK)
{
	string error_type = TEXT("Rutime Error");
	string error_message = TEXT("File:\t");

#ifdef UNICODE
	error_message.append(stringToWstring(file));
#else
	error_message.append(file);
#endif // UNICODE

	error_message.append(TEXT("\r\nLine:\t"));
	error_message.append(to_string(line));
	error_message.append(TEXT("\r\nError:\t"));

	// If HRESULT is omited or S_OK
	// format last error code message
	if (hr == S_OK)
	{
		PVOID lpBuff = nullptr;

		DWORD dwChars = FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER |
			FORMAT_MESSAGE_FROM_SYSTEM,
			nullptr,
			GetLastError(),
			0,
			reinterpret_cast<PTSTR>(&lpBuff),
			0,
			nullptr);

		// If the function succeeds, the return value is
		// the number of TCHARs stored in the output buffer
		if (dwChars)
		{
			error_message.append(reinterpret_cast<PCTSTR>(lpBuff));
		}
		else // If the function fails, the return value is zero
		{
			error_message.append(TEXT("Unknown Error\t"));
			error_message.append(to_string(GetLastError()));
		}

		// Free the buffer allocated by FormatMessage
		LocalFree(lpBuff);
	}
	else // Format com error code into a message
	{
		_com_error err(hr);
		error_message.append(err.ErrorMessage());
	}
	
	// Play the sound and show error message
        // TODO: pass global handle to main window to MessageBox
        // to make modal message box (instead of nullptr)
	MessageBox(nullptr,
		error_message.c_str(),
		error_type.c_str(), MB_OK | MB_ICONERROR);
}


Now to check for error do this:

1
2
3
4
5
6
auto hDialog = CreateDialog(GetModuleHandle(NULL), L"About", hWnd, AboutDlgProc);

if(hDialog == NULL)
{
            ShowError(__FILENAME__, __LINE__);
}


Good luck this method will be your best friend for Win32/COM programing!
Last edited on
CreateDialog is used to create a dialog from a resource template. The second parameter of the function is the resource name or ID. So if you don't have a dialog template called "About" the function it is going to fail.

To create a dialog from an in-memory template (a set of structs) you need to use CreateDialogIndirect.

CreateDialogIndirectA
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-createdialogindirecta

Regards

Andy
Last edited on
Topic archived. No new replies allowed.