- PR -

DLL同士の通信

投稿者投稿内容
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-05 19:16
Jittaさんが作られたサンプル、拝見しました。
有難う御座います!


ちょっと気になることがありまして。。。

Jittaさんが作られたサンプルで、
Form1     (親)
Class1Form1  (子)
Class2Form1  (子)
の3つのFormがあります。
(起動できなかったので、 ソースを見て話しております。
 違っていたらご勘弁を・・・。)


Form1からは、子のクラス名称が分かっているので、
Form1(親)でClass1Form1のインスタンスが
生成できてダイレクト(?)に反映可能、、、と見て宜しいですか?
(ちょっと表現が難しいですが・・・(^^;))

いまさらで申し訳ないのですが、
もう少し詳しくいいますと、
"作成上"、親画面と子画面は干渉したくない(?)
(子画面を修正しても、親画面は修正したくはない)
という場合、子の情報について、
----------------------------
DLL名称   ⇒ 任意な名称
クラス名称  ⇒ 任意な名称
メソッド名称 ⇒ 固定の名称
----------------------------

とすると、
DLL名称とクラス名称はファイルから読み込んで、
可変的に(固定ではなく)作成するようになると思います


ソースで書くと、こんな↓感じです。
コード:

///
/// 子画面を表示する関数
/// String *strDllName   DLL名称
/// String *strClassName クラス名称
///
void MakeChildForm(String *strDllName, String *strClassName)
{
// アセンブリの読み込み
Assembly *asmb = Assembly::LoadFrom(strDllName);
// インスタンスの生成
IWrapDll *wrapInst = dynamic_cast<IWrapDll*>(asmb->CreateInstance(strClassName));

if(wrapInst != 0){
wrapInst->DisplayWindow(); // 該当する子画面の生成
}
};



つまり、親と子はお互いに見えない作りになります。
【親画面】−【ラッパーDLL】−【子画面1】
               −【子画面2】

この方式ですと、
ダイレクト(?)では、難しいのかなって思います。。。
違っていたら、すいません。




・・・・・・で、、、
長くなりましたが、本題です(^^;)


このスレッドのnoderaさんの記述(投稿日時: 2004-02-04 18:12)を
よ〜〜〜く読んでみると、
一番最初に自分が試していたやり方に似ている感じがします。

引用:

ということは、
ここでそれぞれのDLLが一番簡単な方法で通信する手段は、
(通信というにはおかしいけど)IWrapDllインターフェイスに、
それぞれがデータ交換するためのメソッド定義し、
各DLLはそのインターフェイスを実装します。


単純に関数呼び出すだけです・・・・



一番、最初に書いたソースでは、
TextBox2のあるDLLからタイマーイベント処理で、
TextBox1のあるDLLへ値を取りに行っている(ように書いたつもりです)。

で、逆に、
TextBox1で変更があった場合に
TextBox2のあるDLLへ値を送信する、というやり方も
試してみました。
(みなさんにいろんな方法を聞いておいて、
 申し訳ないですが、すごーく気になったので・・・)


実際には、ひとつのTextBoxだけではないので、
構造体で値を持っておいて、
ArrayList型で渡そうと思っています。


↓送信側です。

コード:

///
/// DLL1(TextBox1のあるDLL)のデータを送信する関数
/// String *strDllName 送信先DLL名称
/// String *strClassName 送信先クラス名称
///
void OwnDataSendMethod(String *strDllName, String *strClsName){

SendDataTbl param; // 構造体
ArrayList *lstSendData = new ArrayList(); // リスト格納用

// データ格納(仮に3つ)
param.str1 = TextBox1->Text; // String型
param.str2 = Label1->Text; // String型
param.str3 = strVersion; // String型

// 設定
Object* ptrPrm = __box(param); // Object型にボックス化
lstSendData->Add(ptrPrm); // ArrayListに設定


// DLLの存在確認(ソースは省きます)
// クラス名称のチェック(ソースは省きます)

// アセンブリの読み込み
Assembly *asmb = Assembly::LoadFrom(strDllName);
// インスタンスの生成
IWrapDll *wrapInst = dynamic_cast<IWrapDll*>(asmb->CreateInstance(strClsName));

if(wrapInst != 0){
wrapInst->ReceiveData(lstSendData); // データ送信?
}
}





