HOWTO: Get IDispatch of an Excel or Word Document from an OCXID: Q190985 
  | 
It 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.
      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.
      // 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.
      m_pDocDisp = NULL; 
      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.
      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.
      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.
      void COffCntrDispCtrl::GetDocDispatch()
      {
          // No need, if we already have it.
          if(m_pDocDisp != NULL) return;
          // Get a BindCtx.
          IBindCtx *pbc;
          HRESULT hr = CreateBindCtx(0, &pbc);
          if(FAILED(hr)) {
              DoErr("CreateBindCtx()", hr);
              return;
          }
          // Get running-object table.
          IRunningObjectTable *prot;
          hr = pbc->GetRunningObjectTable(&prot);
          if(FAILED(hr)) {
              DoErr("GetRunningObjectTable()", hr);
              pbc->Release();
              return;
          }
          // Get enumeration interface.
          IEnumMoniker *pem;
          hr = prot->EnumRunning(&pem);
          if(FAILED(hr)) {
              DoErr("EnumRunning()", hr);
              prot->Release();
              pbc->Release();
              return;
          }
          // Start at the beginning.
          pem->Reset();
          // Churn through enumeration.
          ULONG fetched;
          IMoniker *pmon;
          int n = 0;
          while(pem->Next(1, &pmon, &fetched) == S_OK) {
              // Get DisplayName.
              LPOLESTR pName;
              pmon->GetDisplayName(pbc, NULL, &pName);
              // Convert it to ASCII.
              char szName[512];
              WideCharToMultiByte(CP_ACP, 0, pName, -1, szName, 512, NULL,
              NULL);
              // Compare it against the name we got in SetHostNames().
              if(!strcmp(szName, m_szDocName)) {
                  DoMsg("Found document in ROT!");
                  // Bind to this ROT entry.
                  IDispatch *pDisp;
                  hr = pmon->BindToObject(pbc, NULL, IID_IDispatch, (void
                  **)&pDisp);
                  if(!FAILED(hr)) {
                      // Remember IDispatch.
                      m_pDocDisp = pDisp;
                      // Noticeā¦
                      sprintf(buf, "Document IDispatch = %08lx",
                      m_pDocDisp);
                      DoMsg(buf);
                  }
                  else {
                      DoErr("BindToObject()", hr);
                  }
              }
              // Release interfaces.
              pmon->Release();
              // Break out if we obtained the IDispatch successfully.
              if(m_pDocDisp != NULL) break;
          }
          // Release interfaces.
          pem->Release();
          prot->Release();
          pbc->Release();
      }
      void COffCntrDispCtrl::TestDispatch()
      {
          ASSERT(m_pDocDisp);
          COleDispatchDriver doc(m_pDocDisp);
          DISPID dispID = 0;
          unsigned short *ucPtr = L"Name";
          // Get DISPID for Name.
          HRESULT hr = m_pDocDisp->GetIDsOfNames(IID_NULL, &ucPtr, 1,
          LOCALE_USER_DEFAULT, &dispID);
          ASSERT(!FAILED(hr));
          // Get Name property.
          CString name;
          doc.GetProperty(dispID, VT_BSTR, &name);
          AfxMessageBox(
              CString("Document name is ") + name,
              MB_SETFOREGROUND
          );
      } © Microsoft Corporation 1998, All Rights Reserved.
Contributions by Joe Crump, Microsoft Corporation
Additional query words: getobject kbvc600 kbvc500 kbAutomation kbExcel
Keywords          : kbAutomation kbExcel kbVC500 kbVC600 
Version           : WINDOWS:97; winnt:5.0,6.0
Platform          : WINDOWS winnt 
Issue type        : kbhowto 
Last Reviewed: August 8, 1999