home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 18.ddi / MFC / SRC / OLEUI.CP_ / OLEUI.CP
Encoding:
Text File  |  1993-02-08  |  13.9 KB  |  558 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. // OLEUI.CPP - user interface for OLE clients
  12.  
  13. #include "stdafx.h"
  14. #include <shellapi.h>
  15.  
  16. #ifdef AFX_OLE_SEG
  17. #pragma code_seg(AFX_OLE_SEG)
  18. #endif
  19.  
  20. #ifdef _DEBUG
  21. #undef THIS_FILE
  22. static char BASED_CODE THIS_FILE[] = __FILE__;
  23. #endif
  24.  
  25. #ifndef _AFXDLL
  26. static AFX_OCSTATE NEAR _afxOCState;
  27. #else
  28. #define _afxOCState (*_AfxGetAppData()->appOCState)
  29. #endif
  30.  
  31. /////////////////////////////////////////////////////////////////////////////
  32. // User interface for COleClientItem
  33.  
  34. BOOL PASCAL COleClientItem::InWaitForRelease()
  35. {
  36.     return _afxOCState.cWaitForRelease != 0;
  37. }
  38.  
  39. void COleClientItem::WaitForServer()
  40. {
  41.     // enforce synchronous action from the server
  42. #ifdef _DEBUG
  43.     if (afxTraceFlags & 0x10)
  44.         TRACE0("WAITING for server\n");
  45. #endif // _DEBUG
  46.  
  47.     AfxGetApp()->DoWaitCursor(1);       // BeginWaitCursor
  48.  
  49.     ASSERT(m_lpObject != NULL);
  50.     ASSERT(_afxOCState.cWaitForRelease == 0);
  51. #ifdef _DEBUG
  52.     m_lastStatus = OLE_WAIT_FOR_RELEASE;
  53. #endif
  54.     _afxOCState.cWaitForRelease++;
  55.  
  56.     // OnRelease may NULL out our m_lpObject
  57.     while (m_lpObject != NULL && ::OleQueryReleaseStatus(m_lpObject) != OLE_OK)
  58.     {
  59.         TRY
  60.         {
  61.             AfxGetApp()->PumpMessage();
  62.         }
  63.         CATCH_ALL(e)
  64.         {
  65.             TRACE0("DANGER: caught exception in WaitForServer - continuing\n");
  66.         }
  67.         END_CATCH_ALL
  68.     }
  69.     _afxOCState.cWaitForRelease--;
  70.  
  71.     AfxGetApp()->DoWaitCursor(-1);      // EndWaitCursor
  72. #ifdef _DEBUG
  73.     if (afxTraceFlags & 0x10)
  74.         TRACE0("DONE WAITING for server\n");
  75. #endif // _DEBUG
  76. }
  77.  
  78. BOOL COleClientItem::ReportOleError(OLESTATUS status)
  79.     // return TRUE if error or warning reported
  80. {
  81.     ASSERT_VALID(this);
  82.     UINT nIDPrompt = 0;
  83.  
  84.     switch (status)
  85.     {
  86.     default:
  87.         return FALSE;       // nothing sensible to report
  88.  
  89.     case OLE_ERROR_STATIC:
  90.         nIDPrompt = AFX_IDP_STATIC_OBJECT;
  91.         break;
  92.  
  93.     case OLE_ERROR_REQUEST_PICT:
  94.     case OLE_ERROR_ADVISE_RENAME:
  95.     case OLE_ERROR_SHOW:
  96.     case OLE_ERROR_OPEN:
  97.     case OLE_ERROR_NETWORK:
  98.     case OLE_ERROR_ADVISE_PICT:
  99.     case OLE_ERROR_COMM:
  100.     case OLE_ERROR_LAUNCH:
  101.         // invalid link
  102.         nIDPrompt = AFX_IDP_FAILED_TO_CONNECT;
  103.         break;
  104.  
  105.     case OLE_ERROR_DOVERB:
  106.         nIDPrompt = AFX_IDP_BAD_VERB;
  107.         break;
  108.  
  109.     case OLE_BUSY:
  110.         nIDPrompt = AFX_IDP_SERVER_BUSY;
  111.         break;
  112.  
  113.     case OLE_ERROR_MEMORY:
  114.         nIDPrompt = AFX_IDP_FAILED_MEMORY_ALLOC;
  115.         break;
  116.     }
  117.  
  118.     ASSERT(nIDPrompt != 0);
  119.     AfxMessageBox(nIDPrompt);
  120.     return TRUE;
  121. }
  122.  
  123.  
  124. /////////////////////////////////////////////////////////////////////////////
  125. // OLE Object Verb Menu helpers
  126.  
  127. static char BASED_CODE szFmtVerbs[] = "%s\\protocol\\StdFileEditing\\verb\\%d";
  128. static char BASED_CODE szTwoNames[] = "%s %s";
  129. static char BASED_CODE szThreeNames[] = "%s %s %s";
  130.  
  131. // Parameters:
  132. //      pClient = client object to operate on (NULL => none)
  133. //      pMenu = menu to modify
  134. //      iMenuItem = index into menu where menu item or popup is to be placed
  135. //              (note will delete the old one)
  136. //      nIDVerbMin = first menu command id for sending to pClient
  137. //
  138. // Supported cases:
  139. //  NULL client "&Object" disabled
  140. //  0 verbs       "<TypeName> &Object"
  141. //  1 verb (no name) "<TypeName> &Object"
  142. //  1 verb != edit   "<verb> <TypeName> &Object"
  143. //  more than 1 verb "<TypeName> &Object" => verbs
  144.  
  145. void AFXAPI AfxOleSetEditMenu(COleClientItem* pClient, CMenu* pMenu,
  146.     UINT iMenuItem, UINT nIDVerbMin)
  147. {
  148.     ASSERT(pMenu != NULL);
  149.  
  150.     if (_afxOCState.strObjectVerb.IsEmpty())
  151.     {
  152.         VERIFY(_afxOCState.strObjectVerb.LoadString(AFX_IDS_OBJECT_MENUITEM));
  153.         VERIFY(_afxOCState.strEditVerb.LoadString(AFX_IDS_EDIT_VERB));
  154.     }
  155.  
  156.     pMenu->DeleteMenu(iMenuItem, MF_BYPOSITION); // get rid of old UI
  157.  
  158.     HGLOBAL hLinkData = NULL;
  159.     UINT mfObjectVerb = MF_GRAYED|MF_DISABLED;
  160.  
  161.     if (pClient != NULL)
  162.     {
  163.         // get type from object
  164.         hLinkData = pClient->GetLinkFormatData();
  165.         mfObjectVerb = MF_ENABLED;
  166.     }
  167.  
  168.  
  169.     // use the link data to determine what class we are talking about
  170.     LPCSTR lpszData;
  171.     if (hLinkData == NULL ||
  172.        (lpszData = (LPCSTR)::GlobalLock(hLinkData)) == NULL)
  173.     {
  174.         // not a valid link, just use the simple '&Object' format disabled
  175.         pMenu->InsertMenu(iMenuItem, MF_BYPOSITION, nIDVerbMin,
  176.             _afxOCState.strObjectVerb);
  177.         pMenu->EnableMenuItem(iMenuItem, mfObjectVerb | MF_BYPOSITION |
  178.             MF_GRAYED|MF_DISABLED);
  179.         return;
  180.     }
  181.  
  182.     LONG lSize;
  183.     char szTypeName[OLE_MAXNAMESIZE];
  184.     char szBuffer[OLE_MAXNAMESIZE+40];
  185.  
  186.     // get real language class of object in szTypeName for menu
  187.     lSize = OLE_MAXNAMESIZE;
  188.     if (::RegQueryValue(HKEY_CLASSES_ROOT, lpszData, szTypeName,
  189.         &lSize) != ERROR_SUCCESS)
  190.     {
  191.         // no localized class name, use unlocalized name
  192.         lstrcpy(szTypeName, lpszData);
  193.     }
  194.     ::GlobalUnlock(hLinkData);
  195.  
  196.     // determine list of available verbs
  197.     char szFirstVerb[OLE_MAXNAMESIZE];
  198.     HMENU hPopup = NULL;
  199.     int cVerbs = 0;
  200.  
  201.     while (1)
  202.     {
  203.         wsprintf(szBuffer, szFmtVerbs, (LPCSTR)lpszData, cVerbs);
  204.  
  205.         // get verb name
  206.         char szVerb[OLE_MAXNAMESIZE];
  207.         lSize = OLE_MAXNAMESIZE;
  208.         if (::RegQueryValue(HKEY_CLASSES_ROOT, szBuffer, szVerb, &lSize) != 0)
  209.         {
  210.             // finished counting verbs
  211.             break;
  212.         }
  213.         cVerbs++;
  214.  
  215.         if (lstrcmpi(szVerb, _afxOCState.strEditVerb) == 0)
  216.             lstrcpy(szVerb, _afxOCState.strEditVerb);
  217.                 // use 'Edit' not 'EDIT'
  218.  
  219.         if (cVerbs == 1)
  220.         {
  221.             // save first verb (special case if this is it)
  222.             lstrcpy(szFirstVerb, szVerb);
  223.         }
  224.         else
  225.         {
  226.             // overflow into popup
  227.             if (cVerbs == 2)
  228.             {
  229.                 // start the popup
  230.                 ASSERT(hPopup == NULL);
  231.                 hPopup = ::CreatePopupMenu();
  232.  
  233.                 // now add the first verb
  234.                 ::InsertMenu(hPopup, -1, MF_BYPOSITION, nIDVerbMin + 0,
  235.                     szFirstVerb);
  236.             }
  237.  
  238.             ASSERT(hPopup != NULL);
  239.             ::InsertMenu(hPopup, -1, MF_BYPOSITION, nIDVerbMin + cVerbs - 1,
  240.                     szVerb);
  241.         }
  242.     }
  243.  
  244.     if (cVerbs == 0)
  245.     {
  246.         // no verbs
  247.         wsprintf(szBuffer, szTwoNames, (LPCSTR)szTypeName,
  248.             (LPCSTR)_afxOCState.strObjectVerb);
  249.         pMenu->InsertMenu(iMenuItem, MF_BYPOSITION, nIDVerbMin, szBuffer);
  250.     }
  251.     else if (cVerbs == 1)
  252.     {
  253.         // use that verb in menu item
  254.         ASSERT(cVerbs == 1);
  255.         wsprintf(szBuffer, szThreeNames, (LPCSTR)szFirstVerb,
  256.             (LPCSTR)szTypeName, (LPCSTR)_afxOCState.strObjectVerb);
  257.         pMenu->InsertMenu(iMenuItem, MF_BYPOSITION, nIDVerbMin, szBuffer);
  258.     }
  259.     else
  260.     {
  261.         // install the popup
  262.         wsprintf(szBuffer, szTwoNames, (LPCSTR)szTypeName,
  263.             (LPCSTR)_afxOCState.strObjectVerb);
  264.         pMenu->InsertMenu(iMenuItem, MF_BYPOSITION|MF_POPUP, (UINT)hPopup, szBuffer);
  265.     }
  266.  
  267.     // enable what we added
  268.     pMenu->EnableMenuItem(iMenuItem, MF_ENABLED|MF_BYPOSITION);
  269. }
  270.  
  271. /////////////////////////////////////////////////////////////////////////////
  272. // InsertObject dialog
  273.  
  274. class CInsertNewObjectDlg : public CDialog
  275. {
  276. public:
  277.     CString& m_strTypeName;
  278.  
  279.     //{{AFX_DATA(CInsertNewObjectDlg)
  280.     enum { IDD = AFX_IDD_OLEINSERT };
  281.     //}}AFX_DATA
  282.     CInsertNewObjectDlg(CString& strReturn)
  283.             : CDialog(CInsertNewObjectDlg::IDD),
  284.                 m_strTypeName(strReturn)
  285.         { }
  286.  
  287.     BOOL OnInitDialog();
  288.     void OnOK();
  289.  
  290.     //{{AFX_MSG(CInsertNewObjectDlg)
  291.     //}}AFX_MSG
  292.     DECLARE_MESSAGE_MAP()
  293. };
  294.  
  295. BEGIN_MESSAGE_MAP(CInsertNewObjectDlg, CDialog)
  296.     //{{AFX_MSG_MAP(CInsertNewObjectDlg)
  297.     ON_LBN_DBLCLK(AFX_IDC_LISTBOX, OnOK)
  298.     //}}AFX_MSG_MAP
  299. END_MESSAGE_MAP()
  300.  
  301. BOOL CInsertNewObjectDlg::OnInitDialog()
  302. {
  303.     int cTypes = 0;
  304.     CListBox* pList = (CListBox*)GetDlgItem(AFX_IDC_LISTBOX);
  305.  
  306.     pList->ResetContent();
  307.  
  308.     char szTypeName[OLE_MAXNAMESIZE];
  309.     int i = 0;
  310.     while (::RegEnumKey(HKEY_CLASSES_ROOT, i++, szTypeName,
  311.          OLE_MAXNAMESIZE) == 0)
  312.     {
  313.         if (szTypeName[0] == '.')
  314.             continue;       // skip extensions
  315.  
  316.         // See if this class really refers to a server
  317.         LONG lSize;
  318.         HKEY hkey = NULL;
  319.         char szExec[OLE_MAXNAMESIZE+40];
  320.         lstrcpy(szExec, szTypeName);
  321.         lstrcat(szExec, "\\protocol\\StdFileEditing\\server");
  322.  
  323.         if (::RegOpenKey(HKEY_CLASSES_ROOT, szExec, &hkey) == 0)
  324.         {
  325.             // since it has a server - add it to the list
  326.             char szName[OLE_MAXNAMESIZE];
  327.             lSize = OLE_MAXNAMESIZE;
  328.             if (::RegQueryValue(HKEY_CLASSES_ROOT, szTypeName,
  329.               szName, &lSize) == 0)
  330.             {
  331.                 // we have a class name
  332.                 pList->AddString(szName);
  333.                 cTypes++;
  334.             }
  335.             ::RegCloseKey(hkey);
  336.         }
  337.     }
  338.  
  339.     if (cTypes != 0)
  340.         pList->SetCurSel(0);
  341.     else
  342.         TRACE0("Warning: no registered OLE servers\n");
  343.  
  344.     return CDialog::OnInitDialog();
  345. }
  346.  
  347. void CInsertNewObjectDlg::OnOK()
  348. {
  349.     CListBox* pList = (CListBox*)GetDlgItem(AFX_IDC_LISTBOX);
  350.     int nIndex = pList->GetCurSel();
  351.     if (nIndex < 0)
  352.         EndDialog(IDABORT);     // nothing selected
  353.  
  354.     char szKey[OLE_MAXNAMESIZE];
  355.     pList->GetText(nIndex, szKey);
  356.  
  357.     char szTypeName[OLE_MAXNAMESIZE];
  358.     int i = 0;
  359.     while (::RegEnumKey(HKEY_CLASSES_ROOT, i++, szTypeName,
  360.         OLE_MAXNAMESIZE) == 0)
  361.     {
  362.         if (szTypeName[0] == '.')
  363.             continue;       // skip extensions
  364.  
  365.         // See if this class really refers to a server
  366.         LONG lSize;
  367.         HKEY hkey = NULL;
  368.         char szExec[OLE_MAXNAMESIZE+40];
  369.         lstrcpy(szExec, szTypeName);
  370.         lstrcat(szExec, "\\protocol\\StdFileEditing\\server");
  371.  
  372.         if (::RegOpenKey(HKEY_CLASSES_ROOT, szExec, &hkey) == 0)
  373.         {
  374.             // we found a match - see if appropriate name
  375.             char szName[OLE_MAXNAMESIZE];
  376.             lSize = OLE_MAXNAMESIZE;
  377.             if (::RegQueryValue(HKEY_CLASSES_ROOT, szTypeName,
  378.               szName, &lSize) == 0)
  379.             {
  380.                 // it is a named class - see if it matches key
  381.                 if (lstrcmp(szKey, szName) == 0)
  382.                 {
  383.                     // this is it
  384.                     m_strTypeName = szTypeName;
  385.                     CDialog::OnOK();   // terminate dialog
  386.                     ::RegCloseKey(hkey);
  387.                     return;
  388.                 }
  389.             }
  390.             ::RegCloseKey(hkey);
  391.         }
  392.     }
  393.  
  394.     // didn't find it
  395.     EndDialog(IDABORT);
  396. }
  397.  
  398.  
  399. BOOL AFXAPI AfxOleInsertDialog(CString& name)
  400. {
  401.     CInsertNewObjectDlg dlg(name);
  402.  
  403.     return (dlg.DoModal() == IDOK);
  404. }
  405.  
  406. /////////////////////////////////////////////////////////////////////////////
  407. // Item activation
  408.  
  409. BOOL COleClientItem::DoVerb(UINT nVerb)
  410. {
  411.     ASSERT_VALID(this);
  412.  
  413.     if (GetType() == OT_STATIC)
  414.         return FALSE;
  415.  
  416.     TRY
  417.     {
  418.         Activate(nVerb, TRUE, TRUE, AfxGetApp()->m_pMainWnd, NULL);
  419.     }
  420.     CATCH(COleException, e)
  421.     {
  422.         if (!ReportOleError(e->m_status))
  423.             AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH);
  424.         return FALSE;
  425.     }
  426.     AND_CATCH_ALL(e)
  427.     {
  428.         // general error when playing
  429.         AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH);
  430.         return FALSE;
  431.     }
  432.     END_CATCH_ALL
  433.  
  434.     return TRUE;
  435. }
  436.  
  437. BOOL COleClientDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra,
  438.         AFX_CMDHANDLERINFO* pHandlerInfo)
  439. {
  440.     if (nCode == 0 && nID >= ID_OLE_VERB_FIRST && nID <= ID_OLE_VERB_LAST)
  441.     {
  442.         COleClientItem* pSel = GetPrimarySelectedItem(GetRoutingView());
  443.         if (pSel != NULL)
  444.         {
  445.             if (pHandlerInfo != NULL)       // routing test
  446.             {
  447.                 pHandlerInfo->pTarget = this;
  448.                 return TRUE;        // would be handled here
  449.             }
  450.  
  451.             // if waiting for previous command - don't permit this one
  452.             if (COleClientItem::InWaitForRelease())
  453.             {
  454.                 AfxMessageBox(AFX_IDP_SERVER_BUSY);
  455.                 return TRUE;        // handled
  456.             }
  457.  
  458.             // activate the current selection with the appropriate verb
  459.             pSel->DoVerb(nID - ID_OLE_VERB_FIRST);
  460.             return TRUE;        // handled
  461.         }
  462.     }
  463.     return COleDocument::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
  464. }
  465.  
  466. /////////////////////////////////////////////////////////////////////////////
  467. // COleClientDoc - user interface
  468.  
  469. BEGIN_MESSAGE_MAP(COleClientDoc, COleDocument)
  470.     //{{AFX_MSG_MAP(COleClientDoc)
  471.     // default update based on clipboard contents
  472.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdatePasteMenu)
  473.     ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE_LINK, OnUpdatePasteLinkMenu)
  474.     // edit links dialog
  475.     ON_UPDATE_COMMAND_UI(ID_OLE_EDIT_LINKS, OnUpdateEditLinksMenu)
  476.     ON_COMMAND(ID_OLE_EDIT_LINKS, OnEditLinks)
  477.     // object verb
  478.     ON_UPDATE_COMMAND_UI(ID_OLE_VERB_FIRST, OnUpdateObjectVerbMenu)
  479.     //}}AFX_MSG_MAP
  480. END_MESSAGE_MAP()
  481.  
  482. void COleClientDoc::OnUpdatePasteMenu(CCmdUI* pCmdUI)
  483. {
  484.     pCmdUI->Enable(COleClientItem::CanPaste());
  485. }
  486.  
  487. void COleClientDoc::OnUpdatePasteLinkMenu(CCmdUI* pCmdUI)
  488. {
  489.     pCmdUI->Enable(COleClientItem::CanPasteLink());
  490. }
  491.  
  492. void COleClientDoc::OnUpdateEditLinksMenu(CCmdUI* pCmdUI)
  493. {
  494.     POSITION pos = GetStartPosition();
  495.     while (pos != NULL)
  496.     {
  497.         CDocItem* pItem = GetNextItem(pos);
  498.         if (pItem->IsKindOf(RUNTIME_CLASS(COleClientItem)) &&
  499.             ((COleClientItem*)pItem)->GetType() == OT_LINK)
  500.         {
  501.             // we found a link !
  502.             pCmdUI->Enable(TRUE);
  503.             return;
  504.         }
  505.     }
  506.     pCmdUI->Enable(FALSE);      // no links today
  507. }
  508.  
  509. void COleClientDoc::OnEditLinks()
  510. {
  511.     ASSERT_VALID(this);
  512.     AfxOleLinksDialog(this, GetRoutingView());
  513. }
  514.  
  515. void COleClientDoc::OnUpdateObjectVerbMenu(CCmdUI* pCmdUI)
  516. {
  517.     if (pCmdUI->m_pMenu == NULL || pCmdUI->m_nIndex == 0)
  518.     {
  519.         // not a menu or don't recurse down the sub-menu
  520.         pCmdUI->ContinueRouting();
  521.         return;
  522.     }
  523.  
  524.     // check for single selection
  525.     AfxOleSetEditMenu(GetPrimarySelectedItem(GetRoutingView()),
  526.         pCmdUI->m_pMenu, pCmdUI->m_nIndex, ID_OLE_VERB_FIRST);
  527. }
  528.  
  529.  
  530. COleClientItem* COleClientDoc::GetPrimarySelectedItem(CView* pView)
  531. {
  532.     ASSERT_VALID(this);
  533.     ASSERT(pView != NULL);
  534.     ASSERT_VALID(pView);
  535.  
  536.     COleClientItem* pSelectedItem = NULL;
  537.  
  538.     // walk all items in the document - return one if there
  539.     //   is only one client item selected
  540.     // (note: non OLE client items are ignored)
  541.     POSITION pos = GetStartPosition();
  542.     while (pos != NULL)
  543.     {
  544.         CDocItem* pItem = GetNextItem(pos);
  545.         if (pItem->IsKindOf(RUNTIME_CLASS(COleClientItem)) &&
  546.                 pView->IsSelected(pItem))
  547.         {
  548.             // client item selected in
  549.             if (pSelectedItem != NULL)
  550.                 return NULL;        // more than one - no primary selection
  551.             pSelectedItem = (COleClientItem*)pItem;
  552.         }
  553.     }
  554.     return pSelectedItem;
  555. }
  556.  
  557. /////////////////////////////////////////////////////////////////////////////
  558.