C#使用SendMessage進行程序間通訊

韶光荏苒發表於2024-07-10

最近公司有個需求是,拖動檔案到桌面圖示上,自動開啟檔案。那麼只需在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  }

相關文章