ADDCTRL.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:33k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /******************************************************************************
  2. *       This is a part of the Microsoft Source Code Samples. 
  3. *       Copyright (C) 1993-1997 Microsoft Corporation.
  4. *       All rights reserved. 
  5. *       This source code is only intended as a supplement to 
  6. *       Microsoft Development Tools and/or WinHelp documentation.
  7. *       See these sources for detailed information regarding the 
  8. *       Microsoft samples programs.
  9. ******************************************************************************/
  10. /****************************** Module Header *******************************
  11. * Module Name: addctrl.c
  12. *
  13. * Contains routines for adding (creating) and deleting controls.
  14. *
  15. * Functions:
  16. *
  17. *    AddNewDialog()
  18. *    DropControl()
  19. *    AddControl()
  20. *    CreateControl()
  21. *    CreateDlgFont()
  22. *    MyGetCharDimensions()
  23. *    AdjustDefaultSizes()
  24. *    DeleteControl()
  25. *    DeleteDialog()
  26. *    DeleteControl2()
  27. *    FreeCTYPE()
  28. *
  29. * Comments:
  30. *
  31. ****************************************************************************/
  32. #include "dlgedit.h"
  33. #include "dlgfuncs.h"
  34. #include "dlgextrn.h"
  35. #include "dialogs.h"
  36. #include <stdlib.h>
  37. #include <string.h>
  38. STATICFN HFONT CreateDlgFont(HWND hwnd, LPTSTR pszFontName,
  39.     INT nPointSize);
  40. STATICFN INT MyGetCharDimensions(HWND hwnd, HFONT hFont,
  41.     PTEXTMETRIC ptm);
  42. STATICFN VOID AdjustDefaultSizes(VOID);
  43. STATICFN VOID DeleteControl2(NPCTYPE npcDel);
  44. STATICFN VOID FreeCTYPE(NPCTYPE npc);
  45. int CALLBACK GetFontCharSetEnumFunc(LPLOGFONT,LPTEXTMETRIC,int,LPARAM);
  46. STATICFN BYTE NEAR GetFontCharSet(LPTSTR);
  47. /************************************************************************
  48. * AddNewDialog
  49. *
  50. * High level function to add a new dialog to the current resource.
  51. * Any existing dialog will be saved away in the resource buffer.
  52. * The dialog is created at a default position and size with default
  53. * styles.
  54. *
  55. ************************************************************************/
  56. VOID AddNewDialog(VOID)
  57. {
  58.     RECT rc;
  59.     if (gfEditingDlg) {
  60.         if (!SynchDialogResource())
  61.             return;
  62.         DeleteDialog(FALSE);
  63.     }
  64.     /*
  65.      * Now drop a new dialog window.
  66.      */
  67.     SetRect(&rc, DEFDIALOGXPOS, DEFDIALOGYPOS,
  68.             DEFDIALOGXPOS + awcd[W_DIALOG].cxDefault,
  69.             DEFDIALOGYPOS + awcd[W_DIALOG].cyDefault);
  70.     DropControl(&awcd[W_DIALOG], &rc);
  71. }
  72. /************************************************************************
  73. * DropControl
  74. *
  75. * This function drops a new control of Type at the specified
  76. * location.  The default style and text of the control is
  77. * determined from the awcd table based on its type.  The control
  78. * is selected after being dropped.
  79. *
  80. *
  81. * Arguments:
  82. *   PWINDOWCLASSDESC pwcd - Describes the type of new control.
  83. *   PRECT prc             - Rectangle of the new control (in dialog units).
  84. *
  85. ************************************************************************/
  86. VOID DropControl(
  87.     PWINDOWCLASSDESC pwcd,
  88.     PRECT prc)
  89. {
  90.     ORDINAL ordIcon;
  91.     ORDINAL ordDlg;
  92.     LPTSTR pszText;
  93.     NPCTYPE npcNew;
  94.     INT idCtrl;
  95.     DIALOGINFO di;
  96.     /*
  97.      * Get the next available id to use for the new control.
  98.      */
  99.     idCtrl = NextID((pwcd->iType == W_DIALOG) ? NEXTID_DIALOG : NEXTID_CONTROL,
  100.             plInclude, 0);
  101.     if (pwcd->iType == W_ICON) {
  102.         /*
  103.          * For icon controls, the text is really an ordinal or name
  104.          * of the icon resource to display.  We get the next available
  105.          * id (skipping the id we just got for the control itself) to
  106.          * use as an ordinal.
  107.          */
  108.         WriteOrd(&ordIcon, NextID(NEXTID_CONTROL, plInclude, idCtrl));
  109.         pszText = (LPTSTR)&ordIcon;
  110.     }
  111.     else {
  112.         pszText = pwcd->pszTextDefault;
  113.     }
  114.     /*
  115.      * Make the control.
  116.      */
  117.     if (pwcd->iType == W_DIALOG) {
  118.         /*
  119.          * Pick a default name for the dialog.
  120.          */
  121.         WriteOrd(&ordDlg, NextID(NEXTID_DIALOG, plInclude, 0));
  122.         di.fResFlags = DEFDLGMEMFLAGS;
  123. //      di.wLanguage = GetUserDefaultLangID();
  124. di.wLanguage = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  125.         di.pszClass = NULL;
  126.         di.pszMenu = NULL;
  127.         di.DataVersion = 0;
  128.         di.Version = 0;
  129.         di.Characteristics = 0;
  130.         di.nPointSize = DEFPOINTSIZE;
  131.         lstrcpy(di.szFontName, ids(IDS_DEFFONTNAME));
  132.         npcNew = AddControl(pwcd, pszText,
  133.                 pwcd->flStyles, pwcd->flExtStyle, idCtrl,
  134.                 prc->left, prc->top,
  135.                 prc->right - prc->left, prc->bottom - prc->top,
  136.                 (LPTSTR)&ordDlg, &di);
  137.     }
  138.     else {
  139.         npcNew = AddControl(pwcd, pszText,
  140.                 pwcd->flStyles, pwcd->flExtStyle, idCtrl,
  141.                 prc->left, prc->top,
  142.                 prc->right - prc->left, prc->bottom - prc->top,
  143.                 NULL, NULL);
  144.     }
  145.     if (!npcNew)
  146.         return;
  147.     /*
  148.      * If we just dropped a dialog, we need to now show it.
  149.      * It it was some other control, mark the dialog as having
  150.      * been changed.
  151.      */
  152.     if (pwcd->iType == W_DIALOG) {
  153.         ShowWindow(npcNew->hwnd, SW_SHOWNA);
  154.         ToolboxOnTop();
  155.     }
  156.     else {
  157.         gfDlgChanged = TRUE;
  158.     }
  159.     SelectControl(npcNew, FALSE);
  160.     gfResChged = TRUE;
  161.     ShowFileStatus(FALSE);
  162.     /*
  163.      * Now we determine if one of the fields in the status ribbon
  164.      * should be given the focus initially.  The assumption is that
  165.      * there are some things that a user will always want to change
  166.      * when dropping a new control, such as the text in a push
  167.      * button, for example.
  168.      */
  169.     idCtrl = 0;
  170.     switch (pwcd->iType) {
  171.         case W_ICON:
  172.             /*
  173.              * For icons, the first thing the user will
  174.              * probably want to do is to change the name.
  175.              */
  176.             idCtrl = DID_STATUSNAME;
  177.             break;
  178.         default:
  179.             /*
  180.              * If this control has text, they will probably want
  181.              * to change it.  This includes the caption if the
  182.              * control is a dialog.
  183.              */
  184.             if (pwcd->fHasText)
  185.                 idCtrl = DID_STATUSTEXT;
  186.             break;
  187.     }
  188.     if (idCtrl) {
  189.         SendDlgItemMessage(hwndStatus, idCtrl,
  190.  EM_SETSEL, (WPARAM)(0), (LONG)(-1));
  191.         SetFocus(GetDlgItem(hwndStatus, idCtrl));
  192.     }
  193. }
  194. /************************************************************************
  195. * AddControl
  196. *
  197. * This function is used to add a new control.  CreateControl() does
  198. * half the work.
  199. *
  200. * Arguments:
  201. *   PWINDOWCLASSDESC pwcd - Window class structure.  Describes the
  202. *                           type of control to add.
  203. *   LPTSTR pszText        - Text for the new control.
  204. *   DWORD style           - Style of the new control.
  205. *   DWORD flExtStyle      - Extended style of the new control.
  206. *   INT id                - ID for the new control.
  207. *   INT x                 - X location of the new control.
  208. *   INT y                 - Y location of the new control.
  209. *   INT cx                - Width of the new control.
  210. *   INT cy                - Height of the new control.
  211. *   LPTSTR pszDlgName     - For dialogs, has dialog name.
  212. *   PDIALOGINFO pdi       - Ptr to additional dialog info (NULL for controls).
  213. *
  214. * Returns:
  215. *     A pointer to the CTYPE structure for the new control.
  216. *     NULL if it couldn't create the control.
  217. *
  218. ************************************************************************/
  219. NPCTYPE AddControl(
  220.     PWINDOWCLASSDESC pwcd,
  221.     LPTSTR pszText,
  222.     DWORD style,
  223.     DWORD flExtStyle,
  224.     INT id,
  225.     INT x,
  226.     INT y,
  227.     INT cx,
  228.     INT cy,
  229.     LPTSTR pszDlgName,
  230.     PDIALOGINFO pdi)
  231. {
  232.     NPCTYPE npcNew;
  233.     NPCTYPE npcT;
  234.     NPCTYPE *npnpcLast;
  235.     HWND hwndBehind;
  236.     if (!(npcNew = (NPCTYPE)MyAlloc(sizeof(CTYPE))))
  237.         return NULL;
  238.     /*
  239.      * These are checked later if a failure occurs,
  240.      * so we null them out now.
  241.      */
  242.     npcNew->hwnd = NULL;
  243.     npcNew->hwndDrag = NULL;
  244.     npcNew->text = NULL;
  245.     /*
  246.      * Set up some fields and create the control.
  247.      */
  248.     npcNew->npcNext = NULL;
  249.     npcNew->pwcd = pwcd;
  250.     npcNew->fSelected = FALSE;
  251.     SetRect(&npcNew->rc, x, y, x + cx, y + cy);
  252.     if (pwcd->iType == W_DIALOG)
  253.         hwndBehind = (HWND)NULL;
  254.     else
  255.         hwndBehind = (HWND)1;
  256.     if (!CreateControl(npcNew, pszText, style, flExtStyle, id, &npcNew->rc,
  257.             hwndBehind, pdi))
  258.         goto CreateFailed;
  259.     /*
  260.      * Create the drag window, unless this is the dialog.
  261.      */
  262.     if (pwcd->iType != W_DIALOG) {
  263.         npcNew->hwndDrag = CreateWindow(
  264.                 szDragClass,
  265.                 NULL,
  266.                 WS_CHILD,
  267.                 0, 0, 0, 0,
  268.                 gcd.npc->hwnd,
  269.                 NULL,
  270.                 ghInst,
  271.                 NULL);
  272.         /*
  273.          * Store the CTYPE pointer into the control's drag window.
  274.          * This will be used by PCFROMHWND later.
  275.          */
  276.         SETPCINTOHWND(npcNew->hwndDrag, npcNew);
  277.         /*
  278.          * Move the drag window to the top of the Z-Order.
  279.          */
  280.         SetWindowPos(npcNew->hwndDrag, NULL, 0, 0, 0, 0,
  281.                 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
  282.         SizeDragToControl(npcNew);
  283.     }
  284.     /*
  285.      * Did we just create a dialog?
  286.      */
  287.     if (pwcd->iType == W_DIALOG) {
  288.         /*
  289.          * First, copy the new name (it can be an ordinal!).
  290.          */
  291.         if (!(gcd.pszDlgName = MyAlloc(NameOrdLen(pszDlgName))))
  292.             goto CreateFailed;
  293.         NameOrdCpy(gcd.pszDlgName, pszDlgName);
  294.         /*
  295.          * Now, setup some other globals.  We clear the gcd.prl pointer,
  296.          * because we are assuming that this dialog was not created
  297.          * from a res link (it was dropped instead).  The routines
  298.          * that call AddControl when creating a dialog from a res
  299.          * link are  responsible for setting this global later.
  300.          */
  301.         gcd.prl = NULL;
  302.         gcd.npc = npcNew;
  303.         gfEditingDlg = TRUE;
  304.     }
  305.     else {
  306.         /*
  307.          * Search for the last control in the list.
  308.          */
  309.         npnpcLast = &npcHead;
  310.         for (npcT = npcHead; npcT; npcT = npcT->npcNext)
  311.             npnpcLast = &npcT->npcNext;
  312.         /*
  313.          * Link in the new control at the end of the list.
  314.          */
  315.         *npnpcLast = npcNew;
  316.         cWindows++;
  317.     }
  318.     return npcNew;
  319. CreateFailed:
  320.     FreeCTYPE(npcNew);
  321.     return NULL;
  322. }
  323. /************************************************************************
  324. * CreateControl
  325. *
  326. * Creates a control.  Some styles may be masked off of the actual
  327. * control created.  This function can also create the dialog box.
  328. *
  329. * If the control created is the dialog box, it will not be made visible.
  330. * This must be done by the caller.  This allows the caller to first add
  331. * all the controls to the dialog before showing it.
  332. *
  333. * The x, y, cx and cy coordinates are all in dialog units.  For a
  334. * type of W_DIALOG, this will be relative to the apps client.  For a
  335. * control, this will be relative to the "client" area of the dialog.
  336. *
  337. * Arguments:
  338. *   NPCTYPE npc       - The CTYPE pointer to the new control.  The hwnd
  339. *                       fields of the npc will be set.
  340. *   LPTSTR pszText    - The window text.
  341. *   DWORD flStyle     - The style to use.
  342. *   DWORD flExtStyle  - Extended style of the new control.
  343. *   INT id            - ID for the control.
  344. *   PRECT prc         - The size and location of the new control.
  345. *   HWND hwndBehind   - Put new control behind this hwnd in Z-order.
  346. *   PDIALOGINFO pdi   - Pointer to additional dialog info (NULL for controls).
  347. *
  348. * Returns:
  349. *     Handle of the control created.
  350. *     NULL if control was not created.
  351. *
  352. ************************************************************************/
  353. HWND CreateControl(
  354.     NPCTYPE npc,
  355.     LPTSTR pszText,
  356.     DWORD flStyle,
  357.     DWORD flExtStyle,
  358.     INT id,
  359.     PRECT prc,
  360.     HWND hwndBehind,
  361.     PDIALOGINFO pdi)
  362. {
  363.     HWND hwnd;
  364.     HWND hwndChild;
  365.     WNDPROC lpfnChild;
  366.     RECT rcT;
  367.     TEXTMETRIC tm;
  368.     LPTSTR pszCreateClass;
  369.     LPTSTR pszTextOld;
  370.     INT iType = npc->pwcd->iType;
  371.     /*
  372.      * Set the text field.  Remember that it can be an ordinal
  373.      * (for icon controls).
  374.      */
  375.     pszTextOld = npc->text;
  376.     if (pszText && *pszText) {
  377.         if (!(npc->text = MyAlloc(NameOrdLen(pszText))))
  378.             return NULL;
  379.         NameOrdCpy(npc->text, pszText);
  380.     }
  381.     else {
  382.         npc->text = NULL;
  383.     }
  384.     /*
  385.      * If there was text before on this control, free it now.
  386.      * This should be done after the new text is allocated and
  387.      * copied, because it is common to pass this routine the same
  388.      * pointer, and we don't want to free the text before we have
  389.      * copied it!
  390.      */
  391.     if (pszTextOld)
  392.         MyFree(pszTextOld);
  393.     /*
  394.      * Also set some other values in the CTYPE structure.
  395.      */
  396.     npc->id = id;
  397.     npc->flStyle = flStyle;
  398.     npc->flExtStyle = flExtStyle;
  399.     /*
  400.      * If this is a dialog and it has the WS_CHILD style, remove
  401.      * it and make it WS_POPUP instead.  This prevents some problems
  402.      * when editing the dialog.
  403.      */
  404.     if (iType == W_DIALOG && (flStyle & WS_CHILD)) {
  405.         flStyle &= ~WS_CHILD;
  406.         flStyle |= WS_POPUP;
  407.     }
  408.     /*
  409.      * If this is an emulated custom control, we always make it with the
  410.      * default styles no matter what the user has specified.  If not,
  411.      * remove any styles that can cause problems for a control of this
  412.      * type, such as OWNERDRAW styles.
  413.      */
  414.     if (npc->pwcd->fEmulated)
  415.         flStyle = awcd[W_CUSTOM].flStyles;
  416.     else
  417.         flStyle &= ~npc->pwcd->flStylesBad;
  418.     if (iType == W_DIALOG) {
  419.         /*
  420.          * If the style includes the DS_MODALFRAME bit, set the appropriate
  421.          * extended style bit.
  422.          */
  423.         if (flStyle & DS_MODALFRAME)
  424.             flExtStyle |= WS_EX_DLGMODALFRAME;
  425.         /*
  426.          * Create the dialog, but don't show it yet.
  427.          */
  428.         hwnd = CreateWindowEx(
  429.                 flExtStyle,
  430.                 MAKEINTRESOURCE(DIALOGCLASS),
  431.                 npc->text,
  432.                 flStyle & ~WS_VISIBLE,
  433.                 0, 0, 0, 0,
  434.                 ghwndSubClient,
  435.                 0,
  436.                 ghInst,
  437.                 NULL);
  438.     }
  439.     else {
  440.         /*
  441.          * Get the size of the control.
  442.          */
  443.         rcT = *prc;
  444.         /*
  445.          * Map the dialog unit rectangle to window coords.
  446.          */
  447.         DUToWinRect(&rcT);
  448.         /*
  449.          * If this is an icon, the text field is actually going
  450.          * to be an ordinal that has the resource id.  We must map this to
  451.          * an id of our own or when we create the control it will cause a
  452.          * "Resource not found" error.
  453.          */
  454.         if (iType == W_ICON)
  455.             pszText = (LPTSTR)&gordIcon;
  456.         else
  457.             pszText = npc->text;
  458.         /*
  459.          * Get the class name to use.  In the case of custom controls,
  460.          * if the control is emulated, use the special emulator class.
  461.          * Otherwise, it is an installed custom control, and we can use
  462.          * it's real class string.
  463.          */
  464.         if (iType == W_CUSTOM) {
  465.             if (npc->pwcd->fEmulated)
  466.                 pszCreateClass = szCustomClass;
  467.             else
  468.                 pszCreateClass = npc->pwcd->pszClass;
  469.         }
  470.         else {
  471.             pszCreateClass = ids(acsd[awcd[iType].iClass].idsClass);
  472.         }
  473.         /*
  474.          * Create the control.  We always create it visible in work mode,
  475.          * even if the style says it isn't.
  476.          */
  477.         hwnd = CreateWindowEx(
  478.                 flExtStyle,
  479.                 pszCreateClass,
  480. #ifdef JAPAN
  481.                 // pszText is ordnum for icon control.
  482.                 iType == W_ICON ? pszText : TEXT(""),
  483. #else
  484.                 pszText,
  485. #endif
  486.                 flStyle | WS_VISIBLE,
  487.                 rcT.left, rcT.top,
  488.                 rcT.right - rcT.left,
  489.                 rcT.bottom - rcT.top,
  490.                 gcd.npc->hwnd,
  491.                 0,
  492.                 ghInst,
  493.                 NULL);
  494. #ifdef JAPAN
  495.         // It isn't necessary for ICON control to handle accel in text.
  496.         if( iType != W_ICON ) {
  497.             TCHAR   szTmp[CCHTEXTMAX];
  498.             KKExpandCopy(szTmp, pszText, CCHTEXTMAX);
  499.             SetWindowText(hwnd, szTmp);
  500.         }
  501. #endif
  502.     }
  503.     if (!hwnd) {
  504.         Message(MSG_CREATECTRLERROR, pszCreateClass);
  505.         return NULL;
  506.     }
  507.     if (iType == W_DIALOG) {
  508.         /*
  509.          * Did they specify a font?
  510.          */
  511.         if (*pdi->szFontName) {
  512.             gcd.hFont = CreateDlgFont(hwnd, pdi->szFontName, pdi->nPointSize);
  513.             lstrcpy(gcd.di.szFontName, pdi->szFontName);
  514.             gcd.di.nPointSize = pdi->nPointSize;
  515.             gcd.fFontSpecified = TRUE;
  516.         }
  517.         else {
  518.             gcd.hFont = NULL;
  519.             *gcd.di.szFontName = CHAR_NULL;
  520.             gcd.di.nPointSize = 0;
  521.             gcd.fFontSpecified = FALSE;
  522.         }
  523.         /*
  524.          * Get the dimensions of the font.  It is a possible case that
  525.          * they specified a font but it could not be created, so in
  526.          * that case we use the system font as well as if they didn't
  527.          * specify a font at all.
  528.          */
  529.         if (gcd.hFont) {
  530.             gcd.cxChar = MyGetCharDimensions(hwnd, gcd.hFont, &tm);
  531.             gcd.cyChar = tm.tmHeight;
  532.         }
  533.         else {
  534.             gcd.cxChar = gcxSysChar;
  535.             gcd.cyChar = gcySysChar;
  536.         }
  537.         /*
  538.          * Now that we know what font we are using, adjust some entries
  539.          * in the awcd (array of window class data) table for default 
  540.          * sizing of controls.
  541.          */
  542.         AdjustDefaultSizes();
  543.     }
  544.     /*
  545.      * If there is a valid user specified font, inform the control
  546.      * of it.  Once the font has been set into the dialog, it
  547.      * must not be destroyed, because the dialog window will
  548.      * clean it up when it is destroyed.
  549.      */
  550.     if (gcd.hFont)
  551.         SendMessage(hwnd, WM_SETFONT, (WPARAM)gcd.hFont, 0L);
  552.     /*
  553.      * Move the window into the requested Z-Order.
  554.      */
  555.     SetWindowPos(hwnd, hwndBehind, 0, 0, 0, 0,
  556.             SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_NOREDRAW);
  557.     /*
  558.      * Store the CTYPE pointer into the control's hwnd.
  559.      * This will be used by PCFROMHWND later.
  560.      */
  561.     SETPCINTOHWND(hwnd, npc);
  562.     /*
  563.      * Subclass the control.
  564.      */
  565.     npc->pwcd->pfnOldWndProc =
  566.             (WNDPROC)SetWindowLong(hwnd, GWL_WNDPROC,
  567.             (iType == W_DIALOG) ? (DWORD)DialogCtrlWndProc :
  568.             (DWORD)CtrlWndProc);
  569.     /*
  570.      * Be sure double-clicks are enabled for this control.
  571.      */
  572.     (UINT)SetClassLong((hwnd), GCL_STYLE, (LONG)((UINT)GetClassLong((hwnd), GCL_STYLE) | CS_DBLCLKS));
  573.     /*
  574.      * Subclass any children this control may have.
  575.      */
  576.     for (hwndChild = GetTopWindow(hwnd); hwndChild;
  577.             hwndChild = GetNextWindow(hwndChild, GW_HWNDNEXT)) {
  578.         lpfnChild = (WNDPROC)SetWindowLong(hwndChild,
  579.                 GWL_WNDPROC, (DWORD)ChildWndProc);
  580.         SETCHILDPROC(hwndChild, lpfnChild);
  581.     }
  582.     /*
  583.      * Did we just create a dialog?
  584.      */
  585.     if (iType == W_DIALOG) {
  586.         /*
  587.          * Now that the dialog is created, we can figure out how to
  588.          * size it.  We start by mapping the dialog units to window
  589.          * coordinates,
  590.          */
  591.         rcT = *prc;
  592.         DUToWinRect(&rcT);
  593.         /*
  594.          * We now have the rectangle for the client area.  Expand it
  595.          * to account for the frame controls.
  596.          */
  597.         AdjustWindowRectEx(&rcT, flStyle, FALSE, flExtStyle);
  598.         /*
  599.          * Now we can map the rect from the apps client area
  600.          * to the desktop, then we set the dialogs position.
  601.          */
  602.         ClientToScreenRect(ghwndSubClient, &rcT);
  603.         SetWindowPos(hwnd, NULL,
  604.                 rcT.left, rcT.top,
  605.                 rcT.right - rcT.left, rcT.bottom - rcT.top,
  606.                 SWP_NOZORDER | SWP_NOACTIVATE);
  607.         SaveDlgClientRect(hwnd);
  608.         /*
  609.          * Save the class name, if any.
  610.          */
  611.         if (pdi->pszClass && *pdi->pszClass) {
  612.             if (!(gcd.di.pszClass = MyAlloc(NameOrdLen(pdi->pszClass)))) {
  613.                 DestroyWindow(hwnd);
  614.                 return (HWND)NULL;
  615.             }
  616.             NameOrdCpy(gcd.di.pszClass, pdi->pszClass);
  617.         }
  618.         else {
  619.             gcd.di.pszClass = NULL;
  620.         }
  621.         /*
  622.          * Save the menu name, if any.
  623.          */
  624.         if (pdi->pszMenu && *pdi->pszMenu) {
  625.             if (!(gcd.di.pszMenu = MyAlloc(NameOrdLen(pdi->pszMenu)))) {
  626.                 DestroyWindow(hwnd);
  627.                 return (HWND)NULL;
  628.             }
  629.             NameOrdCpy(gcd.di.pszMenu, pdi->pszMenu);
  630.         }
  631.         else {
  632.             gcd.di.pszMenu = NULL;
  633.         }
  634.         /*
  635.          * Set some other fields in the additional dialog info structure.
  636.          */
  637.         gcd.di.fResFlags = pdi->fResFlags;
  638.         gcd.di.wLanguage = pdi->wLanguage;
  639.         gcd.di.DataVersion = pdi->DataVersion;
  640.         gcd.di.Version = pdi->Version;
  641.         gcd.di.Characteristics = pdi->Characteristics;
  642.     }
  643.     npc->hwnd = hwnd;
  644.     return hwnd;
  645. }
  646. /************************************************************************
  647. * CreateDlgFont
  648. *
  649. * This function creates a font with the given face name and point size
  650. * and returns a handle to it.
  651. *
  652. * Arguments:
  653. *   HWND hwnd           - Dialog window handle.
  654. *   LPTSTR pszFontName  - Name of the font (for example: "Helv").
  655. *   INT nPointSize      - Point size of the font (for example: 8 or 12).
  656. *
  657. * Returns:
  658. *   A handle to the created font, or NULL if it could not be created.
  659. *
  660. ************************************************************************/
  661. static BYTE bSystemCharset;
  662. STATICFN HFONT CreateDlgFont(
  663.     HWND hwnd,
  664.     LPTSTR pszFontName,
  665.     INT nPointSize)
  666. {
  667.     HFONT hFont;
  668.     HFONT hFontOld;
  669.     HDC hDC;
  670.     LOGFONT lf;
  671.     TCHAR szFaceName[LF_FACESIZE];
  672.     CHARSETINFO csi;
  673.     DWORD dw = GetACP();
  674.     if (TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE))
  675. bSystemCharset = csi.ciCharset;
  676.     else
  677.         bSystemCharset = ANSI_CHARSET;
  678.     /*
  679.      * Initialize the logical font structure.  Note that filling the
  680.      * structure with zeros gives it all the default settings.
  681.      */
  682.     memset(&lf, 0, sizeof(LOGFONT));
  683.     lf.lfHeight = (SHORT)-PointSizeToPixels(nPointSize);
  684.     if ((lf.lfCharSet = GetFontCharSet(pszFontName)) != bSystemCharset)
  685.         lf.lfWeight = FW_BOLD; // allow boldface on non ShiftJIS fonts
  686.     lstrcpy(lf.lfFaceName, pszFontName);
  687.     if (!(hFont = CreateFontIndirect(&lf)))
  688.         return NULL;
  689.     /*
  690.      * If we didn't get the face name that was requested, delete the
  691.      * new font and return NULL.  This will effectively select the
  692.      * system font for this dialog.
  693.      */
  694.     hDC = GetDC(hwnd);
  695.     if (hFontOld = SelectObject(hDC, hFont)) {
  696.         GetTextFace(hDC, LF_FACESIZE, szFaceName);
  697.         SelectObject(hDC, hFontOld);
  698.         if (lstrcmpi(szFaceName, pszFontName) != 0) {
  699.             DeleteObject(hFont);
  700.             hFont = NULL;
  701.         }
  702.     }
  703.     else {
  704.         DeleteObject(hFont);
  705.         hFont = NULL;
  706.     }
  707.     ReleaseDC(hwnd, hDC);
  708.     return hFont;
  709. }
  710. /************************************************************************
  711. * MyGetCharDimensions
  712. *
  713. * This function calculates the average character width of the given
  714. * font for the given window.  This must be used instead of
  715. * simply using the tmAveCharWidth field of the text metrics, because
  716. * this value is not correct for proportional fonts.  
  717. *
  718. * Arguments:
  719. *   HWND hwnd       - The window handle.
  720. *   HFONT hFont     - The font handle.
  721. *   PTEXTMETRIC ptm - Where to return the text metrics.
  722. *
  723. * Returns:
  724. *   The average character width.  The text metrics are returned in
  725. *   the TEXTMETRIC structure pointed to by ptm.
  726. *
  727. ************************************************************************/
  728. STATICFN INT MyGetCharDimensions(
  729.     HWND hwnd,
  730.     HFONT hFont,
  731.     PTEXTMETRIC ptm)
  732. {
  733.     register INT i;
  734.     HDC hDC;
  735.     SIZE size;
  736.     INT iWidth;
  737.     TCHAR szAveCharWidth[52];
  738.     HFONT hFontOld;
  739.     hDC = GetDC(hwnd);
  740.     hFontOld = SelectObject(hDC, hFont);
  741.     GetTextMetrics(hDC, ptm);
  742.     /*
  743.      * Is this a variable pitch font?
  744.      */
  745.     if (ptm->tmPitchAndFamily & 0x01) {
  746.         for (i = 0; i < 26; i++)
  747.             szAveCharWidth[i] = (TCHAR)(i + CHAR_A);
  748.         for (i = 0; i < 26; i++)
  749.             szAveCharWidth[i + 26] = (TCHAR)(i + CHAR_CAP_A);
  750.         GetTextExtentPoint(hDC, szAveCharWidth, 52, &size);
  751.         iWidth = (INT)size.cx / 26;
  752.         //
  753.         // Round it up.
  754.         //
  755.         iWidth = (iWidth + 1) / 2;
  756.     }
  757.     else {
  758.         iWidth = ptm->tmAveCharWidth;
  759.     }
  760.     SelectObject(hDC, hFontOld);
  761.     ReleaseDC(hwnd, hDC);
  762.     return iWidth;
  763. }
  764. /************************************************************************
  765. * AdjustDefaultSizes
  766. *
  767. * This functions adjusts some default size entries in the awcd (array of
  768. * window class data) table.
  769. * This must be done at run time, because the actual values depend on the
  770. * system that dlgedit is being run on and the font of the current dialog.
  771. *
  772. * This function should be called any time that a dialog is created,
  773. * or its font is changed.
  774. *
  775. ************************************************************************/
  776. STATICFN VOID AdjustDefaultSizes(VOID)
  777. {
  778.     awcd[W_ICON].cxDefault =
  779.             (((GetSystemMetrics(SM_CXICON) * 4) * 2) + gcd.cxChar)
  780.             / (gcd.cxChar * 2);
  781.     awcd[W_ICON].cyDefault =
  782.             (((GetSystemMetrics(SM_CYICON) * 8) * 2) + gcd.cyChar)
  783.             / (gcd.cyChar * 2);
  784.     awcd[W_VERTSCROLL].cxDefault =
  785.             (((GetSystemMetrics(SM_CXVSCROLL) * 4) * 2) + gcd.cxChar)
  786.             / (gcd.cxChar * 2);
  787.     awcd[W_HORZSCROLL].cyDefault =
  788.             (((GetSystemMetrics(SM_CYHSCROLL) * 8) * 2) + gcd.cyChar)
  789.             / (gcd.cyChar * 2);
  790. }
  791. /************************************************************************
  792. * DeleteControl
  793. *
  794. * This deletes all selected controls from the dialog being edited
  795. * (or the dialog itself, if it is selected).
  796. *
  797. ************************************************************************/
  798. VOID DeleteControl(VOID)
  799. {
  800.     if (gfDlgSelected) {
  801.         if (Message(MSG_DELETEDIALOG) == IDYES)
  802.             /*
  803.              * Delete the dialog, including the resource for it.
  804.              */
  805.             DeleteDialog(TRUE);
  806.     }
  807.     else {
  808.         while (gnpcSel)
  809.             DeleteControl2(gnpcSel);
  810.         gfDlgChanged = TRUE;
  811.     }
  812.     gfResChged = TRUE;
  813.     ShowFileStatus(FALSE);
  814.     StatusUpdate();
  815.     StatusSetEnable();
  816. }
  817. /************************************************************************
  818. * DeleteControl2
  819. *
  820. * This deletes a control by destroying its window and removing it
  821. * from the linked list of controls associated with the dialog box.
  822. * The control is destroyed and the window is unlinked and the CTYPE free'd.
  823. *
  824. ************************************************************************/
  825. STATICFN VOID DeleteControl2(
  826.     NPCTYPE npcDel)
  827. {
  828.     register NPCTYPE npcT;
  829.     register NPCTYPE *npnpcLast;
  830.     UnSelectControl(npcDel);
  831.     /*
  832.      * Search for the control, unlink it from the list and free it.
  833.      */
  834.     npcT = npcHead;
  835.     npnpcLast = &npcHead;
  836.     while (npcT) {
  837.         if (npcT == npcDel) {
  838.             *npnpcLast = npcT->npcNext;
  839.             FreeCTYPE(npcT);
  840.             cWindows--;
  841.             break;
  842.         }
  843.         npnpcLast = &npcT->npcNext;
  844.         npcT = npcT->npcNext;
  845.     }
  846. }
  847. /************************************************************************
  848. * DeleteDialog
  849. *
  850. * This deletes the dialog box being worked on and sets globals
  851. * and the Status Window appropriately.  All CTYPEs are freed, the
  852. * status window is updated and the dialog window is destroyed.
  853. *
  854. * Arguments:
  855. *   BOOL fResAlso - If TRUE, delete the dialog resource also.
  856. *
  857. ************************************************************************/
  858. VOID DeleteDialog(
  859.     BOOL fResAlso)
  860. {
  861.     register NPCTYPE npcT;
  862.     register NPCTYPE npcNext;
  863.     CancelSelection(FALSE);
  864.     /*
  865.      * If they requested that the dialog resource be deleted also,
  866.      * do it first while some globals are still set.
  867.      */
  868.     if (fResAlso)
  869.         DeleteDialogResource();
  870.     /*
  871.      * Hide the window for better painting speed.
  872.      */
  873.     ShowWindow(gcd.npc->hwnd, SW_HIDE);
  874.     /*
  875.      * Free all the controls.
  876.      */
  877.     npcT = npcHead;
  878.     while (npcT) {
  879.         npcNext = npcT->npcNext;
  880.         FreeCTYPE(npcT);
  881.         npcT = npcNext;
  882.     }
  883.     npcHead = NULL;
  884.     cWindows = 0;
  885.     /*
  886.      * Free the dialog itself.
  887.      */
  888.     FreeCTYPE(gcd.npc);
  889.     if (gcd.pszDlgName) {
  890.         MyFree(gcd.pszDlgName);
  891.         gcd.pszDlgName = NULL;
  892.     }
  893.     if (gcd.di.pszClass) {
  894.         MyFree(gcd.di.pszClass);
  895.         gcd.di.pszClass = NULL;
  896.     }
  897.     if (gcd.di.pszMenu) {
  898.         MyFree(gcd.di.pszMenu);
  899.         gcd.di.pszMenu = NULL;
  900.     }
  901.     if (gcd.hFont) {
  902.         DeleteObject(gcd.hFont);
  903.         gcd.hFont = NULL;
  904.     }
  905.     gcd.fFontSpecified = FALSE;
  906.     *gcd.di.szFontName = CHAR_NULL;
  907.     /*
  908.      * Set these globals back to the system font values so that
  909.      * workers like WinToDUPoint will still work.
  910.      */
  911.     gcd.cxChar = gcxSysChar;
  912.     gcd.cyChar = gcySysChar;
  913.     gcd.prl = NULL;
  914.     gcd.npc = NULL;
  915.     gfEditingDlg = FALSE;
  916.     gfDlgChanged = FALSE;
  917.     ToolboxSelectTool(W_NOTHING, FALSE);
  918.     StatusUpdate();
  919.     StatusSetEnable();
  920. }
  921. /************************************************************************
  922. * FreeCTYPE
  923. *
  924. * This function frees an allocated CTYPE.  The associated control or
  925. * dialog window is destroyed, and memory for the text and/or class
  926. * is freed, followed by freeing the actual CTYPE structure itself.
  927. *
  928. * If the hwnd in the CTYPE is NULL, only the text (if not NULL) is
  929. * assumed to be valid and will be freed, followed by the CTYPE structure
  930. * itself.  This allows FreeCTYPE to be called when the CTYPE is only
  931. * partially initialized.  This is a little dependant on the order that
  932. * a CTYPE is allocated and initialized in AddControl().
  933. *
  934. * Arguments:
  935. *     NPCTYPE npc = The CTYPE to free.
  936. *
  937. ************************************************************************/
  938. STATICFN VOID FreeCTYPE(
  939.     NPCTYPE npc)
  940. {
  941.     if (npc->hwnd)
  942.         DestroyWindow(npc->hwnd);
  943.     if (npc->hwndDrag)
  944.         DestroyWindow(npc->hwndDrag);
  945.     if (npc->text)
  946.         MyFree(npc->text);
  947.     MyFree(npc);
  948. }
  949. /************************************************************************
  950. *
  951. *
  952. *
  953. ************************************************************************/
  954. int CALLBACK GetFontCharSetEnumFunc(LPLOGFONT lpLf,
  955.     LPTEXTMETRIC lpTm,
  956.     int nFontType,
  957.     LPARAM lParam)
  958. {
  959.     LPBYTE lpB = (LPBYTE)lParam;
  960.     *lpB = lpTm->tmCharSet;
  961.     return 0; // no more enum
  962. }
  963. /************************************************************************
  964. *
  965. *
  966. *
  967. ************************************************************************/
  968. STATICFN BYTE NEAR GetFontCharSet(LPTSTR lpStr)
  969. {
  970.     HDC hDC;
  971.     BYTE cbCharset = bSystemCharset;
  972.     FONTENUMPROC lpEFCB = (FONTENUMPROC)MakeProcInstance(
  973.                               (FARPROC)GetFontCharSetEnumFunc,
  974.                               ghInst);
  975.     if (hDC = GetDC(ghwndMain)) {
  976.         EnumFonts(hDC, lpStr, lpEFCB, (LPARAM)&cbCharset);
  977.         ReleaseDC(ghwndMain,hDC);
  978.     }
  979.     FreeProcInstance(lpEFCB);
  980.     return cbCharset;
  981. }
  982. #ifdef JAPAN
  983. /************************************************************************
  984. * Copy strings to the buffer. Codes 36 and 37 are expanded to
  985. * text strings "36" and "37" respectively. t-Yoshio
  986. ************************************************************************/
  987. VOID KDExpandCopy(LPTSTR pszDest, LPTSTR pszSrc, WORD wLimit)
  988. {
  989.     int  i;
  990.     LPTSTR p = pszSrc;
  991.     wLimit--;
  992.     for (i = 0; i < wLimit && p && *p; i++) {
  993.         if (*p == 036 || *p == 037) {
  994.             if (i < wLimit-4) {
  995.                 lstrcpy(&pszDest[i], (*p == 036) ? TEXT("\036") : TEXT("\037"));
  996.                 i += 3;
  997.             } else {
  998.                 break;
  999.                 }
  1000.         } else {
  1001.             pszDest[i] = *p;
  1002.             }
  1003.         if (IsDBCSLeadByte((BYTE)*p)) {
  1004.             if (i == wLimit - 1) {
  1005.                 break;
  1006.             }
  1007.             pszDest[++i] = *(p+1);
  1008.         }
  1009.         p = CharNext(p);
  1010.     }
  1011.     pszDest[i] = '';
  1012. }
  1013. #endif