[Unity] 在软件标题栏显示工作路径
(一)问题
项目开发中常会有开多个分支,同时启动多个 Unity 程序的情况,来回切换的时候就容易混淆,有时候还需要用 Show In Explorer 或者其他标志来确认当前使用的是哪个分支。
于是想在标题栏上直接显示出当前的工作目录:
- 修改前: 
  - 原本的标题栏由项目名、场景、工作平台等文本组成 
- 修改后: 
  - 额外显示工作路径 
(二)代码
1. 声明要调用的系统接口
using System;
using System.Runtime.InteropServices;
using System.Text;
public partial class UpdateUnityEditorProcess
{
    public delegate bool EnumThreadWindowsCallback(IntPtr hWnd, IntPtr lParam);
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);
    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetWindow(HandleRef hWnd, int uCmd);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern bool IsWindowVisible(HandleRef hWnd);
    [DllImport("user32.dll")]
    private static extern bool GetWindowText(int hWnd, StringBuilder title, int maxBufSize);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private extern static int GetWindowTextLength(IntPtr hWnd);
    [DllImport("user32.dll", EntryPoint = "SetWindowText", CharSet = CharSet.Auto)]
    public extern static int SetWindowText(int hwnd, string lpString);
}
2. 工具类
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using UnityEngine;
public partial class UpdateUnityEditorProcess
{
    public IntPtr hwnd = IntPtr.Zero;
    private bool haveMainWindow = false;
    private IntPtr mainWindowHandle = IntPtr.Zero;
    private int processId = 0;
    private IntPtr hwCurr = IntPtr.Zero;
    private static StringBuilder sbtitle = new StringBuilder(255);
    private static string UTitle = Application.dataPath;
    public static float lasttime = 0;
    private static UpdateUnityEditorProcess _instance;
    public static UpdateUnityEditorProcess Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UpdateUnityEditorProcess();
                _instance.hwnd = _instance.GetMainWindowHandle(Process.GetCurrentProcess().Id);
            }
            return _instance;
        }
    }
    public void SetTitle()
    {
        //UnityEngine.Debug.Log(string.Format("{0} - {1}", Time.realtimeSinceStartup, lasttime));
        if (Time.realtimeSinceStartup > lasttime)
        {
            sbtitle.Length = 0;
            lasttime = Time.realtimeSinceStartup + 2f;
            int length = GetWindowTextLength(hwnd);
            GetWindowText(hwnd.ToInt32(), sbtitle, 255);
            string strTitle = sbtitle.ToString();
            string[] ss = strTitle.Split('-');
            if (ss.Length > 0 && !strTitle.Contains(UTitle))
            {
                SetWindowText(hwnd.ToInt32(), string.Format("{0} - {1}", UTitle, strTitle));
                UnityEngine.Debug.Log("Current Unity Title: " + UTitle);
            }
        }
    }
    public IntPtr GetMainWindowHandle(int processId)
    {
        if (!this.haveMainWindow)
        {
            this.mainWindowHandle = IntPtr.Zero;
            this.processId = processId;
            EnumThreadWindowsCallback callback = new EnumThreadWindowsCallback(this.EnumWindowsCallback);
            EnumWindows(callback, IntPtr.Zero);
            GC.KeepAlive(callback);
            this.haveMainWindow = true;
        }
        return this.mainWindowHandle;
    }
    private bool EnumWindowsCallback(IntPtr handle, IntPtr extraParameter)
    {
        int num;
        GetWindowThreadProcessId(new HandleRef(this, handle), out num);
        if ((num == this.processId) && this.IsMainWindow(handle))
        {
            this.mainWindowHandle = handle;
            return false;
        }
        return true;
    }
    private bool IsMainWindow(IntPtr handle)
    {
        return (!(GetWindow(new HandleRef(this, handle), 4) != IntPtr.Zero) && IsWindowVisible(new HandleRef(this, handle)));
    }
}
3. Editor 回调设置
#if UNITY_EDITOR_WIN
using UnityEditor;
[InitializeOnLoad]
class UpdateUnityEditorTitle
{
    private static bool isInGame = false;
    static UpdateUnityEditorTitle()
    {
        EditorApplication.delayCall += DoUpdateTitleFunc;
        EditorApplication.playmodeStateChanged += OnPlaymodeStateChanged;
    }
    static void OnPlaymodeStateChanged()
    {
        if (EditorApplication.isPlaying == isInGame) return;
        isInGame = EditorApplication.isPlaying;
        UpdateUnityEditorProcess.lasttime = 0;
        DoUpdateTitleFunc();
    }
    static void DoUpdateTitleFunc()
    {
        //UnityEngine.Debug.Log("DoUpdateTitleFunc");
        UpdateUnityEditorProcess.Instance.SetTitle();
    }
}
#endif
(三)备注
- [InitializeOnLoad]的调用时机是在 Unity 初始化标题之前,所以直接在- UpdateUnityEditorTitle()中设置标题的话会被覆盖掉,这里利用EditorApplication.delayCall 调用标题修改
- 进入退出 GameMode 会触发 Unity 软件初始化标题,利用 EditorApplication.playmodeStateChanged来调用自定义的标题修改
[Unity] 在软件标题栏显示工作路径的更多相关文章
- Linux显示工作路径
		Linux显示工作路径 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ pwd /home/youhaidong 
