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 / menu.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  25KB  |  873 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: menu.c
  14. *
  15. * Contains the main menu switching functions and the clipboard functions.
  16. *
  17. * Functions:
  18. *   DialogMenu()
  19. *   LoadMenuBitmaps()
  20. *   FreeMenuBitmaps()
  21. *   InitMenu()
  22. *   MsgFilterHookFunc()
  23. *   ShowHelp()
  24. *   CopyToClipboard()
  25. *   DlgInClipboard()
  26. *   PasteFromClipboard()
  27. *   GetHelpContext()
  28. *
  29. * Comments:
  30. *
  31. ****************************************************************************/
  32.  
  33. #include "dlgedit.h"
  34. #include "dlgfuncs.h"
  35. #include "dlgextrn.h"
  36. #include "dialogs.h"
  37.  
  38. #include <string.h>
  39.  
  40.  
  41. #define MM10PERINCH         254         // Tenths of a millimeter per inch.
  42.  
  43. typedef struct {
  44.     WORD idm;
  45.     INT idbm;
  46.     HBITMAP hbm;
  47. } BITMAPMENU;
  48.  
  49.  
  50. STATICFN VOID CopyToClipboard(VOID);
  51. STATICFN BOOL DlgInClipboard(VOID);
  52. STATICFN VOID PasteFromClipboard(VOID);
  53. STATICFN INT GetHelpContext(INT idSubject, PHELPMAP phmap);
  54.  
  55.  
  56. static BITMAPMENU bmpmenuTable[] = {
  57.     {MENU_ALIGNLEFT,        IDBM_ALEFT,         NULL },
  58.     {MENU_ALIGNVERT,        IDBM_AVERT,         NULL },
  59.     {MENU_ALIGNRIGHT,       IDBM_ARIGHT,        NULL },
  60.     {MENU_ALIGNTOP,         IDBM_ATOP,          NULL },
  61.     {MENU_ALIGNHORZ,        IDBM_AHORZ,         NULL },
  62.     {MENU_ALIGNBOTTOM,      IDBM_ABOTTOM,       NULL },
  63.     {MENU_SPACEVERT,        IDBM_ASPCVERT,      NULL },
  64.     {MENU_SPACEHORZ,        IDBM_ASPCHORZ,      NULL },
  65.     {MENU_ARRSIZEWIDTH,     IDBM_ASZWIDTH,      NULL },
  66.     {MENU_ARRSIZEHEIGHT,    IDBM_ASZHGHT,       NULL },
  67.     {MENU_ARRPUSHBOTTOM,    IDBM_APBBOTTM,      NULL },
  68.     {MENU_ARRPUSHRIGHT,     IDBM_APBRIGHT,      NULL }
  69. };
  70.  
  71.  
  72.  
  73. /************************************************************************
  74. * DialogMenu
  75. *
  76. * This is the main switching function to send menu commands to the
  77. * appropriate function.
  78. *
  79. * Arguments:
  80. *   INT - the menu command
  81. *
  82. ************************************************************************/
  83.  
  84. VOID DialogMenu(
  85.     INT cmd)
  86. {
  87.     /*
  88.      * Be sure any outstanding changes get applied without errors.
  89.      */
  90.     if (!StatusApplyChanges())
  91.         return;
  92.  
  93.     switch (cmd) {
  94.  
  95.         /*
  96.          * File menu ----------------------------------------------------
  97.          */
  98.  
  99.         case MENU_NEWRES:
  100.             if (DoWeSave(FILE_INCLUDE) == IDCANCEL ||
  101.                     DoWeSave(FILE_RESOURCE) == IDCANCEL)
  102.                 break;
  103.  
  104.             FreeInclude();
  105.             FreeRes();
  106.             AddNewDialog();
  107.             ShowFileStatus(TRUE);
  108.             break;
  109.  
  110.         case MENU_OPEN:
  111.             if (DoWeSave(FILE_INCLUDE) == IDCANCEL ||
  112.                     DoWeSave(FILE_RESOURCE) == IDCANCEL)
  113.                 break;
  114.  
  115.             Open(FILE_RESOURCE);
  116.  
  117.             break;
  118.  
  119.         case MENU_SAVE:
  120.             if (gfIncChged) {
  121.                 if (!Save(FILE_NOSHOW | FILE_INCLUDE))
  122.                     break;
  123.             }
  124.  
  125.             if (gfResChged)
  126.                 Save(FILE_NOSHOW | FILE_RESOURCE);
  127.  
  128.             break;
  129.  
  130.         case MENU_SAVEAS:
  131.             /*
  132.              * Save the include file, but only if there is one.
  133.              */
  134.             if (pszIncludeFile || plInclude) {
  135.                 if (!Save(FILE_NOSHOW | FILE_INCLUDE | FILE_SAVEAS))
  136.                     break;
  137.             }
  138.  
  139.             /*
  140.              * Save the resource file.
  141.              */
  142.             Save(FILE_NOSHOW | FILE_RESOURCE | FILE_SAVEAS);
  143.  
  144.             break;
  145.  
  146.         case MENU_NEWCUST:
  147.             DlgBox(DID_NEWCUST, (WNDPROC)NewCustDlgProc);
  148.             break;
  149.  
  150.         case MENU_OPENCUST:
  151.             OpenCustomDialog();
  152.             break;
  153.  
  154.         case MENU_REMCUST:
  155.             DlgBox(DID_REMCUST, (WNDPROC)RemCustDlgProc);
  156.             break;
  157.  
  158.         case MENU_SETINCLUDE:
  159.             if (DoWeSave(FILE_INCLUDE) != IDCANCEL)
  160.                 Open(FILE_INCLUDE);
  161.  
  162.             break;
  163.  
  164.         case MENU_EXIT:
  165.             PostMessage(ghwndMain, WM_CLOSE, 0, 0L);
  166.             break;
  167.  
  168.         /*
  169.          * Edit menu ----------------------------------------------------
  170.          */
  171.  
  172.         case MENU_RESTOREDIALOG:
  173.             RestoreDialog();
  174.             break;
  175.  
  176.         case MENU_CUT:
  177.         case MENU_COPY:
  178.             if (gfEditingDlg) {
  179.                 /*
  180.                  * Save current stuff in clipboard.
  181.                  */
  182.                 CopyToClipboard();
  183.  
  184.                 /*
  185.                  * Clear the selection if they did a "cut" instead of
  186.                  * a "copy".
  187.                  */
  188.                 if (cmd == MENU_CUT)
  189.                     DeleteControl();
  190.             }
  191.  
  192.             break;
  193.  
  194.         case MENU_PASTE:
  195.             PasteFromClipboard();
  196.             break;
  197.  
  198.         case MENU_DELETE:
  199.             DeleteControl();
  200.             break;
  201.  
  202.         case MENU_DUPLICATE:
  203.             Duplicate();
  204.             break;
  205.  
  206.         case MENU_SYMBOLS:
  207.             ViewInclude();
  208.             break;
  209.  
  210.         case MENU_STYLES:
  211.             StylesDialog();
  212.             break;
  213.  
  214.         case MENU_SIZETOTEXT:
  215.             SizeToText();
  216.             break;
  217.  
  218.         case MENU_NEWDIALOG:
  219.             AddNewDialog();
  220.             break;
  221.  
  222.         case MENU_SELECTDIALOG:
  223.             SelectDialogDialog();
  224.             break;
  225.  
  226.         /*
  227.          * Arrange menu -------------------------------------------------
  228.          */
  229.  
  230.         case MENU_ALIGNLEFT:
  231.         case MENU_ALIGNVERT:
  232.         case MENU_ALIGNRIGHT:
  233.         case MENU_ALIGNTOP:
  234.         case MENU_ALIGNHORZ:
  235.         case MENU_ALIGNBOTTOM:
  236.             AlignControls(cmd);
  237.             break;
  238.  
  239.         case MENU_SPACEVERT:
  240.         case MENU_SPACEHORZ:
  241.             ArrangeSpacing(cmd);
  242.             break;
  243.  
  244.         case MENU_ARRSIZEWIDTH:
  245.         case MENU_ARRSIZEHEIGHT:
  246.             ArrangeSize(cmd);
  247.             break;
  248.  
  249.         case MENU_ARRPUSHBOTTOM:
  250.         case MENU_ARRPUSHRIGHT:
  251.             ArrangePushButtons(cmd);
  252.             break;
  253.  
  254.         case MENU_ORDERGROUP:
  255.             OrderGroupDialog();
  256.             break;
  257.  
  258.         case MENU_ARRSETTINGS:
  259.             ArrangeSettingsDialog();
  260.             break;
  261.  
  262.         /*
  263.          * Options menu -------------------------------------------------
  264.          */
  265.  
  266.         case MENU_TESTMODE:
  267.             if (gfTestMode)
  268.                 DestroyTestDialog();
  269.             else
  270.                 CreateTestDialog();
  271.  
  272.             break;
  273.  
  274.         case MENU_HEXMODE:
  275.             /*
  276.              * Flip the flag, and update the status display so that
  277.              * the id value will be displayed in the new format.
  278.              */
  279.             gfHexMode = gfHexMode ? FALSE : TRUE;
  280.             StatusUpdate();
  281.             break;
  282.  
  283.         case MENU_TRANSLATE:
  284.             /*
  285.              * Flip the flag, and set the enable state of the fields
  286.              * in the status window.  Changing the translate mode can
  287.              * effect whether they are allowed to change ids of controls.
  288.              */
  289.             gfTranslateMode = gfTranslateMode ? FALSE : TRUE;
  290.  
  291.             /*
  292.              * If they turned on Translate mode, reset the tool and
  293.              * hide the Toolbox.  Otherwise, show the toolbox if they
  294.              * want it shown.
  295.              */
  296.             if (gfTranslateMode) {
  297.                 ToolboxShow(FALSE);
  298.                 ToolboxSelectTool(W_NOTHING, FALSE);
  299.             }
  300.             else if (gfShowToolbox) {
  301.                 ToolboxShow(TRUE);
  302.             }
  303.  
  304.             StatusSetEnable();
  305.             break;
  306.  
  307.         case MENU_USENEWKEYWORDS:
  308.             /*
  309.              * Flip the flag.
  310.              */
  311.             gfUseNewKeywords = gfUseNewKeywords ? FALSE : TRUE;
  312.             break;
  313.  
  314.         case MENU_SHOWTOOLBOX:
  315.             /*
  316.              * Toggle the state of the Toolbox.
  317.              */
  318.             gfShowToolbox = gfShowToolbox ? FALSE : TRUE;
  319.             ToolboxShow(gfShowToolbox);
  320.  
  321.             break;
  322.  
  323.         /*
  324.          * Help menu ----------------------------------------------------
  325.          */
  326.  
  327.         case MENU_CONTENTS:
  328.             WinHelp(ghwndMain, gszHelpFile, HELP_CONTENTS, 0L);
  329.             break;
  330.  
  331.         case MENU_SEARCH:
  332.             /*
  333.              * Tell winhelp to be sure this app's help file is current,
  334.              * then invoke a search with an empty starting key.
  335.              */
  336.             WinHelp(ghwndMain, gszHelpFile, HELP_FORCEFILE, 0);
  337.             WinHelp(ghwndMain, gszHelpFile, HELP_PARTIALKEY, (DWORD)szEmpty);
  338.             break;
  339.  
  340.         case MENU_ABOUT:
  341.             DlgBox(DID_ABOUT, (WNDPROC)AboutDlgProc);
  342.             break;
  343.  
  344.         /*
  345.          * Hidden menu commands (accessed by accelerators) --------------
  346.          */
  347.  
  348.         case MENU_HIDDEN_TOTOOLBOX:
  349.             if (ghwndToolbox && IsWindowVisible(ghwndToolbox))
  350.                 SetFocus(ghwndToolbox);
  351.  
  352.             break;
  353.  
  354.         case MENU_HIDDEN_TOPROPBAR:
  355.             SetFocus(hwndStatus);
  356.             break;
  357.     }
  358. }
  359.  
  360.  
  361.  
  362. /************************************************************************
  363. * LoadMenuBitmaps
  364. *
  365. * This function loads and inserts the menu items that are bitmaps.
  366. * This has to be done at runtime because windows does not have a
  367. * way to specify bitmap menu items in the rc file.
  368. *
  369. * Arguments:
  370. *   HMENU hMenu - The menu handle.
  371. *
  372. ************************************************************************/
  373.  
  374. VOID LoadMenuBitmaps(
  375.     HMENU hMenu)
  376. {
  377.     INT i;
  378.  
  379.     for (i = 0; i < sizeof(bmpmenuTable) / sizeof(BITMAPMENU); i++) {
  380.         bmpmenuTable[i].hbm =
  381.                 LoadBitmap(ghInst, MAKEINTRESOURCE(bmpmenuTable[i].idbm));
  382.  
  383.         ModifyMenu(hMenu, bmpmenuTable[i].idm,
  384.                 MF_BYCOMMAND | MF_BITMAP, bmpmenuTable[i].idm,
  385.                 (LPTSTR)(DWORD)bmpmenuTable[i].hbm);
  386.     }
  387. }
  388.  
  389.  
  390.  
  391. /************************************************************************
  392. * FreeMenuBitmaps
  393. *
  394. * This function frees the menu bitmaps that were loaded by
  395. * LoadMenuBitmaps.  This function should be called only when
  396. * the application is exiting, because it frees the bitmaps
  397. * without removing them from the menu first.
  398. *
  399. ************************************************************************/
  400.  
  401. VOID FreeMenuBitmaps(VOID)
  402. {
  403.     INT i;
  404.  
  405.     for (i = 0; i < sizeof(bmpmenuTable) / sizeof(BITMAPMENU); i++)
  406.         if (bmpmenuTable[i].hbm)
  407.             DeleteObject(bmpmenuTable[i].hbm);
  408. }
  409.  
  410.  
  411.  
  412. /************************************************************************
  413. * InitMenu
  414. *
  415. * This function grays/enables and checks/unchecks the menu items
  416. * appropriately for the given state.
  417. *
  418. * Arguments:
  419. *   HMENU hMenu - The menu handle.
  420. *
  421. ************************************************************************/
  422.  
  423. VOID InitMenu(
  424.     HMENU hMenu)
  425. {
  426.     register INT i;
  427.     BOOL fEnable;
  428.     NPCTYPE npc;
  429.     HMENU hMenuArrange;
  430.  
  431.     MyEnableMenuItem(hMenu, MENU_NEWRES, !gfTranslateMode);
  432.  
  433.     MyEnableMenuItem(hMenu, MENU_SAVE,
  434.             (gfEditingDlg || gprlHead) && (gfResChged || gfIncChged));
  435.  
  436.     MyEnableMenuItem(hMenu, MENU_SAVEAS, gfEditingDlg || gprlHead);
  437.  
  438.     MyEnableMenuItem(hMenu, MENU_SETINCLUDE,
  439.             (gfEditingDlg || gprlHead) && !gfTranslateMode);
  440.  
  441.     MyEnableMenuItem(hMenu, MENU_REMCUST, gpclHead);
  442.  
  443.     MyEnableMenuItem(hMenu, MENU_RESTOREDIALOG, gfDlgChanged && gcd.prl);
  444.  
  445.     MyEnableMenuItem(hMenu, MENU_CUT,
  446.             gnpcSel && gfEditingDlg && !gfTranslateMode);
  447.  
  448.     MyEnableMenuItem(hMenu, MENU_COPY, gnpcSel && gfEditingDlg);
  449.  
  450.     MyEnableMenuItem(hMenu, MENU_PASTE, !gfTranslateMode &&
  451.             IsClipboardFormatAvailable(fmtDlg) &&
  452.             (gfEditingDlg || DlgInClipboard()));
  453.  
  454.     MyEnableMenuItem(hMenu, MENU_DELETE, gnpcSel && !gfTranslateMode);
  455.  
  456.     MyEnableMenuItem(hMenu, MENU_DUPLICATE, gnpcSel && !gfTranslateMode);
  457.  
  458.     MyEnableMenuItem(hMenu, MENU_SYMBOLS,
  459.             (gfEditingDlg || gprlHead) && !gfTranslateMode);
  460.  
  461.     MyEnableMenuItem(hMenu, MENU_STYLES, gnpcSel && !gfTranslateMode);
  462.  
  463.     /*
  464.      * For the "Size to text" menu command to be enabled, there
  465.      * must be at least one control selected, and one of the
  466.      * controls selected has to be able to be sized to its text.
  467.      */
  468.     fEnable = FALSE;
  469.     if (gcSelected) {
  470.         for (npc = npcHead; npc; npc = npc->npcNext) {
  471.             if (npc->fSelected && npc->pwcd->fSizeToText) {
  472.                 fEnable = TRUE;
  473.                 break;
  474.             }
  475.         }
  476.     }
  477.  
  478.     MyEnableMenuItem(hMenu, MENU_SIZETOTEXT, fEnable);
  479.  
  480.     MyEnableMenuItem(hMenu, MENU_NEWDIALOG, !gfTranslateMode);
  481.  
  482.     MyEnableMenuItem(hMenu, MENU_SELECTDIALOG, gfEditingDlg || gprlHead);
  483.  
  484.     hMenuArrange = GetSubMenu(hMenu, MENUPOS_ARRANGE);
  485.  
  486.     MyEnableMenuItemByPos(hMenuArrange, MENUPOS_ARRANGEALIGN, gcSelected > 1);
  487.  
  488.     MyEnableMenuItemByPos(hMenuArrange, MENUPOS_ARRANGESPACE, gcSelected > 1);
  489.  
  490.     /*
  491.      * For the "Same size" menu option to be enabled, there
  492.      * must be more than one control selected, and they
  493.      * must be sizeable controls.
  494.      */
  495.     fEnable = FALSE;
  496.     if (gcSelected > 1) {
  497.         for (i = 0, npc = npcHead; npc; npc = npc->npcNext) {
  498.             if (npc->fSelected && npc->pwcd->fSizeable) {
  499.                 i++;
  500.  
  501.                 if (i > 1) {
  502.                     fEnable = TRUE;
  503.                     break;
  504.                 }
  505.             }
  506.         }
  507.     }
  508.  
  509.     MyEnableMenuItemByPos(hMenuArrange, MENUPOS_ARRANGESIZE, fEnable);
  510.  
  511.     /*
  512.      * For the Arrange/Push buttons menu item to be enabled,
  513.      * there must be a dialog up and it must have at least one
  514.      * push button.  In addition, if there are control(s) other
  515.      * than the dialog selected, at least one of the selected
  516.      * controls must be a push button.
  517.      */
  518.     fEnable = FALSE;
  519.     if (gfEditingDlg || gprlHead) {
  520.         if (!gcSelected || gfDlgSelected) {
  521.             for (npc = npcHead; npc; npc = npc->npcNext) {
  522.                 if (npc->pwcd->iType == W_PUSHBUTTON) {
  523.                     fEnable = TRUE;
  524.                     break;
  525.                 }
  526.             }
  527.         }
  528.         else {
  529.             for (npc = npcHead; npc; npc = npc->npcNext) {
  530.                 if (npc->pwcd->iType == W_PUSHBUTTON && npc->fSelected) {
  531.                     fEnable = TRUE;
  532.                     break;
  533.                 }
  534.             }
  535.         }
  536.     }
  537.  
  538.     MyEnableMenuItemByPos(hMenuArrange, MENUPOS_ARRANGEPUSH, fEnable);
  539.  
  540.     MyEnableMenuItem(hMenu, MENU_ORDERGROUP,
  541.             npcHead && !gfTranslateMode && !gfTestMode && cWindows > 1);
  542.  
  543.     MyEnableMenuItem(hMenu, MENU_TESTMODE, gfEditingDlg);
  544.     MyCheckMenuItem(hMenu, MENU_TESTMODE, gfTestMode);
  545.  
  546.     MyEnableMenuItem(hMenu, MENU_HEXMODE, !gfTestMode);
  547.     MyCheckMenuItem(hMenu, MENU_HEXMODE, gfHexMode);
  548.  
  549.     MyEnableMenuItem(hMenu, MENU_TRANSLATE, !gfTestMode);
  550.     MyCheckMenuItem(hMenu, MENU_TRANSLATE, gfTranslateMode);
  551.  
  552.     MyEnableMenuItem(hMenu, MENU_USENEWKEYWORDS, !gfTestMode);
  553.     MyCheckMenuItem(hMenu, MENU_USENEWKEYWORDS, gfUseNewKeywords);
  554.  
  555.     MyEnableMenuItem(hMenu, MENU_SHOWTOOLBOX, !gfTestMode && !gfTranslateMode);
  556.     MyCheckMenuItem(hMenu, MENU_SHOWTOOLBOX, gfShowToolbox);
  557. }
  558.  
  559.  
  560.  
  561. /************************************************************************
  562. * CopyToClipboard
  563. *
  564. * Puts the current dialog and a bitmap image of it into the clipboard.
  565. * Gives a dialog box resource to the Clipboard.
  566. * Gives a bit map to the clipboard.
  567. * Clears everything else out of clipboard.
  568. *
  569. ************************************************************************/
  570.  
  571. STATICFN VOID CopyToClipboard(VOID)
  572. {
  573.     INT cbRes;
  574.     HANDLE hResClip;
  575.     PRES lpRes;
  576.     PRES pRes;
  577.     HDC hdcSrc;
  578.     HDC hdcDst;
  579.     RECT rc;
  580.     HBITMAP hbm;
  581.  
  582.     /*
  583.      * Store the current selection in a dialog resource.
  584.      */
  585.     if (!(pRes = AllocDialogResource(FALSE, TRUE)))
  586.         return;
  587.  
  588.     /*
  589.      * Allocate global memory for it.
  590.      */
  591.     cbRes = ResourceSize(pRes);
  592.     if (!cbRes || !(hResClip = GlobalAlloc(GHND | GMEM_DDESHARE, cbRes))) {
  593.         MyFree(pRes);
  594.         Message(MSG_OUTOFMEMORY);
  595.         return;
  596.     }
  597.  
  598.     /*
  599.      * Copy it to the global memory.
  600.      */
  601.     lpRes = (PRES)GlobalLock(hResClip);
  602.     memcpy(lpRes, pRes, cbRes);
  603.     GlobalUnlock(hResClip);
  604.     MyFree(pRes);
  605.  
  606.     /*
  607.      * Now place it in the clipboard.
  608.      */
  609.     if (OpenClipboard(ghwndMain)) {
  610.         EmptyClipboard();
  611.         SetClipboardData(fmtDlg, hResClip);
  612.  
  613.         /*
  614.          * If the dialog is selected, place a bitmap image of it
  615.          * in the clipboard also.  The drag handles will be removed
  616.          * first and the dialog will be activated so that the
  617.          * image looks proper.
  618.          */
  619.         if (gfDlgSelected) {
  620.             CancelSelection(FALSE);
  621.             SetActiveWindow(gcd.npc->hwnd);
  622.             UpdateWindow(gcd.npc->hwnd);
  623.  
  624.             if (hdcSrc = GetDC(NULL)) {
  625.                 GetWindowRect(gcd.npc->hwnd, &rc);
  626.                 if (hbm = CreateCompatibleBitmap(hdcSrc,
  627.                         rc.right - rc.left, rc.bottom - rc.top)) {
  628.                     if (hdcDst = CreateCompatibleDC(hdcSrc)) {
  629.                         /*
  630.                          * Calculate the dimensions of the bitmap and
  631.                          * convert them to tenths of a millimeter for
  632.                          * setting the size with the SetBitmapDimensionEx
  633.                          * call.  This allows programs like WinWord to
  634.                          * retrieve the bitmap and know what size to
  635.                          * display it as.
  636.                          */
  637.                         SetBitmapDimensionEx(hbm,
  638.                                 ((rc.right - rc.left) * MM10PERINCH) /
  639.                                 GetDeviceCaps(hdcSrc, LOGPIXELSX),
  640.                                 ((rc.bottom - rc.top) * MM10PERINCH) /
  641.                                 GetDeviceCaps(hdcSrc, LOGPIXELSY),
  642.                                 NULL);
  643.  
  644.                         SelectObject(hdcDst, hbm);
  645.                         BitBlt(hdcDst, 0, 0,
  646.                                 rc.right - rc.left, rc.bottom - rc.top,
  647.                                 hdcSrc, rc.left, rc.top, SRCCOPY);
  648.                         DeleteDC(hdcDst);
  649.                         SetClipboardData(CF_BITMAP, hbm);
  650.                     }
  651.                     else {
  652.                         DeleteObject(hbm);
  653.                     }
  654.                 }
  655.  
  656.                 ReleaseDC(NULL, hdcSrc);
  657.             }
  658.  
  659.             SetActiveWindow(ghwndMain);
  660.             SelectControl(gcd.npc, FALSE);
  661.         }
  662.  
  663.         CloseClipboard();
  664.     }
  665.     else {
  666.         Message(MSG_NOCLIP);
  667.     }
  668. }
  669.  
  670.  
  671.  
  672. /************************************************************************
  673. * DlgInClipboard
  674. *
  675. * This function returns TRUE if there is data in the clipboard in the
  676. * dialog format, and this data is for a complete dialog, not just for
  677. * a group of controls.
  678. *
  679. ************************************************************************/
  680.  
  681. STATICFN BOOL DlgInClipboard(VOID)
  682. {
  683.     HANDLE hClip;
  684.     PRES pRes;
  685.     PDIALOGBOXHEADER pdbh;
  686.     BOOL fDlgResFound = FALSE;
  687.  
  688.     if (!OpenClipboard(ghwndMain))
  689.         return FALSE;
  690.  
  691.     if (hClip = GetClipboardData(fmtDlg)) {
  692.         pRes = (PRES)GlobalLock(hClip);
  693.  
  694.         /*
  695.          * If cx is CONTROLS_ONLY, then we know that we only
  696.          * want to copy the controls in the template, not the
  697.          * entire dialog plus controls.
  698.          */
  699.         pdbh = (PDIALOGBOXHEADER)SkipResHeader(pRes);
  700.         if (pdbh->cx != CONTROLS_ONLY)
  701.             fDlgResFound = TRUE;
  702.  
  703.         GlobalUnlock(hClip);
  704.     }
  705.  
  706.     CloseClipboard();
  707.  
  708.     return fDlgResFound;
  709. }
  710.  
  711.  
  712.  
  713. /************************************************************************
  714. * PasteFromClipboard
  715. *
  716. * This routine pastes any data from the clipboard into the current
  717. * resource file.  If the data represents a complete dialog, a new dialog
  718. * is added.  If it represents some controls, the operation to drop them
  719. * into the current dialog is begun.
  720. *
  721. ************************************************************************/
  722.  
  723. STATICFN VOID PasteFromClipboard(VOID)
  724. {
  725.     HANDLE hClip;
  726.     PRES pResClip;
  727.     PRES pResCopy;
  728.     INT cbRes;
  729.  
  730.     if (!OpenClipboard(ghwndMain)) {
  731.         Message(MSG_NOCLIP);
  732.         return;
  733.     }
  734.  
  735.     if (hClip = GetClipboardData(fmtDlg)) {
  736.         pResClip = (PRES)GlobalLock(hClip);
  737.         cbRes = ResourceSize(pResClip);
  738.  
  739.         /*
  740.          * Make a copy of the clipboard data.  This needs to be done
  741.          * because we may need to drag the new controls for a while,
  742.          * and it is rude to leave the clipboard open that long.
  743.          */
  744.         if (pResCopy = (PRES)MyAlloc(cbRes)) {
  745.             memcpy((PBYTE)pResCopy, (PBYTE)pResClip, cbRes);
  746.  
  747.             /*
  748.              * Now duplicate the dialog or controls in the clipboard.
  749.              * The pResCopy buffer does NOT need to be freed here, because
  750.              * it will be freed after the drag operation is complete.
  751.              */
  752.             MakeCopyFromRes(pResCopy);
  753.         }
  754.  
  755.         GlobalUnlock(hClip);
  756.     }
  757.  
  758.     CloseClipboard();
  759. }
  760.  
  761.  
  762.  
  763. /************************************************************************
  764. * MsgFilterHookFunc
  765. *
  766. * This is the exported message filter function that is hooked into
  767. * the message stream for detecting the pressing of the F1 key, at
  768. * which time it calls up the appropriate help.
  769. *
  770. ************************************************************************/
  771.  
  772. BOOL APIENTRY MsgFilterHookFunc(
  773.     INT nCode,
  774.     WPARAM wParam,
  775.     LPMSG lpMsg)
  776. {
  777.     if ((nCode == MSGF_MENU || nCode == MSGF_DIALOGBOX) &&
  778.             (lpMsg->message == WM_KEYDOWN && lpMsg->wParam == VK_F1)) {
  779.         /*
  780.          * Display help.
  781.          */
  782.         ShowHelp((nCode == MSGF_MENU) ? TRUE : FALSE);
  783.  
  784.         /*
  785.          * Tell Windows to swallow this message.
  786.          */
  787.         return 1;
  788.     }
  789.  
  790.     return CallNextHookEx(ghhkMsgFilter, nCode, wParam, (LONG)lpMsg);
  791. }
  792.  
  793.  
  794.  
  795. /************************************************************************
  796. * ShowHelp
  797. *
  798. * This function is called when the user has requested help.  It will
  799. * look at the menu state (if fMenuHelp is TRUE) or which dialog
  800. * is currently up to determine the help topic, then it calls WinHelp.
  801. *
  802. * Arguments:
  803. *   BOOL fMenuHelp - TRUE if this help is for a menu (help was requested
  804. *                    in the menu modal loop).  If FALSE, general help
  805. *                    or help for a dialog is assumed.
  806. *
  807. ************************************************************************/
  808.  
  809. VOID ShowHelp(
  810.     BOOL fMenuHelp)
  811. {
  812.     INT nHelpContext = 0;
  813.     HWND hwndFocus;
  814.  
  815.     if (fMenuHelp) {
  816.         nHelpContext = GetHelpContext(gMenuSelected, gahmapMenu);
  817.     }
  818.     else {
  819.         /*
  820.          * Look for help for the current dialog.
  821.          */
  822.         if (gidCurrentDlg) {
  823.             nHelpContext = GetHelpContext(gidCurrentDlg, gahmapDialog);
  824.         }
  825.         else {
  826.             /*
  827.              * There is no current dialog.  Is the window with the
  828.              * focus a control on the Properties Bar?
  829.              */
  830.             if ((hwndFocus = GetFocus()) && IsChild(hwndStatus, hwndFocus))
  831.                 nHelpContext = GetHelpContext(DID_STATUS, gahmapDialog);
  832.         }
  833.     }
  834.  
  835.     /*
  836.      * If there is help context, display it.  Otherwise display
  837.      * the Contents screen.
  838.      */
  839.     if (nHelpContext)
  840.         WinHelp(ghwndMain, gszHelpFile, HELP_CONTEXT, nHelpContext);
  841.     else
  842.         WinHelp(ghwndMain, gszHelpFile, HELP_CONTENTS, 0L);
  843. }
  844.  
  845.  
  846.  
  847. /************************************************************************
  848. * GetHelpContext
  849. *
  850. * This function takes a subject and returns its matching help
  851. * context id from the given HELPMAP table.
  852. *
  853. * Arguments:
  854. *   INT idSubject   - ID of the subject to find the help context for.
  855. *   PHELPMAP phmap  - The help map table.  It is assumed that the
  856. *                     last entry in the table has a NULL subject id.
  857. *
  858. ************************************************************************/
  859.  
  860. STATICFN INT GetHelpContext(
  861.     INT idSubject,
  862.     PHELPMAP phmap)
  863. {
  864.     while (phmap->idSubject) {
  865.         if (phmap->idSubject == idSubject)
  866.             return phmap->HelpContext;
  867.  
  868.         phmap++;
  869.     }
  870.  
  871.     return 0;
  872. }
  873.