最近公司有个需求是,拖动文件到桌面图标上,自动打开文件。那么只需在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 }