Memory Dialog
//=============================================================================
//MEMORY TEMPLATE DIALOG - Copyright © 2000,2005 Ken Fitlike
//=============================================================================
//API functions used: DialogBoxIndirect,EndDialog,GetLastError,HIWORD,
//LoadImage,LOWORD,MAKEWORD,MessageBox,PostMessage,SendMessage,WinMain,
//wsprintf.
//=============================================================================
//This demonstrates the creation of a modal dialog box from a memory template. 
//This technique should not be used for the routine creation of dialog boxes; 
//use resource scripts instead.
//
//Notes: (1) All strings used by the memory template must be wide character
//           strings.
//       (2) Controls must be aligned on WORD boundaries and not DWORD 
//           boundaries as described by msdn.
//For more information refer to windows documentation regarding DLGTEMPLATE,
//DLGTEMPLATEEX and DLGITEMTEMPLATEEX structures
//=============================================================================
#include <windows.h>  //include all the basics
#include <tchar.h>    //string and other mapping macros
#include <string>
#include <vector>

//define an unicode string type alias
typedef std::basic_string<TCHAR> ustring;
//=============================================================================
//message processing function declarations
INT_PTR CALLBACK DlgProc(HWND,UINT,WPARAM,LPARAM);
void OnCommand(const HWND,int,int,const HWND);
INT_PTR OnInitDlg(const HWND,LPARAM);

//non-message function declarations
void AddControl(std::vector<WORD>&,DWORD,DWORD,short,short,short,short,DWORD,
                const std::wstring&,const std::wstring&,DWORD helpID=0,
                DWORD extradata=0);
