Skip to content

Instantly share code, notes, and snippets.

@t-mat
Last active October 15, 2023 23:09
Show Gist options
  • Save t-mat/149643918f685cce6444 to your computer and use it in GitHub Desktop.
Save t-mat/149643918f685cce6444 to your computer and use it in GitHub Desktop.
WIN32 : Resourceless dialog
// 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>(&param));
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