home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / winnt / dlgedit / custcntl.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  43KB  |  1,594 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: custcntl.c
  14. *
  15. * Contains functions to support custom controls.
  16. *
  17. * Functions:
  18. *    NewCustDlgProc()
  19. *    OpenCustomDialog()
  20. *    SelCustDialog()
  21. *    SelCustDlgProc()
  22. *    RemCustDlgProc()
  23. *    CustomWndProc()
  24. *    AddCustomLink()
  25. *    RemoveCustomLink()
  26. *    CallCustomStyle()
  27. *    CallCustomSizeToText()
  28. *    ReadCustomProfile()
  29. *    WriteCustomProfile()
  30. *    NewCustInit()
  31. *    NewCustOK()
  32. *    OpenDLLFile()
  33. *    CallCustomInfoA()
  34. *    SelCustInit()
  35. *    SelCustSelect()
  36. *    SelCustOK()
  37. *    RemCustInit()
  38. *    RemCustOK()
  39. *    AllocCUSTLINK()
  40. *    FreeCUSTLINK()
  41. *
  42. * Comments:
  43. *
  44. ****************************************************************************/
  45.  
  46. #include "dlgedit.h"
  47. #include "dlgfuncs.h"
  48. #include "dlgextrn.h"
  49. #include "dialogs.h"
  50. #include "dlghelp.h"
  51.  
  52. #include <stdlib.h>
  53. #include <string.h>
  54.  
  55. #include <commdlg.h>
  56.  
  57.  
  58. /*
  59.  * Minimum margin around the sample control.
  60.  */
  61. #define SAMPLEMARGIN                4
  62.  
  63.  
  64. STATICFN VOID NewCustInit(HWND hwnd);
  65. STATICFN BOOL NewCustOK(HWND hwnd);
  66. STATICFN VOID OpenDLLFile(LPTSTR pszFileName);
  67. STATICFN UINT CallCustomInfoA(LPFNCCINFOA lpfnInfoA, LPCCINFO acciW,
  68.     INT nControls);
  69. STATICFN VOID SelCustInit(HWND hwnd);
  70. STATICFN VOID SelCustSelect(HWND hwnd);
  71. STATICFN BOOL SelCustOK(HWND hwnd);
  72. STATICFN VOID RemCustInit(HWND hwnd);
  73. STATICFN BOOL RemCustOK(HWND hwnd);
  74. STATICFN PCUSTLINK AllocCUSTLINK(LPCCINFO pcci, BOOL fEmulated,
  75.     BOOL fUnicodeDLL, LPTSTR pszFileName, HANDLE hmod);
  76. STATICFN VOID FreeCUSTLINK(PCUSTLINK pclFree);
  77.  
  78.  
  79. /*
  80.  * Used to return the pwcd that is chosen from the Select Custom
  81.  * Control dialog.
  82.  */
  83. static PWINDOWCLASSDESC pwcdChosen;
  84.  
  85. /*
  86.  * Has the window handle of the sample custom control in the
  87.  * Select Custom Control dialog.
  88.  */
  89. static HWND hwndCustomSample;
  90.  
  91.  
  92.  
  93.  
  94. /************************************************************************
  95. * NewCustDlgProc
  96. *
  97. * This is the Add Custom Control dialog procedure.
  98. *
  99. * :
  100. *
  101. ************************************************************************/
  102.  
  103. DIALOGPROC NewCustDlgProc(
  104.     HWND hwnd,
  105.     UINT msg,
  106.     WPARAM wParam,
  107.     LPARAM lParam)
  108. {
  109.     switch (msg) {
  110.         case WM_INITDIALOG:
  111.             NewCustInit(hwnd);
  112.             return TRUE;
  113.  
  114.         case WM_COMMAND:
  115.             switch (LOWORD(wParam)) {
  116.                 case IDOK:
  117.                     if (NewCustOK(hwnd))
  118.                         EndDialog(hwnd, IDOK);
  119.  
  120.                     break;
  121.  
  122.                 case IDCANCEL:
  123.                     EndDialog(hwnd, IDCANCEL);
  124.                     break;
  125.  
  126.                 case IDHELPDLG:
  127.                     WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
  128.                             HELPID_NEWCUST);
  129.                     break;
  130.             }
  131.  
  132.             return TRUE;
  133.  
  134.         default:
  135.             return FALSE;
  136.     }
  137. }
  138.  
  139.  
  140.  
  141. /************************************************************************
  142. * NewCustInit
  143. *
  144. * Processes the WM_INITDIALOG message for the New Temporary Custom Control
  145. * dialog procedure.
  146. *
  147. * History:
  148. *
  149. ************************************************************************/
  150.  
  151. STATICFN VOID NewCustInit(
  152.     HWND hwnd)
  153. {
  154.     TCHAR szStyles[32];
  155.  
  156.     SendDlgItemMessage(hwnd, DID_NEWCUSTCLASS, EM_LIMITTEXT, CCHCCCLASS - 1, 0L);
  157.  
  158.     SendDlgItemMessage(hwnd, DID_NEWCUSTSTYLES, EM_LIMITTEXT, CCHHEXLONGMAX, 0L);
  159.     wsprintf(szStyles, L"%#.8lx", awcd[W_CUSTOM].flStyles);
  160.     SetDlgItemText(hwnd, DID_NEWCUSTSTYLES, szStyles);
  161.  
  162.     SendDlgItemMessage(hwnd, DID_NEWCUSTCX, EM_LIMITTEXT, 3, 0L);
  163.     SetDlgItemInt(hwnd, DID_NEWCUSTCX, awcd[W_CUSTOM].cxDefault, FALSE);
  164.  
  165.     SendDlgItemMessage(hwnd, DID_NEWCUSTCY, EM_LIMITTEXT, 3, 0L);
  166.     SetDlgItemInt(hwnd, DID_NEWCUSTCY, awcd[W_CUSTOM].cyDefault, FALSE);
  167.  
  168.     SendDlgItemMessage(hwnd, DID_NEWCUSTTEXT, EM_LIMITTEXT, CCHCCTEXT - 1, 0L);
  169.  
  170.     CenterWindow(hwnd);
  171. }
  172.  
  173.  
  174.  
  175. /************************************************************************
  176. * NewCustOK
  177. *
  178. * Processes the OK button from the New Temporary Custom Control dialog.
  179. *
  180. * History:
  181. *
  182. ************************************************************************/
  183.  
  184. STATICFN BOOL NewCustOK(
  185.     HWND hwnd)
  186. {
  187.     TCHAR szStyles[CCHHEXLONGMAX + 1];
  188.     CCINFO cci;
  189.  
  190.     /*
  191.      * Read the class field.  It is required.
  192.      */
  193.     if (!GetDlgItemText(hwnd, DID_NEWCUSTCLASS, cci.szClass, CCHCCCLASS)) {
  194.         Message(MSG_NOCLASS);
  195.         SetFocus(GetDlgItem(hwnd, DID_NEWCUSTCLASS));
  196.         return FALSE;
  197.     }
  198.  
  199.     GetDlgItemText(hwnd, DID_NEWCUSTSTYLES, szStyles, CCHHEXLONGMAX + 1);
  200.     cci.flStyleDefault = valtoi(szStyles);
  201.  
  202.     if (!(cci.cxDefault = GetDlgItemInt(hwnd, DID_NEWCUSTCX, NULL, FALSE))) {
  203.         Message(MSG_GTZERO, ids(IDS_WIDTH));
  204.         SetFocus(GetDlgItem(hwnd, DID_NEWCUSTCX));
  205.         return FALSE;
  206.     }
  207.  
  208.     if (!(cci.cyDefault = GetDlgItemInt(hwnd, DID_NEWCUSTCY, NULL, FALSE))) {
  209.         Message(MSG_GTZERO, ids(IDS_HEIGHT));
  210.         SetFocus(GetDlgItem(hwnd, DID_NEWCUSTCY));
  211.         return FALSE;
  212.     }
  213.  
  214.     GetDlgItemText(hwnd, DID_NEWCUSTTEXT, cci.szTextDefault, CCHCCTEXT);
  215.  
  216.     cci.flOptions = 0;
  217.     *cci.szDesc = TEXT('\0');
  218.     cci.flExtStyleDefault = 0;
  219.     cci.flCtrlTypeMask = 0;
  220.     cci.cStyleFlags = 0;
  221.     cci.aStyleFlags = NULL;
  222.     cci.lpfnStyle = NULL;
  223.     cci.lpfnSizeToText = NULL;
  224.     cci.dwReserved1 = 0;
  225.     cci.dwReserved2 = 0;
  226.  
  227.     if (AddCustomLink(&cci, TRUE, FALSE, NULL, NULL))
  228.         return TRUE;
  229.     else
  230.         return FALSE;
  231. }
  232.  
  233.  
  234.  
  235. /************************************************************************
  236. * OpenCustomDialog
  237. *
  238. * Displays the file open dialog and allows a custom DLL to be selected
  239. * and loaded.
  240. *
  241. * History:
  242. *
  243. ************************************************************************/
  244.  
  245. VOID OpenCustomDialog(VOID)
  246. {
  247.     BOOL fGotName;
  248.     OPENFILENAME ofn;
  249.     TCHAR szNewFileName[CCHMAXPATH];
  250.     TCHAR szFilter[CCHTEXTMAX];
  251.     INT idPrevDlg;
  252.  
  253.     /*
  254.      * Begin setting up the globals and the open file dialog structure.
  255.      */
  256.     *szNewFileName = CHAR_NULL;
  257.  
  258.     /*
  259.      * Build up the filter string.
  260.      */
  261.     BuildFilterString(FILE_DLL, szFilter);
  262.  
  263.     ofn.lStructSize = sizeof(ofn);
  264.     ofn.hwndOwner = ghwndMain;
  265.     ofn.hInstance = NULL;
  266.     ofn.lpstrFilter = szFilter;
  267.     ofn.lpstrCustomFilter = NULL;
  268.     ofn.nMaxCustFilter = 0;
  269.     ofn.nFilterIndex = 1;
  270.     ofn.lpstrFile = szNewFileName;
  271.     ofn.nMaxFile = CCHMAXPATH;
  272.     ofn.lpstrFileTitle = NULL;
  273.     ofn.nMaxFileTitle = 0;
  274.     ofn.lpstrTitle = ids(IDS_DLLOPENTITLE);
  275.     ofn.Flags = OFN_HIDEREADONLY | OFN_SHOWHELP | OFN_FILEMUSTEXIST;
  276.     ofn.lpstrDefExt = ids(IDS_DLLEXT);
  277.     ofn.lpstrInitialDir = NULL;
  278.     ofn.lCustData = 0;
  279.     ofn.lpfnHook = NULL;
  280.     ofn.lpTemplateName = NULL;
  281.  
  282.     /*
  283.      * Fire off the dialog box to open the file.
  284.      */
  285.     EnteringDialog(DID_COMMONFILEOPENDLL, &idPrevDlg, TRUE);
  286.     fGotName = GetOpenFileName(&ofn);
  287.     EnteringDialog(idPrevDlg, NULL, FALSE);
  288.  
  289.     if (fGotName)
  290.         OpenDLLFile(szNewFileName);
  291. }
  292.  
  293.  
  294.  
  295. /************************************************************************
  296. * OpenDLLFile
  297. *
  298. *
  299. * History:
  300. *
  301. ************************************************************************/
  302.  
  303. STATICFN VOID OpenDLLFile(
  304.     LPTSTR pszFileName)
  305. {
  306.     HANDLE hmod;
  307.     LPFNCCINFOA lpfnInfoA;
  308.     LPFNCCINFOW lpfnInfoW;
  309.     INT i;
  310.     BOOL fSuccess = FALSE;
  311.     BOOL fUnicodeDLL;
  312.     PCUSTLINK pclT;
  313.     INT nControls;
  314.     INT nControls2;
  315.     LPCCINFO acci;
  316.  
  317.     /*
  318.      * Check to see if the DLL has already been loaded.
  319.      */
  320.     for (pclT = gpclHead; pclT &&
  321.             (pclT->pwcd->fEmulated ||
  322.             lstrcmpi(pclT->pszFileName, pszFileName) != 0);
  323.             pclT = pclT->pclNext)
  324.         ;
  325.  
  326.     /*
  327.      * Is the DLL already loaded?
  328.      */
  329.     if (pclT) {
  330.         Message(MSG_CUSTALREADYLOADED, pszFileName);
  331.         return;
  332.     }
  333.  
  334.     if (!(hmod = LoadLibrary(pszFileName))) {
  335.         Message(MSG_CANTLOADDLL, pszFileName);
  336.         return;
  337.     }
  338.  
  339.     lpfnInfoA = (LPFNCCINFOA)GetProcAddress(hmod, "CustomControlInfoA");
  340.     lpfnInfoW = (LPFNCCINFOW)GetProcAddress(hmod, "CustomControlInfoW");
  341.  
  342.     if (!lpfnInfoA && !lpfnInfoW) {
  343.         Message(MSG_BADCUSTDLL, pszFileName);
  344.         goto Error1;
  345.     }
  346.  
  347.     if (lpfnInfoW) {
  348.         nControls = (*lpfnInfoW)(NULL);
  349.         fUnicodeDLL = TRUE;
  350.     }
  351.     else {
  352.         nControls = (*lpfnInfoA)(NULL);
  353.         fUnicodeDLL = FALSE;
  354.     }
  355.  
  356.     if (!nControls) {
  357.         Message(MSG_CANTINITDLL, pszFileName);
  358.         goto Error1;
  359.     }
  360.  
  361.     if (!(acci = (LPCCINFO)MyAlloc(nControls * sizeof(CCINFO))))
  362.         goto Error1;
  363.  
  364.     if (fUnicodeDLL)
  365.         nControls2 = (*lpfnInfoW)(acci);
  366.     else
  367.         nControls2 = CallCustomInfoA(lpfnInfoA, acci, nControls);
  368.  
  369.     if (!nControls2) {
  370.         Message(MSG_CANTINITDLL, pszFileName);
  371.         goto Error2;
  372.     }
  373.  
  374.     for (i = 0; i < nControls; i++) {
  375.         if (!AddCustomLink(&acci[i], FALSE, fUnicodeDLL, pszFileName, hmod))
  376.             goto Error2;
  377.     }
  378.  
  379.     fSuccess = TRUE;
  380.  
  381. Error2:
  382.     MyFree(acci);
  383.  
  384. Error1:
  385.     if (!fSuccess)
  386.         FreeLibrary(hmod);
  387. }
  388.  
  389.  
  390.  
  391. /************************************************************************
  392. * CallCustomInfoA
  393. *
  394. * Thunks the call from the unicode DlgEdit to the ANSI custom control
  395. * info procedure.
  396. *
  397. * History:
  398. *
  399. ************************************************************************/
  400.  
  401. STATICFN UINT CallCustomInfoA(
  402.     LPFNCCINFOA lpfnInfoA,
  403.     LPCCINFO acciW,
  404.     INT nControls)
  405. {
  406.     LPCCINFOA acciA;
  407.     INT nControls2;
  408.     INT i;
  409.     INT j;
  410.     LPCCSTYLEFLAGA lpFlagsA;
  411.     LPCCSTYLEFLAGW aFlagsW = NULL;
  412.     INT cch;
  413.  
  414.     /*
  415.      * Allocate the appropriate number of ANSI info structures.
  416.      */
  417.     if (!(acciA = (LPCCINFOA)MyAlloc(nControls * sizeof(CCINFOA))))
  418.         return 0;
  419.  
  420.     /*
  421.      * Call the ANSI info function.
  422.      */
  423.     if (nControls2 = (*lpfnInfoA)(acciA)) {
  424.         /*
  425.          * Copy all the ANSI structures to the UNICODE structures,
  426.          * converting strings to UNICODE as we go.
  427.          */
  428.         for (i = 0; i < nControls; i++) {
  429.             MultiByteToWideChar(CP_ACP, 0, acciA[i].szClass, -1,
  430.                     acciW[i].szClass, CCHCCCLASS);
  431.             acciW[i].flOptions = acciA[i].flOptions;
  432.             MultiByteToWideChar(CP_ACP, 0, acciA[i].szDesc, -1,
  433.                     acciW[i].szDesc, CCHCCDESC);
  434.             acciW[i].cxDefault = acciA[i].cxDefault;
  435.             acciW[i].cyDefault = acciA[i].cyDefault;
  436.             acciW[i].flStyleDefault = acciA[i].flStyleDefault;
  437.             acciW[i].flExtStyleDefault = acciA[i].flExtStyleDefault;
  438.             acciW[i].flCtrlTypeMask = acciA[i].flCtrlTypeMask;
  439.             MultiByteToWideChar(CP_ACP, 0, acciA[i].szTextDefault, -1,
  440.                     acciW[i].szTextDefault, CCHCCTEXT);
  441.  
  442.             /*
  443.              * Is there a table of style flags?  If so, we need to build
  444.              * up a table of unicode style flags.  Note that since we
  445.              * allocate this table, the table must be freed when the
  446.              * custom link is destroyed!
  447.              */
  448.             if (acciA[i].cStyleFlags) {
  449.                 /*
  450.                  * If they specified that there are style flags, the pointer
  451.                  * to the table must not be NULL.
  452.                  */
  453.                 if (!acciA[i].aStyleFlags)
  454.                     return 0;
  455.  
  456.                 if (!(aFlagsW = (LPCCSTYLEFLAGW)MyAlloc(
  457.                         acciA[i].cStyleFlags * sizeof(CCSTYLEFLAGW))))
  458.                     return 0;
  459.  
  460.                 /*
  461.                  * Copy all the flags to the new unicode style flag table.
  462.                  */
  463.                 for (j = 0, lpFlagsA = acciA[i].aStyleFlags;
  464.                         j < acciA[i].cStyleFlags; j++, lpFlagsA++) {
  465.                     aFlagsW[j].flStyle = lpFlagsA->flStyle;
  466.                     aFlagsW[j].flStyleMask = lpFlagsA->flStyleMask;
  467.  
  468.                     cch =  lstrlenA(lpFlagsA->pszStyle) + 1;
  469.                     aFlagsW[j].pszStyle = (LPWSTR)MyAlloc(cch * sizeof(WCHAR));
  470.  
  471.                     if (!aFlagsW[j].pszStyle)
  472.                         return 0;
  473.  
  474.                     MultiByteToWideChar(CP_ACP, 0, lpFlagsA->pszStyle, -1,
  475.                             aFlagsW[j].pszStyle, cch);
  476.                 }
  477.             }
  478.  
  479.             acciW[i].cStyleFlags = acciA[i].cStyleFlags;
  480.             acciW[i].aStyleFlags = aFlagsW;
  481.  
  482.             acciW[i].lpfnStyle = (LPFNCCSTYLE)acciA[i].lpfnStyle;
  483.             acciW[i].lpfnSizeToText = (LPFNCCSIZETOTEXT)acciA[i].lpfnSizeToText;
  484.             acciW[i].dwReserved1 = acciA[i].dwReserved1;
  485.             acciW[i].dwReserved2 = acciA[i].dwReserved2;
  486.         }
  487.     }
  488.  
  489.     MyFree(acciA);
  490.  
  491.     return nControls2;
  492. }
  493.  
  494.  
  495.  
  496. /************************************************************************
  497. * SelCustDialog
  498. *
  499. * Displays the Select Custom Control dialog to choose which custom
  500. * control tool should be selected.
  501. *
  502. * History:
  503. *
  504. ************************************************************************/
  505.  
  506. PWINDOWCLASSDESC SelCustDialog(VOID)
  507. {
  508.     if (DlgBox(DID_SELCUST, (WNDPROC)SelCustDlgProc) == IDOK)
  509.         return pwcdChosen;
  510.     else
  511.         return NULL;
  512. }
  513.  
  514.  
  515.  
  516. /************************************************************************
  517. * SelCustDlgProc
  518. *
  519. * This is the Select Custom Control dialog procedure.
  520. *
  521. * History:
  522. *
  523. ************************************************************************/
  524.  
  525. DIALOGPROC SelCustDlgProc(
  526.     HWND hwnd,
  527.     UINT msg,
  528.     WPARAM wParam,
  529.     LPARAM lParam)
  530. {
  531.     switch (msg) {
  532.         case WM_INITDIALOG:
  533.             SelCustInit(hwnd);
  534.             return TRUE;
  535.  
  536.         case WM_COMMAND:
  537.             switch (LOWORD(wParam)) {
  538.                 case DID_SELCUSTLIST:
  539.                     switch (HIWORD(wParam)) {
  540.                         case LBN_DBLCLK:
  541.                             if (SelCustOK(hwnd))
  542.                                 EndDialog(hwnd, IDOK);
  543.  
  544.                             break;
  545.  
  546.                         case LBN_SELCHANGE:
  547.                             SelCustSelect(hwnd);
  548.                             break;
  549.                     }
  550.  
  551.                     break;
  552.  
  553.                 case IDOK:
  554.                     if (SelCustOK(hwnd))
  555.                         EndDialog(hwnd, IDOK);
  556.  
  557.                     break;
  558.  
  559.                 case IDCANCEL:
  560.                     EndDialog(hwnd, IDCANCEL);
  561.                     break;
  562.  
  563.                 case IDHELPDLG:
  564.                     WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
  565.                             HELPID_SELCUST);
  566.                     break;
  567.             }
  568.  
  569.             return TRUE;
  570.  
  571.         default:
  572.             return FALSE;
  573.     }
  574. }
  575.  
  576.  
  577.  
  578. /************************************************************************
  579. * SelCustInit
  580. *
  581. * Processes the WM_INITDIALOG message for the Select Custom Control
  582. * dialog procedure.
  583. *
  584. * History:
  585. *
  586. ************************************************************************/
  587.  
  588. STATICFN VOID SelCustInit(
  589.     HWND hwnd)
  590. {
  591.     HWND hwndLB;
  592.     INT i;
  593.     PCUSTLINK pcl;
  594.     LPTSTR pszDesc;
  595.  
  596.     hwndLB = GetDlgItem(hwnd, DID_SELCUSTLIST);
  597.  
  598.     /*
  599.      * Insert each custom control into the listbox.
  600.      */
  601.     for (pcl = gpclHead; pcl; pcl = pcl->pclNext) {
  602.         /*
  603.          * Use the short description, if the control has one,
  604.          * otherwise use the class name itself.
  605.          */
  606.         if (pcl->pszDesc)
  607.             pszDesc = pcl->pszDesc;
  608.         else
  609.             pszDesc = pcl->pwcd->pszClass;
  610.  
  611.         i = (INT)SendMessage(hwndLB, LB_ADDSTRING, 0, (DWORD)pszDesc);
  612.         SendMessage(hwndLB, LB_SETITEMDATA, i, (DWORD)pcl);
  613.     }
  614.  
  615.     hwndCustomSample = NULL;
  616.  
  617.     /*
  618.      * Select the first item.
  619.      */
  620.     SendMessage(hwndLB, LB_SETCURSEL, 0, 0L);
  621.     SelCustSelect(hwnd);
  622.  
  623.     CenterWindow(hwnd);
  624. }
  625.  
  626.  
  627.  
  628. /************************************************************************
  629. * SelCustSelect
  630. *
  631. * Called every time that a different control is selected in the list box
  632. * in the Select Custom Control dialog.  It will create a sample control
  633. * and show it in the Sample box.
  634. *
  635. * History:
  636. *
  637. ************************************************************************/
  638.  
  639. STATICFN VOID SelCustSelect(
  640.     HWND hwnd)
  641. {
  642.     HWND hwndLB;
  643.     INT iSelect;
  644.     PCUSTLINK pcl;
  645.     PWINDOWCLASSDESC pwcd;
  646.     LPTSTR pszClass;
  647.     RECT rc;
  648.     RECT rcParent;
  649.     HWND hwndParent;
  650.     INT x;
  651.     INT y;
  652.     INT cx;
  653.     INT cy;
  654.     INT cxParent;
  655.     INT cyParent;
  656.  
  657.     hwndLB = GetDlgItem(hwnd, DID_SELCUSTLIST);
  658.  
  659.     if ((iSelect = (INT)SendMessage(hwndLB, LB_GETCURSEL, 0, 0)) == LB_ERR)
  660.         return;
  661.  
  662.     /*
  663.      * Get a pointer to the custom control link (stored in the listbox
  664.      * items data field).
  665.      */
  666.     pcl = (PCUSTLINK)SendMessage(hwndLB, LB_GETITEMDATA, iSelect, 0L);
  667.     pwcd = pcl->pwcd;
  668.  
  669.     /*
  670.      * Get the coordinates of the Sample box.
  671.      */
  672.     hwndParent = GetDlgItem(hwnd, DID_SELCUSTSAMPLE);
  673.     GetWindowRect(hwndParent, &rcParent);
  674.     ScreenToClientRect(hwnd, &rcParent);
  675.     cxParent = (rcParent.right - rcParent.left) - (2 * SAMPLEMARGIN);
  676.     cyParent = (rcParent.bottom - rcParent.top) - (2 * SAMPLEMARGIN);
  677.  
  678.     /*
  679.      * Calculate the window size of the sample control.
  680.      */
  681.     SetRect(&rc, 0, 0, pwcd->cxDefault, pwcd->cyDefault);
  682.     DUToWinRect(&rc);
  683.     cx = rc.right - rc.left;
  684.     cy = rc.bottom - rc.top;
  685.  
  686.     /*
  687.      * Be sure that the control can fit within the sample box.  Adjust
  688.      * it down if necessary.
  689.      */
  690.     if (cx < cxParent) {
  691.         x = ((cxParent - cx) / 2) + SAMPLEMARGIN;
  692.     }
  693.     else {
  694.         x = SAMPLEMARGIN;
  695.         cx = cxParent;
  696.     }
  697.  
  698.     if (cy < cyParent) {
  699.         y = ((cyParent - cy) / 2) + SAMPLEMARGIN;
  700.     }
  701.     else {
  702.         y = SAMPLEMARGIN;
  703.         cy = cyParent;
  704.     }
  705.  
  706.     x += rcParent.left;
  707.     y += rcParent.top;
  708.  
  709.     /*
  710.      * Destroy the old sample.
  711.      */
  712.     if (hwndCustomSample)
  713.         DestroyWindow(hwndCustomSample);
  714.  
  715.     /*
  716.      * Get the class name to use.
  717.      * If the control is emulated, use the special emulator class.
  718.      * Otherwise, it is an installed custom control, and we can use
  719.      * it's real class string.
  720.      */
  721.     if (pwcd->fEmulated)
  722.         pszClass = szCustomClass;
  723.     else
  724.         pszClass = pwcd->pszClass;
  725.  
  726.     /*
  727.      * Create the sample control.  We always create it visible here,
  728.      * even if the style says it isn't.
  729.      */
  730.     hwndCustomSample = CreateWindow(
  731.             pszClass,
  732.             pwcd->pszTextDefault,
  733.             pwcd->flStyles | WS_VISIBLE,
  734.             x, y, cx, cy,
  735.             hwnd,
  736.             0,
  737.             ghInst,
  738.             NULL);
  739. }
  740.  
  741.  
  742.  
  743. /************************************************************************
  744. * SelCustOK
  745. *
  746. * Processes the final selection of a custom control from the
  747. * Select Custom Control dialog.
  748. *
  749. * History:
  750. *
  751. ************************************************************************/
  752.  
  753. STATICFN BOOL SelCustOK(
  754.     HWND hwnd)
  755. {
  756.     HWND hwndLB;
  757.     INT iSelect;
  758.     PCUSTLINK pcl;
  759.  
  760.     hwndLB = GetDlgItem(hwnd, DID_SELCUSTLIST);
  761.  
  762.     if ((iSelect = (INT)SendMessage(hwndLB, LB_GETCURSEL, 0, 0)) == LB_ERR)
  763.         return FALSE;
  764.  
  765.     /*
  766.      * Get a pointer to the custom control link (stored in the listbox
  767.      * items data field).
  768.      */
  769.     pcl = (PCUSTLINK)SendMessage(hwndLB, LB_GETITEMDATA, iSelect, 0L);
  770.  
  771.     pwcdChosen = pcl->pwcd;
  772.  
  773.     return TRUE;
  774. }
  775.  
  776.  
  777.  
  778. /************************************************************************
  779. * RemCustDlgProc
  780. *
  781. * This is the Remove Custom Control dialog procedure.
  782. * It is used to de-install a custom control.
  783. *
  784. * History:
  785. *
  786. ************************************************************************/
  787.  
  788. DIALOGPROC RemCustDlgProc(
  789.     HWND hwnd,
  790.     UINT msg,
  791.     WPARAM wParam,
  792.     LPARAM lParam)
  793. {
  794.     switch (msg) {
  795.         case WM_INITDIALOG:
  796.             RemCustInit(hwnd);
  797.             return TRUE;
  798.  
  799.         case WM_COMMAND:
  800.             switch (LOWORD(wParam)) {
  801.                 case DID_REMCUSTLIST:
  802.                     if (HIWORD(wParam) == LBN_DBLCLK) {
  803.                         if (RemCustOK(hwnd))
  804.                             EndDialog(hwnd, IDOK);
  805.                     }
  806.  
  807.                     break;
  808.  
  809.                 case IDOK:
  810.                     if (RemCustOK(hwnd))
  811.                         EndDialog(hwnd, IDOK);
  812.  
  813.                     break;
  814.  
  815.                 case IDCANCEL:
  816.                     EndDialog(hwnd, IDCANCEL);
  817.                     break;
  818.  
  819.                 case IDHELPDLG:
  820.                     WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT,
  821.                             HELPID_REMCUST);
  822.                     break;
  823.             }
  824.  
  825.             return TRUE;
  826.  
  827.         default:
  828.             return FALSE;
  829.     }
  830. }
  831.  
  832.  
  833.  
  834. /************************************************************************
  835. * RemCustInit
  836. *
  837. * Processes the WM_INITDIALOG message for the Remove Custom Control
  838. * dialog procedure.
  839. *
  840. * History:
  841. *
  842. ************************************************************************/
  843.  
  844. STATICFN VOID RemCustInit(
  845.     HWND hwnd)
  846. {
  847.     HWND hwndLB;
  848.     INT i;
  849.     PCUSTLINK pcl;
  850.     LPTSTR pszDesc;
  851.  
  852.     hwndLB = GetDlgItem(hwnd, DID_REMCUSTLIST);
  853.  
  854.     /*
  855.      * Insert each custom control into the listbox.
  856.      */
  857.     for (pcl = gpclHead; pcl; pcl = pcl->pclNext) {
  858.         /*
  859.          * Use the short description, if the control has one,
  860.          * otherwise use the class name itself.
  861.          */
  862.         if (pcl->pszDesc)
  863.             pszDesc = pcl->pszDesc;
  864.         else
  865.             pszDesc = pcl->pwcd->pszClass;
  866.  
  867.         i = (INT)SendMessage(hwndLB, LB_ADDSTRING, 0, (DWORD)pszDesc);
  868.         SendMessage(hwndLB, LB_SETITEMDATA, i, (DWORD)pcl);
  869.     }
  870.  
  871.     /*
  872.      * Select the first item.
  873.      */
  874.     SendMessage(hwndLB, LB_SETCURSEL, 0, 0L);
  875.  
  876.     CenterWindow(hwnd);
  877. }
  878.  
  879.  
  880.  
  881. /************************************************************************
  882. * RemCustOK
  883. *
  884. * Processes the selection of a custom control to delete from the
  885. * Remove Custom Control dialog.
  886. *
  887. * History:
  888. *
  889. ************************************************************************/
  890.  
  891. STATICFN BOOL RemCustOK(
  892.     HWND hwnd)
  893. {
  894.     HWND hwndLB;
  895.     INT iSelect;
  896.     PCUSTLINK pcl;
  897.     NPCTYPE npc;
  898.  
  899.     hwndLB = GetDlgItem(hwnd, DID_REMCUSTLIST);
  900.  
  901.     if ((iSelect = (INT)SendMessage(hwndLB, LB_GETCURSEL, 0, 0)) != LB_ERR) {
  902.         /*
  903.          * Get a pointer to the custom control link (stored in the listbox
  904.          * items data field).
  905.          */
  906.         pcl = (PCUSTLINK)SendMessage(hwndLB, LB_GETITEMDATA, iSelect, 0L);
  907.  
  908.         /*
  909.          * Cannot delete if any controls in the current dialog
  910.          * are of this type.
  911.          */
  912.         for (npc = npcHead; npc; npc = npc->npcNext) {
  913.             if (pcl->pwcd == npc->pwcd) {
  914.                 Message(MSG_CUSTCNTLINUSE);
  915.                 return FALSE;
  916.             }
  917.         }
  918.  
  919.         RemoveCustomLink(pcl);
  920.     }
  921.  
  922.     return TRUE;
  923. }
  924.  
  925.  
  926.  
  927. /****************************************************************************
  928. * CustomWndProc
  929. *
  930. * This is the window procedure for the emulated Custom control.
  931. *
  932. * History:
  933. *
  934. ****************************************************************************/
  935.  
  936. WINDOWPROC CustomWndProc(
  937.     HWND hwnd,
  938.     UINT msg,
  939.     WPARAM wParam,
  940.     LPARAM lParam)
  941. {
  942.     switch (msg) {
  943.         case WM_PAINT:
  944.             {
  945.                 HDC hDC;
  946.                 PAINTSTRUCT ps;
  947.                 RECT rc;
  948.                 TCHAR szText[CCHTEXTMAX];
  949.  
  950.                 hDC = BeginPaint(hwnd, &ps);
  951.  
  952.                 SelectObject(hDC, GetStockObject(LTGRAY_BRUSH));
  953.                 GetClientRect(hwnd, &rc);
  954.                 Rectangle(hDC, rc.left, rc.top, rc.right, rc.bottom);
  955.                 GetWindowText(hwnd, szText, CCHTEXTMAX);
  956. #ifdef JAPAN
  957.                 {
  958.                     TCHAR   szTmp[CCHTEXTMAX];
  959.  
  960.                     KDExpandCopy(szTmp, szText, CCHTEXTMAX);
  961.                     lstrcpy(szText, szTmp);
  962.                 }
  963. #endif
  964.                 SetBkMode(hDC, TRANSPARENT);
  965.  
  966.                 if (gcd.hFont)
  967.                     SelectObject(hDC, gcd.hFont);
  968.  
  969.                 DrawText(hDC, szText, -1, &rc,
  970.                         DT_CENTER | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE);
  971.  
  972.                 EndPaint(hwnd, &ps);
  973.             }
  974.  
  975.             break;
  976.  
  977.         default:
  978.             return DefWindowProc(hwnd, msg, wParam, lParam);
  979.     }
  980.  
  981.     return 0;
  982. }
  983.  
  984.  
  985.  
  986. /************************************************************************
  987. * AddCustomLink
  988. *
  989. * Adds a new custom control to the linked list.
  990. *
  991. * Note that normally duplicates are checked for, but it allows multiple
  992. * links to be added with the same class if it is a DLL control.  This
  993. * is to support multiple control types being added from the same DLL.
  994. * Because of this, if the caller is adding a non-emulated link, they
  995. * are responsible for checking the list for duplicates first!
  996. *
  997. * There is one special case.  If it is adding a DLL link, and an
  998. * emulated link with the same class name is found, it will walk the
  999. * current list of controls and replace all of them with the new DLL
  1000. * control type, then delete the emulated link.  This is to support
  1001. * the case where the user creates some controls of class FOO, where
  1002. * FOO is emulated, then later loads the FOO DLL.  All controls of
  1003. * this emulated class will be changed to be the real FOO class, and
  1004. * the DLL FOO link replaces the emulated one.
  1005. *
  1006. * History:
  1007. *
  1008. ************************************************************************/
  1009.  
  1010. PCUSTLINK AddCustomLink(
  1011.     LPCCINFO pcci,
  1012.     BOOL fEmulated,
  1013.     BOOL fUnicodeDLL,
  1014.     LPTSTR pszFileName,
  1015.     HANDLE hmod)
  1016. {
  1017.     PCUSTLINK pcl;
  1018.     PCUSTLINK pclT;
  1019.     PCUSTLINK pclPrev;
  1020.     NPCTYPE npc;
  1021.     HWND hwndOld;
  1022.  
  1023.     if (!(pcl = AllocCUSTLINK(pcci, fEmulated, fUnicodeDLL, pszFileName, hmod)))
  1024.         return NULL;
  1025.  
  1026.     if (fEmulated) {
  1027.         /*
  1028.          * Search the list for another link with the same class.
  1029.          */
  1030.         for (pclT = gpclHead;
  1031.                 pclT && lstrcmpi(pclT->pwcd->pszClass, pcci->szClass) != 0;
  1032.                 pclT = pclT->pclNext)
  1033.             ;
  1034.  
  1035.         /*
  1036.          * Was a duplicate found?
  1037.          */
  1038.         if (pclT) {
  1039.             FreeCUSTLINK(pcl);
  1040.             Message(MSG_CUSTALREADYLOADED, pcci->szClass);
  1041.  
  1042.             return NULL;
  1043.         }
  1044.     }
  1045.     else {
  1046.         /*
  1047.          * Search the list for another link with the same class that
  1048.          * is an emulated control.
  1049.          */
  1050.         for (pclT = gpclHead;
  1051.                 pclT &&
  1052.                 (lstrcmpi(pclT->pwcd->pszClass, pcci->szClass) != 0 ||
  1053.                 !pclT->pwcd->fEmulated);
  1054.                 pclT = pclT->pclNext)
  1055.             ;
  1056.  
  1057.         /*
  1058.          * Was a duplicate found?
  1059.          */
  1060.         if (pclT) {
  1061.             /*
  1062.              * At this point we know that this is a DLL link replacing
  1063.              * an existing emulated control class.  We want to go through
  1064.              * the existing controls and replace any of this class with
  1065.              * the new DLL class.  This allows a user to load a dialog
  1066.              * with some emulated controls, then later install the custom
  1067.              * DLL and have all the existing controls of that class
  1068.              * change to show the real control.
  1069.              */
  1070.             for (npc = npcHead; npc; npc = npc->npcNext) {
  1071.                 /*
  1072.                  * Is the control of the type that we are replacing?
  1073.                  */
  1074.                 if (npc->pwcd == pclT->pwcd) {
  1075.                     hwndOld = npc->hwnd;
  1076.  
  1077.                     /*
  1078.                      * Unsubclass the old control window, then switch
  1079.                      * the pwcd pointer before calling CreateControl.
  1080.                      */
  1081.                     SetWindowLong(hwndOld, GWL_WNDPROC,
  1082.                             (DWORD)npc->pwcd->pfnOldWndProc);
  1083.                     UNSETPCINTOHWND(hwndOld);
  1084.                     npc->pwcd = pcl->pwcd;
  1085.  
  1086.                     /*
  1087.                      * Create a control of the new type in the same position.
  1088.                      */
  1089.                     if (CreateControl(npc, npc->text, npc->flStyle,
  1090.                             npc->flExtStyle, npc->id, &npc->rc,
  1091.                             hwndOld, NULL)) {
  1092.                         /*
  1093.                          * Get rid of the old control window.
  1094.                          */
  1095.                         DestroyWindow(hwndOld);
  1096.  
  1097.                         /*
  1098.                          * Adjust the size and position of its drag window.
  1099.                          */
  1100.                         SizeDragToControl(npc);
  1101.                     }
  1102.                 }
  1103.             }
  1104.  
  1105.             /*
  1106.              * Remove the old link, now that all the controls that
  1107.              * used it are gone.
  1108.              */
  1109.             RemoveCustomLink(pclT);
  1110.         }
  1111.     }
  1112.  
  1113.     /*
  1114.      * Search for the end of the list.  Get a pointer to the last link.
  1115.      */
  1116.     for (pclT = gpclHead, pclPrev = NULL; pclT;
  1117.             pclPrev = pclT, pclT = pclT->pclNext)
  1118.         ;
  1119.  
  1120.     /*
  1121.      * Add the new link to the list.  Add it to the end if there are
  1122.      * other links, or initialize the head pointer if this is the
  1123.      * first one.
  1124.      */
  1125.     if (pclPrev)
  1126.         pclPrev->pclNext = pcl;
  1127.     else
  1128.         gpclHead = pcl;
  1129.  
  1130.     return pcl;
  1131. }
  1132.  
  1133.  
  1134.  
  1135. /************************************************************************
  1136. * AllocCUSTLINK
  1137. *
  1138. * Allocates a CUSTLINK structure and initializes it.  This includes
  1139. * allocating an associated WINDOWCLASSDESC structure.
  1140. *
  1141. * History:
  1142. *
  1143. ************************************************************************/
  1144.  
  1145. STATICFN PCUSTLINK AllocCUSTLINK(
  1146.     LPCCINFO pcci,
  1147.     BOOL fEmulated,
  1148.     BOOL fUnicodeDLL,
  1149.     LPTSTR pszFileName,
  1150.     HANDLE hmod)
  1151. {
  1152.     PCUSTLINK pcl;
  1153.     PWINDOWCLASSDESC pwcd;
  1154.  
  1155.     if (!(pwcd = (PWINDOWCLASSDESC)MyAlloc(sizeof(WINDOWCLASSDESC))))
  1156.         return NULL;
  1157.  
  1158.     /*
  1159.      * Initialize the structure to be like an emulated custom control.
  1160.      */
  1161.     *pwcd = awcd[W_CUSTOM];
  1162.  
  1163.     /*
  1164.      * Now override some values.
  1165.      */
  1166.     pwcd->flStyles = pcci->flStyleDefault;
  1167.     pwcd->flExtStyle = pcci->flExtStyleDefault;
  1168.     pwcd->cxDefault = pcci->cxDefault;
  1169.     pwcd->cyDefault = pcci->cyDefault;
  1170.     pwcd->fEmulated = fEmulated;
  1171.     pwcd->fUnicodeDLL = fUnicodeDLL;
  1172.     pwcd->hmod = hmod;
  1173.     pwcd->cStyleFlags = pcci->cStyleFlags;
  1174.     pwcd->aStyleFlags = pcci->aStyleFlags;
  1175.     pwcd->lpfnStyle = (PROC)pcci->lpfnStyle;
  1176.     pwcd->lpfnSizeToText = (PROC)pcci->lpfnSizeToText;
  1177.     pwcd->flCtrlTypeMask = pcci->flCtrlTypeMask;
  1178.  
  1179.     if (pcci->flOptions & CCF_NOTEXT)
  1180.         pwcd->fHasText = FALSE;
  1181.     else
  1182.         pwcd->fHasText = TRUE;
  1183.  
  1184.     if (pcci->lpfnSizeToText && pwcd->fHasText)
  1185.         pwcd->fSizeToText = TRUE;
  1186.  
  1187.     /*
  1188.      * Copy the class name.
  1189.      */
  1190.     if (!(pwcd->pszClass = NameOrdDup(pcci->szClass)))
  1191.         goto error1;
  1192.  
  1193.     /*
  1194.      * Copy the default text.  This is an optional field.
  1195.      */
  1196.     if (*pcci->szTextDefault) {
  1197.         if (!(pwcd->pszTextDefault = NameOrdDup(pcci->szTextDefault)))
  1198.             goto error2;
  1199.     }
  1200.     else {
  1201.         pwcd->pszTextDefault = NULL;
  1202.     }
  1203.  
  1204.     if (!(pcl = (PCUSTLINK)MyAlloc(sizeof(CUSTLINK))))
  1205.         goto error3;
  1206.  
  1207.     /*
  1208.      * Copy the DLL file name (NULL for emulated controls).
  1209.      */
  1210.     if (pszFileName && *pszFileName) {
  1211.         if (!(pcl->pszFileName = NameOrdDup(pszFileName)))
  1212.             goto error4;
  1213.     }
  1214.     else {
  1215.         pcl->pszFileName = NULL;
  1216.     }
  1217.  
  1218.     /*
  1219.      * Copy the descriptive text.  This is an optional field.
  1220.      */
  1221.     if (*pcci->szDesc) {
  1222.         if (!(pcl->pszDesc = NameOrdDup(pcci->szDesc)))
  1223.             goto error5;
  1224.     }
  1225.     else {
  1226.         pcl->pszDesc = NULL;
  1227.     }
  1228.  
  1229.     pcl->pclNext = NULL;
  1230.     pcl->pwcd = pwcd;
  1231.  
  1232.     return pcl;
  1233.  
  1234. error5:
  1235.     if (pcl->pszFileName)
  1236.         MyFree(pcl->pszFileName);
  1237.  
  1238. error4:
  1239.     MyFree(pcl);
  1240.  
  1241. error3:
  1242.     if (pwcd->pszTextDefault)
  1243.         MyFree(pwcd->pszTextDefault);
  1244.  
  1245. error2:
  1246.     MyFree(pwcd->pszClass);
  1247.  
  1248. error1:
  1249.     MyFree(pwcd);
  1250.  
  1251.     return NULL;
  1252. }
  1253.  
  1254.  
  1255.  
  1256. /************************************************************************
  1257. * RemoveCustomLink
  1258. *
  1259. * Removes and frees a custom control link from the list.
  1260. *
  1261. * History:
  1262. *
  1263. ************************************************************************/
  1264.  
  1265. VOID RemoveCustomLink(
  1266.     PCUSTLINK pclFree)
  1267. {
  1268.     PCUSTLINK pcl;
  1269.     PCUSTLINK pclPrev;
  1270.  
  1271.     /*
  1272.      * Search for the link in the list.
  1273.      */
  1274.     for (pcl = gpclHead, pclPrev = NULL; pcl != pclFree;
  1275.             pclPrev = pcl, pcl = pcl->pclNext)
  1276.         ;
  1277.  
  1278.     /*
  1279.      * Link was not found.
  1280.      */
  1281.     if (!pcl)
  1282.         return;
  1283.  
  1284.     /*
  1285.      * Remove the link from the list.
  1286.      */
  1287.     if (pclPrev)
  1288.         pclPrev->pclNext = pclFree->pclNext;
  1289.     else
  1290.         gpclHead = pclFree->pclNext;
  1291.  
  1292.     /*
  1293.      * Finally, free the link completely.
  1294.      */
  1295.     FreeCUSTLINK(pclFree);
  1296. }
  1297.  
  1298.  
  1299.  
  1300. /************************************************************************
  1301. * FreeCUSTLINK
  1302. *
  1303. * Frees a CUSTLINK structure.  This includes freeing the
  1304. * associated WINDOWCLASSDESC structure.
  1305. *
  1306. * History:
  1307. *
  1308. ************************************************************************/
  1309.  
  1310. STATICFN VOID FreeCUSTLINK(
  1311.     PCUSTLINK pclFree)
  1312. {
  1313.     PCUSTLINK pcl;
  1314.     INT i;
  1315.  
  1316.     /*
  1317.      * Do we need to unload the associated DLL?
  1318.      */
  1319.     if (pclFree->pwcd->hmod) {
  1320.         /*
  1321.          * Run throught the custom list looking to see if any other
  1322.          * installed custom control has the same module handle as the
  1323.          * one that we are freeing.
  1324.          */
  1325.         for (pcl = gpclHead;
  1326.                 pcl &&
  1327.                 (pcl == pclFree || pcl->pwcd->hmod != pclFree->pwcd->hmod);
  1328.                 pcl = pcl->pclNext)
  1329.             ;
  1330.  
  1331.         /*
  1332.          * If none were found, it is safe to unload this library.
  1333.          * Otherwise, we must leave the library loaded for the
  1334.          * others!
  1335.          */
  1336.         if (!pcl)
  1337.             FreeLibrary(pclFree->pwcd->hmod);
  1338.     }
  1339.  
  1340.     MyFree(pclFree->pwcd->pszClass);
  1341.  
  1342.     if (pclFree->pwcd->pszTextDefault)
  1343.         MyFree(pclFree->pwcd->pszTextDefault);
  1344.  
  1345.     /*
  1346.      * Is this a non-unicode DLL?  If so, then when it was loaded,
  1347.      * the dialog editor allocated a table of unicode style strings.
  1348.      * This table must now be freed.  If the DLL was a unicode one,
  1349.      * then the table pointed to by aStyleFlags belongs to the DLL,
  1350.      * and it must NOT be freed.
  1351.      */
  1352.     if (pclFree->pwcd->hmod && !pclFree->pwcd->fUnicodeDLL) {
  1353.         for (i = 0; i < pclFree->pwcd->cStyleFlags; i++)
  1354.             MyFree(pclFree->pwcd->aStyleFlags[i].pszStyle);
  1355.  
  1356.         if (pclFree->pwcd->aStyleFlags)
  1357.             MyFree(pclFree->pwcd->aStyleFlags);
  1358.     }
  1359.  
  1360.     MyFree(pclFree->pwcd);
  1361.  
  1362.     if (pclFree->pszFileName)
  1363.         MyFree(pclFree->pszFileName);
  1364.  
  1365.     if (pclFree->pszDesc)
  1366.         MyFree(pclFree->pszDesc);
  1367.  
  1368.     MyFree(pclFree);
  1369. }
  1370.  
  1371.  
  1372.  
  1373. /************************************************************************
  1374. * CallCustomStyle
  1375. *
  1376. *
  1377. * History:
  1378. *
  1379. ************************************************************************/
  1380.  
  1381. BOOL CallCustomStyle(
  1382.     NPCTYPE npc,
  1383.     PDWORD pflStyleNew,
  1384.     PDWORD pflExtStyleNew,
  1385.     LPTSTR pszTextNew)
  1386. {
  1387.     CCSTYLE ccs;
  1388.     CCSTYLEA ccsA;
  1389.     BOOL fSuccess;
  1390.     BOOL fDefCharUsed;
  1391.     INT idPrevDlg;
  1392.  
  1393.     /*
  1394.      * Because we are about ready to display the dialog, we need to
  1395.      * call EnteringDialog so that the properties bar, toolbox and
  1396.      * work mode dialog get disabled.  The first parameter is the
  1397.      * dialog id, used so that the proper help will be brought up
  1398.      * for this dialog.  Since we don't have a meaningful help screen
  1399.      * for any old random custom control, just pass in a value of
  1400.      * zero, which will cause the Help Contents screen to be
  1401.      * brought up if the user presses F1 while the dialog is up.
  1402.      */
  1403.     EnteringDialog(0, &idPrevDlg, TRUE);
  1404.  
  1405.     /*
  1406.      * Is this a UNICODE DLL?
  1407.      */
  1408.     if (npc->pwcd->fUnicodeDLL) {
  1409.         ccs.flStyle = *pflStyleNew;
  1410.         ccs.flExtStyle = *pflExtStyleNew;
  1411.         lstrcpy(ccs.szText, pszTextNew);
  1412.         ccs.lgid = gcd.di.wLanguage;
  1413.         ccs.wReserved1 = 0;
  1414.  
  1415.         fSuccess = ((LPFNCCSTYLE)(*npc->pwcd->lpfnStyle))(ghwndMain, &ccs);
  1416.  
  1417.         if (fSuccess) {
  1418.             *pflStyleNew = ccs.flStyle;
  1419.             *pflExtStyleNew = ccs.flExtStyle;
  1420.             lstrcpy(pszTextNew, ccs.szText);
  1421.         }
  1422.     }
  1423.     else {
  1424.         ccsA.flStyle = *pflStyleNew;
  1425.         ccsA.flExtStyle = *pflExtStyleNew;
  1426.         WideCharToMultiByte(CP_ACP, 0, pszTextNew, -1, ccsA.szText, CCHCCTEXT,
  1427.                 NULL, &fDefCharUsed);
  1428.         ccsA.lgid = gcd.di.wLanguage;
  1429.         ccsA.wReserved1 = 0;
  1430.  
  1431.         fSuccess = ((LPFNCCSTYLEA)(*npc->pwcd->lpfnStyle))(ghwndMain, &ccsA);
  1432.  
  1433.         if (fSuccess) {
  1434.             *pflStyleNew = ccsA.flStyle;
  1435.             *pflExtStyleNew = ccsA.flExtStyle;
  1436.             MultiByteToWideChar(CP_ACP, 0, ccsA.szText, -1, pszTextNew,
  1437.                     CCHTEXTMAX);
  1438.         }
  1439.     }
  1440.  
  1441.     EnteringDialog(idPrevDlg, NULL, FALSE);
  1442.  
  1443.     return fSuccess;
  1444. }
  1445.  
  1446.  
  1447.  
  1448. /************************************************************************
  1449. * CallCustomSizeToText
  1450. *
  1451. *
  1452. *
  1453. * Returns:
  1454. *
  1455. * History:
  1456. *
  1457. ************************************************************************/
  1458.  
  1459. INT CallCustomSizeToText(
  1460.     NPCTYPE npc)
  1461. {
  1462.     INT x;
  1463.     INT xDU;
  1464.     BOOL fDefCharUsed;
  1465.     CHAR szTextA[CCHTEXTMAX];
  1466.     PSTR pszTextA;
  1467.  
  1468.     /*
  1469.      * Does this custom control have a SizeToText function?
  1470.      */
  1471.     if (!npc->pwcd->lpfnSizeToText)
  1472.         return -1;
  1473.  
  1474.     /*
  1475.      * Is this a UNICODE DLL that we are calling to?
  1476.      */
  1477.     if (npc->pwcd->fUnicodeDLL) {
  1478.         x = ((LPFNCCSIZETOTEXT)(*npc->pwcd->lpfnSizeToText))
  1479.                 (npc->flStyle, npc->flExtStyle, gcd.hFont, npc->text);
  1480.     }
  1481.     else {
  1482.         /*
  1483.          * No, not a UNICODE DLL.  We must convert from UNICODE to
  1484.          * ANSI first.  NULL text cases must be handled properly.
  1485.          */
  1486.         if (npc->text) {
  1487.             WideCharToMultiByte(CP_ACP, 0, npc->text, -1, szTextA, CCHTEXTMAX,
  1488.                     NULL, &fDefCharUsed);
  1489.             pszTextA = szTextA;
  1490.         }
  1491.         else {
  1492.             pszTextA = NULL;
  1493.         }
  1494.  
  1495.         x = ((LPFNCCSIZETOTEXTA)(*npc->pwcd->lpfnSizeToText))
  1496.                 (npc->flStyle, npc->flExtStyle, gcd.hFont, pszTextA);
  1497.     }
  1498.  
  1499.     /*
  1500.      * Did the call to the DLL fail?
  1501.      */
  1502.     if (x == -1)
  1503.         return -1;
  1504.  
  1505.     /*
  1506.      * Convert the size in pixels to a size in Dialog Units.  Be sure
  1507.      * that we round any fraction up to the next higher DU.  Since
  1508.      * we know how wide the control must be to fit the text, we must
  1509.      * be sure that the size does not get rounded down below this
  1510.      * value when converting to DU's.
  1511.      */
  1512.     xDU = MulDiv(x, 4, gcd.cxChar);
  1513.     if (MulDiv(xDU, gcd.cxChar, 4) != x)
  1514.         xDU++;
  1515.  
  1516.     return xDU;
  1517. }
  1518.  
  1519.  
  1520.  
  1521. /************************************************************************
  1522. * ReadCustomProfile
  1523. *
  1524. *
  1525. * History:
  1526. *
  1527. ************************************************************************/
  1528.  
  1529. VOID ReadCustomProfile(VOID)
  1530. {
  1531.     TCHAR szBuf[CCHTEXTMAX];
  1532.     TCHAR szBuf2[CCHTEXTMAX];
  1533.     LPTSTR pszKey;
  1534.  
  1535.     GetPrivateProfileString(szCustomDLL, NULL, szEmpty,
  1536.             szBuf, CCHTEXTMAX, ids(IDS_DLGEDITINI));
  1537.  
  1538.     /*
  1539.      * Get the file name for each custom control DLL and load it.
  1540.      */
  1541.     for (pszKey = szBuf; *pszKey; pszKey += lstrlen(pszKey) + 1) {
  1542.         if (GetPrivateProfileString(szCustomDLL, pszKey, szEmpty,
  1543.                 szBuf2, CCHTEXTMAX, ids(IDS_DLGEDITINI)))
  1544.             OpenDLLFile(szBuf2);
  1545.     }
  1546. }
  1547.  
  1548.  
  1549.  
  1550. /************************************************************************
  1551. * WriteCustomProfile
  1552. *
  1553. *
  1554. * History:
  1555. *
  1556. ************************************************************************/
  1557.  
  1558. VOID WriteCustomProfile(VOID)
  1559. {
  1560.     PCUSTLINK pcl;
  1561.     PCUSTLINK pcl2;
  1562.     BOOL fSecond;
  1563.  
  1564.     /*
  1565.      * Clear out the section.
  1566.      */
  1567.     WritePrivateProfileString(szCustomDLL, NULL, NULL, ids(IDS_DLGEDITINI));
  1568.  
  1569.     for (pcl = gpclHead; pcl; pcl = pcl->pclNext) {
  1570.         /*
  1571.          * Only write out installed DLL's, not emulated controls.
  1572.          */
  1573.         if (pcl->pszFileName) {
  1574.             /*
  1575.              * Before writing out the path to the DLL, be sure
  1576.              * that this DLL's path has not been written out
  1577.              * already.  This would only occur if they have
  1578.              * multiple control types within the DLL.
  1579.              */
  1580.             for (pcl2 = gpclHead, fSecond = FALSE;
  1581.                     pcl2 && pcl2 != pcl; pcl2 = pcl2->pclNext) {
  1582.                 if (lstrcmpi(pcl2->pszFileName, pcl->pszFileName) == 0) {
  1583.                     fSecond = TRUE;
  1584.                     break;
  1585.                 }
  1586.             }
  1587.  
  1588.             if (!fSecond)
  1589.                 WritePrivateProfileString(szCustomDLL, pcl->pwcd->pszClass,
  1590.                         pcl->pszFileName, ids(IDS_DLGEDITINI));
  1591.         }
  1592.     }
  1593. }
  1594.