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

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