using System; using System.Diagnostics; using System.Runtime.InteropServices; using UnityEngine; public static class WebViewWin32 { [DllImport("user32.dll")] static extern bool SetWindowPos( IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [DllImport("user32.dll")] static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect); [DllImport("user32.dll")] static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X; public int Y; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct COPYDATASTRUCT { public IntPtr dwData; public int cbData; public IntPtr lpData; } const uint SWP_NOZORDER = 0x0004; const uint SWP_NOACTIVATE = 0x0010; const uint WM_COPYDATA = 0x004A; public static bool TrySetWindowRect(Process process, int x, int y, int width, int height) { if (process == null || process.HasExited) return false; if (process.MainWindowHandle == IntPtr.Zero) { process.Refresh(); if (process.MainWindowHandle == IntPtr.Zero) return false; } SetWindowPos( process.MainWindowHandle, IntPtr.Zero, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE ); return true; } public static bool TryGetWindowRect(Process process, out RECT rect) { rect = new RECT(); if (process == null || process.HasExited) return false; if (process.MainWindowHandle == IntPtr.Zero) { process.Refresh(); if (process.MainWindowHandle == IntPtr.Zero) return false; } return GetWindowRect(process.MainWindowHandle, out rect); } public static bool TryGetClientScreenRect(Process process, out RECT rect) { rect = new RECT(); if (process == null || process.HasExited) return false; if (process.MainWindowHandle == IntPtr.Zero) { process.Refresh(); if (process.MainWindowHandle == IntPtr.Zero) return false; } POINT point = new POINT { X = 0, Y = 0 }; if (!ClientToScreen(process.MainWindowHandle, ref point)) return false; rect.Left = point.X; rect.Top = point.Y; rect.Right = point.X + UnityEngine.Screen.width; rect.Bottom = point.Y + UnityEngine.Screen.height; return true; } /// /// 尝试向指定进程的主窗口发送 WM_COPYDATA 消息,lParam 为包含 Unicode 字符串的 COPYDATASTRUCT。 /// 接收方需要处理 WM_COPYDATA 并解释字符串为 URL 并导航。 /// 返回 true 表示接收方可能已处理(基于 SendMessage 返回值),false 表示发送或接收未成功。 /// public static bool TrySendUrlToWindow(Process process, string url) { if (process == null || process.HasExited || string.IsNullOrEmpty(url)) return false; if (process.MainWindowHandle == IntPtr.Zero) { process.Refresh(); if (process.MainWindowHandle == IntPtr.Zero) return false; } IntPtr hWnd = process.MainWindowHandle; IntPtr ptrString = IntPtr.Zero; IntPtr ptrCds = IntPtr.Zero; try { // Allocate Unicode string (null-terminated) ptrString = Marshal.StringToHGlobalUni(url); var cds = new COPYDATASTRUCT { dwData = IntPtr.Zero, cbData = (url.Length + 1) * 2, lpData = ptrString }; int size = Marshal.SizeOf(typeof(COPYDATASTRUCT)); ptrCds = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(cds, ptrCds, false); IntPtr res = SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ptrCds); long resVal = res.ToInt64(); UnityEngine.Debug.Log($"WebViewWin32.TrySendUrlToWindow: Sent WM_COPYDATA to hWnd=0x{hWnd.ToInt64():X}, url={url}, SendMessage result={resVal}"); // Treat non-zero as handled/accepted by receiver. If receiver returns zero, consider not handled. return resVal != 0; } catch (Exception e) { UnityEngine.Debug.LogWarning("WebViewWin32.TrySendUrlToWindow exception: " + e.Message); return false; } finally { if (ptrCds != IntPtr.Zero) Marshal.FreeHGlobal(ptrCds); if (ptrString != IntPtr.Zero) Marshal.FreeHGlobal(ptrString); } } }