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;
}

 

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