Eding.ICU域名工具箱因为需要实现OAuth授权,并且需要通过自定义URL协议再不同的WPF窗体间传输Windows消息,所以通过实际调试得到了以下完善的代码。
第一步、注册自定义URL协议
public static void RegisterCustomUrlProtocol() { // 使用 HKEY_CURRENT_USER\Software\Classes 分支创建注册表键 RegistryKey? currentUserKey = Registry.CurrentUser.OpenSubKey("Software", true); if (currentUserKey != null) { RegistryKey classesKey = currentUserKey.CreateSubKey("Classes"); RegistryKey key = classesKey.CreateSubKey("myapp"); // 设置注册表键的值 key.SetValue("", "URL: Custom Protocol"); key.SetValue("URL Protocol", ""); // 创建 "shell\open\command" 子键并设置值 RegistryKey commandKey = key.CreateSubKey(@"shell\open\command"); string executablePath = Assembly.GetEntryAssembly()?.Location ?? string.Empty; string exePath = executablePath.Replace(".dll", ".exe"); commandKey.SetValue("", "\"" + exePath + "\" \"%1\""); } }
第二步、向运行实例发送消息
public static class NativeMethods { // Windows消息常量 public const int WM_COPYDATA = 0x004A; [DllImport("user32.dll", EntryPoint = "SendMessage")] public static extern bool SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); // 结构体用于封装 [StructLayout(LayoutKind.Sequential)] public struct COPYDATASTRUCT { public IntPtr dwData; // 传递的数据 public int cbData; // 数据大小 public IntPtr lpData; // 指向数据的指针 } } public static void SendArgsToRunningInstance(string[] args) { try { // 获取正在运行的实例的进程ID var currentProcess = Process.GetCurrentProcess(); foreach (var process in Process.GetProcessesByName(currentProcess.ProcessName)) { if (process.Id != currentProcess.Id) { // 向正在运行的实例发送参数 string arguments = string.Join("||", args); byte[] data = Encoding.Unicode.GetBytes(arguments); // 分配内存并将数据复制到内存中 IntPtr lpData = Marshal.AllocHGlobal(data.Length); Marshal.Copy(data, 0, lpData, data.Length); // 构造 COPYDATASTRUCT 结构体 COPYDATASTRUCT cds = new() { dwData = IntPtr.Zero, cbData = data.Length, lpData = lpData }; //使用Marshal将struct转化为IntPtr IntPtr cdsPtr = Marshal.AllocHGlobal(Marshal.SizeOf(cds)); Marshal.StructureToPtr(cds, cdsPtr, false); SendMessage(process.MainWindowHandle, WM_COPYDATA, IntPtr.Zero, cdsPtr); // 释放分配的内存 Marshal.FreeHGlobal(lpData); Marshal.FreeHGlobal(cdsPtr); } } } catch (Exception ex) { MessageBox.Show("将参数发送到正在运行的实例时出错: " + ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }
第三步、添加消息处理钩子
void WSInitialized(object sender, EventArgs e) { HwndSource? hs = PresentationSource.FromVisual(this) as HwndSource; hs?.AddHook(new HwndSourceHook(WndProc)); } private bool _isMessageHandled = false;
第四步、处理Windows消息
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case WM_COPYDATA: if (!_isMessageHandled && lParam != IntPtr.Zero) { object? structObj = Marshal.PtrToStructure(lParam, typeof(COPYDATASTRUCT)); if (structObj != null) { COPYDATASTRUCT cds = (COPYDATASTRUCT)structObj; string strResult = Marshal.PtrToStringUni(cds.lpData, cds.cbData / 2); // 调用异步方法处理消息 Task handleTask = OAuth.HandleCustomUrlProtocol(strResult, this); // 在异步操作完成后根据结果设置_isMessageHandled变量的值 handleTask.ContinueWith(task => { _isMessageHandled = task.Result; }); } } break; } return IntPtr.Zero; }
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论(0)