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         }
View Code

 效果:

打開:

 保存:

<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     }
View Code

 

 

 

最新:發布后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         }

 

 

歡迎交流指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM