├── B83.Win32.cs ├── FileDragAndDrop.cs ├── ImageExample.cs ├── LICENSE └── README.md /B83.Win32.cs: -------------------------------------------------------------------------------- 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 | * * * * */ 33 | using System; 34 | using System.Collections.Generic; 35 | using System.Runtime.InteropServices; 36 | 37 | namespace B83.Win32 38 | { 39 | public enum HookType : int 40 | { 41 | WH_JOURNALRECORD = 0, 42 | WH_JOURNALPLAYBACK = 1, 43 | WH_KEYBOARD = 2, 44 | WH_GETMESSAGE = 3, 45 | WH_CALLWNDPROC = 4, 46 | WH_CBT = 5, 47 | WH_SYSMSGFILTER = 6, 48 | WH_MOUSE = 7, 49 | WH_HARDWARE = 8, 50 | WH_DEBUG = 9, 51 | WH_SHELL = 10, 52 | WH_FOREGROUNDIDLE = 11, 53 | WH_CALLWNDPROCRET = 12, 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, 84 | SETTINGCHANGE = WININICHANGE, 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, 280 | DWMCOLORIZATIONCOLORCHANGED = 0x0320, 281 | DWMWINDOWMAXIMIZEDCHANGE = 0x0321, 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 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 result = new List(); 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 | } 493 | -------------------------------------------------------------------------------- /FileDragAndDrop.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using System.Linq; 4 | using B83.Win32; 5 | 6 | 7 | public class FileDragAndDrop : MonoBehaviour 8 | { 9 | List log = new List(); 10 | void OnEnable () 11 | { 12 | // must be installed on the main thread to get the right thread id. 13 | UnityDragAndDropHook.InstallHook(); 14 | UnityDragAndDropHook.OnDroppedFiles += OnFiles; 15 | } 16 | void OnDisable() 17 | { 18 | UnityDragAndDropHook.UninstallHook(); 19 | } 20 | 21 | void OnFiles(List aFiles, POINT aPos) 22 | { 23 | // do something with the dropped file names. aPos will contain the 24 | // mouse position within the window where the files has been dropped. 25 | string str = "Dropped " + aFiles.Count + " files at: " + aPos + "\n\t" + 26 | aFiles.Aggregate((a, b) => a + "\n\t" + b); 27 | Debug.Log(str); 28 | log.Add(str); 29 | } 30 | 31 | private void OnGUI() 32 | { 33 | if (GUILayout.Button("clear log")) 34 | log.Clear(); 35 | foreach (var s in log) 36 | GUILayout.Label(s); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ImageExample.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using System.Linq; 4 | using B83.Win32; 5 | 6 | 7 | public class ImageExample : MonoBehaviour 8 | { 9 | Texture2D[] textures = new Texture2D[6]; 10 | DropInfo dropInfo = null; 11 | class DropInfo 12 | { 13 | public string file; 14 | public Vector2 pos; 15 | } 16 | void OnEnable () 17 | { 18 | UnityDragAndDropHook.InstallHook(); 19 | UnityDragAndDropHook.OnDroppedFiles += OnFiles; 20 | 21 | } 22 | void OnDisable() 23 | { 24 | UnityDragAndDropHook.UninstallHook(); 25 | } 26 | 27 | void OnFiles(List aFiles, POINT aPos) 28 | { 29 | string file = ""; 30 | // scan through dropped files and filter out supported image types 31 | foreach(var f in aFiles) 32 | { 33 | var fi = new System.IO.FileInfo(f); 34 | var ext = fi.Extension.ToLower(); 35 | if (ext == ".png" || ext == ".jpg" || ext == ".jpeg") 36 | { 37 | file = f; 38 | break; 39 | } 40 | } 41 | // If the user dropped a supported file, create a DropInfo 42 | if (file != "") 43 | { 44 | var info = new DropInfo 45 | { 46 | file = file, 47 | pos = new Vector2(aPos.x, aPos.y) 48 | }; 49 | dropInfo = info; 50 | } 51 | } 52 | 53 | void LoadImage(int aIndex, DropInfo aInfo) 54 | { 55 | if (aInfo == null) 56 | return; 57 | // get the GUI rect of the last Label / box 58 | var rect = GUILayoutUtility.GetLastRect(); 59 | // check if the drop position is inside that rect 60 | if (rect.Contains(aInfo.pos)) 61 | { 62 | var data = System.IO.File.ReadAllBytes(aInfo.file); 63 | var tex = new Texture2D(1,1); 64 | tex.LoadImage(data); 65 | if (textures[aIndex] != null) 66 | Destroy(textures[aIndex]); 67 | textures[aIndex] = tex; 68 | } 69 | } 70 | 71 | private void OnGUI() 72 | { 73 | DropInfo tmp = null; 74 | if (Event.current.type == EventType.Repaint && dropInfo!= null) 75 | { 76 | tmp = dropInfo; 77 | dropInfo = null; 78 | } 79 | GUILayout.BeginHorizontal(); 80 | for (int i = 0; i < 3; i++) 81 | { 82 | if (textures[i] != null) 83 | GUILayout.Label(textures[i], GUILayout.Width(200), GUILayout.Height(200)); 84 | else 85 | GUILayout.Box("Drag image here", GUILayout.Width(200), GUILayout.Height(200)); 86 | LoadImage(i, tmp); 87 | } 88 | GUILayout.EndHorizontal(); 89 | GUILayout.BeginHorizontal(); 90 | for (int i = 3; i < 6; i++) 91 | { 92 | if (textures[i] != null) 93 | GUILayout.Label(textures[i], GUILayout.Width(200), GUILayout.Height(200)); 94 | else 95 | GUILayout.Box("Drag image here", GUILayout.Width(200), GUILayout.Height(200)); 96 | LoadImage(i, tmp); 97 | } 98 | GUILayout.EndHorizontal(); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Markus Göbel (Bunny83) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UnityWindowsFileDrag&Drop 2 | Adds file drag and drop support for Unity standalone builds on windows. 3 | 4 | It uses the GetMessage hook to intercept the WM_DROPFILES message 5 | 6 | See the "FileDragAndDrop.cs" or "ImageExample.cs" file for an example usage. 7 | 8 | Due to too many issues in the Unity editor (causes random silent crashes) I have disabled the hook when tested in playmode inside the editor. So this feature only works in a build. 9 | --------------------------------------------------------------------------------