- - PR -
オートメーションで、Excelを操作する時の、BOOKを閉じる前に関して
1
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2007-07-19 21:51
マイクロソフトの解説を頼りに、
Excelを操作するアプリケーションを作成しました。 ある条件のとき、BOOKを閉じたくないので、 VS2003 のクラスの新規作成 「TypeライブラリからMFCクラスの作成」 から、 「Microsoft Excel10.0 Object Library」を選び、 AppEvents を作成して「CAppEvents」クラスを自動生成しました。 このクラスの「WorkbookBeforeClose」がBOOKを閉じる前の処理に 関するものだと思うのですが、使用方法がわかりません。 1.引数には何を指定するのでしょうか? 2.呼ばれたときに、独自の処理を実行できるのでしょうか? (コールバック関数のように使えますか?) ぜひ使い方を教えていただけないでしょうか? #実際に作成されたメンバ関数です class CAppEvents : public COleDispatchDriver { void WorkbookBeforeClose(LPDISPATCH Wb, BOOL * Cancel) { static BYTE parms[] = VTS_DISPATCH VTS_PBOOL ; InvokeHelper(0x622, DISPATCH_METHOD, VT_EMPTY, NULL, parms, Wb, Cancel); } } | ||||||||||||||||
|
投稿日時: 2007-07-20 19:17
こんにちは。
MFCではExcelのイベントを拾うのは無理なのかな… 途中断念しましたが、途中までのやり方を書いておきます。 まずAppEventsディスパッチインターフェイスはこちらから”呼び出す”ものではなく、 コネクタブルオブジェクトであるExcel.Application側から”呼び出される”ものです。 なので、AppEventsディスパッチインターフェイス(IDispatchインターフェイス)をこちらで実装してやる必要があります。 ※COleDispatchDriverクラスはこちらから”呼び出す”ためのヘルパークラスです。 MFCでは通常CCmdTargetクラスでオートメーションのサポートがされていますので、 MFCクラスの追加で基本クラスにCCmdTargetを指定して、オートメーションをオンにして生成します。
コネクタブルオブジェクトであるExcel.Applicationオブジェクトからイベントを受け取るために、 CAppEventsオブジェクトと接続してやります。 まずExcel.ApplicationオブジェクトからIConnectionPointContainerインターフェイスを取得し、 IConnectionPointContainer::FindConnectionPointでIConnectionPointインターフェイスを取得します。 あとは、IConnectionPoint::AdviseでCAppEventsオブジェクトに繋げてやります。 こんな感じ…
これでコールバックが受け取れるはずなのですが、 ExcelはIDispatch::GetIDsOfNamesを呼び出さず、直接IDispatch::Invokeでコールバックしてくるようです(行儀が悪いなぁ)。 なのでCAppEventsクラスにはちゃんと決められたディスパッチIDとメソッドを関連付けておく必要があります。。 ディスパッチIDを明示的に指定するにはDISP_FUNCTION_IDマクロを使えば出来るようです。 ※ここからが問題※ また、Excelは「名前付き引数」でコールバックしてきます。 どうもCCmdTargetクラスでは名前付き引数をサポートしておらず、DISP_E_NONAMEDARGSエラーを返してしまうようです。 あとは、誰か続きをお願いしまぁす^^; | ||||||||||||||||
|
投稿日時: 2007-07-21 02:18
以下の接続ポイント作成の参考情報を踏まえて。
http://support.microsoft.com/kb/309309/
これは仕様通りです。 接続ポイントに対してAppEventsのIIDを要求しているため、 イベントインターフェースはAppEventsを実装しているとみなされます。 つまり、DISPIDは自明なものとして処理されます。
私の知る限りMFCで名前付き引数を処理する方法はありません。 # Visual Studio 2005 は未調査 CCmdTargetクラスに処理される前段階のCOleDispatchImplクラスでDISP_E_NONAMEDARGSを返却しているようです。 Excelに限って言えばIDispatchを実装したクラスを作成した方が早いと私は考えています。 必須となるメソッドは以下の4つだけですので、それほど手間は掛からないと思います。 ・IUnknown::QueryInterface ・IUnknown::AddRef ・IUnknown::Release ・IDispatch::Invoke # 基礎知識が無いなら話は別ですが・・・。 | ||||||||||||||||
|
投稿日時: 2007-07-21 14:04
こんにちは。
フォローどうもありがとうございます。
なるほど。”行儀が悪い”の発言は、私の主観的意見(単にDISPIDを合わせるのが面倒だったので)だったようです。
やはりMFCでは名前付き引数が処理できないっぽいですね。 #実はここ数日の断続的な頭痛に悩まされながら、昨日この辺りでハマって調査していたのですが、 結局あきらめてしまいました。
同意です。 目的のイベント(WorkbookBeforeClose)を拾うだけなら、IDispatch::Invokeの実装も手を抜けそうですし… 自分で作ってしまうのが良い気がします。 | ||||||||||||||||
|
投稿日時: 2007-07-22 15:11
Tdnr_Sym様、Atata!!様返信ありがとうございます。
MFCで自動作成したクラスで(楽に)実装できるものだと思っていたので、 少し、残念ですが、Atata!!様の助言どうり、 IDispatchを実装したクラスを作成したいと思います! 引用: -------------------------------------------------------------------------------- Excelに限って言えばIDispatchを実装したクラスを作成した方が早いと私は考えています。 必須となるメソッドは以下の4つだけですので、それほど手間は掛からないと思います。 ・IUnknown::QueryInterface ・IUnknown::AddRef ・IUnknown::Release ・IDispatch::Invoke # 基礎知識が無いなら話は別ですが・・・。 -------------------------------------------------------------------------------- | ||||||||||||||||
|
投稿日時: 2007-07-22 21:17
独自に実装されるのならば、以下のような手法もあります。 Excelのイベントインターフェースには純粋ディスパッチインターフェース(AppEvents)と デュアルインターフェース(IAppEvents)の2つの定義があります。 デュアルインターフェース側の型情報(ITypeInfo)をタイプライブラリから取得しておいて、 イベントを実装したクラスのIDispatch::Invoke内で 取得しておいたITypeInfo::Invokeメソッドを呼び出すことにより デュアルインターフェースの個別のメソッドに呼び出しを転送するという手法です。 ITypeInfo::Invokeは正確に名前付き引数を処理するので、 名前付き引数を自力で解析する必要がなくなります。 この手法の難点として・・・ ・イベントを処理するクラスでIAppEventsの全てのメソッドを実装する必要があること ・読み込むタイプライブラリを正確に把握している必要があること 等が挙げられます。 # 自分でIDLを書けば、上記の問題をある程度軽減することもできますが・・・。 以上、ご参考まで。 MFCが名前付き引数を処理できないなら、システムに処理させる技とでも言いましょうか。 なお、上記以外にATLでも条件付きながら名前付き引数を処理することができます。 |
1