Excel ファイルまたは Word 文書の IDispatch を OCX から取得する方法
OLE コントロールは自身のコンテナの IDispatch を必要とすることがよくあります。多くの場合、IDispatch を取得するには、サーバーにある IOleClientSite など、即座にアクセスできるインターフェイスから QueryInterface() を使用します。ただし、Microsoft Excel など、一部のサーバーでは、このアプローチは失敗します。
IDispatch を取得するもう 1 つの方法は、GetActiveObject() API を使用して、ROT からサーバーの IDispatch を取得する方法です。ただし、この方法を使用するには、サーバーの CLSID または ProgID を取得する必要があります。さらに、サーバーの複数のインスタンスを互いに区別できない、あいまいな状況が発生することがあります。
この資料では、別のアプローチを使用して IDispatch を取得します。このアプローチは、複数のインスタンスを実行している場合でも、Microsoft Excel と Microsoft Word のどちらでも機能します。
以下に記載されている手順を使用して、コンテナの Document オブジェクトの IDispatch を取得するコントロールをビルドできます。
手順の例
-
OffCntrDisp という名前で新しい MFC ActiveX ControlWizard アプリケーションを作成します。
-
以下のメンバ変数を COleControl 派生クラスに追加します。
char m_szDocName[512];
IDispatch *m_pDocDisp;
注 : m_szDocName はコントロールを含んでいるドキュメントの名前を保持します。m_pDocDisp はそのドキュメントの IDispatch インターフェイスです。
-
以下のコードを COleControl 派生クラス定義の末尾に追加します。
// 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();
このコードは、COleControl の、IOleObject のデフォルトの実装を、ユーザーのカスタム MyOleObject でオーバーライドするために追加されます。
-
COleControl 派生クラスのコンストラクタに、以下のコードを追加します。
-
OffCntrDispCtl.cpp の次の行のすぐ後にコードを追加します。
IMPLEMENT_OLECTLTYPE(COffCntrDispCtrl, IDS_OFFCNTRDISP,
_dwOffCntrDispOleMisc)
上記のコードの後に次のコードを追加します。
BEGIN_INTERFACE_MAP(COffCntrDispCtrl, COleControl)
INTERFACE_PART(COffCntrDispCtrl, IID_IOleObject, MyOleObject)
END_INTERFACE_MAP()
このコードは、手順 3. での変更と共に、COleControl の IOleObject をオーバーライドします。
-
手順 5. で追加したコードのすぐ下に、以下のコードを追加します。
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);
}
これらのコードは、メッセージを表示するために後で使用する、便利なルーチンです。
-
以下のすべてのコードを OffCntrDispCtl.cpp ファイルの末尾に貼り付けます。
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);
}
このコードは IOleObject の実装であり、多くの場合、呼び出しをデフォルトの COleControl の IOleObject の実装にデリゲートします。ただし、SetHostNames() は例外です。SetHostNames() をトラップし、コントロールの挿入先ドキュメント名を格納します。
残念なことに、Microsoft PowerPoint はこのメソッドを呼び出さないので、この例は Microsoft PowerPoint では機能しません。ただし、Microsoft PowerPoint は単一インスタンスのサーバーなので、GetActiveObject() を使用して一意に IDispatch ポインタを取得できます。
-
COleControl 派生クラスに以下のメンバ関数を追加します。
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 Excel 97 で、以下の手順に従ってコントロールをテストします。
-
Excel 97 を起動します。
-
[コントロール ツールボックス] ツール バーを表示します ([表示] メニューで、[ツール バー] をクリックします)。
-
[コントロール ツールボックス] ツール バーの右端にあるハンマーとレンチのアイコンをクリックし、
OffCntrDisp という名前の新しいコントロールを選択します。
-
シートに四角形を描画し、コントロールを挿入します。
結果 : コントロールが表示され、その後間もなく、"Found document in ROT" というメッセージを示すメッセージ ボックスが表示されます。次に、もう 1 つのメッセージ ボックスが表示され、"Document IDispatch = 0043bf8c." に近いメッセージが表示されます。最後に、コントロールを挿入したドキュメントの名前を知らせるメッセージ ボックスが表示されます。
Microsoft Office Excel 2007 で、以下の手順に従ってコントロールをテストします。
-
Excel 2007 を起動します。
-
[開発] タブをクリックします。[開発] タブがリボンに表示されない場合は、次の手順を実行してタブを表示します。
-
Microsoft Office ボタンをクリックし、[Excel のオプション] をクリックします。
-
[基本設定] タブをクリックし、[[開発] タブをリボンに表示する] チェック ボックスをオンにします。
-
[OK] をクリックします。
-
[開発] タブの [コントロール] で、[挿入] をクリックします。
-
[ActiveX コントロール] で、[コントロールの選択] をクリックします。
-
[コントロールの選択] ダイアログ ボックスで、[OffCntrDisp] をクリックし、[OK] をクリックします。
-
シートに四角形を描画し、コントロールを挿入します。
結果 : コントロールが表示され、その後間もなく、"Found document in ROT" というメッセージが記載されたメッセージ ボックスが表示されます。次に、もう 1 つのメッセージ ボックスが表示され、"Document IDispatch = 0043bf8c." に近いメッセージが表示されます。最後に、コントロールを挿入したドキュメントの名前を知らせるメッセージ ボックスが表示されます。
文書番号: 190985 - 最終更新日: 2007年6月14日 - リビジョン: 5.0 この資料は以下の製品について記述したものです。- Microsoft Visual C++ 5.0 Enterprise Edition
- Microsoft Visual C++ 6.0 Enterprise Edition
- Microsoft Visual C++ 5.0 Professional Edition
- Microsoft Visual C++ 6.0 Professional Edition
- Microsoft Visual C++, 32-bit Learning Edition 6.0
- Microsoft Office Word 2007
- Microsoft Office Word 2003
- Microsoft Word 2002
- Microsoft Word 2000
- Microsoft Word 97 Standard Edition
- Microsoft Office Excel 2007
- Microsoft Office Excel 2003
- Microsoft Excel 2002 Standard Edition
- Microsoft Excel 2000 Standard Edition
- Microsoft Excel 97 Standard Edition
| kbhowto kbautomation KB190985 |
"Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。" この情報を使うのにどれだけの労力を費やしましたか? この情報を改善するためのアイデアを理由を添えてお知らせください。 個人情報保護のため、フィードバックには個人情報の記入はご遠慮ください。 ご協力ありがとうございました。お客様のご意見は、サポート情報をより良くするために利用させていただきます。この他のサポート情報をお探しの場合は、引き続きサポート オンラインをご利用ください。 | |