none
[Win10 + c#] WindowHandle and Process.Id issue with ApplicationFrameHost.exe RRS feed

  • Question

  • How do I get the right process ID and IntPtr for calc or taskmgr for instance.

    step 1) I start a simple process for calc and taskmgr

    Process ps= Process.Start("calc");

    Note: If you check ps.Id, you won't find it in the task manager ui because it is one of those ApplicationFrameHost.exe

    Note: it seems ps exit right away when the calculator is started so how do I get a handle on the process or ui of calculator?

    Then how do I get the right IntPtr? ps.MainWindowHandle will be 0 because of ApplicationFrameHost.exe

    step 2) This solution with FindWindow work but is incomplete as it require the title, how do I know the title from a process? ps.MainWindowTitle won't work of course as it is a ApplicationFrameHost.exe

    IntPtr ptr4 = FindWindow(null, "Calculator");

    step 3) I can do a FinWindow and iterate thought all the windows and call GetWindowThreadProcessId(wh.RawPtr, out psId); and compare psId to ps.Id but that doesn't work either because the process ps (that is generated to start "calc") is not the same as the psId (from GetWindowThreadProcessId -> this will return the ApplicationFrameHost.exe)

    How do I reconciliate Title, ps.Id, IntPtr/WindowHandle? how do I get the real process/name/title, intptr behind Caclulator or taskmgr (from any tile or any ApplicationFrameHost.exe)? I'm basically looking for something generic that works for any process.

    A simple question is what is the WindowHandle/IntPtr of the window (a calculator) I just started ( Process.Start("calc");)?

    I dd read many articles (50+) over the web and try many things (FindWindowEx, EnumWindows....), but I didn't find a good solution so far.

    I'm not sure what is the right forum for this? c# or c++ standards and interop or something else? can you please move it if necessary - I'm using c#.

    Thanks for your help


    w.







    • Edited by wil70 Saturday, March 17, 2018 7:07 PM
    Saturday, March 17, 2018 6:34 PM

Answers

  • You must use  the class name + the title to identify a window, or APIs like EnumDesktopWindows, used by Task Manager.

    For example, on my OS (Windows 10, french), it is "Windows.UI.Core.CoreWindow" + "Calculatrice", but the hierarchy is not the same when minimized or not.

    Class : "Windows.UI.Core.CoreWindow"
    Text : "Calculatrice"
    Executable : "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1802.311.0_x64__8wekyb3d8bbwe\Calculator.exe"
    AppUserModel_ID : ""
    Package : "Microsoft.WindowsCalculator_10.1802.311.0_x64__8wekyb3d8bbwe"
    Cloaked : DWM_CLOAKED_SHELL
    
    Class : "ApplicationFrameWindow"
    Text : "Calculatrice"
    Executable : "C:\Windows\System32\ApplicationFrameHost.exe"
    AppUserModel_ID : "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"
    Package : ""
    Cloaked : 0


    • Marked as answer by wil70 Tuesday, March 20, 2018 2:03 PM
    Sunday, March 18, 2018 12:14 AM
  • Do you have some c# code to do this?

    A test with class name and package name for Calc on Windows 10 (I test "calculator" in the package name, not sure if it is this name in other languages... ) :

    public partial class Form1 : Form
    {
        [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 FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool IsWindowVisible(IntPtr hWnd);
    
        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
            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);
    
                        ep.hWnd = hWnd;
                        ep.sExeName = sProcessImageName.ToString();
                        ep.nPID = nPID;
                        ep.nState = 1;
                        Marshal.StructureToPtr(ep, lParam, false);
                        CloseHandle(hProcess);
                        return false;
                    }
                    CloseHandle(hProcess);
                }
            }
    
            // Normal
            if (sClassName == "ApplicationFrameWindow")
            {
                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)
            {
                string sState = (epret.nState == 1) ? "\n(state = minimized)" : "";
                MessageBox.Show(string.Format("Window handle = {0}\nPID = {1}\nExecutable = {2}" + sState, epret.hWnd.ToString("X"), epret.nPID, epret.sExeName), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);               
            }
            else
                MessageBox.Show("Calc not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    
        [StructLayoutAttribute(LayoutKind.Sequential)]
        private struct ENUMPARAM
        {
            public IntPtr hWnd;
            public int nPID;
            public string sExeName;
            public int nState;
        }
    }



    • Edited by Castorix31 Sunday, March 18, 2018 5:53 PM
    • Proposed as answer by Fei HuModerator Tuesday, March 20, 2018 9:52 AM
    • Marked as answer by wil70 Tuesday, March 20, 2018 2:03 PM
    Sunday, March 18, 2018 4:55 PM

