home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / C++-7 / DISK10 / MFC / SRC / OLECLI.CP$ / olecli
Encoding:
Text File  |  1992-03-10  |  22.8 KB  |  925 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library. 
  2. // Copyright (C) 1992 Microsoft Corporation 
  3. // All rights reserved. 
  4. //  
  5. // This source code is only intended as a supplement to the 
  6. // Microsoft Foundation Classes Reference and Microsoft 
  7. // QuickHelp documentation provided with the library. 
  8. // See these sources for detailed information regarding the 
  9. // Microsoft Foundation Classes product. 
  10.  
  11.  
  12. #include "afxole.h"
  13. #pragma hdrstop
  14.  
  15. #include "oleptr_.h"
  16.  
  17. #ifdef AFX_OLE_SEG
  18. #pragma code_seg(AFX_OLE_SEG)
  19. #endif
  20.  
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char BASED_CODE THIS_FILE[] = __FILE__;
  24. #endif
  25.  
  26. #define OLEEXPORT FAR PASCAL _export
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. #ifdef _DEBUG
  30. // character strings to use for debug traces
  31.  
  32. static char BASED_CODE szCHANGED[] = "OLE_CHANGED";
  33. static char BASED_CODE szSAVED[] = "OLE_SAVED";
  34. static char BASED_CODE szCLOSED[] = "OLE_CLOSED";
  35. static char BASED_CODE szRENAMED[] = "OLE_RENAMED";
  36. static char BASED_CODE szQUERY_PAINT[] = "OLE_QUERY_PAINT";
  37. static char BASED_CODE szRELEASE[] = "OLE_RELEASE";
  38. static char BASED_CODE szQUERY_RETRY[] = "OLE_QUERY_RETRY";
  39.  
  40. static char FAR* BASED_CODE notifyStrings[] =
  41. {
  42.     szCHANGED,
  43.     szSAVED,
  44.     szCLOSED,
  45.     szRENAMED,
  46.     szQUERY_PAINT,
  47.     szRELEASE,
  48.     szQUERY_RETRY,
  49. };
  50. #endif //_DEBUG
  51.  
  52. // Standard protocol strings
  53. static char BASED_CODE lpszStaticProtocol[] = "Static";
  54. static char BASED_CODE lpszStdProtocol[] = "StdFileEditing";
  55.  
  56. /////////////////////////////////////////////////////////////////////////////
  57. // Client view of OLEOBJECT (includes OLECLIENT)
  58.  
  59. IMPLEMENT_DYNAMIC(COleClientItem, CObject)
  60.  
  61. inline COleClientItem *
  62. COleClientItem::FromLp(LPOLECLIENT lpClient)
  63. {
  64.     ASSERT(lpClient != NULL);
  65.     COleClientItem* pOleClient;
  66.     pOleClient = (COleClientItem*) GetPtrFromFarPtr(lpClient, sizeof(CObject));
  67.     ASSERT(lpClient == &pOleClient->m_oleClient);
  68.     return pOleClient;
  69. }
  70.  
  71. // friend class to get access to COleClientItem protected implementations
  72. struct _afxOleClientItemImplementation
  73. {
  74.     static int OLEEXPORT
  75.     Client_CallBack(LPOLECLIENT lpClient, OLE_NOTIFICATION wNotification,
  76.         LPOLEOBJECT lpObject)
  77.     {
  78.         COleClientItem* pOleClient = COleClientItem::FromLp(lpClient);
  79.         ASSERT(pOleClient != NULL);
  80.  
  81.     #ifdef _DEBUG
  82.         if (wNotification != OLE_QUERY_PAINT)
  83.         {
  84.             if (afxTraceFlags & 0x10)
  85.                 TRACE("OLE Client_Callback %d [%Fs] for $%lx\n",
  86.                     wNotification, (LPCSTR)notifyStrings[wNotification], lpObject);
  87.         }
  88.     #else
  89.         (void)lpObject; // not used
  90.     #endif
  91.         return pOleClient->ClientCallBack(wNotification);
  92.     }
  93. };
  94.  
  95. static struct _OLECLIENTVTBL NEAR clientVtbl =
  96. {
  97.     &_afxOleClientItemImplementation::Client_CallBack
  98. };
  99.  
  100. // Many creation variants
  101. COleClientItem::COleClientItem(COleClientDoc* pContainerDoc)
  102. {
  103.     ASSERT(pContainerDoc != NULL);
  104.     ASSERT(pContainerDoc->IsOpen());
  105.  
  106.     m_oleClient.lpvtbl = &clientVtbl;
  107.     m_lpObject = NULL;
  108.     m_lastStatus = OLE_OK;
  109.     m_pDocument = pContainerDoc;
  110. }
  111.  
  112. COleClientItem::~COleClientItem()
  113. {
  114.     if (m_lpObject != NULL)
  115.     {
  116.         // wait for object to be not busy
  117.         WaitForServer();
  118.  
  119.         // release linked, delete others
  120.         CheckAsync((GetType() == OT_LINK) ?
  121.           ::OleRelease(m_lpObject) : ::OleDelete(m_lpObject));
  122.     }
  123. }
  124.  
  125. void COleClientItem::Release()
  126. {
  127.     if (m_lpObject == NULL)
  128.         return;
  129.  
  130.     CheckAsync(::OleRelease(m_lpObject));
  131.  
  132.     // detach
  133.     m_lpObject = NULL;
  134. }
  135.  
  136. void COleClientItem::Delete()
  137. {
  138.     if (m_lpObject == NULL)
  139.         return;
  140.  
  141.     CheckAsync(::OleDelete(m_lpObject));
  142.  
  143.     // detach
  144.     m_lpObject = NULL;
  145. }
  146.  
  147. //////////////////////////////////////////////////////////////////////////////
  148. // Create error handling
  149.  
  150. BOOL COleClientItem::CheckCreate(OLESTATUS status)
  151. {
  152.     m_lastStatus = status;
  153.  
  154.     switch (status)
  155.     {
  156.     case OLE_OK:
  157.         ASSERT(m_lpObject != NULL);
  158.         return TRUE;            // immediate create success
  159.  
  160.     case OLE_WAIT_FOR_RELEASE:  // synchronous create
  161.         ASSERT(m_lpObject != NULL);
  162.         WaitForServer();
  163.         return (m_lastStatus == OLE_OK);
  164.  
  165.     // cases to treat as exceptions
  166.     case OLE_ERROR_PROTECT_ONLY:
  167.     case OLE_ERROR_MEMORY:
  168.     case OLE_ERROR_OBJECT:
  169.     case OLE_ERROR_OPTION:
  170.         TRACE("Warning: COleClientItem::Create?() failed %d\n", status);
  171.         AfxThrowOleException(status);
  172.         break;
  173.     }
  174.  
  175.     // the rest are non-exceptional conditions for create
  176.     TRACE("Warning: COleClientItem::Create?() failed %d, returning FALSE\n", status);
  177.     m_lpObject = NULL;      // just in case
  178.     return FALSE;           // create failed
  179. }
  180.  
  181.  
  182. void COleClientItem::CheckAsync(OLESTATUS status)
  183.     // special case for possible Async requests
  184. {
  185.     if (status == OLE_WAIT_FOR_RELEASE)
  186.     {
  187.         ASSERT(m_lpObject != NULL);
  188.         WaitForServer();
  189.         status = m_lastStatus;      // set by ASYNC release
  190.         ASSERT(status != OLE_WAIT_FOR_RELEASE);
  191.     }
  192.     CheckGeneral(status);   // may throw an exception
  193. }
  194.  
  195. void COleClientItem::CheckGeneral(OLESTATUS status)
  196.     // set 'm_lastStatus'
  197.     // throw exception if not ok to continue
  198. {
  199.     ASSERT(status != OLE_WAIT_FOR_RELEASE);
  200.         // Async must be handled as a special case before this
  201.  
  202.     m_lastStatus = status;
  203.     if (status == OLE_OK || status > OLE_WARN_DELETE_DATA)
  204.     {
  205.         // ok, or just a warning
  206.         return;
  207.     }
  208.  
  209.     // otherwise this error wasn't expected, so throw an exception
  210.     TRACE("Warning: COleClientItem operation failed %d, throwing exception\n", status);
  211.     AfxThrowOleException(status);
  212. }
  213.  
  214.  
  215. //////////////////////////////////////////////////////////////////////////////
  216. // Create variants for real OLEOBJECTs
  217.  
  218. // From clipboard
  219. BOOL COleClientItem::CanPaste(OLEOPT_RENDER renderopt,
  220.         OLECLIPFORMAT cfFormat)
  221. {
  222.     return ::OleQueryCreateFromClip(lpszStdProtocol,
  223.         renderopt, cfFormat) == OLE_OK ||
  224.         ::OleQueryCreateFromClip(lpszStaticProtocol,
  225.         renderopt, cfFormat) == OLE_OK;
  226. }
  227.  
  228. BOOL COleClientItem::CanPasteLink(OLEOPT_RENDER renderopt,
  229.         OLECLIPFORMAT cfFormat)
  230. {
  231.     return ::OleQueryLinkFromClip(lpszStdProtocol,
  232.       renderopt, cfFormat) == OLE_OK;
  233. }
  234.  
  235.  
  236. BOOL COleClientItem::CreateFromClipboard(LPCSTR lpszObjname,
  237.     OLEOPT_RENDER renderopt, OLECLIPFORMAT cfFormat)
  238. {
  239.     ASSERT(m_lpObject == NULL);     // one time only
  240.     ASSERT(m_pDocument != NULL);
  241.     ASSERT(m_pDocument->IsOpen());
  242.     ASSERT(lpszObjname != NULL);
  243.  
  244.     return CheckCreate(::OleCreateFromClip(lpszStdProtocol,
  245.         &m_oleClient, m_pDocument->m_lhClientDoc, lpszObjname,
  246.         &m_lpObject, renderopt, cfFormat));
  247. }
  248.  
  249. BOOL COleClientItem::CreateStaticFromClipboard(LPCSTR lpszObjname,
  250.     OLEOPT_RENDER renderopt, OLECLIPFORMAT cfFormat)
  251. {
  252.     ASSERT(m_lpObject == NULL);     // one time only
  253.     ASSERT(m_pDocument != NULL);
  254.     ASSERT(m_pDocument->IsOpen());
  255.     ASSERT(lpszObjname != NULL);
  256.  
  257.     return CheckCreate(::OleCreateFromClip(lpszStaticProtocol,
  258.         &m_oleClient, m_pDocument->m_lhClientDoc, lpszObjname,
  259.         &m_lpObject, renderopt, cfFormat));
  260. }
  261.  
  262. BOOL COleClientItem::CreateLinkFromClipboard(LPCSTR lpszObjname,
  263.     OLEOPT_RENDER renderopt, OLECLIPFORMAT cfFormat)
  264. {
  265.     ASSERT(m_lpObject == NULL);     // one time only
  266.     ASSERT(m_pDocument != NULL);
  267.     ASSERT(m_pDocument->IsOpen());
  268.     ASSERT(lpszObjname != NULL);
  269.  
  270.     return CheckCreate(::OleCreateLinkFromClip(lpszStdProtocol,
  271.         &m_oleClient, m_pDocument->m_lhClientDoc, lpszObjname,
  272.         &m_lpObject, renderopt, cfFormat));
  273. }
  274.  
  275.  
  276. // create from a protocol name or other template
  277. BOOL COleClientItem::CreateNewObject(LPCSTR lpszClass, LPCSTR lpszObjname,
  278.     OLEOPT_RENDER renderopt, OLECLIPFORMAT cfFormat)
  279. {
  280.     ASSERT(m_lpObject == NULL);     // one time only
  281.     ASSERT(m_pDocument != NULL);
  282.     ASSERT(m_pDocument->IsOpen());
  283.     ASSERT(lpszClass != NULL);
  284.     ASSERT(lpszObjname != NULL);
  285.  
  286.     return CheckCreate(::OleCreate(lpszStdProtocol,
  287.         &m_oleClient, lpszClass,
  288.         m_pDocument->m_lhClientDoc, lpszObjname,
  289.         &m_lpObject, renderopt, cfFormat));
  290. }
  291.  
  292. // create invisible
  293. BOOL COleClientItem::CreateInvisibleObject(LPCSTR lpszClass, LPCSTR lpszObjname,
  294.     OLEOPT_RENDER renderopt, OLECLIPFORMAT cfFormat, BOOL bActivate)
  295. {
  296.     ASSERT(m_lpObject == NULL);     // one time only
  297.     ASSERT(m_pDocument != NULL);
  298.     ASSERT(m_pDocument->IsOpen());
  299.     ASSERT(lpszClass != NULL);
  300.     ASSERT(lpszObjname != NULL);
  301.  
  302.     return CheckCreate(::OleCreateInvisible(lpszStdProtocol,
  303.         &m_oleClient, lpszClass,
  304.         m_pDocument->m_lhClientDoc, lpszObjname,
  305.         &m_lpObject, renderopt, cfFormat, bActivate));
  306. }
  307.  
  308.  
  309. /////////////////////////////////////////////////////////////////////////////
  310. // More advanced creation
  311.  
  312. BOOL COleClientItem::CreateCloneFrom(COleClientItem* pSrcObject,
  313.     LPCSTR lpszObjname)
  314. {
  315.     ASSERT(m_lpObject == NULL);     // one time only
  316.     ASSERT(pSrcObject != NULL);
  317.     ASSERT(m_pDocument != NULL);
  318.     ASSERT(m_pDocument->IsOpen());
  319.     ASSERT(lpszObjname != NULL);
  320.  
  321.     return CheckCreate(::OleClone(pSrcObject->m_lpObject,
  322.         &m_oleClient, m_pDocument->m_lhClientDoc, lpszObjname,
  323.         &m_lpObject));
  324. }
  325.  
  326.  
  327. /////////////////////////////////////////////////////////////////////////////
  328. // Default implementations
  329.  
  330. int COleClientItem::ClientCallBack(OLE_NOTIFICATION wNotification)
  331. {
  332.     switch (wNotification)
  333.     {
  334.     case OLE_CHANGED:   // OLE linked item updated
  335.     case OLE_SAVED:     // OLE server document saved
  336.     case OLE_CLOSED:    // OLE server document closed
  337.         OnChange(wNotification);
  338.         break;
  339.     case OLE_RENAMED:
  340.         OnRenamed();
  341.         break;
  342.     case OLE_RELEASE:
  343.         OnRelease();
  344.         break;
  345.     default:
  346.         // ignore it (eg: QueryPaint and QueryRetry)
  347.         break;
  348.     }
  349.  
  350.     return TRUE;    // return TRUE in general
  351. }
  352.  
  353. void COleClientItem::OnRenamed()
  354. {
  355.     // ignore normally
  356. }
  357.  
  358. void COleClientItem::OnRelease()
  359. {
  360.     ASSERT(m_lpObject != NULL);
  361.     // default will store the release error
  362.     m_lastStatus = ::OleQueryReleaseError(m_lpObject);
  363.     ASSERT(m_lastStatus != OLE_WAIT_FOR_RELEASE);
  364.  
  365.     if (m_lastStatus != OLE_OK)
  366.     {
  367.         // operation failed
  368. #ifdef _DEBUG
  369.         TRACE("Warning: COleClientItem::OnRelease with error %d ($%lx)\n", m_lastStatus,
  370.                 m_lpObject);
  371. #endif
  372.         return;
  373.     }
  374.  
  375.     // Success
  376.     OLE_RELEASE_METHOD nWhyReleased = ::OleQueryReleaseMethod(m_lpObject);
  377.  
  378.     if (nWhyReleased == OLE_DELETE)
  379.         m_lpObject = NULL;  // detach
  380. }
  381.  
  382. /////////////////////////////////////////////////////////////////////////////
  383. // COleClientItem - attributes
  384.  
  385.  
  386. UINT COleClientItem::GetType()
  387. {
  388.     ASSERT(m_lpObject != NULL);
  389.     LONG lType;
  390.  
  391.     CheckGeneral(::OleQueryType(m_lpObject, &lType));
  392.     ASSERT(lType == OT_LINK || lType == OT_EMBEDDED || lType == OT_STATIC);
  393.     return (UINT)lType;
  394. }
  395.  
  396.  
  397. CString COleClientItem::GetName()
  398. {
  399.     ASSERT(m_lpObject != NULL);
  400.     char szT[OLE_MAXNAMESIZE];
  401.  
  402.     UINT cb = OLE_MAXNAMESIZE;
  403.     CheckGeneral(::OleQueryName(m_lpObject, szT, &cb));
  404.  
  405.     ASSERT(cb == strlen(szT));
  406.     return CString(szT);
  407. }
  408.  
  409.  
  410. BOOL COleClientItem::GetSize(LPPOINT lpSize)
  411. {
  412.     ASSERT(m_lpObject != NULL);
  413.  
  414.     m_lastStatus = ::OleQuerySize(m_lpObject, (DWORD FAR*)lpSize);
  415.     if (m_lastStatus == OLE_ERROR_BLANK)
  416.         return FALSE;   // no size set yet
  417.     CheckGeneral(m_lastStatus);     // may throw exception
  418.     return TRUE;
  419. }
  420.  
  421. BOOL COleClientItem::GetBounds(LPRECT lpBounds)
  422. {
  423.     ASSERT(m_lpObject != NULL);
  424.  
  425.     m_lastStatus = ::OleQueryBounds(m_lpObject, lpBounds);
  426.     if (m_lastStatus == OLE_ERROR_BLANK)
  427.         return FALSE;   // no size set yet
  428.     CheckGeneral(m_lastStatus);     // may throw exception
  429.     return TRUE;
  430. }
  431.  
  432. BOOL COleClientItem::IsOpen()
  433. {
  434.     ASSERT(m_lpObject != NULL);
  435.  
  436.     m_lastStatus = ::OleQueryOpen(m_lpObject);
  437.     if (m_lastStatus == OLE_ERROR_NOT_OPEN)
  438.         return FALSE;       // not open
  439.     CheckGeneral(m_lastStatus);     // may throw exception
  440.     return TRUE;
  441. }
  442.  
  443. /////////////////////////////////////////////////////////////////////////////
  444. // Data exchange plus helpers
  445.  
  446. HANDLE
  447. COleClientItem::GetData(OLECLIPFORMAT nFormat, BOOL& bMustDelete)
  448. {
  449.     HANDLE hData = NULL;
  450.  
  451.     CheckGeneral(::OleGetData(m_lpObject, nFormat, &hData));
  452.  
  453.     ASSERT(hData != NULL);
  454.     bMustDelete = (m_lastStatus == OLE_WARN_DELETE_DATA);
  455.     return hData;
  456. }
  457.  
  458.  
  459. void
  460. COleClientItem::SetData(OLECLIPFORMAT nFormat, HANDLE hData)
  461. {
  462.     ASSERT(m_lpObject != NULL);
  463.     CheckAsync(::OleSetData(m_lpObject, nFormat, hData));
  464. }
  465.  
  466. void
  467. COleClientItem::RequestData(OLECLIPFORMAT nFormat)
  468. {
  469.     ASSERT(m_lpObject != NULL);
  470.     CheckAsync(::OleRequestData(m_lpObject, nFormat));
  471. }
  472.  
  473. /////////////////////////////////////////////////////////////////////////////
  474. // Rare or implementation specific attributes
  475.  
  476. BOOL
  477. COleClientItem::IsEqual(COleClientItem* pObject)
  478. {
  479.     ASSERT(m_lpObject != NULL);
  480.     ASSERT(pObject != NULL);
  481.     ASSERT(pObject->m_lpObject != NULL);
  482.  
  483.     m_lastStatus = ::OleEqual(m_lpObject, pObject->m_lpObject);
  484.     if (m_lastStatus == OLE_ERROR_NOT_EQUAL)
  485.         return FALSE;       // FALSE => not equal
  486.     CheckGeneral(m_lastStatus);     // may throw exception
  487.     return TRUE;    // otherwise equal
  488. }
  489.  
  490. HANDLE
  491. COleClientItem::GetLinkFormatData()
  492. // Return global HANDLE of block containing link information
  493. //   will return NULL if error or not appropriate type
  494. //   Both link formats are:  "szClass0szDocument0szItem00" */
  495. {
  496.     OLECLIPFORMAT cf = NULL;
  497.  
  498.     // first determine the format of the link data
  499.     switch (GetType())
  500.     {
  501.     default:
  502.         return NULL;    // Static or other (i.e. no link format)
  503.     case OT_EMBEDDED:
  504.         cf = (OLECLIPFORMAT)::RegisterClipboardFormat("OwnerLink");
  505.         break;
  506.     case OT_LINK:
  507.         cf = (OLECLIPFORMAT)::RegisterClipboardFormat("ObjectLink");
  508.         break;
  509.     }
  510.     ASSERT(cf != NULL);
  511.  
  512.     // now get the link data
  513.     BOOL bMustDelete;
  514.     HANDLE h;
  515.     if ((h = GetData(cf, bMustDelete)) == NULL)
  516.         return NULL;
  517.     ASSERT(!bMustDelete);       // must not have to delete clip format data
  518.     return h;
  519. }
  520.  
  521.  
  522. /////////////////////////////////////////////////////////////////////////////
  523. // Special link attributes
  524.  
  525. OLEOPT_UPDATE COleClientItem::GetLinkUpdateOptions()
  526. {
  527.     ASSERT(m_lpObject != NULL);
  528.     OLEOPT_UPDATE updateOpt;
  529.  
  530.     CheckGeneral(::OleGetLinkUpdateOptions(m_lpObject, &updateOpt));
  531.     return updateOpt;
  532. }
  533.  
  534. void
  535. COleClientItem::SetLinkUpdateOptions(OLEOPT_UPDATE updateOpt)
  536. {
  537.     ASSERT(m_lpObject != NULL);
  538.  
  539.     CheckAsync(::OleSetLinkUpdateOptions(m_lpObject, updateOpt));
  540. }
  541.  
  542. /////////////////////////////////////////////////////////////////////////////
  543. // COleClientItem - general operations
  544.  
  545. BOOL
  546. COleClientItem::Draw(CDC *pDC, LPRECT lpBounds, LPRECT lpWBounds,
  547.     CDC* pFormatDC)
  548. {
  549.     ASSERT(m_lpObject != NULL);
  550.     ASSERT(pDC != NULL);
  551.     // pFormatDC may be null
  552.  
  553.     m_lastStatus = ::OleDraw(m_lpObject, pDC->m_hDC, lpBounds,
  554.        lpWBounds, pFormatDC->GetSafeHdc());
  555.  
  556.     if (m_lastStatus == OLE_ERROR_ABORT || m_lastStatus == OLE_ERROR_DRAW ||
  557.       m_lastStatus == OLE_ERROR_BLANK)
  558.         return FALSE;       // expected errors
  559.  
  560.     CheckGeneral(m_lastStatus);     // may throw exception
  561.     return TRUE;    // it worked
  562. }
  563.  
  564. void
  565. COleClientItem::Activate(UINT nVerb, BOOL bShow, BOOL bTakeFocus,
  566.     CWnd* pWndContainer, LPRECT lpBounds)
  567. {
  568.     ASSERT(m_lpObject != NULL);
  569.  
  570.     CheckAsync(::OleActivate(m_lpObject, nVerb, bShow,
  571.         bTakeFocus, pWndContainer->GetSafeHwnd(), lpBounds));
  572. }
  573.  
  574. /////////////////////////////////////////////////////////////////////////////
  575. // more advanced operations
  576.  
  577. void
  578. COleClientItem::Rename(LPCSTR lpszNewname)
  579. {
  580.     ASSERT(m_lpObject != NULL);
  581.     ASSERT(lpszNewname != NULL);
  582.     CheckGeneral(::OleRename(m_lpObject, lpszNewname));
  583. }
  584.  
  585. void
  586. COleClientItem::CopyToClipboard()
  587. {
  588.     ASSERT(m_lpObject != NULL);
  589.  
  590.     CheckGeneral(::OleCopyToClipboard(m_lpObject));
  591. }
  592.  
  593. void
  594. COleClientItem::SetTargetDevice(HANDLE hData)
  595. {
  596.     ASSERT(m_lpObject != NULL);
  597.     ASSERT(hData != NULL);
  598.     CheckAsync(::OleSetTargetDevice(m_lpObject, hData));
  599. }
  600.  
  601. /////////////////////////////////////////////////////////////////////////////
  602. // Embedded COleClient operations
  603.  
  604. void
  605. COleClientItem::SetHostNames(LPCSTR lpszHost, LPCSTR lpszHostObj)
  606. {
  607.     ASSERT(m_lpObject != NULL);
  608.     ASSERT(lpszHost != NULL);
  609.     ASSERT(lpszHostObj != NULL);
  610.  
  611.     CheckAsync(::OleSetHostNames(m_lpObject, lpszHost, lpszHostObj));
  612. }
  613.  
  614. void
  615. COleClientItem::SetBounds(LPRECT lpRect)
  616. {
  617.     ASSERT(m_lpObject != NULL);
  618.     CheckAsync(::OleSetBounds(m_lpObject, lpRect));
  619. }
  620.  
  621. void
  622. COleClientItem::SetColorScheme(LPLOGPALETTE lpLogPalette)
  623. {
  624.     ASSERT(m_lpObject != NULL);
  625.     CheckAsync(::OleSetColorScheme(m_lpObject, lpLogPalette));
  626. }
  627.  
  628. /////////////////////////////////////////////////////////////////////////////
  629. // Linked COleClient operations
  630.  
  631. void
  632. COleClientItem::UpdateLink()
  633. {
  634.     ASSERT(m_lpObject != NULL);
  635.  
  636.     CheckAsync(::OleUpdate(m_lpObject));
  637. }
  638.  
  639. void COleClientItem::CloseLink()
  640. {
  641.     if (m_lpObject == NULL)
  642.         return;
  643.  
  644.     CheckAsync(::OleClose(m_lpObject));
  645.     // Does not detach since this can be reactivated later
  646. }
  647.  
  648. void
  649. COleClientItem::ReconnectLink()
  650. {
  651.     ASSERT(m_lpObject != NULL);
  652.     CheckAsync(::OleReconnect(m_lpObject));
  653. }
  654.  
  655. BOOL COleClientItem::FreezeLink(LPCSTR lpszFrozenName)
  656. {
  657.     ASSERT(m_lpObject != NULL);
  658.     ASSERT(m_pDocument != NULL);
  659.     ASSERT(m_pDocument->IsOpen());
  660.     ASSERT(lpszFrozenName != NULL);
  661.  
  662.     ASSERT(GetType() == OT_LINK);
  663.  
  664.     LPOLEOBJECT lpOriginalObject = m_lpObject;
  665.     m_lpObject = NULL;
  666.     if (!CheckCreate(::OleObjectConvert(lpOriginalObject,
  667.         lpszStaticProtocol,
  668.         &m_oleClient, m_pDocument->m_lhClientDoc, lpszFrozenName,
  669.         &m_lpObject)))
  670.     {
  671.         m_lpObject = lpOriginalObject;
  672.         return FALSE;
  673.     }
  674.     ASSERT(GetType() == OT_STATIC);
  675.  
  676.     // copy from link worked - now get rid of the original
  677.     ASSERT(m_lpObject != lpOriginalObject);
  678.     ASSERT(m_lpObject != NULL);
  679.  
  680.     LPOLEOBJECT lpNewObject = m_lpObject;
  681.     m_lpObject = lpOriginalObject;
  682.     ASSERT(GetType() == OT_LINK);
  683.     Delete();
  684.  
  685.     ASSERT(m_lpObject == NULL);
  686.     m_lpObject = lpNewObject;
  687.     ASSERT(GetType() == OT_STATIC);
  688.  
  689.     return TRUE;
  690. }
  691.  
  692. /////////////////////////////////////////////////////////////////////////////
  693. /////////////////////////////////////////////////////////////////////////////
  694. // _COleStream - implementation class connecting OLESTREAM and CArchive
  695.  
  696. struct _COleStream : public _OLESTREAM
  697. {
  698.     CArchive*   m_pArchive;
  699.     _COleStream(CArchive& ar);
  700. };
  701.  
  702. static UINT CalcSize(DWORD cbTotal, const void FAR* lpStart)
  703. {
  704.     // return size to read/write (16K max unless limited by segment bounds)
  705.     DWORD cbThisSeg = 0x10000 - _AFX_FP_OFF(lpStart);
  706.     DWORD cb = min(cbThisSeg, cbTotal);
  707.     return (cb > 16384) ? 16384 : (UINT)cb;
  708. }
  709.  
  710. // class for static exports
  711. struct _afxOleStreamImplementation
  712. {
  713.     static DWORD OLEEXPORT
  714.     Get(LPOLESTREAM lpStream, void FAR* lpBuffer, DWORD dwCount)
  715.     {
  716.         register _COleStream* pStream =
  717.             (_COleStream*)GetPtrFromFarPtr(lpStream, 0);
  718.         ASSERT(((LPVOID)pStream) == (LPVOID)lpStream);  // no near/far mismatch
  719.  
  720.         DWORD dwToRead = dwCount;
  721.         while (dwToRead > 0)
  722.         {
  723.             UINT nRead = CalcSize(dwToRead, lpBuffer);
  724.             pStream->m_pArchive->Read(lpBuffer, nRead);
  725.             dwToRead -= nRead;
  726.             lpBuffer = ((BYTE _huge*)lpBuffer) + nRead;
  727.         }
  728.         return dwCount;
  729.     }
  730.  
  731.     static DWORD OLEEXPORT
  732.     Put(LPOLESTREAM lpStream, OLE_CONST void FAR* lpBuffer, DWORD dwCount)
  733.     {
  734.         register _COleStream* pStream =
  735.             (_COleStream*)GetPtrFromFarPtr(lpStream, 0);
  736.         ASSERT(((LPVOID)pStream) == (LPVOID)lpStream);  // no near/far mismatch
  737.  
  738.         DWORD dwToWrite = dwCount;
  739.         while (dwToWrite > 0)
  740.         {
  741.             UINT nWrite = CalcSize(dwToWrite, lpBuffer);
  742.             pStream->m_pArchive->Write(lpBuffer, nWrite);
  743.             dwToWrite -= nWrite;
  744.             lpBuffer = ((OLE_CONST BYTE _huge*)lpBuffer) + nWrite;
  745.         }
  746.         return dwCount;
  747.     }
  748. };
  749.  
  750. static struct _OLESTREAMVTBL NEAR streamVtbl =
  751. {
  752.     &_afxOleStreamImplementation::Get,
  753.     &_afxOleStreamImplementation::Put
  754. };
  755.  
  756. _COleStream::_COleStream(CArchive& ar)
  757. {
  758.     m_pArchive = &ar;
  759.     lpstbl = &streamVtbl;           // OLE VTable setup
  760. }
  761.  
  762. /////////////////////////////////////////////////////////////////////////////
  763. // COleClientItem - serialization
  764.  
  765. void COleClientItem::Serialize(CArchive& ar)
  766. {
  767.     ASSERT(GetDocument() != NULL);  // must 'SetDocument' first
  768.     _COleStream oleStream(ar);
  769.  
  770.     if (ar.IsStoring())
  771.     {
  772.         ASSERT(m_lpObject != NULL);
  773.         ar << (WORD) GetType();
  774.         ar << GetName();        // save our document name
  775.  
  776.         // Save object
  777.         CheckGeneral(::OleSaveToStream(m_lpObject, &oleStream));
  778.     }
  779.     else
  780.     {
  781.         ASSERT(m_lpObject == NULL);
  782.  
  783.         WORD nType;
  784.         ar >> nType;
  785.         LPCSTR lpszProtocol;
  786.  
  787.         if (nType == OT_LINK || nType == OT_EMBEDDED)
  788.         {
  789.             lpszProtocol = lpszStdProtocol;
  790.         }
  791.         else if (nType == OT_STATIC)
  792.         {
  793.             lpszProtocol = lpszStaticProtocol;
  794.         }
  795.         else
  796.         {
  797.             // unknown type (i.e. bad file format)
  798.             AfxThrowOleException(OLE_ERROR_GENERIC);
  799.         }
  800.  
  801.         CString name;
  802.         ar >> name; // document name
  803.         if (!CheckCreate(::OleLoadFromStream(&oleStream, lpszProtocol,
  804.             &m_oleClient, m_pDocument->m_lhClientDoc, name, &m_lpObject)))
  805.         {
  806.             // throw an exception regardless
  807.             AfxThrowOleException(GetLastStatus());
  808.         }
  809.     }
  810. }
  811.  
  812. /////////////////////////////////////////////////////////////////////////////
  813. // COleClientDoc - wrapper for LHCLIENTDOC
  814.  
  815. IMPLEMENT_DYNAMIC(COleClientDoc, CObject)
  816.  
  817. COleClientDoc::COleClientDoc()
  818. {
  819.     m_lhClientDoc = NULL;       // not open
  820. }
  821.  
  822. void
  823. COleClientDoc::Revoke()
  824. {
  825.     if (!IsOpen())
  826.         return;
  827.     LHCLIENTDOC lh = m_lhClientDoc;
  828.     ASSERT(lh != NULL);
  829.     m_lhClientDoc = NULL;
  830.     CheckGeneral(::OleRevokeClientDoc(lh));
  831. }
  832.  
  833. COleClientDoc::~COleClientDoc()
  834. {
  835.     Revoke();
  836. }
  837.  
  838. void COleClientDoc::CheckGeneral(OLESTATUS status) const
  839.     // throw exception if not ok to continue
  840. {
  841.     ASSERT(status != OLE_WAIT_FOR_RELEASE);
  842.  
  843.     if (status == OLE_OK || status > OLE_WARN_DELETE_DATA)
  844.     {
  845.         // ok, or just a warning
  846.         return;
  847.     }
  848.  
  849.     // otherwise this error wasn't expected, so throw an exception
  850.     TRACE("Warning: COleClientDoc operation failed %d, throwing exception\n", status);
  851.     AfxThrowOleException(status);
  852. }
  853.  
  854. BOOL
  855. COleClientDoc::Register(LPCSTR lpszClass, LPCSTR lpszDoc)
  856. {
  857.     ASSERT(m_lhClientDoc == NULL);      // one time only
  858.     return ::OleRegisterClientDoc(lpszClass, lpszDoc,
  859.          0L /*reserved*/, &m_lhClientDoc) == OLE_OK;
  860. }
  861.  
  862. void
  863. COleClientDoc::NotifyRename(LPCSTR lpszNewName)
  864. {
  865.     ASSERT(IsOpen());
  866.     ASSERT(lpszNewName != NULL);
  867.  
  868.     CheckGeneral(::OleRenameClientDoc(m_lhClientDoc, lpszNewName));
  869. }
  870.  
  871. void
  872. COleClientDoc::NotifyRevert()
  873. {
  874.     ASSERT(IsOpen());
  875.  
  876.     CheckGeneral(::OleRevertClientDoc(m_lhClientDoc));
  877. }
  878.  
  879. void
  880. COleClientDoc::NotifySaved()
  881. {
  882.     ASSERT(IsOpen());
  883.  
  884.     CheckGeneral(::OleSavedClientDoc(m_lhClientDoc));
  885. }
  886.  
  887. /////////////////////////////////////////////////////////////////////////////
  888. // Diagnostics
  889.  
  890. #ifdef _DEBUG
  891. void COleClientItem::AssertValid() const
  892. {
  893.     CObject::AssertValid();
  894.     ASSERT(m_pDocument != NULL);
  895. }
  896.  
  897. void COleClientItem::Dump(CDumpContext& dc) const
  898. {
  899.     CObject::Dump(dc);
  900.  
  901.     // shallow dump
  902.     dc << "\n\tm_pDocument = " << (void*) m_pDocument;
  903.     dc << "\n\tm_lpObject = " << m_lpObject;
  904.     dc << "\n\tm_lastStatus = " << (int)m_lastStatus;
  905. }
  906.  
  907.  
  908. void COleClientDoc::AssertValid() const
  909. {
  910.     CObject::AssertValid();
  911.     ASSERT(m_lhClientDoc != NULL);
  912.         // only valid if truely open
  913. }
  914.  
  915. void COleClientDoc::Dump(CDumpContext& dc) const
  916. {
  917.     CObject::Dump(dc);
  918.     dc << "\n\tm_lhClientDoc = " << m_lhClientDoc;
  919. }
  920.  
  921. #endif //_DEBUG
  922.  
  923.  
  924. /////////////////////////////////////////////////////////////////////////////
  925.