- PR -

DLL同士の通信

投稿者投稿内容
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-02 21:16
お世話になります。
優希です。

DLL同士の通信について、質問があります。
開発環境は、Visual Studio .NET(VC++)、Windowsフォームを使って行います。


まず、
親画面上に、PictureBox1, PictureBox2を2つ作成し、
そのPictureBoxのそれぞれで非同期呼び出し(BeginInvoke()使用)で、
DLLをコールし、子画面を作成します。

※下記のソースはかなり端折ってありますので、
   コンパイルが通るかわかりません (^^; )
   その点は、ご勘弁ください。m(_ _)m



コード:
	/// 
	/// 親画面の生成
	/// 
	public __gc class ParentForm: public Form
	{
	public:

		// 子画面生成用デリゲート
		__delegate void MakeChildHandler(String *strDllName, 
                                           PictureBox *picChild);

		// コンストラクタ
		ParentForm()
		{
			// Form生成
			this->Location = Point(0, 0);
			this->Size = Drawing::Size(1280, 1024);

			// 子画面ウィンドウ1の表示用PictureBox
			PictureBox *picBack_1 = new PictureBox();		
			picBack_1->Location = Point(10, 10);
			picBack_1->Size = Drawing::Size(500, 500);
			this->Controls->Add(picBack_1);
			// 子画面1生成
			Object *param[] = new Object*[2];
			param[0] = S".\\Child1.dll";		// DLL名称
			param[1] = picBack_1;				// 子画面を追加するPictureBox
			picBack_1->BeginInvoke(new MakeChildHandler(picBack_1, MakeChildForm), param);

			// 子画面ウィンドウ2の表示用PictureBox
			PictureBox *picBack_2 = new PictureBox();		
			picBack_2->Location = Point(510, 10);
			picBack_2->Size = Drawing::Size(500, 500);
			this->Controls->Add(picBack_2);
			// 子画面2生成
			param[0] = S".\\Child2.dll";		// DLL名称
			param[1] = picBack_2;				// 子画面を追加するPictureBox
			picBack_2->BeginInvoke(new MakeChildHandler(picBack_2, MakeChildForm), param);
		};

		// 子画面表示
		void MakeChildForm(String *strDllName, PictureBox *picChild)
		{
			// アセンブリの読み込み
			Assembly *asmb = Assembly::LoadFrom(strDllName);

			// インスタンスの生成
			IWrapDll *wrapInst = dynamic_cast<IWrapDll*>(asmb->CreateInstance(S"ChildForm"));

			if(wrapInst != 0){
				wrapInst->DisplayWindow(picChild);
			}
		};
	};




そして、
子画面上には、TextBoxを作成します。


コード:
	/// 
	/// 子画面1の作成
	/// 
	public __gc class ChildForm
	{
	public:
		// 変数
		TextBox *textBox1;

		// 子画面1の生成
		void DisplayWindow(PictureBox *picBase)
		{
			// テキストボックス1の追加
			textBox1 = new TextBox();
			textBox1->Location = Point(20, 20);
			textBox1->Size = Drawing::Size(50, 25);
			picBase->Controls->Add(textBox1);
		};

		// テキストボックス1の内容を取得
		String *GetData()
		{
			return textBox1->Text;
		};
	};




そこで、
子画面2から子画面1中のTextBox1のTextを取得しようと思い、
以下のようにコーディングしました。

コード:
	/// 
	/// 子画面2の作成
	/// 
	public __gc class ChildForm
	{
	public:
		// テキストボックス2
		TextBox *textBox2;

		// 子画面2の生成
		void DisplayWindow(PictureBox *picBase)
		{
			// テキストボックス2の追加
			textBox2 = new TextBox();
			textBox2->Location = Point(20, 20);
			textBox2->Size = Drawing::Size(50, 25);
			picBase->Controls->Add(textBox2);

			// タイマー処理で子画面1のテキストボックスの
			// 内容を取得する
			sTimer = new Timers::Timer(5000);
			sTimer->Elapsed += new Timers::ElapsedEventHandler(picBase, sTimer_TimerEvent);
			sTimer->Enabled = true;
		};

		// タイマー処理
		void sTimer_TimerEvent(Object* sender, Timers::ElapsedEventArgs* e)
		{
			// アセンブリの読み込み
			Assembly *asmb = Assembly::LoadFrom(S".\\Child1.dll");

			// インスタンスの生成
			IWrapDll *wrapInst = dynamic_cast<IWrapDll*>(asmb->CreateInstance(S"ChildForm"));

			if(wrapInst != 0){
				String *strTextContent = wrapInst->GetData();	// TextBox1の内容を取得
				if(strTextContent != 0){
					// テキストボックス1の内容を表示
					textBox2->Text = strTextContent;
				}
			}
		};
	};



