TextureCombiner/Assets/Plugins/UnityWindowsFileDrag-Drop/B83.Win32.cs

495 lines
16 KiB
C#
Raw Normal View History

2020-11-01 03:54:32 +01:00
/* * * * *
* This is a collection of Win API helpers. Mainly dealing with window message hooks
* and file drag&drop support for Windows standalone Unity applications.
*
* 2019.11.28 - Changed the "UnityDragAndDropHook" class to a static class. This
* has been done for IL2CPP support. IL2CPP can not marshall instance method
* callbacks passed to native code. So the callbacks must be static methods.
* Therefore all fields involved also need to be static.
*
* The MIT License (MIT)
*
* Copyright (c) 2018 Markus Göbel (Bunny83)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* * * * */
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace B83.Win32
{
public enum HookType : int
{
WH_JOURNALRECORD = 0,
WH_JOURNALPLAYBACK = 1,
WH_KEYBOARD = 2,
WH_GETMESSAGE = 3,
WH_CALLWNDPROC = 4,
WH_CBT = 5,
WH_SYSMSGFILTER = 6,
WH_MOUSE = 7,
WH_HARDWARE = 8,
WH_DEBUG = 9,
WH_SHELL = 10,
WH_FOREGROUNDIDLE = 11,
WH_CALLWNDPROCRET = 12,
WH_KEYBOARD_LL = 13,
WH_MOUSE_LL = 14
}
// windows messages
public enum WM : uint
{
NULL = 0x0000,
CREATE = 0x0001,
DESTROY = 0x0002,
MOVE = 0x0003,
SIZE = 0x0005,
ACTIVATE = 0x0006,
SETFOCUS = 0x0007,
KILLFOCUS = 0x0008,
ENABLE = 0x000A,
SETREDRAW = 0x000B,
SETTEXT = 0x000C,
GETTEXT = 0x000D,
GETTEXTLENGTH = 0x000E,
PAINT = 0x000F,
CLOSE = 0x0010,
QUERYENDSESSION = 0x0011,
QUERYOPEN = 0x0013,
ENDSESSION = 0x0016,
QUIT = 0x0012,
ERASEBKGND = 0x0014,
SYSCOLORCHANGE = 0x0015,
SHOWWINDOW = 0x0018,
WININICHANGE = 0x001A,
SETTINGCHANGE = WININICHANGE,
DEVMODECHANGE = 0x001B,
ACTIVATEAPP = 0x001C,
FONTCHANGE = 0x001D,
TIMECHANGE = 0x001E,
CANCELMODE = 0x001F,
SETCURSOR = 0x0020,
MOUSEACTIVATE = 0x0021,
CHILDACTIVATE = 0x0022,
QUEUESYNC = 0x0023,
GETMINMAXINFO = 0x0024,
PAINTICON = 0x0026,
ICONERASEBKGND = 0x0027,
NEXTDLGCTL = 0x0028,
SPOOLERSTATUS = 0x002A,
DRAWITEM = 0x002B,
MEASUREITEM = 0x002C,
DELETEITEM = 0x002D,
VKEYTOITEM = 0x002E,
CHARTOITEM = 0x002F,
SETFONT = 0x0030,
GETFONT = 0x0031,
SETHOTKEY = 0x0032,
GETHOTKEY = 0x0033,
QUERYDRAGICON = 0x0037,
COMPAREITEM = 0x0039,
GETOBJECT = 0x003D,
COMPACTING = 0x0041,
[Obsolete]
COMMNOTIFY = 0x0044,
WINDOWPOSCHANGING = 0x0046,
WINDOWPOSCHANGED = 0x0047,
[Obsolete]
POWER = 0x0048,
COPYDATA = 0x004A,
CANCELJOURNAL = 0x004B,
NOTIFY = 0x004E,
INPUTLANGCHANGEREQUEST = 0x0050,
INPUTLANGCHANGE = 0x0051,
TCARD = 0x0052,
HELP = 0x0053,
USERCHANGED = 0x0054,
NOTIFYFORMAT = 0x0055,
CONTEXTMENU = 0x007B,
STYLECHANGING = 0x007C,
STYLECHANGED = 0x007D,
DISPLAYCHANGE = 0x007E,
GETICON = 0x007F,
SETICON = 0x0080,
NCCREATE = 0x0081,
NCDESTROY = 0x0082,
NCCALCSIZE = 0x0083,
NCHITTEST = 0x0084,
NCPAINT = 0x0085,
NCACTIVATE = 0x0086,
GETDLGCODE = 0x0087,
SYNCPAINT = 0x0088,
NCMOUSEMOVE = 0x00A0,
NCLBUTTONDOWN = 0x00A1,
NCLBUTTONUP = 0x00A2,
NCLBUTTONDBLCLK = 0x00A3,
NCRBUTTONDOWN = 0x00A4,
NCRBUTTONUP = 0x00A5,
NCRBUTTONDBLCLK = 0x00A6,
NCMBUTTONDOWN = 0x00A7,
NCMBUTTONUP = 0x00A8,
NCMBUTTONDBLCLK = 0x00A9,
NCXBUTTONDOWN = 0x00AB,
NCXBUTTONUP = 0x00AC,
NCXBUTTONDBLCLK = 0x00AD,
INPUT_DEVICE_CHANGE = 0x00FE,
INPUT = 0x00FF,
KEYFIRST = 0x0100,
KEYDOWN = 0x0100,
KEYUP = 0x0101,
CHAR = 0x0102,
DEADCHAR = 0x0103,
SYSKEYDOWN = 0x0104,
SYSKEYUP = 0x0105,
SYSCHAR = 0x0106,
SYSDEADCHAR = 0x0107,
UNICHAR = 0x0109,
KEYLAST = 0x0108,
IME_STARTCOMPOSITION = 0x010D,
IME_ENDCOMPOSITION = 0x010E,
IME_COMPOSITION = 0x010F,
IME_KEYLAST = 0x010F,
INITDIALOG = 0x0110,
COMMAND = 0x0111,
SYSCOMMAND = 0x0112,
TIMER = 0x0113,
HSCROLL = 0x0114,
VSCROLL = 0x0115,
INITMENU = 0x0116,
INITMENUPOPUP = 0x0117,
MENUSELECT = 0x011F,
MENUCHAR = 0x0120,
ENTERIDLE = 0x0121,
MENURBUTTONUP = 0x0122,
MENUDRAG = 0x0123,
MENUGETOBJECT = 0x0124,
UNINITMENUPOPUP = 0x0125,
MENUCOMMAND = 0x0126,
CHANGEUISTATE = 0x0127,
UPDATEUISTATE = 0x0128,
QUERYUISTATE = 0x0129,
CTLCOLORMSGBOX = 0x0132,
CTLCOLOREDIT = 0x0133,
CTLCOLORLISTBOX = 0x0134,
CTLCOLORBTN = 0x0135,
CTLCOLORDLG = 0x0136,
CTLCOLORSCROLLBAR = 0x0137,
CTLCOLORSTATIC = 0x0138,
MOUSEFIRST = 0x0200,
MOUSEMOVE = 0x0200,
LBUTTONDOWN = 0x0201,
LBUTTONUP = 0x0202,
LBUTTONDBLCLK = 0x0203,
RBUTTONDOWN = 0x0204,
RBUTTONUP = 0x0205,
RBUTTONDBLCLK = 0x0206,
MBUTTONDOWN = 0x0207,
MBUTTONUP = 0x0208,
MBUTTONDBLCLK = 0x0209,
MOUSEWHEEL = 0x020A,
XBUTTONDOWN = 0x020B,
XBUTTONUP = 0x020C,
XBUTTONDBLCLK = 0x020D,
MOUSEHWHEEL = 0x020E,
MOUSELAST = 0x020E,
PARENTNOTIFY = 0x0210,
ENTERMENULOOP = 0x0211,
EXITMENULOOP = 0x0212,
NEXTMENU = 0x0213,
SIZING = 0x0214,
CAPTURECHANGED = 0x0215,
MOVING = 0x0216,
POWERBROADCAST = 0x0218,
DEVICECHANGE = 0x0219,
MDICREATE = 0x0220,
MDIDESTROY = 0x0221,
MDIACTIVATE = 0x0222,
MDIRESTORE = 0x0223,
MDINEXT = 0x0224,
MDIMAXIMIZE = 0x0225,
MDITILE = 0x0226,
MDICASCADE = 0x0227,
MDIICONARRANGE = 0x0228,
MDIGETACTIVE = 0x0229,
MDISETMENU = 0x0230,
ENTERSIZEMOVE = 0x0231,
EXITSIZEMOVE = 0x0232,
DROPFILES = 0x0233,
MDIREFRESHMENU = 0x0234,
IME_SETCONTEXT = 0x0281,
IME_NOTIFY = 0x0282,
IME_CONTROL = 0x0283,
IME_COMPOSITIONFULL = 0x0284,
IME_SELECT = 0x0285,
IME_CHAR = 0x0286,
IME_REQUEST = 0x0288,
IME_KEYDOWN = 0x0290,
IME_KEYUP = 0x0291,
MOUSEHOVER = 0x02A1,
MOUSELEAVE = 0x02A3,
NCMOUSEHOVER = 0x02A0,
NCMOUSELEAVE = 0x02A2,
WTSSESSION_CHANGE = 0x02B1,
TABLET_FIRST = 0x02c0,
TABLET_LAST = 0x02df,
CUT = 0x0300,
COPY = 0x0301,
PASTE = 0x0302,
CLEAR = 0x0303,
UNDO = 0x0304,
RENDERFORMAT = 0x0305,
RENDERALLFORMATS = 0x0306,
DESTROYCLIPBOARD = 0x0307,
DRAWCLIPBOARD = 0x0308,
PAINTCLIPBOARD = 0x0309,
VSCROLLCLIPBOARD = 0x030A,
SIZECLIPBOARD = 0x030B,
ASKCBFORMATNAME = 0x030C,
CHANGECBCHAIN = 0x030D,
HSCROLLCLIPBOARD = 0x030E,
QUERYNEWPALETTE = 0x030F,
PALETTEISCHANGING = 0x0310,
PALETTECHANGED = 0x0311,
HOTKEY = 0x0312,
PRINT = 0x0317,
PRINTCLIENT = 0x0318,
APPCOMMAND = 0x0319,
THEMECHANGED = 0x031A,
CLIPBOARDUPDATE = 0x031D,
DWMCOMPOSITIONCHANGED = 0x031E,
DWMNCRENDERINGCHANGED = 0x031F,
DWMCOLORIZATIONCOLORCHANGED = 0x0320,
DWMWINDOWMAXIMIZEDCHANGE = 0x0321,
GETTITLEBARINFOEX = 0x033F,
HANDHELDFIRST = 0x0358,
HANDHELDLAST = 0x035F,
AFXFIRST = 0x0360,
AFXLAST = 0x037F,
PENWINFIRST = 0x0380,
PENWINLAST = 0x038F,
APP = 0x8000,
USER = 0x0400,
CPL_LAUNCH = USER + 0x1000,
CPL_LAUNCHED = USER + 0x1001,
SYSTIMER = 0x118,
}
// WH_CALLWNDPROC
[StructLayout(LayoutKind.Sequential)]
public struct CWPSTRUCT
{
public IntPtr lParam;
public IntPtr wParam;
public WM message;
public IntPtr hwnd;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x, y;
public POINT(int aX, int aY)
{
x = aX;
y = aY;
}
public override string ToString()
{
return "(" + x + ", " + y + ")";
}
}
//WH_GETMESSAGE
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public WM message;
public IntPtr wParam;
public IntPtr lParam;
public ushort time;
public POINT pt;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left, Top, Right, Bottom;
public RECT(int left, int top, int right, int bottom)
{
Left = left;
Top = top;
Right = right;
Bottom = bottom;
}
public override string ToString()
{
return "(" + Left + ", " + Top + ", " + Right + ", " + Bottom + ")";
}
}
public delegate IntPtr HookProc(int code, IntPtr wParam, ref MSG lParam);
public delegate bool EnumThreadDelegate(IntPtr Hwnd, IntPtr lParam);
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
public static class Window
{
[DllImport("user32.dll")]
public static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
[DllImport("user32.dll")]
public static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, System.Text.StringBuilder lpClassName, int nMaxCount);
public static string GetClassName(IntPtr hWnd)
{
var sb = new System.Text.StringBuilder(256);
int count = GetClassName(hWnd, sb, 256);
return sb.ToString(0, count);
}
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount);
public static string GetWindowText(IntPtr hWnd)
{
int length = GetWindowTextLength(hWnd) + 2;
var sb = new System.Text.StringBuilder(length);
int count = GetWindowText(hWnd, sb, length);
return sb.ToString(0, count);
}
}
public static class WinAPI
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, ref MSG lParam);
[DllImport("shell32.dll")]
public static extern void DragAcceptFiles(IntPtr hwnd, bool fAccept);
[DllImport("shell32.dll", CharSet = CharSet.Unicode)]
public static extern uint DragQueryFile(IntPtr hDrop, uint iFile, System.Text.StringBuilder lpszFile, uint cch);
[DllImport("shell32.dll")]
public static extern void DragFinish(IntPtr hDrop);
[DllImport("shell32.dll")]
public static extern void DragQueryPoint(IntPtr hDrop, out POINT pos);
}
#endif
public static class UnityDragAndDropHook
{
public delegate void DroppedFilesEvent(List<string> aPathNames, POINT aDropPoint);
#pragma warning disable CS0067
public static event DroppedFilesEvent OnDroppedFiles;
#pragma warning restore CS0067
#if UNITY_STANDALONE_WIN && !UNITY_EDITOR_WIN
private static uint threadId;
private static IntPtr mainWindow = IntPtr.Zero;
private static IntPtr m_Hook;
private static string m_ClassName = "UnityWndClass";
// attribute required for IL2CPP, also has to be a static method
[AOT.MonoPInvokeCallback(typeof(EnumThreadDelegate))]
private static bool EnumCallback(IntPtr W, IntPtr _)
{
if (Window.IsWindowVisible(W) && (mainWindow == IntPtr.Zero || (m_ClassName != null && Window.GetClassName(W) == m_ClassName)))
{
mainWindow = W;
}
return true;
}
public static void InstallHook()
{
threadId = WinAPI.GetCurrentThreadId();
if (threadId > 0)
Window.EnumThreadWindows(threadId, EnumCallback, IntPtr.Zero);
var hModule = WinAPI.GetModuleHandle(null);
m_Hook = WinAPI.SetWindowsHookEx(HookType.WH_GETMESSAGE, Callback, hModule, threadId);
// Allow dragging of files onto the main window. generates the WM_DROPFILES message
WinAPI.DragAcceptFiles(mainWindow, true);
}
public static void UninstallHook()
{
WinAPI.UnhookWindowsHookEx(m_Hook);
WinAPI.DragAcceptFiles(mainWindow, false);
m_Hook = IntPtr.Zero;
}
// attribute required for IL2CPP, also has to be a static method
[AOT.MonoPInvokeCallback(typeof(HookProc))]
private static IntPtr Callback(int code, IntPtr wParam, ref MSG lParam)
{
if (code == 0 && lParam.message == WM.DROPFILES)
{
POINT pos;
WinAPI.DragQueryPoint(lParam.wParam, out pos);
// 0xFFFFFFFF as index makes the method return the number of files
uint n = WinAPI.DragQueryFile(lParam.wParam, 0xFFFFFFFF, null, 0);
var sb = new System.Text.StringBuilder(1024);
List<string> result = new List<string>();
for (uint i = 0; i < n; i++)
{
int len = (int)WinAPI.DragQueryFile(lParam.wParam, i, sb, 1024);
result.Add(sb.ToString(0, len));
sb.Length = 0;
}
WinAPI.DragFinish(lParam.wParam);
if (OnDroppedFiles != null)
OnDroppedFiles(result, pos);
}
return WinAPI.CallNextHookEx(m_Hook, code, wParam, ref lParam);
}
#else
public static void InstallHook()
{
}
public static void UninstallHook()
{
}
#endif
}
}