Ebram
Ebram

Reputation: 1102

DwmGetWindowAttribute doesn't get the correct Rect size for MediaPlayer if it's in full screen mode

I am trying to get application size using this code :

      [DllImport(@"dwmapi.dll")]
      private static extern int DwmGetWindowAttribute(IntPtr hwnd, int dwAttribute, out Rect pvAttribute, int cbAttribute);

    [Serializable, StructLayout(LayoutKind.Sequential)]
    private struct Rect
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;

        public Rectangle ToRectangle()
        {
            return Rectangle.FromLTRB(Left, Top, Right, Bottom);
        }
    }

      private static bool DWMWA_EXTENDED_FRAME_BOUNDS(IntPtr handle, out Rectangle rectangle)
        {
        Rect rect;
        var result = DwmGetWindowAttribute(handle, (int)Dwmwindowattribute.DwmwaExtendedFrameBounds,
            out rect, Marshal.SizeOf(typeof(Rect)));
        rectangle = rect.ToRectangle();
        return result >= 0;
         }

it's working fine for all running applications but if it's Media Player in fullscreen mode I didn't get the right Rect size.

Upvotes: 1

Views: 1083

Answers (1)

Allan R.
Allan R.

Reputation: 76

Windows Media Player is weird in full screen mode such that the main window handle doesn't correspond to the full screen window displayed. The full screen window still has a handle but a little more work is needed to get to it.

First you'd need to declare some WinAPI functions and structs:

delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam);

[DllImport("User32.dll")]
static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam);

[DllImport("User32.dll")]
static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfo lpmi);

[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

[DllImport("User32.dll")]
static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags);

[StructLayout(LayoutKind.Sequential)]
struct MonitorInfo
{
    public uint Size;
    public Rect Monitor;
    public Rect Work;
    public uint Flags;
}

// You seem to have this one already
[StructLayout(LayoutKind.Sequential)]
struct Rect
{
    public int Left;
    public int Top;
    public int Right;
    public int Bottom;
}

From there, the method looks like this:

// Pass Windows Media Player's main window handle here.
static bool GetWmpFullScreenHandle(IntPtr mainHandle, out IntPtr fullScreenHandle)
{
    IntPtr tempHandle = IntPtr.Zero;

    // Getting WMP's PID from the main window handle.
    GetWindowThreadProcessId(mainHandle, out uint wmpProcessId);

    // Optionally, check if the PID resolves to a WMP process.
    if (System.Diagnostics.Process.GetProcessById(wmpProcessId).ProcessName != "wmplayer")
    {
        fullScreenHandle = IntPtr.Zero;

        return false;
    }

    // This iterates through all the open window handles on the machine
    // and passes them to the callback below.
    EnumWindows((hWnd, lParam) =>
    {
        // Getting the window handle's PID.
        GetWindowThreadProcessId(hWnd, out uint windowProcessId);

        // Checking if the window handle belongs to the WMP process.
        if (windowProcessId == wmpProcessId)
        {
            var monitorInfo = new MonitorInfo
            {
                Size = Convert.ToUInt32(Marshal.SizeOf(typeof(MonitorInfo)))
            };

            // Getting the dimensions of the monitor the window is displayed on,
            // as well as the window dimensions.
            if (GetMonitorInfo(MonitorFromWindow(hWnd, 0), ref monitorInfo) && 
                GetWindowRect(hWnd, out Rect windowRect))
            {
                Rect monitorRect = monitorInfo.Monitor;

                // If the window dimensions are the same as its monitor's
                // dimensions, then we found a hidden full-screen window!
                if (windowRect.Left == monitorRect.Left &&
                    windowRect.Top == monitorRect.Top &&
                    windowRect.Right == monitorRect.Right &&
                    windowRect.Bottom == monitorRect.Bottom)
                {
                    tempHandle = hWnd;
                }
            }
        }

        return true;
    },
    IntPtr.Zero);

    fullScreenHandle = tempHandle;

    // Returns true if the hidden full-screen handle was found, false otherwise.
    return fullScreenHandle != IntPtr.Zero;
}

If found, you can then pass the resulting handle to DWMWA_EXTENDED_FRAME_BOUNDS to get the Rectangle.

Upvotes: 3

Related Questions