c# - 通过 WPF 中的 wndProc 与另一个进程(相同的源代码)通信
问题描述
我正在努力通过HwndSource
WPF 实现与另一个进程的通信。
我希望我的程序(让我们称之为)与Windows 上另一个进程上A
的我的程序(也是)进行通信。
下面的图片将帮助我解释我一直在做什么以及我想要实现什么。 A
两个窗口是完全相同的程序(只是背景颜色不同),并且它们彼此完全知道它们的句柄。如果我注意到两个进程具有相同的标题,那么我调用sendMessage
在user32.dll
Message -Raw 输入消息常量中定义的可以全局抽取消息的0x0100
WM_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_Key
。IntPtr.Zero
但我对 lParam 有疑问。我无法获取 lParam 数据。我试图c# string
用Marshal.StringToBSTR
or 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));
}
}
解决方案
wparam
和只是指向您的本地进程内存的lparam
指针,其他进程无法访问。在您的wparam
示例中效果很好,因为您只处理指针值而不是它指向的数据。
出于类似的目的,我使用了WM_COPYDATA
消息,您提供了一个指向COPYDATASTRUCT
. 在那里,您还可以封装复杂的数据结构,这些数据结构可以在您的接收过程中以只读方式处理。
微软在这里提供了一个有用的例子: https ://docs.microsoft.com/en-us/windows/win32/dataxchg/using-data-copy
推荐阅读
- c# - 如何使用 Excel 技术自动填充 DataTable 的下一行?
- c# - 为什么 StructureMap 容器不返回控件然后调用 GetInstance?
- scala - 什么是兼容的使用 Amazon Deequ 的所有依赖项
- bash - bash 函数执行 php 但随后暂停/bash 函数卡住
- javascript - 未发送响应即可解析 API(Next JS with Sendinblue)
- reactjs - Tailwind Css 自定义颜色在构建时消失(React JS)
- python - 无法在 opencv 烧瓶应用程序中显示多个流
- fancybox - 为什么官方的 FancyBox 4 绑定示例不起作用?
- spring-boot - 在 SpringBoot 中使用 liquibase 和 H2 数据库进行单元测试
- c# - 如何使用 Keyvault 将 asp.net 5 API 连接到存储在 Azure 中的数据库