Last active
October 15, 2023 23:09
-
-
Save t-mat/149643918f685cce6444 to your computer and use it in GitHub Desktop.
WIN32 : Resourceless dialog
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Resourceless Dialog | |
// Dialog Template by Max McGuire | |
// http://www.flipcode.com/archives/Dialog_Template.shtml | |
#include <windows.h> | |
#include <tchar.h> | |
#include <stdio.h> | |
class DialogTemplate { | |
public: | |
DialogTemplate(LPCTSTR caption, DWORD style, int x, int y, int w, int h, LPCTSTR font = nullptr, int fontSize = 8) { | |
allocBuffer(sizeof(*dlgTemplate)); | |
dlgTemplate->style = style; | |
dlgTemplate->dwExtendedStyle = 0; | |
dlgTemplate->cdit = 0; | |
dlgTemplate->x = static_cast<WORD>(x); | |
dlgTemplate->y = static_cast<WORD>(y); | |
dlgTemplate->cx = static_cast<WORD>(w); | |
dlgTemplate->cy = static_cast<WORD>(h); | |
// The dialog box doesn't have a menu or a special class | |
appendData(static_cast<WORD>(0)); | |
appendData(static_cast<WORD>(0)); | |
appendString(caption); | |
if(font) { | |
dlgTemplate->style |= DS_SETFONT; | |
appendData(static_cast<WORD>(fontSize)); | |
appendString(font); | |
} | |
} | |
virtual ~DialogTemplate() { | |
if(dlgTemplate) { | |
memFree(dlgTemplate); | |
} | |
} | |
void addComponent(LPCTSTR type, LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
appendData(makeItem(style, exStyle, x, y, w, h, id)); | |
appendString(type); | |
appendString(caption); | |
appendData(static_cast<WORD>(0)); | |
dlgTemplate->cdit++; | |
} | |
void addButton(LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
addStandardComponent(0x0080, caption, style, exStyle, x, y, w, h, id); | |
appendData(static_cast<WORD>(0)); | |
} | |
void addEditBox(LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
addStandardComponent(0x0081, caption, style, exStyle, x, y, w, h, id); | |
appendData(static_cast<WORD>(0)); | |
} | |
void addStatic(LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
addStandardComponent(0x0082, caption, style, exStyle, x, y, w, h, id); | |
appendData(static_cast<WORD>(0)); | |
} | |
void addListBox(LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
addStandardComponent(0x0083, caption, style, exStyle, x, y, w, h, id); | |
appendData(static_cast<WORD>(0)); | |
} | |
void addScrollBar(LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
addStandardComponent(0x0084, caption, style, exStyle, x, y, w, h, id); | |
appendData(static_cast<WORD>(0)); | |
} | |
void addComboBox(LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
addStandardComponent(0x0085, caption, style, exStyle, x, y, w, h, id); | |
appendData(static_cast<WORD>(0)); | |
} | |
// | |
// Returns a pointer to the Win32 dialog template which the object | |
// represents. This pointer may become invalid if additional | |
// components are added to the template. | |
// | |
operator const DLGTEMPLATE*() const { | |
return dlgTemplate; | |
} | |
protected: | |
DLGITEMTEMPLATE makeItem(DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
DLGITEMTEMPLATE t; | |
t.style = style; | |
t.x = static_cast<WORD>(x); | |
t.y = static_cast<WORD>(y); | |
t.cx = static_cast<WORD>(w); | |
t.cy = static_cast<WORD>(h); | |
t.id = static_cast<WORD>(id); | |
t.dwExtendedStyle = exStyle; | |
return t; | |
} | |
void addStandardComponent(WORD type, LPCTSTR caption, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id) { | |
// DWORD algin the beginning of the component data | |
alignData(sizeof(DWORD)); | |
appendData(makeItem(style, exStyle, x, y, w, h, id)); | |
appendData(static_cast<WORD>(0xffff)); | |
appendData(type); | |
appendString(caption); | |
dlgTemplate->cdit++; | |
} | |
void alignData(int size) { | |
const int paddingSize = usedBufferLength % size; | |
if(paddingSize != 0) { | |
ensureSpace(paddingSize); | |
usedBufferLength += paddingSize; | |
} | |
} | |
void appendString(const char* string) { | |
const int length = MultiByteToWideChar(CP_ACP, 0, string, -1, nullptr, 0); | |
const int bytes = length * sizeof(wchar_t); | |
auto* p = reinterpret_cast<wchar_t*>(allocBuffer(bytes)); | |
MultiByteToWideChar(CP_ACP, 0, string, -1, p, length); | |
} | |
void appendString(const wchar_t* string) { | |
appendData(string, (wcslen(string) + 1) * sizeof(*string)); | |
} | |
char* allocBuffer(size_t bytes) { | |
ensureSpace(bytes); | |
auto* p = reinterpret_cast<char*>(dlgTemplate) + usedBufferLength; | |
usedBufferLength += bytes; | |
return p; | |
} | |
void appendData(const void* data, size_t dataLength) { | |
memcpy(allocBuffer(dataLength), data, dataLength); | |
} | |
template<class T> | |
void appendData(const T& data) { | |
appendData(&data, sizeof(data)); | |
} | |
void ensureSpace(size_t bytes) { | |
if(bytes + usedBufferLength > totalBufferLength) { | |
totalBufferLength += bytes * 2; | |
auto* newBuffer = reinterpret_cast<DLGTEMPLATE*>(memAlloc(totalBufferLength)); | |
if(dlgTemplate) { | |
memcpy(newBuffer, dlgTemplate, usedBufferLength); | |
memFree(dlgTemplate); | |
} | |
dlgTemplate = newBuffer; | |
} | |
} | |
virtual HANDLE getHeap() const { | |
return GetProcessHeap(); | |
} | |
virtual void* memAlloc(size_t bytes) const { | |
return HeapAlloc(getHeap(), 0, bytes); | |
} | |
virtual void memFree(void* ptr) const { | |
HeapFree(getHeap(), 0, ptr); | |
} | |
private: | |
DLGTEMPLATE* dlgTemplate { nullptr }; | |
size_t totalBufferLength { 0 }; | |
size_t usedBufferLength { 0 }; | |
}; | |
int main() { | |
enum { | |
IDC_FILENAME = 1, | |
IDC_LINENUMBER, | |
IDC_EXPRESSION, | |
IDC_MESSAGE, | |
IDC_BTN_DEBUG, | |
IDC_BTN_IGNORE, | |
IDC_BTN_IGNOREALWAYS, | |
IDC_BTN_EXIT | |
}; | |
DialogTemplate dt(_T("Assert Failed!"), WS_CAPTION | DS_CENTER, 10, 10, 257, 80+128, _T("Tahoma")); | |
dt.addStatic(_T("Filename:"), WS_VISIBLE, 0, 2 + 3, 7, 37, 8, -1); | |
dt.addStatic(_T("Line:"), WS_VISIBLE, 0, 188 + 3, 7, 16, 8, -1); | |
dt.addStatic(_T("Expression:"), WS_VISIBLE, 0, 2 + 3, 24, 37, 8, -1); | |
dt.addEditBox(_T("Edit"), WS_VISIBLE | ES_READONLY, WS_EX_STATICEDGE, 45 + 3, 7, 131, 12, IDC_FILENAME); | |
dt.addEditBox(_T("Edit"), WS_VISIBLE | ES_READONLY, WS_EX_STATICEDGE, 209 + 3, 7, 39, 12, IDC_LINENUMBER); | |
dt.addEditBox(_T("Edit"), WS_VISIBLE | ES_READONLY, WS_EX_STATICEDGE, 45 + 3, 24, 131+72, 12, IDC_EXPRESSION); | |
dt.addEditBox(_T("Edit"), WS_VISIBLE | WS_VSCROLL | ES_READONLY | ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL, WS_EX_STATICEDGE, 2 + 3, 41, 131+72+43, 12+128, IDC_MESSAGE); | |
dt.addButton(_T("Debug"), WS_VISIBLE, 0, 2 + 3, 62+128, 56, 13, IDC_BTN_DEBUG); | |
dt.addButton(_T("Ignore"), WS_VISIBLE, 0, 65 + 3, 62+128, 56, 13, IDC_BTN_IGNORE); | |
dt.addButton(_T("Ignore Always"), WS_VISIBLE, 0, 127 + 3, 62+128, 56, 13, IDC_BTN_IGNOREALWAYS); | |
dt.addButton(_T("Exit"), WS_VISIBLE, 0, 192 + 3, 62+128, 56, 13, IDC_BTN_EXIT); | |
struct Param { | |
const TCHAR* filename; | |
const TCHAR* lineNumber; | |
const TCHAR* expression; | |
const TCHAR* message; | |
int id; | |
}; | |
Param param { | |
_T("TEST FILE NAME"), | |
_T("1234567"), | |
_T("(TEST_EXPRESSION == 0)"), | |
_T(""), | |
0 | |
}; | |
TCHAR buf[65536] {}; | |
{ | |
auto* p = buf; | |
for(int i = 0; i < 64; ++i) { | |
p += _stprintf_s(p, buf+_countof(buf)-p, _T("Test message #%02d\r\n"), i); | |
} | |
} | |
param.message = buf; | |
const auto& dlgProc = [](HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -> INT_PTR { | |
switch(uMsg) { | |
default: | |
break; | |
case WM_DESTROY: | |
DestroyWindow(hwndDlg); | |
break; | |
case WM_INITDIALOG: | |
if(lParam) { | |
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, static_cast<LONG_PTR>(lParam)); | |
const auto& param = * reinterpret_cast<Param*>(lParam); | |
SetDlgItemText(hwndDlg, IDC_FILENAME , param.filename); | |
SetDlgItemText(hwndDlg, IDC_LINENUMBER , param.lineNumber); | |
SetDlgItemText(hwndDlg, IDC_EXPRESSION , param.expression); | |
SetDlgItemText(hwndDlg, IDC_MESSAGE , param.message); | |
} | |
return TRUE; | |
case WM_COMMAND: | |
if(auto* pParam = reinterpret_cast<Param*>(GetWindowLongPtr(hwndDlg, GWLP_USERDATA))) { | |
auto& param = *pParam; | |
const WORD id = LOWORD(wParam); | |
// const WORD code = HIWORD(wParam); | |
// const HWND item = GetDlgItem(hwndDlg, id); | |
switch(id) { | |
default: | |
break; | |
case IDC_BTN_DEBUG: | |
case IDC_BTN_IGNORE: | |
case IDC_BTN_IGNOREALWAYS: | |
case IDC_BTN_EXIT: | |
param.id = id; | |
EndDialog(hwndDlg, id + 10000); | |
break; | |
} | |
} | |
return TRUE; | |
} | |
return 0; | |
}; | |
auto r = DialogBoxIndirectParam(GetModuleHandle(0), dt, nullptr, dlgProc, reinterpret_cast<LPARAM>(¶m)); | |
printf("r=%d\n", r); | |
printf("param.id=%d\n", param.id); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment