Определение типа fullscreen
Понадобилось мне как‑то определять тип fullscreen для вывода подходящего типа уведомления (звуковое/системное/окном) во время запущенных игр и родился такой код:
public enum WindowFullscreenState { None, Emulated, Shared, Exclusive, ExclusiveGdi, NotOwned } public static WindowFullscreenState GetForegroundWindowFullscreenType() { var result = WindowFullscreenState.None; uint dwProcessId; D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP query = new D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP { hWindow = GetForegroundWindow() }; GetWindowThreadProcessId(query.hWindow, out dwProcessId); query.hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, dwProcessId); if (query.hProcess != IntPtr.Zero) { D3DKMTQueryVidPnExclusiveOwnership(ref query); CloseHandle(query.hProcess); result = query.OwnerType switch { D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_UNOWNED => WindowFullscreenState.NotOwned, D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_SHARED => WindowFullscreenState.Shared, D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE => WindowFullscreenState.Exclusive, D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVEGDI => WindowFullscreenState.ExclusiveGdi, D3DKMT_VIDPNSOURCEOWNER_TYPE.D3DKMT_VIDPNSOURCEOWNER_EMULATED => WindowFullscreenState.Emulated, _ =>WindowFullscreenState.None }; } return result; } public enum D3DKMT_VIDPNSOURCEOWNER_TYPE { D3DKMT_VIDPNSOURCEOWNER_UNOWNED = 0, D3DKMT_VIDPNSOURCEOWNER_SHARED = 1, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVE = 2, D3DKMT_VIDPNSOURCEOWNER_EXCLUSIVEGDI = 3, D3DKMT_VIDPNSOURCEOWNER_EMULATED = 4 } [StructLayout(LayoutKind.Sequential)] public struct LUID { public uint LowPart; public int HighPart; } [StructLayout(LayoutKind.Sequential)] public struct D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP { public IntPtr hProcess; public IntPtr hWindow; public uint VidPnSourceId; public LUID AdapterLuid; public D3DKMT_VIDPNSOURCEOWNER_TYPE OwnerType; } [DllImport("user32.dll", SetLastError = true)] private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hObject); [DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int MessageBoxW(IntPtr hWnd, string lpText, string lpCaption, uint uType); private const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000; [DllImport("gdi32.dll", EntryPoint = "D3DKMTQueryVidPnExclusiveOwnership")] private static extern int D3DKMTQueryVidPnExclusiveOwnership(ref D3DKMT_QUERYVIDPNEXCLUSIVEOWNERSHIP data); [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
Схема использования с типами уведомлений:
WindowFullscreenState.Exclusive -> SendVoiceNotification WindowFullscreenState.ExclusiveGdi -> SendVoiceNotification WindowFullscreenState.Emulated -> ShowSystemNotification WindowFullscreenState.Shared -> ShowSystemNotification WindowFullscreenState.NotOwned || WindowFullscreenState.None -> IsForegroundWindowSmallerThanScreen ? ShowCustomWindow : ShowSystemNotification
Подробнее можно прочитать про виды захвата экрана тут и тут.
P.S. Некоторые игры (ExclusiveGdi) можно заставить (Emulated) получать системные уведомления через режим совместимости.
