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