C#使用SendMessage进行进程间通讯

sendmessage · 浏览次数 : 80

小编点评

这段代码主要包含一个WPF应用程序(App)和一个Windows辅助工具类(Win32Helper),用于实现拖动文件到桌面图标时自动打开文件的功能。具体来说,它包括以下内容: 1. **App类**: * `App()`:类的构造函数,在程序启动时执行。 * `OnStartup(StartupEventArgs e)`:覆盖父类`Application`的`OnStartup`方法。这里获取启动参数,并检查是否有传递给程序的文件路径。 * 使用`Mutex`来确保只有一个实例在运行,避免并发问题。 * 判断当前实例是否由其他实例创建,如果是,则结束当前实例。 2. **Win32Helper类**: * `SetForegroundWindow(IntPtr hWnd)`:将指定窗口置于前台。 * `SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam)`:向指定窗口发送自定义消息。 * `SendMessageString(IntPtr hWnd, string message)`:发送字符串消息到指定窗口。 3. **MainWindow类**: * `MainWindow()`:类的构造函数,在窗口初始化时执行。 * `OnSourceInitialized(EventArgs e)`:覆盖窗体的`OnSourceInitialized`方法。在这里,我们将`WndProc`作为窗口处理程序添加到`HwndSource`,以便接收并处理发送来的消息。 工作流程如下: 1. 当程序启动时,`App`类的`OnStartup`方法被调用。 2. 在`OnStartup`方法中,获取启动参数(如果有的话),并检查是否有传递给程序的文件路径。 3. 如果存在文件路径,使用`Mutex`确保只有一个实例在运行。 4. 如果这是第一个实例,显示该窗口并进入主循环。否则,结束当前实例。 5. 在任何情况下,都将`WndProc`添加到`HwndSource`,以便接收并处理发送来的消息。 6. 当收到`WM_COPYDATA`消息时,从`COPYDATASTRUCT`中解析消息内容。 7. 在`MainWindow`的`WndProc`方法中处理接收到的消息,例如显示在控制台上或执行业务逻辑。 8. 标记消息已处理并返回`IntPtr.Zero`。 这样,当用户将文件拖到桌面图标时,程序会检测到该操作并在控制台上显示接收到的文件路径。然后,可以根据需要处理该文件(如打开它)。

正文

最近公司有个需求是,拖动文件到桌面图标上,自动打开文件。那么只需在OnStartup事件中通过StartupEventArgs获取文件名然后进行操作即可。操作之后发现当软件已经启动了(单例运行),那么将无法将参数传给业务层。原因是因为跨进程了,那么我们可以通过窗口句柄的方式来进行通讯。

 1  public partial class App : Application
 2  {
 3      private static Mutex AppMutex;
 4      public App()
 5      {
 6 
 7      }
 8 
 9      protected override void OnStartup(StartupEventArgs e)
10      {
11          //获取启动参数
12          var param = string.Empty;
13          if (e.Args.Length > 0)
14          {
15              param = e.Args[0].ToString();
16          }
17 
18          //WpfApp8 = 你的项目名称
19          AppMutex = new Mutex(true, "WpfApp8", out var createdNew);
20 
21          if (!createdNew)
22          {
23              var current = Process.GetCurrentProcess();
24 
25              foreach (var process in Process.GetProcessesByName(current.ProcessName))
26              {
27                  if (process.Id != current.Id)
28                  { 
29                      Win32Helper.SetForegroundWindow(process.MainWindowHandle);
30                      Win32Helper.SendMessageString(process.MainWindowHandle, param);
31                      break;
32                  }
33              }
34              Environment.Exit(0);
35          }
36          else
37          {
38              base.OnStartup(e);
39          }
40      }
41  }
 1  public class Win32Helper
 2  {
 3      [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
 4      public static extern bool SetForegroundWindow(IntPtr hWnd);
 5 
 6      /// <summary>
 7      /// 发送消息
 8      /// </summary>
 9      /// <param name="hWnd"></param>
10      /// <param name="Msg"></param>
11      /// <param name="wParam"></param>
12      /// <param name="lParam"></param>
13      /// <returns></returns>
14      [DllImport("user32.dll")]
15      public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
16 
17      // 声明常量
18      public const int WM_COPYDATA = 0x004A; 
19 
20      // 定义 COPYDATASTRUCT 结构
21      [StructLayout(LayoutKind.Sequential)]
22      public struct COPYDATASTRUCT
23      {
24          public IntPtr dwData;
25          public int cbData;
26          public IntPtr lpData;
27      }
28 
29      /// <summary>
30      /// 发送字符串消息
31      /// </summary>
32      /// <param name="hWnd"></param>
33      /// <param name="message"></param>
34      public static void SendMessageString(IntPtr hWnd, string message)
35      {
36          if (string.IsNullOrEmpty(message)) return;
37 
38          byte[] messageBytes = Encoding.Unicode.GetBytes(message + '\0'); // 添加终止符
39 
40          COPYDATASTRUCT cds = new COPYDATASTRUCT();
41          cds.dwData = IntPtr.Zero;
42          cds.cbData = messageBytes.Length;
43          cds.lpData = Marshal.AllocHGlobal(cds.cbData);
44          Marshal.Copy(messageBytes, 0, cds.lpData, cds.cbData);
45          try
46          {
47              SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ref cds);
48          }
49          finally
50          {
51              //释放分配的内存,即使发生异常也不会泄漏资源
52              Marshal.FreeHGlobal(cds.lpData);
53          }
54      } 
55  }
 1  public partial class MainWindow : Window
 2  {
 3      public MainWindow()
 4      {
 5          InitializeComponent();
 6      }
 7 
 8      protected override void OnSourceInitialized(EventArgs e)
 9      {
10          base.OnSourceInitialized(e);
11 
12          HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
13          hwndSource.AddHook(WndProc);
14      }
15 
16      private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
17      {
18          if (msg == WM_COPYDATA)
19          {
20              COPYDATASTRUCT cds = (COPYDATASTRUCT)Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT));
21              string receivedMessage = Marshal.PtrToStringUni(cds.lpData);
22 
23              Console.WriteLine("收到消息:" + receivedMessage);
24 
25              //TODO:业务处理
26              MessageBox.Show(receivedMessage);
27 
28              handled = true;
29          }
30 
31          return IntPtr.Zero;
32      }
33  }

