Link to home
Start Free TrialLog in
Avatar of VoidHawk
VoidHawk

asked on

Window Handlers

Due to a lack of reference material on my behalf, I'm having difficulty in implementing the following:

I wish to execute an installed application, say an instance of MS Internet Explorer, and return the window handle of the browser window it opens so that I may retrieve its coordinates, send commands such as maximise, setfocus, set the window size, retrieve the title bar contents, etc.

Additionally (or if the above is not possible) I want to be able to return the handles of all top level windows belonging to a running process eg "iexplore.exe". I've attempted using EnumWindows in conjunction with EnumWindowsProc, searching for handles based in title contents. I know its not the best solution, but I'd like to know where I went wrong since I always get stuck in an infinite loop. The code is as follows:

What I tried to do here is append the title of each window to a message box's contents. If it weren't for the counter to forcibly stop the process, it would simply loop infinately through the titles of each window over and over again.

I'm using Borland C++ Builder 5.

//--------------------------------------

TForm1 *Form1;

BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
      char text[200];
      GetWindowText(hwnd,text,200);
      Form1->Memo1->Lines->Add(text);
      Form1->counter++;
      if (Form1->counter == 1000) return FALSE;
      return TRUE;
};

//--------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{

      HWND hwnd;
      LPARAM lParam = 0;

    Form1->counter = 0;

      while(EnumWindows((WNDENUMPROC)EnumWindowsProc, lParam))
      {
            EnumWindowsProc(hwnd,lParam);
      }

}
//--------------------------------------


I would greatly appreciate code examples.
Avatar of pjknibbs
pjknibbs

The reason you're getting an infinite loop is because you appear to have misunderstood how EnumWindows() works. EnumWindows() does all the calling of EnumWindowsProc() for you, and it only returns FALSE if it encounters an error. Therefore, what your WHILE loop above will do is: firstly enumerate all the windows on the system via EnumWindows(). EnumWindows() will almost certainly succeed, so you then call EnumWindowsProc() with a garbage window handle (since you never assign anything to hWnd). It then goes round the loop again, enumerating the windows again.

*All* the windows EnumXXX functions work this way, which is why you pass them the address of the enumeration procedure in the first place!
ASKER CERTIFIED SOLUTION
Avatar of pjknibbs
pjknibbs

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
pjknibbs is completely right. Just one addition: If you've enumerated all windows of that main thread, the question is still: Which one is (or are) the main window(s)?
Main windows (that is windows that are visible as buttons in the taskbar) don't have a parent window nor an owner window. Also they must be visible and must not have the WS_EX_TOOLWINDOW style bit set in the extended window style. (APIs GetWindow(window, GW_OWNER), GetParent(window), GetWindowLong(window, GWL_EXSTYLE))

Regards, Madshi.
.. and IsWindowVisible(window)...
Avatar of VoidHawk

ASKER

Thanks very much for that - It really clears things up. I was using a code example written by someone else for EnumWindows. I have altered it to the following.

//--------------------------------------

TForm1 *Form1;

bool EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
      char text[200];
      GetWindowText(hwnd,text,200);
      Form1->Memo1->Lines->Add(text);
      return TRUE;
};

//--------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
      EnumWindows((WNDENUMPROC) EnumWindowsProc,NULL);
}
//--------------------------------------

Just for clarification, Why must I use (WDENUMPROC) in EnumWindows? And why won't it work without the brackets?

As for CreateProcess(), I was looking at ShellExecute() which only returned the application's instance handle.

One last thing, as I asked in my initial question, is it possible to go through all of the active processes and return the window handles from a process of a particular name without knowing its process ID? eg. search for all instances of iexplore.exe and return its top level window handles?

Oh to be able to afford a decent reference book. (Student budget)
>> Just for clarification, Why must I use (WDENUMPROC) in EnumWindows? And why won't it work without the brackets?

Well, I'm using (and loving) Delphi, there are no such syntax mysteriums...  :-)

>> As for CreateProcess(), I was looking at ShellExecute() which only returned the application's instance handle.

You can't do anything with the instance handle. Neither can you do something (that helps you with finding the windows) with the process handle that you can get from ShellExecuteEx. So CreateProcess is the way to go here.

>> is it possible to go through all of the active processes and return the window handles from a process of a particular name without knowing its process ID? eg. search for all instances of iexplore.exe and return its top level window handles?

I told you how to find the top level windows from the PID. So the only part missing is: How to get the PID of all running iexplore.exe instances? That's quite ugly. It's different under win9x and winNT. Under win9x you have to use the toolhelp functions, under winNT the library "psApi.dll" (which you have to distribute with your app).

Regards, Madshi.
(WNDENUMPROC) is just there to keep your compiler happy. It tells it that yes, the function you are supplying *is* of the correct form for an EnumWindows() callback even if the compiler doesn't think it is. You could avoid using this if you declared EnumWindowsProc() *exactly* as it is in the header files rather than the documentation, but who has time to search the headers when a cast is quicker?

As for searching for all instances of a running application, Madshi's right--it's different under Win9x and NT, and it's probably not something you want to get into unless you enjoy grubbing around in the guts of Windows.
Thanks a lot for that. I think I'm just going to have to dig deep and get myself a decent reference book or two.

Id love to be able to throw a few well earned points Madshi's way, but unfortunately I you only get to designate one recipient. I think I'll throw that into the suggestions box.
No problem for me...  :-)

Yes, please do that suggestion. A lot of people have suggested that already, but nothing changed yet. But the more people say something the better are our chances that we'll see a point splitting feature soon.