Tanoda
MinimumWindowSize.cs
Go to the documentation of this file.
1using System;
2using System.Runtime.InteropServices;
3
4public static class MinimumWindowSize {
5 // This code works exclusively with standalone build.
6 // Executing GetActiveWindow in unity editor returns editor window.
7 #if !UNITY_EDITOR && !UNITY_WEBGL
8
9 private const int DefaultValue = -1;
10
11 // Identifier of MINMAXINFO message
12 private const uint WM_GETMINMAXINFO = 0x0024;
13
14 // SetWindowLongPtr argument : Sets a new address for the window procedure.
15 private const int GWLP_WNDPROC = -4;
16
17 private static int width;
18 private static int height;
19 private static bool enabled;
20
21 // Reference to current window
22 private static HandleRef hMainWindow;
23
24 // Reference to unity WindowsProcedure handler
25 private static IntPtr unityWndProcHandler;
26
27 // Reference to custom WindowsProcedure handler
28 private static IntPtr customWndProcHandler;
29
30 // Delegate signature for WindowsProcedure
31 private delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
32
33 // Instance of delegate
34 private static WndProcDelegate procDelegate;
35
36 [StructLayout(LayoutKind.Sequential)]
37 private struct Minmaxinfo {
38 public Point ptReserved;
39 public Point ptMaxSize;
40 public Point ptMaxPosition;
41 public Point ptMinTrackSize;
42 public Point ptMaxTrackSize;
43 }
44
45 private struct Point {
46 public int x;
47 public int y;
48 }
49 #endif
50
51
52 public static void Set(int minWidth, int minHeight){
53 #if !UNITY_EDITOR && !UNITY_WEBGL
54 if (minWidth < 0 || minHeight < 0) throw new ArgumentException("Any component of min size cannot be less than 0");
55
56 width = minWidth;
57 height = minHeight;
58
59 if(enabled) return;
60
61 // Get reference
62 hMainWindow = new HandleRef(null, GetActiveWindow());
63 procDelegate = WndProc;
64 // Generate handler
65 customWndProcHandler = Marshal.GetFunctionPointerForDelegate(procDelegate);
66 // Replace unity mesages handler with custom
67 unityWndProcHandler = SetWindowLongPtr(hMainWindow, GWLP_WNDPROC, customWndProcHandler);
68
69 enabled = true;
70 #endif
71 }
72
73 public static void Reset(){
74 #if !UNITY_EDITOR && !UNITY_WEBGL
75 if(!enabled) return;
76 // Replace custom message handler with unity handler
77 SetWindowLongPtr(hMainWindow, GWLP_WNDPROC, unityWndProcHandler);
78 hMainWindow = new HandleRef(null, IntPtr.Zero);
79 unityWndProcHandler = IntPtr.Zero;
80 customWndProcHandler = IntPtr.Zero;
81 procDelegate = null;
82
83 width = 0;
84 height = 0;
85
86 enabled = false;
87 #endif
88 }
89
90 #if !UNITY_EDITOR && !UNITY_WEBGL
91
92 private static IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam){
93 // All messages except WM_GETMINMAXINFO will send to unity handler
94 if (msg != WM_GETMINMAXINFO) return CallWindowProc(unityWndProcHandler, hWnd, msg, wParam, lParam);
95
96 // Intercept and change MINMAXINFO message
97 var x = (Minmaxinfo) Marshal.PtrToStructure(lParam, typeof(Minmaxinfo));
98 x.ptMinTrackSize = new Point{x = width, y = height};
99 Marshal.StructureToPtr(x, lParam, false);
100
101 // Send changed message
102 return DefWindowProc(hWnd, msg, wParam, lParam);
103 }
104
105 [DllImport("user32.dll")]
106 private static extern IntPtr GetActiveWindow();
107
108 [DllImport("user32.dll", EntryPoint = "CallWindowProcA")]
109 private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint wMsg, IntPtr wParam,
110 IntPtr lParam);
111
112 [DllImport("user32.dll", EntryPoint = "DefWindowProcA")]
113 private static extern IntPtr DefWindowProc(IntPtr hWnd, uint wMsg, IntPtr wParam, IntPtr lParam);
114
115 private static IntPtr SetWindowLongPtr(HandleRef hWnd, int nIndex, IntPtr dwNewLong){
116 if (IntPtr.Size == 8) return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
117 return new IntPtr(SetWindowLong32(hWnd, nIndex, dwNewLong.ToInt32()));
118 }
119
120 [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
121 private static extern int SetWindowLong32(HandleRef hWnd, int nIndex, int dwNewLong);
122
123 [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr")]
124 private static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, IntPtr dwNewLong);
125 #endif
126}