首页 > 解决方案 > 通过 WPF 中的 wndProc 与另一个进程(相同的源代码)通信

问题描述

我正在努力通过HwndSourceWPF 实现与另一个进程的通信。

我希望我的程序(让我们称之为)与Windows 上另一个进程上A的我的程序(也是)进行通信。 下面的图片将帮助我解释我一直在做什么以及我想要实现什么。 A

图像1

两个窗口是完全相同的程序(只是背景颜色不同),并且它们彼此完全知道它们的句柄。如果我注意到两个进程具有相同的标题,那么我调用sendMessageuser32.dllMessage -Raw 输入消息常量中定义的可以全局抽取消息的0x0100WM_KEYDOWN

// if same program - but different process
IntPtr lpData = Marshal.StringToHGlobalAnsi("Hi, Im Sender");
MessageBox.Show(Marshal.PtrToStringAnsi(lpData));
DisplayAnotherProcessHandle.Text = p.MainWindowHandle.ToString();

SendMessage(p.MainWindowHandle, WM_RawInput_key, IntPtr.Zero, lpData);

我成功传给对手程序WM_RawInput_KeyIntPtr.Zero但我对 lParam 有疑问。我无法获取 lParam 数据。我试图c# stringMarshal.StringToBSTRor Marshal.StringToAuto... Marshal ,但在下面的方法中我只是得到Empty.String.

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  if (msg != WM_RawInput_key) return IntPtr.Zero;

  if (wParam == IntPtr.Zero)  // <-- opponent process hit this conditional syntax nicely.
  {
    var str = Marshal.PtrToStringAnsi(lParam);  // but I'm failed pass lParam, or Marshalling lParam I don't know ...
    MessageBox.Show(str);
    DisplaySucceedOrNot.Text = str;
  }

  return IntPtr.Zero;
}

我不知道哪个内存参数IntPtr lParam表示。我什至不知道这种技术是否有效。我需要你的帮助。谢谢你的阅读

以下源代码是我的示例程序的完整源代码。

<Window x:Class="wndProc_IPC_WPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:wndProc_IPC_WPF"
        mc:Ignorable="d"
        Title="WndProc-IPC-WPF" Height="450" Width="800">
    <StackPanel>
        <Button Name="AddHandler" Width="Auto" Height="100" Content="Add Handler to This Handle" Click="AddHandler_Click"></Button>
        <Button Name="CreateNewProcess" Width="Auto" Height="100" Content="Create New Process Window" Click="CreateNewProcess_Click"></Button>
        <Button Width="Auto" Height="100" Content="SendMessage To Another Process" Name="SendMessageBtn" Click="SendMessage_Click"></Button>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="MyHandle : "></TextBlock>
            <TextBlock x:Name="DisplayMyProcessHandle" Margin="50 0 0 0"></TextBlock>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Another Handle : "></TextBlock>
            <TextBlock x:Name="DisplayAnotherProcessHandle" Margin="50 0 0 0"></TextBlock>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Succed?"></TextBlock>
            <TextBlock x:Name="DisplaySucceedOrNot" Margin="50 0 0 0"></TextBlock>
        </StackPanel>

    </StackPanel>
</Window>
public partial class MainWindow : Window
{
    [DllImport("user32.dll")]
    private static extern bool SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

    string AppName;
    public static UInt32 WM_RawInput_key = 0x0100;

    public MainWindow()
    {
        InitializeComponent();
        AppName = this.Title;
    }

    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        if (msg != WM_RawInput_key) return IntPtr.Zero;

        if (wParam == IntPtr.Zero)
        {
            var str = Marshal.PtrToStringAnsi(lParam);
            MessageBox.Show(str);
            DisplaySucceedOrNot.Text = str;
        }

        return IntPtr.Zero;
    }

    private void CreateNewProcess_Click(object sender, RoutedEventArgs e)
    {
        if (Process.GetProcessesByName(AppName).Length > 1)
        {
            MessageBox.Show("Already 2 Process Exist.");
            return;
        }
        var path = (System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
        Process p = new Process();
        p.StartInfo.FileName = path;
        p.Start();
    }

    private void SendMessage_Click(object sender, RoutedEventArgs e)
    {
        foreach (var p in Process.GetProcessesByName(AppName))
        {
            if (p.MainWindowHandle == Process.GetCurrentProcess().MainWindowHandle) continue; 

            {
                IntPtr lpData = Marshal.StringToHGlobalAnsi("Hi, Im Sender");
                MessageBox.Show(Marshal.PtrToStringAnsi(lpData));
                DisplayAnotherProcessHandle.Text = p.MainWindowHandle.ToString();

                SendMessage(p.MainWindowHandle, WM_RawInput_key, IntPtr.Zero, lpData);

            }
        }
    }

    private void AddHandler_Click(object sender, RoutedEventArgs e)
    {
        HwndSource source = HwndSource.FromHwnd(Process.GetCurrentProcess().MainWindowHandle);
        source.AddHook(new HwndSourceHook(WndProc));
    }

}

标签: c#wpfwindows

解决方案


wparam和只是指向您的本地进程内存的lparam指针,其他进程无法访问。在您的wparam示例中效果很好,因为您只处理指针值而不是它指向的数据。

出于类似的目的,我使用了WM_COPYDATA消息,您提供了一个指向COPYDATASTRUCT. 在那里,您还可以封装复杂的数据结构,这些数据结构可以在您的接收过程中以只读方式处理。

微软在这里提供了一个有用的例子: https ://docs.microsoft.com/en-us/windows/win32/dataxchg/using-data-copy


推荐阅读