問題背景:
現在在搞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 }
歡迎交流指正。
