Определение типа 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) получать системные уведомления через режим совместимости.