home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / MFC / SRC / OLESVR.CP_ / OLESVR.CP
Encoding:
Text File  |  1993-02-08  |  46.8 KB  |  1,848 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. #include <shellapi.h>
  13.  
  14. #ifdef AFX_OLE_SEG
  15. #pragma code_seg(AFX_OLE_SEG)
  16. #endif
  17.  
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char BASED_CODE THIS_FILE[] = __FILE__;
  21. #endif
  22.  
  23. #define OLEEXPORT CALLBACK AFX_EXPORT
  24. #ifdef AFX_CLASS_MODEL
  25. #define OLEVTBLMODEL NEAR
  26. #else
  27. #define OLEVTBLMODEL
  28. #endif
  29.  
  30. /////////////////////////////////////////////////////////////////////////////
  31. // Helper class for locking out main message pump during callbacks
  32.  
  33. class LOCK_PUMP
  34. {
  35. public:
  36.     LOCK_PUMP()
  37.     {
  38. #ifdef _DEBUG
  39.         AfxGetApp()->m_nDisablePumpCount++; // prevent App re-entrancy
  40. #endif
  41.     }
  42.  
  43.     ~LOCK_PUMP()
  44.     {
  45. #ifdef _DEBUG
  46.         AfxGetApp()->m_nDisablePumpCount--;
  47. #endif
  48.     }
  49. };
  50.  
  51. #ifdef _DEBUG
  52. #define OLE_TRACE0(string)   \
  53.     if (afxTraceFlags & 0x10)   \
  54.         TRACE0(string)
  55. #define OLE_TRACE1(string, p1)   \
  56.     if (afxTraceFlags & 0x10)   \
  57.         TRACE1(string, p1)
  58. #define OLE_TRACE2(string, p1, p2)   \
  59.     if (afxTraceFlags & 0x10)   \
  60.         TRACE2(string, p1, p2)
  61. #else
  62. // traces are nothing
  63. #define OLE_TRACE0  TRACE0
  64. #define OLE_TRACE1  TRACE1
  65. #define OLE_TRACE2  TRACE2
  66. #endif
  67.  
  68. /////////////////////////////////////////////////////////////////////////////
  69. // OLEOBJECT callbacks mapping to COleServerItem virtual functions
  70.  
  71. // convert far LPOLEOBJECT to ambient model COleServerItem
  72. inline COleServerItem* PASCAL COleServerItem::FromLp(LPOLEOBJECT lpObject)
  73. {
  74.     ASSERT(lpObject != NULL);
  75.     COleServerItem* pItem = (COleServerItem*)
  76.         ((BYTE*)_AfxGetPtrFromFarPtr(lpObject) - sizeof(CDocItem));
  77.     ASSERT(lpObject == &pItem->m_oleObject);
  78.     return pItem;
  79. }
  80.  
  81. // friend class to get access to COleServerItem protected implementations
  82. struct _afxOleSvrItemImpl
  83. {
  84.     static LPVOID OLEEXPORT QueryProtocol(LPOLEOBJECT lpObject,
  85.         OLE_LPCSTR lpszProtocol);
  86.     static OLESTATUS OLEEXPORT Release(LPOLEOBJECT lpObject);
  87.     static OLESTATUS OLEEXPORT Show(LPOLEOBJECT lpObject,
  88.         BOOL bTakeFocus);
  89.     static OLESTATUS OLEEXPORT DoVerb(LPOLEOBJECT lpObject,
  90.         UINT nVerb, BOOL bShow, BOOL bTakeFocus);
  91.     static OLESTATUS OLEEXPORT GetData(LPOLEOBJECT lpObject,
  92.         OLECLIPFORMAT nFormat, LPHANDLE lphDataReturn);
  93.     static OLESTATUS OLEEXPORT SetData(LPOLEOBJECT lpObject,
  94.         OLECLIPFORMAT nFormat, HANDLE hData);
  95.     static OLESTATUS OLEEXPORT SetTargetDevice(LPOLEOBJECT lpObject,
  96.         HGLOBAL hData);
  97.     static OLESTATUS OLEEXPORT SetBounds(LPOLEOBJECT lpObject,
  98.         OLE_CONST RECT FAR* lpRect);
  99.     static OLECLIPFORMAT OLEEXPORT EnumFormats(LPOLEOBJECT lpObject,
  100.         OLECLIPFORMAT nFormat);
  101.     static OLESTATUS OLEEXPORT SetColorScheme(LPOLEOBJECT lpObject,
  102.         OLE_CONST LOGPALETTE FAR* lpLogPalette);
  103. };
  104.  
  105. LPVOID OLEEXPORT _afxOleSvrItemImpl::QueryProtocol(LPOLEOBJECT lpObject,
  106.     OLE_LPCSTR lpszProtocol)
  107. {
  108.     LOCK_PUMP lock;
  109.     OLE_TRACE0("COleServerItem::OnQueryProtocol()\n");
  110.     return COleServerItem::FromLp(lpObject)->OnQueryProtocol(lpszProtocol);
  111. }
  112.  
  113. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::Release(LPOLEOBJECT lpObject)
  114. {
  115.     LOCK_PUMP lock;
  116.     OLE_TRACE0("COleServerItem::OnRelease()\n");
  117.     return COleServerItem::FromLp(lpObject)->OnRelease();
  118. }
  119.  
  120. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::Show(LPOLEOBJECT lpObject,
  121.     BOOL bTakeFocus)
  122. {
  123.     LOCK_PUMP lock;
  124.     OLE_TRACE0("COleServerItem::OnShow()\n");
  125.     return COleServerItem::FromLp(lpObject)->OnShow(bTakeFocus);
  126. }
  127.  
  128. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::DoVerb(LPOLEOBJECT lpObject,
  129.     UINT nVerb, BOOL bShow, BOOL bTakeFocus)
  130. {
  131.     LOCK_PUMP lock;
  132.     OLE_TRACE0("COleServerItem::OnDoVerb()\n");
  133.  
  134.     OLESTATUS status;
  135.     status = COleServerItem::FromLp(lpObject)->OnDoVerb(nVerb, bShow,
  136.         bTakeFocus);
  137. #ifdef _DEBUG
  138.     if (status != OLE_OK)
  139.         OLE_TRACE1("COleServerItem::OnDoVerb(%d) failed\n", nVerb);
  140. #endif
  141.     return status;
  142. }
  143.  
  144. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::GetData(LPOLEOBJECT lpObject,
  145.     OLECLIPFORMAT nFormat, LPHANDLE lphDataReturn)
  146. {
  147.     LOCK_PUMP lock;
  148.     OLE_TRACE0("COleServerItem::OnGetData()\n");
  149.     OLESTATUS status;
  150.     status = COleServerItem::FromLp(lpObject)->OnGetData(nFormat, lphDataReturn);
  151. #ifdef _DEBUG
  152.     if (status != OLE_OK)
  153.         OLE_TRACE1("COleServerItem::OnGetData() failed to get format 0x%x\n",
  154.                 nFormat);
  155. #endif
  156.     return status;
  157. }
  158.  
  159. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::SetData(LPOLEOBJECT lpObject,
  160.     OLECLIPFORMAT nFormat, HANDLE hData)
  161. {
  162.     LOCK_PUMP lock;
  163.     OLE_TRACE0("COleServerItem::OnSetData()\n");
  164.     return COleServerItem::FromLp(lpObject)->OnSetData(nFormat, hData);
  165. }
  166.  
  167. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::SetTargetDevice(LPOLEOBJECT lpObject,
  168.     HGLOBAL hData)
  169. {
  170.     LOCK_PUMP lock;
  171.     OLE_TRACE0("COleServerItem::OnSetTargetDevice()\n");
  172.  
  173.     OLESTATUS status;
  174.     status = COleServerItem::FromLp(lpObject)->OnSetTargetDevice(
  175.         (LPOLETARGETDEVICE)((hData == NULL) ? NULL : ::GlobalLock(hData)));
  176.  
  177.     if (hData != NULL)
  178.     {
  179.         ::GlobalUnlock(hData);
  180.         ::GlobalFree(hData);
  181.     }
  182.     return status;
  183. }
  184.  
  185. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::SetBounds(LPOLEOBJECT lpObject,
  186.     OLE_CONST RECT FAR* lpRect)
  187. {
  188.     LOCK_PUMP lock;
  189.     OLE_TRACE0("COleServerItem::SetBounds()\n");
  190.     return COleServerItem::FromLp(lpObject)->OnSetBounds(lpRect);
  191. }
  192.  
  193. OLECLIPFORMAT OLEEXPORT _afxOleSvrItemImpl::EnumFormats(LPOLEOBJECT lpObject,
  194.     OLECLIPFORMAT nFormat)
  195. {
  196.     OLECLIPFORMAT cfNext;
  197.     LOCK_PUMP lock;
  198.     cfNext = COleServerItem::FromLp(lpObject)->OnEnumFormats(nFormat);
  199.     OLE_TRACE2("COleServerItem::OnEnumFormats(0x%x) returns 0x%x\n",
  200.         nFormat, cfNext);
  201.     return cfNext;
  202. }
  203.  
  204. OLESTATUS OLEEXPORT _afxOleSvrItemImpl::SetColorScheme(LPOLEOBJECT lpObject,
  205.     OLE_CONST LOGPALETTE FAR* lpLogPalette)
  206. {
  207.     LOCK_PUMP lock;
  208.     OLE_TRACE0("COleServerItem::SetColorScheme()\n");
  209.     return COleServerItem::FromLp(lpObject)->
  210.             OnSetColorScheme(lpLogPalette);
  211. }
  212.  
  213. static struct _OLEOBJECTVTBL OLEVTBLMODEL objectVtbl =
  214. {
  215.     _afxOleSvrItemImpl::QueryProtocol,
  216.     _afxOleSvrItemImpl::Release,
  217.     _afxOleSvrItemImpl::Show,
  218.     _afxOleSvrItemImpl::DoVerb,
  219.     _afxOleSvrItemImpl::GetData,
  220.     _afxOleSvrItemImpl::SetData,
  221.     _afxOleSvrItemImpl::SetTargetDevice,
  222.     _afxOleSvrItemImpl::SetBounds,
  223.     _afxOleSvrItemImpl::EnumFormats,
  224.     _afxOleSvrItemImpl::SetColorScheme,
  225. };
  226.  
  227. //////////////////////////////////////////////////////////////////////////////
  228. // Server view of embedded OLEOBJECT (includes back pointer to OLECLIENT)
  229.  
  230. IMPLEMENT_DYNAMIC(COleServerItem, CDocItem)
  231.  
  232. COleServerItem::COleServerItem(COleServerDoc* pContainerDoc)
  233. {
  234.     ASSERT(pContainerDoc != NULL);
  235.     ASSERT_VALID(pContainerDoc);
  236.  
  237.     m_oleObject.lpvtbl = &objectVtbl;
  238.     m_pDocument = NULL;
  239.     m_lpClient = NULL;  // will be set later
  240.     m_rectBounds.SetRectEmpty();
  241.  
  242.     pContainerDoc->AddItem(this);
  243.     ASSERT(m_pDocument == pContainerDoc);
  244. }
  245.  
  246. COleServerItem::~COleServerItem()
  247. {
  248.     Revoke();
  249.     ASSERT(m_lpClient == NULL);     // must be released first
  250.     ASSERT(m_pDocument != NULL);
  251.     m_pDocument->RemoveItem(this);
  252. }
  253.  
  254. void COleServerItem::BeginRevoke()   // Start revoking the client connection
  255. {
  256.     ASSERT_VALID(this);
  257.     ASSERT(m_lpClient != NULL);
  258.  
  259.     OLESTATUS status = ::OleRevokeObject(m_lpClient);
  260.     ASSERT(status == OLE_OK || status == OLE_WAIT_FOR_RELEASE);
  261.     // revoke will not be finished until OnRelease called
  262. }
  263.  
  264. void COleServerItem::Revoke()   // revoke - wait if necessary
  265. {
  266.     ASSERT_VALID(this);
  267.     if (m_lpClient == NULL)
  268.         return;
  269.  
  270.     OLESTATUS status = ::OleRevokeObject(m_lpClient);
  271.     if (status == OLE_WAIT_FOR_RELEASE)
  272.     {
  273.         while (m_lpClient != NULL)
  274.         {
  275.             OLE_TRACE0("OLE Server Item waiting for release\n");
  276.             AfxGetApp()->PumpMessage();
  277.         }
  278.     }
  279.     m_lpClient = NULL;  // just in case
  280. }
  281.  
  282. int COleServerItem::NotifyClient(OLE_NOTIFICATION wNotify)
  283. {
  284.     ASSERT_VALID(this);
  285.     ASSERT(m_lpClient != NULL);
  286.     ASSERT(wNotify <= OLE_QUERY_RETRY); // last valid notification code
  287.  
  288.     OLE_TRACE1("Notifying client item (wNotification = %d)\n", wNotify);
  289.     return (*m_lpClient->lpvtbl->CallBack)(m_lpClient, wNotify, &m_oleObject);
  290. }
  291.  
  292. //////////////////////////////////////////////////////////////////////////////
  293. // Default implementations
  294.  
  295. OLESTATUS COleServerItem::OnRelease()
  296. {
  297.     ASSERT_VALID(this);
  298.     ASSERT(m_lpClient != NULL);
  299.     m_lpClient = NULL;
  300.  
  301.     return OLE_OK;
  302. }
  303.  
  304.  
  305. OLESTATUS
  306. COleServerItem::OnSetTargetDevice(LPOLETARGETDEVICE /*lpTargetDevice*/)
  307. {
  308.     ASSERT_VALID(this);
  309.     // default to ignore request
  310.     return OLE_OK;
  311. }
  312.  
  313.  
  314. BOOL COleServerItem::OnGetTextData(CString& /*rStringReturn*/) const
  315. {
  316.     ASSERT_VALID(this);
  317.     // default to not supported
  318.     return FALSE;
  319. }
  320.  
  321.  
  322. OLESTATUS COleServerItem::OnExtraVerb(UINT /*nVerb*/)
  323. {
  324.     ASSERT_VALID(this);
  325.     return OLE_ERROR_DOVERB;    // Error in sending do verb, or invalid
  326. }
  327.  
  328.  
  329. // Overridables you do not have to override
  330. LPVOID COleServerItem::OnQueryProtocol(LPCSTR lpszProtocol) const
  331. {
  332.     ASSERT_VALID(this);
  333.  
  334.     static char BASED_CODE szStdFileEditing[] = "StdFileEditing";
  335.     if (lstrcmp(lpszProtocol, szStdFileEditing) == 0)
  336.         return (LPVOID) &m_oleObject;
  337.  
  338.     return NULL;        // not supported
  339. }
  340.  
  341.  
  342. OLESTATUS COleServerItem::OnSetColorScheme(const LOGPALETTE FAR*)
  343. {
  344.     ASSERT_VALID(this);
  345.     // default does nothing
  346.     return OLE_OK;
  347. }
  348.  
  349. OLESTATUS COleServerItem::OnSetBounds(LPCRECT lpRect)
  350. {
  351.     ASSERT_VALID(this);
  352.  
  353.     m_rectBounds = lpRect;
  354.     return OLE_OK;
  355. }
  356.  
  357.  
  358. OLESTATUS COleServerItem::OnDoVerb(UINT nVerb, BOOL bShow, BOOL bTakeFocus)
  359. {
  360.     ASSERT_VALID(this);
  361.  
  362.     OLESTATUS status;
  363.     if (nVerb == OLEVERB_PRIMARY)
  364.     {
  365.         status = OLE_OK;
  366.     }
  367.     else
  368.     {
  369.         status = OnExtraVerb(nVerb);
  370.     }
  371.  
  372.     if ((status == OLE_OK) && bShow)
  373.         status = OnShow(bTakeFocus);
  374.     return status;
  375. }
  376.  
  377. OLESTATUS COleServerItem::OnShow(BOOL bTakeFocus)
  378. {
  379.     ASSERT_VALID(this);
  380.  
  381.     // find the first view of this document
  382.     POSITION pos = GetDocument()->GetFirstViewPosition();
  383.     if (pos == NULL)
  384.         return OLE_ERROR_SHOW;      // no view
  385.     CView* pView;
  386.     if ((pView = GetDocument()->GetNextView(pos)) == NULL)
  387.         return OLE_ERROR_SHOW;      // no view
  388.  
  389.     // activate frame holding view
  390.     CFrameWnd* pFrame = pView->GetParentFrame();
  391.     if (pFrame != NULL)
  392.         pFrame->ActivateFrame();
  393.     CFrameWnd* pAppFrame;
  394.     if (pFrame != (pAppFrame = (CFrameWnd*)AfxGetApp()->m_pMainWnd))
  395.     {
  396.         ASSERT(pAppFrame->IsKindOf(RUNTIME_CLASS(CFrameWnd)));
  397.         pAppFrame->ActivateFrame();
  398.     }
  399.  
  400.     if (bTakeFocus)
  401.         pView->SetFocus();
  402.  
  403.     return OLE_OK;
  404. }
  405.  
  406.  
  407. ///////////////////////////////////////////////////////
  408. // Clipboard formats
  409.  
  410. OLECLIPFORMAT COleServerItem::OnEnumFormats(OLECLIPFORMAT nFormat) const
  411. {
  412.     ASSERT_VALID(this);
  413.  
  414.     // order of clipboard formats is TEXT, NATIVE, METAFILE
  415.     if (nFormat == 0)
  416.     {
  417.         // check to see if we can do CF_TEXT
  418.         CString strTmp;
  419.         if (OnGetTextData(strTmp))
  420.             return CF_TEXT;     // we can
  421.         // fall through to native
  422.     }
  423.  
  424.     if (nFormat == 0 || nFormat == CF_TEXT)
  425.     {
  426.         // native format next (see GetNativeData)
  427.         return (OLECLIPFORMAT)afxData.cfNative;
  428.     }
  429.     else if (nFormat == afxData.cfNative)
  430.     {
  431.         // item drawn into a metafile (see GetMetafileData)
  432.         return CF_METAFILEPICT;
  433.     }
  434.  
  435.     // no more standard clipboard formats
  436.     return 0;
  437. }
  438.  
  439. HGLOBAL COleServerItem::GetNativeData()
  440. {
  441.     ASSERT_VALID(this);
  442.  
  443.     // get native data via serialization
  444.     CSharedFile memFile;
  445.  
  446.     TRY
  447.     {
  448.         CArchive    getArchive(&memFile, CArchive::store);
  449.         Serialize(getArchive);        // store to archive
  450.     }
  451.     CATCH(CNotSupportedException, e)
  452.     {
  453.         memFile.Close();
  454.         return NULL;        // not supported
  455.     }
  456.     AND_CATCH_ALL(e)
  457.     {
  458.         memFile.Close();
  459.         THROW_LAST();       // will be caught in GetData
  460.     }
  461.     END_CATCH_ALL
  462.     return memFile.Detach();
  463. }
  464.  
  465. HGLOBAL COleServerItem::GetMetafileData()
  466. {
  467.     ASSERT_VALID(this);
  468.  
  469.     CMetaFileDC dc;
  470.     if (!dc.Create())
  471.         return NULL;
  472.  
  473.     // Paint directly into the metafile.
  474.     if (!OnDraw(&dc))
  475.     {
  476.         OLE_TRACE0("calling COleServerItem::OnDraw() failed\n");
  477.         return NULL;    // will destroy DC
  478.     }
  479.  
  480.     HMETAFILE hMF = (HMETAFILE)dc.Close();
  481.     if (hMF == NULL)
  482.         return NULL;
  483.  
  484.     HGLOBAL hPict;
  485.     if ((hPict = ::GlobalAlloc(GMEM_DDESHARE, sizeof(METAFILEPICT))) == NULL)
  486.     {
  487.         DeleteMetaFile(hMF);
  488.         return NULL;
  489.     }
  490.  
  491.     LPMETAFILEPICT lpPict;
  492.     if ((lpPict = (LPMETAFILEPICT)::GlobalLock(hPict)) == NULL)
  493.     {
  494.         DeleteMetaFile(hMF);
  495.         ::GlobalFree(hPict);
  496.         return NULL;
  497.     }
  498.  
  499.     // set the metafile size here
  500.     lpPict->mm = MM_ANISOTROPIC;
  501.     lpPict->hMF = hMF;
  502.     lpPict->xExt = m_rectBounds.Width();
  503.     ASSERT(lpPict->xExt >= 0);
  504.     lpPict->yExt = m_rectBounds.top - m_rectBounds.bottom;  // HIMETRIC height
  505.     if (lpPict->yExt < 0)
  506.     {
  507.         TRACE0("Warning: HIMETRIC bounding rectangle is negative\n");
  508.         lpPict->yExt = -lpPict->yExt;   // backward compatibility fix
  509.     }
  510.  
  511. #ifdef _DEBUG
  512.     if (lpPict->xExt == 0 || lpPict->yExt == 0)
  513.     {
  514.         // usually the m_rectBounds rectangle is set to something interesting
  515.         TRACE0("Warning: COleServerItem has no bounding rectangle\n"
  516.                 "   - will not work with some client apps like MS Write\n");
  517.     }
  518. #endif
  519.     ::GlobalUnlock(hPict);
  520.     return hPict;
  521. }
  522.  
  523.  
  524. OLESTATUS COleServerItem::OnGetData(OLECLIPFORMAT nFormat, LPHANDLE lphReturn)
  525. {
  526.     ASSERT_VALID(this);
  527.  
  528.     HGLOBAL hData = NULL;    // default to not supported
  529.         // global for all the types supported
  530.         // HBITMAP for CF_BITMAP
  531.  
  532.     TRY
  533.     {
  534.         if (nFormat == afxData.cfNative)
  535.         {
  536.             hData = GetNativeData();
  537.         }
  538.         else if (nFormat == CF_METAFILEPICT)
  539.         {
  540.             hData = GetMetafileData();
  541.         }
  542.         else if (nFormat == CF_TEXT) 
  543.         {
  544.             CString strText;
  545.             if (OnGetTextData(strText))
  546.             {
  547.                 // allocate a global block for the string
  548.                 hData = ::GlobalAlloc(GMEM_DDESHARE, strText.GetLength() + 1);
  549.                 if (hData == NULL)
  550.                     AfxThrowMemoryException();
  551.  
  552.                 LPSTR  lpszText = (LPSTR)::GlobalLock(hData);
  553.                 ASSERT(lpszText != NULL);
  554.                 lstrcpy(lpszText, strText);
  555.                 ::GlobalUnlock(hData);
  556.             }
  557.         }
  558.         else
  559.         {
  560.             OLE_TRACE1("Warning: OLE get data, unknown format %d\n", nFormat);
  561.         }
  562.     }
  563.     CATCH(COleException, e)
  564.     {
  565.         return e->m_status;
  566.     }
  567.     AND_CATCH_ALL(e)
  568.     {
  569.         // other exceptions
  570.         return OLE_ERROR_MEMORY;
  571.     }
  572.     END_CATCH_ALL
  573.  
  574.     if (hData == NULL)
  575.         return OLE_ERROR_FORMAT;        // not supported
  576.  
  577.     // return the data
  578.     *lphReturn = (HANDLE)hData;
  579.     return OLE_OK;
  580. }
  581.  
  582.  
  583. OLESTATUS COleServerItem::OnSetData(OLECLIPFORMAT nFormat, HANDLE hData)
  584. {
  585.     ASSERT_VALID(this);
  586.  
  587.     if (nFormat != afxData.cfNative)
  588.     {
  589.         return OLE_ERROR_SETDATA_FORMAT;
  590.             // we don't understand the format
  591.             //  the OLE server DLL will free the data for us
  592.     }
  593.  
  594.     // set native data via serialization for embedded item
  595.     CSharedFile memFile;
  596.     memFile.SetHandle((HGLOBAL)hData);
  597.         // destroying the CSharedFile will call GlobalFree for the shared memory
  598.  
  599.     TRY
  600.     {
  601.         CArchive    setArchive(&memFile, CArchive::load);
  602.         Serialize(setArchive);        // load me
  603.     }
  604.     CATCH_ALL(e)
  605.     {
  606.         memFile.Close();
  607.         return OLE_ERROR_GENERIC;
  608.     }
  609.     END_CATCH_ALL
  610.  
  611.     return OLE_OK;
  612. }
  613.  
  614. /////////////////////////////////////////////////////////////////////////////
  615. // Helpers for clipboard
  616.  
  617.  
  618. BOOL COleServerItem::CopyToClipboard(BOOL bIncludeNative, BOOL bIncludeLink)
  619. {
  620.     ASSERT_VALID(this);
  621.  
  622.     HWND hWndDesktop = AfxGetApp()->m_pMainWnd->GetSafeHwnd();
  623.     ASSERT(hWndDesktop != NULL);        // must have a window for the owner
  624.  
  625.     if (!::OpenClipboard(hWndDesktop))
  626.     {
  627.         OLE_TRACE0("OpenClipboard failed in COleServerItem::CopyToClipboard\n");
  628.         return FALSE;
  629.     }
  630.  
  631.     ::EmptyClipboard();
  632.  
  633.     BOOL bOK = TRUE;
  634.     // copy all the formats supported
  635.     OLECLIPFORMAT cf = 0;
  636.     while ((cf = OnEnumFormats(cf)) != 0)
  637.     {
  638.         if (cf == afxData.cfNative && !bIncludeNative)
  639.             continue;       // skip native
  640.  
  641.         if (cf == afxData.cfObjectLink || cf == afxData.cfOwnerLink)
  642.             continue;       // link and owner link done separately
  643.  
  644.         HANDLE hData = NULL;
  645.         if (OnGetData(cf, &hData) != OLE_OK ||
  646.             hData == NULL ||
  647.             !::SetClipboardData(cf, hData))
  648.         {
  649.             TRACE1("Failed to copy clipboard format 0x%04X\n", cf);
  650.             bOK = FALSE;
  651.         }
  652.     }
  653.  
  654.     COleServerDoc* pDoc = GetDocument();
  655.     if (pDoc->m_pServer != NULL)
  656.     {
  657.         // attached to an OLE Server - try owner link and object link
  658.         // set clipboard data for owner link (don't go through OnGetData)
  659.         HGLOBAL hLinkData;
  660.         if ((hLinkData = GetLinkFormatData(FALSE)) == NULL ||
  661.             !::SetClipboardData(afxData.cfOwnerLink, hLinkData))
  662.         {
  663.             TRACE0("Failed to copy owner link\n");
  664.             if (hLinkData != NULL)
  665.                 ::GlobalFree(hLinkData);
  666.             bOK = FALSE;
  667.         }
  668.  
  669.         // same as above but optional for object link [for linked data]
  670.         if (bIncludeLink && pDoc->IsOpenServerDoc() &&
  671.              (hLinkData = GetLinkFormatData(TRUE)) != NULL)
  672.         {
  673.             // try to set the ObjectLink data
  674.             if (!::SetClipboardData(afxData.cfObjectLink, hLinkData))
  675.             {
  676.                 TRACE0("Failed to copy object link\n");
  677.                 if (hLinkData != NULL)
  678.                     ::GlobalFree(hLinkData);
  679.                 bOK = FALSE;
  680.             }
  681.         }
  682.     }
  683.     else
  684.     {
  685.         TRACE0("OLE Document not attached to server - can't copy OLE data\n");
  686.         bOK = FALSE;
  687.     }
  688.  
  689.     ::CloseClipboard();
  690.     return bOK;
  691. }
  692.  
  693. extern const CString NEAR afxEmptyString;   
  694.  
  695. // Actually allocates the data
  696. HGLOBAL COleServerItem::GetLinkFormatData(BOOL bObjectLink)
  697. {
  698.     ASSERT_VALID(this);
  699.  
  700.     // calculate length needed for class\0doc\0item\0\0.
  701.     COleServerDoc* pDoc = GetDocument();
  702.     ASSERT_VALID(pDoc);
  703.     COleServer* pServer = pDoc->m_pServer;
  704.     ASSERT_VALID(pServer);
  705.  
  706.     const CString& strServer = pServer->GetServerName();
  707.     const CString& strDoc = pDoc->GetPathName();
  708.     if (bObjectLink && strDoc.IsEmpty())
  709.         return NULL;    // can't link without a document
  710.  
  711.     // item name is exported only if we have a document name
  712.     const CString& strItem = strDoc.IsEmpty() ? afxEmptyString : GetItemName();
  713.     int nLen = strServer.GetLength() + strDoc.GetLength() + 
  714.                 strItem.GetLength() + 4;
  715.  
  716.     HGLOBAL hData = GlobalAlloc(GMEM_DDESHARE | GHND, nLen);
  717.     if (hData == NULL)
  718.         return NULL;
  719.     LPSTR lpData = (LPSTR)::GlobalLock(hData);
  720.     lstrcpy(lpData, strServer);
  721.     lpData += strServer.GetLength() + 1;
  722.     lstrcpy(lpData, strDoc);
  723.     lpData += strDoc.GetLength() + 1;
  724.     lstrcpy(lpData, strItem);
  725.     lpData += strItem.GetLength() + 1;
  726.     *lpData++ = '\0';
  727.     ::GlobalUnlock(hData);
  728.  
  729.     return hData;
  730. }
  731.  
  732. /////////////////////////////////////////////////////////////////////////////
  733. /////////////////////////////////////////////////////////////////////////////
  734. // COleServerDoc
  735.  
  736. // convert far LPOLESERVERDOC to ambient model COleServerDoc
  737. inline COleServerDoc* PASCAL COleServerDoc::FromLp(LPOLESERVERDOC lpServerDoc)
  738. {
  739.     COleServerDoc* pDoc = (COleServerDoc*)
  740.         ((BYTE*)_AfxGetPtrFromFarPtr(lpServerDoc) - sizeof(COleDocument));
  741.     ASSERT(lpServerDoc == &pDoc->m_oleServerDoc);
  742.     return pDoc;
  743. }
  744.  
  745. // friend class to get access to COleServerDoc protected implementations
  746. struct _afxOleSvrDocImpl
  747. {
  748.     static OLESTATUS OLEEXPORT Save(LPOLESERVERDOC lpServerDoc);
  749.     static OLESTATUS OLEEXPORT Close(LPOLESERVERDOC lpServerDoc);
  750.     static OLESTATUS OLEEXPORT SetHostNames(LPOLESERVERDOC lpServerDoc,
  751.         OLE_LPCSTR lpszClient, OLE_LPCSTR lpszDoc);
  752.     static OLESTATUS OLEEXPORT SetDocDimensions(LPOLESERVERDOC lpServerDoc,
  753.         OLE_CONST RECT FAR* lpRect);
  754.     static OLESTATUS OLEEXPORT Release(LPOLESERVERDOC lpServerDoc);
  755.     static OLESTATUS OLEEXPORT SetColorScheme(LPOLESERVERDOC lpServerDoc,
  756.         OLE_CONST LOGPALETTE FAR* lpLogPalette);
  757.     static OLESTATUS OLEEXPORT Execute(LPOLESERVERDOC lpServerDoc,
  758.         HGLOBAL hCommands);
  759.     static OLESTATUS OLEEXPORT GetObject(LPOLESERVERDOC lpServerDoc,
  760.         OLE_LPCSTR lpszItemName, LPOLEOBJECT FAR* lplpObject,
  761.         LPOLECLIENT lpClient);
  762. };
  763.  
  764. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::Save(LPOLESERVERDOC lpServerDoc)
  765. {
  766.     LOCK_PUMP lock;
  767.     OLE_TRACE0("COleServerDoc::OnSave()\n");
  768.     return COleServerDoc::FromLp(lpServerDoc)->OnSave();
  769. }
  770.  
  771. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::Close(LPOLESERVERDOC lpServerDoc)
  772. {
  773.     LOCK_PUMP lock;
  774.     OLE_TRACE0("COleServerDoc::OnClose()\n");
  775.     return COleServerDoc::FromLp(lpServerDoc)->OnClose();
  776. }
  777.  
  778. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::SetHostNames(LPOLESERVERDOC lpServerDoc,
  779.     OLE_LPCSTR lpszClient, OLE_LPCSTR lpszDoc)
  780. {
  781.     LOCK_PUMP lock;
  782.     OLE_TRACE0("COleServerDoc::OnSetHostNames()\n");
  783.     OLESTATUS status = COleServerDoc::FromLp(lpServerDoc)->OnSetHostNames(
  784.         lpszClient, lpszDoc);
  785.     return status;
  786. }
  787.  
  788. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::SetDocDimensions(
  789.     LPOLESERVERDOC lpServerDoc, OLE_CONST RECT FAR* lpRect)
  790. {
  791.     LOCK_PUMP lock;
  792.     OLE_TRACE0("COleServerDoc::OnSetDocDimensions()\n");
  793.     return COleServerDoc::FromLp(lpServerDoc)->OnSetDocDimensions(lpRect);
  794. }
  795.  
  796. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::Release(LPOLESERVERDOC lpServerDoc)
  797. {
  798.     LOCK_PUMP lock;
  799.     OLE_TRACE0("COleServerDoc::OnRelease()\n");
  800.     return COleServerDoc::FromLp(lpServerDoc)->OnRelease();
  801. }
  802.  
  803. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::SetColorScheme(
  804.     LPOLESERVERDOC lpServerDoc, OLE_CONST LOGPALETTE FAR* lpLogPalette)
  805. {
  806.     LOCK_PUMP lock;
  807.     OLE_TRACE0("COleServerDoc::OnSetColorScheme()\n");
  808.     OLESTATUS status = COleServerDoc::FromLp(lpServerDoc)->OnSetColorScheme(
  809.         lpLogPalette);
  810.     return status;
  811. }
  812.  
  813. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::Execute(LPOLESERVERDOC lpServerDoc, HGLOBAL hCommands)
  814. {
  815.     LOCK_PUMP lock;
  816.     OLE_TRACE0("COleServerDoc::OnExecute()\n");
  817.     LPVOID  lpCommands = ::GlobalLock(hCommands);
  818.     ASSERT(lpCommands != NULL);
  819.     OLESTATUS status;
  820.     status = COleServerDoc::FromLp(lpServerDoc)->OnExecute(lpCommands);
  821.     ::GlobalUnlock(hCommands);
  822.     return status;
  823. }
  824.  
  825. OLESTATUS OLEEXPORT _afxOleSvrDocImpl::GetObject(LPOLESERVERDOC lpServerDoc,
  826.     OLE_LPCSTR lpszItemName, LPOLEOBJECT FAR* lplpObject, LPOLECLIENT lpClient)
  827. {
  828.     COleServerDoc* pDoc = COleServerDoc::FromLp(lpServerDoc);
  829.     COleServerItem* pItem;
  830.     LOCK_PUMP lock;
  831.  
  832.     TRY
  833.     {
  834.         if (lpszItemName == NULL || *lpszItemName == '\0')
  835.         {
  836.             OLE_TRACE0("calling COleServerDoc::OnGetEmbeddedItem\n");
  837.             pItem = pDoc->OnGetEmbeddedItem();
  838.         }
  839.         else
  840.         {
  841.             OLE_TRACE1("calling COleServerDoc::OnGetLinkedItem(%Fs)\n", lpszItemName);
  842.             pItem = pDoc->OnGetLinkedItem(lpszItemName);
  843.         }
  844.     }
  845.     CATCH_ALL(e)
  846.     {
  847.         return COleException::Process(e);
  848.     }
  849.     END_CATCH_ALL
  850.  
  851.     if (pItem == NULL)
  852.         return OLE_ERROR_GENERIC;
  853.  
  854.     ASSERT(pDoc->IsOpenServerDoc());    // must be open
  855.     ASSERT(pItem->m_pDocument == pDoc); // must be contained
  856.     ASSERT(pItem->m_lpClient == NULL); // must be unconnected !
  857.     pItem->m_lpClient = lpClient;
  858.     *lplpObject = &pItem->m_oleObject;
  859.     return OLE_OK;
  860. }
  861.  
  862. static struct _OLESERVERDOCVTBL OLEVTBLMODEL serverDocVtbl =
  863. {
  864.     _afxOleSvrDocImpl::Save,
  865.     _afxOleSvrDocImpl::Close,
  866.     _afxOleSvrDocImpl::SetHostNames,
  867.     _afxOleSvrDocImpl::SetDocDimensions,
  868.     _afxOleSvrDocImpl::GetObject,
  869.     _afxOleSvrDocImpl::Release,
  870.     _afxOleSvrDocImpl::SetColorScheme,
  871.     _afxOleSvrDocImpl::Execute,
  872. };
  873.  
  874. /////////////////////////////////////////////////////////////////////////////
  875. // COleServerDoc construction and other operations
  876.  
  877. COleServerDoc::COleServerDoc()
  878. {
  879.     m_oleServerDoc.lpvtbl = &serverDocVtbl;
  880.     m_pServer = NULL;
  881.     m_lhServerDoc = NULL;
  882.     m_bWaiting = FALSE;
  883. }
  884.  
  885. IMPLEMENT_DYNAMIC(COleServerDoc, COleDocument)
  886.  
  887. BEGIN_MESSAGE_MAP(COleServerDoc, COleDocument)
  888.     //{{AFX_MSG_MAP(COleServerDoc)
  889.     ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSaveMenu)
  890.     ON_COMMAND(ID_FILE_SAVE, OnFileSaveOrUpdate)
  891.     ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveMenu)
  892.     ON_COMMAND(ID_FILE_SAVE_AS, OnFileSaveAs)
  893.     //}}AFX_MSG_MAP
  894. END_MESSAGE_MAP()
  895.  
  896. COleServerDoc::~COleServerDoc()
  897. {
  898.     if (IsOpenServerDoc())
  899.         Revoke();       // wait for revoke to finish
  900. }
  901.  
  902. void COleServerDoc::CheckAsync(OLESTATUS status)
  903.     // throw exception if not ok to continue
  904. {
  905.     ASSERT(!m_bWaiting);
  906.     ASSERT_VALID(this);
  907.  
  908.     if (status == OLE_WAIT_FOR_RELEASE)
  909.     {
  910.         m_bWaiting = TRUE;
  911.         while (m_bWaiting)
  912.         {
  913.             OLE_TRACE0("OLE Server Doc waiting for release\n");
  914.             AfxGetApp()->PumpMessage();
  915.         }
  916.         m_bWaiting = FALSE;
  917.  
  918.         return;     // assume it worked
  919.     }
  920.  
  921.     if (status == OLE_OK || status >= OLE_WARN_DELETE_DATA)
  922.     {
  923.         // ok, or just a warning
  924.         return;
  925.     }
  926.  
  927.     // otherwise this error wasn't expected, so throw an exception
  928.     OLE_TRACE1("Warning: COleServerDoc operation failed %d, throwing exception\n", status);
  929.     AfxThrowOleException(status);
  930. }
  931.  
  932. OLESTATUS COleServerDoc::BeginRevoke()
  933.     // do not wait for async completion
  934. {
  935.     ASSERT_VALID(this);
  936.     ASSERT(IsOpenServerDoc());
  937.  
  938.     LHCLIENTDOC lh = m_lhServerDoc;
  939.     ASSERT(lh != NULL);
  940.     m_lhServerDoc = NULL;
  941.     if (m_pServer != NULL)
  942.         m_pServer->RemoveDocument(this);
  943.     OLESTATUS status = ::OleRevokeServerDoc(lh);
  944.     ASSERT(status == OLE_OK || status == OLE_WAIT_FOR_RELEASE);
  945.     // revoke will not be finished until OnRelease called
  946.     return status;
  947. }
  948.  
  949. void COleServerDoc::Revoke()
  950.     // wait for async completion
  951. {
  952.     ASSERT_VALID(this);
  953.     if (IsOpenServerDoc())
  954.         CheckAsync(BeginRevoke());
  955. }
  956.  
  957. /////////////////////////////////////////////////////////////////////////////
  958. // Interesting operations
  959.  
  960. BOOL COleServerDoc::RegisterServerDoc(COleServer* pServer, LPCSTR lpszDoc)
  961. {
  962.     ASSERT_VALID(this);
  963.     ASSERT(pServer != NULL);
  964.     ASSERT(pServer->IsOpen());
  965.     ASSERT(lpszDoc != NULL);
  966.     ASSERT(m_pServer == NULL || m_pServer == pServer);
  967.  
  968.     if (m_lhServerDoc != NULL)
  969.         return TRUE; // already registered - return OK if same server
  970.  
  971.     LHSERVERDOC lhDoc;
  972.     if (::OleRegisterServerDoc(pServer->m_lhServer, lpszDoc,
  973.         &m_oleServerDoc, &lhDoc) != OLE_OK)
  974.     {
  975.         return FALSE;
  976.     }
  977.  
  978.     pServer->AddDocument(this, lhDoc);
  979.     ASSERT(m_lhServerDoc == lhDoc); // make sure it connected it
  980.     return TRUE;
  981. }
  982.  
  983. void COleServerDoc::NotifyRename(LPCSTR lpszNewName)
  984. {
  985.     ASSERT_VALID(this);
  986.     ASSERT(IsOpenServerDoc());
  987.     ASSERT(lpszNewName != NULL);
  988.  
  989.     CheckAsync(::OleRenameServerDoc(m_lhServerDoc, lpszNewName));
  990. }
  991.  
  992. void COleServerDoc::NotifyRevert()
  993. {
  994.     ASSERT_VALID(this);
  995.     ASSERT(IsOpenServerDoc());
  996.  
  997.     CheckAsync(::OleRevertServerDoc(m_lhServerDoc));
  998. }
  999.  
  1000. void COleServerDoc::NotifySaved()
  1001. {
  1002.     ASSERT_VALID(this);
  1003.     ASSERT(IsOpenServerDoc());
  1004.  
  1005.     CheckAsync(::OleSavedServerDoc(m_lhServerDoc));
  1006. }
  1007.  
  1008. void COleServerDoc::NotifyAllClients(OLE_NOTIFICATION wNotify)
  1009. {
  1010.     ASSERT_VALID(this);
  1011.  
  1012.     POSITION pos = GetStartPosition();
  1013.     while (pos)
  1014.     {
  1015.         COleServerItem* pItem = (COleServerItem*)GetNextItem(pos);
  1016.         if (pItem->IsKindOf(RUNTIME_CLASS(COleServerItem)) &&
  1017.            pItem->IsConnected())
  1018.         {
  1019.             pItem->NotifyClient(wNotify);
  1020.         }
  1021.     }
  1022. }
  1023.  
  1024. /////////////////////////////////////////////////////////////////////////////
  1025. // COleServerDoc standard implementation of overridables
  1026.  
  1027. OLESTATUS COleServerDoc::OnRelease()
  1028. {
  1029.     OLE_TRACE0("COleServerDoc::OnRelease\n");
  1030.     m_bWaiting = FALSE;
  1031.     ASSERT_VALID(this); // valid once we leave the waiting mode
  1032.  
  1033.     // close connection to OLE server doc
  1034.     m_lhServerDoc = NULL;
  1035.     return OLE_OK;
  1036. }
  1037.  
  1038.  
  1039. OLESTATUS COleServerDoc::OnSave()
  1040. {
  1041.     ASSERT_VALID(this);
  1042.     // OnSave is not used in OLE V1.
  1043.     return OLE_OK;
  1044. }
  1045.  
  1046.  
  1047. OLESTATUS COleServerDoc::OnClose()
  1048. {
  1049.     ASSERT_VALID(this);
  1050.     ASSERT(IsOpenServerDoc());
  1051.  
  1052.     // can't close the document right now - post a close command
  1053.     POSITION pos = GetFirstViewPosition();
  1054.     while (pos)
  1055.     {
  1056.         CView* pView = GetNextView(pos);
  1057.         ASSERT_VALID(pView);
  1058.         CFrameWnd* pFrame = pView->GetParentFrame();
  1059.         if (pFrame != NULL)
  1060.         {
  1061.             SetModifiedFlag(FALSE);     // make clean for closing
  1062.             pFrame->PostMessage(WM_COMMAND, ID_FILE_CLOSE);
  1063.             return OLE_OK;
  1064.         }
  1065.     }
  1066.     // otherwise frame-less document - just start the revoking process
  1067.     BeginRevoke();
  1068.     return OLE_OK;
  1069. }
  1070.  
  1071.  
  1072. OLESTATUS COleServerDoc::OnExecute(LPVOID /*lpCommands*/) // DDE commands
  1073. {
  1074.     ASSERT_VALID(this);
  1075.  
  1076.     return OLE_ERROR_COMMAND;   // default to not supported
  1077. }
  1078.  
  1079.  
  1080. OLESTATUS COleServerDoc::OnSetDocDimensions(LPCRECT /*lpRect*/)
  1081. {
  1082.     ASSERT_VALID(this);
  1083.  
  1084.     return OLE_OK;      // default to ignore it
  1085. }
  1086.  
  1087.  
  1088. // Overridables you do not have to override
  1089. OLESTATUS
  1090. COleServerDoc::OnSetHostNames(LPCSTR /*lpszHost*/, LPCSTR /*lpszHostObj*/)
  1091. {
  1092.     ASSERT_VALID(this);
  1093.  
  1094.     return OLE_OK;
  1095. }
  1096.  
  1097.  
  1098. OLESTATUS COleServerDoc::OnSetColorScheme(const LOGPALETTE FAR*)
  1099. {
  1100.     ASSERT_VALID(this);
  1101.  
  1102.     return OLE_OK;
  1103. }
  1104.  
  1105. COleServerItem* COleServerDoc::OnGetLinkedItem(LPCSTR lpszItemName)
  1106. {
  1107.     ASSERT_VALID(this);
  1108.     ASSERT(lpszItemName != NULL);
  1109.  
  1110.     // default implementation walks list of server items looking for
  1111.     //  a case sensitive match
  1112.  
  1113.     POSITION pos = GetStartPosition();
  1114.     while (pos)
  1115.     {
  1116.         COleServerItem* pItem = (COleServerItem*)GetNextItem(pos);
  1117.         if (pItem->IsKindOf(RUNTIME_CLASS(COleServerItem)) &&
  1118.             lstrcmp(pItem->GetItemName(), lpszItemName) == 0)
  1119.         {
  1120.             // found exact match
  1121.             return pItem;
  1122.         }
  1123.     }
  1124.     OLE_TRACE1("Warning: default COleServerDoc::OnGetLinkedItem implementation "
  1125.             "failed to find item '%Fs'\n", lpszItemName);
  1126.     return NULL;        // not found (no link found)
  1127. }
  1128.  
  1129. /////////////////////////////////////////////////////////////////////////////
  1130. // COleServerDoc - document processing
  1131.  
  1132. BOOL COleServerDoc::OnNewDocument()
  1133. {
  1134.     ASSERT_VALID(this);
  1135.  
  1136.     if (!COleDocument::OnNewDocument())
  1137.         return FALSE;
  1138.  
  1139.     Revoke();       // get rid of old doc if needed
  1140.     RegisterIfServerAttached(NULL);
  1141.     return TRUE;
  1142. }
  1143.  
  1144. BOOL COleServerDoc::OnOpenDocument(const char* pszPathName)
  1145. {
  1146.     ASSERT_VALID(this);
  1147.  
  1148.     if (!COleDocument::OnOpenDocument(pszPathName))
  1149.         return FALSE;
  1150.  
  1151.     Revoke();       // get rid of old doc if needed
  1152.     RegisterIfServerAttached(pszPathName);
  1153.     return TRUE;
  1154. }
  1155.  
  1156. // register with OLE server if attached to our doc template
  1157. void COleServerDoc::RegisterIfServerAttached(const char* pszPathName)
  1158. {
  1159.     ASSERT_VALID(this);
  1160.     ASSERT(!IsOpenServerDoc());
  1161.  
  1162.     CDocTemplate* pTemplate = GetDocTemplate();
  1163.     ASSERT_VALID(pTemplate);
  1164.     COleServer* pServer = (COleServer*)pTemplate->m_pAttachedServer;
  1165.     if (pServer != NULL && pServer->IsKindOf(RUNTIME_CLASS(COleServer)))
  1166.     {
  1167.         // register with OLE Server
  1168.         if (pszPathName == NULL)
  1169.         {
  1170.             // no name, just attach to server, but not register yet
  1171.             pServer->AddDocument(this, NULL);
  1172.         }
  1173.         else if (!RegisterServerDoc(pServer, pszPathName))
  1174.         {
  1175.             // not fatal
  1176.             AfxMessageBox(AFX_IDP_FAILED_TO_NOTIFY);
  1177.             ASSERT(!IsOpenServerDoc());
  1178.         }
  1179.         else
  1180.         {
  1181.             ASSERT(IsOpenServerDoc());
  1182.         }
  1183.     }
  1184. }
  1185.  
  1186. BOOL COleServerDoc::OnSaveDocument(const char* pszPathName)
  1187. {
  1188.     ASSERT_VALID(this);
  1189.  
  1190.     if (!COleDocument::OnSaveDocument(pszPathName))
  1191.         return FALSE;
  1192.  
  1193.     if (IsOpenServerDoc())
  1194.     {
  1195.         if (GetPathName().IsEmpty())
  1196.         {
  1197.             // nothing to do for embedded case
  1198.             OLE_TRACE0("OnSaveDocument succeeded for SaveCopyAs\n");
  1199.         }
  1200.         else if (GetPathName() == pszPathName)
  1201.         {
  1202.             // saved to same file
  1203.             NotifySaved();
  1204.         }
  1205.         else
  1206.         {
  1207.             // saved to a different file
  1208.             NotifyRename(GetPathName());
  1209.         }
  1210.     }
  1211.     else
  1212.     {
  1213.         // now we have a path name - register it
  1214.         RegisterIfServerAttached(pszPathName);
  1215.     }
  1216.  
  1217.     return TRUE;
  1218. }
  1219.  
  1220.  
  1221. void COleServerDoc::OnCloseDocument()
  1222. {
  1223.     ASSERT_VALID(this);
  1224.  
  1225.     DeleteContents();       // clean up contents before revoke
  1226.     if (IsOpenServerDoc())
  1227.     {
  1228.         // do notifications and closing
  1229.         if (IsModified())
  1230.         {
  1231.             NotifyRevert();
  1232.             SetModifiedFlag(FALSE);     // clear dirty
  1233.         }
  1234.         else
  1235.         {
  1236.             NotifyClosed();
  1237.         }
  1238.         Revoke();       // wait for revoke to finish
  1239.         ASSERT(!IsOpenServerDoc());
  1240.     }
  1241.     ASSERT_VALID(this); // must still exist
  1242.     COleDocument::OnCloseDocument();    // may delete the document object
  1243. }
  1244.  
  1245. /////////////////////////////////////////////////////////////////////////////
  1246. // COleServerDoc UI
  1247.  
  1248. // if OLE Server document is open, and there is no path name set,
  1249. //   then you are editing an embedded object, in which case
  1250. //   ID_FILE_SAVE changes from "Save" to "Update".  really
  1251. //   "Save Copy As..."
  1252. // if OLE Server document is open, and there is a path name set,
  1253. //   then you are editing an data file document, which may contain
  1254. //   linked objects.  ID_FILE_SAVE is a normal file save, followed
  1255. //   by an update notification to all clients.
  1256. // if the OLE server document is not open, and there is no path name set,
  1257. //   then this case turns into ID_FILE_SAVE_AS.
  1258. // if the OLE server document is not open, and there is a path name set,
  1259. //   then this is a normal file save.
  1260.  
  1261. void COleServerDoc::OnUpdateFileSaveMenu(CCmdUI* pCmdUI)
  1262. {
  1263.     ASSERT_VALID(this);
  1264.     ASSERT(pCmdUI->m_nID == ID_FILE_SAVE || pCmdUI->m_nID == ID_FILE_SAVE_AS);
  1265.  
  1266.     UINT nIDS = (pCmdUI->m_nID == ID_FILE_SAVE) ? 
  1267.             AFX_IDS_SAVE_MENU : AFX_IDS_SAVE_AS_MENU;
  1268.             // IDS strings for non-embedded case
  1269.  
  1270.     if (IsOpenServerDoc() && GetPathName().IsEmpty())
  1271.     {
  1272.         ASSERT(AFX_IDS_UPDATE_MENU == AFX_IDS_SAVE_MENU + 1);
  1273.         ASSERT(AFX_IDS_SAVE_COPY_AS_MENU == AFX_IDS_SAVE_AS_MENU + 1);
  1274.         nIDS++;     // embedded case
  1275.     }
  1276.  
  1277.     CString str;
  1278.     if (!str.LoadString(nIDS))
  1279.     {
  1280.         TRACE0("Warning: failed to load string for OLE Save/Update menu\n");
  1281.         return;
  1282.     }
  1283.     // set to correct string
  1284.     pCmdUI->SetText(str);
  1285. }
  1286.  
  1287. void COleServerDoc::OnFileSaveOrUpdate()
  1288. {
  1289.     ASSERT_VALID(this);
  1290.  
  1291.     if (IsOpenServerDoc() && GetPathName().IsEmpty())
  1292.     {
  1293.         // embedded case
  1294.         OnUpdateDocument();     // update
  1295.         return;
  1296.     }
  1297.  
  1298.     // do normal save to file, OnSaveDocument will update as needed
  1299.     COleDocument::OnFileSave(); // normal file save
  1300. }
  1301.  
  1302. BOOL COleServerDoc::SaveModified()
  1303. {
  1304.     ASSERT_VALID(this);
  1305.  
  1306.     if (!IsOpenServerDoc() || !GetPathName().IsEmpty())
  1307.         return COleDocument::SaveModified();
  1308.  
  1309.     if (!IsModified())
  1310.         return TRUE;        // ok to continue
  1311.  
  1312.     CString prompt;
  1313.     AfxFormatString1(prompt, AFX_IDP_ASK_TO_UPDATE, m_strTitle);
  1314.     switch (AfxMessageBox(prompt, MB_YESNOCANCEL, AFX_IDP_ASK_TO_UPDATE))
  1315.     {
  1316.     case IDCANCEL:
  1317.         return FALSE;       // don't continue
  1318.  
  1319.     case IDYES:
  1320.         if (!OnUpdateDocument())
  1321.         {
  1322.             TRACE0("Warning: OnUpdateDocument failed to update\n");
  1323.             // keep going, close will flush it
  1324.         }
  1325.         break;
  1326.     }
  1327.     return TRUE;    // keep going
  1328. }
  1329.  
  1330. BOOL COleServerDoc::OnUpdateDocument()
  1331. {
  1332.     ASSERT_VALID(this);
  1333.     ASSERT(IsOpenServerDoc());
  1334.  
  1335.     BOOL bOK = TRUE;
  1336.     // save a server document -> update
  1337.     TRY
  1338.     {
  1339.         NotifySaved();
  1340.         SetModifiedFlag(FALSE);     // back to unmodified
  1341.     }
  1342.     CATCH_ALL(e)
  1343.     {
  1344.         AfxMessageBox(AFX_IDP_FAILED_TO_UPDATE);
  1345.         bOK = FALSE;
  1346.     }
  1347.     END_CATCH_ALL
  1348.     return bOK;
  1349. }
  1350.  
  1351. void COleServerDoc::OnFileSaveAs()
  1352. {
  1353.     ASSERT_VALID(this);
  1354.  
  1355.     if (IsOpenServerDoc() && GetPathName().IsEmpty())
  1356.     {
  1357.         // embedded case
  1358.         if (!DoSave(NULL, FALSE))
  1359.             TRACE0("Warning: File save-copy-as failed\n");
  1360.     }
  1361.     else
  1362.     {
  1363.         // normal case
  1364.         COleDocument::OnFileSaveAs();
  1365.     }
  1366. }
  1367.  
  1368. /////////////////////////////////////////////////////////////////////////////
  1369. /////////////////////////////////////////////////////////////////////////////
  1370. // COleServer
  1371.  
  1372. // convert far LPOLESERVER to ambient model COleServer
  1373. inline COleServer* PASCAL COleServer::FromLp(LPOLESERVER lpServer)
  1374. {
  1375.     COleServer* pOleServer = (COleServer*)
  1376.         ((BYTE*)_AfxGetPtrFromFarPtr(lpServer) - sizeof(CObject));
  1377.     ASSERT(lpServer == &pOleServer->m_oleServer);
  1378.     return pOleServer;
  1379. }
  1380.  
  1381. // friend class to get access to COleServer protected implementations
  1382. struct _afxSvrImpl
  1383. {
  1384.     static OLESTATUS OLEEXPORT Exit(LPOLESERVER lpServer);
  1385.     static OLESTATUS OLEEXPORT Release(LPOLESERVER lpServer);
  1386.     static OLESTATUS OLEEXPORT Execute(LPOLESERVER lpServer,
  1387.         HGLOBAL hCommands);
  1388.     static OLESTATUS OLEEXPORT Open(LPOLESERVER lpServer,
  1389.         LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszDoc,
  1390.         LPOLESERVERDOC FAR* lplpServerDoc);
  1391.     static OLESTATUS OLEEXPORT Create(LPOLESERVER lpServer,
  1392.         LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszTypeName, OLE_LPCSTR lpszDoc,
  1393.         LPOLESERVERDOC FAR* lplpServerDoc);
  1394.     static OLESTATUS OLEEXPORT CreateFromTemplateFile(LPOLESERVER lpServer,
  1395.         LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszTypeName, OLE_LPCSTR lpszDoc,
  1396.         OLE_LPCSTR lpszTemplate, LPOLESERVERDOC FAR* lplpServerDoc);
  1397.     static OLESTATUS OLEEXPORT Edit(LPOLESERVER lpServer,
  1398.         LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszTypeName, OLE_LPCSTR lpszDoc,
  1399.         LPOLESERVERDOC FAR* lplpServerDoc);
  1400. };
  1401.  
  1402. OLESTATUS OLEEXPORT _afxSvrImpl:: Exit(LPOLESERVER lpServer)
  1403. {
  1404.     LOCK_PUMP lock;
  1405.     OLE_TRACE0("COleServer::OnExit()\n");
  1406.     return COleServer::FromLp(lpServer)->OnExit();
  1407. }
  1408.  
  1409. OLESTATUS OLEEXPORT _afxSvrImpl:: Release(LPOLESERVER lpServer)
  1410. {
  1411.     LOCK_PUMP lock;
  1412.     OLE_TRACE0("COleServer::OnRelease()\n");
  1413.     return COleServer::FromLp(lpServer)->OnRelease();
  1414. }
  1415.  
  1416. OLESTATUS OLEEXPORT _afxSvrImpl:: Execute(LPOLESERVER lpServer, HGLOBAL hCommands)
  1417. {
  1418.     LOCK_PUMP lock;
  1419.     OLE_TRACE0("COleServer::Execute()\n");
  1420.  
  1421.     LPVOID  lpCommands = ::GlobalLock(hCommands);
  1422.     ASSERT(lpCommands != NULL);
  1423.     OLESTATUS status;
  1424.     status = COleServer::FromLp(lpServer)->OnExecute(lpCommands);
  1425.     ::GlobalUnlock(hCommands);
  1426.     return status;
  1427. }
  1428.  
  1429. OLESTATUS OLEEXPORT _afxSvrImpl:: Open(LPOLESERVER lpServer, LHSERVERDOC lhServerDoc,
  1430.     OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR* lplpServerDoc)
  1431. {
  1432.     LOCK_PUMP lock;
  1433.     OLE_TRACE0("COleServer::OnOpenDoc()\n");
  1434.  
  1435.     COleServer* pServer = COleServer::FromLp(lpServer);
  1436.     COleServerDoc* pDoc;
  1437.  
  1438.     TRY
  1439.         pDoc = pServer->OnOpenDoc(lpszDoc);
  1440.     CATCH_ALL(e)
  1441.         return COleException::Process(e);
  1442.     END_CATCH_ALL
  1443.  
  1444.     if (pDoc == NULL)
  1445.         return OLE_ERROR_GENERIC;
  1446.     pServer->AddDocument(pDoc, lhServerDoc);
  1447.     *lplpServerDoc = &pDoc->m_oleServerDoc;
  1448.     return OLE_OK;
  1449. }
  1450.  
  1451. OLESTATUS OLEEXPORT _afxSvrImpl::Create(LPOLESERVER lpServer,
  1452.     LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszTypeName,
  1453.     OLE_LPCSTR lpszDoc,
  1454.     LPOLESERVERDOC FAR* lplpServerDoc)
  1455. {
  1456.     LOCK_PUMP lock;
  1457.     OLE_TRACE0("COleServer::OnCreateDoc()\n");
  1458.  
  1459.     COleServer* pServer = COleServer::FromLp(lpServer);
  1460.     COleServerDoc* pDoc;
  1461.  
  1462.     TRY
  1463.         pDoc = pServer->OnCreateDoc(lpszTypeName, lpszDoc);
  1464.     CATCH_ALL(e)
  1465.         return COleException::Process(e);
  1466.     END_CATCH_ALL
  1467.  
  1468.     if (pDoc == NULL)
  1469.         return OLE_ERROR_GENERIC;
  1470.  
  1471.     pServer->AddDocument(pDoc, lhServerDoc);
  1472.     *lplpServerDoc = &pDoc->m_oleServerDoc;
  1473.     return OLE_OK;
  1474. }
  1475.  
  1476. OLESTATUS OLEEXPORT _afxSvrImpl:: CreateFromTemplateFile(LPOLESERVER lpServer,
  1477.     LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszTypeName,
  1478.     OLE_LPCSTR lpszDoc, OLE_LPCSTR lpszTemplate,
  1479.     LPOLESERVERDOC FAR* lplpServerDoc)
  1480. {
  1481.     LOCK_PUMP lock;
  1482.     OLE_TRACE0("COleServer::OnCreateDocFromTemplateFile()\n");
  1483.  
  1484.     COleServer* pServer = COleServer::FromLp(lpServer);
  1485.     COleServerDoc* pDoc;
  1486.  
  1487.     TRY
  1488.         pDoc = pServer->OnCreateDocFromTemplateFile(lpszTypeName,
  1489.           lpszDoc, lpszTemplate);
  1490.     CATCH_ALL(e)
  1491.         return COleException::Process(e);
  1492.     END_CATCH_ALL
  1493.  
  1494.     if (pDoc == NULL)
  1495.         return OLE_ERROR_GENERIC;
  1496.     pServer->AddDocument(pDoc, lhServerDoc);
  1497.     *lplpServerDoc = &pDoc->m_oleServerDoc;
  1498.     return OLE_OK;
  1499. }
  1500.  
  1501. OLESTATUS OLEEXPORT _afxSvrImpl::Edit(LPOLESERVER lpServer,
  1502.     LHSERVERDOC lhServerDoc, OLE_LPCSTR lpszTypeName,
  1503.     OLE_LPCSTR lpszDoc, LPOLESERVERDOC FAR* lplpServerDoc)
  1504. {
  1505.     LOCK_PUMP lock;
  1506.     OLE_TRACE0("COleServer::OnEditDoc()\n");
  1507.  
  1508.     COleServer* pServer = COleServer::FromLp(lpServer);
  1509.     COleServerDoc* pDoc;
  1510.  
  1511.     TRY
  1512.         pDoc = pServer->OnEditDoc(lpszTypeName, lpszDoc);
  1513.     CATCH_ALL(e)
  1514.         return COleException::Process(e);
  1515.     END_CATCH_ALL
  1516.  
  1517.     if (pDoc == NULL)
  1518.         return OLE_ERROR_EDIT;
  1519.     pServer->AddDocument(pDoc, lhServerDoc);
  1520.     *lplpServerDoc = &pDoc->m_oleServerDoc;
  1521.     return OLE_OK;
  1522. }
  1523.  
  1524. static struct _OLESERVERVTBL OLEVTBLMODEL serverVtbl =
  1525. {
  1526.     _afxSvrImpl::Open,
  1527.     _afxSvrImpl::Create,
  1528.     _afxSvrImpl::CreateFromTemplateFile,
  1529.     _afxSvrImpl::Edit,
  1530.     _afxSvrImpl::Exit,
  1531.     _afxSvrImpl::Release,
  1532.     _afxSvrImpl::Execute,
  1533. };
  1534.  
  1535. //////////////////////////////////////////////////////////////////////////////
  1536. // COleServer construction etc
  1537.  
  1538. COleServer::COleServer(BOOL bLaunchEmbedded)
  1539. {
  1540.     m_oleServer.lpvtbl = &serverVtbl;
  1541.     m_lhServer = NULL;
  1542.  
  1543.     m_cOpenDocuments = 0;
  1544.     m_bLaunchEmbedded = bLaunchEmbedded;
  1545. }
  1546.  
  1547. IMPLEMENT_DYNAMIC(COleServer, CObject)
  1548.  
  1549. COleServer::~COleServer()
  1550. {
  1551.     if (IsOpen())
  1552.         BeginRevoke();          // server death
  1553. }
  1554.  
  1555. void COleServer::BeginRevoke()
  1556. {
  1557.     ASSERT_VALID(this);
  1558.     ASSERT(IsOpen());
  1559.  
  1560.     LHSERVER lhServer = m_lhServer;
  1561.  
  1562.     if (lhServer != NULL)
  1563.     {
  1564.         m_lhServer = NULL;      // closed for all intensive purposes
  1565.         OLESTATUS status = ::OleRevokeServer(lhServer);
  1566.         ASSERT(status == OLE_OK || status == OLE_WAIT_FOR_RELEASE);
  1567.     }
  1568.     // NOTE: will return before the Revoke is acknowledged
  1569. }
  1570.  
  1571. BOOL
  1572. COleServer::Register(LPCSTR lpszTypeName, BOOL bMultiInstance)
  1573. {
  1574.     ASSERT_VALID(this);
  1575.     ASSERT(m_lhServer == NULL);     // one time only
  1576.     ASSERT(lpszTypeName != NULL);
  1577.  
  1578.     OLE_SERVER_USE use = bMultiInstance ? OLE_SERVER_MULTI : OLE_SERVER_SINGLE;
  1579.     if (::OleRegisterServer(lpszTypeName, &m_oleServer, &m_lhServer,
  1580.         AfxGetInstanceHandle(), use) != OLE_OK)
  1581.     {
  1582.         // error during registration
  1583.         return FALSE;
  1584.     }
  1585.     m_strServerName = lpszTypeName;
  1586.     return TRUE;
  1587. }
  1588.  
  1589. //////////////////////////////////////////////////////////////////////////////
  1590. // COleServer manages COleServerDocs
  1591.  
  1592. void COleServer::AddDocument(COleServerDoc* pDoc, LHSERVERDOC lhServerDoc)
  1593. {
  1594. #ifdef _DEBUG
  1595.     // pre-condition checks
  1596.     ASSERT_VALID(this);
  1597.     ASSERT_VALID(pDoc);
  1598.  
  1599.     if (pDoc->m_pServer != NULL)
  1600.     {
  1601.         // document is already attached to a server
  1602.         ASSERT(pDoc->m_pServer == this);        // must be this server
  1603.         if (pDoc->m_lhServerDoc != NULL)
  1604.         {
  1605.             // document is already registered - must be same handle
  1606.             ASSERT(pDoc->m_lhServerDoc == lhServerDoc);
  1607.         }
  1608.     }
  1609.     else
  1610.     {
  1611.         // not attached to a server
  1612.         ASSERT(pDoc->m_lhServerDoc == NULL);    // must be unregistered !
  1613.     }
  1614. #endif
  1615.     if (pDoc->m_pServer == NULL)
  1616.     {
  1617.         // attach to server
  1618.         pDoc->m_pServer = this;
  1619.         m_cOpenDocuments++;
  1620.     }
  1621.     if (pDoc->m_lhServerDoc == NULL)
  1622.     {
  1623.         // set handle (once)
  1624.         pDoc->m_lhServerDoc = lhServerDoc;
  1625.     }
  1626. }
  1627.  
  1628. void COleServer::RemoveDocument(COleServerDoc* pDoc)
  1629. {
  1630.     ASSERT_VALID(this);
  1631.     ASSERT(pDoc != NULL);
  1632.     ASSERT(pDoc->m_pServer == this);
  1633.     ASSERT(pDoc->m_lhServerDoc == NULL);        // must be detached
  1634.     ASSERT(m_cOpenDocuments > 0);
  1635.  
  1636.     pDoc->m_pServer = NULL;
  1637.     m_cOpenDocuments--;
  1638. }
  1639.  
  1640. //////////////////////////////////////////////////////////////////////////////
  1641. // COleServer default implementation of overridables
  1642.  
  1643. COleServerDoc* COleServer::OnOpenDoc(LPCSTR /*lpszDoc*/)
  1644. {
  1645.     ASSERT_VALID(this);
  1646.     return NULL;
  1647. }
  1648.  
  1649. COleServerDoc* COleServer::OnCreateDocFromTemplateFile(LPCSTR /*lpszTypeName*/,
  1650.     LPCSTR /*lpszDoc*/, LPCSTR /*lpszTemplate*/)
  1651. {
  1652.     ASSERT_VALID(this);
  1653.  
  1654.     return NULL;
  1655. }
  1656.  
  1657. OLESTATUS COleServer::OnExecute(LPVOID /*lpCommands*/)  // DDE commands
  1658. {
  1659.     ASSERT_VALID(this);
  1660.  
  1661.     return OLE_ERROR_COMMAND;
  1662. }
  1663.  
  1664. OLESTATUS COleServer::OnExit()
  1665. {
  1666.     ASSERT_VALID(this);
  1667.  
  1668.     if (IsOpen())
  1669.     {
  1670.         OLE_TRACE0("COleServer::OnExit() Revoking server\n");
  1671.         BeginRevoke();
  1672.     }
  1673.     return OLE_OK;
  1674. }
  1675.  
  1676. OLESTATUS COleServer::OnRelease()
  1677. {
  1678.     ASSERT_VALID(this);
  1679.  
  1680.     if (IsOpen() && m_bLaunchEmbedded)
  1681.     {
  1682.         // there is a chance we should be shutting down
  1683.         // shut down if no open documents from this server or manually opened
  1684.         if (m_cOpenDocuments == 0 &&
  1685.             AfxGetApp()->GetOpenDocumentCount() == 0)
  1686.         {
  1687.             OLE_TRACE0("COleServer::OnRelease() Revoking server\n");
  1688.             BeginRevoke();
  1689.         }
  1690.     }
  1691.  
  1692.     // if someone has already revoked us
  1693.     if (!IsOpen())
  1694.     {
  1695.         OLE_TRACE0("COleServer::OnRelease() terminating server app\n");
  1696.         OLE_TRACE0("\tcalling ::PostQuitMessage\n");
  1697.         ::PostQuitMessage(0);
  1698.     }
  1699.  
  1700.     return OLE_OK;
  1701. }
  1702.  
  1703. //////////////////////////////////////////////////////////////////////////////
  1704. // Special register for server in case user does not run REGLOAD
  1705.  
  1706. BOOL AFXAPI AfxOleRegisterServerName(LPCSTR lpszTypeName,
  1707.     LPCSTR lpszLocalTypeName)
  1708. {
  1709.     ASSERT(lpszTypeName != NULL && *lpszTypeName != '\0');
  1710.     LONG    lSize;
  1711.     char    szBuffer[OLE_MAXNAMESIZE];
  1712.  
  1713.     if (lpszLocalTypeName == NULL || *lpszLocalTypeName == '\0')
  1714.     {
  1715.         OLE_TRACE1("Warning: no localized class name provided for server,"
  1716.             " using %Fs\n", lpszTypeName);
  1717.         lpszLocalTypeName = lpszTypeName;
  1718.     }
  1719.  
  1720.     lSize = OLE_MAXNAMESIZE;
  1721.     if (::RegQueryValue(HKEY_CLASSES_ROOT, lpszTypeName, szBuffer,
  1722.         &lSize) == ERROR_SUCCESS)
  1723.     {
  1724.         // don't replace an existing localized name
  1725. #ifdef _DEBUG
  1726.         // warn if not the same
  1727.         if (lstrcmp(szBuffer, lpszLocalTypeName) != 0)
  1728.             OLE_TRACE1("Server already has localized class name (%s)\n",
  1729.                 szBuffer);
  1730. #endif //_DEBUG
  1731.     }
  1732.     else
  1733.     {
  1734.         // set localized (user visible) class name
  1735.         if (::RegSetValue(HKEY_CLASSES_ROOT, lpszTypeName, REG_SZ,
  1736.           lpszLocalTypeName, lstrlen(lpszLocalTypeName)) != ERROR_SUCCESS)
  1737.             return FALSE;
  1738.     }
  1739.  
  1740.     // set the path name for the server for "StdFileEditing" to this app
  1741.  
  1742.     // get name/path of executable
  1743.     char szPathName[_MAX_PATH+1];
  1744.     ::GetModuleFileName(AfxGetInstanceHandle(), szPathName, _MAX_PATH);
  1745.  
  1746.     static char BASED_CODE szFmtSvr[] = "%s\\protocol\\StdFileEditing\\server";
  1747.     wsprintf(szBuffer, szFmtSvr, (LPCSTR)lpszTypeName);
  1748.     if (::RegSetValue(HKEY_CLASSES_ROOT, szBuffer, REG_SZ,
  1749.       szPathName, strlen(szPathName)) != ERROR_SUCCESS)
  1750.         return FALSE;
  1751.  
  1752.     // if there are no verbs, throw in the default "Edit" verb
  1753.     // (Note: we hard code the English "Edit" so you should have
  1754.     //   a .REG file for localized verb names)
  1755.  
  1756.     char szOldVerb[256];
  1757.     static char BASED_CODE szFmtVerb[] = "%s\\protocol\\StdFileEditing\\verb";
  1758.     wsprintf(szBuffer, szFmtVerb, (LPCSTR)lpszTypeName);
  1759.     lSize = OLE_MAXNAMESIZE;
  1760.     if (::RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szOldVerb,
  1761.         &lSize) != ERROR_SUCCESS)
  1762.     {
  1763.         // no verbs, add "Edit"
  1764.         if (::RegSetValue(HKEY_CLASSES_ROOT, szBuffer, REG_SZ,
  1765.           "", 0) != ERROR_SUCCESS)
  1766.             return FALSE;
  1767.  
  1768.         lstrcat(szBuffer, "\\0");    // backslash + zero
  1769.         if (::RegSetValue(HKEY_CLASSES_ROOT, szBuffer, REG_SZ,
  1770.           "Edit", 4) != ERROR_SUCCESS)
  1771.             return FALSE;
  1772.     }
  1773.  
  1774.     // all set
  1775.     return TRUE;
  1776. }
  1777.  
  1778. //////////////////////////////////////////////////////////////////////////////
  1779. // Diagnostics
  1780.  
  1781. #ifdef _DEBUG
  1782. void COleServerItem::AssertValid() const
  1783. {
  1784.     CObject::AssertValid();
  1785.  
  1786.     // must be attached to a document
  1787.     ASSERT(m_pDocument != NULL);
  1788. }
  1789.  
  1790. void COleServerItem::Dump(CDumpContext& dc) const
  1791. {
  1792.     CObject::Dump(dc);
  1793.  
  1794.     // shallow dump
  1795.     AFX_DUMP1(dc, "\n\tm_lpClient = ", (void FAR*)m_lpClient);
  1796.     AFX_DUMP1(dc, "\n\tm_rectBounds (HIMETRIC) = ", m_rectBounds);
  1797.     AFX_DUMP1(dc, "\n\tm_strItemName = ", m_strItemName);
  1798. }
  1799.  
  1800.  
  1801. void COleServerDoc::AssertValid() const
  1802. {
  1803.     CObject::AssertValid();
  1804.     ASSERT(!m_bWaiting);    // invalid while waiting for release
  1805. }
  1806.  
  1807. void COleServerDoc::Dump(CDumpContext& dc) const
  1808. {
  1809.     CObject::Dump(dc);
  1810.     AFX_DUMP1(dc, "\n\tm_pServer = ", (void*)m_pServer);
  1811.     AFX_DUMP1(dc, "\n\tm_lhServerDoc = ", (void FAR*)m_lhServerDoc);
  1812.     AFX_DUMP1(dc, "\n\tm_bWaiting = ", m_bWaiting);
  1813. }
  1814.  
  1815. void COleServer::AssertValid() const
  1816. {
  1817.     CObject::AssertValid();
  1818.     ASSERT(m_cOpenDocuments >= 0);
  1819. }
  1820.  
  1821. void COleServer::Dump(CDumpContext& dc) const
  1822. {
  1823.     CObject::Dump(dc);
  1824.     AFX_DUMP1(dc, "\n\tm_lhServer = ", (void FAR*)m_lhServer);
  1825.     AFX_DUMP1(dc, "\n\tm_bLaunchEmbedded = ", m_bLaunchEmbedded);
  1826.     AFX_DUMP1(dc, "\n\tm_cOpenDocuments = ", m_cOpenDocuments);
  1827.     AFX_DUMP1(dc, "\n\tm_strServerName = ", m_strServerName);
  1828. }
  1829.  
  1830. #endif //_DEBUG
  1831.  
  1832.  
  1833. //////////////////////////////////////////////////////////////////////////////
  1834. // Inline function declarations expanded out-of-line
  1835.  
  1836. #ifndef _AFX_ENABLE_INLINES
  1837.  
  1838. // expand inlines for OLE server APIs
  1839. static char BASED_CODE _szAfxOleInl[] = "afxole.inl";
  1840. #undef THIS_FILE
  1841. #define THIS_FILE _szAfxOleInl
  1842. #define _AFXOLESVR_INLINE
  1843. #include "afxole.inl"
  1844.  
  1845. #endif //!_AFX_ENABLE_INLINES
  1846.  
  1847. /////////////////////////////////////////////////////////////////////////////
  1848.