同上!

解决方案 »

  1.   

    HOWTO: Get IDispatch of an Excel or Word Document from an OCX
    The information in this article applies to: 
    Microsoft Excel 2000 
    Microsoft Visual C++, 32-bit Enterprise Edition 5.0 
    Microsoft Visual C++, 32-bit Enterprise Edition 6.0 
    Microsoft Visual C++, 32-bit Professional Edition 5.0 
    Microsoft Visual C++, 32-bit Professional Edition 6.0 
    Microsoft Visual C++, 32-bit Learning Edition 6.0 
    Microsoft Excel 2002 
    Microsoft Excel 97 for Windows 
    Microsoft Word 2002 
    Microsoft Word 2000 
    Microsoft Word 97 for WindowsThis article was previously published under Q190985 
    SUMMARYIt is common for an OLE control to need the IDispatch of its container. You can often get the IDispatch by using QueryInterface() from immediately accessible interfaces on the server, such as IOleClientSite. However, for some servers, such as Microsoft Excel, this approach fails. Another way to get the IDispatch is by using the GetActiveObject() API to get the server's IDispatch from the ROT. However, this method requires that you must be able to obtain the CLSID or ProgID of the server. Furthermore, ambiguous situations can occur where you can't distinguish between multiple instances of the server. This article uses another approach to obtain the IDispatch, which works for both Microsoft Excel and Microsoft Word, even when multiple instances are running. The steps listed below allow you to build a control that can obtain the IDispatch of the container's Document object. 
    MORE INFORMATIONStep By Step Example
    Create a new MFC ActiveX ControlWizard application named OffCntrDisp. 
    Add the following member variables to your COleControl-derived class:
          char m_szDocName[512];
          IDispatch *m_pDocDisp;

    NOTE: m_szDocName holds the name of the document containing our control, and m_pDocDisp is the IDispatch interface for that document.
    Add the following to the end of your COleControl-derived class definition:
          // Interface Maps.
          protected:
             // IoleObject.
             BEGIN_INTERFACE_PART(MyOleObject, IOleObject)
                INIT_INTERFACE_PART(COffCtlDispCtrl, MyOleObject)
                STDMETHOD(SetClientSite)(LPOLECLIENTSITE);
                STDMETHOD(GetClientSite)(LPOLECLIENTSITE*);
                STDMETHOD(SetHostNames)(LPCOLESTR, LPCOLESTR);
                STDMETHOD(Close)(DWORD);
                STDMETHOD(SetMoniker)(DWORD, LPMONIKER);
                STDMETHOD(GetMoniker)(DWORD, DWORD, LPMONIKER*);
                STDMETHOD(InitFromData)(LPDATAOBJECT, BOOL, DWORD);
                STDMETHOD(GetClipboardData)(DWORD, LPDATAOBJECT*);
                STDMETHOD(DoVerb)(LONG, LPMSG, LPOLECLIENTSITE, LONG, HWND,
                LPCRECT);
                STDMETHOD(EnumVerbs)(IEnumOLEVERB**);
                STDMETHOD(Update)();
                STDMETHOD(IsUpToDate)();
                STDMETHOD(GetUserClassID)(CLSID*);
                STDMETHOD(GetUserType)(DWORD, LPOLESTR*);
                STDMETHOD(SetExtent)(DWORD, LPSIZEL);
                STDMETHOD(GetExtent)(DWORD, LPSIZEL);
                STDMETHOD(Advise)(LPADVISESINK, LPDWORD);
                STDMETHOD(Unadvise)(DWORD);
                STDMETHOD(EnumAdvise)(LPENUMSTATDATA*);
                STDMETHOD(GetMiscStatus)(DWORD, LPDWORD);
                STDMETHOD(SetColorScheme)(LPLOGPALETTE);
            END_INTERFACE_PART(MyOleObject)        DECLARE_INTERFACE_MAP();

    This is added to override COleControl's default implementation of IOleObject with your custom MyOleObject.
      

  2.   

    In your COleControl-derived class's constructor, add the following:
          m_pDocDisp = NULL;
    Just after the following line in OffCntrDispCtl.cpp:
          IMPLEMENT_OLECTLTYPE(COffCntrDispCtrl, IDS_OFFCNTRDISP,       _dwOffCntrDispOleMisc)

    add the following code: 
          BEGIN_INTERFACE_MAP(COffCntrDispCtrl, COleControl)
              INTERFACE_PART(COffCntrDispCtrl, IID_IOleObject, MyOleObject)
          END_INTERFACE_MAP()

    This, along with the modifications in step 3, override COleControl's IOleObject.
    Just below the code added in step 5, add the following:
          static char buf[8192];
          static void DoMsg(char *msg) {
             ::MessageBox(NULL, msg, "Message", MB_SETFOREGROUND);
          }      static void DoErr(char *msg, long err) {
             static char errBuf[8192];
             sprintf(errBuf, "%s, Error: %ld (%08lx)", msg, err,err);
             ::MessageBox(NULL, errBuf, "Error", MB_SETFOREGROUND);
          }

    These are helpful routines used later for displaying messages.
      

  3.   

    Paste all of the following code at the end of your OffCntrDispCtl.cpp file:
          STDMETHODIMP COffCntrDispCtrl::XMyOleObject::SetHostNames(LPCOLESTR
          pwApp, LPCOLESTR pwObj)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);          // Convert OLESTR into ASCII string.          WideCharToMultiByte(CP_ACP, 0, pwObj, -1, pThis->m_szDocName,
              512, NULL, NULL);          // Get IDispatch.
              pThis->GetDocDispatch();          // Test it out by getting the document name.
              pThis->TestDispatch();          return S_OK;
          }      STDMETHODIMP
          COffCntrDispCtrl::XMyOleObject::SetClientSite(LPOLECLIENTSITE
          pClientSite)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.SetClientSite(pClientSite);
          }      STDMETHODIMP
          COffCntrDispCtrl::XMyOleObject::SetColorScheme(LPLOGPALETTE plp)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.SetColorScheme(plp);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::GetMiscStatus(DWORD
          dwAspect, DWORD* pdwStatus)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.GetMiscStatus(dwAspect, pdwStatus);
          }      STDMETHODIMP
          COffCntrDispCtrl::XMyOleObject::EnumAdvise(LPENUMSTATDATA*
          ppenumAdvise)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.EnumAdvise(ppenumAdvise);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::Unadvise(DWORD
          dwConnection)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.Unadvise(dwConnection);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::Advise(LPADVISESINK
          pAdvSink, DWORD* pdwConnection)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.Advise(pAdvSink, pdwConnection);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::GetExtent(DWORD
          dwDrawAspect, LPSIZEL lpsizel)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.GetExtent(dwDrawAspect, lpsizel);
          }
          STDMETHODIMP COffCntrDispCtrl::XMyOleObject::SetExtent(DWORD
          dwDrawAspect, LPSIZEL lpsizel)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.SetExtent(dwDrawAspect, lpsizel);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::GetUserType(DWORD
          dwFormOfType, LPOLESTR* ppszUserType)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);          return pThis->m_xOleObject.GetUserType(dwFormOfType,
              ppszUserType);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::GetUserClassID(CLSID*
          pClsid)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.GetUserClassID(pClsid);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::IsUpToDate()
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);          return pThis->m_xOleObject.IsUpToDate();
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::Update()
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.Update();
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::EnumVerbs(LPENUMOLEVERB*
          ppenumOleVerb)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);          return pThis->m_xOleObject.EnumVerbs(ppenumOleVerb);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::DoVerb(LONG iVerb, LPMSG
          lpmsg, LPOLECLIENTSITE pActiveSite, LONG lindex, HWND hwndParent,
          LPCRECT lprcPosRect)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.DoVerb(iVerb, lpmsg, pActiveSite,
              lindex, hwndParent, lprcPosRect);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::GetClipboardData(DWORD
          dwReserved, LPDATAOBJECT *ppDataObject)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.GetClipboardData(dwReserved,
              ppDataObject);
          }      STDMETHODIMP
          COffCntrDispCtrl::XMyOleObject::InitFromData(LPDATAOBJECT
          pDataObject, BOOL fCreation, DWORD dwReserved)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.InitFromData(pDataObject, fCreation,
              dwReserved);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::GetMoniker(DWORD
          dwAssign, DWORD dwWhichMoniker, LPMONIKER *ppmk)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.GetMoniker(dwAssign, dwWhichMoniker,
              ppmk);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::SetMoniker(DWORD
          dwWhichMoniker, LPMONIKER pmk)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.SetMoniker(dwWhichMoniker, pmk);
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::Close(DWORD
          dwSaveOption)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.Close(dwSaveOption);
          }      STDMETHODIMP
          COffCntrDispCtrl::XMyOleObject::GetClientSite(LPOLECLIENTSITE*
          ppClientSite)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.GetClientSite(ppClientSite);      }      STDMETHODIMP_(ULONG) COffCntrDispCtrl::XMyOleObject::Release()
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.Release();
          }      STDMETHODIMP_(ULONG) COffCntrDispCtrl::XMyOleObject::AddRef()
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.AddRef();
          }      STDMETHODIMP COffCntrDispCtrl::XMyOleObject::QueryInterface(REFIID
          iid, LPVOID* ppvObj)
          {
              METHOD_MANAGE_STATE(COffCntrDispCtrl, MyOleObject)
              ASSERT_VALID(pThis);
              return pThis->m_xOleObject.QueryInterface(iid, ppvObj);
          }

    This is your implementation of IOleObject, which mostly delegates all of its calls to the default COleControl's IOleObject implementation, except for SetHostNames(). You trap SetHostNames() and store the document name where the control is inserted.Unfortunately, Microsoft PowerPoint doesn't call this method, so this example won't work with that product. However, Microsoft Powerpoint is a single-instance server, so you could use GetActiveObject() to uniquely get the IDispatch pointer.