minigame-tuanjie-transform-sdk/Runtime/WXPCHPInitScript.cs
2026-03-02 19:15:34 +08:00

386 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Runtime.InteropServices;
using UnityEngine;
namespace WeChatWASM
{
/// <summary>
/// PC高性能小游戏初始化脚本
/// 负责与宿主程序的 direct_applet_sdk.dll 进行交互
/// </summary>
public class WXPCHPInitScript : MonoBehaviour
{
#region DLL Imports
private const string DLL_NAME = "direct_applet_sdk.dll";
// 初始化SDK
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern bool InitEmbeddedGameSDK();
// 注册异步消息处理器
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern void RegisterAsyncMsgHandler(AsyncMsgHandlerDelegate handler);
// 建立Mojo连接
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern bool EstablishConnection();
// 初始化游戏窗口 - 传入窗口句柄
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern bool InitGameWindow(ulong hwnd);
// 异步发送消息
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern bool SendMsgAsync(IntPtr data, int len);
// 清理资源
[DllImport(DLL_NAME, CallingConvention = CallingConvention.Cdecl)]
private static extern bool Cleanup();
// 获取当前活动窗口句柄
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
// Windows MessageBox
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern int MessageBox(IntPtr hWnd, string text, string caption, uint type);
#endregion
#region Delegate Definition
// 异步消息处理器委托
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void AsyncMsgHandlerDelegate(IntPtr data, int len);
// 保持委托引用防止被GC回收
private static AsyncMsgHandlerDelegate asyncMsgHandler;
#endregion
#region Singleton
private static WXPCHPInitScript instance;
public static WXPCHPInitScript Instance => instance;
#endregion
#region Events
// 收到异步消息时触发的事件
public event Action<byte[]> OnMessageReceived;
#endregion
#region Properties
// SDK是否已初始化
public bool IsInitialized { get; private set; }
// 是否已连接
public bool IsConnected { get; private set; }
// 窗口句柄
public IntPtr WindowHandle { get; private set; }
#endregion
#region Unity Lifecycle
private void Awake()
{
Debug.Log("[WXPCHPInitScript] ========== Awake 被调用 ==========");
Debug.Log($"[WXPCHPInitScript] GameObject 名称: {gameObject.name}");
Debug.Log($"[WXPCHPInitScript] 场景名称: {UnityEngine.SceneManagement.SceneManager.GetActiveScene().name}");
if (instance != null && instance != this)
{
Debug.LogWarning("[WXPCHPInitScript] 检测到重复实例,销毁当前对象");
Destroy(gameObject);
return;
}
instance = this;
DontDestroyOnLoad(gameObject);
Debug.Log("[WXPCHPInitScript] 单例创建成功,已设置 DontDestroyOnLoad");
// 初始化SDK
Initialize();
}
private void OnDestroy()
{
if (instance == this)
{
CleanupSDK();
instance = null;
}
}
private void OnApplicationQuit()
{
CleanupSDK();
}
#endregion
#region Public Methods
/// <summary>
/// 初始化SDK并建立连接
/// </summary>
public void Initialize()
{
if (IsInitialized)
{
Debug.LogWarning("[WXPCHPInitScript] SDK已经初始化");
return;
}
Debug.Log("[WXPCHPInitScript] ========== 开始初始化 ==========");
Debug.Log($"[WXPCHPInitScript] 当前工作目录: {System.IO.Directory.GetCurrentDirectory()}");
Debug.Log($"[WXPCHPInitScript] DLL 搜索路径: {DLL_NAME}");
try
{
// 1. 初始化SDK
Debug.Log("[WXPCHPInitScript] Step 1: 调用 InitEmbeddedGameSDK");
ShowInfo("开始调用 InitEmbeddedGameSDK...");
if (!InitEmbeddedGameSDK())
{
ShowError("InitEmbeddedGameSDK 返回 false");
return;
}
ShowInfo("InitEmbeddedGameSDK 成功");
// 2. 注册消息处理器 (暂时屏蔽)
// asyncMsgHandler = HandleAsyncMessage;
// RegisterAsyncMsgHandler(asyncMsgHandler);
// ShowInfo("RegisterAsyncMsgHandler 成功");
Debug.Log("[WXPCHPInitScript] Step 2: RegisterAsyncMsgHandler 已跳过");
ShowInfo("RegisterAsyncMsgHandler 已跳过");
// 3. 建立连接
Debug.Log("[WXPCHPInitScript] Step 3: 调用 EstablishConnection");
if (!EstablishConnection())
{
ShowError("EstablishConnection 返回 false");
IsConnected = false;
return;
}
IsConnected = true;
ShowInfo("EstablishConnection 成功");
// 4. 获取窗口句柄并初始化游戏窗口
Debug.Log("[WXPCHPInitScript] Step 4: 获取窗口句柄");
WindowHandle = GetActiveWindow();
if (WindowHandle == IntPtr.Zero)
{
ShowError("GetActiveWindow 返回空句柄");
return;
}
ShowInfo($"获取窗口句柄成功: 0x{WindowHandle.ToInt64():X}");
Debug.Log("[WXPCHPInitScript] Step 5: 调用 InitGameWindow");
if (!InitGameWindow((ulong)WindowHandle.ToInt64()))
{
ShowError("InitGameWindow 返回 false");
return;
}
ShowInfo("InitGameWindow 成功");
IsInitialized = true;
ShowInfo("SDK 完全初始化成功!");
Debug.Log("[WXPCHPInitScript] ========== 初始化完成 ==========");
}
catch (DllNotFoundException e)
{
ShowError($"找不到DLL: {e.Message}");
Debug.LogError($"[WXPCHPInitScript] DLL 加载失败,请确保 {DLL_NAME} 在以下位置之一:");
Debug.LogError($" - 与 .exe 同级目录");
Debug.LogError($" - System32 目录");
Debug.LogError($" - PATH 环境变量包含的路径");
}
catch (EntryPointNotFoundException e)
{
ShowError($"找不到函数入口: {e.Message}");
Debug.LogError($"[WXPCHPInitScript] 函数入口点错误,可能是 DLL 版本不匹配");
}
catch (Exception e)
{
ShowError($"初始化异常: {e.Message}\n{e.StackTrace}");
Debug.LogError($"[WXPCHPInitScript] 未知异常: {e}");
}
}
/// <summary>
/// 显示信息弹窗(仅 Windows
/// </summary>
private void ShowInfo(string message)
{
Debug.Log($"[WXPCHPInitScript] {message}");
#if UNITY_STANDALONE_WIN
try
{
// MB_OK | MB_ICONINFORMATION = 0x40
MessageBox(IntPtr.Zero, message, "WXPCHPInitScript Info", 0x40);
}
catch (System.Exception e)
{
Debug.LogWarning($"[WXPCHPInitScript] MessageBox 调用失败: {e.Message}");
}
#endif
}
/// <summary>
/// 显示错误弹窗(仅 Windows
/// </summary>
private void ShowError(string message)
{
Debug.LogError($"[WXPCHPInitScript] {message}");
#if UNITY_STANDALONE_WIN
try
{
// MB_OK | MB_ICONERROR = 0x10
MessageBox(IntPtr.Zero, message, "WXPCHPInitScript Error", 0x10);
}
catch (System.Exception e)
{
Debug.LogWarning($"[WXPCHPInitScript] MessageBox 调用失败: {e.Message}");
}
#endif
}
/// <summary>
/// 发送异步消息到宿主
/// </summary>
/// <param name="message">消息内容</param>
/// <returns>是否发送成功</returns>
public bool SendMessage(string message)
{
if (!IsInitialized || !IsConnected)
{
Debug.LogWarning("[WXPCHPInitScript] SDK未初始化或未连接");
return false;
}
try
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(message);
return SendMessage(data);
}
catch (Exception e)
{
Debug.LogError($"[WXPCHPInitScript] 发送消息异常: {e.Message}");
return false;
}
}
/// <summary>
/// 发送异步消息到宿主
/// </summary>
/// <param name="data">消息数据</param>
/// <returns>是否发送成功</returns>
public bool SendMessage(byte[] data)
{
if (!IsInitialized || !IsConnected)
{
Debug.LogWarning("[WXPCHPInitScript] SDK未初始化或未连接");
return false;
}
if (data == null || data.Length == 0)
{
Debug.LogWarning("[WXPCHPInitScript] 发送的数据为空");
return false;
}
try
{
IntPtr ptr = Marshal.AllocHGlobal(data.Length);
try
{
Marshal.Copy(data, 0, ptr, data.Length);
return SendMsgAsync(ptr, data.Length);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
catch (Exception e)
{
Debug.LogError($"[WXPCHPInitScript] 发送消息异常: {e.Message}");
return false;
}
}
#endregion
#region Private Methods
/// <summary>
/// 清理SDK资源
/// </summary>
private void CleanupSDK()
{
if (!IsInitialized)
{
return;
}
try
{
Cleanup();
Debug.Log("[WXPCHPInitScript] SDK清理完成");
}
catch (Exception e)
{
Debug.LogError($"[WXPCHPInitScript] 清理异常: {e.Message}");
}
finally
{
IsInitialized = false;
IsConnected = false;
}
}
/// <summary>
/// 异步消息处理回调
/// </summary>
[AOT.MonoPInvokeCallback(typeof(AsyncMsgHandlerDelegate))]
private static void HandleAsyncMessage(IntPtr data, int len)
{
if (data == IntPtr.Zero || len <= 0)
{
return;
}
try
{
byte[] buffer = new byte[len];
Marshal.Copy(data, buffer, 0, len);
// 在主线程中触发事件
if (instance != null)
{
// 直接调用如果需要线程安全可以使用Unity的主线程调度
instance.OnMessageReceived?.Invoke(buffer);
// 打印收到的消息(用于调试)
string message = System.Text.Encoding.UTF8.GetString(buffer);
Debug.Log($"[WXPCHPInitScript] 收到消息: {message}");
}
}
catch (Exception e)
{
Debug.LogError($"[WXPCHPInitScript] 处理消息异常: {e.Message}");
}
}
#endregion
}
}