unity3d 实现windows 消息


Windows Message in the Unity3D : WndProc

先前提到可以用 Hooks 的方法在 Unity 裡監控 Windows Message,但是使用 Hooks 這個方法我們沒辦法更改 Message 的內容。因此這邊提出第二個方式。Windows 傳送 Message 給 Unity 時,會呼叫 Unity 預設的 Message 處理函數,但透過函數:

pOldWndProc =(WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)SubWndProc);

我們可以將原本 Windows 呼叫 Unity 預設的 Message 處理函數改為呼叫我們指定的函數,指定的函數把我們想要處理的 Message 處理完,再把剩下的 Message 丟回給 Unity 來處理。

原本實作是使用 dllimport 讓 SetWindowLong function 可以在 C# 裡呼叫, 並把整個 callback function 及流程實作出來,且測試時運作都相當正常,但程式在關閉時會出現 Access Violation 的錯誤,後來將整個實作改成 C DLL 之後錯誤才沒有出現,不知道是什麼原因?底下是 DLL 部分的原始碼:

  1. #include "stdafx.h"
  2. LRESULT CALLBACK SubWndProc(
  3. HWND hWnd, 
  4. UINT nMessage, 
  5. WPARAM wParam, LPARAM lParam); 

  6. WNDPROC  gOldWndProc = NULL; 
  7. HWND  gUnityWnd = NULL; 

  8. #ifdef    __cplusplus
  9. extern "C" {
  10. #endif    /*    __cplusplus    */

  11. __declspec(dllexport) bool __stdcall init(HWND hWnd)
  12. {
  13.   gOldWndProc =(WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)SubWndProc);
  14.   gUnityWnd =hWnd;

  15.   if (gOldWndProc !=NULL)
  16.    return true;

  17.   return false;
  18. }

  19. __declspec(dllexport) void __stdcall release()
  20. {
  21.   SetWindowLong(gUnityWnd, GWL_WNDPROC, (LONG)gOldWndProc);
  22.   gOldWndProc =0;
  23.   gUnityWnd =0;
  24. }

  25. #ifdef    __cplusplus
  26. }
  27. #endif    /*    __cplusplus    */


  28. LRESULT CALLBACK SubWndProc(
  29. HWND hWnd, 
  30. UINT nMessage, 
  31. WPARAM wParam, LPARAM lParam)
  32. {
  33. switch(nMessage)
  34. {
  35.   case WM_IME_SETCONTEXT:
  36.   case WM_IME_STARTCOMPOSITION:
  37.   case WM_IME_ENDCOMPOSITION:
  38.   case WM_IME_COMPOSITION:
  39.   case WM_IME_REQUEST:
  40.    {
  41.     //...
  42.    }
  43.    break;
  44. }
  45. return CallWindowProc(gOldWndProc, hWnd, nMessage, wParam, lParam);
  46. }
复制代码

Unity 可以透過呼叫 DLL 提供的 init() 函數,讓 Windows 改為呼叫我們指定的函數 (SubWndProc) 來處理 Message,透過 release() 函數讓 Message 處理流程復原。底下是 Unity 部分的原始碼(DLL 檔名為 UnityIMEDLL.dll 且檔案放在 Assets/Plugins 目錄下)

  1. using UnityEngine;

  2. using System;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.Runtime.InteropServices;

  6. public class IMEInputBox : MonoBehaviour
  7. {
  8.     //-----------------------------------------------------------
  9.     [DllImport("UnityIMEDLL")]
  10.     protected static extern bool init(IntPtr hWnd);

  11.     [DllImport("UnityIMEDLL")]
  12.     protected static extern void release();

  13.     [DllImport("user32")]
  14.     protected static extern IntPtr GetActiveWindow();

  15.     //-----------------------------------------------------------
  16. // Use this for initialization
  17. void Start ()
  18. {
  19.         Debug.Log("init UnityIMEDLL.");
  20.         try
  21.         {
  22.             init(GetActiveWindow());
  23.         }
  24.         catch (Exception e)
  25.         {
  26.             Debug.Log(e.ToString());
  27.         }
  28. }

  29.     void OnDisable()
  30.     {
  31.         Debug.Log("release UnityIMEDLL.");
  32.         try
  33.         {
  34.             release();
  35.         }
  36.         catch (Exception e)
  37.         {
  38.             Debug.Log(e.ToString());
  39.         }
  40.     }
  41. }
复制代码




你可能感兴趣的:(unity3d 实现windows 消息)