locked
How to use GetForeGroundWindow() to get newly launched application windows instance in C#?

    Question

  • Hello All,

    I am trying to capture newly launched application using GetForegroundWindow() using P/Invoke in C#. However, all i get is explorer.exe window handle instead of the actual process window handle that was launched.

    Actually i am trying to log user entered text when user opens "notepad" at the same time i want to get the actual handle of the "notepad" instance(if multiple notepad instances are open) in which user is attempting to write something.

    i.e I launch notepad.exe from start menu on Windows 7 Ultimate x64 with my C#.Net based application running for keys pressed. I have setup application key hooks in my application so that on text changed event, the application attempts to get the foreground window. The problem is: It gets explorer.exe instead of notepad.exe.

    The code works for already-open windows perfectly but it doesn't work for newly launched instances of any application such as chrome, notepad, wordpad or any other. Instead of logging text against the correct application, it logs text for explorer.exe. Here is my code:

     private string GetActiveWindowTitle()
        {
            const int nChars = 256;
            IntPtr handle = IntPtr.Zero;
            StringBuilder Buff = new StringBuilder(nChars);
            handle = GetForegroundWindow();
    
            if (GetWindowText(handle, Buff, nChars) > 0)
            {
                return Buff.ToString();
            }
            return null;
        }
        Process GetActiveProcess()
        {
            Process[] AllProcess = Process.GetProcesses();
            String title = GetActiveWindowTitle();
    
            foreach (Process pro in AllProcess)
            {
                if (title.Equals(pro.MainWindowTitle))
                {
                    return pro;
                }
            }
            return Process.GetCurrentProcess();
        }
    
        string GetActiveProcessFileName()
        {
            IntPtr hwnd = GetForegroundWindow();
            SetForegroundWindow(hwnd);
            uint pid;
            GetWindowThreadProcessId(hwnd, out pid);
            Process p = Process.GetProcessById((int)pid);
            //p.MainModule.FileName.Dump();
            return p.ProcessName;
        }
    
        ProcessInfo GetActiveProcessInfo()
        {
            IntPtr hwnd = GetForegroundWindow();
    
            const int nChars = 256;
            StringBuilder Buff = new StringBuilder(nChars);
            uint pid;
            GetWindowThreadProcessId(hwnd, out pid);
            Process p = Process.GetProcessById((int)pid);
            ProcessInfo pi = new ProcessInfo();
            if (GetWindowText(hwnd, Buff, nChars) > 0)
            {
                pi.ProcessTitle = Buff.ToString();
            }
            pi.ProcessName = p.ProcessName;
            pi.ProcessHandle = (int)p.MainWindowHandle;
    
            return pi;
        }
    

    GetActiveProcessInfo returns explorer.exe instead of correct application i.e notepad.exe because the GetForegroundWindow() read explorer.exe as foreground window. The same code reads the correct application window when i type in existing open applications and donot launch a new instance of teh application.

    I read somewhere  that there is some race-condition problem. if this is the case, how can i solve this?

    Please help me. I am really stuck on this very long.

    Thanks.


    ~~ A man's dreams are an index to his Greatness ~~

    Monday, April 02, 2012 8:38 AM

