Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DialogBoxIndirect creates dialog bigger than asked

Tags:

c++

dialog

winapi

For my application I need to create a Dialog Box without using resource. I am trying to do it with DialogBoxInderect function. The code is unbelievably ugly but somehow I succeeded to do it.

The problem is that dialog, for some reason, is much bigger than I asked with much bigger fonts.

Here is how the dialog looks like if I load it from resource: enter image description here

And here is the dialog with the same size stated when I call DialogBoxInderect function. enter image description here

Here is how it is defined in code:

HGLOBAL             hGlobal;
LPDLGTEMPLATE       wlsDialogTemplate;
LPDLGITEMTEMPLATE   wlsDialogItemTemplate;
LPWORD              nextItem;
LPWSTR              itemString;
int32_t             itemStringLength;

// Check for memory allocation errors
hGlobal = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hGlobal) 
    return -1;

wlsDialogTemplate = (LPDLGTEMPLATE)GlobalLock(hGlobal);

// Define a dialog box.
wlsDialogTemplate->style    = WS_CAPTION;
wlsDialogTemplate->x        = 0;
wlsDialogTemplate->y        = 0;
wlsDialogTemplate->cx       = 320;
wlsDialogTemplate->cy       = 115;

GlobalUnlock(hGlobal);
retCode = DialogBoxIndirect(0, (LPDLGTEMPLATE)hGlobal, 0, ActivateWlsMsgDialog);

And here is how it is defined in RC file:

IDD_WLS_SMALL_MESSAGE_DLG DIALOGEX 0, 0, 320, 115
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
CAPTION "Dialog"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
    DEFPUSHBUTTON   "OK",ID_CUSTOM_OK,175,95,120,15
    PUSHBUTTON      "Cancel",ID_CUSTOM_CANCEL,45,95,120,15
    CTEXT           "Static",IDC_HEADER_TEXT,120,10,170,70
    CONTROL         "",IDC_LOGO,"Static",SS_BITMAP,16,10,83,70
END

As you can see, the second dialog is much bigger than defined. I tried to play with various style flags but without any success (That is why there is red cross on the bigger dialog).

Any help with that? Thanks!

like image 564
Iron-Eagle Avatar asked Feb 09 '12 08:02

Iron-Eagle


2 Answers

The larger size is easy to explain. Windows automatically sizes the dialog in accordance with its font, and the larger dialog uses a different font. In fact, it is using the default system font (more info on the confusing issue of Windows dialog fonts is found in my answer here).

So the real issue to focus on is why it's using a different font, and fixing that will solve the size problem.

In the dialog box resource file, you specify the DS_SETFONT flag as one of the dialog box styles. According to the documentation, this flag

[i]ndicates that the header of the dialog box template (either standard or extended) contains additional data specifying the font to use for text in the client area and controls of the dialog box. If possible, the system selects a font according to the specified font data. The system passes a handle to the font to the dialog box and to each control by sending them the WM_SETFONT message.

So that explains why that one is displaying with the expected font.

The next logical question is what's different about your dynamically-created dialog template, shown with the DialogBoxIndirect function. The culprit is, once again, the DS_SETFONT flag, but in this case, the flag is absent. That means that the dialog doesn't contain any information about which font to use to display its controls, and the system defaults to the default system font (which is the ugly Windows 2.0-era font that you see in the second screenshot).

Once we've come to this understanding, the solution should be obvious: you need to tell the dialog which font you want it to use. There are two possible ways of doing so that come to mind:

  1. You can set the DS_SETFONT flag and provide the font information in the header of the dialog box template as described in the above-linked documentation.
  2. Or you can simply create and set the dialog's font in response to the WM_INITDIALOG message.

The latter is probably what you really want to do, as it allows you to use the actual system font (which, confusingly, is different from what I've been calling the "default" system font), which is Segoe UI in Windows Vista and later. Note that even in your first screenshot, it's using MS Sans Serif and therefore sticks out like a sore thumb in the Aero interface. Again, see this answer for more about fonts than you ever wanted to know and sample code for making this work. You'll need to make sure that you set the font for the dialog itself and all of its child controls.

like image 60
Cody Gray Avatar answered Oct 08 '22 07:10

Cody Gray


I had played with DialogBoxIndirect (actually with DialogBoxIndirectParam), and here's the part of the code that sets the font. Observe the DS_SHELLFONT option.

LPWORD lpwAlign(LPWORD lpIn, int nAlignment)
{
    return (LPWORD)(((ULONG_PTR)lpIn + nAlignment - 1) & -nAlignment);
}

LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner, LPMYMESSAGEPARAMS pParams)
{
    WORD mem[1024];           // Buffer for dialog resource
    LPDLGTEMPLATEW lpdt;      // Pointer to heading resource structure
    LPDLGITEMTEMPLATEW lpdit; // Pointer to current control
    LPWORD lpw;               // Cursor to resource buffer
    LPWSTR lpwsz;             // Cursor to resource buffer (of type WCHAR)
    LPCWSTR lpwszCaption;     // Aux pointer for text copying
    LRESULT ret;              // Function's return value

    lpdt = (LPDLGTEMPLATEW)lpwAlign( mem, 4 );

    //-----------------------
    // Define a dialog box.
    //-----------------------
    lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU | WS_CAPTION |
        DS_MODALFRAME | DS_CENTER | DS_SHELLFONT;
    lpdt->dwExtendedStyle = 0;
    lpdt->cdit = 3;  // number of controls
    lpdt->x  = 0;   lpdt->y  = 0;
    lpdt->cx = 164; lpdt->cy = 49;

    lpw = (LPWORD)(lpdt + 1);
    // Dialog menu
    *lpw++ = 0;
    // Dialog class
    *lpw++ = 0;
    // Dialog title
    for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"Choose language";
        *lpwsz++ = *lpwszCaption++;
        );
    lpw = (LPWORD)lpwsz;
    // Dialog font
    if ( lpdt->style & (DS_SETFONT | DS_SHELLFONT) )
    {
        // Size
        *lpw++ = 8;
        // Typeface name
        for (lpwsz = (LPWSTR)lpw, lpwszCaption = L"MS Shell Dlg";
            *lpwsz++ = *lpwszCaption++;
            );
        lpw = (LPWORD)lpwsz;
    }


    // Define the rest of the controls
    ...

    ret = DialogBoxIndirectParamW( hinst, lpdt, 
        hwndOwner, MyMessageProc, (LPARAM)pParams );

    return ret;
}
like image 21
Dialecticus Avatar answered Oct 08 '22 08:10

Dialecticus