- - PR -
[C#]ActiveX DLLのメソッドの返値がobject型でキャストできません・・・
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-06-12 18:27
渋木宏明(ひどり) 様
早速のご返答大変感謝しています。有難うございます。 ActiveX DLLの方は修正できないませんので別な手段というものはあるのでしょうか? 先ほどEXCELのVBAで確認してみたのですが、 Dim DataArray(1024) AS Singleと宣言し、そのままメソッドに渡してみたのですが、問題なく正しい値を返してくれました。 C#では動かず(?)、VBAでは動くという点から何かお気づきの点でもあれば教えて頂けますでしょうか? 提供されているサンプルプログラム(VC++6?)では内容は全くわからないのですが、 .hファイル内で「自動生成されたIDispatch ラップクラス」と書かれたファイルがあり、そこでの宣言では 「VARIANT& ArrayData」となっていました。 実際の呼び出しでは、 // データ配列取得用バッファ確保 SAFEARRAYBOUND rgsabound[1]; rgsabound[0].lLbound = 0; rgsabound[0].cElements = 1024; SAFEARRAY* psa = SafeArrayCreate(VT_R4, 1, rgsabound); VARIANT vntArray; vntArray.vt = VT_ARRAY | VT_R4 | VT_BYREF; vntArray.pparray = &psa; として、目的のメソッドにvntArrayを渡していました。 参考にと思ったのですが、恥ずかしながら私にはまったく理解できませんでした。 | ||||||||
|
投稿日時: 2005-06-12 19:01
OLE/COM と .NET の COM 連携機能に関する(深い)造詣があれば不可能ではないです。
VBA のスクリプトエンジンはネイティブコードで実装されており、OLE/COM に直接的にアクセスできます。 メソッドの in, out 属性なんかはテキトーでも動いてしまいます。 これに対して、C# というか .NET はプログラムの実行方式がまったく異なります。 .NET からは「COM 連携」という、一種のミドルウェアのようなものを介して OLE/COM にアクセスします。 本来 in, out という属性が付与されるべきメソッドに適切な属性が付与されていなければ void Hoge(ref object array); というラッパメソッドを生成するべきところで void Hoge(object array); というラッパメソッドが自動生成されてしまうのは避けようがありません。 なので、「目的のメソッド呼び出しを行うためのラッパを自分で書く」のが直接的な解決の基本路線です。 あとは、 1.C# などの .NET な言語で書く 2.C++ などのネイティブな言語で書く の2つの選択肢から好きな方を選び、実装を行うだけです。 が、私ならそんな時間があったら ActiveX DLL を直すか、ActiveX DLL なんか捨てて、代わりのコードを書くことを検討します。 _________________ // 渋木宏明 (Hiroaki SHIBUKI) // http://hidori.jp/ // Microsoft MVP for Visual C# // // @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/ | ||||||||
|
投稿日時: 2005-06-12 19:42
C# だけでもなんとかなる気がしてきました。
元々インターフェース型にキャストしてメソッド呼び出しをしているので、 ・C# で問題のメソッドを含む「正しい」インターフェースを別名で再定義 (ただし IID はそろえる) ・再定義したインターフェース型でキャストし、メソッド呼び出し でいけるかもしれません。 問題のメソッドが [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("xxx")] public interface IHoge { void OtherMethod1(int a); void OtherMethodN(int a, int b); void Hoge(object array); void OtherMethodNPluse1(int a, int b, int c); void OtherMethodM(); } のよううなインターフェース定義に含まれている時、別途 [ComImport] [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] [Guid("xxx")] public interface IMyHoge { void OtherMethod1(); void OtherMethodN(); void Hoge(ref object array); void OtherMethodNPluse1(); void OtherMethodM(); } # メソッドの並び順は元の IHoge と同じにすること。 # 他のメソッドの引数は(呼び出ししないなら)省略してしまっても問題なし。 というインターフェースを定義して、これまで IHoge hoge = (IHoge) obj; hoge.Hoge (array); としていたところを IMyHoge hoge = (IMyHoge) obj; hoge.Hoge (ref array); とすればOKかもしれません。 _________________ // 渋木宏明 (Hiroaki SHIBUKI) // http://hidori.jp/ // Microsoft MVP for Visual C# // // @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/ | ||||||||
|
投稿日時: 2005-06-12 22:11
渋木宏明(ひどり) 様
度々、ご返答有難うございます。 残念ながらActiveXDLLは提供されているものなので手が出せません。 初心者には難しいという感じでお手上げ状態です。でも、諦めているわけではないので・・・。 全然的外れな事をしているのかも知れませんが、今は次のような事から対処できないか悩んでいる最中です。 1. 元々提供されているタイプライブラリ(?)A.tlbをtlbimpでA.dll(アセンブリ?)を作成する 2. ildasmでMSIL(何の意味かは知らないです)を作成する。 3. 上記のMSILのどこかを編集し、dll化する。 MSILファイルを除いてみると、 .method public hidebysig newslot virtual instance int32 GetArrayData(int32 xxxx, int32 xxxx, int32 xxxx, int32 xxxx, object marshal( struct) Array,<--問題の部分です int32 xxxx) runtime managed preservesig internalcall { .custom instance void [mscorlib]System.Runtime.InteropServices.DispIdAttribute::.ctor(int32)=( 01 00 24 00 00 00 00 00 ) .override Interop.XXXX.XXXX::GetArrayData } とありました。 「相互運用機能アセンブリの編集」という項目に書いてあった事なのですが、この方法を用いて対処可能なのでしょうか?それともやはり見当違いの事でしょうか? [ メッセージ編集済み 編集者: ひでと 編集日時 2005-06-12 22:13 ] | ||||||||
|
投稿日時: 2005-06-12 23:48
目の付け所は悪くないです。 が、「そこまでしなくてもどーにかなるかも?」というのが、1個前の投稿の趣旨です。 _________________ // 渋木宏明 (Hiroaki SHIBUKI) // http://hidori.jp/ // Microsoft MVP for Visual C# // // @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/ |