home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / BC_502 / BOCOLE.PAK / BOLESVC.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  39.8 KB  |  1,425 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1991, 1996 by Borland International, All Rights Reserved
  4. //
  5. // $Revision:   2.15  $
  6. //
  7. //  Implements the Bolero half of the application-level object. Provides some 
  8. //  system services such as default dialogs.
  9. //----------------------------------------------------------------------------
  10. #include "BOle.h"
  11. #include "BOleSvc.h"
  12. #include "BOleIPS.h"
  13. #include "BOlePart.h"
  14. #include "BOleDoc.h"
  15. #include "BHatch.h"
  16. #include "BOleCMan.h"
  17. #include "BOleFact.h"
  18. #include "BOleData.h"
  19.  
  20. #include "Ole2Ui.h"
  21.  
  22. struct BOleFactNode {
  23.   IBClass *factory;
  24.   BOleFactNode *pNext;
  25.   BOleFactNode( IBClass *f ){ factory = f; f->AddRef(); pNext = NULL; }
  26.   ~BOleFactNode(){ factory->Release(); }
  27. };
  28.  
  29. BOOL IsControlClass (REFCLSID rclsid, HKEY hKey);
  30.  
  31. HRESULT _IFUNC BOleService::QueryInterfaceMain(REFIID iid, LPVOID *p)
  32. {
  33.   HRESULT hr = ResultFromScode(E_NOINTERFACE);
  34.   *p = NULL;
  35.  
  36.   // interfaces
  37.  
  38.   if (SUCCEEDED(hr = IOleInPlaceFrame_QueryInterface(this, iid, p))) {
  39.   }
  40.   else if SUCCEEDED(hr = IBService_QueryInterface(this, iid, p)) {
  41.   }
  42.   else if SUCCEEDED(hr = IBService2_QueryInterface(this, iid, p)) {
  43.   }
  44.   // base classes
  45.   else if SUCCEEDED(hr = BOleComponent::  QueryInterfaceMain(iid, p)) {
  46.   }
  47.  
  48.   // helpers
  49.  
  50.   return hr;
  51. }
  52.  
  53. POINT BOleService::pixPerIn = {0,};
  54.  
  55. BOleService::BOleService (BOleClassManager *pF, IBUnknownMain *pO) : pApp(NULL),
  56.   pActiveDoc(NULL), pFocusedSite(NULL), BOleComponent(pF, pO),
  57.   helpMode (BOLE_HELP_GET), pClipboardData (NULL), pSubclassedWindow(NULL),
  58.   lpfnHelpWndProc (NULL)
  59. {
  60.   clipList = NULL;
  61.   clipCount = 0;
  62.   clipOkToLink = FALSE;
  63.   clipOkToEmbed = FALSE;
  64.  
  65.   dropList = NULL;
  66.   dropCount = 0;
  67.   dropOkToLink = FALSE;
  68.   dropOkToEmbed = FALSE;
  69.  
  70.   fUseDropList = FALSE;
  71.   pFirstFactNode = NULL;
  72.  
  73. }
  74.  
  75. BOleService::~BOleService ()
  76. {
  77.   FlushClipboardData();
  78.  
  79.   if (clipList) {
  80.     delete [] clipList;
  81.     clipList = NULL;
  82.   }
  83.   if (dropList) {
  84.     delete [] dropList;
  85.     dropList = NULL;
  86.   }
  87. }
  88.  
  89. //
  90. //        Called in BOleSite::OnClose to check if the bolesite object
  91. //        is on the clipboard (BOleSite doesn't do delayed rendering.)
  92. //
  93. BOOL BOleService::IsOnClipboard(IDataObject *pPat)
  94. {
  95.   BOOL ret = FALSE;
  96.   if ( pClipboardData && (S_OK == OleIsCurrentClipboard (pClipboardData))) {
  97.     if (pPat == pClipboardData) {
  98.       ret = TRUE;
  99.     }
  100.     else {
  101.       // if the shadow object is on the clipboard we need to check
  102.       // if the real data object pointer it holds is the same as
  103.       // the one passed
  104.       BOleShadowData * pShadow;
  105.       if (SUCCEEDED(pClipboardData->QueryInterface(
  106.           IID_BOleShadowData, &(LPVOID)pShadow))) {
  107.         ret = (pShadow->GetRealData() == pPat);
  108.         pShadow->Release();
  109.       }
  110.     }
  111.   }
  112.   return ret;
  113. }
  114.  
  115. void BOleService::FlushClipboardData(BOOL bCheck)
  116. {
  117.   if (pClipboardData) { // one of ours may've been on the clipboard
  118.     if (bCheck) {
  119.       IDataObject *pD;
  120.       if (S_OK == GetScode(OleGetClipboard(&pD))) {
  121.   if (pD == pClipboardData)
  122.     OleFlushClipboard();
  123.   pD->Release();
  124.       }
  125.     }
  126.     else
  127.       OleFlushClipboard();
  128.  
  129.     pClipboardData = NULL;
  130.   }
  131. }
  132.  
  133. void BOleService::NotifyClipboardEmptied()
  134. {
  135.   pClipboardData = NULL;
  136. }
  137.  
  138. HRESULT _IFUNC BOleService::Init( IBApplication *pA )
  139. {
  140.  
  141. #ifdef _DEBUG
  142.   //  to make sure client's QueryInterface is implemented correctly
  143.   //
  144.   IBApplication *dbgApp = NULL;
  145.   LPOLEINPLACEFRAME dbgIPFrame = NULL;
  146.   if ((!SUCCEEDED(pObjOuter->QueryInterfaceMain(IID_IBApplication, &(LPVOID)dbgApp)))
  147.        || (!SUCCEEDED(pObjOuter->QueryInterfaceMain(IID_IOleInPlaceFrame,&(LPVOID)dbgIPFrame)))) {
  148.     MessageBox (NULL, TEXT("QueryInterface Aggregation isn\'t working right"),
  149.           TEXT("BOleService::Init"), MB_OK);
  150.   }
  151.   else {
  152.     dbgApp->Release();
  153.     dbgIPFrame->Release();
  154.     dbgApp = NULL;
  155.     dbgIPFrame = NULL;
  156.   }
  157. #endif
  158.  
  159.   if (!pA)
  160.     return ResultFromScode(E_INVALIDARG);
  161.  
  162.   pApp = pA;
  163.   BOleHatchWindow::Register (boleInst);
  164.  
  165.   // The screen is the same resolution for all windows and all processes
  166.   // so we'll just squirrel this away so we don't have to retrieve it
  167.   // every time we need to translate between himetric and pixels
  168.   //
  169.   HWND w = ::GetDesktopWindow ();
  170.   HDC dc = ::GetDC (w);
  171.   if (!w || !dc)
  172.     return ResultFromScode (E_FAIL);
  173.   pixPerIn.x = WIN::GetDeviceCaps(dc, LOGPIXELSX);
  174.   pixPerIn.y = WIN::GetDeviceCaps(dc, LOGPIXELSY);
  175.   ::ReleaseDC (w, dc);
  176.  
  177.   return NOERROR;
  178. }
  179.  
  180. void _IFUNC BOleService::SetActiveDoc (BOleDocument FAR *pD)
  181. {
  182.   pActiveDoc = pD;
  183. }
  184.  
  185. BOleDocument FAR *_IFUNC BOleService::GetActiveDoc ()
  186. {
  187.   return pActiveDoc;
  188. }
  189.  
  190. // SetHelpMode is used by the other Bolero helper objects when
  191. // one of them gets a broadcast help msg. It can come through
  192. // any of them because help is in IOleWindow, from which they inherit.
  193. //
  194. void _IFUNC BOleService::SetHelpMode (BOOL fEnterMode)
  195. {
  196.   helpMode = fEnterMode ? BOLE_HELP_ENTER : BOLE_HELP_EXIT;
  197. }
  198.  
  199. // Maybe useful for Activate As
  200. //
  201. void _IFUNC BOleService::UnloadObjects (REFCLSID c)
  202. {
  203. }
  204.  
  205. UINT _IFUNC BOleService::ExcludeOurselves (LPCLSID FAR *ppClsid)
  206. {
  207.   LPCLSID pClsid = *ppClsid;
  208.   UINT rCnt = 128;
  209.   UINT exclusionCount = 0;
  210.  
  211.   // Allocate an array of CLSIDs to pass back to the caller (who must delete it)
  212.   //
  213.   pClsid = (LPCLSID) new CLSID [rCnt];
  214.   if (!pClsid) {
  215.     *ppClsid = NULL;
  216.     return 0;
  217.   }
  218.  
  219.   BOleFactNode *pNode;
  220.   for (pNode = pFirstFactNode; pNode; pNode = pNode->pNext ){
  221.  
  222.     // Ask the class factory if it's willing to embed in its own container
  223.     // If it isn't willing to do this, we will exclude the CLSID for that
  224.     // factory from the list.
  225.     //
  226.     if( !pNode->factory->AllowEmbedFromSelf() ){
  227.  
  228.       pNode->factory->GetClassID(&pClsid[exclusionCount]);
  229.       exclusionCount++;
  230.     }
  231.   }
  232.  
  233.   *ppClsid = pClsid;
  234.   return exclusionCount;
  235. }
  236.  
  237. // ShowHelpButton -- BOleService helper function used by Bolero to find
  238. //       out if the container app wants us to show the help
  239. //       button for the dialog boxes. If the container is
  240. //       generated by Delphi, they might not.
  241. //
  242. BOOL _IFUNC BOleService::ShowHelpButton (BOleDialogHelp whichDialog)
  243. {
  244.   BOOL ret = TRUE;
  245.   PIBOverrideHelpButton pOHB = NULL;
  246.  
  247.   if (SUCCEEDED(pApp->QueryInterface(IID_IBOverrideHelpButton,
  248.       &(LPVOID) pOHB))) {
  249.     if (S_OK != GetScode (pOHB->ShowHelpButton (whichDialog)))
  250.       ret = FALSE;
  251.     pOHB->Release();
  252.   }
  253.  
  254.   return ret;
  255. }
  256.  
  257. //*************************************************************************
  258. //
  259. // IService implementation
  260. //
  261. //*************************************************************************
  262.  
  263. // Convert is supported on the service because (1) the other OLE2 dialogs
  264. // are supported on the IBService and (2) I didn't want to make another
  265. // function on IBPart which doesn't match up on the real server object
  266. //
  267. HRESULT _IFUNC BOleService::ConvertUI (PIBPart pPart, BOOL b, BOleConvertInfo FAR *pInfo)
  268. {
  269.   BOlePart FAR *pPartImpl = NULL;
  270.   pPart->QueryInterface (IID_BOlePart, &(LPVOID) pPartImpl);
  271.   HRESULT hr = pPartImpl->ConvertUI (pApp, b, pInfo);
  272.   pPartImpl->Release();
  273.   return hr;
  274. }
  275.  
  276. HRESULT _IFUNC BOleService::ConvertGuts (PIBPart pPart, BOOL b, BOleConvertInfo FAR *pInfo)
  277. {
  278.   BOlePart FAR *pPartImpl = NULL;
  279.   pPart->QueryInterface (IID_BOlePart, &(LPVOID) pPartImpl);
  280.   HRESULT hr = pPartImpl->ConvertGuts (b, pInfo);
  281.   pPartImpl->Release();
  282.   return hr;
  283. }
  284.  
  285. // CreateStorageOnFile is a near-trivial helper function which creates
  286. // an IStorage on a DOS file path. Bolero users can do this for themselves
  287. // if they like, but this is a little protection from the OLE2 headers
  288. //
  289. LPSTORAGE _IFUNC BOleService::CreateStorageOnFile (LPCOLESTR pFileName, BOOL bCreate)
  290. {
  291.   IStorage * pStorage;
  292.   HRESULT hr;
  293.   if (bCreate) {
  294.     hr = StgCreateDocfile (
  295.       pFileName,
  296.       STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE|STGM_CREATE,
  297.       0,
  298.       &pStorage
  299.       );
  300.   }
  301.   else {
  302.     hr = StgOpenStorage (
  303.       pFileName, NULL,
  304.       STGM_READWRITE|STGM_DIRECT|STGM_SHARE_EXCLUSIVE,
  305.       NULL,
  306.       0,
  307.       &pStorage
  308.       );
  309.   }
  310.   return pStorage;
  311. }
  312.  
  313. void _IFUNC BOleService::OnResize ()
  314. {
  315.   if (pActiveDoc && pActiveDoc->pActivePart) {
  316.  
  317.     // Ask the active IOleInPlaceActiveObject to recalculate the
  318.     // dimensions of its border adornments in the window, based on
  319.     // the rectangle available in our frame
  320.     //
  321.     RECT r;
  322.     pApp->GetWindowRect (&r);
  323.     pActiveDoc->pActivePart->ResizeBorder (&r, this, TRUE);
  324.   }
  325. }
  326.  
  327. void _IFUNC BOleService::OnActivate (BOOL fActivate)
  328. {
  329.   if (pActiveDoc && pActiveDoc->pActivePart)
  330.     pActiveDoc->pActivePart->OnFrameWindowActivate (fActivate);
  331. }
  332.  
  333. HRESULT _IFUNC BOleService::OnSetFocus(BOOL bSet)
  334. {
  335.   // Just send it on to the active doc
  336.   //
  337.   if (pActiveDoc)
  338.     return pActiveDoc->OnSetFocus(bSet);
  339.  
  340.   // If there's no active doc, there can't be an active object, so
  341.   // the Bolero container app gets to keep focus
  342.   //
  343.   return ResultFromScode (S_OK);
  344. }
  345.  
  346. HRESULT _IFUNC BOleService::Browse(BOleInitInfo FAR * pInfo)
  347. {
  348.   HRESULT ret = ResultFromScode (S_FALSE);
  349.  
  350.   // These guys are in member data so we don't have to create big objects
  351.   // on the stack, but we can still have their lifetime extend from
  352.   // IBService::Browse until IBPart::Init, like they couldn't if we
  353.   // just used a stack variable for OLEUIINSERTOBJECT
  354.   //
  355.   dynamicScopePath[0] = 0;
  356.   dynamicScopeClsid = CLSID_NULL;
  357.  
  358.   OLEUIINSERTOBJECT iod;
  359.   memset(&iod, 0, sizeof(iod));
  360.   iod.cbStruct = sizeof(iod);
  361.   iod.dwFlags  = IOF_SELECTCREATENEW;
  362.   iod.hWndOwner= ::GetActiveWindow();
  363.   iod.lpszFile = dynamicScopePath;
  364.   iod.cchFile  = _MAX_PATH;
  365.   pInfo->pStorage = NULLP;  // User must fill this in after...
  366.  
  367.   iod.cClsidExclude = ExcludeOurselves (&iod.lpClsidExclude);
  368.  
  369. #ifdef NO_CONTROLS
  370.  
  371.     // BEGIN:  - exclude controls from insert object dlg
  372.     HKEY hkey;
  373.     if (RegOpenKey(HKEY_CLASSES_ROOT, "CLSID", &hkey) == ERROR_SUCCESS)
  374.     {
  375.         DWORD dwNumSubKeys;
  376.         RegQueryInfoKey(hkey, NULL, 0, 0, &dwNumSubKeys, NULL, NULL, NULL, NULL,
  377.                              NULL, NULL, NULL);
  378.  
  379.         for (int i = 0; i < dwNumSubKeys; i++)
  380.         {
  381.             char keyBuf[255];
  382.             if (RegEnumKey(hkey, i, keyBuf, sizeof(keyBuf)-1) == ERROR_SUCCESS)
  383.             {
  384.                 HKEY subkey;
  385.                 if (RegOpenKey(hkey, keyBuf, &subkey) == ERROR_SUCCESS)
  386.                 {
  387.                     HKEY tempkey;
  388.                     if (RegOpenKey(subkey, "Control", &tempkey) == ERROR_SUCCESS)
  389.                     {
  390.                         OLECHAR keyBufW[255];
  391.                         CLSID clsid;
  392.                         // move keyBuf (clsid) into the exclude list
  393.                         MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,keyBuf,-1,keyBufW, sizeof(keyBufW) / sizeof(OLECHAR));
  394.                         CLSIDFromString(keyBufW, &clsid);
  395.                         if (iod.cClsidExclude < 128)        // rCnt in ::ExcludeOurselves
  396.                             iod.lpClsidExclude[iod.cClsidExclude++] = clsid;
  397.                         else
  398.                         {
  399.                             RegCloseKey(tempkey);
  400.                             RegCloseKey(subkey);
  401.                             break;        // leave for loop
  402.                         }
  403.                         RegCloseKey(tempkey);
  404.                     }
  405.                     RegCloseKey(subkey);
  406.                 }
  407.             }
  408.         }
  409.         RegCloseKey(hkey);
  410.     }
  411.     // End:
  412. #endif
  413.  
  414.   if (ShowHelpButton(BOLE_HELP_BROWSE))
  415.     iod.dwFlags |= IOF_SHOWHELP;
  416.  
  417. #ifndef WIN32   // MS_OLEUI_DEF  EnterBOleDialog
  418.   iod.dwIBApplication = (DWORD) pApp;
  419.   EnterBOleDialog (iod.hWndOwner, &iod.hHook, &iod.hTask);
  420. #else
  421.   EnterBOleDialog (iod.hWndOwner, NULL, NULL);
  422. #endif
  423.   UINT stat = OUI::OleUIInsertObject (&iod);
  424.   ExitBOleDialog ();
  425.  
  426.   if (stat == OLEUI_OK) {
  427.     DWORD dwFlags = iod.dwFlags;
  428.     pInfo->hIcon = (dwFlags & IOF_CHECKDISPLAYASICON) ? (HICON) iod.hMetaPict : NULL;
  429.     if (dwFlags & IOF_SELECTCREATENEW) {
  430.       pInfo->Where = BOLE_NEW;
  431.       pInfo->How = BOLE_EMBED;
  432.       dynamicScopeClsid = iod.clsid;
  433.       pInfo->whereNew.cid = (BCID) &dynamicScopeClsid;
  434.       if (IsControlClass (dynamicScopeClsid, NULL))
  435.         pInfo->Where = BOLE_NEW_OCX;
  436.  
  437.     }
  438.     else if (dwFlags & IOF_SELECTCREATEFROMFILE) {
  439.       pInfo->Where = BOLE_FILE;
  440.       pInfo->How = (dwFlags & IOF_CHECKLINK) ? BOLE_LINK : BOLE_EMBED;
  441.       int len = strlen (iod.lpszFile) + 1;
  442.       pInfo->whereFile.pPath = new OLECHAR [len];
  443. #if defined(ANSI)    // MS_OLEUI_DEF
  444.       MultiByteToWideChar (CP_ACP, 0, iod.lpszFile, len, 
  445.                       (LPOLESTR)pInfo->whereFile.pPath, len);
  446. #else
  447.       lstrcpy ((LPOLESTR)pInfo->whereFile.pPath, iod.lpszFile);
  448. #endif
  449.     }
  450.     ret = ResultFromScode (S_OK);
  451.   }
  452.  
  453.   if (iod.lpClsidExclude)
  454.     delete [] iod.lpClsidExclude;
  455.  
  456.   if (iod.hMetaPict) {
  457.     ;//       OleUIMetafilePictIconFree(iod.hMetaPict);    // clean up metafile
  458.   }
  459.   return ret;
  460. }
  461.  
  462. HRESULT _IFUNC BOleService::BrowseControls(BOleInitInfo FAR * pInfo)
  463. {
  464.   HRESULT ret = ResultFromScode (S_FALSE);
  465.  
  466.   // These guys are in member data so we don't have to create big objects
  467.   // on the stack, but we can still have their lifetime extend from
  468.   // IBService::Browse until IBPart::Init, like they couldn't if we
  469.   // just used a stack variable for OLEUIINSERTOBJECT
  470.   //
  471.   dynamicScopePath[0] = 0;
  472.   dynamicScopeClsid = CLSID_NULL;
  473.  
  474.   OLEUIINSERTOBJECT iod;
  475.   memset(&iod, 0, sizeof(iod));
  476.   iod.cbStruct = sizeof(iod);
  477.   iod.dwFlags  = IOF_SELECTCREATENEW;
  478.   iod.hWndOwner= ::GetActiveWindow();
  479.   iod.lpszFile = dynamicScopePath;
  480.   iod.cchFile  = _MAX_PATH;
  481.   pInfo->pStorage = NULLP;  // User must fill this in after...
  482.  
  483.   iod.cClsidExclude = ExcludeOurselves (&iod.lpClsidExclude);
  484.  
  485.   if (ShowHelpButton(BOLE_HELP_BROWSE))
  486.     iod.dwFlags |= IOF_SHOWHELP;
  487.  
  488. #ifndef WIN32   // MS_OLEUI_DEF    EnterBOleDialog
  489.   iod.dwIBApplication = (DWORD) pApp;
  490.   EnterBOleDialog (iod.hWndOwner, &iod.hHook, &iod.hTask);
  491. #else
  492.   EnterBOleDialog (iod.hWndOwner, NULL, NULL);
  493. #endif
  494.   UINT stat = OleUIInsertControl (&iod);
  495.   ExitBOleDialog ();
  496.  
  497.   if (stat == OLEUI_OK) {
  498.     DWORD dwFlags = iod.dwFlags;
  499.     pInfo->hIcon = NULL;
  500.     if (dwFlags & IOF_SELECTCREATENEW) {
  501.       pInfo->Where = BOLE_NEW_OCX;
  502.       pInfo->How = BOLE_EMBED;
  503.       dynamicScopeClsid = iod.clsid;
  504.       pInfo->whereNew.cid = (BCID) &dynamicScopeClsid;
  505.     }
  506.     ret = ResultFromScode (S_OK);
  507.   }
  508.  
  509.   if (iod.lpClsidExclude)
  510.     delete [] iod.lpClsidExclude;
  511.  
  512.   return ret;
  513. }
  514.  
  515. // Dialog enabling strategy:
  516. //
  517. // BOleService::OnModalDialog is how Bolero containers and servers
  518. // send dialog state to the outside world
  519. //
  520. // IBApplication::OnModalDialog is how Bolero containers and servers
  521. // receive dialog state from the outside world
  522. //
  523. HRESULT _IFUNC BOleService::OnModalDialog (BOOL fEnable)
  524. {
  525.   HRESULT hr = NOERROR;
  526.  
  527.   // Propogate this state "down" to the active object
  528.   //
  529.   if (pActiveDoc)
  530.     hr = pActiveDoc->OnModalDialog (fEnable);
  531.  
  532.   // Propogate this state "up" to the inplace frame
  533.   //
  534.   if (pFocusedSite) {
  535.     PIBApplication tmpapp = NULL;
  536.     if (SUCCEEDED(pFocusedSite->QueryInterface(
  537.       IID_IBApplication, &(LPVOID) tmpapp))) {
  538.       hr = tmpapp->OnModalDialog (fEnable);
  539.       tmpapp->Release();
  540.     }
  541.   }
  542.  
  543.   // Propogate this state "back" to the application. Since Bolero
  544.   // calls OnModalDialog itself for the OLE2 dialog boxes, the app
  545.   // wouldn't otherwise know we're in a modal dialog
  546.   //
  547.   hr = pApp->OnModalDialog (fEnable);
  548.  
  549.   return hr;
  550. }
  551.  
  552. HRESULT _IFUNC BOleService::TranslateAccel (LPMSG pMsg)
  553. {
  554.   HRESULT hR = ResultFromScode( S_FALSE );
  555.   if( pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST ){
  556.     if( pFocusedSite )
  557.       hR = pFocusedSite->Accelerator( pMsg );
  558.     else if( pActiveDoc )
  559.       hR = pActiveDoc->TranslateAccel( pMsg );
  560.   }
  561.   return hR;
  562. }
  563.  
  564. BOleHelp _IFUNC BOleService::HelpMode (BOleHelp newMode)
  565. {
  566.   BOleHelp oldMode = helpMode;
  567.   if (newMode != BOLE_HELP_GET)
  568.     // broadcast to all documents
  569.     if (pActiveDoc && pActiveDoc->pActivePart)
  570.       pActiveDoc->pActivePart->ContextSensitiveHelp (newMode == BOLE_HELP_ENTER);
  571.  
  572.   return oldMode;
  573. }
  574.  
  575. HRESULT _IFUNC BOleService::CanClose()
  576. {
  577.   if (pFactory->ServerCount() == 0)
  578.     return ResultFromScode (S_OK);
  579.   else
  580.     return ResultFromScode (S_FALSE);
  581. }
  582.  
  583. HRESULT _IFUNC BOleService::BrowseClipboard (BOleInitInfo FAR * pInfo)
  584. {
  585.   if (TRUE == PasteHelper (pInfo, TRUE))
  586.     return ResultFromScode (S_OK);
  587.   else
  588.     return ResultFromScode (S_FALSE);
  589. }
  590.  
  591. HRESULT _IFUNC BOleService::Paste (BOleInitInfo *pInfo)
  592. {
  593.   if (TRUE == PasteHelper (pInfo, FALSE))
  594.     return ResultFromScode (S_OK);
  595.   else
  596.     return ResultFromScode (S_FALSE);
  597. }
  598.  
  599. // This function is called when a moniker becomes invalid for an object
  600. // on the clipboard
  601. //
  602. void _IFUNC BOleService::RemoveLinkFromClipList()
  603. {
  604.   UINT i=0, from=0;
  605.   for (; i < clipCount; i++, from++) {
  606.     if ((clipList[i].cfFormat == BOleDocument::oleLinkSrcDescFmt) ||
  607.       (clipList[i].cfFormat == BOleDocument::oleLinkSrcClipFmt)) {
  608.       // skip link format
  609.       //
  610.       ++from;
  611.     }
  612.     // and shift
  613.     //
  614.     if (i != from && from < clipCount)
  615.       clipList[i] = clipList[from];
  616.   }
  617.   clipCount -= (from - i);
  618.   clipOkToLink = FALSE;
  619. }
  620.  
  621. // This is a helper function for IService::Drag and IService::Clip. Its
  622. // purpose is to make a format list for each operation. The lists are
  623. // independent since drag/drop shouldn't disturb the clipboard. So the
  624. // lists are parameterized in this function.
  625. //
  626. BOOL _IFUNC BOleService::FormatHelper (LPFORMATETC FAR* ppList, UINT *pCount,
  627.   BOOL &fLink, BOOL &fEmbed, PIBDataProvider pProvider)
  628. {
  629.   UINT nOffered = 0;
  630.  
  631.   if (!pProvider) {
  632.     *ppList = NULL;
  633.     *pCount = 0;
  634.     fLink =FALSE;
  635.     fEmbed = FALSE;
  636.     return FALSE;
  637.   }
  638.  
  639.   nOffered = pProvider->CountFormats();
  640.  
  641.   if (nOffered == 0) {
  642.     *ppList = NULL;
  643.     *pCount = 0;
  644.     fLink =FALSE;
  645.     fEmbed = FALSE;
  646.     return FALSE;
  647.   }
  648.  
  649.   // This will disable linking when GetMoniker fails
  650.   // eg. When the container has not been saved.
  651.   if (fLink) {
  652.     IOleObject *pOleObj;
  653.     if (SUCCEEDED(pProvider->QueryInterface(IID_IOleObject,
  654.             &(LPVOID) pOleObj))) {
  655.       IMoniker *pMon;
  656.       if (SUCCEEDED(pOleObj->GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
  657.                 OLEWHICHMK_OBJFULL, &pMon))) {
  658.         pMon->Release();
  659.       }
  660.       else {
  661.         fLink = FALSE;
  662.       }
  663.       pOleObj->Release();
  664.     }
  665.     else
  666.       fLink = FALSE;    // forbid linking if IOleObject fails
  667.   }
  668.  
  669.   if (*ppList)
  670.     delete [] *ppList;
  671.  
  672.   // The part is responsible for offering all clipboard formats except
  673.   // link source descriptor and object descriptor.
  674.   //
  675.   // Note that the part won't get called in GetFormatData for embeddings
  676.   // (because getting an embedded object means calling IBDataProv::Save) or
  677.   // for CF_METAFILEPICT (because we get that in IBDataProv::Draw)
  678.   //
  679.   *ppList = new FORMATETC [nOffered + 1 + (fLink ? 1 : 0)];
  680.             // 1 for object descriptor
  681.             // 1 for link source descriptor if linkable
  682.   if (!*ppList)
  683.     return FALSE;
  684.  
  685.   LPFORMATETC pNext = *ppList;
  686.  
  687.  
  688.   // All objects get an object descriptor
  689.   //
  690.  
  691.     pNext->cfFormat = BOleDocument::oleObjectDescFmt;
  692.     pNext->ptd = NULL;
  693.     pNext->dwAspect = DVASPECT_CONTENT;
  694.     pNext->lindex = -1;
  695.     pNext->tymed = TYMED_HGLOBAL;
  696.     pNext++;
  697.  
  698.  
  699.   if (fLink) {
  700.     pNext->cfFormat = BOleDocument::oleLinkSrcDescFmt;
  701.     pNext->ptd = NULL;
  702.     pNext->dwAspect = DVASPECT_CONTENT;
  703.     pNext->lindex = -1;
  704.     pNext->tymed = TYMED_HGLOBAL;
  705.     pNext++;
  706.   }
  707.  
  708.   // Enumerate the server's formats for this object into our list
  709.   //
  710.   BOleFormat boleFmt;
  711.   fEmbed = FALSE;
  712.   UINT i;
  713.   for (i = 0; i < nOffered; i++) {
  714.     if (NOERROR == pProvider->GetFormat (i, &boleFmt)) {
  715.       if ((boleFmt.fmtId == BOleDocument::oleLinkSrcDescFmt) && !fLink) {
  716.         // This will disable linking when GetMoniker fails
  717.         // eg. When the container has not been saved.
  718.         continue;
  719.       }
  720.       if ((boleFmt.fmtId == BOleDocument::oleLinkSrcClipFmt) && !fLink) {
  721.         // This will disable linking when GetMoniker fails
  722.         // eg. When the container has not been saved.
  723.         continue;
  724.       }
  725.       if (boleFmt.fmtId == BOleDocument::oleEmbdObjClipFmt ||
  726.         boleFmt.fmtId == BOleDocument::oleEmbSrcClipFmt) {
  727.         // This will enable embedding if the source of the
  728.         // drag offers an embedding format
  729.         //
  730.         fEmbed = TRUE;
  731.       }
  732.       pNext->cfFormat = boleFmt.fmtId;
  733.       pNext->ptd = NULL;
  734.       pNext->dwAspect = DVASPECT_CONTENT;
  735.       pNext->lindex = -1;
  736.       pNext->tymed = boleFmt.fmtMedium & ~BOLE_MED_STATIC;
  737.       pNext++;
  738.     }
  739.   }
  740.   *pCount = pNext - *ppList;
  741.   return TRUE;
  742. }
  743.  
  744. HRESULT _IFUNC BOleService::Clip (PIBDataProvider pClonePart, BOOL fLink,
  745.   BOOL fEmbed, BOOL fUseDataCache)
  746. {
  747.   HRESULT hr;
  748.  
  749.   // If the clone object is null, we're invalidating everything on the
  750.   // clipboard, for example if the app is shutting down or if the app
  751.   // is doing pseudo-delayed-rendering, and the clipboard doesn't reflect
  752.   // the data any more.
  753.   //
  754.   if (!pClonePart) {
  755.  
  756.     OleSetClipboard (NULL);     
  757.     if (clipList) {
  758.       delete [] clipList;
  759.       clipList = NULL;
  760.     }
  761.     clipCount = 0;
  762.     clipOkToLink = FALSE;
  763.     clipOkToEmbed = FALSE;
  764.     return ResultFromScode (S_OK);
  765.   }
  766.  
  767.   // Get the IPart from the part object. Need this so we can enumerate
  768.   // the formats which should be available to the data object.
  769.   //
  770.   PIBDataProvider pProvider = pClonePart;
  771.  
  772.   FlushClipboardData();
  773.  
  774.   // Here we have a choice of ways to get a data object to put on the
  775.   // clipboard. The first is a "snapshot" object which can be used for
  776.   // delayed rendering. The second is the original object which won't
  777.   // be protected from delayed rendering.
  778.   //
  779.  
  780.   if (fUseDataCache) {
  781.     // Get the data object from the snapshot data cache implemented
  782.     // in BOleData
  783.     //
  784.     BOlePart *pBOlePart = NULL;
  785.     hr = pProvider->QueryInterface (IID_BOlePart, &(LPVOID) pBOlePart);
  786.     if (!SUCCEEDED(hr))
  787.       return hr;
  788.  
  789.     hr = pBOlePart->CopyFromOriginal (NULL, &pClipboardData);
  790.     pBOlePart->Release();
  791.     if (!SUCCEEDED(hr))
  792.       return hr;
  793.   }
  794.   else {
  795.     // Get the data object from the part. Because of aggregation this
  796.     // is actually the IDataObject of the BOleSite which the part is
  797.     // associated with.
  798.     //
  799.     IDataObject *pData;
  800.     hr = pClonePart->QueryInterface(IID_IDataObject, &(LPVOID) pData);
  801.     if (!SUCCEEDED(hr))
  802.       return hr;
  803.     pClipboardData = new BOleShadowData(pFactory, pData);
  804.     pData->Release();
  805.  
  806.     // Find out how many formats we need. This allows us to malloc a list
  807.     // of FORMATETCs for matching later. The user doesn't have to know
  808.     // about the OLE2 formats, so we need to add those to the count.
  809.     //
  810.     // This list is only used in BOleSite.
  811.     //
  812.     fUseDropList= FALSE;
  813.     clipOkToLink = fLink; // will be cleared by FormatHelper if format not offered
  814.     clipOkToEmbed = fEmbed;// will be cleared by FormatHelper if format not offered
  815.  
  816.     if (!FormatHelper (&clipList, &clipCount, clipOkToLink, clipOkToEmbed, pProvider))
  817.       // clipOkToLink is passed by reference
  818.       hr = ResultFromScode (DV_E_FORMATETC);
  819.   }
  820.  
  821.   // Use the OLE2 API to put the data object on the clipboard.
  822.   //
  823.   if (SUCCEEDED(hr)) {
  824.  
  825.     hr = OleSetClipboard( pClipboardData);
  826.     if (!SUCCEEDED(hr))
  827.       Clip(NULL, FALSE, FALSE, FALSE);
  828.  
  829.   }
  830.   if (pClipboardData)
  831.     pClipboardData->Release();
  832.  
  833.   // pClipboardData is a non ref counted copy of the pointer
  834.   // that is referenced by the clipboard.
  835.   // We release our ref count now to allow BOleShadowData or BOleData
  836.   // to go away as soon as some other app copies to the clipboard. We'll set
  837.   // pClipboardData to NULL when BOleShadowData or BoleData goes away
  838.   // to avoid leaving it dangling.
  839.  
  840.   return hr;
  841. }
  842.  
  843. HRESULT _IFUNC BOleService::Drag (PIBDataProvider pPart, BOleDropAction inEffects, BOleDropAction *outEffect)
  844. {
  845.   HRESULT hr = ResultFromScode(S_FALSE);
  846.   DWORD dwOutEffect;
  847.   IDataObject *pDataObj = NULL;
  848.   IDropSource *pDropSrc = NULL;
  849.   if (outEffect)
  850.     *outEffect = BOLE_DROP_NONE;
  851.   BOOL fUnlockRunning = FALSE;
  852.  
  853.   // Get IDataObject of embedding or server being dragged
  854.  
  855.   BOlePart *pBOlePart = NULL;
  856.  
  857.   if (SUCCEEDED(pPart->QueryInterface(IID_IDataObject,&(LPVOID)pDataObj))) {
  858.  
  859.     // Cache the data formats associated with the server object so
  860.     // when we get called in the IDataObject, we'll have something to
  861.     // compare against in BOleSite
  862.     //
  863.     fUseDropList = TRUE;
  864.     dropOkToLink = (inEffects & BOLE_DROP_LINK) != 0;
  865.     FormatHelper (&dropList, &dropCount, dropOkToLink, dropOkToEmbed, pPart);
  866.     if (!dropOkToLink)        // in case link not possible
  867.       (int)inEffects &= ~BOLE_DROP_LINK;
  868.   }
  869.   else {
  870.     hr = pPart->QueryInterface (IID_BOlePart, &(LPVOID) pBOlePart);
  871.     if (!SUCCEEDED(hr))
  872.       return hr;
  873.  
  874.  
  875.  
  876.  
  877.  
  878.  
  879.  
  880.  
  881.  
  882.  
  883.  
  884.  
  885.  
  886.  
  887.  
  888.       // This can be a little slow, but I think it should be better
  889.       // than running the app
  890.       //
  891.       pBOlePart->CopyFromOriginal (NULL, &pDataObj);
  892.  
  893.   }
  894.  
  895.   if (!pDataObj)
  896.     return hr;
  897.  
  898.   if (!pDropSrc)
  899.     pPart->QueryInterface(IID_IDropSource,&(LPVOID)pDropSrc);
  900.  
  901.   if (!pDropSrc) {
  902.     pDataObj->Release();
  903.     return hr;
  904.   }
  905.  
  906.   // Don't lock if the objects are in another process space
  907.   //
  908.   if (!pBOlePart) {
  909.     CoLockObjectExternal (pDataObj, TRUE, FALSE);
  910.     CoLockObjectExternal (pDropSrc, TRUE, FALSE);
  911.   }
  912.  
  913.   hr = OLE::DoDragDrop (pDataObj, pDropSrc, (DWORD)inEffects, &dwOutEffect);
  914.  
  915.   // Fill in the out param if we got one
  916.   //
  917.   if (outEffect)
  918.     *outEffect = (BOleDropAction)dwOutEffect;
  919.  
  920.   // Make up a return code. The Bolero convention here is NOERROR for
  921.   // success or an error if not. Strangely, the container can fail from
  922.   // IDropTarget::Drop and we still get DRAGDROP_S_DROP. Fortunately we
  923.   // do get the DROPEFFECT_NONE if the container set it, so use it here
  924.   // to produce an error.
  925.   //
  926.   if (GetScode(hr) == DRAGDROP_S_DROP)
  927.     if (dwOutEffect == DROPEFFECT_NONE)
  928.       hr = ResultFromScode (E_FAIL);
  929.     else
  930.       hr = ResultFromScode(S_OK);
  931.  
  932.   if (!pBOlePart) {
  933.     // TRUE releases ref counts held by OLE2 if this is last unlock
  934.     // this is important if the dragging object is a clone
  935.     CoLockObjectExternal (pDataObj, FALSE, TRUE);
  936.     CoLockObjectExternal (pDropSrc, FALSE, TRUE);
  937.   }
  938.  
  939.   // When we're dragging an embedding, we need to keep the object running.
  940.   // Unlock it after the drag/drop has completed.
  941.   //
  942.   if (pBOlePart) {
  943.     if (fUnlockRunning)
  944.       OleLockRunning (pBOlePart->pOleObject, FALSE, FALSE);
  945.     pBOlePart->Release();
  946.   }
  947.  
  948.   pDropSrc->Release();
  949.   pDataObj->Release(); // should delete BOleData if dragging from embedding
  950.  
  951.   return hr;
  952. }
  953.  
  954. BOleMenuEnable _IFUNC BOleService::EnableEditMenu (BOleMenuEnable bmeIn,
  955.               PIBDataConsumer pConsumer)
  956. {
  957.   BOleMenuEnable bmeOut = BOleMenuEnable( 0 );
  958.   HRESULT hr = NOERROR;
  959.   LPDATAOBJECT data = NULL;
  960.  
  961.   if (bmeIn & BOLE_ENABLE_PASTELINK) {
  962.  
  963.     hr = OleGetClipboard (&data);
  964.     if (S_OK == GetScode(hr)) {
  965.  
  966.       hr = OleQueryLinkFromData (data);
  967.       if (data)
  968.         data->Release ();
  969.  
  970.       // I didn't use SUCCEEDED here because someone returns 0x00030000
  971.       // which doesn't look like an scode at all. Go figure.
  972.       //
  973.       if (GetScode(hr) == S_OK)
  974.         ( int )bmeOut |= BOLE_ENABLE_PASTELINK;
  975.     }
  976.   }
  977.  
  978.   // We're borrowing the logic from the dialog which enumerates the links in
  979.   // the document. In this case, we don't so much need to enumerate them;
  980.   // it's enough to know that one exists.
  981.   //
  982.   if (bmeIn & BOLE_ENABLE_BROWSELINKS) {
  983.     if (pActiveDoc && pActiveDoc->EnableBrowseLinks())
  984.       ( int )bmeOut |= BOLE_ENABLE_BROWSELINKS;
  985.   }
  986.  
  987.   // The test for whether to enable these last two is really the same
  988.   // criteria: a match between what the container can accept and what the
  989.   // server offers.
  990.   //
  991.   if ((bmeIn & BOLE_ENABLE_PASTE) || (bmeIn & BOLE_ENABLE_BROWSECLIPBOARD)) {
  992.  
  993.  
  994.  
  995.  
  996.  
  997.     LPDATAOBJECT pDataObj = NULL;
  998.     OLEUIPASTEENTRY *pOle2UIEntries = NULL;
  999.     BOleFormat *pBOleEntries = NULL;
  1000.     UINT nAcceptableFormats = 0;
  1001.     CLIPFORMAT i;
  1002.  
  1003.     hr = OLE::OleGetClipboard (&pDataObj);
  1004.     if (S_OK == GetScode(hr)) {
  1005.       nAcceptableFormats = pConsumer->CountFormats ();
  1006.       if (!nAcceptableFormats)
  1007.         goto cleanup;
  1008.       pOle2UIEntries = new OLEUIPASTEENTRY [nAcceptableFormats];
  1009.       if (!pOle2UIEntries)
  1010.         goto cleanup;
  1011.       pBOleEntries = new BOleFormat[nAcceptableFormats];
  1012.       if (!pBOleEntries)
  1013.         goto cleanup;
  1014.  
  1015.       for (i = 0; i < nAcceptableFormats; i++) {
  1016.         //_fmemset (&pOle2UIEntries[i], 0, sizeof (OLEUIPASTEENTRY));
  1017.         pConsumer->GetFormat (i, &pBOleEntries[i]);
  1018.  
  1019.         pOle2UIEntries[i].fmtetc.cfFormat = pBOleEntries[i].fmtId;
  1020.         pOle2UIEntries[i].fmtetc.ptd = NULL;
  1021.         pOle2UIEntries[i].fmtetc.dwAspect = DVASPECT_CONTENT;
  1022.         pOle2UIEntries[i].fmtetc.tymed = pBOleEntries[i].fmtMedium & ~BOLE_MED_STATIC;
  1023.         pOle2UIEntries[i].fmtetc.lindex = -1;
  1024.  
  1025.         pOle2UIEntries[i].lpstrFormatName = TEXT ("%s");  // unused for menu enabling
  1026. //          (pBOleEntries[i].fmtName[0] ? pBOleEntries[i].fmtName : OLESTR ("%s") );
  1027.         pOle2UIEntries[i].lpstrResultText = TEXT ("%s");  // unused for menu enabling
  1028. //          (pBOleEntries[i].fmtResultName[0] ? pBOleEntries[i].fmtResultName : OLESTR ("%s") );
  1029.  
  1030.         if (pBOleEntries[i].fmtId == BOleDocument::oleEmbdObjClipFmt ||
  1031.           pBOleEntries[i].fmtId == BOleDocument::oleLinkSrcClipFmt  ||
  1032.           pBOleEntries[i].fmtId == BOleDocument::oleEmbSrcClipFmt)
  1033.  
  1034.           //      PASTEONLY and ENABLEICON are mutually exclusive
  1035.           //
  1036.           pOle2UIEntries[i].dwFlags =
  1037.             OLEUIPASTE_PASTE | OLEUIPASTE_ENABLEICON;
  1038.         else
  1039.           pOle2UIEntries[i].dwFlags = OLEUIPASTE_PASTEONLY;
  1040.  
  1041.       }
  1042.  
  1043.       i = MatchPriorityClipFormat (pDataObj, pOle2UIEntries, nAcceptableFormats);
  1044.       if (i != 0xFFFF) {
  1045.         ( int )bmeOut |= ( BOLE_ENABLE_PASTE|BOLE_ENABLE_BROWSECLIPBOARD );
  1046.       }
  1047.  
  1048. cleanup:
  1049.       // Clean up our various scratch buffers etc
  1050.       //
  1051.       if (pBOleEntries)
  1052.         delete [] pBOleEntries;
  1053.       if (pOle2UIEntries)
  1054.         delete [] pOle2UIEntries;
  1055.  
  1056.       pDataObj->Release();
  1057.  
  1058.     }
  1059.   }
  1060.   return bmeOut;
  1061.  
  1062. }
  1063.  
  1064. //*************************************************************************
  1065. //
  1066. // IOleWindow implementation -- base class of OLE2 windows
  1067. //
  1068. //*************************************************************************
  1069.  
  1070. HRESULT _IFUNC BOleService::GetWindow (HWND FAR *phwnd)
  1071. {
  1072.   *phwnd = pApp->GetWindow();
  1073.   return *phwnd != NULL ? NOERROR : ResultFromScode (E_FAIL);
  1074. }
  1075.  
  1076. HRESULT _IFUNC BOleService::ContextSensitiveHelp (BOOL fEnterMode)
  1077. {
  1078.   // The BOleService object is responsible for keeping track of Shift-F1
  1079.   //
  1080.   SetHelpMode (fEnterMode);
  1081.   return NOERROR;
  1082. }
  1083.  
  1084. //*************************************************************************
  1085. //
  1086. // IOleInPlaceUIWindow implementation
  1087. //
  1088. //*************************************************************************
  1089.  
  1090. HRESULT _IFUNC BOleService::GetBorder (LPRECT prectBorder)
  1091. {
  1092.   if (SUCCEEDED(pApp->GetWindowRect(prectBorder)))
  1093.     return NOERROR;
  1094.  
  1095.   return ResultFromScode (INPLACE_E_NOTOOLSPACE);
  1096. }
  1097.  
  1098. HRESULT _IFUNC BOleService::RequestBorderSpace (LPCRECT prectWidths)
  1099. {
  1100.   // Ask the application if it can accept the amount of space the
  1101.   // server wants on the left, top, right, and bottom of the window
  1102.   //
  1103.   if (SUCCEEDED(pApp->RequestBorderSpace (prectWidths)))
  1104.     return NOERROR;
  1105.  
  1106.   return ResultFromScode (INPLACE_E_NOTOOLSPACE);
  1107. }
  1108.  
  1109. HRESULT _IFUNC BOleService::SetBorderSpace (LPCBORDERWIDTHS prectWidths)
  1110. {
  1111.   // This seems like it does the same thing as RequestBorderSpace,
  1112.   // except that this time the server is really taking the space, so
  1113.   // we should get our stuff out of the way.
  1114.   //
  1115.  
  1116.   if (SUCCEEDED(pApp->SetBorderSpace(prectWidths)))
  1117.     return NOERROR;
  1118.  
  1119.   return ResultFromScode (OLE_E_INVALIDRECT);
  1120. }
  1121.  
  1122. HRESULT _IFUNC BOleService::SetActiveObject (IOleInPlaceActiveObject *pActiveObject, LPCOLESTR pszObjName)
  1123. {
  1124.   // Although it seems a little strange, we're supposed to put the
  1125.   // name of the object in our caption bar in the client.
  1126.   //
  1127.   IBWindow *pWnd;
  1128.   if (pActiveDoc)
  1129.     pWnd = getNegotiator(pApp, pActiveDoc->pContainer);
  1130.   else
  1131.     pWnd = pApp;      // just in case
  1132.  
  1133.   if (pszObjName)
  1134.      pWnd->AppendWindowTitle (pszObjName);
  1135.   else if (!pszObjName && !pActiveObject)
  1136.     // Calling SetActiveObject with a null name means the object
  1137.     // is deactivating.
  1138.  
  1139.  
  1140.     //
  1141.     pWnd->RestoreUI();
  1142.  
  1143.  
  1144.   // Decrement the ref count of the pointer we're giving up, and
  1145.   // bump the ref count of the new pointer we're going to hold
  1146.   //
  1147.   if (pActiveDoc) {
  1148.     if (pActiveDoc->pActivePart)
  1149.       pActiveDoc->pActivePart->Release();
  1150.     if (pActiveDoc->pActiveCtrl) {
  1151.       pActiveDoc->pActiveCtrl->Release();
  1152.       pActiveDoc->pActiveCtrl = NULL;
  1153.     }
  1154.     pActiveDoc->pActivePart = pActiveObject;
  1155.     if (pActiveObject) {
  1156.       pActiveObject->AddRef();
  1157.       pActiveObject->QueryInterface(
  1158.           IID_IOleControl, &(LPVOID)pActiveDoc->pActiveCtrl);
  1159.     }
  1160.   }
  1161.  
  1162.   return NOERROR;
  1163. }
  1164.  
  1165. //*************************************************************************
  1166. //
  1167. // IOleInPlaceFrame implementation
  1168. //
  1169. //*************************************************************************
  1170.  
  1171. HRESULT _IFUNC BOleService::InsertMenus (HMENU hmenuShared, LPOLEMENUGROUPWIDTHS lpMenuWidths)
  1172. {
  1173.   if (SUCCEEDED(pApp->InsertContainerMenus (hmenuShared,
  1174.     (BOleMenuWidths*) lpMenuWidths)))
  1175.     return NOERROR;
  1176.  
  1177.   return ResultFromScode (E_FAIL);
  1178. }
  1179.  
  1180. HRESULT _IFUNC BOleService::SetMenu (HMENU hmenuShared, HOLEMENU holeMenu, HWND hwndActiveObject)
  1181. {
  1182.   HRESULT hr = NOERROR;
  1183.  
  1184.   // hmenuShared will be null when the call to BOleService::SetMenu is
  1185.   // initiated from BOlePart::OnUIDeactivate. hmenuShared will be valid
  1186.   // when the SetMenu call comes from the real server object
  1187.   //
  1188.   // Even when hmenuShared is NULL, we have to pass the call on to the
  1189.   // container because the container has to remove the menu from its
  1190.   // frame window.
  1191.   //
  1192.   hr = pApp->SetFrameMenu (hmenuShared);
  1193.  
  1194.   // holemenu will be null when the call to BOleService::SetMenu is
  1195.   // initiated from BOlePart::OnUIDeactivate. holeMenu will be valid
  1196.   // when the SetMenu call comes from the real server object
  1197.   //
  1198.   if (SUCCEEDED(hr))
  1199.     hr = OleSetMenuDescriptor (holeMenu, pApp->GetWindow(),
  1200.       hwndActiveObject, NULL, NULL);
  1201.  
  1202.   return hr;
  1203. }
  1204.  
  1205. HRESULT _IFUNC BOleService::RemoveMenus (HMENU hmenuShared)
  1206. {
  1207.  
  1208.  
  1209.  
  1210.  
  1211.   BOOL fNoError = TRUE;
  1212.  
  1213.   // Remove container group menus
  1214.   //
  1215.   while (GetMenuItemCount(hmenuShared))
  1216.     fNoError &= RemoveMenu(hmenuShared, 0, MF_BYPOSITION);
  1217.  
  1218.   return fNoError ? NOERROR : ResultFromScode(E_FAIL);
  1219. }
  1220.  
  1221. HRESULT _IFUNC BOleService::SetStatusText (LPCOLESTR statusText)
  1222. {
  1223.   // Servers use this function to put text in the container's status bar.
  1224.   // The server is not supposed to negotiate tool space to put their own
  1225.   // status bar at the bottom of the frame window.
  1226.   //
  1227.   pApp->SetStatusText(statusText);
  1228.   return NOERROR;
  1229. }
  1230.  
  1231. HRESULT _IFUNC BOleService::EnableModeless (BOOL fEnable)
  1232. {
  1233.   return pApp->OnModalDialog (!fEnable);
  1234. }
  1235.  
  1236. HRESULT _IFUNC BOleService::TranslateAccelerator (MSG FAR* msg, WORD wID)
  1237. {
  1238.   HWND oldhwnd = msg->hwnd;
  1239.   msg->hwnd = pApp->GetWindow ();
  1240.   HRESULT hr = pApp->Accelerator(msg);
  1241.   msg->hwnd = oldhwnd;
  1242.   return hr;
  1243. }
  1244.  
  1245. /*
  1246.  *        Registration related.
  1247.  */
  1248.  
  1249. HRESULT _IFUNC BOleService::RegisterClass(LPCOLESTR szProgId, 
  1250.   IBClassMgr * pCM, BCID rId,
  1251.   BOOL fInProcExe, BOOL fSingleUse)
  1252. {
  1253.   HRESULT hErr;
  1254.   LPUNKNOWN pObjF;
  1255.   IBClass *pClass;
  1256.   pFactory->ComponentCreate(&pObjF, NULL, cidBOleFactory);
  1257.   if (SUCCEEDED(hErr = pObjF->QueryInterface(IID_IBClass, &(LPVOID)pClass))) {
  1258.     if (SUCCEEDED(hErr = pClass->Init(fInProcExe, szProgId, pCM, rId))) {
  1259.       if (SUCCEEDED(hErr = pClass->Register(fSingleUse))) {
  1260.         AddClassFactory( pClass );
  1261.       }
  1262.     }
  1263.     pClass->Release();
  1264.   }
  1265.   pObjF->Release();
  1266.   return hErr;
  1267. }
  1268.  
  1269. HRESULT _IFUNC BOleService::UnregisterClass (LPCOLESTR szProgId)
  1270. {
  1271.   return RemoveClassFactory(szProgId);
  1272. }
  1273.  
  1274. HRESULT _IFUNC BOleService::RegisterControlClass (LPCOLESTR szProgId, 
  1275.   IBClassMgr * pCM, BCID rId,
  1276.   BOOL fInProcExe, BOOL fSingleUse)
  1277. {
  1278.   // rayk - this is a place holder for registering a control class
  1279.   //        this will create the appropriate class factory that will
  1280.   //        properly handle the licensing information for controls that we
  1281.   //        create
  1282.  
  1283.   HRESULT hErr;
  1284.   LPUNKNOWN pObjF;
  1285.   IBClass *pClass;
  1286.   pFactory->ComponentCreate(&pObjF, NULL, cidBOleControlFactory);
  1287.   if (SUCCEEDED(hErr = pObjF->QueryInterface(IID_IBClass, &(LPVOID)pClass))) {
  1288.     if (SUCCEEDED(hErr = pClass->Init(fInProcExe, szProgId, pCM, rId))) {
  1289.       if (SUCCEEDED(hErr = pClass->Register(fSingleUse))) {
  1290.         AddClassFactory( pClass );
  1291.       }
  1292.     }
  1293.     pClass->Release();
  1294.   }
  1295.   pObjF->Release();
  1296.   return hErr;
  1297. }
  1298.  
  1299. HRESULT _IFUNC BOleService::UnregisterControlClass (LPCOLESTR szProgId)
  1300. {
  1301.   return RemoveClassFactory (szProgId);
  1302. }
  1303.  
  1304. HRESULT BOleService::AddClassFactory (IBClass *pF)
  1305. {
  1306.   HRESULT hErr = NOERROR;
  1307.   BOleFactNode *pNewNode = new BOleFactNode( pF );
  1308.   if( !pFirstFactNode )
  1309.     pFirstFactNode = pNewNode;
  1310.   else {
  1311.     BOleFactNode *pNode = pFirstFactNode;
  1312.     for(; pNode->pNext; pNode = pNode->pNext )
  1313.       ;
  1314.     pNode->pNext = pNewNode;
  1315.   }
  1316.   OLEHRES("Registered classid", hErr);
  1317.   return hErr;
  1318. }
  1319.  
  1320. HRESULT BOleService::RemoveClassFactory (LPCOLESTR szProgId)
  1321. {
  1322.   CLSID cid;
  1323.   if (SUCCEEDED( CLSIDFromProgID (szProgId, &cid) ) ){
  1324.     return RemoveClassFactory (cid);
  1325.   }
  1326.   return ResultFromScode (E_FAIL);
  1327. }
  1328.  
  1329. HRESULT BOleService::RemoveClassFactory (REFCLSID cid)
  1330. {
  1331.   BOleFactNode *pNode = pFirstFactNode, *pPrevNode = NULL;
  1332.   while( pNode ){
  1333.     IBClass *pF = pNode->factory;
  1334.     if (pF->IsA(cid)) {
  1335.       pF->Revoke();
  1336.       // Unchain the node
  1337.       if( pPrevNode )
  1338.         pPrevNode->pNext = pNode->pNext;
  1339.       else
  1340.         pFirstFactNode = pNode->pNext;
  1341.       BOleFactNode *pDel = pNode;
  1342.       pNode = pNode->pNext;
  1343.       delete pDel;        // releases the factory
  1344.     } else {
  1345.       pPrevNode = pNode;
  1346.       pNode = pNode->pNext;
  1347.     }
  1348.   }
  1349.   return NOERROR;
  1350. }
  1351.  
  1352.  
  1353. HRESULT BOleService::FindClassFactory(LPCOLESTR szProgId, IBClass **pF)
  1354. {
  1355.   CLSID cid;
  1356.   if( SUCCEEDED( CLSIDFromProgID(szProgId, &cid ) ) ){
  1357.     return FindClassFactory( cid, pF );
  1358.   }
  1359.   return ResultFromScode (E_FAIL);
  1360. }
  1361.  
  1362.  
  1363. HRESULT BOleService::FindClassFactory(REFCLSID cid, IBClass **ppF)
  1364. {
  1365.   *ppF = NULL;
  1366.   BOleFactNode *pNode;
  1367.   for (pNode = pFirstFactNode; pNode; pNode = pNode->pNext ){
  1368.     if( pNode->factory->IsA(cid) ) {
  1369.       *ppF = pNode->factory;
  1370.       (*ppF)->AddRef();
  1371.       break;
  1372.     }
  1373.   }
  1374.   return (*ppF) ? NOERROR : ResultFromScode(E_FAIL);
  1375. }
  1376.  
  1377.  
  1378. BOOL IsControlClass (REFCLSID rclsid, HKEY hKey)
  1379. {
  1380.   DWORD    dw;
  1381.   LONG     lRet;
  1382.   LPOLESTR lpszCLSID;
  1383.   char     lpszAnsiCLSID[256];
  1384.   char     szKey[64];
  1385.   char     szMiscStatus[_MAX_PATH];
  1386.   BOOL     bCloseRegDB = FALSE;
  1387.  
  1388.   if (hKey == NULL)
  1389.   {
  1390.  
  1391.    //Open up the root key.
  1392.    lRet=RegOpenKey(HKEY_CLASSES_ROOT, (LPCTSTR)"CLSID", &hKey);
  1393.  
  1394.    if ((LONG)ERROR_SUCCESS!=lRet)
  1395.      return FALSE;
  1396.  
  1397.    bCloseRegDB = TRUE;
  1398.   }
  1399.  
  1400.   // Get a string containing the class name
  1401.   StringFromCLSID(rclsid, &lpszCLSID);
  1402. #if defined(ANSI)    // MS_OLEUI_DEF
  1403.   WideCharToMultiByte (CP_ACP, 0, lpszCLSID, -1, lpszAnsiCLSID, 256, 
  1404.       NULL, NULL);
  1405.   strcpyA ((LPTSTR)szKey, (LPCTSTR)lpszAnsiCLSID);
  1406.   strcatA ((LPTSTR)szKey, (LPCTSTR)"\\Control");
  1407. #else
  1408.   lstrcpy((LPTSTR)szKey, (LPCTSTR)lpszCLSID);
  1409.   lstrcat((LPTSTR)szKey, (LPCTSTR)"\\Control");
  1410. #endif
  1411.  
  1412.   dw=_MAX_PATH;
  1413.   lRet = RegQueryValue(hKey, (LPCTSTR)szKey, (LPTSTR)szMiscStatus, (PLONG)&dw);
  1414.  
  1415.   OleStdFreeString(lpszCLSID, NULL);
  1416.   if (bCloseRegDB)
  1417.     RegCloseKey(hKey);
  1418.  
  1419.   if ((LONG)ERROR_SUCCESS!=lRet)
  1420.      return FALSE;
  1421.  
  1422.   return TRUE;
  1423.  
  1424. }
  1425.