↓受信側です。

コード:

///
/// DLL1(TextBox1のあるDLL)のデータを受信する関数
/// ArrayList *DataTbl データ
///
void ReceiveData(ArrayList *DataTbl){

if(DataTbl != 0){
try{
// ボックス化解除
SendDataTbl pData =
*__try_cast<__box SendDataTbl*>(DataTbl->get_Item(0));
// TextBox1のテキストを表示
TextBox2->Text = pData.str1;
}catch(InvalidCastException *e)
{
MessageBox::Show(String::Concat(S"Error: Incorrect unboxing.", e));
}
}
}




ReceiveData(ArrayList *DataTbl)関数でデータを受信し、
"DataTbl"には、データが入っております。

ですが、[ボックス化解除]の部分で、
引用:

指定されたキャストは有効ではありません


となります。

この方法でいけるのかなーと思っていたのですが、
ボックス化の解除の仕方が悪いのか、
送り方が悪いのか、そもそも出来ないのか、
アドバイスを頂きたいのですが・・・。

# "DataTbl"には、データが受信できたので、
# できないこともないと思うのですが・・・


長くなってすいません。


[ メッセージ編集済み 編集者: 優希 編集日時 2004-02-05 19:30 ]
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-02-05 20:33
引用:

優希さんの書き込み (2004-02-05 19:16) より:



> (起動できなかったので、 ソースを見て話しております。
>  違っていたらご勘弁を・・・。)
 インストールし直して、まだウイルススキャンを入れていないPCからなので、実行形式ははずしました。ソリューションを読み込んでコンパイルすればいけると思ったのですが、だめでした?


> Form1からは、子のクラス名称が分かっているので、
> Form1(親)でClass1Form1のインスタンスが
> 生成できてダイレクト(?)に反映可能、、、と見て宜しいですか?
 はい、わかっていることを前提にしました。


> "作成上"、親画面と子画面は干渉したくない(?)
> (子画面を修正しても、親画面は修正したくはない)

 なるほど。IWrapDllインタフェースというのがMSDN上で見つからないのですが、これは自作インタフェースでしょうか。自作インタフェースとして話を進めます。

 この自作インタフェースを、独立したプロジェクトで定義します。そして、このプロジェクトを、ソリューション中の全プロジェクトに参照させます。インタフェースにイベントを定義します。
コード:
// デリゲートと引数の宣言は省略
public interface IWrapDll
{
	event ChangeEventHandler Change; /// イベント定義
	System.Windows.Forms.Form CreateForm(); // 自分をつくらせるMethod
	void ReceiveData(string RecievedString); // 受けもついでに
// これもいる? void OnChange(string EventArgument);
// publicになるから、とりあえずコメントアウト
}



 子フォームに、このインタフェースを実装させれば、子フォームの「送信」を、親フォームがイベントとして受けられます。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-05 22:46
優希です。

引用:

引用:

起動できなかったので、 ソースを見て話しております。
違っていたらご勘弁を・・・。)


 インストールし直して、まだウイルススキャンを入れていないPCからなので、実行形式ははずしました。ソリューションを読み込んでコンパイルすればいけると思ったのですが、だめでした?


えぇ、ソリューションをダブルクリックして起動しようとしたら、
起動できない(?)って言われました(^^;)


引用:

 なるほど。IWrapDllインタフェースというのがMSDN上で見つからないのですが、これは自作インタフェースでしょうか。自作インタフェースとして話を進めます。


そうです、自作のインタフェースです。

Jittaさんのソースのように、
Stringで渡さないとできないのでしょうかねぇ!?

構造体をArrayListに格納して、(←送信側)
それをBox化解除して(←受信側)
・・・なんて、無理なんでしょうか〜〜 (^^;)
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-02-06 06:27
引用:

優希さんの書き込み (2004-02-05 22:46) より:

えぇ、ソリューションをダブルクリックして起動しようとしたら、
起動できない(?)って言われました(^^;)


 Togetherがじゃましたかな?
追記:作ったのと別の環境で読み込めましたから、Togetherがじゃましたっぽいです。


引用:

