问题背景:
现在在搞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 }
欢迎交流指正。