void AddString(std::vector<WORD>&,const std::wstring&);
inline int ErrMsg(const ustring&);
void WordAlign(std::vector<WORD>&);
//=============================================================================
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,int)
{
std::vector<WORD> memdlg;

//setup the dialog template
memdlg.push_back(1);
memdlg.push_back(0xffff);

DWORD helpID=0;
memdlg.push_back(LOWORD(helpID));
memdlg.push_back(HIWORD(helpID));

DWORD exStyle=0;
memdlg.push_back(LOWORD(exStyle));
memdlg.push_back(HIWORD(exStyle));

DWORD style=DS_CENTER|WS_OVERLAPPEDWINDOW|WS_POPUP|WS_VISIBLE|DS_SETFONT;
memdlg.push_back(LOWORD(style));
memdlg.push_back(HIWORD(style));

memdlg.push_back(3);    //number of controls

memdlg.push_back(0);    //left
memdlg.push_back(0);    //top
memdlg.push_back(186);  //width
memdlg.push_back(93);   //height

memdlg.push_back(0);    //no menu
memdlg.push_back(0);    //standard system dialog box class

//add dialogbox title
AddString(memdlg,L"Dialog: Memory Template");

//set font but only if DS_SETFONT or DS_SHELLFONT styles are set
DWORD dwTest=style;
if (dwTest & DS_SETFONT)
  {
  //this is for simplicity; it would probably be better to obtain and use the
  //respective properties of the default gui or system fonts
  memdlg.push_back(8);          //pointsize
  memdlg.push_back(FW_NORMAL);  //weight
  
  memdlg.push_back(MAKEWORD(0,DEFAULT_CHARSET));  //italic,charset
  
  AddString(memdlg,L"MS Sans Serif");
  }

//add 'ok' button
AddControl(memdlg,
           0,
           WS_CHILD|WS_VISIBLE|BS_DEFPUSHBUTTON|WS_TABSTOP,
           22,62,50,14,
           IDOK,
           L"button",
           L"Ok");  

//add 'cancel' button           
AddControl(memdlg,
           0,
           WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON|WS_TABSTOP,
           111,62,50,14,
           IDCANCEL,
           L"button",
           L"Cancel");  

//add an edit control
AddControl(memdlg,
           WS_EX_CLIENTEDGE,
           WS_CHILD|WS_VISIBLE|WS_TABSTOP,
           10,10,100,14,
           200,
           L"edit",
           L"single line edit control");  
           
//create the dialog  
DLGTEMPLATE *pdt=reinterpret_cast<DLGTEMPLATE*>(&memdlg[0]);

INT_PTR success=DialogBoxIndirect(hInst,pdt,0,DlgProc);

if (success==-1)
  {
  ErrMsg(_T("DialogBoxIndirect failed"));
  }

return 0;
}
//=============================================================================
//message processing functions
//=============================================================================
INT_PTR CALLBACK DlgProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch (uMsg)
  {
  case WM_COMMAND:
    {
    OnCommand(hwnd,LOWORD(wParam),HIWORD(wParam),
              reinterpret_cast<HWND>(lParam));
    return 0;
    }
  case WM_INITDIALOG:
    {
    return OnInitDlg(hwnd,lParam);
    }
  default:
    return FALSE;  //let system deal with msg
  }
}
//=============================================================================
void OnCommand(const HWND hwnd,int id,int notifycode,const HWND hCntrl)
{
//handles WM_COMMAND message of the modal dialogbox
switch (id)
  {
  case IDOK:        //RETURN key pressed or 'ok' button selected
  case IDCANCEL:    //ESC key pressed or 'cancel' button selected
    EndDialog(hwnd,id);
  }
}
//=============================================================================
INT_PTR OnInitDlg(const HWND hwnd,LPARAM lParam)
{
//set the small icon for the dialog. IDI_APPLICATION icon is set by default 
//for winxp
SendMessage(hwnd,WM_SETICON,ICON_SMALL,
            reinterpret_cast<LPARAM>(LoadImage(0,IDI_APPLICATION,IMAGE_ICON,
                                               0,0,LR_SHARED)));
//ensure focus rectangle is properly drawn around control with focus
PostMessage(hwnd,WM_KEYDOWN,VK_TAB,0);
return TRUE;
}
//=============================================================================
//non-message processing functions
//=============================================================================
void AddControl(std::vector<WORD>& v,DWORD exStyle,DWORD style,short x,short y,
                short cx,short cy,DWORD id,const std::wstring& classname,
                const std::wstring& caption,DWORD helpID,DWORD extradata)
{
//add a control. defaults: helpID=0,extradata=0. Note there is no capability
//in this function for dealing with non-zero values of extradata.
WordAlign(v);

v.push_back(LOWORD(helpID));
v.push_back(HIWORD(helpID));

v.push_back(LOWORD(exStyle));
v.push_back(HIWORD(exStyle));

v.push_back(LOWORD(style));
v.push_back(HIWORD(style));

v.push_back(x);  //left
v.push_back(y);  //top
v.push_back(cx); //width
v.push_back(cy); //height

//msdn docs are incorrect - the id is a DWORD value and not a WORD
v.push_back(LOWORD(id)); 
v.push_back(HIWORD(id));

//there are only a few class atoms defined for standard (user) controls
//so it's arguably better to use string class names than ordinals.
AddString(v,classname.c_str());

AddString(v,caption.c_str());

v.push_back(0);  //no creation data 
}
//=============================================================================
void AddString(std::vector<WORD>& v,const std::wstring& s)
{
//add a string to the array (eg. dialog title, control caption etc.)
std::wstring::const_iterator iter;
for (iter=s.begin();iter!=s.end();++iter)
  {
  v.push_back(*iter);
  }
v.push_back(L'\0');
}
//=============================================================================
inline int ErrMsg(const ustring& s)
{
return MessageBox(0,s.c_str(),_T("ERROR"),MB_OK|MB_ICONEXCLAMATION);
}
//=============================================================================
void WordAlign(std::vector<WORD>& v)
{
//msdn states that controls must be added at dword boundary. This is incorrect;
//controls must be WORD aligned.
std::size_t size=v.size()%2;

for (unsigned int i=0;i<size;++i)
  {
  v.push_back(0);  //padding
  }
}
//=============================================================================