使用User32.dll SendMessage将字符串发送到另一个Windows窗体应用程序

时间:2013-01-12 14:50:44

标签: c# winforms com-interop sendmessage

我有一个奇怪的问题。

我正在使用SendMessage将字符串发送到同一Windows窗体应用程序的所有正在运行的实例。

我可以成功发送IntPtr指针的数值的字符串表示,如下所示:

 unsafe private void SendString(IntPtr handle, IntPtr myHandle)
    {
        string s = handle.ToString(); // This will work and the value will be received.
                                      // Try with "123553" which wont work.
                                      // How can that be?
        IntPtr lpData = Marshal.StringToHGlobalUni(s);

        COPYDATASTRUCT data = new COPYDATASTRUCT();
        data.dwData = 0;
        data.cbData = s.Length * 2;
        data.lpData = lpData;

        IntPtr lpStruct = Marshal.AllocHGlobal(
            Marshal.SizeOf(data));

        Marshal.StructureToPtr(data, lpStruct, false);

        int hTarget;
        var succes = Int32.TryParse(s, out hTarget);

        if (succes)
            SendMessage(hTarget, WM_COPYDATA, handle, lpStruct);
    }

接收应用程序正确输出类似'123553'的值。

但是,如果我手动为s分配值,则不会收到任何内容:

 string s = "123553";

有没有人知道为什么在IntPtr上调用ToString并且硬编码该值不会产生相同的行为?

自己运行应用程序的代码在这里:

    public const int WM_COPYDATA = 0x004a;

    [StructLayout(LayoutKind.Sequential)]
    public struct COPYDATASTRUCT
    {
        [MarshalAs(UnmanagedType.I4)]
        public int dwData;
        [MarshalAs(UnmanagedType.I4)]
        public int cbData;
        [MarshalAs(UnmanagedType.SysInt)]
        public IntPtr lpData;
    }

    [DllImport("User32.dll")]
    private static extern bool SendMessage(int hWnd,
        int wMsg, IntPtr wParam, IntPtr lParam);

    public Form1()
    {
        InitializeComponent();
    }

    unsafe protected override void WndProc(ref Message message)
    {
        if (message.Msg == WM_COPYDATA)
        {
            COPYDATASTRUCT data = (COPYDATASTRUCT)
                message.GetLParam(typeof(COPYDATASTRUCT));

            string str = new string((char*)(data.lpData),
                0, data.cbData / 2);

            Debug.WriteLine(str);
        }
        base.WndProc(ref message);
    }

    unsafe private void SendString(IntPtr handle, IntPtr myHandle)
    {
        string s = handle.ToString();
        IntPtr lpData = Marshal.StringToHGlobalUni(s);

        COPYDATASTRUCT data = new COPYDATASTRUCT();
        data.dwData = 0;
        data.cbData = s.Length * 2;
        data.lpData = lpData;

        IntPtr lpStruct = Marshal.AllocHGlobal(
            Marshal.SizeOf(data));

        Marshal.StructureToPtr(data, lpStruct, false);

        int hTarget;
        var succes = Int32.TryParse(s, out hTarget);

        if (succes)
            SendMessage(hTarget, WM_COPYDATA, handle, lpStruct);
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Process currentProcess = Process.GetCurrentProcess();

        var handles = (from process in Process.GetProcesses()
                       where
                         process.Id != currentProcess.Id &&
                         process.ProcessName.Equals(
                           currentProcess.ProcessName,
                           StringComparison.Ordinal)
                       select process.MainWindowHandle).ToList<IntPtr>();

        foreach (var handle in handles)
        {
            SendString(handle, this.Handle);
            Debug.WriteLine(string.Format("Sending handle {0} from handle {1}", handle, this.Handle));
        }
    }

来源:

Detecting if another instance of the application is already running

Using WM_COPYDATA for interprocess communication (VFP9)

0 个答案:

没有答案