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