与C#使用SendMessage进行进程间通讯相似的内容:

C#使用SendMessage进行进程间通讯

最近公司有个需求是,拖动文件到桌面图标上,自动打开文件。那么只需在OnStartup事件中通过StartupEventArgs获取文件名然后进行操作即可。操作之后发现当软件已经启动了(单例运行),那么将无法将参数传给业务层。原因是因为跨进程了,那么我们可以通过窗口句柄的方式来进行通讯。 1 publ

C# 使用模式匹配的好处,因为好用所以推荐~

类型检查和转换:当你需要检查对象是否为特定类型,并且希望在同一时间内将其转换为那个类型时,模式匹配提供了一种更简洁的方式来完成这一任务,避免了使用传统的as和is操作符后还需要进行额外的null检查。 复杂条件逻辑:在处理复杂的条件逻辑时,特别是涉及到多个条件和类型的情况下,使用模式匹配可以使代码更

【C++】使用ort推理yolov10

【C++】使用ort推理yolov10 前言:由于笔者是编导专业,想玩玩yolo模型,搜来搜去全是python,所以在学会之后写一篇文章帮助和笔者同样情况的人 环境 Windows 10 C++17 onnxruntime18.1(DML版本) opencv4.9 visual studio2022

C++使用gnuplot-cpp库绘制图像

最近想要对一些时变的变量进行可视化,搜索来搜索去选择了使用gnuplot这个工具。 sudo apt-get install gnuplot sudo apt-get install gnuplot-x11 # 使其支持linux终端 这样就安装完gnuplot了。接着可以在命令行中键入gnuplo

C#使用MX Component实现三菱PLC软元件数据采集的完整步骤(仿真)

前言 本文介绍了如何使用三菱提供的MX Component插件实现对三菱PLC软元件数据的读写,记录了使用计算机仿真,模拟PLC,直至完成测试的详细流程,并重点介绍了在这个过程中的易错点,供参考。 用到的软件: 1. PLC开发编程环境GX Works2,GX Works2下载链接 https://

C# 使用openxml解析PPTX中的文本内容

前言 本文讨论的仅针对微软Office 2007以后的(OOXML定义)PowerPoint文档,Office 2007以前的用二进制格式定义的(ppt格式)文档不在本文讨论范围。 一、依赖类库 本文需要依赖两个免费的第三方类库:DocumentFormat.OpenXml和FreeSpire.Do

C#中使用CAS实现无锁算法

CAS 的基本概念 CAS(Compare-and-Swap)是一种多线程并发编程中常用的原子操作,用于实现多线程间的同步和互斥访问。 它操作通常包含三个参数:一个内存地址(通常是一个共享变量的地址)、期望的旧值和新值。 CompareAndSwap(内存地址,期望的旧值,新值) CAS 操作会比较

2.1 C/C++ 使用数组与指针

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

3.1 C/C++ 使用字符与指针

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。

4.1 C/C++ 使用结构与指针

C/C++语言是一种通用的编程语言,具有高效、灵活和可移植等特点。C语言主要用于系统编程,如操作系统、编译器、数据库等;C语言是C语言的扩展,增加了面向对象编程的特性,适用于大型软件系统、图形用户界面、嵌入式系统等。C/C++语言具有很高的效率和控制能力,但也需要开发人员自行管理内存等底层资源,对于初学者来说可能会有一定的难度。