Answers

  • Ok so i changed my code. and this now works for me. Maybe it helps somebody else.

    The conclusion is GetForegroundWindow(0 functions was returning correctly. I had problem with other functions. Here is the new code.

    public ProcessInfo GetCurrentProcess() { Process[] AllProcess = Process.GetProcesses(); String title = GetActiveWindowTitle(); IntPtr handle = GetForegroundWindow(); Process pro = null; foreach (Process p in AllProcess) { try { if (p.MainWindowTitle.Equals(title)) { pro = p; break; } } catch (Exception) { } } ProcessInfo pi = new ProcessInfo(); if (pro == null) { pi.ProcessTitle = title; pi.ProcessHandle = handle.ToInt32(); pi.ProcessName = title; } else { pi.ProcessTitle = pro.MainWindowTitle; pi.ProcessName = pro.ProcessName; pi.ProcessHandle = (int)pro.MainWindowHandle; } if (title.Equals(System.Diagnostics.Process.GetCurrentProcess().MainWindowTitle)) { //Some windows don't have title like IE 9 when it is launched or a new tab is opened!

    //or some windows have strange title

    Process myProcess = Process.GetProcesses().Single(p => p.Id != 0 && p.Handle == handle); pi.ProcessTitle = myProcess.MainWindowTitle + "Empty"; pi.ProcessHandle = handle.ToInt32(); pi.ProcessName = myProcess.ProcessName + "Empty"; //Access is denied } return pi; }

    Empty is just appended for testing. It must be removed in production code.

    Thanks for all the help.


    ~~ A man's dreams are an index to his Greatness ~~


    • Edited by timematcher Thursday, April 12, 2012 6:33 AM fixed spelling, grammar
    • Marked as answer by timematcher Thursday, April 12, 2012 6:33 AM
    Thursday, April 12, 2012 6:32 AM

All replies

  • Syntax:

    HWND WINAPI GetForegroundWindow(void);

    Paramerter

    This function has no parameters.

    Return Value

    Type:

    Type: HWND

    The return value is a handle to the foreground window. The foreground window can beNULL in certain circumstances, such as when a window is losing activation.

    it require User32.lib
    Tuesday, April 03, 2012 8:40 AM
  • Thank you for your response.

    The thing is: I never get a NULL handle in response to GetForeGroundWindow(). I get the wrong handle though and it of explorer.exe.

    The question is: Even if the problem can be due to Null handle being returned, how can i fix it? I need to get handle to the foreground window when a new application is launched, focused and user is writing text inside that windows such as that of notepad.

    Any help is appreciated.

    Thanks


    ~~ A man's dreams are an index to his Greatness ~~

    Tuesday, April 03, 2012 4:24 PM
  • Hi,

    Could you please provide us with the codes about how you do the keyboard hook and when you call codes to get the foreground window?   I think the problem might the moment when we call GetForegroundWindow API.  Besides, would you mind letting us know why do you want to develop such an app to get the user's input?   Please understand that it may lead to malicious codes.

    Good day!

    Thanks


    Michael Sun [MSFT]
    MSDN Community Support | Feedback to us

    Wednesday, April 04, 2012 1:54 AM
    Moderator
  • Hi,

    Any update of this issue?  If you need any assistance, please feel free to let me know.

    Good day!

    Thanks


    Michael Sun [MSFT]
    MSDN Community Support | Feedback to us

    Thursday, April 12, 2012 1:49 AM
    Moderator
  • Ok so i changed my code. and this now works for me. Maybe it helps somebody else.

    The conclusion is GetForegroundWindow(0 functions was returning correctly. I had problem with other functions. Here is the new code.

    public ProcessInfo GetCurrentProcess() { Process[] AllProcess = Process.GetProcesses(); String title = GetActiveWindowTitle(); IntPtr handle = GetForegroundWindow(); Process pro = null; foreach (Process p in AllProcess) { try { if (p.MainWindowTitle.Equals(title)) { pro = p; break; } } catch (Exception) { } } ProcessInfo pi = new ProcessInfo(); if (pro == null) { pi.ProcessTitle = title; pi.ProcessHandle = handle.ToInt32(); pi.ProcessName = title; } else { pi.ProcessTitle = pro.MainWindowTitle; pi.ProcessName = pro.ProcessName; pi.ProcessHandle = (int)pro.MainWindowHandle; } if (title.Equals(System.Diagnostics.Process.GetCurrentProcess().MainWindowTitle)) { //Some windows don't have title like IE 9 when it is launched or a new tab is opened!

    //or some windows have strange title

    Process myProcess = Process.GetProcesses().Single(p => p.Id != 0 && p.Handle == handle); pi.ProcessTitle = myProcess.MainWindowTitle + "Empty"; pi.ProcessHandle = handle.ToInt32(); pi.ProcessName = myProcess.ProcessName + "Empty"; //Access is denied } return pi; }

    Empty is just appended for testing. It must be removed in production code.

    Thanks for all the help.


    ~~ A man's dreams are an index to his Greatness ~~


    • Edited by timematcher Thursday, April 12, 2012 6:33 AM fixed spelling, grammar
    • Marked as answer by timematcher Thursday, April 12, 2012 6:33 AM
    Thursday, April 12, 2012 6:32 AM
  • Thanks!

    Have a nice day!


    Michael Sun [MSFT]
    MSDN Community Support | Feedback to us

    Thursday, April 12, 2012 6:34 AM
    Moderator