home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 May / Pcwk5b98.iso / Borland / Cplus45 / BC45 / BOCOLE.PAK / BOLESVC.CPP < prev    next >
C/C++ Source or Header  |  1995-08-29  |  44KB  |  1,265 lines

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