Unity中调用Windows窗口句柄以及根据需求设置并且解决扩展屏窗体显示错乱/位置错误的Bug/指定Windows窗口文件类型筛选
问题背景:
现在在搞PC端应用开发,我们开发中需要调用系统的窗口以及需要最大化最小化,缩放窗口拖拽窗口,以及设置窗口位置,去边框等功能
解决根据:
使用user32.dll解决
具体功能:
Unity中对Windows窗口设置
<1>.unity中调用打开文件窗口和保存窗口:
调用Comdlg32.dll中方法
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Runtime.InteropServices; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace Tx3d.Ventilation 9 { 10 /// <summary> 11 /// 场景窗口类型基类 12 /// </summary> 13 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 14 public class SceneWindows 15 { 16 public int structSize = 0; 17 public IntPtr dlgOwner = IntPtr.Zero; 18 public IntPtr instance = IntPtr.Zero; 19 public String filter = null; 20 public String customFilter = null; 21 public int maxCustFilter = 0; 22 public int filterIndex = 0; 23 public String file = null; 24 public int maxFile = 0; 25 public String fileTitle = null; 26 public int maxFileTitle = 0; 27 public String initialDir = null; 28 public String title = null; 29 public int flags = 0; 30 public short fileOffset = 0; 31 public short fileExtension = 0; 32 public String defExt = null; 33 public IntPtr custData = IntPtr.Zero; 34 public IntPtr hook = IntPtr.Zero; 35 public String templateName = null; 36 public IntPtr reservedPtr = IntPtr.Zero; 37 public int reservedInt = 0; 38 public int flagsEx = 0; 39 } 40 41 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 42 public class OpenFile : SceneWindows 43 { 44 45 } 46 47 public class OpenFileWindow 48 { 49 [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] 50 51 public static extern bool GetOpenFileName([In, Out] OpenFile ofd); 52 } 53 54 public class SaveFileWindow 55 { 56 [DllImport("Comdlg32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)] 57 public static extern bool GetSaveFileName([In, Out] SaveFile ofd); 58 } 59 60 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 61 public class SaveFile : SceneWindows 62 { 63 64 } 65 66 }
具体使用:
1 /// <summary> 2 /// 创建保存场景/另存场景面板 3 /// </summary> 4 /// <param name="titleName">面板主题名</param> 5 /// <param name="filePath">保存路径</param> 6 private void SaveOrSaveAsWindows(string titleName,Action<string> action) 7 { 8 SaveFile pth = new SaveFile(); 9 pth.structSize = System.Runtime.InteropServices.Marshal.SizeOf(pth); 10 pth.filter = "All Files\0 *.*\0\0";//是什么文件类型就修改此处 11 pth.file = new string(new char[256]); 12 pth.maxFile = pth.file.Length; 13 pth.fileTitle = new string(new char[64]); 14 pth.maxFileTitle = pth.fileTitle.Length; 15 pth.initialDir = Application.dataPath; // default path 16 pth.title = titleName; 17 pth.defExt = "json"; 18 pth.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008; 19 if (SaveFileWindow.GetSaveFileName(pth)) 20 { 21 string filepath = pth.file;//选择的文件路径; 22 action(filepath); 23 } 24 } 25 26 /// <summary> 27 /// 打开项目弹框 28 /// </summary> 29 /// <returns></returns> 30 private void OpenWindow(Action<string> action) 31 { 32 string filepath = ""; 33 OpenFile pth = new OpenFile(); 34 pth.structSize = System.Runtime.InteropServices.Marshal.SizeOf(pth); 35 // pth.filter = "JSON file(*.json)";//是什么文件类型就修改此处 36 pth.filter = "All Files\0*.*\0\0"; 37 pth.file = new string(new char[256]); 38 pth.maxFile = pth.file.Length; 39 pth.fileTitle = new string(new char[64]); 40 pth.maxFileTitle = pth.fileTitle.Length; 41 pth.initialDir = Application.dataPath; // default path 42 pth.title = "打开项目"; 43 pth.defExt = "json"; 44 45 //注意 一下项目不一定要全选 但是0x00000008项不要缺少 46 //0x00080000 是否使用新版文件选择窗口,0x00000200 是否可以多选文件 47 pth.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008; 48 49 if (OpenFileWindow.GetOpenFileName(pth)) 50 { 51 filepath = pth.file;//选择的文件路径; 52 action(filepath); 53 } 54 } 55 56 /// <summary> 57 /// 根据路径生成本地json文件 58 /// </summary> 59 /// <param name="filePath">写入的路径</param> 60 /// <param name="jsonData">写入的json数据</param> 61 private void WriteJsonFile(string filePath,JsonData jsonData) 62 { 63 //构建文件流,创建文件,若存在则覆盖 64 FileStream fileStream = new FileStream(filePath, FileMode.Create); 65 66 //构建写流,设置文件格式 67 StreamWriter sw = new StreamWriter(fileStream, Encoding.UTF8); 68 69 //ToJson接口将你的json数据传进去,并自动转换为string类型 70 string json = JsonMapper.ToJson(jsonData); 71 72 //将转好的json字符串写入文件 73 sw.WriteLine(json); 74 75 sw.Flush(); 76 77 //关流,释放资源 78 sw.Close(); 79 fileStream.Close(); 80 sw.Dispose(); 81 } 82 83 /// <summary> 84 /// 读取json文件 85 /// </summary> 86 /// <param name="path"></param> 87 /// <returns></returns> 88 private JsonData ReadJson(string path) 89 { 90 //构建读流,设置文件格式 91 StreamReader sr = new StreamReader(path); 92 93 //再转换成json数据 94 JsonReader json = new JsonReader(sr); 95 //读取json数据 96 JsonData data = JsonMapper.ToObject(json); 97 98 sr.Close(); 99 100 return data; 101 } 102 103 /// <summary> 104 /// 获取SceneName 105 /// </summary> 106 /// <param name="name">路径名字</param> 107 /// <returns></returns> 108 private string GetSceneName(string name) 109 { 110 string [] names= name.Split('\\'); 111 string myname=names[names.Length - 1].Split('.')[0]; 112 return myname; 113 }
效果:
打开:
保存:
<2>.去边框/设置窗口尺寸和位置
导入user32.dll的相关方法:
1 //设置窗口边框 2 [DllImport("user32.dll")] 3 public static extern IntPtr SetWindowLong(IntPtr hwnd, int _nIndex, int dwNewLong); 4 5 //设置窗口位置,尺寸 6 [DllImport("user32.dll")] 7 public static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); 8 9 [DllImport("user32.dll", SetLastError = true)] 10 private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
具体使用:
1 //边框参数 2 private const uint SWP_SHOWWINDOW = 0x0040; 3 private const int GWL_STYLE = -16; 4 private const int WS_BORDER = 1; 5 6 //隐藏标题栏图标 7 private const int WS_POPUP = 0x800000; 8 private const int WS_SYSMENU = 0x80000; 9 10 //最大最小化 11 private const int SW_SHOWMINIMIZED = 2;//(最小化窗口) 12 private const int SW_SHOWMAXIMIZED = 3;//最大化窗口 13 14 //去除标题栏保留边框 15 private const int WS_CAPTION = 0x00C00000; 16 private const int WS_THICKFRAME = 0x00040000; 17 18 //去除上边栏(不可拖拽缩放) 19 SetWindowLong(GetForegroundWindow(), GWL_STYLE, WS_POPUP); 20 21 22 23 //设置拖拽缩放模式(未完全去掉(参数控制,即GetWindowLong(GetForegroundWindow(), GWL_STYLE)& ~WS_CAPTION | WS_THICKFRAME))
24 SetWindowLong(GetForegroundWindow(), GWL_STYLE, GetWindowLong(GetForegroundWindow(), GWL_STYLE) 25 & ~WS_CAPTION | WS_THICKFRAME);
//设置窗口位置及分辨率
bool result = SetWindowPos(GetForegroundWindow(), 0, (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, SWP_SHOWWINDOW);
注:
1.windows下的窗口一旦去了上边栏(边框),就无法拖拽缩放了,边框和上边栏是一体的,所以拖拽功能要想保留不能直接去掉边框,当然可以自己写拖拽缩放,我试着写过,实现可以,但是无奈领导说最好使用原生的,我就放弃了。
2.还有一个坑,注意windows环境下,屏幕坐标原点(0,0)在左上角,不和unity中一样在左下角。
去边框上边框(自带白色上边框)效果:
<3>.最大化最小化窗口(没有上边框下,有的话就不用考虑这功能了)
导入user32.dll的相关方法以及参数:
1 //最大最小化 2 private const int SW_SHOWMINIMIZED = 2;//(最小化窗口) 3 private const int SW_SHOWMAXIMIZED = 3;//最大化窗口
//设置当前窗口的显示状态
[DllImport("user32.dll")]
public static extern bool ShowWindow(System.IntPtr hwnd, int nCmdShow);
使用:
1 /// <summary> 2 /// 最小化窗口 3 /// </summary> 4 public void SetMinWindows() 5 { 6 ShowWindow(GetForegroundWindow(), SW_SHOWMINIMIZED); 7 } 8 9 /// <summary> 10 /// 最大化窗口 11 /// </summary> 12 public void SetMaxWindows() 13 { 14 ShowWindow(GetForegroundWindow(), SW_SHOWMAXIMIZED); 15 }
注:这里的最大化窗口是指全屏铺满,如果想要那种普通exe的最大化(保留任务栏),需要自己去掉任务栏高再设置分辨率以及定位置
<4>.拖动窗口
导入user32.dll的相关方法:
1 //窗口拖动 2 [DllImport("user32.dll")] 3 public static extern bool ReleaseCapture(); 4 [DllImport("user32.dll")] 5 public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 6 7 //获取当前激活窗口 8 [DllImport("user32.dll", EntryPoint = "GetForegroundWindow")] 9 public static extern System.IntPtr GetForegroundWindow();
使用:
/// <summary> /// 拖动窗口 /// </summary> /// <param name="window">当前句柄</param> public void DragWindow(IntPtr window) { ReleaseCapture(); SendMessage(window, 0xA1, 0x02, 0); SendMessage(window, 0x0202, 0, 0); }
注:里面参数都是默认的,无需改(重点是很多参数,想搞明白去查下user32 的API)。
<5>.更改标题栏
导入user32.dll的相关方法:
1 //更改标题栏 2 [DllImport("user32.dll")] 3 public static extern int SetWindowText(IntPtr hWnd, string text);
1 /// <summary> 2 /// 改变标题栏标题 3 /// </summary> 4 public void ChangeTitleText() 5 { 6 SetWindowText(GetForegroundWindow(), string.Empty); 7 }
<6>.查找任务栏,并获取任务栏高度(这个需求是因为该库中最大化是指全屏铺满,但是我们需要的最大化时保留下方任务栏)
导入user32.dll的相关方法:
1 //使用查找任务栏 2 [DllImport("user32.dll")] 3 public static extern IntPtr FindWindow(string strClassName, int nptWindowName);
1 /// <summary> 2 /// 获取任务栏高度 3 /// </summary> 4 /// <returns>任务栏高度</returns> 5 private int GetTaskBarHeight() 6 { 7 int taskbarHeight = 10; 8 IntPtr hWnd = FindWindow("Shell_TrayWnd", 0); 9 RECT rect = new RECT(); 10 GetWindowRect(hWnd, ref rect); 11 taskbarHeight = rect.Bottom - rect.Top; 12 return taskbarHeight; 13 }
此时设置想要保留任务栏的最大化:
1 /// <summary> 2 /// 最大化窗口 3 /// </summary> 4 public void SetMaxWindows() 5 { 6 int currMaxScreenHeight = Screen.currentResolution.height - GetTaskBarHeight(); 7 SetWindowPos(GetForegroundWindow(), 0, 0, 0, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 8 // ShowWindow(GetForegroundWindow(), SW_SHOWMAXIMIZED); 9 }
注:Screen.currentResolution.height 当前设备高,Screen.currentResolution.width 当前设备宽
保留任务栏最大化效果:
<7>.获取当前窗口句柄的分辨率
导入user32.dll的相关方法:
1 //获取窗口位置以及大小 2 [DllImport("user32.dll")] 3 [return: MarshalAs(UnmanagedType.Bool)] 4 public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); 5 [StructLayout(LayoutKind.Sequential)] 6 public struct RECT 7 { 8 public int Left; //最左坐标 9 public int Top; //最上坐标 10 public int Right; //最右坐标 11 public int Bottom; //最下坐标 12 }
使用:
1 /// <summary> 2 /// 获取当前窗口尺寸 3 /// </summary> 4 /// <returns></returns> 5 public Rect GetWindowInfo() 6 { 7 RECT rect = new RECT(); 8 Rect targetRect = new Rect(); 9 GetWindowRect(GetForegroundWindow(), ref rect); 10 targetRect.width = Mathf.Abs(rect.Right - rect.Left); 11 targetRect.height = Mathf.Abs(rect.Top - rect.Bottom);
//锚点在左上角 12 targetRect.x = rect.Left; 13 targetRect.y = rect.Top; 14 return targetRect; 15 }
注:锚点在左上角 targetRect.x = rect.Left; targetRect.y = rect.Top;所以拿的是左上。
完整代码:
1 /// <summary> 2 /// 窗口工具系统类(窗口状态) 3 /// </summary> 4 public class WindowsTool 5 { 6 7 #region 系统字段 & 系统方法 8 9 //设置当前窗口的显示状态 10 [DllImport("user32.dll")] 11 public static extern bool ShowWindow(System.IntPtr hwnd, int nCmdShow); 12 13 //获取当前激活窗口 14 [DllImport("user32.dll", EntryPoint = "GetForegroundWindow")] 15 public static extern System.IntPtr GetForegroundWindow(); 16 17 //设置窗口边框 18 [DllImport("user32.dll")] 19 public static extern IntPtr SetWindowLong(IntPtr hwnd, int _nIndex, int dwNewLong); 20 21 //设置窗口位置,尺寸 22 [DllImport("user32.dll")] 23 public static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); 24 25 [DllImport("user32.dll", SetLastError = true)] 26 private static extern int GetWindowLong(IntPtr hWnd, int nIndex); 27 28 //窗口拖动 29 [DllImport("user32.dll")] 30 public static extern bool ReleaseCapture(); 31 [DllImport("user32.dll")] 32 public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 33 34 //更改标题栏 35 [DllImport("user32.dll")] 36 public static extern int SetWindowText(IntPtr hWnd, string text); 37 38 //使用查找任务栏 39 [DllImport("user32.dll")] 40 public static extern IntPtr FindWindow(string strClassName, int nptWindowName); 41 42 //获取窗口位置以及大小 43 [DllImport("user32.dll")] 44 [return: MarshalAs(UnmanagedType.Bool)] 45 public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); 46 [StructLayout(LayoutKind.Sequential)] 47 public struct RECT 48 { 49 public int Left; //最左坐标 50 public int Top; //最上坐标 51 public int Right; //最右坐标 52 public int Bottom; //最下坐标 53 } 54 55 //边框参数 56 private const uint SWP_SHOWWINDOW = 0x0040; 57 private const int GWL_STYLE = -16; 58 private const int WS_BORDER = 1; 59 60 //隐藏标题栏图标 61 private const int WS_POPUP = 0x800000; 62 private const int WS_SYSMENU = 0x80000; 63 64 //最大最小化 65 private const int SW_SHOWMINIMIZED = 2;//(最小化窗口) 66 private const int SW_SHOWMAXIMIZED = 3;//最大化窗口 67 68 //去除标题栏保留边框 69 private const int WS_CAPTION = 0x00C00000; 70 private const int WS_THICKFRAME = 0x00040000; 71 72 #endregion 73 74 #region 方法 75 76 /// <summary> 77 /// 最小化窗口 78 /// </summary> 79 public void SetMinWindows() 80 { 81 ShowWindow(GetForegroundWindow(), SW_SHOWMINIMIZED); 82 } 83 84 /// <summary> 85 /// 最大化窗口 86 /// </summary> 87 public void SetMaxWindows() 88 { 89 int currMaxScreenHeight = Screen.currentResolution.height - GetTaskBarHeight(); 90 SetWindowPos(GetForegroundWindow(), 0, 0, 0, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 91 // ShowWindow(GetForegroundWindow(), SW_SHOWMAXIMIZED); 92 } 93 94 /// <summary> 95 /// 设置无边框,窗口位置及分辨率 96 /// </summary> 97 /// <param name="rect">尺寸数据</param> 98 public void SetNoFrameWindow(Rect rect, bool isMax, bool isDrag = false) 99 { 100 if (!isDrag) 101 { 102 //去除上边栏(不可拖拽缩放) 103 SetWindowLong(GetForegroundWindow(), GWL_STYLE, WS_POPUP); 104 } 105 else 106 { 107 if (!isMax) 108 { 109 //设置拖拽缩放模式 110 SetWindowLong(GetForegroundWindow(), GWL_STYLE, GetWindowLong(GetForegroundWindow(), GWL_STYLE) 111 & ~WS_CAPTION | WS_THICKFRAME); 112 } 113 else { 114 //去除上边栏(不可拖拽缩放) 115 SetWindowLong(GetForegroundWindow(), GWL_STYLE, WS_POPUP); 116 } 117 } 118 119 //隐藏上边栏(部分) 120 // SetWindowLong(GetForegroundWindow(), GWL_STYLE, GetWindowLong(GetForegroundWindow(), GWL_STYLE) & ~WS_POPUP); 121 122 if (isMax) 123 { 124 SetMaxWindows(); 125 } 126 else 127 { 128 //设置窗口位置及分辨率 129 bool result = SetWindowPos(GetForegroundWindow(), 0, (int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height, SWP_SHOWWINDOW); 130 } 131 } 132 133 /// <summary> 134 /// 拖动窗口 135 /// </summary> 136 /// <param name="window">当前句柄</param> 137 public void DragWindow(IntPtr window) 138 { 139 ReleaseCapture(); 140 SendMessage(window, 0xA1, 0x02, 0); 141 SendMessage(window, 0x0202, 0, 0); 142 } 143 144 /// <summary> 145 /// 改变标题栏标题 146 /// </summary> 147 public void ChangeTitleText() 148 { 149 SetWindowText(GetForegroundWindow(), string.Empty); 150 } 151 152 /// <summary> 153 /// 获取当前窗口尺寸 154 /// </summary> 155 /// <returns></returns> 156 public Rect GetWindowInfo() 157 { 158 RECT rect = new RECT(); 159 Rect targetRect = new Rect(); 160 GetWindowRect(GetForegroundWindow(), ref rect); 161 targetRect.width = Mathf.Abs(rect.Right - rect.Left); 162 targetRect.height = Mathf.Abs(rect.Top - rect.Bottom); 163 targetRect.x = rect.Left; 164 targetRect.y = rect.Top; 165 return targetRect; 166 } 167 168 #endregion 169 170 #region Private Methods 171 172 /// <summary> 173 /// 获取任务栏高度 174 /// </summary> 175 /// <returns>任务栏高度</returns> 176 private int GetTaskBarHeight() 177 { 178 int taskbarHeight = 10; 179 IntPtr hWnd = FindWindow("Shell_TrayWnd", 0); 180 RECT rect = new RECT(); 181 GetWindowRect(hWnd, ref rect); 182 taskbarHeight = rect.Bottom - rect.Top; 183 return taskbarHeight; 184 } 185 186 #endregion 187 }
最新:发布后windows扩展模式下窗体显示错乱不对的情况?
几种扩展特殊扩展屏幕方式,比如:
这四种方式,大家都知道,扩展屏就是在原有基本尺寸屏幕上,扩了一定尺寸的屏幕显示,实质上还是一个屏(计算机内部认为)
初步分析下:
1.左右扩展:往左扩展就在X方向减去初始屏幕的分辨率宽,往右扩展就在X方向加上初始屏幕的分辨率宽。
2.上下扩展:往上扩展就在Y方向加上初始屏幕的分辨率高,往下扩展就在Y方向减去初始屏幕的分辨率高。
姑且这样认为。测试一下,这个地方的坐标是不是我们认为的这种(左-,右+,上+,下-),这个地方我测了下,如图:
1区(X>0 & Y<0),2区(X<0 & Y<0),3区(X<0 & Y>0),5区(X>0 & Y>0),4区是窗口区域,左上角是窗口锚点o(0,0)点。
原则搞清楚了不是我们想的那样。按我们上面分析的,到这里你可以解决上述四种扩展方式屏幕的问题,但是,恶心的事发生了(一直没注意),扩展屏幕的排列方式很自由,比如:
图1.
图2.
图3.
图4.
瞬间让我感觉windows太JB没底线了,给老子加难度。
下面再仔细分析一下还有什么问题?
我想知道这俩排列的高度差,也就是分屏的信息,主机连接了几个显示器?各自分辨率是多少?屏幕锚点坐标是什么?我们需要这些信息!不然根本没法确定窗口位置。
Unity中获取主机连接了几个显示器,显示器的分辨率以及位置这些是没提供给我们相应的API的。
有人说有Resolution[] resolutions = Screen.resolutions;
这不是所有显示器分辨率列表
这是说明,自己看看,也可以试试,绝不是你想象中的那样亦或者你仅仅可以获取当前屏幕的分辨率。
还有人说Display这是unity中的分屏处理,具体自己去查查吧,比较官方。
所以这里我使用了WinForm中的API,即主要是System.Windows.Forms.dll这个库中的Screen.AllScreens函数获取显示器信息,显示器数量,位置,分辨率等信息。
间接引用到System.Drawing.dll但是在引用这个库时遇到诸多问题:
1.System.Windows.Forms.dll正常引用方式引用不进来(在vs“引用”中直接应用,原因不详,可能是与问题2所说的有关系),只能将System.Windows.Forms.dll放到工程中来,在Plugins下,当作其他那种dll用
2.由于.NET类库System.Drawing.dll提供了一系列的图形函数,但由于其使用的是GDI接口,与DirectX和OpenGL之间不兼容,在Unity中默认是不被支持的。引用方式如1.
3.引用进来后打包出错,或者导进去直接报错(具体忘记是什么了),找到playerSetting中的Other Settings中的改成如图。(还有错误就重启Unity,可能需要重新配置)
我记忆中会有以上的三个问题,最后我的解决方案是:
1.无需将这两个DLL放入工程
2.写一名为csc.rsp的文件,内容是-r:System.Windows.Forms.dll -r:System.Drawing.dll。-r开头,想引用多个dll就空格后继续-r,然后将这文件放到Assets文件夹下(根目录)然后就搞定了,引用成功。
具体代码:
获取第一显示器的锚点和分辨率
//Y坐标
int Y = System.Windows.Forms.Screen.AllScreens[0].Bounds.Y; //X坐标
int X = System.Windows.Forms.Screen.AllScreens[0].Bounds.X; //高度
int height = System.Windows.Forms.Screen.AllScreens[0].Bounds.Height; //宽度
int width = System.Windows.Forms.Screen.AllScreens[0].Bounds.Width;
最大化窗口(不同显示器定位搞定):
App.initDeviceWidth 初始显示器宽,
App.initDeviceHeight 初始显示器高
(里面没说明的函数,上面去找)
1 /// <summary> 2 /// 最大化窗口 3 /// </summary> 4 public void SetMaxWindows() 5 { 8 int currMaxScreenHeight = Screen.currentResolution.height - GetTaskBarHeight(); 9 Rect rect = GetWindowInfo(); 10 Y = System.Windows.Forms.Screen.AllScreens[0].Bounds.Y; 11 X = System.Windows.Forms.Screen.AllScreens[0].Bounds.X; 12 height = System.Windows.Forms.Screen.AllScreens[0].Bounds.Height; 13 width = System.Windows.Forms.Screen.AllScreens[0].Bounds.Width; 14 15 //右 16 if (rect.x >= App.initDeviceWidth) 17 { 18 if (Y < 0)//上 19 { 20 SetWindowPos(GetForegroundWindow(), 0, (int)(width - App.initDeviceWidth), Y, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 21 } 22 else 23 { 24 SetWindowPos(GetForegroundWindow(), 0, (int)App.initDeviceWidth, (int)(height - App.initDeviceHeight), Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 25 } 26 return; 27 } 28 else if (rect.x < 0)//左 29 { 30 //上 31 if (Y < 0) 32 { 33 SetWindowPos(GetForegroundWindow(), 0, X, Y, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 34 } 35 else 36 { 37 SetWindowPos(GetForegroundWindow(), 0, -(int)App.initDeviceWidth, (int)(height - App.initDeviceHeight), Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 38 } 39 return; 40 } 41 else if (rect.y >= App.initDeviceHeight || rect.y < 0) 42 { 43 //正下 44 if (Y == 0) 45 { 46 SetWindowPos(GetForegroundWindow(), 0, 0, (int)App.initDeviceHeight, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 47 } 48 else 49 { 50 SetWindowPos(GetForegroundWindow(), 0, 0, -(int)App.initDeviceHeight, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 51 } 52 return; 53 } 54 else 55 { 56 SetWindowPos(GetForegroundWindow(), 0, 0, 0, Screen.currentResolution.width, currMaxScreenHeight, SWP_SHOWWINDOW); 57 } 58 }
显示器信息拿到了,设置位置就全是算数问题了,
但是有如下几坑:
1.如上图1234,扩展屏这个地方拿到的是Hright和width其实是下图的黑框大小(默认为组合屏的(两个屏幕的最外围矩形)尺寸),位置xy指的红圈处的坐标
2.图1这种情况左上角锚点(x=0 &y<0),图2这种情况左上角锚点(x=0 &y=0),图3这种情况左上角锚点(x<0 &y<0),图4这种情况左上角锚点(x<0 &y=0)
图二和图四是坑,容易想错,注意!!!
完美解决!
最新问题:上面一系列操作最近遇到了一点问题,就是使用获取窗口的方式用的有错误,我使用的是获取当前激活窗口GetForegroundWindow();在你切换exe时,可能操作的窗口就不是你原本想操作的那个窗口了,我们应该使用一个方法,获取指定窗口,无论你切换到哪个窗口都不能影响,这个方法是FindWindow();
具体方法:
//获取指定unity.exe窗口 [DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); public static IntPtr ParenthWnd = FindWindow(null, "ProjectName"); //build时候的项目名,playerSetting中设置的
用这个方法替换掉GetForegroundWindow()就可以解决了,这样就可以避免由于切换窗口失去指定窗口句柄的问题。
最新问题:Unity中调用windows窗口对文件进行筛选功能,文件类型自定义。如:
主要是:设置filter,并且结合pth.filterIndex去选择使用生成的类型列表中的第几个(注意是从1开始的)。
1 //\0字符串分隔符(多个根据\0分割的字符串形成下拉列表); 2 //pth.filter = "JSON file(*.json)\0*.json\0FBX file(*.fbx)\0*.fbx\0"; //* \0*.fbx"; 3 //;是&的作用 1:.json;.fbx;.gltf 2:.json 3:.fbx 4:.gltf 5:PNG 6:All Files 4 pth.filter = "模型文件(*.json|*.fbx|*.gltf)\0*.json;*.fbx;*.gltf\0JSON file(*.json)\0*.json\0FBX file(*.fbx)\0*.fbx\0GLTF file(*.gltf)\0*.gltf\0PNG file(*.png)\0*.png\0All Files\0*.*\0\0";
完整代码:
1 /// <summary> 2 /// 文件过滤器类型 3 /// </summary> 4 public enum FileFilterType 5 { 6 7 /// <summary> 8 /// 模型文件(.json/.gltf/.fbx) 1 9 /// </summary> 10 Model_File, 11 12 /// <summary> 13 /// json文件(.json) 2 14 /// </summary> 15 JSON_File, 16 17 /// <summary> 18 /// FBX文件(.fbx) 3 19 /// </summary> 20 FBX_File, 21 22 /// <summary> 23 /// GLTF文件(.gltf) 4 24 /// </summary> 25 GLTF_File, 26 27 /// <summary> 28 /// PNG文件(.png) 5 29 /// </summary> 30 PNG_File, 31 32 /// <summary> 33 /// ALLFile 6 34 /// </summary> 35 AllFile, 36 } 37 38 /// <summary> 39 /// 打开项目弹框 40 /// </summary> 41 /// <returns></returns> 42 private void OpenWindow(string foldName, FileFilterType fileFilterType, string defExtString, Action<string> action) 43 { 44 string filepath = ""; 45 OpenFile pth = new OpenFile(); 46 pth.structSize = System.Runtime.InteropServices.Marshal.SizeOf(pth); 47 48 //\0字符串分隔符(多个根据\0分割的字符串形成下拉列表); 49 //pth.filter = "JSON file(*.json)\0*.json\0FBX file(*.fbx)\0*.fbx\0"; //* \0*.fbx"; 50 //;是&的作用 1:.json;.fbx;.gltf 2:.json 3:.fbx 4:.gltf 5:PNG 6:All Files 51 pth.filter = "模型文件(*.json|*.fbx|*.gltf)\0*.json;*.fbx;*.gltf\0JSON file(*.json)\0*.json\0FBX file(*.fbx)\0*.fbx\0GLTF file(*.gltf)\0*.gltf\0PNG file(*.png)\0*.png\0All Files\0*.*\0\0"; 52 pth.filterIndex = ((int)fileFilterType + 1); 53 pth.file = new string(new char[256]); 54 pth.maxFile = pth.file.Length; 55 pth.fileTitle = new string(new char[64]); 56 pth.maxFileTitle = pth.fileTitle.Length; 57 pth.initialDir = Application.dataPath; // default path 58 pth.title = foldName; 59 pth.defExt = defExtString; 60 61 //注意 一下项目不一定要全选 但是0x00000008项不要缺少 62 //0x00080000 是否使用新版文件选择窗口,0x00000200 是否可以多选文件 63 pth.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000200 | 0x00000008; 64 65 if (OpenFileWindow.GetOpenFileName(pth)) 66 { 67 filepath = pth.file;//选择的文件路径; 68 action(filepath); 69 } 70 }
欢迎交流指正。