none
[win 10, c#] Interop - Generic way to Maximized or Normal a Minimized application RRS feed

  • Question

  • Hello,

    I have problem to generically put to Normal a Minimized window?

    It works great if I memorize its hWnd when it is normal, but if the window is already minimized then that doesn't work for me.

    To reproduce, use the code from here - castorix31

    1. Then start a Calculator on win 10, notice the hWnd is different when minimized or not.

    2. Add the simple code as

            [DllImport("User32")]
            public static extern int ShowWindow(int hwnd, int nCmdShow);

            and call "ShowWindow(hWnd.ToInt32(), 1);" just before the return false in the "// minimized" use case

    3. minimized calculator and press the button again, notice it won't show the window as normal as the hWnd is from from the minimized version, if you memorize the one when Normal and call it with ShowWindow when minimized, then this work (calc will be displayed as Normal)....but in my case the application is minimized from the start, so how do I get the right hWnd so I can call this ShowWindow or MoveWindow?

    thanks for your help


    w.


    • Edited by wil70 Wednesday, April 4, 2018 5:23 AM
    Wednesday, April 4, 2018 2:43 AM

All replies

  • In fact, the handle is wrong when it is minimized.

    You must get the handle from the window with "ApplicationFrameWindow" class

    Wednesday, April 4, 2018 7:18 AM
  • I added the following in the "minimized" case to get the right hWnd, but it always returns 0?

                            ep.hWnd = hWnd;
                            ep.sExeName = sProcessImageName.ToString();
                            ep.nPID = nPID;
                            ep.nState = 1;
                            Marshal.StructureToPtr(ep, lParam, false);
                            hWnd = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
                            ShowWindow(hWnd.ToInt32(), 1);
                            //SetVisualStat(hWnd, WindowVisualState.Normal);
                            return false;
     

    (I added this before the return)

    Do you know hoe to make it work?

    thanks


    w.

    Wednesday, April 4, 2018 4:04 PM
  • For testing, I did (title in french) :

    hWnd = FindWindow("ApplicationFrameWindow", "Calculatrice");

    But the title must be hard-coded in the OS Language

    I tested a better way, with SHGetPropertyStoreForWindow (on "ApplicationFrameWindow"window) and if the AUMID (PKEY_AppUserModel_ID) contains "Calculator", it is the right window)

    But it needs more code...

    Wednesday, April 4, 2018 4:17 PM
  • Updated sample with SHGetPropertyStoreForWindow

    (tested on Windows 10)

      public partial class Form1 : Form
        {
            public enum HRESULT : int
            {         
                S_OK = 0,
                S_FALSE = 1,
                E_NOINTERFACE = unchecked((int)0x80004002),
                E_NOTIMPL = unchecked((int)0x80004001),          
                E_FAIL = unchecked((int)0x80004005)          
            }
    
            public const int SW_HIDE = 0;
            public const int SW_SHOWNORMAL = 1;
            public const int SW_SHOWMINIMIZED = 2;
            public const int SW_SHOWMAXIMIZED = 3;
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref IntPtr lParam);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
            public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumWindowsProc lpEnumFunc, ref IntPtr lParam);
    
            public delegate bool EnumWindowsProc(IntPtr hWnd, ref IntPtr lParam);
    
            public const long SYNCHRONIZE = (0x00100000L);
            public const int STANDARD_RIGHTS_REQUIRED = (0x000F0000);
    
            public const int PROCESS_VM_READ = (0x0010);
            public const int PROCESS_VM_WRITE = (0x0020);
            public const int PROCESS_DUP_HANDLE = (0x0040);
            public const int PROCESS_CREATE_PROCESS = (0x0080);
            public const int PROCESS_SET_QUOTA = (0x0100);
            public const int PROCESS_SET_INFORMATION = (0x0200);
            public const int PROCESS_QUERY_INFORMATION = (0x0400);
            public const int PROCESS_SUSPEND_RESUME = (0x0800);
            public const int PROCESS_QUERY_LIMITED_INFORMATION = (0x1000);
            public const int PROCESS_SET_LIMITED_INFORMATION = (0x2000);
            public const long PROCESS_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF);
    
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool QueryFullProcessImageName(IntPtr hProcess, int dwFlags, StringBuilder lpExeName, ref uint lpdwSize);    
    
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool CloseHandle(IntPtr hObject);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
    
            [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool GetPackageFullName(IntPtr hProcess, ref uint packageFullNameLength, StringBuilder packageFullName);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool IsWindowVisible(IntPtr hWnd);
    
            [StructLayout(LayoutKind.Sequential)]
            public struct RECT
            {
                public int left;
                public int top;
                public int right;
                public int bottom;
            }
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    
            public const int SPI_GETWORKAREA = 0x0030;
    
            [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern bool SystemParametersInfo(uint uiAction, uint uiParam, [In, Out] ref RECT pvParam, uint fWinIni);
    
            [DllImport("Shell32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
            public static extern HRESULT SHGetPropertyStoreForWindow(IntPtr hwnd, ref Guid iid, [Out(), MarshalAs(UnmanagedType.Interface)] out IPropertyStore propertyStore);
    
            public struct PROPERTYKEY
            {
                public PROPERTYKEY(Guid InputId, UInt32 InputPid)
                {
                    fmtid = InputId;
                    pid = InputPid;
                }
                Guid fmtid;
                uint pid;
            };
    
            [StructLayout(LayoutKind.Sequential, Pack = 0)]
            public struct PROPARRAY
            {
                public UInt32 cElems;
                public IntPtr pElems;
            }
    
            [StructLayout(LayoutKind.Explicit, Pack = 1)]
            public struct PROPVARIANT
            {
                [FieldOffset(0)]
                public ushort varType;
                [FieldOffset(2)]
                public ushort wReserved1;
                [FieldOffset(4)]
                public ushort wReserved2;
                [FieldOffset(6)]
                public ushort wReserved3;
    
                [FieldOffset(8)]
                public byte bVal;
                [FieldOffset(8)]
                public sbyte cVal;
                [FieldOffset(8)]
                public ushort uiVal;
                [FieldOffset(8)]
                public short iVal;
                [FieldOffset(8)]
                public UInt32 uintVal;
                [FieldOffset(8)]
                public Int32 intVal;
                [FieldOffset(8)]
                public UInt64 ulVal;
                [FieldOffset(8)]
                public Int64 lVal;
                [FieldOffset(8)]
                public float fltVal;
                [FieldOffset(8)]
                public double dblVal;
                [FieldOffset(8)]
                public short boolVal;
                [FieldOffset(8)]
                public IntPtr pclsidVal; // GUID ID pointer
                [FieldOffset(8)]
                public IntPtr pszVal; // Ansi string pointer
                [FieldOffset(8)]
                public IntPtr pwszVal; // Unicode string pointer
                [FieldOffset(8)]
                public IntPtr punkVal; // punkVal (interface pointer)
                [FieldOffset(8)]
                public PROPARRAY ca;
                [FieldOffset(8)]
                public System.Runtime.InteropServices.ComTypes.FILETIME filetime;        
            }
    
            [ComImport,  Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"),  InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
            public interface IPropertyStore
            {
                HRESULT GetCount([Out] out uint propertyCount);
                HRESULT GetAt([In] uint propertyIndex, [Out, MarshalAs(UnmanagedType.Struct)] out PROPERTYKEY key);
                HRESULT GetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [Out, MarshalAs(UnmanagedType.Struct)] out PROPVARIANT pv);
                HRESULT SetValue([In, MarshalAs(UnmanagedType.Struct)] ref PROPERTYKEY key, [In, MarshalAs(UnmanagedType.Struct)] ref PROPVARIANT pv);
                HRESULT Commit();
            }
    
            public static PROPERTYKEY PKEY_AppUserModel_ID = new PROPERTYKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5);
    
            public static bool ListWindows(IntPtr hWnd, ref IntPtr lParam)
            {
                ENUMPARAM ep = (ENUMPARAM)Marshal.PtrToStructure(lParam, typeof(ENUMPARAM));
    
                StringBuilder sbClassName = new StringBuilder(260);
                string sClassName = null;
    
                GetClassName(hWnd, sbClassName, (int)(sbClassName.Capacity));
                sClassName = sbClassName.ToString();
    
                // Minimized :  "Windows.UI.Core.CoreWindow" top window
                if (sClassName == "Windows.UI.Core.CoreWindow")
                {
                    int nPID = 0;
                    uint nThreadId = GetWindowThreadProcessId(hWnd, out nPID);
                    IntPtr hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, nPID);
                    string sPackage = string.Empty;
                    if (hProcess != IntPtr.Zero)
                    {
                        uint nSize = 260;
                        StringBuilder sPackageFullName = new StringBuilder((int)nSize);
                        GetPackageFullName(hProcess, ref nSize, sPackageFullName);
                        if (sPackageFullName.ToString().ToLower().Contains ("calculator") && IsWindowVisible(hWnd))
                        {
                            nSize = 260;
                            StringBuilder sProcessImageName = new StringBuilder((int)nSize);
                            QueryFullProcessImageName(hProcess, 0, sProcessImageName, ref nSize);
                            //hWnd = FindWindow("ApplicationFrameWindow", "Calculatrice");
                            //ep.hWnd = hWnd;
                            ep.sExeName = sProcessImageName.ToString();
                            ep.nPID = nPID;
                            ep.nState = 1;
                            Marshal.StructureToPtr(ep, lParam, false);
                            if (ep.hWnd != IntPtr.Zero)
                            {
                                CloseHandle(hProcess);
                                return false;
                            }
                        }
                        CloseHandle(hProcess);
                    }
                }
    
                // Normal : "Windows.UI.Core.CoreWindow" child of "ApplicationFrameWindow"
                if (sClassName == "ApplicationFrameWindow")
                {
                    // get real hWnd 
                    IPropertyStore pPropertyStore;
                    Guid guid = new Guid("{886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99}");                
                    HRESULT hr = SHGetPropertyStoreForWindow(hWnd, ref guid, out pPropertyStore);
                    //if (hr != HRESULT.S_OK)
                    //    throw Marshal.GetExceptionForHR((int)hr);
                    if (hr == HRESULT.S_OK)
                    {
                        PROPVARIANT propVar = new PROPVARIANT();
                        hr = pPropertyStore.GetValue(ref PKEY_AppUserModel_ID, out propVar);
                        string sAUMID = Marshal.PtrToStringUni(propVar.pwszVal);
                        if (sAUMID != null && sAUMID.ToLower().Contains("calculator"))
                        { 
                            RECT rect, rectWorkArea = new RECT();
                            GetWindowRect(hWnd, out rect);
                            IntPtr pRectWorkArea = IntPtr.Zero;
                            bool bRet = SystemParametersInfo(SPI_GETWORKAREA, 0, ref rectWorkArea, 0);                       
                            // maximized : out of SPI_GETWORKAREA   
                            if (rect.left < rectWorkArea.left && rect.top < rectWorkArea.top && rect.right > rectWorkArea.right && rect.bottom > rectWorkArea.bottom)
                                ep.nState = 2;
                            ep.hWnd = hWnd;
                            Marshal.StructureToPtr(ep, lParam, false);
                        }
                        Marshal.ReleaseComObject(pPropertyStore);
                    }
    
                    IntPtr hWndFind = FindWindowEx(hWnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);               
                    if (hWndFind != IntPtr.Zero)
                    {
                        int nPID = 0;
                        uint nThreadId = GetWindowThreadProcessId(hWndFind, out nPID);
                        IntPtr hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, nPID);
                        string sPackage = string.Empty;
                        if (hProcess != IntPtr.Zero)
                        {
                            uint nSize = 260;
                            StringBuilder sPackageFullName = new StringBuilder((int)nSize);
                            GetPackageFullName(hProcess, ref nSize, sPackageFullName);
                            if (sPackageFullName.ToString().ToLower().Contains("calculator") && IsWindowVisible(hWnd))
                            {
                                nSize = 260;
                                StringBuilder sProcessImageName = new StringBuilder((int)nSize);
                                QueryFullProcessImageName(hProcess, 0, sProcessImageName, ref nSize);
                                ep.hWnd = hWnd;
                                ep.sExeName = sProcessImageName.ToString();
                                ep.nPID = nPID;
                                Marshal.StructureToPtr(ep, lParam, false);
                                CloseHandle(hProcess);
                                return false;
                            }
                            CloseHandle(hProcess);
                        }
                    }
                }
                return true;
            }
            public Form1()
            {
                InitializeComponent();
            }
    
            private System.Windows.Forms.Button button1;
    
            private void Form1_Load(object sender, EventArgs e)
            {
                this.button1 = new System.Windows.Forms.Button();
    
                this.button1.Location = new System.Drawing.Point(105, 110);
                this.button1.Name = "button1";
                this.button1.Size = new System.Drawing.Size(75, 23);
                this.button1.TabIndex = 0;
                this.button1.Text = "Find Calc";
                this.button1.UseVisualStyleBackColor = true;
                this.button1.Click += new System.EventHandler(this.button1_Click);
    
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(284, 261);
    
                this.Controls.Add(this.button1);
                CenterToScreen();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                EnumWindowsProc Callback = new EnumWindowsProc(ListWindows);
                ENUMPARAM ep = new ENUMPARAM();
                IntPtr plParam = Marshal.AllocHGlobal(Marshal.SizeOf(ep));
                Marshal.StructureToPtr(ep, plParam, false);
                EnumWindows(Callback, ref plParam);
                ENUMPARAM epret = (ENUMPARAM)Marshal.PtrToStructure(plParam, typeof(ENUMPARAM));
                Marshal.FreeHGlobal(plParam);
                if (epret.hWnd != IntPtr.Zero)
                {
                    // State can also be got with UI Automation and WindowVisualState
                    //string sState = (epret.nState == 1) ? "\n(state = minimized)" : "";
                    string sState = string.Empty;
                    switch (epret.nState)
                    {
                        case 0:
                            sState = "Normal";
                            break;
                        case 1:
                            sState = "Minimized";
                            break;
                        case 2:
                            sState = "Maximized";
                            break;                  
                    }
                    MessageBox.Show(string.Format("Window handle = {0}\nPID = {1}\nExecutable = {2}\nState = {3}", epret.hWnd.ToString("X"), epret.nPID, epret.sExeName, sState), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);               
                }
                else
                    MessageBox.Show("Calc not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    
                ShowWindow(epret.hWnd, SW_SHOWNORMAL);
            }
    
            [StructLayoutAttribute(LayoutKind.Sequential)]
            private struct ENUMPARAM
            {
                public IntPtr hWnd;
                public int nPID;
                public string sExeName;
                public int nState;
            }
        }

    • Proposed as answer by Stanly Fan Thursday, April 5, 2018 1:11 AM
    Wednesday, April 4, 2018 5:04 PM