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

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
  4. //
  5. // $Revision:   2.16  $
  6. //
  7. //  Implements the Bolero half of the OLE2 client site. BOlePart objects 
  8. //  impersonate the server object (IPart) from the point of view of the 
  9. //  Bolero customer who's writing a client site (ISite)
  10. //----------------------------------------------------------------------------
  11. #include "BOleSvc.h"
  12. #include "BOleDoc.h"
  13. #include "BOlePart.h"
  14. #include "BOleData.h"
  15. #include "BOleCMan.h"
  16.  
  17. #include "Ole2Ui.h"
  18.  
  19.  
  20. // MulDiv uses int; won't work with HIMETRIC values
  21. //
  22. inline int Scale(double src, long mult, long div)
  23. {
  24.   src *= mult;
  25.   src += (div/2); 
  26.   src /= div;
  27.   return (int) src;
  28. }
  29.  
  30. const OLECHAR szcBOlePart[] = OLESTR ("\3BOlePart");
  31.  
  32. // Since we don't know why Excel returns RPC_E_CALL_REJECTED the
  33. // first N times and then finally works, we have this kludge.
  34. //
  35. HRESULT ForceOleRun(IOleObject *pOO)
  36. {
  37.   int timeout = 500;
  38.   while (timeout-- > 0) {
  39.     if (ResultFromScode(RPC_E_CALL_REJECTED) != OleRun(pOO))
  40.       break;
  41.   }
  42.   return (timeout == 0) ? ResultFromScode(RPC_E_CALL_REJECTED) : NOERROR;
  43. }
  44.  
  45.  
  46. HRESULT _IFUNC BOlePart::QueryInterfaceMain(REFIID iid, LPVOID FAR *ppv)
  47. {
  48.   HRESULT hr = ResultFromScode(E_NOINTERFACE);
  49.   *ppv = NULL;
  50.  
  51.   // Self
  52.   //
  53.   if (iid == IID_BOlePart) {
  54.     (BOlePart*) *ppv = this;
  55.     AddRef ();
  56.     return NOERROR;
  57.   }
  58.  
  59.   // interfaces
  60.  
  61.      SUCCEEDED(hr = IOleInPlaceSite_QueryInterface(this, iid, ppv))
  62.   || SUCCEEDED(hr = IOleClientSite_QueryInterface(this, iid, ppv))
  63.   || SUCCEEDED(hr = IAdviseSink_QueryInterface(this, iid, ppv))
  64.  //       || SUCCEEDED(hr = IBPart_QueryInterface(this, iid, ppv))
  65.   || SUCCEEDED(hr = IBPart2_QueryInterface(this, iid, ppv))
  66.   || SUCCEEDED(hr = IBLinkable_QueryInterface(this, iid, ppv))
  67. #ifdef PART_DATA
  68.   || SUCCEEDED(hr = IPersist_QueryInterface(this, iid, ppv))
  69.   || SUCCEEDED(hr = IDataObject_QueryInterface(this, iid, ppv))
  70.   || SUCCEEDED(hr = IEnumFORMATETC_QueryInterface(this, iid, ppv))
  71. #endif
  72.   || SUCCEEDED(hr = IDropSource_QueryInterface(this, iid, ppv))
  73.   || (IsLink && SUCCEEDED(hr = IBLinkInfo_QueryInterface(this, iid, ppv)))
  74.  
  75.   // base classes
  76.  
  77.   || SUCCEEDED(hr = BOleComponent::QueryInterfaceMain(iid, ppv))
  78.  
  79.   ;
  80.  
  81.   return hr;
  82. };
  83.  
  84. //**************************************************************************
  85. //
  86. // BOlePart implementation -- functions which aren't part of any inherited
  87. //                            interface, but are just part of the private
  88. //                            implementation
  89. //
  90. //**************************************************************************
  91.  
  92. BOlePart::BOlePart (BOleClassManager *pF, IBUnknownMain * pO, 
  93.                                                 BOleDocument * pOD) :
  94.   BOleComponent(pF, pO),
  95.   pDoc (pOD),             pOleObject(NULLP),   pViewObject(NULLP),
  96.   pInPlaceObject(NULLP),  pSite (NULLP),       pVerbEnumerator(NULLP),
  97.   verbIndex(0),           dwDrawAspect (0),    IsOpen(FALSE),
  98.   HasMoniker(FALSE),      IsOpenInPlace(FALSE),IsOpenInsideOut(FALSE),
  99.   IsLink (FALSE),         pNextPart(NULLP),    pPrevPart (NULLP),
  100.   pLinkObject (NULLP),    dwExtAspect(0),      pStgFromInit(NULLP),
  101.   pDataObject (NULLP),    pEnumFE (NULLP),     MonikerAssigned(FALSE),
  102.   pILinkCont (0),         pszInstName (NULLP), pShortName (NULL),
  103.   pLongName (NULL),       pAppName (NULL),     fLinkSrcAvail(TRUE),
  104.   pDocument (NULL)
  105. {
  106.   if (pDoc)
  107.     pDoc->AddRefMain();
  108.  
  109.   oleVerb.lpszVerbName = NULLP;
  110.   mfpIcon = NULL;
  111.   CachedExtent.cx = CachedExtent.cy = 0;        
  112.   scaleSite.xN = 1L;
  113.   scaleSite.xD = 1L;
  114.   scaleSite.yN = 1L;
  115.   scaleSite.yD = 1L;
  116.   OLEPRINTF5("Initializing scaleSite:\t {%ld, %ld, %ld, %ld}",
  117.                 scaleSite.xN, scaleSite.xD, scaleSite.yN, scaleSite.yD);
  118. }
  119.  
  120.  
  121. BOlePart::~BOlePart()
  122. {
  123.   Close();  // just to be sure
  124.  
  125.   if (pszInstName) {
  126.     delete [] pszInstName;
  127.     pszInstName = NULLP;
  128.   }
  129.  
  130.   if (pDocument) {        // set in BOleContainer::GetObject
  131.     CoLockObjectExternal(pDocument, FALSE, FALSE);
  132.     pDocument = NULL;
  133.   }
  134.   DeleteTypeNames();
  135. }
  136.  
  137. void BOlePart::DeleteTypeNames ()
  138. {
  139.     // Delete any type names which were allocated in IOleObject::GetUserType
  140.   //
  141.   if (pLongName || pShortName || pAppName) {
  142.     LPMALLOC pMalloc = NULL;
  143.     HRESULT hr = ::CoGetMalloc (MEMCTX_TASK, &pMalloc);
  144.     if (SUCCEEDED(hr)) {
  145.       if (pShortName) {
  146.         if (pMalloc->DidAlloc(pShortName))
  147.           pMalloc->Free (pShortName);
  148.         pShortName = NULLP;
  149.       }
  150.       if (pAppName) {
  151.         if (pMalloc->DidAlloc(pAppName))
  152.           pMalloc->Free (pAppName);
  153.         pAppName = NULLP;
  154.       }
  155.       if (pLongName) {
  156.         if (pMalloc->DidAlloc(pLongName))
  157.           pMalloc->Free (pLongName);
  158.         pLongName = NULLP;
  159.       }
  160.       pMalloc->Release ();
  161.     }
  162.   }
  163. }
  164.  
  165. // Close -- Let go of all our connections to the server object
  166. //
  167. HRESULT _IFUNC BOlePart::Close()
  168. {
  169.   // We should let go of all server resources to allow the server to quit.
  170.   //
  171.   HRESULT hRes = NOERROR;
  172.  
  173.   RemoveFromList ();
  174.  
  175.   // Ask the server to close its document and exit its program
  176.   if (pOleObject) {
  177.     hRes = pOleObject->Close(OLECLOSE_SAVEIFDIRTY);
  178.     IsOpen = FALSE;
  179.   }
  180.  
  181.   if (pOleObject) {
  182.     pOleObject->Release();
  183.     pOleObject = NULL;
  184.   }
  185.   if (pViewObject) {
  186.     pViewObject->Release();
  187.     pViewObject = NULL;
  188.   }
  189.   if (pDataObject) {
  190.     pDataObject->Release();
  191.     pDataObject = NULL;
  192.   }
  193.   if (pEnumFE) {
  194.     pEnumFE = NULL;
  195.   }
  196.   if (pDoc) {
  197.     pDoc->ReleaseMain();  // dec count on helper
  198.     pDoc = NULL;
  199.   }
  200.   if (pLinkObject) {
  201.     pLinkObject->Release();
  202.     pLinkObject = NULL;
  203.   }
  204.   if (pStgFromInit) {
  205.     pStgFromInit->Release ();
  206.     pStgFromInit = NULL;
  207.   }
  208.  
  209.   // Required for AVI media stuff to release properly.
  210.   // And DLL servers
  211.   //
  212.   CoFreeUnusedLibraries();
  213.  
  214.   return hRes;
  215. }
  216.  
  217. BOOL _IFUNC BOlePart::InitAdvises(LPOLEOBJECT lpOleObject,
  218.           DWORD dwDrawAspect,
  219.           LPOLESTR lpszContainerApp,
  220.           LPOLESTR lpszContainerObj,
  221.           LPADVISESINK lpAdviseSink,
  222.           BOOL fCreate)
  223. {
  224.   LPVIEWOBJECT lpViewObject;
  225.   HRESULT hrErr;
  226.   BOOL fStatus = TRUE;
  227. #if defined( SPECIAL_CONTAINER )
  228.   DWORD dwTemp;
  229. #endif
  230.  
  231.   hrErr = lpOleObject->QueryInterface (IID_IViewObject,
  232.     (LPVOID FAR*)&lpViewObject);
  233.  
  234.   // Setup View advise
  235.   //
  236.   if (hrErr == NOERROR) {
  237.  
  238.     lpViewObject->SetAdvise(dwDrawAspect, (fCreate ? ADVF_PRIMEFIRST : 0),
  239.       lpAdviseSink);
  240.  
  241.     lpViewObject->Release();
  242.   } else
  243.     fStatus = FALSE;
  244.  
  245. #if defined( SPECIAL_CONTAINER )
  246.   /* Setup OLE advise.
  247.   **    OLE2NOTE: normally containers do NOT need to setup an OLE
  248.   **    advise. this advise connection is only useful for the OLE's
  249.   **    DefHandler and the OleLink object implementation. some
  250.   **    special container's might need to setup this advise for
  251.   **    programatic reasons.
  252.   **
  253.   **    NOTE: this advise will be torn down automatically by the
  254.   **    server when we release the object, therefore we do not need
  255.   **    to store the connection id.
  256.   */
  257.   hrErr = lpOleObject->Advise(lpAdviseSink, (DWORD FAR*)&dwTemp);
  258.   if (hrErr != NOERROR)
  259.     fStatus = FALSE;
  260. #endif
  261.  
  262.   // Setup the host names for the OLE object.
  263.   //
  264.   hrErr = lpOleObject->SetHostNames(lpszContainerApp,lpszContainerObj);
  265.   if (hrErr != NOERROR)
  266.     fStatus = FALSE;
  267.  
  268.   // Inform the loadded object's handler/inproc-server that it is in
  269.   //    its embedding container's process.
  270.   //
  271.   OleSetContainedObject(lpOleObject, TRUE);
  272.  
  273.   return fStatus;
  274. }
  275.  
  276. #ifdef __BORLANDC__ 
  277. #pragma option -Od
  278. #endif
  279.  
  280. HRESULT BOlePart::CreateFromBOleInitInfo(BOleInitInfo *pBI, BOOL &fShowAfterCreate)
  281. {
  282.   HRESULT hRes = ResultFromScode(E_INVALIDARG);
  283.   // another result code which can fail without causing Init to fail
  284.   HRESULT hrOkToFail;
  285.  
  286.   BOOL fIcon = pBI->hIcon != NULL;
  287.   DWORD dwRenderOpt = fIcon ? OLERENDER_NONE : OLERENDER_DRAW;
  288.  
  289.   dwDrawAspect = fIcon ? DVASPECT_ICON : DVASPECT_CONTENT;
  290.  
  291.   switch (pBI->Where) {
  292.     case BOLE_STORAGE: {
  293.  
  294.       // Load the OLE object's display aspect out of the stream we
  295.       // dumped it in. This is all we need to do in order to make
  296.       // drawing aspects persistent
  297.       //
  298.       LPSTREAM pStream;
  299.       if (SUCCEEDED (pStgFromInit->OpenStream (szcBOlePart, NULL,
  300.         STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pStream)))  {
  301.         ULONG cb;
  302.         pStream->Read (&dwDrawAspect, sizeof(dwDrawAspect), &cb);
  303.         if (dwDrawAspect == DVASPECT_ICON) {
  304.           fIcon = TRUE;
  305.           dwRenderOpt = OLERENDER_NONE;
  306.         }
  307.         if (!fIcon) {
  308.           pStream->Read (&scaleSite, sizeof(scaleSite), &cb);
  309.           OLEPRINTF5("Reading scaleSite:\t {%ld, %ld, %ld, %ld}",
  310.             scaleSite.xN, scaleSite.xD, scaleSite.yN, scaleSite.yD);
  311.           SIZE size;
  312.           size.cx = scaleSite.xD;     // server's extent's in Denom
  313.           size.cy = scaleSite.yD;
  314.  
  315.           if (!(size.cx == 1 && size.cy == 1))
  316.             // if scale factor exists,
  317.             // force the server to restore the extent from last time.
  318.  
  319.             // because Word doesn't put height back to what
  320.             // it was before. (they only load the width??)
  321.             SetPartSize(&size);
  322.         }
  323.         pStream->Release ();
  324.       }
  325.       // Load OLE object from container's file
  326.       //
  327.       hRes = OLE::OleLoad (pStgFromInit, IID_IOleObject, this, &(LPVOID)pOleObject);
  328.       if (hRes != NOERROR) 
  329.         break;
  330.  
  331.       // Don't activate OLE objects when loading container's file. If there
  332.       // are a bunch of objects, or if the server is a big app, performance
  333.       // would be severely degraded.
  334.       //
  335.  
  336.       DWORD status = 0;
  337.       fShowAfterCreate = FALSE;
  338.       IsOpenInsideOut = FALSE;
  339.       hrOkToFail = pOleObject->GetMiscStatus (dwDrawAspect, &status);
  340.       if (hrOkToFail == NOERROR) {
  341.         IsOpenInsideOut = (status & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)) ?
  342.             TRUE : FALSE;
  343.         fShowAfterCreate = (status & (OLEMISC_ACTIVATEWHENVISIBLE)) ?
  344.             TRUE : FALSE;
  345.       }
  346.       break;
  347.     }
  348.  
  349.     case BOLE_NEW_OCX:
  350.     case BOLE_NEW:
  351.       // Create the object and set its parent
  352.       hRes = BOleCreate (pBI, dwRenderOpt, &(LPVOID) pOleObject);
  353.       if (hRes != NOERROR) 
  354.         break;
  355.  
  356.       // Find out whether the object is inside out.
  357.       if (dwDrawAspect == DVASPECT_CONTENT) {
  358.         DWORD status = 0;
  359.  
  360.         // Cl2test is passing 0 and ignoring the
  361.         // error from Shapes. If I use the real aspect, outline returns
  362.         // that it's an inside-out object. Crazy.
  363.         //
  364.         hrOkToFail = pOleObject->GetMiscStatus (dwDrawAspect, &status);
  365.         if (hrOkToFail != NOERROR)
  366.           IsOpenInsideOut = FALSE;
  367.         else
  368.           IsOpenInsideOut = (status & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)) ?
  369.             TRUE : FALSE;
  370.       }
  371.       
  372.       break;
  373.  
  374.     case BOLE_FILE:
  375.  
  376.       if (pBI->How == BOLE_EMBED) {
  377.         hRes = OLE::OleCreateFromFile(CLSID_NULL, pBI->whereFile.pPath, IID_IOleObject,
  378.         dwRenderOpt, NULL, this, pStgFromInit, &(VOID FAR*)pOleObject);
  379.  
  380.         fShowAfterCreate = FALSE;
  381.       }
  382.       else {
  383.         hRes = OLE::OleCreateLinkToFile (pBI->whereFile.pPath, IID_IOleObject,
  384.           dwRenderOpt, NULL, this, pStgFromInit, &(VOID FAR*)pOleObject);
  385.  
  386.         // User should double-click to open link source. Showing the
  387.         // object here would bring up the server out-of-place, which
  388.         // would obscure the link we just created.
  389.         //
  390.         fShowAfterCreate = FALSE;
  391.       }
  392.       break;
  393.  
  394.     case BOLE_DATAOBJECT:
  395.  
  396.       if (pBI->How == BOLE_EMBED) {
  397.         hRes = OLE::OleCreateFromData (pBI->whereData.pData, IID_IOleObject,
  398.           OLERENDER_DRAW, NULL, this, pStgFromInit, &(VOID FAR*)pOleObject);
  399.  
  400.         // This is the result of a drop or a paste special. The UI
  401.         // convention is not to inplace activate the server
  402.         //
  403.         fShowAfterCreate = FALSE;
  404.       }
  405.       else if (pBI->How == BOLE_LINK) {
  406.  
  407.         hRes = OLE::OleCreateLinkFromData (pBI->whereData.pData, IID_IOleObject,
  408.           OLERENDER_DRAW, NULL, this, pStgFromInit, &(VOID FAR*)pOleObject);
  409.  
  410.         // User should double-click to open link source. Showing the
  411.         // object here would bring up the server out-of-place, which
  412.         // would obscure the link we just created.
  413.         //
  414.         fShowAfterCreate = FALSE;
  415.  
  416.       }
  417.       else {
  418.         hRes = OleCreateStaticFromData (pBI->whereData.pData, IID_IOleObject,
  419.           OLERENDER_DRAW, NULL, this, pStgFromInit, &(LPVOID) pOleObject);
  420.         fShowAfterCreate = FALSE;
  421.       }
  422.  
  423.  
  424.       // Get the drawing aspect for the object.
  425.       //
  426.       STGMEDIUM stgmed;
  427.       dwDrawAspect = fIcon ? DVASPECT_ICON : DVASPECT_CONTENT;
  428.       HGLOBAL memhandle = pDoc->pService->GetDataFromDataObject (
  429.         pBI->whereData.pData, BOleDocument::oleObjectDescFmt, NULL,
  430.         DVASPECT_CONTENT, &stgmed);
  431.       if (memhandle) {
  432.         LPOBJECTDESCRIPTOR objDesc = (LPOBJECTDESCRIPTOR) WIN::GlobalLock (memhandle);
  433.         if (objDesc->dwDrawAspect == DVASPECT_ICON)
  434.           dwDrawAspect = DVASPECT_ICON;
  435.         WIN::GlobalUnlock (memhandle);
  436.         OLE::ReleaseStgMedium (&stgmed);
  437.       }
  438.  
  439.       // Find out whether the object is inside out.
  440.       //
  441.       if (hRes == NOERROR)
  442.         if (dwDrawAspect == DVASPECT_CONTENT) {
  443.           DWORD status;
  444.           pOleObject->GetMiscStatus (dwDrawAspect, &status);
  445.           IsOpenInsideOut = (status & (OLEMISC_INSIDEOUT|OLEMISC_ACTIVATEWHENVISIBLE)) ?
  446.             TRUE : FALSE;
  447.         }
  448.       break;
  449.   }
  450.   if (SUCCEEDED(hRes) && !pOleObject)
  451.     hRes = ResultFromScode(E_NOINTERFACE);
  452.  
  453.   return hRes;
  454. }
  455.  
  456. HRESULT _IFUNC BOlePart::BOleCreate (BOleInitInfo *pBI, DWORD dwRenderOpt, 
  457.                                                       LPVOID FAR *ppv)
  458. {
  459.   return OLE::OleCreate (*(LPIID)pBI->whereNew.cid, IID_IOleObject, 
  460.         dwRenderOpt, NULL, this, pStgFromInit, &(LPVOID) pOleObject);
  461. }
  462.  
  463.  
  464. #ifdef __BORLANDC__
  465. #pragma option -O.
  466. #endif
  467.  
  468. // Init -- Create a new OLE2 server object. Probably the BOlePart helper
  469. //   has just been created, and it's time to initiate OLE2 transactions
  470. //
  471. HRESULT _IFUNC BOlePart::Init(IBSite * pIS,BOleInitInfo *pBI)
  472. {
  473.  
  474. #ifdef _DEBUG
  475.  
  476.   // Test to make sure client's QueryInterface is implemented correctly
  477.   //
  478.   IBSite *dbgSite = NULL;
  479.   LPOLECLIENTSITE dbgCSite = NULL;
  480.   if (  (!SUCCEEDED(pObjOuter->QueryInterfaceMain(IID_IBSite, &(LPVOID)dbgSite)))
  481.     || (!SUCCEEDED(pObjOuter->QueryInterfaceMain(IID_IOleClientSite,&(LPVOID)dbgCSite)))) {
  482.     MessageBox (NULL,
  483.       TEXT ("QueryInterface Aggregation isn\'t working right"),
  484.       TEXT ("BOlePart::Init"), MB_OK);
  485.   }
  486.   else {
  487.     dbgSite->Release();
  488.     dbgCSite->Release();
  489.     dbgSite = NULL;
  490.     dbgCSite = NULL;
  491.   }
  492.  
  493. #endif
  494.  
  495.  
  496.   pSite = pIS;
  497.  
  498.   if (pBI->pContainer) {
  499.     BOleDocument *oldDoc = pDoc;
  500.     if (!SUCCEEDED(pBI->pContainer->QueryInterface(IID_BOleDocument, &(LPVOID) pDoc)))
  501.       return ResultFromScode (E_NOINTERFACE);
  502.     pDoc->Release();  // PREVENT CYCLE
  503.  
  504.     // Since passing the container in the init info was added later, this
  505.     // makes the reference counting semantic on our BOleDocument pointer
  506.     // the same as is done in BOlePart::BOlePart and BOlePart::Close
  507.     //
  508.     pDoc->AddRefMain();       // AddRef the new doc from the init info
  509.     if (oldDoc)
  510.       oldDoc->ReleaseMain();  // Release the doc from the constructor
  511.  
  512.     pContainer = pBI->pContainer;
  513.   }
  514.   else
  515.     //  Only work if the caller is not a container/server
  516.     pContainer = pDoc->GetContainer();
  517.  
  518.   AddToList ();
  519.  
  520.   pStgFromInit = pBI->pStorage;
  521.   pStgFromInit->AddRef();
  522.  
  523.   HRESULT hRes = ResultFromScode (E_INVALIDARG);
  524.  
  525.   BOOL fShowAfterCreate = TRUE;
  526.  
  527.   for (int idx=0; idx < 42; idx++) {    // knock 42 times if you want Excel
  528.     if (ResultFromScode(RPC_E_CALL_REJECTED) !=
  529.       (hRes = CreateFromBOleInitInfo(pBI, fShowAfterCreate)))
  530.       break;
  531.   }
  532.  
  533.   if (!SUCCEEDED(hRes))
  534.     return hRes;
  535.  
  536.   // Do standard initialization on the freshly created object
  537.   // where pOleObject is valid
  538.  
  539.  
  540.   // If we have to draw as an icon, make sure the IOleCache in
  541.   // handler for this OLE object has an iconic representation
  542.   //
  543.   // If we're loading from storage, just run the usual advises
  544.   //
  545.   if (dwDrawAspect == DVASPECT_ICON && pBI->Where != BOLE_STORAGE) {
  546. #if 0
  547.     if (pBI->Where == BOLE_FILE)
  548.       mfpIcon = OleGetIconOfFile ((LPSTR)(pBI->whereFile.pPath), TRUE);
  549.     else {
  550.       OLECHAR buf[128] = {0,};
  551.       mfpIcon = OleGetIconOfClass (*(LPIID)pBI->whereNew.cid, buf, TRUE);
  552.     }
  553. #endif
  554.     mfpIcon = pBI->hIcon;
  555.     CacheIconicAspect (mfpIcon);
  556.     OnViewChange(dwDrawAspect, -1);
  557.   }
  558.   else {
  559.     IBApplication * pApplication = pDoc->pApplication;
  560.     InitAdvises (pOleObject, dwDrawAspect,
  561.       (LPOLESTR)pApplication->GetAppName(),
  562.       (LPOLESTR)pContainer->GetWindowTitle(), this, (pBI->Where != BOLE_STORAGE));
  563.     // <eho> This not getting called causes our part size to be {0,0}!!
  564.     OnViewChange(dwDrawAspect, -1);
  565.   }
  566.  
  567.   if (fShowAfterCreate && pContainer->GetWindow() && hRes == NOERROR)
  568.     hRes = DoVerb(OLEIVERB_SHOW);
  569.  
  570.   // Cache the view object interface for drawing later on
  571.   //
  572.   pOleObject->QueryInterface (IID_IViewObject, &(VOID FAR*)pViewObject);
  573.  
  574.   // Cache the data object interface for "embed from embedding"
  575.   //
  576.   pOleObject->QueryInterface (IID_IDataObject, &(VOID FAR*)pDataObject);
  577.  
  578.   // Cache the "user type name" for enumerating verbs later on
  579.   //
  580.   pOleObject->GetUserType (USERCLASSTYPE_SHORT, &pShortName);
  581.  
  582.   //      Ask the OLE object if it's a link, and cache the pointer if so
  583.   //
  584.   IsLink = SUCCEEDED(pOleObject->QueryInterface (IID_IOleLink, &(VOID FAR*) pLinkObject));
  585.  
  586.   DWORD status = 0;
  587.   pOleObject->GetMiscStatus (dwDrawAspect, &status);
  588.   if (status & (OLEMISC_ALWAYSRUN))
  589.     OleRun (pOleObject);
  590.  
  591.   return hRes;
  592. }
  593.  
  594. // Copies CF_EMBEDDEDOBJECT into a BOleData cache so we can do embed from
  595. // embedding with a snapshot of the embedded object. This allows the user to
  596. // change the original embedding and still paste the snapshot later.
  597. //
  598. HRESULT _IFUNC BOlePart::CopyFromOriginal (LPFORMATETC pFE, LPDATAOBJECT FAR*ppCopy)
  599. {
  600.  
  601.   *ppCopy = NULL;
  602.  
  603.   // Get the original object's IDataObject and IPersistStorage interfaces
  604.   // so we can write it into our cache. The server object must support
  605.   // these interfaces.
  606.   //
  607. #if 1
  608.   // We have to make sure that we DO need to know that this guy implements
  609.   // IDataObject, otherwise, just use the other branch
  610.   LPDATAOBJECT pOrig;
  611.   HRESULT hr = pOleObject->QueryInterface (IID_IDataObject, &(LPVOID) pOrig);
  612.   if (!SUCCEEDED(hr))
  613.     return hr;
  614.   LPPERSISTSTORAGE pPersistStg = NULL;
  615.   hr = pOrig->QueryInterface (IID_IPersistStorage, &(LPVOID) pPersistStg);
  616.   // JP: Now no longer use pOrig. Lets release it
  617.   pOrig->Release();
  618.   if (!SUCCEEDED(hr))
  619.     return hr;
  620. #else
  621.   HRESULT hr = pOleObject->QueryInterface( IID_IPersistStorage, &(LPVOID) pPersistStg);
  622.   if (!SUCCEEDED(hr))
  623.     return hr;
  624. #endif
  625.   // Create the data cache object which will hold the snapshots in as many
  626.   // formats as we need
  627.   //
  628.   LPUNKNOWN pObjDataCache = NULL;
  629.   hr = pFactory->ComponentCreate ((LPUNKNOWN FAR*)&pObjDataCache, NULL, cidBOleData);
  630.   if (!SUCCEEDED(hr))
  631.     return hr;
  632.   LPDATAOBJECT pIDataCache = NULL;
  633.   hr = pObjDataCache->QueryInterface (IID_IDataObject, &(LPVOID)pIDataCache);
  634.   pObjDataCache->Release(); //JP
  635.   pObjDataCache = NULL;
  636.  
  637.   if (!SUCCEEDED(hr))
  638.     return hr;
  639.  
  640.   // Create a temporary docfile which will hold the data
  641.   //
  642.   STGMEDIUM stm;
  643.   memset (&stm, 0, sizeof(STGMEDIUM));
  644.   stm.tymed = TYMED_ISTORAGE;
  645.   hr = ::StgCreateDocfile (NULL, STGM_TRANSACTED | STGM_READWRITE |
  646.     STGM_CREATE | STGM_SHARE_EXCLUSIVE | STGM_DELETEONRELEASE, 0, &stm.pstg);
  647.   if (!SUCCEEDED(hr))
  648.     return hr;
  649.  
  650.   // Save the original OLE server object into our temporary docfile
  651.   //
  652.   if (pPersistStg->IsDirty () == NOERROR) {
  653.     ::OleSave (pPersistStg, stm.pstg, FALSE);
  654.     pPersistStg->SaveCompleted (NULL);
  655.   }
  656.   else
  657.     pStgFromInit->CopyTo (0, NULL, NULL, stm.pstg);
  658.   pPersistStg->Release ();
  659.  
  660.   FORMATETC fe;
  661.   memset (&fe, 0, sizeof(FORMATETC));
  662.   fe.cfFormat = BOleDocument::oleEmbdObjClipFmt;
  663.   fe.ptd = NULL;
  664.   fe.dwAspect = dwDrawAspect;
  665.   fe.lindex = -1;
  666.   fe.tymed = TYMED_ISTORAGE;
  667.  
  668.   hr = pIDataCache->SetData (&fe, &stm, TRUE);
  669.   if (!SUCCEEDED(hr))
  670.     return hr; 
  671.  
  672.   stm.tymed = TYMED_HGLOBAL;
  673.   fe.cfFormat = BOleDocument::oleObjectDescFmt;
  674.   fe.tymed = TYMED_HGLOBAL;
  675.   POINTL unused = {0,0};
  676.   SIZEL unused2 = {0,0};
  677.   stm.hGlobal = OleStdGetObjectDescriptorDataFromOleObject (pOleObject,
  678.     NULL, dwDrawAspect, unused, &unused2);
  679.   hr = pIDataCache->SetData (&fe, &stm, TRUE);
  680.   if (!SUCCEEDED(hr))
  681.     return hr; 
  682.  
  683.   AddSiteData (pIDataCache);
  684.   AddCachedData( pIDataCache );
  685.  
  686.   // Setup linking formats for linking to embedding (if possible)
  687.   //
  688.   DWORD dwStat=0L;
  689.   pOleObject->GetMiscStatus (dwDrawAspect, &dwStat);
  690.   if (!(OLEMISC_CANTLINKINSIDE & dwStat)) // (says can't do in registry)
  691.     AddLinkSourceData (pIDataCache);
  692.  
  693.   *ppCopy = pIDataCache;
  694.   return NOERROR;
  695. }
  696.  
  697. HRESULT _IFUNC BOlePart::SwitchDisplayAspect(
  698.     LPOLEOBJECT   lpOleObj,
  699.     LPDWORD       lpdwCurAspect,
  700.     DWORD         dwNewAspect,
  701.     HGLOBAL       hMetaPict,
  702.     BOOL          fDeleteOldAspect,
  703.     BOOL          fSetupViewAdvise,
  704.     LPADVISESINK  lpAdviseSink,
  705.     BOOL FAR*     lpfMustUpdate,
  706.     BOOL          fRunIfNecessary
  707. )
  708. {
  709.   LPOLECACHE      lpOleCache = NULL;
  710.   LPVIEWOBJECT    lpViewObj = NULL;
  711.   LPENUMSTATDATA  lpEnumStatData = NULL;
  712.   STATDATA        StatData;
  713.   FORMATETC       FmtEtc;
  714.   STGMEDIUM       Medium;
  715.   DWORD           dwAdvf;
  716.   DWORD           dwNewConnection;
  717.   DWORD           dwOldAspect = *lpdwCurAspect;
  718.   HRESULT         hrErr;
  719.  
  720.   // This fixes a bug in the sample code: insert a shape as an icon,
  721.   // close sr2test, then convert the icon to content. They fail because
  722.   // the object isn't running. We run it if we need to. The fRunIfNecessary
  723.   // flag may be false if we're in SwitchDisplayAspect from Insert Object.
  724.   // Obviously, then the object doesn't need to be run.
  725.   //
  726.   BOOL fMustClose = FALSE;
  727.   if (fRunIfNecessary && !OLE::OleIsRunning(pOleObject)) {
  728.     OleRun (pOleObject);
  729.     fMustClose = TRUE;
  730.   }
  731.  
  732.   if (lpfMustUpdate)
  733.     *lpfMustUpdate = FALSE;
  734.  
  735.   lpOleObj->QueryInterface (IID_IOleCache, &(VOID FAR*) lpOleCache);
  736.  
  737.   // if IOleCache* is NOT available, do nothing
  738.   //
  739.   if (!lpOleCache)
  740.     return ResultFromScode(E_INVALIDARG);
  741.  
  742.   // Setup new cache with the new aspect
  743.   FmtEtc.cfFormat = NULL;     // whatever is needed to draw
  744.   FmtEtc.ptd      = NULL;
  745.   FmtEtc.dwAspect = dwNewAspect;
  746.   FmtEtc.lindex   = -1;
  747.   FmtEtc.tymed    = TYMED_NULL;
  748.  
  749.   // Icons shouldn't receive data advise connections. If they did, the
  750.   // metafile representation of the icon in the OLE cache would be lost.
  751.   //
  752.   if (dwNewAspect == DVASPECT_ICON && hMetaPict)
  753.     dwAdvf = ADVF_NODATA;
  754.   else
  755.     dwAdvf = ADVF_PRIMEFIRST;
  756.  
  757.   hrErr = lpOleCache->Cache(&FmtEtc, dwAdvf, &dwNewConnection);
  758.  
  759.   if (!SUCCEEDED(hrErr)) {
  760.     lpOleCache->Release();
  761.     return hrErr;
  762.   }
  763.  
  764.   *lpdwCurAspect = dwNewAspect;
  765.  
  766.   // Stuff the icon into the cache
  767.   //
  768.   if (dwNewAspect == DVASPECT_ICON && hMetaPict) {
  769.  
  770.     FmtEtc.cfFormat = CF_METAFILEPICT;
  771.     FmtEtc.ptd      = NULL;
  772.     FmtEtc.dwAspect = DVASPECT_ICON;
  773.     FmtEtc.lindex   = -1;
  774.     FmtEtc.tymed    = TYMED_MFPICT;
  775.  
  776.     Medium.tymed      = TYMED_MFPICT;
  777.     Medium.hGlobal    = hMetaPict;
  778.     Medium.pUnkForRelease   = NULL;
  779.  
  780.     hrErr = lpOleCache->SetData (&FmtEtc, &Medium, FALSE /* fRelease */);
  781.   } else {
  782.     if (lpfMustUpdate)
  783.       *lpfMustUpdate = TRUE;
  784.   }
  785.  
  786.   if (fSetupViewAdvise && lpAdviseSink) {
  787.     // re-establish the ViewAdvise connection
  788.     //
  789.     lpOleObj->QueryInterface (IID_IViewObject, &(VOID FAR*) lpViewObj);
  790.  
  791.     if (lpViewObj) {
  792.       lpViewObj->SetAdvise(dwNewAspect, 0, lpAdviseSink);
  793.       lpViewObj->Release();
  794.     }
  795.   }
  796.  
  797.   // Remove cached presentations for the ole display aspect
  798.   //
  799.   if (fDeleteOldAspect) {
  800.     hrErr = lpOleCache->EnumCache(&lpEnumStatData);
  801.  
  802.     while(hrErr == NOERROR) {
  803.       hrErr = lpEnumStatData->Next(1, &StatData, NULL);
  804.       if (hrErr != NOERROR)
  805.         break;        // DONE! no more caches.
  806.  
  807.       if (StatData.formatetc.dwAspect == dwOldAspect) {
  808.  
  809.         // Remove previous cache with old aspect
  810.         //
  811.         lpOleCache->Uncache(StatData.dwConnection);
  812.       }
  813.     }
  814.  
  815.     if (lpEnumStatData)
  816.       lpEnumStatData->Release();
  817.   }
  818.  
  819.   if (lpOleCache)
  820.     lpOleCache->Release();
  821.  
  822.   if (fMustClose)
  823.     pOleObject->Close (OLECLOSE_SAVEIFDIRTY);
  824.  
  825.   return NOERROR;
  826. }
  827.  
  828. BOOL _IFUNC BOlePart::CacheIconicAspect (HGLOBAL mfpIcon)
  829. {
  830.   BOOL fMustUpdate;
  831.   HRESULT hrErr = SwitchDisplayAspect (pOleObject, &dwDrawAspect,
  832.     DVASPECT_ICON, mfpIcon, FALSE, TRUE, this, &fMustUpdate, FALSE);
  833.  
  834.   //if (hrErr == NOERROR)
  835.     //hrErr = pOleObject->Update ();
  836.  
  837.   OleUIMetafilePictIconFree(mfpIcon);    // clean up metafile
  838.   return (hrErr == NOERROR);
  839. }
  840.  
  841. void BOlePart::AddToList ()
  842. {
  843.   // Insert "this" onto the list of part instances in this document.
  844.   //
  845.   // Avoid overhead by inserting the new part at the front of the list
  846.   // rather than searching for a null pNextPart. So the list is in
  847.   // first-in-last-out order
  848.   //
  849.   BOlePart *pOldFirstPart = pDoc->GetFirstPart ();
  850.   pDoc->SetFirstPart (this);
  851.   pNextPart = pOldFirstPart;
  852.   if (pOldFirstPart)
  853.     pOldFirstPart->pPrevPart = this;
  854. }
  855.  
  856. void BOlePart::RemoveFromList ()
  857. {
  858.   // Remove "this" from the list of part instances in this document.
  859.   //
  860.   // Standard list removal by joining the previous part with the next one
  861.   //
  862.   if (pPrevPart)
  863.     pPrevPart->pNextPart = pNextPart;
  864.   if (pNextPart)
  865.     pNextPart->pPrevPart = pPrevPart;
  866.  
  867.   if (pDoc)
  868.     pDoc->OnRemovePart (this);
  869.  
  870.   pNextPart = pPrevPart = NULLP;
  871. }
  872.  
  873. void BOlePart::SiteShow(BOOL show)
  874. {
  875.   BOOL doShow = show;
  876.   DWORD status = 0;
  877.   HRESULT hrOkToFail = pOleObject->GetMiscStatus (dwDrawAspect, &status);
  878.   if (hrOkToFail == NOERROR) {
  879.     if ((status & (OLEMISC_ACTIVATEWHENVISIBLE)) 
  880.                                             && IsOpenInPlace) // !DR try to avoid crash when 2 controls inserted
  881.       doShow = FALSE;
  882.   }
  883.   pSite->SiteShow (doShow);
  884. }
  885.  
  886. // ConvertHelper -- Helper function which is used in ConvertUI and
  887. //      ConvertGuts. The reason to have this function is
  888. //      because the user type and clsid must be known in
  889. //      both UI and guts, but it wouldn't be nice to put
  890. //      them in the BOleConvertInfo struct, which would
  891. //      otherwise be the best way to get dynamic scope.
  892. //
  893. HRESULT _IFUNC BOlePart::ConvertHelper (LPCLSID pCid,
  894.           LPOLESTR FAR* ppType,
  895.           WORD FAR* pwFormat)
  896. {
  897.   BOOL fHaveClsid = FALSE;
  898.   BOOL fHaveUserType = FALSE;
  899.   HRESULT hr = NOERROR;
  900.  
  901.   //
  902.   LPPERSISTSTORAGE pps = NULL;
  903.   pOleObject->QueryInterface (IID_IPersistStorage, &(LPVOID) pps);
  904.   pps->Save (pStgFromInit, TRUE);
  905.   pps->Release();
  906.  
  907.   hr = ReadClassStg (pStgFromInit, pCid);
  908.   if (SUCCEEDED(hr))
  909.     fHaveClsid = TRUE;
  910.  
  911.   hr = ReadFmtUserTypeStg (pStgFromInit, pwFormat, ppType);
  912.   if (SUCCEEDED(hr))
  913.     fHaveUserType = TRUE;
  914.  
  915.  
  916.  
  917.   if (!fHaveClsid) {
  918.     hr = pOleObject->GetUserClassID (pCid);
  919.     if (!SUCCEEDED(hr))
  920.       *pCid = CLSID_NULL;
  921.   }
  922.  
  923.   if (!fHaveUserType) {
  924.     OLECHAR szUserType[128];
  925.     *pwFormat = 0;
  926.     if (OleStdGetUserTypeOfClass(
  927.                           *pCid, szUserType, sizeof(szUserType), NULL)) {
  928.             //LPMALLOC pMalloc;     
  929.          //CoGetMalloc (MEMCTX_TASK, pMalloc); // get allocator
  930.       //*ppType = pMalloc->Alloc(128 * sizeof (OLECHAR));
  931.             //pMalloc->Release ();
  932.       *ppType = new OLECHAR[128];
  933. #if defined(WIN32)
  934.             lstrcpyW2 (*ppType, szUserType);
  935. #else
  936.       lstrcpy(*ppType, szUserType);
  937. #endif
  938.       
  939.             //*ppType = OleStdCopyString(szUserType, NULL); 
  940.     } else {
  941.       *ppType = NULL;
  942.     }
  943.   }
  944.   return hr;
  945. }
  946.  
  947.  
  948. // Bring up the Convert dialog box to give the user a chance to convert
  949. // or emulate the OLE object associated with this part.
  950. //
  951. // Convert is actually implemented here because most of the data needed
  952. // to do the conversion lives in the BOlePart not the BOleService
  953. //
  954. //
  955. HRESULT _IFUNC BOlePart::ConvertUI (PIBApplication pHelpApp, BOOL f, BOleConvertInfo FAR *pInfo)
  956. {
  957.   HRESULT hr = NOERROR;
  958.  
  959.   memset (pInfo, 0, sizeof(BOleConvertInfo));
  960.  
  961.   OLEUICONVERT ouc;
  962.   LPOLESTR DefLabel = NULL;
  963.   LPOLESTR UserType = NULL;
  964.   TCHAR    temp [255];
  965.  
  966.   memset (&ouc, 0, sizeof (ouc));
  967.   ouc.cbStruct = sizeof (ouc);
  968.   if (pDoc->pService->ShowHelpButton (BOLE_HELP_CONVERT))
  969.     ouc.dwFlags = CF_SHOWHELPBUTTON;
  970.   ouc.hWndOwner = ::GetActiveWindow();    // pHelpApp->GetWindow();
  971.   ouc.fIsLinkedObject = IsLink;
  972.   ouc.dvAspect = dwDrawAspect;
  973.  
  974.   if (IsLink) {
  975.     hr = pLinkObject->GetSourceDisplayName (&DefLabel);
  976. #if defined(ANSI) // MS_OLEUI_DEF
  977.     WideCharToMultiByte (CP_ACP, 0, DefLabel, lstrlen(DefLabel), 
  978.                       temp, 255, 0, 0);
  979.     ouc.lpszDefLabel = temp;
  980. #else
  981.     ouc.lpszDefLabel = DefLabel;
  982. #endif
  983.     hr = pOleObject->GetUserClassID (&ouc.clsid);
  984.   }
  985.   else {
  986.     ConvertHelper (&ouc.clsid, &UserType, &ouc.wFormat);
  987. #if defined(ANSI)   // MS_OLEUI_DEF
  988.     WideCharToMultiByte (CP_ACP, 0, UserType, -1 /*lstrlen(UserType)*/, 
  989.                       temp, 255, 0, 0);
  990.     ouc.lpszUserType = temp;
  991. #else
  992.     ouc.lpszUserType = UserType;
  993. #endif
  994.   }
  995.  
  996.   STGMEDIUM medium;
  997.   if (dwDrawAspect == DVASPECT_ICON)
  998.     ouc.hMetaPict = OleStdGetData (pDataObject, CF_METAFILEPICT, NULL,
  999.       DVASPECT_ICON, &medium);
  1000.   else
  1001.     ouc.hMetaPict = NULL;
  1002.  
  1003. #ifndef WIN32  // MS_OLEUI_DEF  EnterBOleDialog
  1004.   ouc.dwIBApplication = (DWORD) pHelpApp;
  1005.   pDoc->pService->EnterBOleDialog (ouc.hWndOwner, &ouc.hHook, &ouc.hTask);
  1006. #else
  1007.   pDoc->pService->EnterBOleDialog (ouc.hWndOwner, NULL, NULL);
  1008. #endif
  1009.   UINT uRet = OleUIConvert (&ouc);
  1010.   pDoc->pService->ExitBOleDialog ();
  1011.  
  1012.   // If the user clicked OK, look at the dialog settings to see what
  1013.   // we should set in the output BOleConvertInfo.
  1014.   //
  1015.   if (uRet == OLEUI_OK) {
  1016.  
  1017.     if (ouc.dwFlags & CF_SELECTCONVERTTO && !IsEqualCLSID (ouc.clsid, ouc.clsidNew)) {
  1018.       (int) pInfo->action |= BOLE_CONVERT_TO_CLSID;
  1019.       pInfo->clsidNew = ouc.clsidNew;
  1020.     }
  1021.  
  1022.     if (ouc.dwFlags & CF_SELECTACTIVATEAS) {
  1023.       (int) pInfo->action |= BOLE_ACTIVATE_AS_CLSID;
  1024.       pInfo->clsidNew = ouc.clsidNew;
  1025.     }
  1026.  
  1027.     if (ouc.dvAspect != dwDrawAspect || ouc.fObjectsIconChanged) {
  1028.       if (ouc.dvAspect == DVASPECT_ICON) {
  1029.         (int) pInfo->action |= BOLE_ASPECT_TO_ICON;
  1030.         pInfo->hIcon = ouc.hMetaPict;
  1031.       }
  1032.       else
  1033.         (int) pInfo->action |= BOLE_ASPECT_TO_CONTENT;
  1034.     }
  1035.   }
  1036.  
  1037.   if (DefLabel) {
  1038.     LPMALLOC pMalloc;
  1039.       CoGetMalloc( MEMCTX_TASK, &pMalloc );
  1040.       pMalloc->Free (DefLabel);
  1041.     pMalloc->Release();
  1042.   }
  1043.  
  1044.   // If the user clicked Cancel or clicked OK, but didn't actually do
  1045.   // anything, we would get here with the action bitfield cleared.
  1046.   //
  1047.   // Return S_FALSE to indicate that the BOleConvertInfo is not valid,
  1048.   // and we shouldn't call ConvertGuts
  1049.   //
  1050.   if (pInfo->action == (BOleConvertAction) 0)
  1051.     hr = ResultFromScode (S_FALSE);
  1052.   else
  1053.     hr = ResultFromScode (S_OK);
  1054.   return hr;
  1055.  
  1056. }
  1057.  
  1058. HRESULT _IFUNC BOlePart::ConvertGuts (BOOL b, BOleConvertInfo FAR *pInfo)
  1059. {
  1060.   BOOL fMustActivate = FALSE;
  1061.   BOOL fMustRun = FALSE;
  1062.   BOOL fObjConverted = TRUE;
  1063.  
  1064.   HRESULT hr = NOERROR;
  1065.  
  1066.   // This could be a while
  1067.   //
  1068.   HCURSOR hPrevCursor = ::SetCursor (::LoadCursor (NULL, IDC_WAIT));
  1069.  
  1070.   CLSID cid = CLSID_NULL;
  1071.   LPOLESTR pType = NULL;
  1072.   WORD wFormat = 0;
  1073.   ConvertHelper (&cid, &pType, &wFormat);
  1074.  
  1075.   // User selected Convert To
  1076.   //
  1077.   if (pInfo->action & BOLE_CONVERT_TO_CLSID) {
  1078.     LPSTORAGE pTmpStg = pStgFromInit; pTmpStg->AddRef();// will be released in Close
  1079.     BOleDocument *pTmpDoc = pDoc; pTmpDoc->AddRefMain();
  1080.     Close ();
  1081.     pDoc = pTmpDoc;
  1082.     pStgFromInit = pTmpStg;
  1083.     DeleteTypeNames();
  1084.     hr = OleStdDoConvert (pStgFromInit, pInfo->clsidNew);
  1085.     if (!SUCCEEDED (hr))
  1086.       goto error;
  1087.     hr = OLE::OleLoad (pStgFromInit, IID_IOleObject, this, &(LPVOID)pOleObject);
  1088.     fMustRun = TRUE;
  1089.     fObjConverted = TRUE;
  1090.  
  1091.     InitAdvises (pOleObject, dwDrawAspect,
  1092.       (LPOLESTR)pDoc->pApplication->GetAppName(),
  1093.       (LPOLESTR)pContainer->GetWindowTitle(), this, FALSE);
  1094.  
  1095.   }
  1096.  
  1097.   // User selected Activate As
  1098.   //
  1099.   if (pInfo->action & BOLE_ACTIVATE_AS_CLSID) {
  1100.     LPSTORAGE pTmpStg = pStgFromInit; pTmpStg->AddRef();// will be released in Close
  1101.     BOleDocument *pTmpDoc = pDoc; pTmpDoc->AddRefMain();
  1102.     Close ();
  1103.     pDoc = pTmpDoc;
  1104.     pStgFromInit = pTmpStg;
  1105.     DeleteTypeNames();
  1106.  
  1107.     pDoc->pService->UnloadObjects (cid);
  1108.     hr = OleStdDoTreatAsClass (pType, cid, pInfo->clsidNew);
  1109.     hr = OLE::OleLoad (pStgFromInit, IID_IOleObject, this, &(LPVOID)pOleObject);
  1110.     fMustActivate = TRUE;
  1111.   }
  1112.  
  1113.   // We'll want to draw this object later on
  1114.   //
  1115.   if (pOleObject) {
  1116.     if (pViewObject)
  1117.       pViewObject->Release();
  1118.     pOleObject->QueryInterface (IID_IViewObject, &(LPVOID) pViewObject);
  1119.     if (pDataObject)
  1120.       pDataObject->Release();
  1121.     pOleObject->QueryInterface (IID_IDataObject, &(VOID FAR*)pDataObject);
  1122.   }
  1123.  
  1124.   // If we're switching to icon, don't check the curr aspect because
  1125.   // we could be switching between icons.
  1126.   //
  1127.   if (pInfo->action & BOLE_ASPECT_TO_ICON) {
  1128.  
  1129.     // Special thing for scripting: if you ask for an object to be converted
  1130.     // to an icon from script/macro, you probably don't have an HMETAPICT
  1131.     // for the icon, so we let them pass 0 as a sentinel, and we use a
  1132.     // default icon for the CLSID
  1133.     //
  1134.     if (pInfo->hIcon == 0) {
  1135.       pInfo->hIcon = OleGetIconOfClass (cid, NULL, TRUE);
  1136.     }
  1137.  
  1138.     // Don't delete the old aspect if we're switching from one icon
  1139.     // to another. Otherwise, deleting the old aspect depends on whether
  1140.     // we're activating the object
  1141.     //
  1142.     BOOL fDeleteOld;
  1143.     if (dwDrawAspect == DVASPECT_ICON)
  1144.       fDeleteOld = FALSE;
  1145.     else
  1146.       fDeleteOld = !b;
  1147.  
  1148.     hr = SwitchDisplayAspect (pOleObject, &dwDrawAspect, DVASPECT_ICON,
  1149.       pInfo->hIcon, fDeleteOld, TRUE, this, &fMustRun, TRUE);
  1150.     if (SUCCEEDED(hr)) {
  1151.       OnViewChange(DVASPECT_ICON, -1);
  1152.     }
  1153.   }
  1154.  
  1155.   // Switching to content aspect
  1156.   //
  1157.   if (dwDrawAspect == DVASPECT_ICON && pInfo->action & BOLE_ASPECT_TO_CONTENT) {
  1158.     hr = SwitchDisplayAspect (pOleObject, &dwDrawAspect, DVASPECT_CONTENT,
  1159.       NULL, !b, TRUE, this, &fMustRun, TRUE);
  1160.     if (SUCCEEDED(hr)) {
  1161.       OnViewChange(DVASPECT_CONTENT, -1);
  1162.     }
  1163.   }
  1164.  
  1165.   if (fMustRun) {
  1166.     if (!fMustActivate && !OLE::OleIsRunning (pOleObject)) {
  1167.       hr = OleRun (pOleObject);
  1168.       if (!SUCCEEDED(hr))
  1169.         return hr;
  1170.  
  1171.       if (fObjConverted) {
  1172.  
  1173.         // Of course, static objects can't be run. This isn't an
  1174.         // error to be worried about
  1175.         //
  1176.         if (hr == ResultFromScode (OLE_E_STATIC)) {
  1177.           Close();
  1178.           pStgFromInit->Revert ();
  1179.           return hr; 
  1180.         }
  1181.         else {
  1182.           // The object probably already has an OLERENDER_DRAW cache,
  1183.           // but this is just to make sure.
  1184.           //
  1185.           LPOLECACHE pCache = NULL;
  1186.           hr = pOleObject->QueryInterface (IID_IOleCache, &(LPVOID) pCache);
  1187.           if (SUCCEEDED(hr)) {
  1188.             FORMATETC fe;
  1189.             DWORD newCnxn;
  1190.             fe.cfFormat = NULL;
  1191.             fe.ptd = NULL;
  1192.             fe.dwAspect = DVASPECT_CONTENT;
  1193.             fe.lindex = -1;
  1194.             fe.tymed = TYMED_NULL;
  1195.             pCache->Cache (&fe, ADVF_PRIMEFIRST, &newCnxn);
  1196.             pCache->Release();
  1197.           }
  1198.         }
  1199.         // Force the storage to be committed
  1200.         //
  1201.         pOleObject->Close (OLECLOSE_SAVEIFDIRTY);
  1202.  
  1203.       }
  1204.     }
  1205.   }
  1206.  
  1207.   pSite->Invalidate(BOLE_INVAL_VIEW);
  1208.   if (fMustActivate)
  1209.     DoVerb (OLEIVERB_PRIMARY);
  1210. error:
  1211.  
  1212.  
  1213.   ::SetCursor (hPrevCursor);
  1214.   return hr;
  1215. }
  1216.  
  1217. void _IFUNC BOlePart::ResetObjectRects ()
  1218. {
  1219.   RECT pos, clip;
  1220.   OLEPRINTF1("Entering ResetObjectRects");
  1221.   if (NOERROR == pSite->GetSiteRect (&pos, &clip)) {
  1222.     OLEPRINTF3("GettingSiteRect:\t {%d, %d}",
  1223.            pos.right - pos.left, pos.bottom - pos.top);
  1224.     pInPlaceObject->SetObjectRects (&pos, &clip);
  1225.   }
  1226. }
  1227.  
  1228. //**************************************************************************
  1229. //
  1230. // IPart implementation
  1231. //
  1232. //**************************************************************************
  1233.  
  1234. HRESULT _IFUNC BOlePart::Save (IStorage * pStg, BOOL fSameAsLoad, BOOL fRemember)
  1235. {
  1236.   HRESULT ret = NOERROR;
  1237.   // Get a pointer to the Ole object's IPersistStorage
  1238.   if (pOleObject) {
  1239.     IPersistStorage* pPersistStg;
  1240.     HRESULT hr = pOleObject->QueryInterface(IID_IPersistStorage,
  1241.       &(VOID FAR *)pPersistStg);
  1242.     if (SUCCEEDED(hr) && !pPersistStg)
  1243.       ret = ResultFromScode (E_FAIL);
  1244.     else {
  1245.  
  1246.       // Write the object out to storage.
  1247.       //
  1248.       ret = OLE::OleSave(pPersistStg, pStg, fSameAsLoad);
  1249.  
  1250.       // Write the object's drawing aspect out to storage so we know
  1251.       // which presentation data to use when we reload it. OleSave
  1252.       // already knows how to save the iconic presentation data to storage
  1253.       //
  1254.       // Also write out the additional scale factor for the size
  1255.       // imposed when the user resized the size.
  1256.       //
  1257.  
  1258.       LPSTREAM pStream = NULLP;
  1259.  
  1260.       if (SUCCEEDED(pStg->CreateStream(szcBOlePart,
  1261.         STGM_WRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE,
  1262.         NULL,NULL,&pStream)))  {
  1263.         ULONG cb;
  1264.         pStream->Write(&dwDrawAspect, sizeof(dwDrawAspect), &cb);
  1265.         if (!(dwDrawAspect == DVASPECT_ICON)) {
  1266.           OLEPRINTF5("Saving scaleSite:\t {%ld, %ld, %ld, %ld}",
  1267.                  scaleSite.xN, scaleSite.xD, scaleSite.yN, scaleSite.yD);
  1268.           pStream->Write(&scaleSite, sizeof(scaleSite), &cb);
  1269.         }
  1270.         pStream->Release();
  1271.       }
  1272.  
  1273.       if (fRemember) {
  1274. #if 0     // not used in outline example or mfc source
  1275.         // for SaveAs case release initial storage and remember new one
  1276.         pPersistStg->HandsOffStorage();  // server releases initial storage
  1277. #endif
  1278.         pPersistStg->SaveCompleted ( pStg );
  1279.         if (pStgFromInit)
  1280.           pStgFromInit->Release();
  1281.         pStgFromInit = pStg;
  1282.         pStgFromInit->AddRef();
  1283.       }
  1284.       else {
  1285.         pPersistStg->SaveCompleted ( NULL );
  1286.       }
  1287.       pPersistStg->Release();
  1288.     }
  1289.  
  1290.   }
  1291.   return ret;
  1292. }
  1293.  
  1294. HRESULT _IFUNC BOlePart::CanOpenInPlace ()
  1295. {
  1296.   // this is only used in our server code
  1297.   return ResultFromScode(E_FAIL);
  1298. }
  1299.  
  1300. HRESULT _IFUNC BOlePart::GetPalette (LPLOGPALETTE FAR *ppPal)
  1301. {
  1302.   if (pViewObject) {
  1303.     HRESULT hrErr = pViewObject->GetColorSet (
  1304.       dwDrawAspect, -1, NULL, NULL, NULL, ppPal);
  1305.     if (hrErr == NOERROR)
  1306.       return hrErr;
  1307.   }
  1308.  
  1309.   return ResultFromScode (E_FAIL);
  1310.  
  1311. }
  1312.  
  1313. HRESULT _IFUNC BOlePart::SetHost (IBContainer FAR *pNewContainer)
  1314. {
  1315.   if (!pNewContainer)
  1316.     return ResultFromScode (E_FAIL);
  1317.  
  1318.   BOleDocument *pNewDoc = NULL;
  1319.   if (!SUCCEEDED(pNewContainer->QueryInterface(IID_BOleDocument, &(LPVOID) pNewDoc)))
  1320.     return ResultFromScode (E_NOINTERFACE);
  1321.   pNewDoc->Release();    // PREVENT CYCLE
  1322.  
  1323.   if (IsOpenInPlace)
  1324.     return ResultFromScode (E_FAIL);
  1325.  
  1326.   if (pNewDoc->pActivePart)
  1327.     // Need to change pActivePart to a BOlePart* to
  1328.     // we can call Activate (FALSE) here.
  1329.     //
  1330.     return ResultFromScode (E_FAIL);
  1331.  
  1332.  
  1333.   RemoveFromList ();
  1334.   if (pDoc) {
  1335.     pDoc->ReleaseMain();
  1336.     pDoc = NULLP;
  1337.   }
  1338.   if (pNewDoc) {
  1339.     pDoc = pNewDoc;
  1340.     pDoc->AddRefMain();     // directly on helper
  1341.     pContainer = pNewContainer;
  1342.   }
  1343.   AddToList ();
  1344.   return NOERROR;
  1345. }
  1346.  
  1347. HRESULT _IFUNC BOlePart::Open (BOOL bOpen)
  1348. {
  1349.   if (bOpen) {
  1350.     HRESULT hRes = DoVerb(OLEIVERB_OPEN);
  1351.     pSite->Invalidate(BOLE_INVAL_VIEW); // ? do we need this (ICS)
  1352.     return hRes;
  1353.   }
  1354.   else {
  1355.     return pOleObject->DoVerb(OLEIVERB_HIDE, NULL, this, 0,
  1356.       pContainer->GetWindow(), (LPRECT) 0);
  1357.   }
  1358. }
  1359.  
  1360. HRESULT _IFUNC BOlePart::Show (BOOL bShow)
  1361. {
  1362.   if (bShow) {
  1363.     HRESULT hRes = DoVerb(OLEIVERB_SHOW);
  1364.     pSite->Invalidate(BOLE_INVAL_VIEW); // ? do we need this (ICS)
  1365.     return hRes;
  1366.   }
  1367.   else {
  1368.     return pOleObject->DoVerb(OLEIVERB_HIDE, NULL, this, 0,
  1369.       pContainer->GetWindow(), (LPRECT) 0);
  1370.   }
  1371.  
  1372. }
  1373.  
  1374.  
  1375. HRESULT _IFUNC BOlePart::Activate (BOOL fActivate)
  1376. {
  1377.   HRESULT hr = NOERROR;
  1378.  
  1379.   if (fActivate) {
  1380.     hr = DoVerb (OLEIVERB_PRIMARY);
  1381.   }
  1382.   else
  1383.     if (IsOpenInPlace) {
  1384.       hr = pInPlaceObject->UIDeactivate ();
  1385.  
  1386. #if 1    
  1387.       if (hr == NOERROR)
  1388.         if (IsOpenInsideOut) {
  1389.           hr = pOleObject->DoVerb (OLEIVERB_DISCARDUNDOSTATE, NULL,
  1390.             this, 0, pContainer->GetWindow(), (LPRECT) 0);
  1391.           // if DISCARDUNDOSTATE is not implemented who cares!
  1392.           if (hr == ResultFromScode(E_NOTIMPL))
  1393.               hr = NOERROR;
  1394.         }
  1395.         else {
  1396.           if (pInPlaceObject)
  1397.             hr = pInPlaceObject->InPlaceDeactivate ();
  1398.         }
  1399. #endif
  1400.     }
  1401.  
  1402.   return hr;
  1403. }
  1404.  
  1405. HWND _IFUNC BOlePart::OpenInPlace (HWND hWndParent)
  1406. {
  1407.   // this is meaningful only in our server code
  1408.   return 0;
  1409. }
  1410.  
  1411. HRESULT _IFUNC BOlePart::SetPartSize (LPSIZE pSize)
  1412. {
  1413.   SIZEL sl;
  1414.   sl.cx = MAP_PIX_TO_LOGHIM (pSize->cx, BOleService::pixPerIn.x);
  1415.   sl.cy = MAP_PIX_TO_LOGHIM (pSize->cy, BOleService::pixPerIn.y);
  1416.  
  1417.   // Size passed is in scaled units but we need to tell the server
  1418.   // its "actual size"
  1419.   //
  1420.   BOleScaleFactor scale;
  1421.   pSite->GetZoom(&scale);
  1422.   sl.cx = Scale(sl.cx, scale.xD, scale.xN);    // unscale
  1423.   sl.cy = Scale(sl.cy, scale.yD, scale.yN);
  1424.  
  1425.   // IOleObject::SetExtent only works if the object is running.
  1426.   // If not, we need to cache the extent locally and pass it on to the
  1427.   // object when it opens.
  1428.   //
  1429.   if (!pOleObject || !OLE::OleIsRunning(pOleObject)) {
  1430.  
  1431.     // If the object's MISCSTATUS specifies that it wants to be run
  1432.     // whenever we resize it, do so here
  1433.     //
  1434.     DWORD miscStatus = 0;
  1435.     if (pOleObject &&
  1436.       (NOERROR == pOleObject->GetMiscStatus(dwDrawAspect, &miscStatus)))
  1437.       if (miscStatus & OLEMISC_RECOMPOSEONRESIZE)
  1438.         if (NOERROR == ForceOleRun (pOleObject))
  1439.           return pOleObject->SetExtent (dwDrawAspect, &sl);
  1440.  
  1441.     // Cache the size of the nonrunning object
  1442.     //
  1443.     CachedExtent = sl;
  1444.     return NOERROR;
  1445.  
  1446.   }
  1447.  
  1448.   // Set the size of the running object
  1449.   //
  1450.   HRESULT hr = pOleObject->SetExtent (dwDrawAspect, &sl);
  1451.   return hr;
  1452. }
  1453.  
  1454. HRESULT _IFUNC BOlePart::GetPartSize (LPSIZE pSize)
  1455. {
  1456.   if (!pSize)
  1457.     return ResultFromScode (E_INVALIDARG);
  1458.  
  1459.   SIZEL sl;
  1460.  
  1461.   // get himetric size and convert it to pixels
  1462.   // also adjust for scaling
  1463.   // we can give it to SetPartPos and Extent
  1464.   //
  1465.   HRESULT hr = pOleObject->GetExtent(dwDrawAspect, &sl);
  1466.   if (SUCCEEDED(hr)) {
  1467.  
  1468.     // If we've cached a modified extent for the object, inform the object
  1469.     // now that it's running.
  1470.     //
  1471.     if (CachedExtent.cx) {
  1472.       if ((sl.cx == CachedExtent.cx) && (sl.cy == CachedExtent.cy)) {
  1473.         CachedExtent.cx = 0L;
  1474.       }
  1475.       else {
  1476.         if (SUCCEEDED(pOleObject->SetExtent (dwDrawAspect, &CachedExtent))) {
  1477.           hr = pOleObject->GetExtent(dwDrawAspect, &sl);
  1478.           CachedExtent.cx = 0L;
  1479.         }
  1480.       }
  1481.     }
  1482.  
  1483.  
  1484.     pSize->cx = MAP_LOGHIM_TO_PIX (sl.cx, BOleService::pixPerIn.x);
  1485.     pSize->cy = MAP_LOGHIM_TO_PIX (sl.cy, BOleService::pixPerIn.y);
  1486.  
  1487.     BOleScaleFactor scale;
  1488.     pSite->GetZoom(&scale);
  1489.     pSize->cx = Scale(pSize->cx, scale.xN, scale.xD);
  1490.     pSize->cy = Scale(pSize->cy, scale.yN, scale.yD);
  1491.   }
  1492.   else {
  1493.     OLEPRINTF1("Entering GetPartSize failure case");
  1494.     // if the server isn't ready to return the size we should use the sites
  1495.     RECT rPos, rClip;
  1496.     pSite->GetSiteRect(&rPos, &rClip);
  1497.     OLEPRINTF3("GettingSiteRect:\t {%d, %d}",
  1498.            rPos.right - rPos.left, rPos.bottom - rPos.top);
  1499.     pSize->cx = rPos.right - rPos.left;
  1500.     pSize->cy = rPos.bottom - rPos.top;
  1501.   }
  1502.   return hr;
  1503. }
  1504.  
  1505. HRESULT _IFUNC BOlePart::SetPartPos (LPRECT pNewSize)
  1506. {
  1507.   HRESULT hr = ResultFromScode (E_FAIL);
  1508.  
  1509.   OLEPRINTF1("Entering SetPartPos");
  1510.   // If we're open in place, we can actually change the location of the
  1511.   // object's in-place window. Used for scrolling
  1512.   //
  1513.   if (IsOpenInPlace) {
  1514.     RECT pos, clip;
  1515.     if (NOERROR == pSite->GetSiteRect (&pos, &clip))  {
  1516.     hr = pInPlaceObject->SetObjectRects ((LPCRECT)pNewSize, &clip);
  1517.     OLEPRINTF3("SettingObjectRects:\t {%d, %d}",
  1518.        pNewSize->right - pNewSize->left,
  1519.        pNewSize->bottom - pNewSize->top);
  1520.     }
  1521.   }
  1522.  
  1523.   // If we're not open in place, we can only change the extent of the
  1524.   // object, and the rectangles should be right in the next IPart::Draw
  1525.   //
  1526.   else {
  1527.     SIZE s;
  1528.     s.cx = pNewSize->right - pNewSize->left;
  1529.     s.cy = pNewSize->bottom - pNewSize->top;
  1530.     SetPartSize(&s);
  1531.   }
  1532.  
  1533.   return hr;
  1534. }
  1535.  
  1536. inline BOOL IsMetafile(HDC hdc)
  1537. {
  1538.   return (DT_METAFILE == GetDeviceCaps(hdc,TECHNOLOGY));
  1539. }
  1540.  
  1541. HRESULT _IFUNC BOlePart::Draw (HDC hdc, LPCRECTL pPosRect, LPCRECTL pClipRect,
  1542.              BOleAspect reqAspect, BOleDraw bdFlags)
  1543. {
  1544.   int oldDCInfo = WIN::SaveDC (hdc);
  1545.  
  1546.  
  1547.   HRESULT hRes = ResultFromScode (E_FAIL);
  1548.  
  1549.   // If you're drawing objects, but not using the metafile to get it,
  1550.   // you'd get the high-res graphics data yourself, but you still need to
  1551.   // draw the open-editing shading. Hence this flag.
  1552.   //
  1553.   if (bdFlags & BOLE_DRAW_SHADINGONLY) {
  1554.     hRes = NOERROR;
  1555.     goto shadingOnly;
  1556.   }
  1557.  
  1558.   // If this object is a link, make sure we're bound to it just in case
  1559.   // someone else has opened the link source and makes changes to it. This
  1560.   // will force those changes to be propogated to us
  1561.   //
  1562.   if (IsLink) {
  1563.     DWORD linkopts = 0;
  1564.     if (SUCCEEDED(pLinkObject->GetUpdateOptions (&linkopts)))
  1565.       if (linkopts & OLEUPDATE_ALWAYS)
  1566.         pLinkObject->BindIfRunning();
  1567.   }
  1568.  
  1569.   // Remove the special Bolero aspect values from the bitfield
  1570.   // so those values don't show through when we send the aspect
  1571.   // to OLE2. OLE2 will return OLE_E_BLANK for non-standard values
  1572.   //
  1573.   dwExtAspect = 0; // Clear this out so caller can use different settings each time through
  1574.   if (reqAspect & BOLE_DEFAULT)
  1575.     dwExtAspect = dwExtAspect | BOLE_DEFAULT;
  1576.   else
  1577.     dwDrawAspect = reqAspect;
  1578.   if (reqAspect & BOLE_ASPECT_MAINTAIN)
  1579.     dwExtAspect = dwExtAspect | BOLE_ASPECT_MAINTAIN;
  1580.   if (reqAspect & BOLE_CLIP)
  1581.     dwExtAspect = dwExtAspect | BOLE_CLIP;
  1582.  
  1583.   reqAspect = (reqAspect & ~(BOLE_ASPECT_MAINTAIN | BOLE_DEFAULT | BOLE_CLIP));
  1584.  
  1585.   if (pViewObject) {
  1586.     RECTL hmRect = *pPosRect;
  1587.  
  1588.     // Get the part's extents in himetric
  1589.     SIZEL srvExt;
  1590.     HRESULT hr = pOleObject->GetExtent(dwDrawAspect, &srvExt);
  1591.     if (SUCCEEDED(hr)) {
  1592.       // scale part's extents by client's scale factor
  1593.       BOleScaleFactor scale;
  1594.       pSite->GetZoom(&scale);
  1595.       srvExt.cx = Scale(srvExt.cx, scale.xN, scale.xD);
  1596.       srvExt.cy = Scale(srvExt.cy, scale.yN, scale.yD);
  1597.     }
  1598.     else {
  1599.       OLEPRINTF1("Couldn't GetExtent during draw");
  1600.       // if server's extent isn't available, use what's passed in
  1601.       srvExt.cx = hmRect.right - hmRect.left;
  1602.       srvExt.cy = hmRect.bottom - hmRect.top;
  1603.     }
  1604.  
  1605. #if 1
  1606.     if (dwExtAspect & BOLE_ASPECT_MAINTAIN) {
  1607.       // Scale the rect we draw into if either the x extent or the y extent
  1608.       // overflows. The resulting rect is in the upper left corner of the client.
  1609.       SIZEL cliExt;
  1610.       cliExt.cx = hmRect.right - hmRect.left;
  1611.       cliExt.cy = hmRect.bottom - hmRect.top;
  1612.  
  1613.       //
  1614.       long dx, dy;
  1615.       dx = cliExt.cx - srvExt.cx;
  1616.       dy = cliExt.cy - srvExt.cy;
  1617.       if (dx >= 0 && dy >= 0) {
  1618.         // We have enough room, both x and y, to display the object
  1619.         hmRect.right = hmRect.left + srvExt.cx;
  1620.         hmRect.bottom = hmRect.top + srvExt.cy;
  1621.       }
  1622.       else {
  1623.         // Either the x or y extent is too large. Decide which axis overflows
  1624.         // more, and leave it the same size as the client, which is its
  1625.         // maximum value. Then scale the axis which overflows less (maybe not
  1626.         // at all) to maintain the server's aspect ratio
  1627.         //
  1628.         if (dx < dy)
  1629.           hmRect.bottom = hmRect.top + Scale(srvExt.cy, cliExt.cx, srvExt.cx);
  1630.         else
  1631.           hmRect.right = hmRect.left + Scale(srvExt.cx, cliExt.cy, srvExt.cy);
  1632.       }
  1633.     }
  1634. #endif
  1635.  
  1636.     if (dwExtAspect & BOLE_CLIP) {
  1637.       hmRect.right = hmRect.left + srvExt.cx;
  1638.       hmRect.bottom = hmRect.top + srvExt.cy;
  1639.     }
  1640.     // Ask the server object to draw itself.
  1641.     //
  1642.     hRes = pViewObject->Draw(dwDrawAspect, -1, NULL,  NULL,
  1643.       NULL, hdc, &hmRect, IsMetafile(hdc) ? pClipRect : NULL,
  1644.       NULL, 0);
  1645.   }
  1646.   else {
  1647.     WIN::RestoreDC (hdc, oldDCInfo);
  1648.     return ResultFromScode (E_FAIL);
  1649.   }
  1650.  
  1651. shadingOnly:
  1652.  
  1653.   RECT r;
  1654.   r.top = pPosRect->top;
  1655.   r.left = pPosRect->left;
  1656.   r.bottom = pPosRect->bottom;
  1657.   r.right = pPosRect->right;
  1658.  
  1659.   // If the server app has the embedded object open in its own window,
  1660.   // as opposed to inplace in our window, draw special highlighting
  1661.   //
  1662.   if (IsOpen) {
  1663.     OUI::OleUIDrawShading(&r, hdc, OLEUI_SHADE_FULLRECT, 0);
  1664.   }
  1665.  
  1666.   // If the app wants us to draw the borders around OLE2 objects as
  1667.   // described in the OLE2 UI guidelines, do it here.
  1668.   //
  1669.   if (bdFlags & BOLE_DRAW_SHOWOBJECTS) {
  1670.     int penStyle = IsLink ? PS_DASH : PS_SOLID;
  1671.     HPEN p = CreatePen (penStyle, 1, RGB(0,0,0));
  1672.     HBRUSH b = (HBRUSH) GetStockObject (HOLLOW_BRUSH);
  1673.     HPEN oldP = (HPEN) SelectObject (hdc,p);
  1674.     HBRUSH oldB = (HBRUSH) SelectObject (hdc,b);
  1675.     Rectangle (hdc, ( int )r.left, ( int )r.top,
  1676.       ( int )( r.right - r.left ),
  1677.       ( int )( r.bottom - r.top ) );
  1678.     SelectObject (hdc, oldP);
  1679.     SelectObject (hdc, oldB);
  1680.     DeleteObject (p);
  1681.     DeleteObject (b);
  1682.   }
  1683.  
  1684.   WIN::RestoreDC (hdc, oldDCInfo);
  1685.   return hRes;
  1686. }
  1687.  
  1688. HRESULT _IFUNC BOlePart::InsertMenus (HMENU, BOleMenuWidths*)
  1689. {
  1690.   // this is meaningful only in our server code
  1691.   return ResultFromScode (E_NOTIMPL);
  1692. }
  1693.  
  1694. void _IFUNC BOlePart::FrameResized (const RECT *, BOOL)
  1695. {
  1696.   // this is meaningful only in our server code
  1697. }
  1698.  
  1699. HRESULT _IFUNC BOlePart::ShowTools (BOOL)
  1700. {
  1701.   // this is meaningful only in our server code
  1702.    return ResultFromScode (E_NOTIMPL);
  1703. }
  1704.  
  1705. HRESULT _IFUNC BOlePart::EnumVerbs (BOleVerb *pBV)
  1706. {
  1707.   // The purpose of verbIndex is to keep track of the enumerator in
  1708.   // here rather than forcing the Bolero user to do it. It is assumed
  1709.   // that the Bolero user will call EnumVerbs until it fails, otherwise
  1710.   // the enumerator will be left in an incoherent state
  1711.  
  1712.   // The strategy for pVerbEnumerator is different than other interfaces.
  1713.   // Usually, we just get a pointer to it during IPart::Init and hang on
  1714.   // to the pointer until the Part is destroyed. In this case, the verb
  1715.   // enumerator could be made invalid by closing the server app. Then
  1716.   // the Next function returns RPC_E_SERVERDIED. It seems that OLE2, probably
  1717.   // in the default handler, provides another enumerator which can get
  1718.   // the verbs, probably from the registration database, when the
  1719.   // server isn't running. So we'll obtain and release the pointer
  1720.   // dynamically.
  1721.  
  1722.   // The lpszVerbName field in the OLEVERB is dynamically allocated during
  1723.   // IEnumVerb::Next. In order to prevent a memory leak, deallocate it here.
  1724.   // The DidAlloc is probably unnecessary, but it's a little protection
  1725.   // against the user passing in a pBV->verbName which is just a random
  1726.   // value off the stack.
  1727.   //
  1728.   if (pBV->verbName) {
  1729.     LPMALLOC pMalloc = NULL;
  1730.     HRESULT hr = ::CoGetMalloc (MEMCTX_TASK, &pMalloc);
  1731.     if (!SUCCEEDED(hr))
  1732.       return hr;
  1733.     if (!IsBadReadPtr ((LPVOID) pBV->verbName, 4) &&
  1734.       pMalloc->DidAlloc ((LPVOID) pBV->verbName)) {
  1735.       pMalloc->Free ((LPVOID) pBV->verbName);
  1736.       pBV->verbName = NULL;
  1737.     }
  1738.     pMalloc->Release ();
  1739.   }
  1740.  
  1741.   if (verbIndex == 0) {
  1742.     HRESULT hr = pOleObject->EnumVerbs(&pVerbEnumerator);
  1743.  
  1744.     if (hr != NOERROR)
  1745.       return hr;
  1746.  
  1747.     pVerbEnumerator->Reset ();
  1748.   }
  1749.  
  1750.   // Loop over verbs looking for non-negative verb numbers. The negative
  1751.   // ones are "aliases" for other verbs, and shouldn't be displayed
  1752.   //
  1753.   // The loop stops when Next returns an error, but loops over alias
  1754.   // verbs. EnumVerbs should be called in a loop by the user
  1755.   //
  1756.   SCODE sc;
  1757.   ULONG  temp = 0L;
  1758.   while (TRUE) {
  1759.     sc = GetScode(pVerbEnumerator->Next (1, &oleVerb, &temp));
  1760.     if (sc == S_OK) {
  1761.       if (oleVerb.lVerb > -1) {
  1762.         pBV->verbName = oleVerb.lpszVerbName;
  1763.         pBV->typeName = GetName (BOLE_NAME_SHORT);
  1764.         pBV->verbIndex = oleVerb.lVerb;
  1765.         pBV->fCanDirty = !(oleVerb.grfAttribs & OLEVERBATTRIB_NEVERDIRTIES);
  1766.         verbIndex++;
  1767.         return NOERROR;
  1768.       }
  1769.       else {
  1770.           // free the string coming from Next, if any
  1771.               if (oleVerb.lpszVerbName) {
  1772.                 LPMALLOC pMalloc = NULL;
  1773.                 HRESULT hr = ::CoGetMalloc (MEMCTX_TASK, &pMalloc);
  1774.                 if (!SUCCEEDED(hr))
  1775.                   return hr;
  1776.                 if (!IsBadReadPtr ((LPVOID) oleVerb.lpszVerbName, 4) &&
  1777.                   pMalloc->DidAlloc ((LPVOID) oleVerb.lpszVerbName)) {
  1778.                   pMalloc->Free ((LPVOID) oleVerb.lpszVerbName);
  1779.                 }
  1780.                 pMalloc->Release ();
  1781.               }
  1782.       }
  1783.     }
  1784.     else {
  1785.       verbIndex = 0;
  1786.       pVerbEnumerator->Release ();
  1787.       return ResultFromScode (sc);
  1788.     }
  1789.   }
  1790. }
  1791.  
  1792. HRESULT _IFUNC BOlePart::DoVerb (UINT whichVerb)
  1793. {
  1794.   ForceOleRun(pOleObject);    // this line only added for Excel problems
  1795.  
  1796.   // Ask the container/app again for their names, in case something
  1797.   // is different from the last time we were open editing.
  1798.   //
  1799.   pOleObject->SetHostNames (pDoc->pApplication->GetAppName(),
  1800.     pDoc->pContainer->GetWindowTitle());
  1801.  
  1802.   RECT rect;
  1803.   pSite->GetSiteRect (&rect, 0);
  1804.   HRESULT hRes = pOleObject->DoVerb((LONG) (int)whichVerb, NULL, this, 0,
  1805.     pContainer->GetWindow(), &rect);
  1806.  
  1807.   if( !SUCCEEDED( hRes ) ){
  1808.     // This following (potentially big) block will deserve a helper function.
  1809.     // So far, only ONE error is implemented. Need to be completed.
  1810.     // Reference: outline/cntrline.c: ContainerLine_ProcessOleRunError()
  1811.     //
  1812.     SCODE error = GetScode( hRes );
  1813.     if ((error >= MK_E_FIRST && error <= MK_E_LAST) ||
  1814.        (error == OLE_E_CANT_BINDTOSOURCE)) {
  1815.       HandleLinkError();
  1816.       fLinkSrcAvail = FALSE;
  1817.     }
  1818.     if( error == REGDB_E_CLASSNOTREG ){
  1819.       // Server not registered (unexpected here?)
  1820.     }
  1821.     if( error == OLE_E_STATIC ){
  1822.       // A static object with no server registered
  1823.     }
  1824.     if( error == OLE_E_CLASSDIFF ){
  1825.       // Type of link has changed
  1826.     }
  1827.     if( ( error == CO_E_APPDIDNTREG )||( error == CO_E_APPNOTFOUND ) ){
  1828.       // Server not found
  1829.     }
  1830.     if( error == E_OUTOFMEMORY ){
  1831.       // Out of memory
  1832.     }
  1833.     return hRes;
  1834.   }
  1835.  
  1836.   HWND hWnd, hWndPrevParented;
  1837.   if (IsOpenInPlace && pInPlaceObject &&
  1838.     SUCCEEDED(pInPlaceObject->GetWindow(&hWnd)) &&
  1839.     SUCCEEDED(GetWindow(&hWndPrevParented))) {
  1840.     while (hWnd && GetParent(hWnd) != hWndPrevParented) {
  1841.       hWnd = GetParent(hWnd);  // make sure its the window they parented
  1842.     }
  1843.     if (hWnd && hWnd != GetTopWindow(GetParent(hWnd))) {
  1844.       SetWindowPos(hWnd, HWND_TOP, 0,0,0,0,   // MSWORD z-order workaround
  1845.         SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
  1846.       LONG l = GetWindowLong(hWnd, GWL_STYLE);  // visio paint problems
  1847.       SetWindowLong(hWnd, GWL_STYLE ,l | WS_CLIPSIBLINGS);  // visio paint problems
  1848.     }
  1849.   }
  1850.  
  1851.   return hRes;
  1852. }
  1853.  
  1854. HRESULT _IFUNC BOlePart::DragFeedback(POINT*,BOOL)
  1855. {
  1856.   return ResultFromScode (E_NOTIMPL);
  1857. }
  1858.  
  1859. UINT _IFUNC BOlePart::CountFormats ()
  1860. {
  1861. #if 0
  1862.   LPENUMFORMATETC enumFormatEtc;
  1863.   UINT n = 0;
  1864.  
  1865.   if( pDataObject && SUCCEEDED( pDataObject->EnumFormatEtc( DATADIR_GET, &enumFormatEtc ) ) ){
  1866.     FORMATETC fmt;
  1867.     while( enumFormatEtc->Next( 1, &fmt, 0 ) == NOERROR )
  1868.       n++;
  1869.     enumFormatEtc->Release();
  1870.   }
  1871.   return n;
  1872. #else
  1873.   return 0;
  1874. #endif
  1875. }
  1876.  
  1877. HRESULT _IFUNC BOlePart::GetFormat ( UINT i, BOleFormat *BOleFmt )
  1878. {
  1879. #if 0
  1880.   LPENUMFORMATETC enumFormatEtc;
  1881.  
  1882.   if( pDataObject && SUCCEEDED( pDataObject->EnumFormatEtc( DATADIR_GET, &enumFormatEtc ) ) ){
  1883.     FORMATETC fmt;
  1884.     while( enumFormatEtc->Next( 1, &fmt, 0 ) != NOERROR && i-- );
  1885.     memset( BOleFmt, 0, sizeof( *BOleFmt ) );
  1886.     BOleFmt->fmtId = fmt.cfFormat;
  1887.     BOleFmt->fmtMedium = ( BOleMedium )fmt.tymed;
  1888.     enumFormatEtc->Release();
  1889.   }
  1890.   return NOERROR;
  1891. #else
  1892.   return ResultFromScode (E_NOTIMPL);
  1893. #endif
  1894. }
  1895.  
  1896. HANDLE  _IFUNC BOlePart::GetFormatData (BOleFormat*pF)
  1897. {
  1898.   LPDATAOBJECT pDataObj = NULL;
  1899.   if (!pOleObject)
  1900.     assert (FALSE);
  1901.  
  1902.   HRESULT hr = pOleObject->QueryInterface (IID_IDataObject, &(void FAR*) pDataObj);
  1903.  
  1904.   if (!pDataObj || !SUCCEEDED(hr))
  1905.     return NULL;
  1906.  
  1907.   STGMEDIUM medium;
  1908.  
  1909.   // Just change it to WORD in boledefs.h please
  1910.   HANDLE h = pDoc->pService->GetDataFromDataObject (pDataObj,
  1911.     (CLIPFORMAT)pF->fmtId, NULL, dwDrawAspect, &medium);
  1912.  
  1913.   pDataObj->Release ();
  1914.  
  1915.   return h;
  1916. }
  1917.  
  1918. // Set data into the server
  1919. //
  1920. HRESULT  _IFUNC BOlePart::SetFormatData(BOleFormat* fmt, HANDLE hData, BOOL release)
  1921. {
  1922.   if (!fmt || !hData)
  1923.     return ResultFromScode(DATA_E_FORMATETC);
  1924.  
  1925.   LPDATAOBJECT pIData;
  1926.   HRESULT hr = pOleObject->QueryInterface (IID_IDataObject, &(LPVOID) pIData);
  1927.   if (!SUCCEEDED(hr))
  1928.     return hr;
  1929.  
  1930.   STGMEDIUM stm;
  1931.   memset (&stm, 0, sizeof(STGMEDIUM));
  1932.   stm.tymed = TYMED_ISTORAGE;
  1933.  
  1934.   FORMATETC fe;
  1935.   memset (&fe, 0, sizeof(FORMATETC));
  1936.   fe.cfFormat = fmt->fmtId;
  1937.   fe.ptd = NULL;
  1938.   fe.dwAspect = DVASPECT_CONTENT;
  1939.   fe.lindex = -1;
  1940.   fe.tymed = TYMED_HGLOBAL;
  1941.  
  1942.   return pIData->SetData (&fe, &stm, release);
  1943. }
  1944.  
  1945.  
  1946. LPOLESTR _IFUNC BOlePart::GetName (BOlePartName nameCode)
  1947. {
  1948.   // First see if we've already retrieved this name, and return
  1949.   // it without asking again
  1950.   //
  1951.   LPOLESTR FAR *ppName = NULL;
  1952.   switch (nameCode) {
  1953.     case BOLE_NAME_LONG  : ppName = &pLongName; break;
  1954.     case BOLE_NAME_SHORT : ppName = &pShortName; break;
  1955.     case BOLE_NAME_APP   : ppName = &pAppName; break;
  1956.     default        : return NULL;
  1957.   }
  1958.  
  1959.   if (*ppName)
  1960.     return *ppName;
  1961.  
  1962.   if (!pOleObject)
  1963.     return NULL;
  1964.  
  1965.   // Ask the OLE object for the name. GetUserType will allocate space
  1966.   // in our IMalloc, so we don't have to allocate it again. Of course,
  1967.   // we will have to free it later.
  1968.   //
  1969.   HRESULT hr = pOleObject->GetUserType (nameCode, ppName);
  1970.  
  1971.   if (!SUCCEEDED(hr) || !(*ppName))
  1972.     return NULL;
  1973.  
  1974.   return *ppName;
  1975. }
  1976.  
  1977. HRESULT _IFUNC BOlePart::DoQueryInterface(REFIID iid, void FAR* FAR* pif)
  1978. {       return (pOleObject) ?
  1979.     pOleObject->QueryInterface(iid, pif)
  1980.     : ResultFromScode(E_NOINTERFACE);
  1981. }
  1982.  
  1983. #undef  OLE_INTERFACE
  1984. /**************************************************************************/
  1985. #define OLE_INTERFACE "IOleClientSite"
  1986.  
  1987. HRESULT _IFUNC BOlePart::SaveObject ()
  1988. {
  1989.   if (!pStgFromInit)
  1990.     return ResultFromScode(E_NOTIMPL);
  1991.  
  1992.   return Save(pStgFromInit, TRUE, FALSE);
  1993. }
  1994.  
  1995. IMoniker * _IFUNC BOlePart::GetObjectMoniker(DWORD dwAssign)
  1996. {
  1997.   IMoniker* pMoniker = NULL;
  1998.   if (pszInstName) {
  1999.  
  2000.     switch (dwAssign) {
  2001.       case OLEGETMONIKER_FORCEASSIGN:
  2002.         OLE::CreateItemMoniker (OLESTR("!"), pszInstName, &pMoniker);
  2003.         if (pOleObject && !MonikerAssigned) {
  2004.           pOleObject->SetMoniker(OLEWHICHMK_OBJREL, pMoniker);
  2005.           MonikerAssigned = TRUE;
  2006.         }
  2007.         break;
  2008.       case OLEGETMONIKER_TEMPFORUSER:
  2009.         OLE::CreateItemMoniker (OLESTR("!"), pszInstName, &pMoniker);
  2010.         break;
  2011.       case OLEGETMONIKER_ONLYIFTHERE:
  2012.         if (MonikerAssigned) {
  2013.           OLE::CreateItemMoniker (OLESTR("!"), pszInstName, &pMoniker);
  2014.         }
  2015.         break;
  2016.       case OLEGETMONIKER_UNASSIGN:
  2017.         MonikerAssigned = FALSE;
  2018.         break;
  2019.     }
  2020.   }
  2021.   return pMoniker;
  2022. }
  2023.  
  2024. HRESULT _IFUNC BOlePart::GetMoniker (DWORD dwAssign, DWORD dwWhichMoniker, IMoniker* FAR* ppmk)
  2025. {
  2026.   *ppmk = NULL;
  2027.   if (pILinkCont) {
  2028.     switch (dwWhichMoniker) {
  2029.  
  2030.       // Identifies the document within the filesystem
  2031.       case OLEWHICHMK_CONTAINER:
  2032.         pILinkCont->GetMoniker(ppmk);
  2033.         break;
  2034.  
  2035.       // Identifies the object relative to the document
  2036.       case OLEWHICHMK_OBJREL:
  2037.         *ppmk = GetObjectMoniker(dwAssign);
  2038.         break;
  2039.  
  2040.       // Identifies the doc and object absolutely
  2041.       case OLEWHICHMK_OBJFULL:
  2042.         LPMONIKER pmkDoc;
  2043.         LPMONIKER pmkObj;
  2044.         if (SUCCEEDED(pILinkCont->GetMoniker(&pmkDoc))) {
  2045.           pmkObj = GetObjectMoniker(dwAssign);
  2046.           if (pmkObj) {
  2047.             CreateGenericComposite(pmkDoc, pmkObj, ppmk);
  2048.             pmkDoc->Release();
  2049.             pmkObj->Release();
  2050.           }
  2051.         }
  2052.         break;
  2053.     }
  2054.   }
  2055.   return ResultFromScode((*ppmk) ? S_OK : E_FAIL);
  2056. }
  2057.  
  2058. HRESULT _IFUNC BOlePart::GetContainer (IOleContainer* FAR* ppContainer)
  2059. {
  2060.   return pDoc->QueryInterface(IID_IOleContainer, (LPVOID*)ppContainer);
  2061. }
  2062.  
  2063. HRESULT _IFUNC BOlePart::ShowObject ()
  2064. {
  2065.   if (!IsOpenInPlace)
  2066.     SiteShow (TRUE);
  2067.   return NOERROR;
  2068. }
  2069.  
  2070. HRESULT _IFUNC BOlePart::OnShowWindow (BOOL fShow)
  2071. {
  2072.   // The server app calls OnShowWindow when it believes we should draw
  2073.   // or redraw the open-editing shading over the object. To cut down on
  2074.   // the noise, only Invalidate if the new state is different.
  2075.   //
  2076.   if (fShow != IsOpen) {
  2077.     IsOpen = fShow;
  2078.     pSite->Invalidate(BOLE_INVAL_VIEW);
  2079.   }
  2080.   return NOERROR;
  2081. }
  2082.  
  2083. HRESULT _IFUNC BOlePart::RequestNewObjectLayout ()
  2084. {
  2085.   // The OUTLINE test app says OLE doesn't use this function yet.
  2086.   // The OLE docs say it can be called if the server needs more or less
  2087.   //   room in the client, but that the client can ignore the request if
  2088.   //       the client wants to determine the amount of available real estate
  2089.   //
  2090.   return ResultFromScode (E_NOTIMPL);
  2091. }
  2092.  
  2093. //*************************************************************************
  2094. //
  2095. // ILinkInfo implementation
  2096. //
  2097. //*************************************************************************
  2098.  
  2099. HRESULT _IFUNC BOlePart::SourceBreak()
  2100. {
  2101.   if (!pLinkObject)
  2102.     return ResultFromScode (E_FAIL);
  2103.  
  2104.   // Break the link by setting its moniker to NULL
  2105.   //
  2106.   HRESULT hrErr = pLinkObject->SetSourceMoniker ((LPMONIKER)NULL, CLSID_NULL);
  2107.   if (SUCCEEDED(hrErr)) {
  2108.     IsLink = FALSE;
  2109.     pLinkObject->Release();
  2110.     pLinkObject = NULL;
  2111.   }
  2112.  
  2113.   // Release all the pointers we have on this OLE object in preparation
  2114.   // for creating a new object. We might also delete the part, but it seems
  2115.   // rude to do that while the user still has a refcount on us.
  2116.   //
  2117.   //Close ();
  2118.  
  2119.   // Create a static object in place of the current link object
  2120.   //
  2121.   IDataObject *dataObj = NULL;
  2122.   hrErr = pOleObject->QueryInterface (IID_IDataObject, &(VOID FAR*)dataObj);
  2123.   if (hrErr != NOERROR)
  2124.     return hrErr;
  2125.  
  2126.   FORMATETC fe;
  2127.   LPFORMATETC pFE;
  2128.   DWORD render;
  2129.   if (dwDrawAspect == DVASPECT_ICON) {
  2130.     // If the link we're breaking is displayed as an icon, we'll have to
  2131.     // display the static picture as content
  2132.     //
  2133.     fe.tymed = TYMED_NULL;
  2134.     fe.ptd = NULL;
  2135.     fe.lindex = -1;
  2136.     fe.dwAspect = DVASPECT_ICON;
  2137.     fe.cfFormat = 0;
  2138.     pFE = &fe;
  2139. //        dwDrawAspect = DVASPECT_CONTENT;
  2140.   }
  2141.   else {
  2142.     pFE = NULL;
  2143.   }
  2144.  
  2145.   render = OLERENDER_DRAW;
  2146.  
  2147.   pOleObject->Release(); 
  2148.  
  2149.   hrErr = OLE::OleCreateStaticFromData (dataObj, IID_IOleObject, render,
  2150.     pFE, this, pStgFromInit, &(LPVOID)pOleObject);
  2151.  
  2152.   if (dataObj) {
  2153.     dataObj->Release ();
  2154.     dataObj = NULL;
  2155.   }
  2156.  
  2157.   return NOERROR;
  2158. }
  2159.  
  2160. HRESULT _IFUNC BOlePart::SourceGet(LPOLESTR FAR szOut, UINT count)
  2161. {
  2162.   if (!pOleObject || !pLinkObject)
  2163.     return ResultFromScode (E_FAIL);
  2164.  
  2165.   LPOLESTR pDisplayName;
  2166.   DWORD len;
  2167.  
  2168.  
  2169.   HRESULT hr = pLinkObject->GetSourceDisplayName (&pDisplayName);
  2170.   if (SUCCEEDED (hr)) {
  2171.     lstrcpyn( szOut, pDisplayName, count );
  2172.     IMalloc *pMalloc;
  2173.     if (SUCCEEDED(CoGetMalloc(MEMCTX_TASK, &pMalloc))) {
  2174.       pMalloc->Free(pDisplayName);
  2175.       pMalloc->Release();
  2176.     }
  2177.   }
  2178.   return hr;
  2179. }
  2180.  
  2181. HRESULT _IFUNC BOlePart::SourceSet (LPOLESTR pNewSrc)
  2182. {
  2183.   if (!pLinkObject)
  2184.     return ResultFromScode (E_FAIL);
  2185.  
  2186.   HRESULT hrErr = NOERROR;
  2187.   LPMONIKER pMk = NULLP;
  2188.   CLSID clsid   = CLSID_NULL;
  2189.   LPBC bindCtx  = NULLP;
  2190.  
  2191.  
  2192.   // Create a new bind context to use for these monikers
  2193.   //
  2194.   hrErr = OLE::CreateBindCtx (0 /*unused*/, &bindCtx);
  2195.   if (hrErr != NOERROR)
  2196.     return hrErr;
  2197.  
  2198.   // Recursively resolve this textual representation into a binary moniker
  2199.   //
  2200.   DWORD chEaten = 0;
  2201.   hrErr = OLE::MkParseDisplayName (bindCtx, pNewSrc, &chEaten, &pMk);
  2202.   if (hrErr != NOERROR) {
  2203.     bindCtx->Release ();
  2204.     return hrErr;
  2205.   }
  2206.  
  2207.   // Obtain the CLSID of the object the moniker points to by using
  2208.   // a pointer to the IOleObject as a middleman
  2209.   //
  2210.   LPOLEOBJECT pObj = NULLP;
  2211.   hrErr = pMk->BindToObject (bindCtx, NULL, IID_IOleObject, &(VOID FAR*)pObj);
  2212.   if (hrErr == NOERROR) {
  2213.     hrErr = pObj->GetUserClassID (&clsid);
  2214.     pObj->Release();
  2215.  
  2216.     OnViewChange (dwDrawAspect, -1); // get new size if any
  2217.     fLinkSrcAvail = TRUE;
  2218.   }
  2219.   else {
  2220.     HandleLinkError();
  2221.     fLinkSrcAvail = FALSE;
  2222.   }
  2223.  
  2224.   // Make changes to the link object: if we were successful in getting a
  2225.   // moniker, use that, but fall back to the textual name if no moniker
  2226.   // was found.
  2227.   //
  2228.   if (pMk)
  2229.     hrErr = pLinkObject->SetSourceMoniker (pMk, clsid);
  2230.   else
  2231.     hrErr = pLinkObject->SetSourceDisplayName (pNewSrc);
  2232.  
  2233.   // Release scratch pointers (in reverse order)
  2234.   //
  2235.   if (pMk)
  2236.     pMk->Release ();
  2237.   if (bindCtx)
  2238.     bindCtx->Release ();
  2239.  
  2240.   // Now that the site is relinked to a new link source, we don't know
  2241.   // anything about the type of the new source. So delete the type
  2242.   // information we keep around. It will get allocated next time someone
  2243.   // asks for it.
  2244.   //
  2245.   DeleteTypeNames();
  2246.  
  2247.   if (hrErr == NOERROR)
  2248.     UpdateNow();
  2249.  
  2250.   if (dwDrawAspect == DVASPECT_ICON) {
  2251.     CacheIconicAspect(OleGetIconOfFile (pNewSrc, TRUE));
  2252.   }
  2253.  
  2254.   return hrErr;
  2255. }
  2256.  
  2257. HRESULT _IFUNC BOlePart::SourceOpen()
  2258. {
  2259.   if (!pOleObject)
  2260.     return ResultFromScode (E_FAIL);
  2261.  
  2262.   return DoVerb (OLEIVERB_SHOW);
  2263. }
  2264.  
  2265. HRESULT _IFUNC BOlePart::UpdateGet(BOleLinkUpdate *pOptions)
  2266. {
  2267.   if (!pLinkObject)
  2268.     return ResultFromScode (E_FAIL);
  2269.  
  2270.   // Use a temporary to avoid problems since BOleLinkUpdate is an enum
  2271.   // of some size (we don't want to rely on) and the update options
  2272.   // are a long
  2273.   //
  2274.   DWORD o = 0;
  2275.   HRESULT hrErr = pLinkObject->GetUpdateOptions (&o);
  2276.   *pOptions = (BOleLinkUpdate)o;
  2277.  
  2278.   return hrErr;
  2279. }
  2280.  
  2281. HRESULT _IFUNC BOlePart::UpdateSet(BOleLinkUpdate options)
  2282. {
  2283.   if (!pLinkObject)
  2284.     return ResultFromScode (E_FAIL);
  2285.  
  2286.   HRESULT hrErr = pLinkObject->SetUpdateOptions (options);
  2287.   return hrErr;
  2288. }
  2289.  
  2290. // Since we don't know why Excel returns RPC_E_CALL_REJECTED the
  2291. // first N times and then finally works, we have this kludge.
  2292. //
  2293. HRESULT ForceOleUpdate(IOleObject *pOO)
  2294. {
  2295.   int timeout = 500;
  2296.   while (timeout-- > 0) {
  2297.     if (ResultFromScode(RPC_E_CALL_REJECTED) != pOO->Update())
  2298.       break;
  2299.   }
  2300.   return (timeout == 0) ? ResultFromScode(RPC_E_CALL_REJECTED) : NOERROR;
  2301. }
  2302.  
  2303. HRESULT _IFUNC BOlePart::UpdateNow()
  2304. {
  2305.   if (!pOleObject)
  2306.     return ResultFromScode (E_FAIL);
  2307.  
  2308.   HRESULT hrErr = pOleObject->IsUpToDate ();
  2309.   if (hrErr != NOERROR)
  2310.     hrErr = ForceOleUpdate(pOleObject);
  2311.  
  2312.   return hrErr;
  2313. }
  2314.  
  2315. // This version of SourceGet is not part of the public bolero
  2316. // interface for now. It only exists to support IOleUILinkContainer::GetLinkSource
  2317. // Maybe we'll end up putting more stuff in the Bolero version ???
  2318. //
  2319. HRESULT _IFUNC BOlePart::SourceGet
  2320. (
  2321.   LPOLESTR FAR *lplpszDisplayName,
  2322.   LPOLESTR FAR *lplpszFullLinkType,
  2323.   LPOLESTR FAR *lplpszShortLinkType,
  2324.   DWORD FAR *lplenFileName
  2325. )
  2326. {
  2327.   if (!pOleObject || !pLinkObject)
  2328.     return ResultFromScode (E_FAIL);
  2329.  
  2330.   LPMONIKER pmk;
  2331.   HRESULT hrErr = pLinkObject->GetSourceMoniker (&pmk);
  2332.   if (hrErr == NOERROR) {
  2333.     pOleObject->GetUserType (USERCLASSTYPE_FULL, lplpszFullLinkType);
  2334.     pOleObject->GetUserType (USERCLASSTYPE_SHORT, lplpszShortLinkType);
  2335.     *lplenFileName = OleStdGetLenFilePrefixOfMoniker (pmk);
  2336.     pmk->Release ();
  2337.     hrErr = pLinkObject->GetSourceDisplayName (lplpszDisplayName);
  2338.   }
  2339.   return hrErr;
  2340. }
  2341.  
  2342. BOlePart * _IFUNC BOlePart::GetNextLink (BOOL fAllowThis)
  2343. {
  2344.   BOlePart *ret = fAllowThis ? this : this->pNextPart;
  2345.   while (ret) {
  2346.     if (ret->IsLink)
  2347.       return ret;
  2348.     ret = ret->pNextPart;
  2349.   }
  2350.   return NULLP;
  2351. }
  2352.  
  2353. //*************************************************************************
  2354. //
  2355. // IAdviseSink implementation
  2356. //
  2357. //*************************************************************************
  2358.  
  2359. void _IFUNC BOlePart::OnDataChange (FORMATETC FAR* pFormatetc,STGMEDIUM FAR* pStgmed)
  2360. {
  2361.   // I'm not sure how to respond to this, vs how to respond to OnViewChange.
  2362.   //  It seems like if our visible view onto the data hasn't changed, then
  2363.   //  we're not interested in OnDataChange. Maybe there's some significance
  2364.   //  for non-visible server objects...
  2365.   //
  2366. #ifdef _DEBUG
  2367.   MessageBox (NULL, TEXT ("BOLE.DLL"), TEXT ("Unexpected call to OnDataChange"), MB_OK);
  2368. #endif
  2369.   return;
  2370. }
  2371.  
  2372. void _IFUNC BOlePart::OnViewChange (DWORD changedAspect, LONG lindex)
  2373. {
  2374.   // The server may generate an OnViewChange when its extent changes,
  2375.   // so try to make the site the same size.
  2376.   //
  2377.   // This is really important for Paintbrush (all OLE1 servers?) whose
  2378.   // initial size is zero, and don't send OnPosRectChanged (because
  2379.   // they're never inplace). They only send OnViewChange, and expect
  2380.   // us to get the new extent.
  2381.   //
  2382.   // The changedAspect parameter tells us which aspect's view has
  2383.   // changed. It seems like we only care if the aspect we're currently
  2384.   // viewing is the same as the one which has changed.
  2385.   //
  2386.  
  2387.   if (dwDrawAspect == changedAspect) {
  2388.  
  2389.     // this can be called when we've resized the site, but not set
  2390.     // the part extent. In such a case the part extent is not equal to
  2391.     // the site extent.  The part is scaling by the ratio, scaleSite (set in
  2392.     // OnUIActivate).  So, we need to scale the part extent
  2393.     // and set our site size to that. If we were to just use the part's
  2394.     // extent, the symptom would be that upon deactivation the site
  2395.     // would return to the size it had before the (non-active) site
  2396.     // was resized, (or worse if an in-place active resize happened too).
  2397.  
  2398.     SIZE shortSize;
  2399.  
  2400.     GetPartSize(&shortSize);
  2401.  
  2402.     // adjust by additional scaling caused when resizing site while
  2403.     // not in place active (and not setting server extent).
  2404.  
  2405.     OLEPRINTF5("Adjusting by scaleSite:\t {%ld, %ld, %ld, %ld}",
  2406.       scaleSite.xN, scaleSite.xD, scaleSite.yN, scaleSite.yD);
  2407.  
  2408.     shortSize.cx = Scale(shortSize.cx, scaleSite.xN, scaleSite.xD);
  2409.     shortSize.cy = Scale(shortSize.cy, scaleSite.yN, scaleSite.yD);
  2410.  
  2411.     if (!SUCCEEDED(pSite->SetSiteExtent(&shortSize))) {
  2412.  
  2413.       // if client doesn't accept server's extent maybe the
  2414.       // server will accept the client's...
  2415.       //
  2416.       RECT rSite, rClip;
  2417.       HRESULT hr = pSite->GetSiteRect(&rSite, &rClip);
  2418.       if (SUCCEEDED(hr)) {
  2419.         SIZE sizeSite = {rSite.right - rSite.left, rSite.bottom - rSite.top};
  2420.         SetPartSize(&sizeSite);
  2421.       }
  2422.     } else {
  2423.       RECT posR, clipR;
  2424.       pSite->GetSiteRect (&posR, &clipR);
  2425.       if (pInPlaceObject) {
  2426.         posR.right  = posR.left + shortSize.cx;
  2427.         posR.bottom = posR.top  + shortSize.cy;
  2428.         // adjust posR because the site may not want to really
  2429.         // change the extent.  They could succeed to allow
  2430.         // the in-place window to be free, but when the user
  2431.         // deactivates go back to the same old site.
  2432.         pInPlaceObject->SetObjectRects (&posR, &clipR);
  2433.       }
  2434.     }
  2435.  
  2436.     // Generate a paint message for the client app's window, which will
  2437.     // eventually call back to our pViewObject->Draw
  2438.     //
  2439.     pSite->Invalidate(BOLE_INVAL_VIEW | BOLE_INVAL_DATA);
  2440.     UpdateSiteScaleFactor();
  2441.   }
  2442.  
  2443.   return;
  2444. }
  2445.  
  2446. void _IFUNC BOlePart::OnRename (IMoniker* pmk)
  2447. {
  2448.   // Significant for IOleLink objects which must track the link source
  2449.   //
  2450.   return;
  2451. }
  2452.  
  2453. void _IFUNC BOlePart::OnSave ()
  2454. {
  2455.   // Significant if the client implements IOleCache with ADVF_ONSAVE
  2456.   //
  2457.   return;
  2458. }
  2459.  
  2460. void _IFUNC BOlePart::OnClose ()
  2461. {
  2462.   // Significant for IOleLink objects when server is shutting down
  2463.   //
  2464.   return;
  2465. }
  2466.  
  2467.  
  2468. //**************************************************************************
  2469. //
  2470. // IOleWindow implementation
  2471. //
  2472. //**************************************************************************
  2473.  
  2474. HRESULT _IFUNC BOlePart::GetWindow (HWND FAR *phwnd)
  2475. {
  2476.   HRESULT hr = NOERROR;
  2477.   PIBSite2 pSite2 = NULL;
  2478.   *phwnd = NULL;
  2479.  
  2480.   hr = pObjOuter->QueryInterfaceMain (IID_IBSite2, &(LPVOID)pSite2);
  2481.   if (SUCCEEDED (hr)) {
  2482.     hr = pSite2->GetParentWindow (phwnd);
  2483.     pSite2->Release();
  2484.   }
  2485.   else {
  2486.     *phwnd = pContainer->GetWindow();
  2487.     hr = NOERROR;
  2488.   }
  2489.  
  2490.   return hr;
  2491. }
  2492.  
  2493. HRESULT _IFUNC BOlePart::ContextSensitiveHelp (BOOL fEnterMode)
  2494. {
  2495.   // The BOleService object is responsible for keeping track of Shift-F1
  2496.   //
  2497.   pDoc->pService->SetHelpMode (fEnterMode);
  2498.  
  2499.   return NOERROR;
  2500. }
  2501.  
  2502. //**************************************************************************
  2503. //
  2504. // IOleInPlaceSite Implementation
  2505. //
  2506. //**************************************************************************
  2507.  
  2508. HRESULT _IFUNC BOlePart::CanInPlaceActivate (void)
  2509. {
  2510.   HRESULT hr;
  2511.   // Objects rendered as an icon can only be edited "out of place"
  2512.   //
  2513.   if (dwDrawAspect == DVASPECT_ICON)
  2514.     OLERET(S_FALSE);
  2515.  
  2516.   return pContainer->AllowInPlace();
  2517. }
  2518.  
  2519. HRESULT _IFUNC BOlePart::OnInPlaceActivate (void)
  2520. {
  2521.   // In case we don't have balanced calls...
  2522.   if (pInPlaceObject) {
  2523.     pInPlaceObject->Release();
  2524.     pInPlaceObject = NULL;
  2525.   }
  2526.   // This is our opportunity to get a pointer to the object's
  2527.   // IOleInPlaceObject interface
  2528.   //
  2529.   HRESULT hr = pOleObject->QueryInterface(IID_IOleInPlaceObject, &(VOID FAR*)pInPlaceObject);
  2530.  
  2531.   if (hr == NOERROR) {
  2532.     IsOpenInPlace = TRUE;
  2533.     // If the object has opened in place site should hide themselves to
  2534.     // avoid strange drawing behavior
  2535.     //
  2536.     SiteShow (FALSE);
  2537.   }
  2538.   else {
  2539.     IsOpenInPlace = FALSE;
  2540.     pInPlaceObject = NULL;
  2541.   }
  2542.  
  2543.   return hr;
  2544. }
  2545.  
  2546. HRESULT _IFUNC BOlePart::OnInPlaceDeactivate (void)
  2547. {
  2548.   if (pInPlaceObject) {
  2549.     pInPlaceObject->Release();
  2550.     pInPlaceObject = NULL;
  2551.   }
  2552.   if (IsOpenInPlace) {
  2553.     IsOpenInPlace = FALSE;
  2554.     SiteShow (TRUE);    // put the site window back again
  2555.   }
  2556.   return NOERROR;
  2557. }
  2558.  
  2559. // Remember the additional scale factor for this site.
  2560. // If we've resized the site the scale factor is different than normal.
  2561. // We need to know it in OnViewChange, in case the server is resized
  2562. // when in-place active.
  2563. //
  2564. void BOlePart::UpdateSiteScaleFactor()
  2565. {
  2566.   RECT rPos, rClip;
  2567.   if (SUCCEEDED(pSite->GetSiteRect (&rPos, &rClip))) {
  2568.  
  2569.     SIZE sizePart;
  2570.     GetPartSize(&sizePart);
  2571.  
  2572.     if ((sizePart.cx == 0) || (sizePart.cy == 0)) {
  2573.       scaleSite.xN = scaleSite.xD = scaleSite.yN = scaleSite.yD = 1L;
  2574.     }
  2575.     else {
  2576.       scaleSite.xN = rPos.right - rPos.left;
  2577.       scaleSite.xD = sizePart.cx;
  2578.       scaleSite.yN = rPos.bottom - rPos.top;
  2579.       scaleSite.yD = sizePart.cy;
  2580.     }
  2581.     OLEPRINTF5("Updating scaleSite:\t {%ld, %ld, %ld, %ld}",
  2582.       scaleSite.xN, scaleSite.xD, scaleSite.yN, scaleSite.yD);
  2583.   }
  2584. }
  2585.  
  2586. HRESULT _IFUNC BOlePart::OnUIActivate (void)
  2587. {
  2588.   OLEPRINTF1("Entering OnUIActivate");
  2589.  
  2590.   // (Used to UpdateSiteScaleFactor in GetWindowContext.
  2591.   // But, MS Excel Chart doesn't give accurate extents at that point
  2592.   // In OnInPlaceActivate Excel Chart gives inaccurate extents.
  2593.   // In OnUIActivate Excel Sheet gives inaccurate extents.
  2594.   //
  2595.   UpdateSiteScaleFactor();
  2596.  
  2597.   // The inplace server is about to put up its own tool/status
  2598.   // bars, so ask the client app to remove its adorners
  2599.   //
  2600.   // Although it isn't in the official docs, the Outline example
  2601.   // (in frametls.c) uses the convention where SetBorderSpace({0,})
  2602.   // means hide adornments
  2603.  
  2604.   // hide their adornments
  2605.   //
  2606.   HRESULT hr = NOERROR;
  2607.  
  2608.   LPOLEINPLACESITE pIPS;
  2609.   if (SUCCEEDED(GetParentIPS(&pIPS))) {
  2610.     IBPart *pServerSide;
  2611.     if (SUCCEEDED(pDoc->QueryInterface(IID_IBPart, &(LPVOID)pServerSide))) {
  2612.       pServerSide->ShowTools(FALSE);
  2613.       pServerSide->Release();
  2614.     }
  2615.     pIPS->Release();
  2616.   }
  2617.   else {
  2618.     RECT r = {0,0,0,0};
  2619.  
  2620.     pContainer->BringToFront();
  2621.  
  2622.     IBWindow *pWnd = getNegotiator(pDoc->pApplication, pContainer);
  2623.  
  2624. //    hr = pWnd->SetBorderSpace (&r);
  2625.   }
  2626.  
  2627.   pSite->OnSetFocus(TRUE);
  2628.  
  2629.   // Hitting ESC from some servers only does a UIDeactivate so
  2630.   // next time you activate it, it only calls OnUIActivate rather
  2631.   // than OnInPlaceActivate. So be sure to keep the flags coherent with
  2632.   // the real state.
  2633.   //
  2634.   IsOpenInPlace = TRUE;
  2635.   SiteShow (FALSE); // assumes hiding an already hidden site is a nop
  2636.  
  2637.   return hr;
  2638. }
  2639.  
  2640. HRESULT _IFUNC BOlePart::OnUIDeactivate (BOOL fUndoable)
  2641. {
  2642.   // The inplace server is about to remove its own tool/status
  2643.   // bars, so ask the client app to restore its adorners
  2644.   //
  2645.   // Although it isn't in the official docs, the Outline example
  2646.   // (in frametls.c) uses the convention where SetBorderSpace(NULL)
  2647.   // means show adornments
  2648.   //
  2649.  
  2650.   HRESULT hr = NOERROR;
  2651.  
  2652.   if (IsOpenInPlace && !IsOpenInsideOut) {
  2653.     // when ESC key is used to deactivate excel and word
  2654.     // OnInPlaceDeactivate is not called.
  2655.     SiteShow (TRUE);    // put the site window back again
  2656.     IsOpenInPlace = FALSE;
  2657.   }
  2658.  
  2659.   // This SetFocus call is to take the focus back from the OLE object's
  2660.   // inplace window, since that window has gone away
  2661.   //
  2662.   pSite->OnSetFocus(TRUE);
  2663.  
  2664.   LPOLEINPLACESITE pIPS;
  2665.   if (SUCCEEDED(GetParentIPS(&pIPS))) {
  2666.     IBPart *pServerSide;
  2667.     if (SUCCEEDED(pDoc->QueryInterface(IID_IBPart, &(LPVOID)pServerSide))) {
  2668.       pServerSide->ShowTools(TRUE);
  2669.       pServerSide->Release();
  2670.     }
  2671.     pIPS->Release();
  2672.   }
  2673.   else {
  2674.     // show their adornments
  2675.     //
  2676.     IBWindow *pWnd = getNegotiator(pDoc->pApplication, pContainer);
  2677.  
  2678.     hr = pWnd->SetBorderSpace (NULL);
  2679.  
  2680.     // We're using this call to our own IOleInPlaceFrame implementation
  2681.     // to get to OleSetMenuDescriptor(NULL), which is supposed to unhook
  2682.     // OLE's message dispatching stuff. We could just call
  2683.     // OleSetMenuDescriptor from here, but it's not clear if the server
  2684.     // app might call SetMenu with NULL for the same purpose?
  2685.     //
  2686.     // The pointer-juggling here is intended to make sure we disconnect
  2687.     // the OLE message filter from the right window (frame vs. container).
  2688.     //
  2689.     IOleInPlaceFrame FAR *ipframe = NULL;
  2690.     if (S_OK == (GetScode(pDoc->pApplication->IsMDI())))
  2691.       ipframe = pDoc->pService;
  2692.     else
  2693.       ipframe = pDoc;
  2694.     PIBWindow ipNegWnd = getNegotiator (pDoc->pApplication, pDoc->pContainer);
  2695.     hr = ipframe->SetMenu (NULL, NULL, ipNegWnd->GetWindow());
  2696.   }
  2697.  
  2698.   return hr;
  2699. }
  2700.  
  2701. HRESULT _IFUNC BOlePart::GetParentIPS(LPOLEINPLACESITE *ppIPS)
  2702. {
  2703.   HRESULT hr = ResultFromScode(E_NOINTERFACE);
  2704.   LPOLEOBJECT pSelfAsServer;
  2705.   if (SUCCEEDED(pDoc->QueryInterface(IID_IOleObject, &(LPVOID)pSelfAsServer))) {
  2706.     LPOLECLIENTSITE pCS;
  2707.     if (SUCCEEDED(pSelfAsServer->GetClientSite(&pCS)) && pCS) {
  2708.       hr = pCS->QueryInterface(IID_IOleInPlaceSite, (LPVOID*)ppIPS);
  2709.       pCS->Release();
  2710.     }
  2711.     pSelfAsServer->Release();
  2712.   }
  2713.   return hr;
  2714. }
  2715.  
  2716. HRESULT _IFUNC BOlePart::GetWindowContext (IOleInPlaceFrame* FAR* ppFrame, IOleInPlaceUIWindow* FAR* ppDoc, LPRECT prcPosRect, LPRECT prcVisRect, LPOLEINPLACEFRAMEINFO pFrameInfo)
  2717. {
  2718.   LPOLEINPLACESITE pIPSite;
  2719.   if (SUCCEEDED(GetParentIPS(&pIPSite)) && (S_OK == pIPSite->CanInPlaceActivate ()))
  2720.   {
  2721.     // if nested in place active,
  2722.     // get parent's window interfaces, but our site size
  2723.     //
  2724.     HRESULT hr = pIPSite->GetWindowContext(ppFrame, ppDoc, prcPosRect,
  2725.                  prcVisRect, pFrameInfo);
  2726.     pIPSite->Release();
  2727.     pSite->GetSiteRect (prcPosRect, prcVisRect);
  2728.     return hr;
  2729.   }
  2730.  
  2731.   // The isMdi flag tells the server whether it should negotiate for
  2732.   // space on the "frame" window or the "document" window
  2733.   //
  2734.   IBApplication * pApp = pDoc->pApplication;
  2735.   pFrameInfo->fMDIApp = (GetScode(pApp->IsMDI()) == S_OK) ? TRUE : FALSE;
  2736.  
  2737.   // Decide which window should do inplace negotiation
  2738.   //
  2739.   PIBWindow ipNegWnd = NULL;
  2740.   if (pFrameInfo->fMDIApp)
  2741.     ipNegWnd = pDoc->pApplication;
  2742.   else
  2743.     ipNegWnd = pContainer;
  2744.  
  2745.   // Decide which HWND to give out so toolbar parenting etc is correct
  2746.   //
  2747.   pFrameInfo->hwndFrame = ipNegWnd->GetWindow();
  2748.  
  2749.   // Allow the server to call back for menu negotiation at the document level
  2750.   //
  2751.   ipNegWnd->QueryInterface (IID_IOleInPlaceFrame, (void**) ppFrame);
  2752.  
  2753.   // Allow the server to call back for toolbar negotiation at the document level
  2754.   //
  2755.   if (pFrameInfo->fMDIApp)
  2756.     pDoc->QueryInterface (IID_IOleInPlaceUIWindow, (void**)ppDoc);
  2757.   else
  2758.     *ppDoc = NULL;
  2759.  
  2760.   // Get the accelerator table from the window
  2761.   //
  2762.   if (!SUCCEEDED(ipNegWnd->GetAccelerators (&pFrameInfo->haccel,
  2763.     (int FAR *) (&pFrameInfo->cAccelEntries)))) {
  2764.     pFrameInfo->haccel = NULL;
  2765.     pFrameInfo->cAccelEntries = 0;
  2766.   }
  2767.  
  2768.   pSite->GetSiteRect (prcPosRect, prcVisRect);
  2769.  
  2770.   return NOERROR;
  2771. }
  2772.  
  2773. HRESULT _IFUNC BOlePart::DiscardUndoState ()
  2774. {
  2775.   return ResultFromScode (E_NOTIMPL);
  2776. }
  2777.  
  2778. HRESULT _IFUNC BOlePart::DeactivateAndUndo ()
  2779. {
  2780.   // This is called by the server when the user picks Undo immediately
  2781.   // after activating the server inplace. We should remove the server's
  2782.   // adornments, set focus to ourselves, and pop the undo stack
  2783.   //
  2784.   HRESULT hr = pInPlaceObject->UIDeactivate();
  2785.   if (hr != NOERROR)
  2786.     return hr;
  2787.  
  2788.   pSite->OnSetFocus(TRUE);
  2789.   return NOERROR;
  2790. }
  2791.  
  2792. HRESULT _IFUNC BOlePart::Scroll (SIZE scrollExtent)
  2793. {
  2794.   return ResultFromScode (E_NOTIMPL);
  2795. }
  2796.  
  2797. HRESULT _IFUNC BOlePart::OnPosRectChange (LPCRECT lprcPosRect)
  2798. {
  2799.   HRESULT hr;
  2800.   // The server size is changing, let's try to set it in the container..
  2801.  
  2802.   OLEPRINTF1("Entering OnPosRectChange");
  2803.   if (SUCCEEDED(pSite->SetSiteRect (lprcPosRect))) {
  2804.     RECT posR, clipR;
  2805.     pSite->GetSiteRect (&posR, &clipR);
  2806.     if (pInPlaceObject) {
  2807.       // use lprcPosRect because the site may not want to really
  2808.       // change the extent.  They could succeed to allow
  2809.       // the in-place window to be free, but when the user
  2810.       // deactivates go back to the same old site.
  2811.       hr = pInPlaceObject->SetObjectRects (lprcPosRect, &clipR);
  2812.     }
  2813.   }
  2814.   else {
  2815.     // try to back out of hatch window resize with the fewest possible
  2816.     // side effects.  This is best all around solution.  Although visio
  2817.     // scales inappropriately, one can live with it.
  2818.  
  2819.     RECT rSite, rClip;
  2820.     pSite->GetSiteRect(&rSite, &rClip);
  2821.     SIZE sizeSite = {rSite.right - rSite.left, rSite.bottom - rSite.top};
  2822.  
  2823.     SetPartSize(&sizeSite);
  2824.     pInPlaceObject->SetObjectRects (&rSite, &rClip);
  2825.     hr = ResultFromScode(E_FAIL);
  2826.  
  2827. #if 0
  2828.     // Here are the other trials:
  2829.  
  2830.     // this approach causes visio to scale inappropriately
  2831.     // and excel's extents to be wrong
  2832.     SetPartSize(&sizeSite);
  2833.     hr = pInPlaceObject->SetObjectRects (&rSite, &rClip);
  2834.  
  2835.     // w/o SetPartSize also excel sheet and chart scale inappropriately
  2836.     hr = pInPlaceObject->SetObjectRects (&rSite, &rClip);
  2837.  
  2838.     // same but chart in MS excel is a bit better
  2839.     pInPlaceObject->SetObjectRects (&rSite, &rClip);
  2840.     hr = ResultFromScode(E_FAIL);
  2841.  
  2842.     // this approach causes servers (chart, visio) to leave hatch window
  2843.     SetPartSize(&sizeSite);
  2844.     hr = NOERROR;
  2845.  
  2846.     // same but chart doesn't leave window, only visio
  2847.     SetPartSize(&sizeSite);
  2848.     hr = ResultFromScode(E_FAIL);
  2849.  
  2850.     // just failing causes both scale factor and window problems
  2851.     hr = ResultFromScode(E_FAIL);
  2852.  
  2853.     // doing the set part size after plays havoc with scaling
  2854.     pInPlaceObject->SetObjectRects (&rSite, &rClip);
  2855.     SetPartSize(&sizeSite);
  2856.     hr = ResultFromScode(E_FAIL);
  2857.  
  2858. #endif
  2859.   }
  2860.   return hr;
  2861. }
  2862.  
  2863. HRESULT _IFUNC BOlePart::GetMoniker(IMoniker FAR* FAR* ppMon)
  2864. {
  2865.   HRESULT hrErr = GetMoniker(OLEGETMONIKER_ONLYIFTHERE,
  2866.     OLEWHICHMK_OBJFULL, ppMon);
  2867.   return hrErr;
  2868. }
  2869.  
  2870. HRESULT _IFUNC BOlePart::OnRename(PIBLinkable pCont, LPCOLESTR szName)
  2871. {
  2872.   HRESULT hrErr = NOERROR;
  2873.  
  2874.   pILinkCont = pCont;
  2875.   if (pszInstName) {
  2876.     delete pszInstName;
  2877.     pszInstName = NULL;
  2878.   }
  2879.   if (szName) {
  2880.     pszInstName = new OLECHAR [lstrlen (szName) +1];
  2881.     lstrcpy(pszInstName, szName);
  2882.   }
  2883.  
  2884.   if (pOleObject) {
  2885.     LPMONIKER pMon;
  2886.     // Server registers as GetObjectMoniker calls IOleObject::SetMoniker
  2887.     GetObjectMoniker(OLEGETMONIKER_UNASSIGN);    // really force!
  2888.     pMon = GetObjectMoniker(OLEGETMONIKER_FORCEASSIGN);
  2889.     if (pMon)
  2890.       pMon->Release();
  2891.  
  2892.     // update window title
  2893.     if (pszInstName) {
  2894.       pOleObject->SetHostNames (pDoc->pApplication->GetAppName(),
  2895.       pDoc->pContainer->GetWindowTitle());
  2896.     }
  2897.   }
  2898.   return hrErr;
  2899. }
  2900.  
  2901. //**************************************************************************
  2902. //
  2903. // IDropSource Implementation -- Although this is normally implemented by
  2904. //             server objects, we need it on our client
  2905. //             side helper to do "embed from embedding"
  2906. //             which is where you drag/drop or copy/paste
  2907. //             from an existing embedded object.
  2908. //
  2909. //**************************************************************************
  2910.  
  2911. HRESULT _IFUNC BOlePart::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
  2912. {
  2913.   SCODE sc;
  2914.  
  2915.   if (fEscapePressed)
  2916.     sc = DRAGDROP_S_CANCEL;
  2917.   else
  2918.     if (!(grfKeyState & MK_LBUTTON))
  2919.       sc = DRAGDROP_S_DROP;
  2920.     else
  2921.       sc = S_OK;
  2922.  
  2923.   return ResultFromScode (sc);
  2924.  
  2925. }
  2926.  
  2927. HRESULT _IFUNC BOlePart::GiveFeedback(DWORD dwEffect)
  2928. {
  2929.   return ResultFromScode (DRAGDROP_S_USEDEFAULTCURSORS);
  2930. }
  2931.  
  2932. //**************************************************************************
  2933. //
  2934. // CopyFromOriginal() helpers
  2935. //
  2936. //**************************************************************************
  2937.  
  2938. HRESULT _IFUNC BOlePart::AddCachedData (IDataObject *pTarget)
  2939. {
  2940.   BOOL fAddedMetafile = FALSE;
  2941.   LPOLECACHE pOleCache;
  2942.  
  2943.   if (SUCCEEDED (pOleObject && pDataObject &&
  2944.     pOleObject->QueryInterface (IID_IOleCache, &(LPVOID) pOleCache))) {
  2945.  
  2946.     // Get IEnumSTATDATA interface for IOleCache
  2947.     //
  2948.     LPENUMSTATDATA lpEnumSTATDATA;
  2949.     if (pOleCache->EnumCache (&lpEnumSTATDATA) == NOERROR && lpEnumSTATDATA) {
  2950.  
  2951.       // Enumerate all of the cached formats
  2952.       //
  2953.       STATDATA statData;
  2954.       while (lpEnumSTATDATA->Next (1, &statData, NULL) == NOERROR) {
  2955.         TCHAR name[32];
  2956.         GetClipboardFormatName (statData.formatetc.cfFormat, name, sizeof(name));
  2957.  
  2958.         // For each "cachable" format, try to get a copy of the data
  2959.         //
  2960.         STGMEDIUM stgMedium;
  2961.         if (pDataObject->GetData (&statData.formatetc, &stgMedium) != NOERROR) {
  2962.           // Data is not available
  2963.         }
  2964.         else
  2965.           if (stgMedium.pUnkForRelease != NULL) {
  2966.  
  2967.             // Don't cache data with pUnkForRelease != NULL
  2968.             //
  2969.             ::ReleaseStgMedium (&stgMedium);
  2970.             ::OleStdDeleteTargetDevice (statData.formatetc.ptd);
  2971.           }
  2972.           else {
  2973.  
  2974.             // Transfer to the target
  2975.             //
  2976.             pTarget->SetData (&statData.formatetc, &stgMedium, TRUE /*give ownership*/);
  2977.             if (statData.formatetc.cfFormat == CF_METAFILEPICT)
  2978.               fAddedMetafile = TRUE;
  2979.           }
  2980.       }
  2981.       lpEnumSTATDATA->Release();
  2982.     }
  2983.     pOleCache->Release();
  2984.   }
  2985.  
  2986.   // Just about everyone has a metafile in the cache. Paintbrush does not,
  2987.   // so we'll add it forcibly here.
  2988.   //
  2989.   if (!fAddedMetafile) {
  2990.     FORMATETC fe;
  2991.     fe.cfFormat = CF_METAFILEPICT;
  2992.     fe.tymed = TYMED_MFPICT;
  2993.     fe.lindex = -1;
  2994.     fe.ptd = NULL;
  2995.  
  2996.     SIZEL sizel;
  2997.     if (NOERROR != pOleObject->GetExtent (dwDrawAspect, &sizel)) {
  2998.       RECT rcpos, rcclip;
  2999.       pSite->GetSiteRect (&rcpos, &rcclip);
  3000.       sizel.cx = MAP_PIX_TO_LOGHIM (rcpos.right - rcpos.left, BOleService::pixPerIn.x);
  3001.       sizel.cy = MAP_PIX_TO_LOGHIM (rcpos.bottom - rcpos.top, BOleService::pixPerIn.y);
  3002.     }
  3003.  
  3004.     STGMEDIUM sm;
  3005.     sm.tymed = TYMED_MFPICT;
  3006.     sm.pUnkForRelease = NULL;
  3007.     sm.hGlobal = OleStdGetMetafilePictFromOleObject (pOleObject,
  3008.       dwDrawAspect, &sizel, NULL);
  3009.     if (sm.hGlobal)
  3010.       pTarget->SetData (&fe, &sm, TRUE);
  3011.  
  3012.   }
  3013.   return NOERROR;
  3014. }
  3015.  
  3016. HRESULT _IFUNC BOlePart::AddLinkSourceData (IDataObject *pTarget)
  3017. {
  3018.   FORMATETC fe;
  3019.   STGMEDIUM stgMedium;
  3020.   LPMONIKER lpMoniker;
  3021.  
  3022.   if (!pLinkObject) {
  3023.  
  3024.     // Get moniker from client site
  3025.     //
  3026.     LPOLECLIENTSITE cSite;
  3027.     if (SUCCEEDED (pObjOuter->QueryInterfaceMain (IID_IOleClientSite, &(LPVOID)cSite))) {
  3028.       cSite->GetMoniker (OLEGETMONIKER_TEMPFORUSER, OLEWHICHMK_OBJFULL, &lpMoniker);
  3029.       cSite->Release();
  3030.       if (!lpMoniker)
  3031.         return ResultFromScode (E_FAIL);
  3032.     } else
  3033.       return ResultFromScode (E_FAIL);
  3034.   }
  3035.   else {
  3036.     // Get moniker from the link object itself
  3037.     //
  3038.     if (SUCCEEDED (pOleObject->GetMoniker(OLEGETMONIKER_TEMPFORUSER,
  3039.       OLEWHICHMK_OBJFULL, &lpMoniker))) {
  3040.     }
  3041.     else
  3042.       return ResultFromScode (E_FAIL);
  3043.   }
  3044.  
  3045.   // Create a memory based stream to write the moniker to
  3046.   //
  3047.   LPSTREAM lpStream;
  3048.   if (!SUCCEEDED (::CreateStreamOnHGlobal (NULL, TRUE, &lpStream))) {
  3049.     lpMoniker->Release();
  3050.     return ResultFromScode (E_FAIL);
  3051.   }
  3052.  
  3053.   // Write the moniker to the stream
  3054.   //
  3055.   if (!SUCCEEDED (OleSaveToStream (lpMoniker, lpStream))) {
  3056.     lpStream->Release();
  3057.     return ResultFromScode (E_FAIL);
  3058.   }
  3059.  
  3060.   // Write the class ID of the document to the stream as well
  3061.   //
  3062.   CLSID clsid;
  3063.   pOleObject->GetUserClassID (&clsid);
  3064.   WriteClassStm (lpStream, clsid);
  3065.  
  3066.   lpMoniker->Release();
  3067.  
  3068.   // Give this stream to the data source (which then owns it)
  3069.   //
  3070.   memset (&fe, 0, sizeof (fe));
  3071.   fe.cfFormat = BOleDocument::oleLinkSrcClipFmt;
  3072.   fe.dwAspect = dwDrawAspect;
  3073.   fe.lindex = -1;
  3074.   fe.tymed = TYMED_ISTREAM;
  3075.   stgMedium.tymed = TYMED_ISTREAM;
  3076.   stgMedium.pstm = lpStream;
  3077.   stgMedium.pUnkForRelease = NULL;
  3078.   pTarget->SetData (&fe, &stgMedium, TRUE);
  3079.  
  3080.   // Set the object descriptor
  3081.   //
  3082.   stgMedium.tymed = TYMED_HGLOBAL;
  3083.   fe.cfFormat = BOleDocument::oleLinkSrcDescFmt;
  3084.   fe.tymed = TYMED_HGLOBAL;
  3085.   POINTL unused = {0,0};
  3086.   SIZEL unused2 = {0,0};
  3087.   stgMedium.hGlobal = OleStdGetObjectDescriptorDataFromOleObject(pOleObject,
  3088.     NULL, dwDrawAspect, unused, &unused2);
  3089.   stgMedium.pUnkForRelease = NULL;
  3090.   pTarget->SetData (&fe, &stgMedium, TRUE);
  3091.  
  3092.   return NOERROR;
  3093. }
  3094.  
  3095. HRESULT _IFUNC BOlePart::AddSiteData (LPDATAOBJECT pTarget)
  3096. {
  3097.   // Ask the site if they have any data to add.
  3098.   //
  3099.   // Implementation note: this is a slightly quirky way to do this, but
  3100.   // we're not set up to change it at this point. Other ways it could work:
  3101.   //
  3102.   // 1. Use aggregation so the user calls IBService::Clip with the data
  3103.   //    provider supported on their site object. Then they would get to
  3104.   //    provide their formats first, and then call back to the data provier
  3105.   //    on BOlePart to add the cached formats. Although this seems OLE-like,
  3106.   //    abandoned this idea because the aggregation is tricky and our
  3107.   //    data format negotiation stuff is different enough from OLE2's to
  3108.   //    make it difficult to bottleneck the OLE2 cache.
  3109.   //
  3110.   // 2. Put a flag in BOlePart which would be set when we're in a CopyFrom-
  3111.   //    Original. Then our BOlePart's data provider implementation would
  3112.   //    know when to get the data of the real OLE object, and when to get
  3113.   //    it from the cache. Abandoned this idea because the idea of more
  3114.   //    weird state information isn't attractive.
  3115.   //
  3116.   // 3. Add a SetFormatData to IBPart or IBDataProvider which could do an
  3117.   //    IBDataObject::SetData on the cache directly. Abandoned this idea
  3118.   //    because it would be another stub method on the server side.
  3119.   //
  3120.  
  3121.   HRESULT hr = NOERROR;
  3122.   PIBDataProvider pProvider = NULL;
  3123.   hr = pSite->QueryInterface (IID_IBDataProvider, &(LPVOID) pProvider);
  3124.  
  3125.   // Should never happen because aggregation will always return the
  3126.   // data provider on us if the site doesn't support it.
  3127.   //
  3128.   if (hr != NOERROR)
  3129.     return hr;
  3130.  
  3131.   if (pProvider != (PIBDataProvider)(IBPart*)this) {
  3132.     UINT count = pProvider->CountFormats ();
  3133.  
  3134.     HANDLE hData;
  3135.     BOleFormat bf;
  3136.     FORMATETC fe;
  3137.     STGMEDIUM stm;
  3138.  
  3139.     for (UINT i = 0; i < count; i++) {
  3140.  
  3141.       // Get the formats the site wants to add
  3142.       //
  3143.       hr = pProvider->GetFormat (i, &bf);
  3144.       if (hr == NOERROR) {
  3145.         hData = pProvider->GetFormatData (&bf);
  3146.  
  3147.         // Convert from BOleFormat to FORMATETC
  3148.         //
  3149.         if (hData) {
  3150.           fe.cfFormat = bf.fmtId;
  3151.           fe.ptd = NULL;
  3152.           fe.dwAspect = dwDrawAspect;
  3153.           fe.lindex = -1;
  3154.           switch (bf.fmtId) {
  3155.             case CF_METAFILEPICT:
  3156.               fe.tymed = TYMED_MFPICT;
  3157.               break;
  3158.             case CF_BITMAP:
  3159.               fe.tymed = TYMED_GDI;
  3160.               break;
  3161.             default:
  3162.               fe.tymed = TYMED_HGLOBAL;
  3163.           }
  3164.  
  3165.           // Only formats described by HGLOBALs are allowed here.
  3166.           // If we had this to do again, we'd just use FORMATETC
  3167.           //
  3168.           stm.tymed = fe.tymed;
  3169.           stm.hGlobal = hData;
  3170.           stm.pUnkForRelease = NULL;
  3171.         }
  3172.  
  3173.         // Set the FORMATETC and STGMEDIUM into the data cache
  3174.         //
  3175.         hr = pTarget->SetData (&fe, &stm, TRUE);
  3176.       }
  3177.     }
  3178.   }
  3179.  
  3180.   pProvider->Release();
  3181.   return hr;
  3182. }
  3183.  
  3184. // Link source not available
  3185. //
  3186. void _IFUNC BOlePart::HandleLinkError()
  3187. {
  3188.   HWND hWnd = pContainer->GetWindow();
  3189.   if (hWnd) {
  3190.  
  3191.     // Need to retrieve the descriptive name for the container to make the caption
  3192.     //
  3193.     HWND hTopWnd = GetTopWindow( hWnd );
  3194.     LPOLESTR pCaption = OLESTR( "" );
  3195. #ifndef MS_OLEUI_DEF  
  3196.     if (OleUIPromptUser (IDD_LINKSOURCEUNAVAILABLE, hTopWnd, pCaption) == ID_PU_LINKS ){
  3197. // #endif
  3198.  
  3199.       // Since a link is unavailable, we ask the user whether they
  3200.       // want to go to the links dialog box. If they do, we invoke it
  3201.       // through the IBOverrideBrowseLinks interface. The reason we
  3202.       // don't call it directly on the BOleDocument is so that a
  3203.       // container app (WPWin) can use their own dialog in this case.
  3204.       //
  3205.       // In general, it isn't nice for Bolero to call our own dialogs
  3206.       // because users are supposed to be able to use their own.
  3207.       //
  3208.       PIBOverrideBrowseLinks pOBL = NULL;
  3209.       HRESULT qiHr = pDoc->QueryInterface (IID_IBOverrideBrowseLinks, &(LPVOID)pOBL);
  3210.       if (SUCCEEDED(qiHr)) { // should never fail since OBL is supported on the doc
  3211.         pOBL->BrowseLinks();
  3212.         pOBL->Release();
  3213.       }
  3214. // #ifndef MS_OLEUI_DEF  
  3215.     }
  3216. #endif
  3217.   }
  3218. }
  3219.  
  3220.  
  3221.