Tanoda
B83.Win32.cs
Go to the documentation of this file.
1/* * * * *
2 * This is a collection of Win API helpers. Mainly dealing with window message hooks
3 * and file drag&drop support for Windows standalone Unity applications.
4 *
5 * 2019.11.28 - Changed the "UnityDragAndDropHook" class to a static class. This
6 * has been done for IL2CPP support. IL2CPP can not marshall instance method
7 * callbacks passed to native code. So the callbacks must be static methods.
8 * Therefore all fields involved also need to be static.
9 *
10 * The MIT License (MIT)
11 *
12 * Copyright (c) 2018 Markus Göbel (Bunny83)
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this software and associated documentation files (the "Software"), to deal
16 * in the Software without restriction, including without limitation the rights
17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18 * copies of the Software, and to permit persons to whom the Software is
19 * furnished to do so, subject to the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in all
22 * copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 *
32 * * * * */
33using System;
34using System.Collections.Generic;
35using System.Runtime.InteropServices;
36
37namespace B83.Win32
38{
39 public enum HookType : int
40 {
43 WH_KEYBOARD = 2,
44 WH_GETMESSAGE = 3,
46 WH_CBT = 5,
48 WH_MOUSE = 7,
49 WH_HARDWARE = 8,
50 WH_DEBUG = 9,
51 WH_SHELL = 10,
54 WH_KEYBOARD_LL = 13,
55 WH_MOUSE_LL = 14
56 }
57
58 // windows messages
59 public enum WM : uint
60 {
61 NULL = 0x0000,
62 CREATE = 0x0001,
63 DESTROY = 0x0002,
64 MOVE = 0x0003,
65 SIZE = 0x0005,
66 ACTIVATE = 0x0006,
67 SETFOCUS = 0x0007,
68 KILLFOCUS = 0x0008,
69 ENABLE = 0x000A,
70 SETREDRAW = 0x000B,
71 SETTEXT = 0x000C,
72 GETTEXT = 0x000D,
73 GETTEXTLENGTH = 0x000E,
74 PAINT = 0x000F,
75 CLOSE = 0x0010,
76 QUERYENDSESSION = 0x0011,
77 QUERYOPEN = 0x0013,
78 ENDSESSION = 0x0016,
79 QUIT = 0x0012,
80 ERASEBKGND = 0x0014,
81 SYSCOLORCHANGE = 0x0015,
82 SHOWWINDOW = 0x0018,
83 WININICHANGE = 0x001A,
85 DEVMODECHANGE = 0x001B,
86 ACTIVATEAPP = 0x001C,
87 FONTCHANGE = 0x001D,
88 TIMECHANGE = 0x001E,
89 CANCELMODE = 0x001F,
90 SETCURSOR = 0x0020,
91 MOUSEACTIVATE = 0x0021,
92 CHILDACTIVATE = 0x0022,
93 QUEUESYNC = 0x0023,
94 GETMINMAXINFO = 0x0024,
95 PAINTICON = 0x0026,
96 ICONERASEBKGND = 0x0027,
97 NEXTDLGCTL = 0x0028,
98 SPOOLERSTATUS = 0x002A,
99 DRAWITEM = 0x002B,
100 MEASUREITEM = 0x002C,
101 DELETEITEM = 0x002D,
102 VKEYTOITEM = 0x002E,
103 CHARTOITEM = 0x002F,
104 SETFONT = 0x0030,
105 GETFONT = 0x0031,
106 SETHOTKEY = 0x0032,
107 GETHOTKEY = 0x0033,
108 QUERYDRAGICON = 0x0037,
109 COMPAREITEM = 0x0039,
110 GETOBJECT = 0x003D,
111 COMPACTING = 0x0041,
112 [Obsolete]
113 COMMNOTIFY = 0x0044,
114 WINDOWPOSCHANGING = 0x0046,
115 WINDOWPOSCHANGED = 0x0047,
116 [Obsolete]
117 POWER = 0x0048,
118 COPYDATA = 0x004A,
119 CANCELJOURNAL = 0x004B,
120 NOTIFY = 0x004E,
121 INPUTLANGCHANGEREQUEST = 0x0050,
122 INPUTLANGCHANGE = 0x0051,
123 TCARD = 0x0052,
124 HELP = 0x0053,
125 USERCHANGED = 0x0054,
126 NOTIFYFORMAT = 0x0055,
127 CONTEXTMENU = 0x007B,
128 STYLECHANGING = 0x007C,
129 STYLECHANGED = 0x007D,
130 DISPLAYCHANGE = 0x007E,
131 GETICON = 0x007F,
132 SETICON = 0x0080,
133 NCCREATE = 0x0081,
134 NCDESTROY = 0x0082,
135 NCCALCSIZE = 0x0083,
136 NCHITTEST = 0x0084,
137 NCPAINT = 0x0085,
138 NCACTIVATE = 0x0086,
139 GETDLGCODE = 0x0087,
140 SYNCPAINT = 0x0088,
141 NCMOUSEMOVE = 0x00A0,
142 NCLBUTTONDOWN = 0x00A1,
143 NCLBUTTONUP = 0x00A2,
144 NCLBUTTONDBLCLK = 0x00A3,
145 NCRBUTTONDOWN = 0x00A4,
146 NCRBUTTONUP = 0x00A5,
147 NCRBUTTONDBLCLK = 0x00A6,
148 NCMBUTTONDOWN = 0x00A7,
149 NCMBUTTONUP = 0x00A8,
150 NCMBUTTONDBLCLK = 0x00A9,
151 NCXBUTTONDOWN = 0x00AB,
152 NCXBUTTONUP = 0x00AC,
153 NCXBUTTONDBLCLK = 0x00AD,
154 INPUT_DEVICE_CHANGE = 0x00FE,
155 INPUT = 0x00FF,
156 KEYFIRST = 0x0100,
157 KEYDOWN = 0x0100,
158 KEYUP = 0x0101,
159 CHAR = 0x0102,
160 DEADCHAR = 0x0103,
161 SYSKEYDOWN = 0x0104,
162 SYSKEYUP = 0x0105,
163 SYSCHAR = 0x0106,
164 SYSDEADCHAR = 0x0107,
165 UNICHAR = 0x0109,
166 KEYLAST = 0x0108,
167 IME_STARTCOMPOSITION = 0x010D,
168 IME_ENDCOMPOSITION = 0x010E,
169 IME_COMPOSITION = 0x010F,
170 IME_KEYLAST = 0x010F,
171 INITDIALOG = 0x0110,
172 COMMAND = 0x0111,
173 SYSCOMMAND = 0x0112,
174 TIMER = 0x0113,
175 HSCROLL = 0x0114,
176 VSCROLL = 0x0115,
177 INITMENU = 0x0116,
178 INITMENUPOPUP = 0x0117,
179 MENUSELECT = 0x011F,
180 MENUCHAR = 0x0120,
181 ENTERIDLE = 0x0121,
182 MENURBUTTONUP = 0x0122,
183 MENUDRAG = 0x0123,
184 MENUGETOBJECT = 0x0124,
185 UNINITMENUPOPUP = 0x0125,
186 MENUCOMMAND = 0x0126,
187 CHANGEUISTATE = 0x0127,
188 UPDATEUISTATE = 0x0128,
189 QUERYUISTATE = 0x0129,
190 CTLCOLORMSGBOX = 0x0132,
191 CTLCOLOREDIT = 0x0133,
192 CTLCOLORLISTBOX = 0x0134,
193 CTLCOLORBTN = 0x0135,
194 CTLCOLORDLG = 0x0136,
195 CTLCOLORSCROLLBAR = 0x0137,
196 CTLCOLORSTATIC = 0x0138,
197 MOUSEFIRST = 0x0200,
198 MOUSEMOVE = 0x0200,
199 LBUTTONDOWN = 0x0201,
200 LBUTTONUP = 0x0202,
201 LBUTTONDBLCLK = 0x0203,
202 RBUTTONDOWN = 0x0204,
203 RBUTTONUP = 0x0205,
204 RBUTTONDBLCLK = 0x0206,
205 MBUTTONDOWN = 0x0207,
206 MBUTTONUP = 0x0208,
207 MBUTTONDBLCLK = 0x0209,
208 MOUSEWHEEL = 0x020A,
209 XBUTTONDOWN = 0x020B,
210 XBUTTONUP = 0x020C,
211 XBUTTONDBLCLK = 0x020D,
212 MOUSEHWHEEL = 0x020E,
213 MOUSELAST = 0x020E,
214 PARENTNOTIFY = 0x0210,
215 ENTERMENULOOP = 0x0211,
216 EXITMENULOOP = 0x0212,
217 NEXTMENU = 0x0213,
218 SIZING = 0x0214,
219 CAPTURECHANGED = 0x0215,
220 MOVING = 0x0216,
221 POWERBROADCAST = 0x0218,
222 DEVICECHANGE = 0x0219,
223 MDICREATE = 0x0220,
224 MDIDESTROY = 0x0221,
225 MDIACTIVATE = 0x0222,
226 MDIRESTORE = 0x0223,
227 MDINEXT = 0x0224,
228 MDIMAXIMIZE = 0x0225,
229 MDITILE = 0x0226,
230 MDICASCADE = 0x0227,
231 MDIICONARRANGE = 0x0228,
232 MDIGETACTIVE = 0x0229,
233 MDISETMENU = 0x0230,
234 ENTERSIZEMOVE = 0x0231,
235 EXITSIZEMOVE = 0x0232,
236 DROPFILES = 0x0233,
237 MDIREFRESHMENU = 0x0234,
238 IME_SETCONTEXT = 0x0281,
239 IME_NOTIFY = 0x0282,
240 IME_CONTROL = 0x0283,
241 IME_COMPOSITIONFULL = 0x0284,
242 IME_SELECT = 0x0285,
243 IME_CHAR = 0x0286,
244 IME_REQUEST = 0x0288,
245 IME_KEYDOWN = 0x0290,
246 IME_KEYUP = 0x0291,
247 MOUSEHOVER = 0x02A1,
248 MOUSELEAVE = 0x02A3,
249 NCMOUSEHOVER = 0x02A0,
250 NCMOUSELEAVE = 0x02A2,
251 WTSSESSION_CHANGE = 0x02B1,
252 TABLET_FIRST = 0x02c0,
253 TABLET_LAST = 0x02df,
254 CUT = 0x0300,
255 COPY = 0x0301,
256 PASTE = 0x0302,
257 CLEAR = 0x0303,
258 UNDO = 0x0304,
259 RENDERFORMAT = 0x0305,
260 RENDERALLFORMATS = 0x0306,
261 DESTROYCLIPBOARD = 0x0307,
262 DRAWCLIPBOARD = 0x0308,
263 PAINTCLIPBOARD = 0x0309,
264 VSCROLLCLIPBOARD = 0x030A,
265 SIZECLIPBOARD = 0x030B,
266 ASKCBFORMATNAME = 0x030C,
267 CHANGECBCHAIN = 0x030D,
268 HSCROLLCLIPBOARD = 0x030E,
269 QUERYNEWPALETTE = 0x030F,
270 PALETTEISCHANGING = 0x0310,
271 PALETTECHANGED = 0x0311,
272 HOTKEY = 0x0312,
273 PRINT = 0x0317,
274 PRINTCLIENT = 0x0318,
275 APPCOMMAND = 0x0319,
276 THEMECHANGED = 0x031A,
277 CLIPBOARDUPDATE = 0x031D,
278 DWMCOMPOSITIONCHANGED = 0x031E,
279 DWMNCRENDERINGCHANGED = 0x031F,
282 GETTITLEBARINFOEX = 0x033F,
283 HANDHELDFIRST = 0x0358,
284 HANDHELDLAST = 0x035F,
285 AFXFIRST = 0x0360,
286 AFXLAST = 0x037F,
287 PENWINFIRST = 0x0380,
288 PENWINLAST = 0x038F,
289 APP = 0x8000,
290 USER = 0x0400,
291 CPL_LAUNCH = USER + 0x1000,
292 CPL_LAUNCHED = USER + 0x1001,
293 SYSTIMER = 0x118,
294 }
295
296 // WH_CALLWNDPROC
297 [StructLayout(LayoutKind.Sequential)]
298 public struct CWPSTRUCT
299 {
300 public IntPtr lParam;
301 public IntPtr wParam;
302 public WM message;
303 public IntPtr hwnd;
304 }
305
306 [StructLayout(LayoutKind.Sequential)]
307 public struct POINT
308 {
309 public int x, y;
310 public POINT(int aX, int aY)
311 {
312 x = aX;
313 y = aY;
314 }
315 public override string ToString()
316 {
317 return "(" + x + ", " + y + ")";
318 }
319 }
320
321 //WH_GETMESSAGE
322 [StructLayout(LayoutKind.Sequential)]
323 public struct MSG
324 {
325 public IntPtr hwnd;
326 public WM message;
327 public IntPtr wParam;
328 public IntPtr lParam;
329 public ushort time;
330 public POINT pt;
331 }
332
333 [StructLayout(LayoutKind.Sequential)]
334 public struct RECT
335 {
336 public int Left, Top, Right, Bottom;
337
338 public RECT(int left, int top, int right, int bottom)
339 {
340 Left = left;
341 Top = top;
342 Right = right;
343 Bottom = bottom;
344 }
345 public override string ToString()
346 {
347 return "(" + Left + ", " + Top + ", " + Right + ", " + Bottom + ")";
348 }
349 }
350
351 public delegate IntPtr HookProc(int code, IntPtr wParam, ref MSG lParam);
352 public delegate bool EnumThreadDelegate(IntPtr Hwnd, IntPtr lParam);
353
354#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
355
356 public static class Window
357 {
358 [DllImport("user32.dll")]
359 public static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
360
361 [DllImport("user32.dll", SetLastError = true)]
362 public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
363
364 [DllImport("user32.dll")]
365 public static extern bool IsWindowVisible(IntPtr hWnd);
366
367 [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
368 static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);
369 public static string GetClassName(IntPtr hWnd)
370 {
371 var sb = new System.Text.StringBuilder(256);
372 int count = GetClassName(hWnd, sb, 256);
373 return sb.ToString(0, count);
374 }
375
376 [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
377 static extern int GetWindowTextLength(IntPtr hWnd);
378 [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
379 static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
380 public static string GetWindowText(IntPtr hWnd)
381 {
382 int length = GetWindowTextLength(hWnd) + 2;
383 var sb = new System.Text.StringBuilder(length);
384 int count = GetWindowText(hWnd, sb, length);
385 return sb.ToString(0, count);
386 }
387 }
388
389 public static class WinAPI
390 {
391 [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
392 public static extern IntPtr GetModuleHandle(string lpModuleName);
393 [DllImport("kernel32.dll")]
394 public static extern uint GetCurrentThreadId();
395
396 [DllImport("user32.dll", SetLastError = true)]
397 public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
398 [DllImport("user32.dll", SetLastError = true)]
399 public static extern bool UnhookWindowsHookEx(IntPtr hhk);
400 [DllImport("user32.dll")]
401 public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, ref MSG lParam);
402
403 [DllImport("shell32.dll")]
404 public static extern void DragAcceptFiles(IntPtr hwnd, bool fAccept);
405 [DllImport("shell32.dll", CharSet = CharSet.Unicode)]
406 public static extern uint DragQueryFile(IntPtr hDrop, uint iFile, System.Text.StringBuilder lpszFile, uint cch);
407 [DllImport("shell32.dll")]
408 public static extern void DragFinish(IntPtr hDrop);
409
410 [DllImport("shell32.dll")]
411 public static extern void DragQueryPoint(IntPtr hDrop, out POINT pos);
412 }
413#endif
414
415
416 public static class UnityDragAndDropHook
417 {
418 public delegate void DroppedFilesEvent(List<string> aPathNames, POINT aDropPoint);
419 public static event DroppedFilesEvent OnDroppedFiles;
420
421#if UNITY_STANDALONE_WIN && !UNITY_EDITOR_WIN
422
423 private static uint threadId;
424 private static IntPtr mainWindow = IntPtr.Zero;
425 private static IntPtr m_Hook;
426 private static string m_ClassName = "UnityWndClass";
427
428 // attribute required for IL2CPP, also has to be a static method
429 [AOT.MonoPInvokeCallback(typeof(EnumThreadDelegate))]
430 private static bool EnumCallback(IntPtr W, IntPtr _)
431 {
432 if (Window.IsWindowVisible(W) && (mainWindow == IntPtr.Zero || (m_ClassName != null && Window.GetClassName(W) == m_ClassName)))
433 {
434 mainWindow = W;
435 }
436 return true;
437 }
438
439 public static void InstallHook()
440 {
441 threadId = WinAPI.GetCurrentThreadId();
442 if (threadId > 0)
443 Window.EnumThreadWindows(threadId, EnumCallback, IntPtr.Zero);
444
445 var hModule = WinAPI.GetModuleHandle(null);
446 m_Hook = WinAPI.SetWindowsHookEx(HookType.WH_GETMESSAGE, Callback, hModule, threadId);
447 // Allow dragging of files onto the main window. generates the WM_DROPFILES message
448 WinAPI.DragAcceptFiles(mainWindow, true);
449 }
450 public static void UninstallHook()
451 {
452 WinAPI.UnhookWindowsHookEx(m_Hook);
453 WinAPI.DragAcceptFiles(mainWindow, false);
454 m_Hook = IntPtr.Zero;
455 }
456
457 // attribute required for IL2CPP, also has to be a static method
458 [AOT.MonoPInvokeCallback(typeof(HookProc))]
459 private static IntPtr Callback(int code, IntPtr wParam, ref MSG lParam)
460 {
461 if (code == 0 && lParam.message == WM.DROPFILES)
462 {
463 POINT pos;
464 WinAPI.DragQueryPoint(lParam.wParam, out pos);
465
466 // 0xFFFFFFFF as index makes the method return the number of files
467 uint n = WinAPI.DragQueryFile(lParam.wParam, 0xFFFFFFFF, null, 0);
468 var sb = new System.Text.StringBuilder(1024);
469
470 List<string> result = new List<string>();
471 for (uint i = 0; i < n; i++)
472 {
473 int len = (int)WinAPI.DragQueryFile(lParam.wParam, i, sb, 1024);
474 result.Add(sb.ToString(0, len));
475 sb.Length = 0;
476 }
477 WinAPI.DragFinish(lParam.wParam);
478 if (OnDroppedFiles != null)
479 OnDroppedFiles(result, pos);
480 }
481 return WinAPI.CallNextHookEx(m_Hook, code, wParam, ref lParam);
482 }
483#else
484 public static void InstallHook()
485 {
486 }
487 public static void UninstallHook()
488 {
489 }
490#endif
491 }
492}
@ DWMCOMPOSITIONCHANGED
@ IME_STARTCOMPOSITION
@ DWMNCRENDERINGCHANGED
@ INPUTLANGCHANGEREQUEST
@ DWMWINDOWMAXIMIZEDCHANGE
@ DWMCOLORIZATIONCOLORCHANGED
delegate IntPtr HookProc(int code, IntPtr wParam, ref MSG lParam)
delegate bool EnumThreadDelegate(IntPtr Hwnd, IntPtr lParam)
delegate void Callback()
ushort time
Definition: B83.Win32.cs:329
IntPtr hwnd
Definition: B83.Win32.cs:325
IntPtr wParam
Definition: B83.Win32.cs:327
IntPtr lParam
Definition: B83.Win32.cs:328
POINT(int aX, int aY)
Definition: B83.Win32.cs:310
override string ToString()
Definition: B83.Win32.cs:315
RECT(int left, int top, int right, int bottom)
Definition: B83.Win32.cs:338
override string ToString()
Definition: B83.Win32.cs:345