添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

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)
        // 获取正在运行的实例的进程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;
	声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。