DOBON.NET DOBON.NETプログラミング掲示板過去ログ

exeどうしの値渡し

環境/言語:[C#(.NET Framework2.0.5)]
分類:[.NET]

C#で、テキストボックスが一つある画面を作成しました。
それを一つのプロジェクトとし、exeにしました。
そのexeをクリックして立ち上げた状態で、
他のプロジェクトの処理のexeをクリックして立ち上げた場合、
このexeから最初の画面のテキストボックスの情報を取得という事は可能なのでしょうか?
(手短に言うと、exe間で値の受け渡しというのは可能なのでしょうか?)
いろいろな方法があるかもしれませんが、
今はテキストボックスに入力したら、ボタンを押させ、それをテキストファイルに書き込み、
そのテキストファイルを他のexeが読むというやり方をしてるのですが、
あまりスマートなやり方とは思っていません。
というよりかこのやり方しか分からないというのが現状です。
何でも良いのでこういうやり方やああいうやり方もあるよ、みたいなアドバイスが頂けたら光栄です。
よろしくお願いします。
■No19691に返信(彩さんの記事)

.NETでは、「リモート処理」を使用するというのが正攻法になるでしょう。一度リモート処理についてお調べになってみてください。

その他には、DDEや、SendMessageを使う方法も考えられますので、リモート処理に問題があれば、検討する価値があるかもしれません。
書き込みありがとうございます。
一応、いろいろとあり、SendMessageを使用する事になりました。
しかし、よく分からずじまいで、一応それなりのものを書いたのですが、
全然動きません。
作成中、勉強中に質問はあつかましいのですが、
現時点でのソースを見て、アドバイス頂けたら光栄です。

--------form1(送る側)--------
private void button1_Click(object sender, EventArgs e)
{
Execute();
}

const int WM_COPYDATA = 0x4a;
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}

[DllImport("user32", EntryPoint = "SendMessage")]
public static extern int SendMessageCds(IntPtr h, uint m, IntPtr wp, ref COPYDATASTRUCT cds);

private void Execute()
{
string test = "テスト";
COPYDATASTRUCT cds = new COPYDATASTRUCT();
cds.lpData = Marshal.StringToHGlobalAuto(test);
cds.cbData = (test.Length + 1) * 2;
SendMessageCds((IntPtr)0x00170608, WM_COPYDATA, Handle, ref cds);
}

--------Form2受け取る側--------
const int WM_COPYDATA = 0x4a;
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}

// 受け取る側
protected override void WndProc(ref Message m)
{
string a = "";
if (m.Msg == WM_COPYDATA)
{

COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(m.LParam,
typeof(COPYDATASTRUCT));
a = Marshal.PtrToStringAuto(cds.lpData, cds.cbData);
}
base.WndProc(ref m);
this.textBox1.Text = a;
}


form1のボタンを押した場合にform2のテキストボックスに表示されるというのをイメージしたのですが、全然反応ありません。
よろしくお願いします。
■No19702に返信(彩さんの記事)

> 一応、いろいろとあり、SendMessageを使用する事になりました。
> しかし、よく分からずじまいで、一応それなりのものを書いたのですが、
> 全然動きません。

「いろいろとあり」にどういった紆余曲折があったのかが気になります。
管理人さんも書かれていますが、リモート処理という正攻法があるわけですけど。
いまどき SendMessage という選択肢もかなり疑問が…
SendMssage を使うなという意味ではないですが、休日のハイキングコースで冬
の富士山に登るようなものと考えてください。

> 作成中、勉強中に質問はあつかましいのですが、
> 現時点でのソースを見て、アドバイス頂けたら光栄です。

とりあえず斜め読みで。

・ WndProc は(WM_COPYDATA 以外の)メッセージがくるたびに呼ばれるから、
   毎回 textBox1.Text を書き換えてたらダメじゃん?
・ PtrToStructure しても、IntPtr が構造体にコピーされるだけじゃん?そこ
   から PtrToStringAuto でコピーなんてできないじゃん?
  (送信側で確保してるメモリは送信側のメモリ空間の中じゃん?)
・ そもそも (IntPtr)0x00170608 なんてやってる時点でダメじゃん?
  (受信側のウィンドウハンドルなんて起動するたびに変わるじゃん?)
・ つーかそれ以前になんで WM_COPYDATA なんて使っちゃうんじゃん?

