home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Source / DialogTemplate.cpp < prev    next >
C/C++ Source or Header  |  2004-01-30  |  19KB  |  628 lines

  1. /*
  2.   Copyright (C) 2002 Amir Szekely <kichik@netvision.net.il>
  3.  
  4.   This software is provided 'as-is', without any express or implied
  5.   warranty.  In no event will the authors be held liable for any damages
  6.   arising from the use of this software.
  7.  
  8.   Permission is granted to anyone to use this software for any purpose,
  9.   including commercial applications, and to alter it and redistribute it
  10.   freely, subject to the following restrictions:
  11.  
  12.   1. The origin of this software must not be misrepresented; you must not
  13.   claim that you wrote the original software. If you use this software
  14.   in a product, an acknowledgment in the product documentation would be
  15.   appreciated but is not required.
  16.  
  17.   2. Altered source versions must be plainly marked as such, and must not be
  18.   misrepresented as being the original software.
  19.  
  20.   3. This notice may not be removed or altered from any source distribution.
  21. */
  22.  
  23. #include "DialogTemplate.h"
  24.  
  25. //////////////////////////////////////////////////////////////////////
  26. // Utilities
  27. //////////////////////////////////////////////////////////////////////
  28.  
  29. #define ALIGN(dwToAlign, dwAlignOn) dwToAlign = (dwToAlign%dwAlignOn == 0) ? dwToAlign : dwToAlign - (dwToAlign%dwAlignOn) + dwAlignOn
  30.  
  31. // returns the number of WCHARs in str including null charcter
  32. inline DWORD WCStrLen(WCHAR* szwStr) {
  33.   int i;
  34.   for (i = 0; szwStr[i]; i++);
  35.   return i+1;
  36. }
  37.  
  38. // Reads a variany length array from seeker into readInto and advances seeker
  39. void ReadVarLenArr(BYTE* &seeker, char* &readInto, unsigned int uCodePage) {
  40.   WORD* arr = (WORD*)seeker;
  41.   switch (arr[0]) {
  42.   case 0x0000:
  43.     readInto = 0;
  44.     seeker += sizeof(WORD);
  45.     break;
  46.   case 0xFFFF:
  47.     readInto = MAKEINTRESOURCE(arr[1]);
  48.     seeker += 2*sizeof(WORD);
  49.     break;
  50.   default:
  51.     {
  52.       int iStrLen = WideCharToMultiByte(uCodePage, 0, (WCHAR*)arr, -1, 0, 0, 0, 0);
  53.       readInto = new char[iStrLen];
  54.       WideCharToMultiByte(uCodePage, 0, (WCHAR*)arr, -1, readInto, iStrLen, 0, 0);
  55.       seeker += WCStrLen((WCHAR*)arr)*sizeof(WCHAR);
  56.     }
  57.     break;
  58.   }
  59. }
  60.  
  61. // A macro that writes a given string (that can be a number too) into the buffer
  62. #define WriteStringOrId(x) \
  63.   if (x) \
  64.     if (IS_INTRESOURCE(x)) { \
  65.       *(WORD*)seeker = 0xFFFF; \
  66.       seeker += sizeof(WORD); \
  67.       *(WORD*)seeker = WORD(x); \
  68.       seeker += sizeof(WORD); \
  69.     } \
  70.     else { \
  71.       int us = MultiByteToWideChar(m_uCodePage, 0, x, -1, (WCHAR*)seeker, dwSize); \
  72.       seeker += us*sizeof(WCHAR); \
  73.     } \
  74.   else \
  75.     seeker += sizeof(WORD);
  76.  
  77. // A macro that adds the size of x (which can be a string a number, or nothing) to dwSize
  78. #define AddStringOrIdSize(x) dwSize += x ? (IS_INTRESOURCE(x) ? sizeof(DWORD) : (lstrlen(x)+1)*sizeof(WCHAR)) : sizeof(WORD)
  79.  
  80. //////////////////////////////////////////////////////////////////////
  81. // Construction/Destruction
  82. //////////////////////////////////////////////////////////////////////
  83.  
  84. CDialogTemplate::CDialogTemplate(BYTE* pbData, unsigned int uCodePage) {
  85.   m_uCodePage = uCodePage;
  86.  
  87.   m_szClass = 0;
  88.   m_szFont = 0;
  89.   m_szMenu = 0;
  90.   m_szTitle = 0;
  91.  
  92.   WORD wItems = 0;
  93.  
  94.   if (*(DWORD*)pbData == 0xFFFF0001) { // Extended dialog template signature
  95.     m_bExtended = true;
  96.  
  97.     DLGTEMPLATEEX* dTemplateEx = (DLGTEMPLATEEX*)pbData;
  98.  
  99.     m_dwHelpId = dTemplateEx->helpID;
  100.     m_dwStyle = dTemplateEx->style;
  101.     m_dwExtStyle = dTemplateEx->exStyle;
  102.     m_sX = dTemplateEx->x;
  103.     m_sY = dTemplateEx->y;
  104.     m_sWidth = dTemplateEx->cx;
  105.     m_sHeight = dTemplateEx->cy;
  106.  
  107.     wItems = dTemplateEx->cDlgItems;
  108.   }
  109.   else {
  110.     m_bExtended = false;
  111.     DLGTEMPLATE* dTemplate = (DLGTEMPLATE*)pbData;
  112.  
  113.     m_dwStyle = dTemplate->style;
  114.     m_dwExtStyle = dTemplate->dwExtendedStyle;
  115.     m_sX = dTemplate->x;
  116.     m_sY = dTemplate->y;
  117.     m_sWidth = dTemplate->cx;
  118.     m_sHeight = dTemplate->cy;
  119.  
  120.     wItems = dTemplate->cdit;
  121.   }
  122.  
  123.   BYTE* seeker = pbData + (m_bExtended ? sizeof(DLGTEMPLATEEX) : sizeof(DLGTEMPLATE));
  124.  
  125.   // Read menu variant length array
  126.   ReadVarLenArr(seeker, m_szMenu, m_uCodePage);
  127.   // Read class variant length array
  128.   ReadVarLenArr(seeker, m_szClass, m_uCodePage);
  129.   // Read title variant length array
  130.   ReadVarLenArr(seeker, m_szTitle, m_uCodePage);
  131.   // Read font size and variant length array (only if style DS_SETFONT is used!)
  132.   if (m_dwStyle & DS_SETFONT) {
  133.     m_sFontSize = *(short*)seeker;
  134.     seeker += sizeof(short);
  135.     if (m_bExtended) {
  136.       m_sFontWeight = *(short*)seeker;
  137.       seeker += sizeof(short);
  138.       m_bItalic = *(BYTE*)seeker;
  139.       seeker += sizeof(BYTE);
  140.       m_bCharset = *(BYTE*)seeker;
  141.       seeker += sizeof(BYTE);
  142.     }
  143.     ReadVarLenArr(seeker, m_szFont, m_uCodePage);
  144.   }
  145.  
  146.   // Read items
  147.   for (int i = 0; i < wItems; i++) {
  148.     // DLGITEMTEMPLATE[EX]s must be aligned on DWORD boundry
  149.     if (DWORD(seeker - pbData) % sizeof(DWORD))
  150.       seeker += sizeof(WORD);
  151.  
  152.     DialogItemTemplate* item = new DialogItemTemplate;
  153.     ZeroMemory(item, sizeof(DialogItemTemplate));
  154.  
  155.     if (m_bExtended) {
  156.       DLGITEMTEMPLATEEX* rawItem = (DLGITEMTEMPLATEEX*)seeker;
  157.  
  158.       item->dwHelpId = rawItem->helpID;
  159.       item->dwStyle = rawItem->style;
  160.       item->dwExtStyle = rawItem->exStyle;
  161.       item->sX = rawItem->x;
  162.       item->sY = rawItem->y;
  163.       item->sWidth = rawItem->cx;
  164.       item->sHeight = rawItem->cy;
  165.       item->wId = rawItem->id;
  166.  
  167.       seeker += sizeof(DLGITEMTEMPLATEEX);
  168.     }
  169.     else {
  170.       DLGITEMTEMPLATE* rawItem = (DLGITEMTEMPLATE*)seeker;
  171.  
  172.       item->dwStyle = rawItem->style;
  173.       item->dwExtStyle = rawItem->dwExtendedStyle;
  174.       item->sX = rawItem->x;
  175.       item->sY = rawItem->y;
  176.       item->sWidth = rawItem->cx;
  177.       item->sHeight = rawItem->cy;
  178.       item->wId = rawItem->id;
  179.  
  180.       seeker += sizeof(DLGITEMTEMPLATE);
  181.     }
  182.  
  183.     // Read class variant length array
  184.     ReadVarLenArr(seeker, item->szClass, m_uCodePage);
  185.     // Read title variant length array
  186.     ReadVarLenArr(seeker, item->szTitle, m_uCodePage);
  187.  
  188.     // Read creation data variant length array
  189.     // First read the size of the array (no null termination)
  190.     item->wCreateDataSize = *(WORD*)seeker;
  191.     seeker += sizeof(WORD);
  192.     // Then read the array it self (if size is not 0)
  193.     if (item->wCreateDataSize) {
  194.       item->wCreateDataSize -= sizeof(WORD); // Size includes size field itself...
  195.       item->szCreationData = new char[item->wCreateDataSize];
  196.       CopyMemory(item->szCreationData, seeker, item->wCreateDataSize);
  197.       seeker += item->wCreateDataSize;
  198.     }
  199.  
  200.     // Add the item to the vector
  201.     m_vItems.push_back(item);
  202.   }
  203. }
  204.  
  205. CDialogTemplate::~CDialogTemplate() {
  206.   if (m_szMenu && !IS_INTRESOURCE(m_szMenu))
  207.     delete [] m_szMenu;
  208.   if (m_szClass && !IS_INTRESOURCE(m_szClass))
  209.     delete [] m_szClass;
  210.   if (m_szTitle)
  211.     delete [] m_szTitle;
  212.   if (m_szFont)
  213.     delete [] m_szFont;
  214.  
  215.   for (unsigned int i = 0; i < m_vItems.size(); i++) {
  216.     if (m_vItems[i]->szClass && !IS_INTRESOURCE(m_vItems[i]->szClass))
  217.       delete [] m_vItems[i]->szClass;
  218.     if (m_vItems[i]->szTitle && !IS_INTRESOURCE(m_vItems[i]->szTitle))
  219.       delete [] m_vItems[i]->szTitle;
  220.     if (m_vItems[i]->szCreationData)
  221.       delete [] m_vItems[i]->szCreationData;
  222.   }
  223. }
  224.  
  225. //////////////////////////////////////////////////////////////////////
  226. // Methods
  227. //////////////////////////////////////////////////////////////////////
  228.  
  229. // Returns the width of the dialog
  230. short CDialogTemplate::GetWidth() {
  231.   return m_sWidth;
  232. }
  233.  
  234. // Returns the height of the dialog
  235. short CDialogTemplate::GetHeight() {
  236.   return m_sHeight;
  237. }
  238.  
  239. // Returns info about the item with the id wId
  240. DialogItemTemplate* CDialogTemplate::GetItem(WORD wId) {
  241.   for (unsigned int i = 0; i < m_vItems.size(); i++)
  242.     if (m_vItems[i]->wId == wId)
  243.       return m_vItems[i];
  244.   return 0;
  245. }
  246.  
  247. // Returns info about the item with the indexed i
  248. DialogItemTemplate* CDialogTemplate::GetItemByIdx(DWORD i) {
  249.   if (i >= m_vItems.size()) return 0;
  250.   return m_vItems[i];
  251. }
  252.  
  253. // Removes an item
  254. // Returns 1 if removed, 0 otherwise
  255. int CDialogTemplate::RemoveItem(WORD wId) {
  256.   for (unsigned int i = 0; i < m_vItems.size(); i++) {
  257.     if (m_vItems[i]->wId == wId) {
  258.       m_vItems.erase(m_vItems.begin() + i);
  259.       return 1;
  260.     }
  261.   }
  262.   return 0;
  263. }
  264.  
  265. // Sets the font of the dialog
  266. void CDialogTemplate::SetFont(char* szFaceName, WORD wFontSize) {
  267.   if (lstrcmp(szFaceName, "MS Shell Dlg")) {
  268.      // not MS Shell Dlg
  269.     m_dwStyle &= ~DS_SHELLFONT;
  270.     m_bExtended = false;
  271.   }
  272.   else {
  273.     // MS Shell Dlg
  274.     m_dwStyle |= DS_SHELLFONT;
  275.     m_bExtended = true;
  276.   }
  277.   m_dwStyle |= DS_SETFONT;
  278.   if (m_szFont) delete [] m_szFont;
  279.   m_szFont = new char[lstrlen(szFaceName)+1];
  280.   lstrcpy(m_szFont, szFaceName);
  281.   m_sFontSize = wFontSize;
  282. }
  283.  
  284. // Adds an item to the dialog
  285. void CDialogTemplate::AddItem(DialogItemTemplate item) {
  286.   DialogItemTemplate* newItem = new DialogItemTemplate;
  287.   CopyMemory(newItem, &item, sizeof(DialogItemTemplate));
  288.  
  289.   if (item.szClass && !IS_INTRESOURCE(item.szClass)) {
  290.     newItem->szClass = new char[lstrlen(item.szClass)+1];
  291.     lstrcpy(newItem->szClass, item.szClass);
  292.   }
  293.   if (item.szTitle && !IS_INTRESOURCE(item.szTitle)) {
  294.     newItem->szTitle = new char[lstrlen(item.szTitle)+1];
  295.     lstrcpy(newItem->szTitle, item.szTitle);
  296.   }
  297.   if (item.wCreateDataSize) {
  298.     newItem->szCreationData = new char[item.wCreateDataSize];
  299.     memcpy(newItem->szCreationData, item.szCreationData, item.wCreateDataSize);
  300.   }
  301.   m_vItems.push_back(newItem);
  302. }
  303.  
  304. // Moves all of the items in the dialog by (x,y)
  305. void CDialogTemplate::MoveAll(short x, short y) {
  306.   for (unsigned int i = 0; i < m_vItems.size(); i++) {
  307.     m_vItems[i]->sX += x;
  308.     m_vItems[i]->sY += y;
  309.   }
  310. }
  311.  
  312. // Resizes the dialog by (x,y)
  313. void CDialogTemplate::Resize(short x, short y) {
  314.   m_sWidth += x;
  315.   m_sHeight += y;
  316. }
  317.  
  318. // Creates a dummy dialog that is used for converting units
  319. HWND CDialogTemplate::CreateDummyDialog() {
  320.   DWORD dwTemp;
  321.   BYTE* pbDlg = Save(dwTemp);
  322.   HWND hDlg = CreateDialogIndirect(GetModuleHandle(0), (DLGTEMPLATE*)pbDlg, 0, 0);
  323.   delete [] pbDlg;
  324.   if (!hDlg)
  325.     throw runtime_error("Can't create dialog from template!");
  326.  
  327.   return hDlg;
  328. }
  329.  
  330. // Converts pixels to this dialog's units
  331. void CDialogTemplate::PixelsToDlgUnits(short& x, short& y) {
  332.   HWND hDlg = CreateDummyDialog();
  333.   RECT r = {0, 0, 10000, 10000};
  334.   MapDialogRect(hDlg, &r);
  335.   DestroyWindow(hDlg);
  336.  
  337.   x = short(float(x) / (float(r.right)/10000));
  338.   y = short(float(y) / (float(r.bottom)/10000));
  339. }
  340.  
  341. // Converts pixels to this dialog's units
  342. void CDialogTemplate::DlgUnitsToPixels(short& x, short& y) {
  343.   HWND hDlg = CreateDummyDialog();
  344.   RECT r = {0, 0, 10000, 10000};
  345.   MapDialogRect(hDlg, &r);
  346.   DestroyWindow(hDlg);
  347.  
  348.   x = short(float(x) * (float(r.right)/10000));
  349.   y = short(float(y) * (float(r.bottom)/10000));
  350. }
  351.  
  352. // Returns the size of a string in the dialog (in dialog units)
  353. SIZE CDialogTemplate::GetStringSize(WORD id, char *str) {
  354.   HWND hDlg = CreateDummyDialog();
  355.  
  356.   LOGFONT f;
  357.   GetObject((HFONT)SendMessage(hDlg, WM_GETFONT, 0, 0), sizeof(LOGFONT), &f);
  358.  
  359.   HDC memDC = CreateCompatibleDC(GetDC(hDlg));
  360.   HFONT font = CreateFontIndirect(&f);
  361.   SelectObject(memDC, font);
  362.  
  363.   SIZE size;
  364.   GetTextExtentPoint32(memDC, str, lstrlen(str), &size);
  365.  
  366.   DestroyWindow(hDlg);
  367.   DeleteObject(font);
  368.   DeleteDC(memDC);
  369.  
  370.   PixelsToDlgUnits((short&)size.cx, (short&)size.cy);
  371.   
  372.   return size;
  373. }
  374.  
  375. // Trims the right margins of a control to fit a given text string size.
  376. void CDialogTemplate::RTrimToString(WORD id, char *str, int margins) {
  377.   DialogItemTemplate* item = GetItem(id);
  378.   if (!item) return;
  379.  
  380.   SIZE size = GetStringSize(id, str);
  381.  
  382.   size.cx += margins;
  383.   size.cy += 2;
  384.  
  385.   item->sWidth = short(size.cx);
  386.   item->sHeight = short(size.cy);
  387. }
  388.  
  389. // Trims the left margins of a control to fit a given text string size.
  390. void CDialogTemplate::LTrimToString(WORD id, char *str, int margins) {
  391.   DialogItemTemplate* item = GetItem(id);
  392.   if (!item) return;
  393.  
  394.   SIZE size = GetStringSize(id, str);
  395.  
  396.   size.cx += margins;
  397.   size.cy += 2;
  398.  
  399.   item->sX += item->sWidth - short(size.cx);
  400.   item->sWidth = short(size.cx);
  401.   item->sHeight = short(size.cy);
  402. }
  403.  
  404. // Trims the left and right margins of a control to fit a given text string size.
  405. void CDialogTemplate::CTrimToString(WORD id, char *str, int margins) {
  406.   DialogItemTemplate* item = GetItem(id);
  407.   if (!item) return;
  408.  
  409.   SIZE size = GetStringSize(id, str);
  410.  
  411.   size.cx += margins;
  412.   size.cy += 2;
  413.  
  414.   item->sX += item->sWidth/2 - short(size.cx/2);
  415.   item->sWidth = short(size.cx);
  416.   item->sHeight = short(size.cy);
  417. }
  418.  
  419. // Moves every item right and gives it the WS_EX_RIGHT extended style
  420. void CDialogTemplate::ConvertToRTL() {
  421.   for (unsigned int i = 0; i < m_vItems.size(); i++) {
  422.     bool addExStyle = false;
  423.  
  424.     // Button
  425.     if (int(m_vItems[i]->szClass) == 0x80) {
  426.       m_vItems[i]->dwStyle ^= BS_LEFTTEXT;
  427.       m_vItems[i]->dwStyle ^= BS_RIGHT;
  428.       m_vItems[i]->dwStyle ^= BS_LEFT;
  429.  
  430.       if ((m_vItems[i]->dwStyle & (BS_LEFT|BS_RIGHT)) == (BS_LEFT|BS_RIGHT)) {
  431.         m_vItems[i]->dwStyle ^= BS_LEFT;
  432.         m_vItems[i]->dwStyle ^= BS_RIGHT;
  433.         if (m_vItems[i]->dwStyle & (BS_RADIOBUTTON|BS_CHECKBOX|BS_USERBUTTON)) {
  434.           m_vItems[i]->dwStyle |= BS_RIGHT;
  435.         }
  436.       }
  437.     }
  438.     // Edit
  439.     else if (int(m_vItems[i]->szClass) == 0x81) {
  440.       if ((m_vItems[i]->dwStyle & ES_CENTER) == 0) {
  441.         m_vItems[i]->dwStyle ^= ES_RIGHT;
  442.       }
  443.     }
  444.     // Static
  445.     else if (int(m_vItems[i]->szClass) == 0x82) {
  446.       if ((m_vItems[i]->dwStyle & SS_TYPEMASK) == SS_LEFT || (m_vItems[i]->dwStyle & SS_TYPEMASK) == SS_LEFTNOWORDWRAP)
  447.       {
  448.         m_vItems[i]->dwStyle &= ~SS_TYPEMASK;
  449.         m_vItems[i]->dwStyle |= SS_RIGHT;
  450.       }
  451.       else if ((m_vItems[i]->dwStyle & SS_TYPEMASK) == SS_ICON) {
  452.         m_vItems[i]->dwStyle |= SS_CENTERIMAGE;
  453.       }
  454.     }
  455.     else if (!IS_INTRESOURCE(m_vItems[i]->szClass) && !strcmpi(m_vItems[i]->szClass, "RichEdit20A")) {
  456.       if ((m_vItems[i]->dwStyle & ES_CENTER) == 0) {
  457.         m_vItems[i]->dwStyle ^= ES_RIGHT;
  458.       }
  459.     }
  460.     else if (!IS_INTRESOURCE(m_vItems[i]->szClass) && !strcmpi(m_vItems[i]->szClass, "SysTreeView32")) {
  461.       m_vItems[i]->dwStyle |= TVS_RTLREADING;
  462.       addExStyle = true;
  463.     }
  464.     else addExStyle = true;
  465.  
  466.     if (addExStyle)
  467.       m_vItems[i]->dwExtStyle |= WS_EX_RIGHT;
  468.  
  469.     m_vItems[i]->dwExtStyle |= WS_EX_RTLREADING;
  470.  
  471.     m_vItems[i]->sX = m_sWidth - m_vItems[i]->sWidth - m_vItems[i]->sX;
  472.   }
  473.   m_dwExtStyle |= WS_EX_RIGHT | WS_EX_RTLREADING;
  474. }
  475.  
  476. // Saves the dialog in the form of DLGTEMPLATE[EX]
  477. BYTE* CDialogTemplate::Save(DWORD& dwSize) {
  478.   // We need the size first to know how much memory to allocate
  479.   dwSize = GetSize();
  480.   BYTE* pbDlg = new BYTE[dwSize];
  481.   ZeroMemory(pbDlg, dwSize);
  482.   BYTE* seeker = pbDlg;
  483.  
  484.   if (m_bExtended) {
  485.     DLGTEMPLATEEX dh = {
  486.       0x0001,
  487.       0xFFFF,
  488.       m_dwHelpId,
  489.       m_dwExtStyle,
  490.       m_dwStyle,
  491.       m_vItems.size(),
  492.       m_sX,
  493.       m_sY,
  494.       m_sWidth,
  495.       m_sHeight
  496.     };
  497.  
  498.     CopyMemory(seeker, &dh, sizeof(DLGTEMPLATEEX));
  499.     seeker += sizeof(DLGTEMPLATEEX);
  500.   }
  501.   else {
  502.     DLGTEMPLATE dh = {
  503.       m_dwStyle,
  504.       m_dwExtStyle,
  505.       m_vItems.size(),
  506.       m_sX,
  507.       m_sY,
  508.       m_sWidth,
  509.       m_sHeight
  510.     };
  511.  
  512.     CopyMemory(seeker, &dh, sizeof(DLGTEMPLATE));
  513.     seeker += sizeof(DLGTEMPLATE);
  514.   }
  515.  
  516.   // Write menu variant length array
  517.   WriteStringOrId(m_szMenu);
  518.   // Write class variant length array
  519.   WriteStringOrId(m_szClass);
  520.   // Write title variant length array
  521.   WriteStringOrId(m_szTitle);
  522.  
  523.   // Write font variant length array, size, and extended info (if needed)
  524.   if (m_dwStyle & DS_SETFONT) {
  525.     *(short*)seeker = m_sFontSize;
  526.     seeker += sizeof(short);
  527.     if (m_bExtended) {
  528.       *(short*)seeker = m_sFontWeight;
  529.       seeker += sizeof(short);
  530.       *(BYTE*)seeker = m_bItalic;
  531.       seeker += sizeof(BYTE);
  532.       *(BYTE*)seeker = m_bCharset;
  533.       seeker += sizeof(BYTE);
  534.     }
  535.     WriteStringOrId(m_szFont);
  536.   }
  537.  
  538.   // Write all of the items
  539.   for (unsigned int i = 0; i < m_vItems.size(); i++) {
  540.     // DLGITEMTEMPLATE[EX]s must be aligned on DWORD boundry
  541.     if (DWORD(seeker - pbDlg) % sizeof(DWORD))
  542.       seeker += sizeof(WORD);
  543.  
  544.     if (m_bExtended) {
  545.       DLGITEMTEMPLATEEX dih = {
  546.         m_vItems[i]->dwHelpId,
  547.         m_vItems[i]->dwExtStyle,
  548.         m_vItems[i]->dwStyle,
  549.         m_vItems[i]->sX,
  550.         m_vItems[i]->sY,
  551.         m_vItems[i]->sWidth,
  552.         m_vItems[i]->sHeight,
  553.         m_vItems[i]->wId
  554.       };
  555.  
  556.       CopyMemory(seeker, &dih, sizeof(DLGITEMTEMPLATEEX));
  557.       seeker += sizeof(DLGITEMTEMPLATEEX);
  558.     }
  559.     else {
  560.       DLGITEMTEMPLATE dih = {
  561.         m_vItems[i]->dwStyle,
  562.         m_vItems[i]->dwExtStyle,
  563.         m_vItems[i]->sX,
  564.         m_vItems[i]->sY,
  565.         m_vItems[i]->sWidth,
  566.         m_vItems[i]->sHeight,
  567.         m_vItems[i]->wId
  568.       };
  569.  
  570.       CopyMemory(seeker, &dih, sizeof(DLGITEMTEMPLATE));
  571.       seeker += sizeof(DLGITEMTEMPLATE);
  572.     }
  573.  
  574.     // Write class variant length array
  575.     WriteStringOrId(m_vItems[i]->szClass);
  576.     // Write title variant length array
  577.     WriteStringOrId(m_vItems[i]->szTitle);
  578.  
  579.     // Write creation data variant length array
  580.     // First write its size
  581.     if (m_vItems[i]->wCreateDataSize) m_vItems[i]->wCreateDataSize += sizeof(WORD);
  582.     *(WORD*)seeker = m_vItems[i]->wCreateDataSize;
  583.     seeker += sizeof(WORD);
  584.     // If size is nonzero write the data too
  585.     if (m_vItems[i]->wCreateDataSize) {
  586.       CopyMemory(seeker, m_vItems[i]->szCreationData, m_vItems[i]->wCreateDataSize);
  587.       seeker += m_vItems[i]->wCreateDataSize;
  588.     }
  589.   }
  590.  
  591.   // DONE!
  592.   return pbDlg;
  593. }
  594.  
  595. // Returns the size that the DLGTEMPLATE[EX] will take when saved
  596. DWORD CDialogTemplate::GetSize() {
  597.   DWORD dwSize = m_bExtended ? sizeof(DLGTEMPLATEEX) : sizeof(DLGTEMPLATE);
  598.  
  599.   // Menu
  600.   AddStringOrIdSize(m_szMenu);
  601.   // Class
  602.   AddStringOrIdSize(m_szClass);
  603.   // Title
  604.   AddStringOrIdSize(m_szTitle);
  605.  
  606.   // Font
  607.   if (m_dwStyle & DS_SETFONT) {
  608.     dwSize += sizeof(WORD) + (m_bExtended ? sizeof(short) + 2*sizeof(BYTE) : 0);
  609.     AddStringOrIdSize(m_szFont);
  610.   }
  611.  
  612.   for (unsigned int i = 0; i < m_vItems.size(); i++) {
  613.     // DLGITEMTEMPLATE[EX]s must be aligned on DWORD boundry
  614.     ALIGN(dwSize, sizeof(DWORD));
  615.  
  616.     dwSize += m_bExtended ? sizeof(DLGITEMTEMPLATEEX) : sizeof(DLGITEMTEMPLATE);
  617.  
  618.     // Class
  619.     AddStringOrIdSize(m_vItems[i]->szClass);
  620.     // Title
  621.     AddStringOrIdSize(m_vItems[i]->szTitle);
  622.  
  623.     dwSize += sizeof(WORD) + m_vItems[i]->wCreateDataSize;
  624.   }
  625.  
  626.   return dwSize;
  627. }
  628.