none
COleDispatchDriverでExcelをCells(3,5).Selectする方法 RRS feed

  • 質問

  • いつもお世話になっております。

    VS2015UD2で作業しています。

    COleDispatchDriver InvokeHelper()でいろんなイベントにてExcelへデータを出力するものを作っていまして、Rangeオブジェクトを使用したCells(3,5).Selectをしたいのですが、InvokeHelper()へ設定する引数の内容をよく理解していないので通りません。

    CreateDispatch("Excel.Application")で取得したExcelからRangeオブジェクトを使用し、アクティブセルへのデータを出力するようなことはできています。

    以下の処理では全体がSelectされてしまいます。Cells()がよくないと思いますが調査すれども全く見当つかない状態です。

    リファレンスでも結構です。どうぞ宜しくお願いいたします。

    static DISPID GetDispID( LPDISPATCH lpDispatch, LPOLESTR lpszName )
    {
    	DISPID     dispid;
    	lpDispatch->GetIDsOfNames( IID_NULL, &lpszName, 1, LOCALE_USER_DEFAULT, &dispid );
    	return dispid;
    }
    
    
    本体処理()
    {
    	Range rg = gExcelApp.GetCells();
    	rg.Cells( COleVariant( 3 ), COleVariant( 5 ) );
    	rg.Select();
    }
    
    
    VARIANT Range::Cells( const VARIANT& RowIndex, const VARIANT& ColumnIndex )
    {
    	VARIANT result;
    	DISPID dispid = GetDispID( m_lpDispatch, L"Cells" );
    	static BYTE parms[] =
    		VTS_VARIANT VTS_VARIANT;
    	InvokeHelper(dispid, DISPATCH_PROPERTYPUT, VT_VARIANT, (void*)&result, parms,
    		&RowIndex, &ColumnIndex);
    	return result;
    }
    
    VARIANT Range::Select()
    {
    	VARIANT result;
    	DISPID dispid = GetDispID( m_lpDispatch, L"Select" );
    	InvokeHelper(dispid, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL);
    	return result;
    }
    
    
    
    
    class Range : public COleDispatchDriver
    {
    public:
    	Range() {}		// COleDispatchDriver デフォルト コンストラクション
    	Range(LPDISPATCH pDispatch) : COleDispatchDriver(pDispatch) {}
    	Range(const Range& dispatchSrc) : COleDispatchDriver(dispatchSrc) {}
    
    	VARIANT Cells( const VARIANT& RowIndex, const VARIANT& ColumnIndex );
    	VARIANT Cells( const COleVariant& RowIndex, const COleVariant& ColumnIndex )
    	{
    		return Cells((const VARIANT&)RowIndex, (const VARIANT&)ColumnIndex);
    	}
    
    	VARIANT Select( const VARIANT& RowIndex, const VARIANT& ColumnIndex );
    	VARIANT Select(const COleVariant& RowIndex, const COleVariant& ColumnIndex)
    	{
    		return Select((const VARIANT&)RowIndex, (const VARIANT&)ColumnIndex);
    	}
    };
    

    2016年6月21日 1:31

回答

  • Officeは自分のマシンにもインストールされていることを思い出したので、インストールしている Excel 2016 のタイプライブラリを見てみました。

    Cells は、Range オブジェクトを返すだけの読み取り専用プロパティ(DISPATCH_PROPERTYGETのみのプロパティ)です。

    Range オブジェクトには、Default プロパティがあったので、Invoke に DISPID_VALUE で、DISPATCH_PROPERTYGET アクセスすればいいと思います。

    ところで。。。リファレンスはお持ちではないようですが、社内のだれかが古いOfficeのSDKを持っているなどはありませんか?

    もし、リファレンスなしでやるなら、MFCのクラスウィザードにタイプライブラリからMFCのクラス(ヘルパークラス)を作る機能があるので、それを使うことをお勧めします。

    最終的に、そのオブジェクトは使わなくてもいいと思いますが、調べる際のリファレンス代わりとしてはかなり有用だと思いますよ。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年6月22日 0:38
    2016年6月21日 4:59