…総評としては。
SendMessage を使うには、Windows のメッセージ処理について知識不足が多すぎ
る気がします。
(僕もそんなに詳しいわけじゃないですが)

とりあえず管理人さんと一緒で、リモート処理をオススメしておきます。
スミマセン。
アドバイスありがとうございます。
一からリモート処理を勉強します。
一つだけ付け加えさして下さい。
同一のパソコン(PC1台)で、このような事をする場合でもリモート処理というのを
しないといけないのでしょうか?
リモート処理というのが、コンピュータを分散したネットワークでの処理の時に使用するものだと勝手に思い込んでいたので、やめようみたいな感があったのですが、どうでしょうか?
かなり初歩的な質問なのですが、よろしくお願いします。
知識不足ですみません。
> 同一のパソコン(PC1台)で、このような事をする場合でもリモート処理というのを
> しないといけないのでしょうか?
> リモート処理というのが、コンピュータを分散したネットワークでの処理の時に使用するものだと勝手に思い込んでいたので、やめようみたいな感があったのですが、どうでしょうか?

その点は問題ありません。「リモート処理をしないといけない」ということはありませんが、この目的のために.NETで用意されている方法はこの方法ということです。

ちなみに、WM_COPYDATAを使った方法は、vbAcceleratorで紹介されています。

vbAccelerator - Simple Interprocess Communications using WM_COPYDATA
http://www.vbaccelerator.com/home/NET/Code/Libraries/Windows_Messages/Simple_Interprocess_Communication/article.asp
2007/05/21(Mon) 13:58:14 編集(投稿者)

リモート処理というのを、調べて、出来ました。
IpcChannelとIpcServerChannelというのを使用し、exe間の値の受け渡しに成功しました。
ありがとうございました。
後追加で質問したいのですが、
始めにログイン用exe(ユーザ名とパスワードを入力)を立ち上げ、
後から立ち上げたexeが、そのユーザ名とパスワードを見たりするのですが、
例えば、単なるプログラムミスで繋がらなくて、エラーになるのと、
ログイン用exeを立ち上げなくて、
exeが無いから、繋がらなくて、エラーになるのを、判定する事は可能なのでしょうか?
(必要の無い判定といえば、必要無いかもしれませんが・・・)
質問ばかりで申し訳ござませんが、何か良い案がありましたらよろしくお願いします。
----------値をもらう側のプログラム---------------
IpcClientChannel clientChannel = new IpcClientChannel();

ChannelServices.RegisterChannel(clientChannel, true);

RemoteMessage msg = (RemoteMessage)Activator.GetObject(
typeof(RemoteMessage), "ipc://remote/message");

string id = msg.Call();//exeが立ち上がってない場合、あるいは「ipc://remote/message」のパスが間違っていた場合でも、同じエラーRemotingException

MessageBox.Show(id + "を受取ました");

----------ログインフォーム側のプログラム---------------
private void button1_Click(object sender, EventArgs e)
{
IpcServerChannel servChannel = new IpcServerChannel("remote");

ChannelServices.RegisterChannel(servChannel, true);

RemoteMessage msg = new RemoteMessage();
msg.eventCall += new RemoteMessage.CallHandler(msg_eventCall);

RemotingServices.Marshal(msg, "message", typeof(RemoteMessage));
}
----------共通-------------
public class RemoteMessage : MarshalByRefObject
{
public delegate string CallHandler();

public event CallHandler eventCall;

public string Call()
{
return eventCall();
}
}
> 始めにログイン用exe(ユーザ名とパスワードを入力)を立ち上げ、
> 後から立ち上げたexeが、そのユーザ名とパスワードを見たりするのですが、
> 例えば、単なるプログラムミスで繋がらなくて、エラーになるのと、
> ログイン用exeを立ち上げなくて、
> exeが無いから、繋がらなくて、エラーになるのを、判定する事は可能なのでしょうか?

ログイン用exeが起動しているかどうかを調べてみてはいかがでしょうか?そのための方法はいくつか考えられますが、下記のURLを参考にしてみてください。

http://dobon.net/vb/dotnet/process/getprocessesbyname.html

http://dobon.net/vb/dotnet/process/checkprevinstance.html
管理人さん、ありがとうございました。
全て解決しました。
本当にありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板