QA@IT
この質問・回答は、@ITの旧掲示板からインポートされたものです。

C# .Net SendMessageで他のアプリに文言を送信したい

はじめまして。Netなどで調べたのですが、解決方法が見つからないため、
こちらのお力を借りたいと思います。

いま、A.exeからB.exeへメッセージを送信することを考えています。
C++でしたら、
送信元(A.exe)
HWND hWnd = 0;
char msg[256];
strcpy(msg,"hello");
COPYDATASTRUCT cds;
cds.dwData = 1;
cds.cbData = strlen(msg) + 1;
cds.lpData = (LPVOID)msg;
hWnd = ::FindWindow(NULL,"B");
if(hWnd != 0){
::SendMessage(hWnd,WM_COPYDATA, 0, (LPARAM)&cds);
}
受信側(B.exe) WindowProc内
COPYDATASTRUCT pdat = (COPYDATASTRUCT)lParam;
m_edit = (char*)pdat->lpData;

で受信側で「hello」と受け取ることができます。
しかし、C#で記述に変換しようと試みたのですが・・・・
送信元(A.exe)
[DllImport("USER32.dll")]
private static extern IntPtr SendMessage (IntPtr hWnd , int msg , IntPtr wp, IntPtr lp);

struct COPYDATASTRUCT
{
public long dwData;
public long cbData;
public string lpData;
}

private void button1_Click(object sender, System.EventArgs e)
{
int hWnd = 0;
COPYDATASTRUCT st = new COPYDATASTRUCT();

string msg = "hello";

st.dwData = 0;
st.cbData = msg.Length+1;
st.lpData = msg;

hWnd = FindWindow(null,"B");
if(hWnd != 0)
{
    IntPtr lparam;
    lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(st));
    SendMessage((System.IntPtr)hWnd, 0x004A, this.Handle, lparam);
}

}
受信側(B.exe)
struct COPYDATASTRUCT
{
public long dwData;
public long cbData;
public string lpData;
}
protected override void WndProc(ref Message m)
{
// Listen for operating system messages.
if(m.Msg == 0x004A)
{
COPYDATASTRUCT st = new COPYDATASTRUCT();
st = (COPYDATASTRUCT)m.GetLParam(typeof(COPYDATASTRUCT));

    textBox1.Text = st.lpData;
}
base.WndProc(ref m);

}

とすると、「U駆d。」こんな文字化けしたものが送信されてしまいます。
何か足りない処理や、間違った処理などがあるのでしょうか。

お知恵を貸して頂けませんでしょうか。

質問者:もも

回答

Marshal.AllocCoTaskMem/AllocHGlobalは、文字通りメモリを確保するメソッドです。
勝手に構造体の中身をコピーしたりする機能はありません。
構造体インスタンスを確保したメモリ領域にコピーするにはMarshal.StructureToPtrメソッドを使用します。
またAllocした領域をFreeCoTaskMem/FreeHGlobalするのを忘れないで下さい。リークします。

追記:
実は、SendMessageの宣言を
static extern uint SendMessage(IntPtr window, int msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
のようにしてやるとMarshalクラスの出番が無くなったりします。
[ メッセージ編集済み 編集者: Hongliang 編集日時 2005-07-25 12:40 ]

投稿者:Hongliang

編集 履歴 (0)

Hongliangさんありがとうございます。
コピーする機能はないんですね・・・・。勉強になります。
早速、追記の宣言で動作を確認させてもらいました。

Marshalの出番をなくすことができました〜〜
しかし、受信側では、相変わらず、文字化けしてしまっています。

投稿者:もも

編集 履歴 (0)

手元ではできるのになー、と思って改めてももさんのコードをチェックしてみました。

で、はたと気付きました。
COPYDATASTRUCTUREの定義ですね。
MSDNのをそのままコピーしますが、


typedef struct tagCOPYDATASTRUCT { 
    ULONG_PTR dwData; 
    DWORD     cbData; 
    PVOID     lpData; 
} COPYDATASTRUCT, *PCOPYDATASTRUCT; 

まず、DWORDは32ビット値です。.NETならUInt32(Int32)に相当しますね。
またULONG_PTRはプラットフォーム依存のポインタ、つまり32bitOSなら32ビットですから、こちらはIntPtrで宣言すべきでしょう。

投稿者:Hongliang

編集 履歴 (0)

Hongliangさんありがとうございます。
構造体の宣言を
struct COPYDATASTRUCT
{
public IntPtr dwData;
public UInt32 cbData;
public string lpData;
}
と変えたところ・・・・
文字を送信することができました〜〜〜〜〜〜〜!!
丁寧に教えて頂きありがとうございました。

投稿者:もも

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。