#if UNITY_EDITOR_WIN using System; using System.Runtime.InteropServices; namespace Cn.Tuanjie.Codely.Editor { /// /// NativeBrowser.dll 的 P/Invoke 声明。 /// DLL 内部管理 STA 线程、WebView2 COM 生命周期和 WndProcHook, /// C# 侧只需持有不透明句柄并调用 API。 /// internal static class NativeBrowserAPI { const string DLL = "NativeBrowser"; // ── 回调委托(必须 stdcall + 持有强引用,防止 GC 回收)──────────────── [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] public delegate void NavigationCallback(string url, IntPtr ctx); [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void LoadCompletedCallback(bool success, IntPtr ctx); [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] public delegate void TitleChangedCallback(string title, IntPtr ctx); [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] public delegate void MessageCallback(string json, IntPtr ctx); [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void DestroyedCallback(IntPtr ctx); [StructLayout(LayoutKind.Sequential)] public struct Callbacks { public NavigationCallback onNavigationStarting; public LoadCompletedCallback onLoadCompleted; public TitleChangedCallback onTitleChanged; public MessageCallback onWebMessageReceived; public DestroyedCallback onParentDestroyed; public IntPtr ctx; } // ── 生命周期 ────────────────────────────────────────────────────────── [DllImport(DLL, CharSet = CharSet.Unicode)] public static extern IntPtr NB_Create( IntPtr parentHwnd, string userDataFolder, string initialUrl, ref Callbacks callbacks); [DllImport(DLL)] public static extern void NB_Destroy(IntPtr handle); /// /// 同步关闭所有活跃 BrowserInstance(总耗时最长 timeoutMs)。 /// 在调用线程 pump 消息以驱动 WebView2 跨 apartment marshaling,避免父 HWND /// 所属线程被阻塞导致 Close 死锁。仅 PrepareShutdown + FinalizeShutdown, /// 不释放内存(进程即将退出由 OS 回收)。必须在 EditorApplication.quitting 调用一次。 /// [DllImport(DLL)] public static extern void NB_ShutdownAll(uint timeoutMs); /// /// 替换 BrowserInstance 内的托管回调函数指针。 /// Unity Domain Reload 后旧委托已失效,必须在 OnEnable 中调用此函数注册新委托。 /// [DllImport(DLL)] public static extern void NB_SetCallbacks(IntPtr handle, ref Callbacks callbacks); /// /// 判断 handle 是否仍指向一个活跃的 BrowserInstance(不解引用指针,安全)。 /// 用于 Domain Reload 后验证序列化的句柄是否仍然有效。 /// [DllImport(DLL)] public static extern bool NB_IsHandleValid(IntPtr handle); // ── 导航 ────────────────────────────────────────────────────────────── [DllImport(DLL, CharSet = CharSet.Unicode)] public static extern void NB_Navigate(IntPtr handle, string url); [DllImport(DLL)] public static extern void NB_GoBack (IntPtr handle); [DllImport(DLL)] public static extern void NB_GoForward(IntPtr handle); [DllImport(DLL)] public static extern void NB_Reload (IntPtr handle); [DllImport(DLL)] public static extern void NB_Stop (IntPtr handle); // ── 布局 ────────────────────────────────────────────────────────────── [DllImport(DLL)] public static extern void NB_Resize (IntPtr handle, int x, int y, int w, int h); [DllImport(DLL)] public static extern void NB_SetVisible (IntPtr handle, bool visible); [DllImport(DLL)] public static extern void NB_SetTopInset(IntPtr handle, int topPx); // ── 脚本 ────────────────────────────────────────────────────────────── [DllImport(DLL, CharSet = CharSet.Unicode)] public static extern void NB_ExecuteScript(IntPtr handle, string js); [DllImport(DLL, CharSet = CharSet.Unicode)] public static extern void NB_PostWebMessage(IntPtr handle, string json); // ── 焦点 ────────────────────────────────────────────────────────────── // 将键盘焦点移入 WebView2 内容(ICoreWebView2Controller::MoveFocus PROGRAMMATIC)。 // 嵌入 Unity 后导航完成时焦点仍在父窗口,autofocus/element.focus() 不生效,需显式调用。 [DllImport(DLL)] public static extern void NB_MoveFocus(IntPtr handle); // ── 调试 ────────────────────────────────────────────────────────────── [DllImport(DLL)] public static extern void NB_OpenDevTools(IntPtr handle); // ── Runtime 检测 ────────────────────────────────────────────────────── [DllImport(DLL)] public static extern bool NB_IsRuntimeAvailable(); [DllImport(DLL, CharSet = CharSet.Unicode)] public static extern IntPtr NB_GetRuntimeVersion(); // 返回 DLL 内部静态字符串 } } #endif