ところが、変数strTextContentはNULLになってしまい、
うまく取得することが出来ませんでした。

これは非同期呼び出しで行なっているからなのでしょうか?
変数strTextContentがNULLにならずに、
内容がきちんと取れる方法があれば、アドバイスをお願い致します。

以上、宜しくお願い致します。

Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-02-03 06:26
 DLLをロードしてしても、それは実行中のモノと違いますから・・・

 親画面に中継させるのが一番簡単ですが、DLL同士が直接通信しなければなりませんか?
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-03 06:53
ご回答、ありがとう御座います。

そうですねぇ、
DLL同士で直接通信させたいと思っています。
これは、可能なのでしょうか?

DLL同士で直接通信させる方法や、
親画面に中継させるの方法がありましたら、
具体的な実装方法をお聞かせください。

宜しくお願い致します。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-02-03 08:30
 中継させるなら、「発信」をイベントやデリゲートで通知します。「受信」はメソッド呼び出し。親画面は作成した子画面を“知っている”はずですから、そのインスタンスを使用します。

 直接なら、「メッセージ」かな?インスタンスに直接送るorキューがたまったことをイベントのように知ることができるのかどうか、調べていないのでわかりませんが、キューを定期的に見に行くなどで対応できるでしょう。MSDNで、「フィルタ」を「.NET Framework」にし、「メッセージ」または「メッセージ キュー」でキーワード検索してみてください。「メッセージボックス」は違いますから、注意してください。


 具体的…コード例ですか?私としては、コードまで示してしまうとそこで「知る」が停まってしまうと思うので、「これを使えばできるから後は調べてね」で止めたいのですが・・・
#興味はあるので、時間があれば作るかも、ということで。。。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-03 09:00
アドバイス、ありがとうございます。

早速、調べて作成して見たいと思います。
また何かありましたら、宜しくお願い致します。
優希
ベテラン
会議室デビュー日: 2003/08/12
投稿数: 92
投稿日時: 2004-02-03 16:00
「メッセージキュー」で検索した結果、
"MSMQ"というAPIが見つかりました。

これって、ソフトをインストールしないと、
使えないものなのでしょうか?


試しに、送信プログラムを作成してみましたが、
マシン上にキューが存在していないように見えます。
([マイコンピュータの管理]-[サービスとアプリケーション]で
 [Message Queuing]という項目が無い為)

コード:
	///
	/// メッセージキューの送信プログラム
	///

	// メッセージキュー
	String *strQue = S".\\private$\\Orders";
	// テキスト メッセージを準備する
	String *msgText;
	msgText = String::Format(S"Sample Message Sent At {0}", DateTime::Now.ToString());

	MessageQueue *msgQ;

	// メッセージキューの存在チェック
	if(!MessageQueue::Exists(strQue)){		// 存在しない場合
		try{
			msgQ = MessageQueue::Create(strQue);
		}catch(Exception *e){
			// コードにキューを作成するための十分な権限がなければ
			// キューの作成時にエラーが発生する可能性がある
			throw new Exception(S"Error Creating Queue", e);
		}
	}else{									// 存在していた場合
		try{
			msgQ = new MessageQueue(strQue);
		}catch(Exception *e){
			throw new Exception(S"Error Getting Queue", e);
		}
	}

	// メッセージ送信
	msgQ->Send(msgText, S"Sample Test");


おばけ
ぬし
会議室デビュー日: 2002/11/14
投稿数: 609
お住まい・勤務地: 東京都江東区
投稿日時: 2004-02-03 16:10
私は.NETもWindowsアプリ開発も全然ですが、MSMQというのはMSが出しているメッセージキューの
ミドルウェアだと思います。この製品を入れないと件のAPIは機能しないでしょう。
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2004-02-03 16:50
 System.Messaging.dll を参照するようにして、System.Messaging 名前空間をインポート(C++はusingだっけ?)すれば、使えませんか?

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