4.00 | 3.51
WINDOWS | WINDOWS NT
kbprg kbdocerr kbcode
The information in this article applies to:
Note: This docerr is fixed in Windows NT version 4.0 beta documents.
SUMMARY
The Win32 SDK documentation demonstrates how to create a template in memory
for a modal dialog box by using DialogBoxIndirect() in a section called
"Creating a Template in Memory." The code included in this section of the
documentation has problems in Windows 95 and Windows NT version 3.51, which
may cause the dialog box to come up with only one control or may cause
DialogBoxIndirect() to return -1, indicating failure.
The same problems occur if the call to DialogBoxIndirect() is replaced with
CreateDialogIndirect().
MORE INFORMATION
There are four problems with the DialogBoxIndirect() code. The corrected
code appears at the end of this article.
- The code was intended to bring up a modal dialog box that contains a
static control (an OK button) and a Help button. However, because of two
conflicting lines of code that were supposed to set the DLGTEMPLATE
struct's cdit member to the number of controls in the dialog box, the
system is made to think there is only one control in the dialog.
lpdt->cdit = 3; // number of controls
lpdt->cdit = 1;
As is, the code works when pasted into an application, although the
dialog box comes up with only the OK button and the other two controls
are not shown. The second line should be removed because the dialog box
actually contains three controls, not one. However, doing this while
leaving the rest of the code as is causes no dialog box to come up and
DialogBoxIndirect() returns -1 as a result of two other problems
described in this article.
- The DLGTEMPLATE structure passed to the DialogBoxIndirect or
CreateDialogIndirect() functions is followed by one or more
DLGITEMTEMPLATE structures. These DLGITEMTEMPLATE structures need to
be DWORD aligned. Calling the following lpwAlign() function will do just
that:
/*
Helper routine. Take an input pointer, return closest
pointer that is aligned on a DWORD (4 byte) boundary.
*/
LPWORD lpwAlign ( LPWORD lpIn)
{
ULONG ul;
ul = (ULONG) lpIn;
ul +=3;
ul >>=2;
ul <<=2;
return (LPWORD) ul;
}
- The help button and the static control have identical (x,y) coordinates
as well as width and height (cx,cy):
lpdit->x = 55; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
This causes the static control to overlap the help button. You need to
adjust these values accordingly so that they both show up in the dialog
box. The following code shows how the modified code looks like so far.
Note the calls to the lpwAlign function each time a DLGITEMTEMPLATE
structure is added. This works fine in Windows NT version 3.51.
#define ID_HELP 150
#define ID_TEXT 200
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner,
LPSTR lpszMessage)
{
HGLOBAL hgbl;
LPDLGTEMPLATE lpdt;
LPDLGITEMTEMPLATE lpdit;
LPWORD lpw;
LPWSTR lpwsz;
LRESULT ret;
hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hgbl)
return -1;
lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
// Define a dialog box.
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
| DS_MODALFRAME | WS_CAPTION;
lpdt->cdit = 3; // number of controls
// lpdt->cdit = 1; // COMMENTED OUT -- unnecessary code
lpdt->x = 10; lpdt->y = 10;
lpdt->cx = 100; lpdt->cy = 100;
lpw = (LPWORD) (lpdt + 1);
*lpw++ = 0; // no menu
*lpw++ = 0; // predefined dialog box class (by default)
lpwsz = (LPWSTR) lpw;
lstrcpyW(lpwsz, L"My Message"); // dialog title (Unicode)
lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
//-----------------------
// Define an OK button.
//-----------------------
lpw = lpwAlign (lpw);
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 70;
lpdit->cx = 80; lpdit->cy = 20;
lpdit->id = IDOK; // OK button identifier
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // button class
lpwsz = (LPWSTR) lpw;
lstrcpyW(lpwsz, L"OK"); // button label (Unicode)
lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
*lpw++ = 0; // no creation data
//-----------------------
// Define a Help button.
//-----------------------
lpw = lpwAlign (lpw);
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 55; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = ID_HELP; // Help button identifier
lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // button class atom
lpwsz = (LPWSTR) lpw;
lstrcpyW(lpwsz, L"Help"); // button label (Unicode)
lpw = (LPWORD) (lpwsz + lstrlenW(lpwsz) + 1);
*lpw++ = 0; // no creation data
//-----------------------
// Define a static text control.
//-----------------------
lpw = lpwAlign (lpw);
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 10; // Changed this from (55,10)
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = ID_TEXT; // text identifier
lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0082; // static class
for (lpwsz = (LPWSTR)lpw;
*lpwsz++ = (WCHAR) *lpszMessage++;
);
lpw = (LPWORD)lpwsz;
*lpw++ = 0; // no creation data
GlobalUnlock(hgbl);
ret = DialogBoxIndirect(hinst,
(LPDLGTEMPLATE) hgbl,
hwndOwner, (DLGPROC) DialogProc);
GlobalFree(hgbl);
return ret;
}
- As previously stated, this modified code works fine in Windows NT 3.51.
In Windows 95, however, the dialog box and the controls come up, but
with no text for the help and OK buttons or for the dialog box.
Notice how the text in the code copies the text onto the memory block
using lstrcpyW(), which is not implemented in Windows 95, so it returns
ERROR_NOT_IMPLEMENTED. To generate Unicode strings in Windows 95, the
application must use MultiByteToWideChar().
Following is the modified code that works in Windows 95:
#define ID_HELP 150
#define ID_TEXT 200
LRESULT DisplayMyMessage(HINSTANCE hinst, HWND hwndOwner,
LPSTR lpszMessage)
{
HGLOBAL hgbl;
LPDLGTEMPLATE lpdt;
LPDLGITEMTEMPLATE lpdit;
LPWORD lpw;
LPWSTR lpwsz;
LRESULT ret;
hgbl = GlobalAlloc(GMEM_ZEROINIT, 1024);
if (!hgbl)
return -1;
lpdt = (LPDLGTEMPLATE)GlobalLock(hgbl);
// Define a dialog box.
lpdt->style = WS_POPUP | WS_BORDER | WS_SYSMENU
| DS_MODALFRAME | WS_CAPTION;
lpdt->cdit = 3; // number of controls
lpdt->x = 10; lpdt->y = 10;
lpdt->cx = 100; lpdt->cy = 100;
lpw = (LPWORD) (lpdt + 1);
*lpw++ = 0; // no menu
*lpw++ = 0; // predefined dialog box class (by default)
lpwsz = (LPWSTR) lpw;
nchar = 1+ MultiByteToWideChar (CP_ACP, 0, "My Dialog", -1, lpwsz, 50);
lpw += nchar;
//-----------------------
// Define an OK button.
//-----------------------
lpw = lpwAlign (lpw);
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 70;
lpdit->cx = 80; lpdit->cy = 20;
lpdit->id = IDOK; // OK button identifier
lpdit->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON;
lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // button class
lpwsz = (LPWSTR) lpw;
nchar = 1+MultiByteToWideChar (CP_ACP, 0, "OK", -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0; // no creation data
//-----------------------
// Define a Help button.
//-----------------------
lpw = lpwAlign (lpw);
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 55; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = 101; //ID_HELP; // Help button identifier
lpdit->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0080; // button class atom
lpwsz = (LPWSTR) lpw;
nchar = 1+MultiByteToWideChar (CP_ACP, 0, "Help", -1, lpwsz, 50);
lpw += nchar;
*lpw++ = 0; // no creation data
//-----------------------
// Define a static text control.
//-----------------------
lpw = lpwAlign (lpw);
lpdit = (LPDLGITEMTEMPLATE) lpw;
lpdit->x = 10; lpdit->y = 10;
lpdit->cx = 40; lpdit->cy = 20;
lpdit->id = 200; //ID_TEXT; // text identifier
lpdit->style = WS_CHILD | WS_VISIBLE | SS_LEFT;
lpw = (LPWORD) (lpdit + 1);
*lpw++ = 0xFFFF;
*lpw++ = 0x0082; // static class
for (lpwsz = (LPWSTR)lpw;
*lpwsz++ = (WCHAR) *lpszMessage++;
);
lpw = (LPWORD)lpwsz;
*lpw++ = 0; // no creation data
GlobalUnlock(hgbl);
ret = DialogBoxIndirect(hinst,
(LPDLGTEMPLATE) hgbl,
hwndOwner,
(DLGPROC) DialogProc);
GlobalFree(hgbl);
return ret;
}
|