home *** CD-ROM | disk | FTP | other *** search
/ ActiveX Programming Unleashed CD / AXU.iso / source / chap18 / doserver / mfcbind.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-02  |  9.7 KB  |  335 lines

  1. // mfcbind.cpp : Example of Binder-compatible utility functions
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. //BINDER:
  14. //    This module contains functions specific to Binder support.
  15. //  The code here is used to add special registry entries used by
  16. //    Binder-Compatible DocObjects, in addition to registering
  17. //    the standard entries generated by the MFC libraries.
  18. //
  19. //    The following keys are written only if no existing entries 
  20. //    are found:
  21. //        HKEY_CLASSES_ROOT\<ProgID>\DocObject
  22. //        HKEY_CLASSES_ROOT\CLSID\<clsid>\DocObject
  23. //        HKEY_CLASSES_ROOT\CLSID\<clsid>\Printable
  24. //
  25. //    The following keys will overwrite any existing values:
  26. //        HKEY_CLASSES_ROOT\CLSID\<clsid>\DefaultExtension
  27. //BINDER_END
  28.  
  29. #include "stdafx.h"
  30. #include "mfcbind.h"
  31. #include <afxpriv.h>    // for conversion helpers
  32.  
  33. #ifdef _DEBUG
  34. #undef THIS_FILE
  35. static char BASED_CODE THIS_FILE[] = __FILE__;
  36. #endif
  37.  
  38. //////////////////////////////////////////////////////////////////////////////
  39. // data for MfcBinderUpdateRegistry functionality
  40. //       %1 = Class ID, formatted as a string
  41. //       %2 = ProgID
  42. //       %3 = Document file extension
  43. //       %4 = Document filter name displayed in File Open dialog
  44. //
  45. static const TCHAR szCLSIDDocObject[] = 
  46.    _T("CLSID\\%1\\DocObject\0" _T("0"));
  47. static const TCHAR szProgIDDocObject[] = 
  48.    _T("%2\\DocObject\0" _T("0"));
  49. static const TCHAR szPrintable[] = 
  50.    _T("CLSID\\%1\\Printable\0");
  51. static const TCHAR szDefaultExt[] = 
  52.    _T("CLSID\\%1\\DefaultExtension\0%3,%4");
  53.  
  54. static const LPCTSTR rglpszBindRegister[] =
  55. {
  56.    szCLSIDDocObject, szProgIDDocObject, szPrintable, NULL
  57. };
  58.  
  59. static const LPCTSTR rglpszBindOverwrite[] =
  60. {
  61.     szDefaultExt, NULL
  62. };
  63.                  
  64. void MfcBinderUpdateRegistry(const CDocTemplate* pDocTemplate, 
  65.                            OLE_APPTYPE nAppType, 
  66.                            LPCTSTR* rglpszRegister,
  67.                            LPCTSTR* rglpszOverwrite)
  68. {
  69.     USES_CONVERSION;
  70.     ASSERT(pDocTemplate != NULL);
  71.  
  72.     // Find the COleTemplateServer associated with the document 
  73.     // template
  74.     COleTemplateServer* pServer = 
  75.         (COleTemplateServer*)pDocTemplate->m_pAttachedFactory;
  76.  
  77.     if (pServer == NULL)
  78.         return;
  79.  
  80.     // Do the normal registration for an OLE document type
  81.     pServer->UpdateRegistry(nAppType, rglpszRegister, rglpszOverwrite);
  82.  
  83.     // Retrieve the values needed for the Binder-Compatible
  84.     // registry entries. 
  85.     CString strProgID;
  86.     CString strFilterName;
  87.     CString strFilterExt;
  88.  
  89.     TRY
  90.     {
  91.         if (!pDocTemplate->GetDocString(strProgID, CDocTemplate::regFileTypeId) || 
  92.             strProgID.IsEmpty())
  93.         {
  94.             AfxThrowUserException();
  95.         }
  96.  
  97.         if (!pDocTemplate->GetDocString(strFilterName, CDocTemplate::filterName) || 
  98.             strFilterName.IsEmpty())
  99.         {
  100.             AfxThrowUserException();
  101.         }
  102.         
  103.         if (!pDocTemplate->GetDocString(strFilterExt, CDocTemplate::filterExt) ||
  104.            strFilterExt.IsEmpty())
  105.         {
  106.             AfxThrowUserException();
  107.         }
  108.     }
  109.     CATCH(CResourceException, pEx)
  110.     {
  111.         TRACE0("Error: not enough information in DocTemplate to"
  112.             " register Binder-compatible document\n");
  113.         return;
  114.     }
  115.     END_CATCH
  116.  
  117.     LPOLESTR lpszClassID;
  118.     ::StringFromCLSID(pServer->GetClassID(), &lpszClassID);
  119.     if (lpszClassID == NULL)
  120.     {
  121.         TRACE0("Error: Could not generate CLSID in MfcBinderUpdateRegistry\n");
  122.         return;
  123.     }
  124.  
  125.     // Use the helper function AfxOleRegisterHelp() to add the 
  126.     // Binder-Compatible entries to the registry.
  127.     LPCTSTR rglpszSymbols[4];
  128.     rglpszSymbols[0] = OLE2T(lpszClassID);
  129.     rglpszSymbols[1] = strProgID;
  130.     rglpszSymbols[2] = strFilterExt;
  131.     rglpszSymbols[3] = strFilterName;
  132.  
  133.     BOOL bResult;
  134.     bResult = AfxOleRegisterHelper((LPCTSTR*)rglpszBindRegister, 
  135.                                    rglpszSymbols, 
  136.                                    sizeof(rglpszSymbols)/sizeof(LPCTSTR), 
  137.                                    FALSE);
  138.     if (bResult)
  139.         bResult = AfxOleRegisterHelper((LPCTSTR*)rglpszBindOverwrite, 
  140.                                        rglpszSymbols, 
  141.                                        sizeof(rglpszSymbols)/sizeof(LPCTSTR), 
  142.                                        TRUE);
  143.  
  144.     // free memory for class ID
  145.     ASSERT(lpszClassID != NULL);
  146.     AfxFreeTaskMem(lpszClassID);
  147.  
  148.     if (!bResult)
  149.         AfxMessageBox(BIND_IDP_FAILED_TO_AUTO_REGISTER);
  150. }
  151.  
  152. HMENU MfcBinderMergeMenus(CMenu* pMenuShared, CMenu* pMenuSource,
  153.                         LONG* lpMenuWidths, int iWidthIndex)
  154. {
  155.     BOOL  bHelpMergedAsSubMenu = FALSE;
  156.     HMENU hMenuHelpSubMenu = NULL;
  157.  
  158.     // copy the popups from the pMenuSource
  159.     int cMenuItems = pMenuSource->GetMenuItemCount();
  160.     int cGroupWidth = 0; // number of items in current group
  161.     int nPosition = 0;   // position in shared menu
  162.  
  163.     // insert at appropriate spot depending on iWidthIndex
  164.     ASSERT(iWidthIndex == 0 || iWidthIndex == 1);
  165.     if (iWidthIndex == 1)
  166.         nPosition = (int)lpMenuWidths[0];
  167.     
  168.     int nItem;
  169.     for (nItem = 0; nItem < cMenuItems; nItem++)
  170.     {
  171.         // get the HMENU of the popup
  172.         HMENU hMenuPopup = ::GetSubMenu(pMenuSource->m_hMenu, nItem);
  173.  
  174.         // separators move us to next group
  175.         UINT state = pMenuSource->GetMenuState(nItem, MF_BYPOSITION);
  176.         if (hMenuPopup == NULL && (state & MF_SEPARATOR) != 0)
  177.         {
  178.             ASSERT(iWidthIndex <= 5);   // servers should not touch past 5
  179.             lpMenuWidths[iWidthIndex] += cGroupWidth;
  180.             cGroupWidth = 0;
  181.             if (iWidthIndex < 5)
  182.                 nPosition += (int)lpMenuWidths[iWidthIndex+1];
  183.             iWidthIndex += 2;
  184.         }
  185.         else
  186.         {
  187.             CMenu* pMenuHelp = NULL;
  188.             // first check whether this is the Help group
  189.             if (iWidthIndex == 5)
  190.             {
  191.                 // if so, check to see if container has Help menu items
  192.                 if (lpMenuWidths[iWidthIndex] == 1)
  193.                 {
  194.                     // Get the container's Help menu
  195.                     pMenuHelp = pMenuShared->GetSubMenu(nPosition);
  196.                 }
  197.             }
  198.  
  199.             // get the menu item text
  200.             CString strItemText;
  201.             int nLen = pMenuSource->GetMenuString(nItem, strItemText, MF_BYPOSITION);
  202.  
  203.             // popups are handled differently than normal menu items
  204.             if (hMenuPopup != NULL)
  205.             {
  206.                 if (::GetMenuItemCount(hMenuPopup) != 0)
  207.                 {
  208.                     // strip the HIBYTE because it contains a count of items
  209.                     state = LOBYTE(state) | MF_POPUP;   // must be popup
  210.  
  211.                     // non-empty popup -- add it to the shared menu bar
  212.                     if (pMenuHelp != NULL)
  213.                     {
  214.                         // Container has help items - add as submenu
  215.                         // Name of our help menu should indicate the server
  216.                         CString strObjHelp(AfxGetAppName());
  217.                         strObjHelp += ' ';
  218.  
  219.                         // add item name, skipping ampersands
  220.                         int nChar;
  221.                         for (nChar = 0; nChar < nLen; nChar++)
  222.                             if (strItemText[nChar] != '&')
  223.                                 strObjHelp += strItemText[nChar];
  224.  
  225.                         pMenuHelp->AppendMenu(MF_POPUP, (UINT)hMenuPopup,
  226.                             strObjHelp);
  227.  
  228.                         // Clear the count of Help group items and
  229.                         // add Help menu to Window group
  230.                         lpMenuWidths[iWidthIndex] = 0;
  231.                         lpMenuWidths[iWidthIndex-1]++;
  232.  
  233.                         bHelpMergedAsSubMenu = TRUE;
  234.                         hMenuHelpSubMenu = hMenuPopup;
  235.                         continue;
  236.                     }
  237.                     else
  238.                     {
  239.                         // if we didn't do special Help menu merging, just 
  240.                         // insert the menu
  241.                         pMenuShared->InsertMenu(nPosition, state | MF_BYPOSITION,
  242.                             (UINT)hMenuPopup, strItemText);
  243.                         nPosition++;
  244.                         cGroupWidth++;
  245.                     }
  246.                 }
  247.             }
  248.             else if (nLen > 0)
  249.             {
  250.                 // only non-empty items are added
  251.                 ASSERT(!strItemText.IsEmpty());
  252.  
  253.                 if (pMenuHelp != NULL)
  254.                 {
  255.                     // Container has help items - add to its submenu
  256.                     pMenuHelp->AppendMenu(MF_STRING, 
  257.                                         pMenuSource->GetMenuItemID(nItem), 
  258.                                         strItemText);
  259.  
  260.                     // Clear the count of Help group items and
  261.                     // add Help menu to Window group
  262.                     lpMenuWidths[iWidthIndex] = 0;
  263.                     lpMenuWidths[iWidthIndex-1]++;
  264.  
  265.                     bHelpMergedAsSubMenu = TRUE;
  266.                     continue;
  267.                 }
  268.                 else
  269.                 {
  270.                     // here the state does not contain a count in the HIBYTE
  271.                     pMenuShared->InsertMenu(nPosition, state | MF_BYPOSITION,
  272.                         pMenuSource->GetMenuItemID(nItem), strItemText);
  273.                     nPosition++;
  274.                     cGroupWidth++;
  275.                 }
  276.             }
  277.         }
  278.     }
  279.  
  280.     // set the last group width
  281.     if (!bHelpMergedAsSubMenu)
  282.     {
  283.         ASSERT(iWidthIndex <= 5);   // servers should not touch past 5
  284.         lpMenuWidths[iWidthIndex] += cGroupWidth;
  285.     }
  286.  
  287.     return hMenuHelpSubMenu;
  288. }
  289.  
  290. void MfcBinderUnmergeMenus(CMenu* pMenuShared, CMenu* pMenuSource, 
  291.                          CMenu* pMenuHelpPopup)
  292. {
  293.     int cOurItems = pMenuSource->GetMenuItemCount();
  294.     int cMenuItems = pMenuShared->GetMenuItemCount();
  295.  
  296.     for (int i = cMenuItems-1; i >= 0; i--)
  297.     {
  298.         // check out the popup menus
  299.         HMENU hMenuPopup = ::GetSubMenu(pMenuShared->m_hMenu, i);
  300.         if (hMenuPopup != NULL)
  301.         {
  302.          // if we have a Help submenu, check to see if it appears
  303.          // in this submenu somewhere
  304.          if (pMenuHelpPopup)
  305.          {
  306.             int cPopupItems = ::GetMenuItemCount(hMenuPopup);
  307.             for (int k = 0; k < cPopupItems; k++)
  308.             {
  309.                if (::GetSubMenu(hMenuPopup, k) == pMenuHelpPopup->m_hMenu)
  310.                {
  311.                   // remove the Help submenu
  312.                   ::RemoveMenu(hMenuPopup, k, MF_BYPOSITION);
  313.                   pMenuHelpPopup = NULL;
  314.                   break;
  315.                }
  316.             }
  317.         }
  318.         else
  319.             {
  320.                 // if it is one of ours, remove it from the pMenuShared
  321.                 for (int j = 0; j < cOurItems; j++)
  322.                 {
  323.                     if (::GetSubMenu(pMenuSource->m_hMenu, j) == hMenuPopup)
  324.                     {
  325.                         // remove the menu from pMenuShared
  326.                         pMenuShared->RemoveMenu(i, MF_BYPOSITION);
  327.                         break;
  328.                     }
  329.                 }
  330.             }
  331.         }
  332.     }
  333. }
  334.  
  335.