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)
//*/