Link to home
Start Free TrialLog in
Avatar of Administrator
Administrator

asked on

Retreive window title bar from PID?

Hi there!
Here is my problem:

Using the ToolHelp functions, I have the PID and the path+filename of every running processes on my PC. Is there a way from those values to retrieve the corresponding windows title?
Example: I have
PID = FFFAF5C9
filename = msdev.exe

And I want to retrieve "Microsoft Visual C++"...

Any idea?
Avatar of Administrator
Administrator

ASKER

Edited text of question.
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I hope that if this code works you give me the credit... i was gonna propose an answer, but quick jkr has done it first :-))

HWND ph;
char title[MAX_PATH];

ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (ph != 0) {
  GetWindowText(ph, title, MAX_PATH);
  MessageBox(title);
CloseHandle(ph);

-= Viktor =-
opps... pid is your PID variable :-))

-Viktor-
and i forgot the closing bracket..

this is how your code should look like.

HWND ph;
     char title[MAX_PATH];

     ph = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
     if (ph != 0) {
       GetWindowText(ph, title, MAX_PATH);
       MessageBox(title);
     }  //<<------- I had forgotten this bracket :-))
     CloseHandle(ph);

-=Viktor=-
The following code illustrates how to do it:

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam) :


LPSTR GetWindowTitleFromPID ( DWORD dwProcessId)
{
 g_hwnd = NULL;
 g_nFound = 0;

 EnumWindows (  FindHwndFromPID,    ( LPARAM) dwProcessId));

 if ( g_nFound)  // we found one...
      return ( g_acTitle);

 // nothing found :-(

 return (NULL);
}

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam)
{
    DWORD   dwPID2Find  =   ( DWORD) lParam;
    DWORD   dwPID       =   0;

    if  (   GetWindowThreadProcessId    (   hwnd,   &dwPID))
        {
            if  (   dwPID   ==  dwPID2Find)
                {
                    g_hwnd  =   hwnd;

                    g_ nFound = GetWindowText ( g_hwnd, g_acTitle, MAX_SIZE);

                    return  (   FALSE);
                }
        }

    return  (   TRUE);
}
The following code illustrates how to do it:

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam) :


LPSTR GetWindowTitleFromPID ( DWORD dwProcessId)
{
 g_hwnd = NULL;
 g_nFound = 0;

 EnumWindows (  FindHwndFromPID,    ( LPARAM) dwProcessId));

 if ( g_nFound)  // we found one...
      return ( g_acTitle);

 // nothing found :-(

 return (NULL);
}

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam)
{
    DWORD   dwPID2Find  =   ( DWORD) lParam;
    DWORD   dwPID       =   0;

    if  (   GetWindowThreadProcessId    (   hwnd,   &dwPID))
        {
            if  (   dwPID   ==  dwPID2Find)
                {
                    g_hwnd  =   hwnd;

                    g_ nFound = GetWindowText ( g_hwnd, g_acTitle, MAX_SIZE);

                    return  (   FALSE);
                }
        }

    return  (   TRUE);
}
Sorry for the double posting ;-)

NOTE that i simply hacke down the above code from scratch, no guarantee that it'll instantly compile - but i hope you got the idea ;-)
Sorry Viktor, but for 'GetWindowText()' we need a HWND rather than a process handle...
That's why I said if it works, because i have not tested it, and don't know if it would work :-))

Your code looks okay to me... But i would appraciate it if you coul try mine too. If it works it's a lot simpler and faster than going through all the windows and look for the PID...

-= Viktor =-
>>Your code looks okay to me...

Thanx ;-)

I really just typed it into Notepad <s> - 3:45am here and i should go to bed... but nevertheless, Viktor, as elegant as your approach would be, a process handle won't work, as proceeses don't have aa necessary relationship to  GDI objectd (just imagine they would - each service would be forced to have a GUI...;-)
yeah, i guess you are right :-)

well, talk to you later then ;-)
But not too tired to see that i forgot to declare the global variables:

HWND  g_hwnd;
int  g_nFound;
char g_acTitle[ MAX_SIZE];

sorry, Administrator...

So the commplete code should read:

// globals
HWND  g_hwnd;
int  g_nFound;
char g_acTitle[ MAX_SIZE];

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam) :


LPSTR GetWindowTitleFromPID ( DWORD dwProcessId)
{
 g_hwnd = NULL;
 g_nFound = 0;

 EnumWindows (  FindHwndFromPID,    ( LPARAM) dwProcessId));

 if ( g_nFound)  // we found one...
      return ( g_acTitle);

 // nothing found :-(

 return (NULL);
}

BOOL CALLBACK FindHwndFromPID( HWND hwnd, LPARAM lParam)
{
    DWORD   dwPID2Find  =   ( DWORD) lParam;
    DWORD   dwPID       =   0;

    if  (   GetWindowThreadProcessId    (   hwnd,   &dwPID))
        {
            if  (   dwPID   ==  dwPID2Find)
                {
                    g_hwnd  =   hwnd;

                    g_ nFound = GetWindowText ( g_hwnd, g_acTitle, MAX_SIZE);

                    return  (   FALSE);
                }
        }

    return  (   TRUE);
}
Well.
Thanks a lot for both of you.
There is a problem with the HWND confusion with Viktor's answer.

But jkr's answer is very close to the solution:
Using your code, I can retrieve the Title of ... 70% of the running Windows. But not for the 30% left... GetWindowText simply return nothing! But the PID is correct.

Any idea?
I didn't grade jkr just to leave the thread open. But even if you don't give me anything else, I'll give you my 400 points.

Thanx again.
>>GetWindowText simply return nothing! But the PID is correct

Could it be that these are either the PIDs of console windows or of processes that don't have a window?
>>GetWindowText simply return nothing! But the PID is correct

Could it be that these are either the PIDs of console windows or of processes that don't have a window?

>>I didn't grade jkr just to leave the thread open

The thread stays always open ;-)
Hum.
Well 'Process Viewer' which comes with VisualC++ gives exactly the same list of processes than my app does. But there are processes that of course don't have any window.

The problem is that for the processes that DO have a window, GetWindowText sometimes return nothing.

I have changed a little bit your function to try something:

In FindHwndFromPID, when you return FALSE, I do nothing.
So there is another call, even if the PID was the good one.
And there IS the problem:
When there is a second call, the PID is good again...

Example:
Fisrt call : wrong PID
Second call : good PID : no title
Third call : good PID : title = "Properties"
Fourth call : good PID : title = "Microsoft Visual C++"
Fifth call : good PID : title = "MSDN Library" (the help!!!)
Sixth call : good PID : no title
etc...

How could I know which ones of these call is the good one???
Weird isn't it?

I had an idea but no success:
g_hwnd always change of course, and I thought that if it doesn't have a parent, it would be the one I'm looking for. But that's not the case... Well, not always!
>>In FindHwndFromPID, when you return FALSE, I do nothing

This is a callback function called by windows internally (when using 'EnumWindows()' - when this function returns FALSE, it simply means that the enumeration should be stopped (i.e. we found the window matching the PID)
I know:-)
What I meant by 'I do nothing' was that I was not stopping the enumeration : which gave me the weird values for one PID.

Problem:
There are more than one window handle for only one PID.
Which one of these handles is the good one?
Well, I have changed your code a little bit and now it fits exactly my needs!

The only thing I have added, are 2 verifications on the handle:
- it has to be visible
- it has to get no parent

Merci beaucoup ;-)
Arn@ud
Great!

As i said - it was a quick hack at 3:45am so i'm quite content that it works without major modifications ;-)