すべての返信

  • 手元に Excel のタイプライブラリがないのでわかりませんが、Cells は、DISPATCH_PROPERTYPUT ではなく DISPATCH_METHOD ではありませんか?

    Select が DISPATCH_METHOD なので、同じじゃないのかな?と思っただけで詳細はわかりません。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2016年6月21日 2:03
  • とっちゃん 様

    早速のレス、ありがとうございます。

    CellsにDISPATCH_METHODを試してみたところ、例外が発生しました。OKはメモリ不足のメッセージになります。

    手元のVBA辞典を見るとCellsはプロパティみたいですので、

        VARIANT result;
        long r = 3, c = 5;
        DISPID dispid = GetDispID( m_lpDispatch, L"Cells" );
        SetProperty( dispid, VT_I4, r, c );
        return result;


    と仮に変更すると、今度はExcelの「大量の処理を行う操作」メッセージボックスが表示されました。

    どうぞ宜しくお願いいたします。

    • 編集済み SHIN109 2016年6月21日 2:55 追記
    2016年6月21日 2:49
  • Officeは自分のマシンにもインストールされていることを思い出したので、インストールしている Excel 2016 のタイプライブラリを見てみました。

    Cells は、Range オブジェクトを返すだけの読み取り専用プロパティ(DISPATCH_PROPERTYGETのみのプロパティ)です。

    Range オブジェクトには、Default プロパティがあったので、Invoke に DISPID_VALUE で、DISPATCH_PROPERTYGET アクセスすればいいと思います。

    ところで。。。リファレンスはお持ちではないようですが、社内のだれかが古いOfficeのSDKを持っているなどはありませんか?

    もし、リファレンスなしでやるなら、MFCのクラスウィザードにタイプライブラリからMFCのクラス(ヘルパークラス)を作る機能があるので、それを使うことをお勧めします。

    最終的に、そのオブジェクトは使わなくてもいいと思いますが、調べる際のリファレンス代わりとしてはかなり有用だと思いますよ。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    • 回答としてマーク SHIN109 2016年6月22日 0:38
    2016年6月21日 4:59
  • とっちゃん 様

    レスありがとうございました。
    目的達成できました。ありがとうございました。

    リファレンスについてもご指導ありがとうございました。
    クラスウィザードにて参照しました。
    自分で作るよりこちらの方が楽ですね。

    ところでこのdispidですが、Excelのバージョン毎に変わったりするものでしょうか?

    宜しくお願いいたします。
    2016年6月21日 7:21
  • >自分で作るよりこちらの方が

    タイプライブラリがあるなら、一度自動生成させた方が楽ですね。

    そのあとで、中身をごっそり作り変えてしまうということもよくありますがw

    >ところでこのdispidですが、Excelのバージョン毎に変わったりするものでしょうか?

    Excelは、Dual Interfaceではないと思うので、DISPIDがバージョン間で維持されているかどうかは、わかりません。

    COMの遅延バインディングの仕組み上、実行時に名前からDISPIDを取り出すことを想定して(遅延バインディングの推奨)バージョンアップしている可能性が高いので、バージョンごとにDISPIDが違う可能性はあります。

    SDKがあれば、リファレンスのどこかにバージョン間の互換性についての記述があると思いますが、自分では持っていないのでこれについては何とも言えません。


    とっちゃん@わんくま同盟, Visual Studio and Development Technologies http://blogs.wankuma.com/tocchann/default.aspx

    2016年6月21日 8:07
  • とっちゃん 様

    レスありがとうございました。


    >COMの遅延バインディングの仕組み上、実行時に名前からDISPIDを取り出すことを想定して(遅延バインディングの推奨)
    >バージョンアップしている可能性が高いので、バージョンごとにDISPIDが違う可能性はあります。

    そうすると16進数で書かれているのはGetIDsOfNames()で調べるようにした方が手堅くなるかもしれませんね。
    実際16進数ですと、?ってなりますし。
    その辺も同時にやってみます。

    ご教示、ありがとうございました。
    「回答としてマーク」は先のご回答分にさせていただきます。
    ありがとうございました。
    2016年6月22日 0:38