using System; using System.Runtime.InteropServices; namespace Test { public static class WindowsOperations { //https://docs.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-setwindowpos?redirectedfrom=MSDN [DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags flags); [DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, SetWindowPosFlags flags); [DllImport("user32.dll", EntryPoint = "FindWindow")] public static extern IntPtr FindWindow(System.String className, System.String windowName); [DllImport("user32.dll")] static extern IntPtr GetForegroundWindow(); // window long [DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindowLong(IntPtr hwnd, WindowLongFlags flags); [DllImport("user32.dll")] static extern IntPtr SetWindowLong(IntPtr hwnd, WindowLongFlags flags, int index); // window rect private struct WinRect { public int left, top, right, bottom; } [DllImport("user32.dll", SetLastError = true)] static extern IntPtr GetWindowRect(IntPtr hwnd, out WinRect lpRect); // window top [DllImport("user32.dll")] public static extern int BringWindowToTop(IntPtr hwnd); // window layered [DllImport("user32.dll")] static extern bool SetLayeredWindowAttributes(IntPtr hwnd, uint crKey, byte bAlpha, uint dwFlags); public const int GWL_EXSTYLE = -20; public const int WS_EX_LAYERED = 0x80000; public const int LWA_ALPHA = 0x2; public const int LWA_COLORKEY = 0x1; static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); //맨 위가 아닌 모든 창 위에 창을 배치합니다. 창은 비활성화된 경우에도 맨 위 위치를 유지합니다. static readonly IntPtr HWND_NOTOPMOST = new IntPtr(1); //창이 맨 위가 아닌 모든 창 위에 배치합니다(즉, 맨 위 창 뒤에). 창이 이미 맨 위가 아닌 창인 경우에는 이 플래그가 적용되지 않습니다. // show/hide window [DllImport("user32")] public static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); [DllImport("user32.dll", SetLastError = true)] static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); // prevent capture [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool SetWindowDisplayAffinity(IntPtr hwnd, DisplayAffinity affinity); enum DisplayAffinity : uint { None = 0, Monitor = 1 } [DllImport("user32.dll", SetLastError = true)] static extern bool SetForegroundWindow(IntPtr hWnd); #region (prevent capture) 캡쳐 방지 public static void OnPreventCapture() { var hwnd = FindWindow(null, WindowMaanger.Instance.programName); bool ok = SetWindowDisplayAffinity(hwnd, DisplayAffinity.Monitor); UnityEngine.Debug.Log("####### OnPreventCapture ok :" + ok); } #endregion #region (show/hide) 윈도우 public enum CmdShow { Hide, Normal, Minimized, Maximized, NoActivate, Show, Minimize, MinimizeNoActive, NA, Restore, Default, ForceMinimize } public static void ShowWindow() { var hwnd = GetForegroundWindow(); ShowWindow(hwnd, (int)CmdShow.Show); } public static void HideWindow() { var hwnd = GetForegroundWindow(); ShowWindow(hwnd, (int)CmdShow.Hide); } public static void MinmizeWindow(string windowName) { var hwnd = FindWindow(null, windowName); ShowWindow(hwnd, 2); } public static void HideWindow(string winName) { var hwnd = FindWindow(null, winName); ShowWindow(hwnd, (int)CmdShow.Hide); } #endregion #region (exclude layer) 레이어 제외 //Sets the opacity and transparency color key of a layered window. public static void OnSetExcludeLayered() { var hwnd = FindWindow(null, WindowMaanger.Instance.programName); // SetWindowLong(hwnd, WindowLongFlags.WS_EX_LAYERED); var style = GetWindowLong(hwnd, GWL_EXSTYLE); SetWindowLong(hwnd, GWL_EXSTYLE, style | WS_EX_LAYERED); SetLayeredWindowAttributes(hwnd, 0, 128, LWA_ALPHA); } #endregion #region (mvoe window) 윈도우 이동 public static void MoveHideWinodw() { var hwnd = FindWindow(null, WindowMaanger.Instance.programName); //복사 않되게 설정 (시커멋게남음) //SetWindowPos(hwnd, Test.WindowsOperations.HWND_TOPMOST, -10000, -10000, 3840, 1080, SetWindowPosFlags.ShowWindow); //SetWindowPos(hwnd, Test.WindowsOperations.HWND_TOPMOST, 0, 0, 3840, 1080, SetWindowPosFlags.ShowWindow); } public static void MoveShowWinodw() { var hwnd = FindWindow(null, WindowMaanger.Instance.programName); SetWindowPos(hwnd, Test.WindowsOperations.HWND_TOPMOST, 0, 0, 3840, 1080, SetWindowPosFlags.ShowWindow); } #endregion #region (focus window) 윈도우 포커스 public static void SetWinodwFocus(string winName) { var hwnd = FindWindow(null, winName); UnityEngine.Debug.Log("...find hwnd :" + hwnd); SetForegroundWindow(hwnd); } #endregion #region (back window) 맨뒤로 보내기 //https://ryeggg.tistory.com/56 //https://learn.microsoft.com/ko-kr/windows/win32/api/winuser/nf-winuser-setwindowpos public static void BackNoBorderWindow(string windowName) { var hwnd = FindWindow(null, windowName); //위치 정보 구하기 var windowRect = GetWindowRect(hwnd, out WinRect winRect); //// 레이어만 변경 //SetWindowPos(hwnd, HWND_NOTOPMOST, winRect.left ,winRect.top, // winRect.right- winRect.left, // winRect.bottom - winRect.top, SetWindowPosFlags.ShowWindow // /* | SetWindowPosFlags.DoNotSendChangingEvent // | SetWindowPosFlags.IgnoreMove*/); int widht = winRect.right - winRect.left; SetWindowPos(hwnd, 10, winRect.left, winRect.top, winRect.right - winRect.left, winRect.bottom - winRect.top, SetWindowPosFlags.ShowWindow /* | SetWindowPosFlags.DoNotSendChangingEvent | SetWindowPosFlags.IgnoreMove*/); } public static void BringWindowTop(string windowName) { var hwnd = FindWindow(null, windowName); BringWindowToTop(hwnd); } #endregion #region (Top window) 윈도우 설정 // no border top window public static void NoBorderTopWindow(string windowName, int x, int y, int width, int height) { //var hwnd = GetForegroundWindow(); var hwnd = FindWindow(null, windowName); var result = GetWindowLong(hwnd, WindowLongFlags.GWL_STYLE); //---------- 타이틀 형태 스타일 // 스타일 설정 //var style = (WindowStyles)result.ToInt64(); //style &= ~(WindowStyles.WS_CAPTION | WindowStyles.WS_THICKFRAME | WindowStyles.WS_MINIMIZE // | WindowStyles.WS_MAXIMIZE | WindowStyles.WS_SYSMENU); //SetWindowLong(hwnd, WindowLongFlags.GWL_STYLE, (int)style); //SetWindowPos(hwnd, Test.WindowsOperations.HWND_TOPMOST, x, y, width, height, SetWindowPosFlags.ShowWindow); //-------- 팝업 topmost 스타일 var style = WindowStyles.WS_POPUP; SetWindowLong(hwnd, WindowLongFlags.GWL_STYLE, (int)style); SetWindowPos(hwnd, Test.WindowsOperations.HWND_TOPMOST, x, y, width, height, SetWindowPosFlags.ShowWindow /* | SetWindowPosFlags.DoNotSendChangingEvent | SetWindowPosFlags.IgnoreMove*/); } // no border window public static void NoBorderWindow(string windowName, int x, int y, int width, int height) { //var hwnd = GetForegroundWindow(); var hwnd = FindWindow(null, windowName); var result = GetWindowLong(hwnd, WindowLongFlags.GWL_STYLE); var style = (WindowStyles)result.ToInt64(); // style &= ~(WindowStyles.WS_CAPTION | WindowStyles.WS_THICKFRAME | WindowStyles.WS_MINIMIZE // | WindowStyles.WS_MAXIMIZE | WindowStyles.WS_SYSMENU); SetWindowLong(hwnd, WindowLongFlags.GWL_STYLE, (int)style); SetWindowPos(hwnd, 0, x, y, width, height, SetWindowPosFlags.ShowWindow); } #endregion [Flags] enum WindowStyles : uint { WS_OVERLAPPED = 0x00000000, WS_POPUP = 0x80000000, WS_CHILD = 0x40000000, WS_MINIMIZE = 0x20000000, WS_VISIBLE = 0x10000000, WS_DISABLED = 0x08000000, WS_CLIPSIBLINGS = 0x04000000, WS_CLIPCHILDREN = 0x02000000, WS_MAXIMIZE = 0x01000000, WS_BORDER = 0x00800000, WS_DLGFRAME = 0x00400000, WS_VSCROLL = 0x00200000, WS_HSCROLL = 0x00100000, WS_SYSMENU = 0x00080000, WS_THICKFRAME = 0x00040000, WS_GROUP = 0x00020000, WS_TABSTOP = 0x00010000, WS_MINIMIZEBOX = 0x00020000, WS_MAXIMIZEBOX = 0x00010000, WS_CAPTION = WS_BORDER | WS_DLGFRAME, WS_TILED = WS_OVERLAPPED, WS_ICONIC = WS_MINIMIZE, WS_SIZEBOX = WS_THICKFRAME, WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW, WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU, WS_CHILDWINDOW = WS_CHILD, //Extended Window Styles WS_EX_DLGMODALFRAME = 0x00000001, WS_EX_NOPARENTNOTIFY = 0x00000004, WS_EX_TOPMOST = 0x00000008, WS_EX_ACCEPTFILES = 0x00000010, WS_EX_TRANSPARENT = 0x00000020, //#if(WINVER >= 0x0400) WS_EX_MDICHILD = 0x00000040, WS_EX_TOOLWINDOW = 0x00000080, WS_EX_WINDOWEDGE = 0x00000100, WS_EX_CLIENTEDGE = 0x00000200, WS_EX_CONTEXTHELP = 0x00000400, WS_EX_RIGHT = 0x00001000, WS_EX_LEFT = 0x00000000, WS_EX_RTLREADING = 0x00002000, WS_EX_LTRREADING = 0x00000000, WS_EX_LEFTSCROLLBAR = 0x00004000, WS_EX_RIGHTSCROLLBAR = 0x00000000, WS_EX_CONTROLPARENT = 0x00010000, WS_EX_STATICEDGE = 0x00020000, WS_EX_APPWINDOW = 0x00040000, WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE), WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST), //#endif /* WINVER >= 0x0400 */ //#if(WIN32WINNT >= 0x0500) WS_EX_LAYERED = 0x00080000, //#endif /* WIN32WINNT >= 0x0500 */ //#if(WINVER >= 0x0500) WS_EX_NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children WS_EX_LAYOUTRTL = 0x00400000, // Right to left mirroring //#endif /* WINVER >= 0x0500 */ //#if(WIN32WINNT >= 0x0500) WS_EX_COMPOSITED = 0x02000000, WS_EX_NOACTIVATE = 0x08000000 //#endif /* WIN32WINNT >= 0x0500 */ } enum WindowLongFlags : int { GWL_EXSTYLE = -20, GWLP_HINSTANCE = -6, GWLP_HWNDPARENT = -8, GWL_ID = -12, GWL_STYLE = -16, GWL_USERDATA = -21, GWL_WNDPROC = -4, DWLP_USER = 0x8, DWLP_MSGRESULT = 0x0, DWLP_DLGPROC = 0x4 } [Flags()] private enum SetWindowPosFlags : uint { /// If the calling thread and the thread that owns the window are attached to different input queues, /// the system posts the request to the thread that owns the window. This prevents the calling thread from /// blocking its execution while other threads process the request. /// SWP_ASYNCWINDOWPOS AsynchronousWindowPosition = 0x4000, /// Prevents generation of the WM_SYNCPAINT message. /// SWP_DEFERERASE DeferErase = 0x2000, /// Draws a frame (defined in the window's class description) around the window. /// SWP_DRAWFRAME DrawFrame = 0x0020, /// Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to /// the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE /// is sent only when the window's size is being changed. /// SWP_FRAMECHANGED FrameChanged = 0x0020, /// Hides the window. /// SWP_HIDEWINDOW HideWindow = 0x0080, /// Does not activate the window. If this flag is not set, the window is activated and moved to the /// top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter /// parameter). /// SWP_NOACTIVATE DoNotActivate = 0x0010, /// Discards the entire contents of the client area. If this flag is not specified, the valid /// contents of the client area are saved and copied back into the client area after the window is sized or /// repositioned. /// SWP_NOCOPYBITS DoNotCopyBits = 0x0100, /// Retains the current position (ignores X and Y parameters). /// SWP_NOMOVE IgnoreMove = 0x0002, /// Does not change the owner window's position in the Z order. /// SWP_NOOWNERZORDER DoNotChangeOwnerZOrder = 0x0200, /// Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to /// the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent /// window uncovered as a result of the window being moved. When this flag is set, the application must /// explicitly invalidate or redraw any parts of the window and parent window that need redrawing. /// SWP_NOREDRAW DoNotRedraw = 0x0008, /// Same as the SWP_NOOWNERZORDER flag. /// SWP_NOREPOSITION DoNotReposition = 0x0200, /// Prevents the window from receiving the WM_WINDOWPOSCHANGING message. /// SWP_NOSENDCHANGING DoNotSendChangingEvent = 0x0400, /// Retains the current size (ignores the cx and cy parameters). /// SWP_NOSIZE IgnoreResize = 0x0001, /// Retains the current Z order (ignores the hWndInsertAfter parameter). /// SWP_NOZORDER IgnoreZOrder = 0x0004, /// Displays the window. /// SWP_SHOWWINDOW ShowWindow = 0x0040, } } } /* * Window Styles // */ //#define WS_OVERLAPPED 0x00000000L //디폴트 윈도우 //#define WS_POPUP 0x80000000L // 팝업 윈도우를 만든다. WS_CHILD와 함께 쓸수 없다. //#define WS_CHILD 0x40000000L //차일드 윈도우를 만든다. WS_POPUP와 함께 쓸 수 없다. //#define WS_MINIMIZE 0x20000000L //최초 최소화된 상태로 윈도우를 만든다. //#define WS_VISIBLE 0x10000000L //윈도우를 만들자 마자 화면에 출력한다. //#define WS_DISABLED 0x08000000L // 사용금지된 상태, 즉 입력을 받아들일 수 없는 상태로 만든다. //#define WS_CLIPSIBLINGS 0x04000000L //차일드끼리 상호 겹친 영역은 그리기 영역에서 제외된다. //#define WS_CLIPCHILDREN 0x02000000L //차일드가 위치한 영역은 그리기 영역에서 제외된다. //#define WS_MAXIMIZE 0x01000000L // 최초 최대화된 ㅏㅇ태로 윈도우를 만든다. //#define WS_CAPTION 0x00C00000L /* WS_BORDER | WS_DLGFRAME */ // 타이틀 바를 가진 윈도우를 만들며 WS_BORDER 스타일을 포함한다. //#define WS_BORDER 0x00800000L // 단선으로 된 경계선을 만들며 크기 조정은 할 수 없다. //#define WS_DLGFRAME 0x00400000L // 두꺼운 경계선을 가지며 타이틀 바를 가질 수 없다. //#define WS_VSCROLL 0x00200000L // 수직 스크롤 바를 가진 윈도우를 만든다. //#define WS_HSCROLL 0x00100000L // 수평 스크롤 바를 가진 윈도우를 만든다. //#define WS_SYSMENU 0x00080000L // 시스템 메뉴를 가진 윈도우를 만든다. //#define WS_THICKFRAME 0x00040000L // 크기 조정 가능한 두꺼운 경계선을 가진다. //#define WS_GROUP 0x00020000L // 라디오 버튼 등 그룹을 이루는 컨트롤의 그룹 지정에 사용된다. //#define WS_TABSTOP 0x00010000L // Tab키로 포커스를 이동할 수 있다. //#define WS_MINIMIZEBOX 0x00020000L // 최소화 버튼을 만든다. //#define WS_MAXIMIZEBOX 0x00010000L // 최대화 버튼을 만든다. //#define WS_TILED WS_OVERLAPPED //#define WS_ICONIC WS_MINIMIZE //#define WS_SIZEBOX WS_THICKFRAME //#define WS_TILEDWINDOW WS_OVERLAPPEDWINDOW ///* // * Common Window Styles // */ //#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED | \ /*가장 일반적인 윈도우 스타일*/ // WS_CAPTION | \ // WS_SYSMENU | \ // WS_THICKFRAME | \ // WS_MINIMIZEBOX | \ // WS_MAXIMIZEBOX) //#define WS_POPUPWINDOW (WS_POPUP | \ /* 일반적인 팝업 윈도우*/ // WS_BORDER | \ // WS_SYSMENU) //#define WS_CHILDWINDOW (WS_CHILD) //*/