zoukankan      html  css  js  c++  java
  • 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 部分的原始碼:

    #include "stdafx.h"
    LRESULT CALLBACK SubWndProc(
     HWND hWnd, 
     UINT nMessage, 
     WPARAM wParam, LPARAM lParam); 
     
    WNDPROC  gOldWndProc = NULL; 
    HWND  gUnityWnd = NULL; 
     
    #ifdef    __cplusplus
    extern "C" {
    #endif    /*    __cplusplus    */
     
     __declspec(dllexportbool __stdcall init(HWND hWnd)
     {
      gOldWndProc =(WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, (LONG)SubWndProc);
      gUnityWnd =hWnd;
     
      if (gOldWndProc !=NULL)
       return true;
     
      return false;
     }
     
     __declspec(dllexportvoid __stdcall release()
     {
      SetWindowLong(gUnityWnd, GWL_WNDPROC, (LONG)gOldWndProc);
      gOldWndProc =0;
      gUnityWnd =0;
     }
     
    #ifdef    __cplusplus
    }
    #endif    /*    __cplusplus    */
     
     
    LRESULT CALLBACK SubWndProc(
     HWND hWnd, 
     UINT nMessage, 
     WPARAM wParam, LPARAM lParam)
    {
     switch(nMessage)
     {
      case WM_IME_SETCONTEXT:
      case WM_IME_STARTCOMPOSITION:
      case WM_IME_ENDCOMPOSITION:
      case WM_IME_COMPOSITION:
      case WM_IME_REQUEST:
       {
        //...
       }
       break;
     }
     return CallWindowProc(gOldWndProc, hWnd, nMessage, wParam, lParam);
    }

    Unity 可以透過呼叫 DLL 提供的 init() 函數,讓 Windows 改為呼叫我們指定的函數 (SubWndProc) 來處理 Message,透過 release() 函數讓 Message 處理流程復原。底下是 Unity 部分的原始碼(DLL 檔名為 UnityIMEDLL.dll 且檔案放在 Assets/Plugins 目錄下)
    using UnityEngine;
     
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
     
    public class IMEInputBox : MonoBehaviour
    {
        //-----------------------------------------------------------
        [DllImport("UnityIMEDLL")]
        protected static extern bool init(IntPtr hWnd);
     
        [DllImport("UnityIMEDLL")]
        protected static extern void release();
     
        [DllImport("user32")]
        protected static extern IntPtr GetActiveWindow();
     
        //-----------------------------------------------------------
     // Use this for initialization
     void Start ()
     {
            Debug.Log("init UnityIMEDLL.");
            try
            {
                init(GetActiveWindow());
            }
            catch (Exception e)
            {
                Debug.Log(e.ToString());
            }
     }
     
        void OnDisable()
        {
            Debug.Log("release UnityIMEDLL.");
            try
            {
                release();
            }
            catch (Exception e)
            {
                Debug.Log(e.ToString());
            }
        }
    }
  • 相关阅读:
    【开发笔记】- Linux命令大全
    【面试突击】- SpringMVC那些事(一)
    【阿里云开发】- 搭建和卸载svn服务器
    【阿里云开发】- 安装tomcat
    SpringCloud之Eureka服务发现和注册(二)
    springcloud之环境工程模块(一)
    java多线程中篇(三) —— 线程的控制(创建,运行,阻塞,中断,结束)
    java多线程中篇(二) —— 线程的创建和Synchronized锁关键字
    java多线程中篇(一) —— Thread详情
    JUC之AbstractQueuedSynchronizer原理分析
  • 原文地址:https://www.cnblogs.com/ultrasoon/p/2036972.html
Copyright © 2011-2022 走看看