Обновить

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

Теги:
+3
Комментарии0

Публикации

Ближайшие события