All replies

  • Calc class is "Windows.UI.Core.CoreWindow"

    GetWindowThreadProcessId() gives me the same PID as in Task Manager

    Saturday, March 17, 2018 8:25 PM
  • I'm wondering if you tried on win10? (for me it is working on win7 as there is no concept of ApplicationFramehost.exe but failing on win 10)

    For me, on win 10, it always returns the process id of ApplicationFrameHost.exe
    Note: Many people are having the same issue on différent forums...

    Even if I do not know the name of the className(as my application only deal with ps and hwd)

    I tried with 

                IntPtr ptr2 = WinAPI.FindWindow(null, "Calculator");
                IntPtr ptr3 = WinAPI.FindWindow("Windows.UI.Core.CoreWindow", null);

    Result: ptr2 is diff than ptr3 (1 calculator is started)

    and for both ptr2 and ptr3 I tried (by switching ptr)

                    uint uint1 = WinAPI.GetWindowThreadProcessId(ptr, out psId);
                    IntPtr int1 = WinAPI.GetWindowThreadProcessId(ptr, IntPtr.Zero);
                    IntPtr int2 = WinAPI.GetWindowThreadProcessId(ptr, out pid2);

    Result: They were different for both ptr2 and ptr3, and none of them was the process id from Calculator in "task manager" (ptr2 returns the process id of ApplicationFramehost.exe and ptr3 returned lockApp.exe)




    w.



    • Edited by wil70 Saturday, March 17, 2018 10:42 PM
    Saturday, March 17, 2018 10:40 PM
  • You must use  the class name + the title to identify a window, or APIs like EnumDesktopWindows, used by Task Manager.

    For example, on my OS (Windows 10, french), it is "Windows.UI.Core.CoreWindow" + "Calculatrice", but the hierarchy is not the same when minimized or not.

    Class : "Windows.UI.Core.CoreWindow"
    Text : "Calculatrice"
    Executable : "C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1802.311.0_x64__8wekyb3d8bbwe\Calculator.exe"
    AppUserModel_ID : ""
    Package : "Microsoft.WindowsCalculator_10.1802.311.0_x64__8wekyb3d8bbwe"
    Cloaked : DWM_CLOAKED_SHELL
    
    Class : "ApplicationFrameWindow"
    Text : "Calculatrice"
    Executable : "C:\Windows\System32\ApplicationFrameHost.exe"
    AppUserModel_ID : "Microsoft.WindowsCalculator_8wekyb3d8bbwe!App"
    Package : ""
    Cloaked : 0


    • Marked as answer by wil70 Tuesday, March 20, 2018 2:03 PM
    Sunday, March 18, 2018 12:14 AM
  • Thanks Castorix31, let me dig a bit.

    How do you generate/get those output automatically? Class, Text, Executable, AppSuerModel_ID, Packageand Cloadked ...

    Do you have some c# code to do this?

    thanks for sharing


    • Edited by wil70 Sunday, March 18, 2018 2:56 PM
    Sunday, March 18, 2018 12:44 AM
  • Do you have some c# code to do this?

    A test with class name and package name for Calc on Windows 10 (I test "calculator" in the package name, not sure if it is this name in other languages... ) :

    public partial class Form1 : Form
    {
        [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 FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
    
        [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool IsWindowVisible(IntPtr hWnd);
    
        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
            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);
    
                        ep.hWnd = hWnd;
                        ep.sExeName = sProcessImageName.ToString();
                        ep.nPID = nPID;
                        ep.nState = 1;
                        Marshal.StructureToPtr(ep, lParam, false);
                        CloseHandle(hProcess);
                        return false;
                    }
                    CloseHandle(hProcess);
                }
            }
    
            // Normal
            if (sClassName == "ApplicationFrameWindow")
            {
                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)
            {
                string sState = (epret.nState == 1) ? "\n(state = minimized)" : "";
                MessageBox.Show(string.Format("Window handle = {0}\nPID = {1}\nExecutable = {2}" + sState, epret.hWnd.ToString("X"), epret.nPID, epret.sExeName), "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);               
            }
            else
                MessageBox.Show("Calc not found", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    
        [StructLayoutAttribute(LayoutKind.Sequential)]
        private struct ENUMPARAM
        {
            public IntPtr hWnd;
            public int nPID;
            public string sExeName;
            public int nState;
        }
    }



    • Edited by Castorix31 Sunday, March 18, 2018 5:53 PM
    • Proposed as answer by Fei HuModerator Tuesday, March 20, 2018 9:52 AM
    • Marked as answer by wil70 Tuesday, March 20, 2018 2:03 PM
    Sunday, March 18, 2018 4:55 PM