- linux服务器上如何显示工作路径
		1. 修改PS环境变量 [root@linux-node01 ~]# vi /etc/bashrc [ "$PS1" = "\\s-\\v\\\$ " ] &a ... 
- pwd 显示当前所在的工作路径
		1.功能说明 pwd命令是“print working directory ”首字母缩写,显示当前目录的绝对路径. 2.语法格式 pwd [option] pwd 选项 3.命令参数 参数 参数说明 ... 
- C#、ASP.NET获取当前应用程序的绝对路径,获取程序工作路径 (转帖)
		C#.ASP.NET获取当前应用程序的绝对路径,获取程序工作路径 ============================================ 使用 Application.Start ... 
- 关于source insight、添加.s和.S文件,显示全部路径、加入项目后闪屏幕
		1.source insight使用也有一年多时间了,今天出现建工程后添加文件“no files found” 百思不得姐: 后面发现是原工程命名时出现非法字符.重新命名就ok了. 切记切记 2.实用 ... 
- Jupyter Notebook默认工作路径的修改
		相信每一个学习Python的童鞋,都尝试过Jupyter Notebook,所以我也就不多介绍,真的还不错哎这软件. 不过美中不足的,就是它的默认工作路径,每次打开都是系统盘的Administrato ... 
- 【原创】os.chdir设置的工作路径和sys.path之间到底是个啥关系?
		转载请注明出处:https://www.cnblogs.com/oceanicstar/p/9390455.html 直接放上测试后的结论(测试代码和截图过多,有兴趣的小伙伴可自己测试,未来看情况 ... 
- Ubuntu 14 下,命令行终端显示短路径
		Ubuntu的终端命令行默认是长路径,即把路径深度全部显示出来,操作起来不是很方便,下面介绍命令行显示短路径的操作: $ vi ~/.bashrc 找到PS1= 的行,将\w(小写)改成\W(大写 ... 
- BAT: Windows批处理更改当前工作路径
		最近项目上需要获取文件夹下所有文件信息,因为文件夹是在server上,所以想用批处理bat来获取该路径下所有文件信息,然后通过任务计划管理去每天自动运行bat去更新文件信息内容. 获取文件夹下所有文件 ... 
随机推荐
- leetcode 33. 搜索旋转排序数组 及 81. 搜索旋转排序数组 II
			33. 搜索旋转排序数组 问题描述 假设按照升序排序的数组在预先未知的某个点上进行了旋转. ( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] ). 搜索一个给定 ... 
- 基于 NFS 搭建便捷远程硬盘
			基于 NFS 搭建便捷远程硬盘 知识准备: 一.NFS服务简介 NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向 ... 
- Superset SSO改造和自定义宏命令
			目录 背景 关于Superset 需要解决的问题 定制化改造 准备环境 改造OAuth SSO 安装依赖 配置SSO 添加自定义的SecurityManager 运行一下吧 自定义宏命令 开启配置 添 ... 
- 【Vue源码学习】响应式原理探秘
			最近准备开启Vue的源码学习,并且每一个Vue的重要知识点都会记录下来.我们知道Vue的核心理念是数据驱动视图,所有操作都只需要在数据层做处理,不必关心视图层的操作.这里先来学习Vue的响应式原理,V ... 
- 【Vue源码学习】依赖收集
			前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ... 
- *衡树 Treap(树堆) 学习笔记
			调了好几个月的 Treap 今天终于调通了,特意写篇博客来纪念一下. 0. Treap 的含义及用途 在算法竞赛中很多题目要使用二叉搜索树维护信息.然而毒瘤数据可能让二叉搜索树退化成链,这时就需要让二 ... 
- Core 3.1 MVC 抛异常“InvalidOperationException: No service for type 'Microsoft.AspNetCore.Mvc.ViewFeatures.ITempDataDictionaryFactory' has been registered.”
			.NET Core 的版本是 3.1遇到的问题是 Action 中 return View() 的时候报错 An unhandled exception occurred while processi ... 
- libevent网络库
			1.概述 libevent是一个C语言编写的.轻量级开源高性能事件通知库.作为底层网络库,已经被广泛应用(如:memcached.Vomit.Nylon.Netchat等).主要有以下几个亮点: 事件 ... 
- 计算机网络再次整理————tcp例子[五]
			前言 本文介绍一些tcp的例子,然后不断完善一下. 正文 服务端: // See https://aka.ms/new-console-template for more information us ... 
- ApacheCN 大数据译文集 20211206 更新
			PySpark 大数据分析实用指南 零.前言 一.安装 Pyspark 并设置您的开发环境 二.使用 RDD 将您的大数据带入 Spark 环境 三.Spark 笔记本的大数据清理和整理 四.将数据汇 ... 