構造体をArrayListに格納して、(←送信側)
それをBox化解除して(←受信側)
・・・なんて、無理なんでしょうか〜〜 (^^;)


 面倒だったのでstringにしましたが、型がわかっていればArrayListでも同じだと思いますけど?

[ メッセージ編集済み 編集者: Jitta 編集日時 2004-02-06 08:25 ]
Hirashige
常連さん
会議室デビュー日: 2002/10/26
投稿数: 29
投稿日時: 2004-02-06 08:35
引用:

りばぁさんの書き込み (2004-02-05 09:46) より:

あと、Windowsフォームアプリってメッセージ扱えないのですか??
もしそうなら、なんて面倒な…
マウスクリックやらなにやらのメッセージも自分で処理できないのですか?
例えばMFCであればPreTranslateMessageあたりでいくらでもメッセージを
処理できるのに。



IMessageFilter の PreFilterMessage( ref System.Windows.Forms.Message m )
が MFCのPreTranslateMessage のように使える様です。

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=3828&forum=7
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-06 09:43
どうも、優希です。

引用:


Jittaさんの書き込み (2004-02-06 06:27) より:

引用:

構造体をArrayListに格納して、(←送信側)
それをBox化解除して(←受信側)
・・・なんて、無理なんでしょうか〜〜 (^^;)


面倒だったのでstringにしましたが、型がわかっていればArrayListでも同じだと思いますけど?



うーん、そうなんですけど。。。

ちなみに、
送信側↓でBOX化したあとに、
すぐにBOX化解除してメッセージボックスに出したら、
きちんと表示されたんですよねぇ(^^;)

引用:

SendDataTbl param;             // 構造体
ArrayList *lstSendData = new ArrayList(); // リスト格納用

// データ格納(仮に3つ)
param.str1 = TextBox1->Text; // String型
param.str2 = Label1->Text; // String型
param.str3 = strVersion; // String型

// 設定
Object* ptrPrm = __box(param); // Object型にボックス化
lstSendData->Add(ptrPrm); // ArrayListに設定

// ◆◆試しに追加◆◆
SendDataTbl recieveData =
*dynamic_cast<__box SendDataTbl*>(lstSendData->get_Item(0));
MessageBox::Show(recieveData.str1);





もうひとつ。
自分の書き込んだ(投稿日時: 2004-02-05 19:16 )
受信側ソースで、

コード:
// ボックス化解除
SendDataTbl pData = 
	*__try_cast<__box SendDataTbl*>(DataTbl->get_Item(0));


となっているところを、

コード:
// ボックス化解除
SendDataTbl pData = 
	*dynamic_cast<__box SendDataTbl*>(DataTbl->get_Item(0));



とキャストの仕方を変えてみたのですが、

引用:

オブジェクト参照がオブジェクトインスタンスに設定されていません。


とエラーになってしまいます。
"DataTbl->get_Item(0)"には、データが入っているんですけど。

うーん、ますます訳が分からなくなってしまった。。。



Microsoft Visual Studio .NETのヘルプで、
【C++: マネージ拡張の仕様 5.2.3 ボックス化解除】
ってあって、そこを参考にしてみたんですけど、、、
うまくボックス化解除がされなかったのでしょうか?
C#だと簡単にできそうなんですけどね。

優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-06 10:21
どーも。
またまた優希です。

以下のサイトで、ボックス化解除の
条件が載っていました。

【MSDN ボックス化解除】

引用:

実行時に、指定された値型へのボックス化解除が成功するためには、その値型の値のボックス化によって以前に作成されたオブジェクトへの参照をソース引数として指定する必要があります。



・・・ってことは、
引数で渡したら、解除不可能・・・ってことでしょうか!?(^^;)

ゆうじゅん
ぬし
会議室デビュー日: 2004/01/16
投稿数: 347
投稿日時: 2004-02-06 10:39
引用:

・・・ってことは、
引数で渡したら、解除不可能・・・ってことでしょうか!?(^^;)



引数を参照渡しにすればいいのではないでしょうか?

wrapInst->ReceiveData(lstSendData); // データ送信?

wrapInst->ReceiveData(*lstSendData); // データ送信?

void ReceiveData(ArrayList *DataTbl){

void ReceiveData(ArrayList &DataTbl){

これでうごきませんか?

スキルアップ/キャリアアップ(JOB@IT)