winapi >> GetWindow - Infinite Loop?

by Joseph Geretz » Tue, 11 Mar 2008 07:24:10 GMT

I have been using GetWindow recursively for about 6 - 7 years now, to search
for a particular Window. We've never had a problem up until now.

Recently, a customer started reporting application hangs. We traced this
down into our code to the point just before the first (outer) call into the
recursive function.

A little Googling turns up the following:

--------------------
http://support.microsoft.com/kb/183009

You can list Windows, including Child Windows, using the GetWindow API.
However, an application that calls GetWindow to perform this task risks
being caught in an infinite loop...
--------------------

There are plenty of hits on GetWindow and 'infinite loop', however every
page is simply parroting the same little blurb. I've yet to see any
explanation as to what precise circumstance will trigger an infinite loop
when using GetWindow. The only circumstance I could see would be in the
event that a call to GetWindow starting with a particular hWnd would return
the same hWnd. Would this even be possible? Can a Window be both its own
parent and child? Or can a circular parent child relationship exist between
two or more Windows?

Does any one have any additional information to augment Microsoft's advice
that an application that calls GetWindow to perform this task risks being
caught in an infinite loop? Does Microsoft simply mean that recursion is
inherently risky? Or is there something specific to GetWindow which will
create a particular condition which will cause a recursive algorithm to
enter an endless loop?

I've posted my function below. As you can see, the loop for siblings ends
when a 0 is returned. This should take care for normal end-of-siblings or
for any error encountered, since the defined functional return in an error
condition is 0. So my own loop doesn't seem succeptible to inifinite
looping. And I don't see how the recursion itself can be infinite unless
it's possible for a circular parent child relationship within the Windows
hierarchy. Is such a thing possible?

Thanks for any advice which you can provide.

- Joseph Geretz -

Public Function FindWindowLike(hWnds() As Long, _
WinTitles() As String, _
WinClasses() As String, _
Optional ByVal hWndStart As Long = 0, _
Optional ByVal WinTitle As String = "", _
Optional ByVal WinClass As String = "", _
Optional ByVal WinChildID As Long = 0, _
Optional ByVal CaseSensitive As Boolean =
True) _
As Long

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' This function calls itself recursively. Static variables '
' keep track of the level of recursion. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

' Hold the RecLevel of recursion:
Static RecLevel As Long
' Hold the number of matching windows:
Static NumMatches As Long

Dim hWnd As Long
Dim APIReturn As Long
Dim bMatch As Boolean
Dim sWinTitle As String
Dim sWinClass As String
Dim lID As Long

' Initialize if necessary:
If RecLevel = 0 Then
NumMatches = 0
ReDim hWnds(0 To 0)
If hWndStart < 1 Then
hWndStart = GetDesktopWindow()
End If
End If

If CaseSensitive = False Then
WinTitle = UCase$(WinTitle)
WinClass = UCase$(WinClass)
End If

' Increase recursion counter:
RecLevel = RecLevel + 1

' Priming action; Get first child window.
hWnd = GetWindow(hWndStart, GW_CHILD)

Do Until hWnd = 0

' Search children by recursion:
APIReturn = FindWindowLike(hWnds(), _
WinTitles, _
WinClasses, _
hWnd, _
WinTitle, _
WinClass, _
WinChildID, _
CaseSensitive)

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' OK, let's set the match flag to True. Then, as long '
' as the match flag remains True, we'll apply each '
' filter criteria in sequence. After applying all filters, '
' if the match flag is still True, then we've got a match! '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

bMatch = True

If WinTitle <> "" Then
sWinTitle = GetWinTitle(hWnd)
If CaseSensitive = False Then
sWinTitle = UCase$(sWinTitle)
End If
If Not (sWinTitle Like WinTitle) Then
bMatch = False
End If
End If

If bMatch = True Then
If WinClass <> "" Then
sWinClass = GetWinClass(hWnd)
If CaseSensitive = False Then
sWinClass = UCase$(sWinClass)
End If
If Not (sWinClass Like WinClass) Then
bMatch = False
End If
End If
End If

If bMatch = True Then
If WinChildID > 0 Then
If GetParent(hWnd) <> 0 Then
lID = GetWindowLW(hWnd, GWL_ID)
If WinChildID <> lID Then
bMatch = False
End If
Else
bMatch = False
End If
End If
End If

If bMatch = True Then
' If find a match, increment counter and
' add handle to array:
NumMatches = NumMatches + 1
ReDim Preserve hWnds(0 To NumMatches)
ReDim Preserve WinTitles(0 To NumMatches)
ReDim Preserve WinClasses(0 To NumMatches)
hWnds(NumMatches) = hWnd
WinTitles(NumMatches) = GetWinTitle(hWnd)
WinClasses(NumMatches) = GetWinClass(hWnd)
End If

' Get next child window:
hWnd = GetWindow(hWnd, GW_HWNDNEXT)
Loop

' Decrement recursion counter
RecLevel = RecLevel - 1

' Return the number of windows found:
FindWindowLike = NumMatches

End Function




winapi >> GetWindow - Infinite Loop?

by Thorsten Albers » Tue, 11 Mar 2008 08:45:05 GMT

Joseph Geretz < XXXX@XXXXX.COM > schrieb im Beitrag
< XXXX@XXXXX.COM >...
advice


There are functions which may change the relationship between windows (e.g.
SetParent()) or the Z-order. Windows may be created or destroyed by
applications at any time. This IMHO may confuse the relationship between
windows and therefore cause GetWindow() to hang in an infinite loop.
Have a look at MSDN articles such as "Window Owners and Parents" , "Win32
Window Hierarchy and Styles", and "Owner-Owned Windows" (all included in
the MSDN version shipped with VB 6.0).

--
----------------------------------------------------------------------
THORSTEN ALBERS Universit Freiburg
albers@
uni-freiburg.de
----------------------------------------------------------------------



winapi >> GetWindow - Infinite Loop?

by mayayana » Tue, 11 Mar 2008 11:31:37 GMT

I've read the same blurb. And EnumChildWindows
will search through all levels of children with
a convenient callback function. So why not just
switch to using that?


search
the
return
between




winapi >> GetWindow - Infinite Loop?

by Joseph Geretz » Wed, 12 Mar 2008 06:14:33 GMT

gt; So why not just

You're in management, right? ;-)

Seriously, *just switching* cost the better part of the afternoon, and
significantly rearchitects the solution.. (Is the common BAS module now
possibly subject to reentrancy problems?) Anyway, I've gone ahead and done
this because it does seem, from all our diagnostics, as though the GetWindow
function has reached the limits of its usefulness. The revised code works
initially which is nice, but obviously, the entire application needs serious
regression testing because Window resolution is at the heart of our most
core application features.

Ce la vie.

Thanks for your suggestion!

- Joseph Geretz -

"mayayana" < XXXX@XXXXX.COM > wrote in message
news: XXXX@XXXXX.COM ...




winapi >> GetWindow - Infinite Loop?

by mayayana » Wed, 12 Mar 2008 11:11:26 GMT

> You're in management, right? ;-)


"Rearchitects the solution"... So you would be in the
marketing dept., then? :)


I can't imagine where you'd need to call it
concurrently, but I suppose it could be put into
a class if you did need to. I've typically used it in a
situation where I've got two module-scope variables -
a string and a long. The long gets set to 0 and the string
gets set to, say, a class name, before the window-hunting
function is called. With each call to the EnumChildProc
I'm then checking the class name of the window
against the string variable. If I find my match I then
set the long variable to that window's hWnd and return
0 from EnumChildProc to end the iteration. So when
EnumChildWindows returns I've either got 0 or an hWnd
in the module-scope long. (You probably already know all
that by now.)

I think I was originally using GetWindow, checking
class name with a Select Case in order to step
down through a known window hierarchy. But then
I noticed the same warning you had seen, and came
across a posting by Raymond Chen noting that
EnumChildWindows will follow all children down until
they've all been returned. So that method turned
out to be a lot easier. (I'm taking the doc's word for
it that EnumChildWindows has its own built-in
stability.)




winapi >> GetWindow - Infinite Loop?

by Joseph Geretz » Wed, 12 Mar 2008 13:40:04 GMT

> I can't imagine where you'd need to call it

That's news to me. You can put an API callback handler into a Class? I
thought this has to be in a BAS module?

My solution differs from yours slightly in that I do not stop after the
first match. My application searches for all qualifying windows and returns
an array of qualifying hWnds. So I need to cycle through to the end in any
case, building up an array as each qualifying window is found.

The existing function takes an array (actually 3 arrays) passed in as
parametes. On the initial call (recursion level = 0) the arrays are redimmed
to 0 and the recursive search begins. By the time the search unwinds, the
array parameters contain hwnds and info for all qualifying entries.

The recoding was a bit of a pain since I wanted to remain compatible with
existing clients. The arrays are passed in on the function call, and now
these arrays, along with a plethora of search parameters are passed into the
BAS module. The callback function now performs the array accumulation. When
the Enum call finishes, the arrays must be scooped out of the BAS module and
returned back as the parameters to the original call. Not a huge deal, but a
significant number of lines of code were moved around.

Anyway, as soon as this passes QA, I'm going to apply for a transfer to
marketing on your recommendation - I could use some relaxation!

:-)

- Joe Geretz -







winapi >> GetWindow - Infinite Loop?

by Karl E. Peterson » Wed, 12 Mar 2008 20:56:59 GMT





Exactly. I would think, though, that the address of a function in a class
*instance* would be static, wouldn't you? I suppose class instances may be juggled
around in memory?


I have a vague recollection of Matt Curland telling me otherwise. Could be I'm
mistaken, and we were talking about something much easier, like inheritance. Just
don't recall precisely. <g>
--
.NET: It's About Trust!
http://vfred.mvps.org




winapi >> GetWindow - Infinite Loop?

by mayayana » Wed, 12 Mar 2008 22:18:47 GMT

> That's news to me. You can put an API callback handler into a Class? I

Woops. AddressOf doesn't work inside a class? I would
have thought that sending the function pointer could be
done from anywhere, but maybe inside a class it's a relative
pointer, like a vTable. (?) I guess I've never had an occasion
to try it, so I don't know.




winapi >> GetWindow - Infinite Loop?

by Karl E. Peterson » Thu, 13 Mar 2008 00:34:45 GMT




Nope, not directly. With callbacks that let you pass a DWORD back to yourself,
there's an easy workaround, though. You just pass ObjPtr(Me), and the callback
procedure is then enabled to directly recieve a reference. Something like this
example taken from http://vb.mvps.org/samples/TimerObj . . .

In the class:

' Pass pointer to Me so we can return event to this instance.
m_TmrID = SetTimer(m_hWnd, ObjPtr(Me), m_Interval, AddressOf TimerProc)

In the BAS module:

Public Sub TimerProc(ByVal hWnd As Long, _
ByVal uMsg As Long, _
ByVal oTimer As CTimer, _
ByVal dwTime As Long)
' Alert appropriate timer object instance.
oTimer.RaiseTimer
End Sub

Same strategy would work with most Enum* calls.
--
.NET: It's About Trust!
http://vfred.mvps.org




winapi >> GetWindow - Infinite Loop?

by mayayana » Thu, 13 Mar 2008 02:52:18 GMT


Thanks. I never thought about that. Matthew
Curland showed a similar method for UserControls
to subclass themselves, but it hadn't occurred
to me that calling out to the .bas might be
required.

yourself,
callback
this




winapi >> GetWindow - Infinite Loop?

by Karl E. Peterson » Thu, 13 Mar 2008 03:02:12 GMT




I'd be interested in looking at that method by Matt. Do you recall, was it in his
book or one of his VBPJ columns?

I'm not honestly sure why AddressOf (doesn't) work the way it does. Sorta smells of
paternalistic protection from ourselves, doesn't it? I suspect they figured it was
"safe" with BAS modules as the code pointer would be valid for the life of the app?

Thanks... Karl




--
.NET: It's About Trust!
http://vfred.mvps.org




winapi >> GetWindow - Infinite Loop?

by Jim Mack » Thu, 13 Mar 2008 03:20:10 GMT




I suspect it has to do with the fact that modules are static. Is the
address of a function in a class distinct across all instances? What
happens when it goes out of scope or is otherwise disposed of?

Of course there are ways around anything, but this smells more like
"too hard" than "paternalistic". (-:

--
Jim



winapi >> GetWindow - Infinite Loop?

by Scott Seligman » Thu, 13 Mar 2008 04:47:26 GMT





If AddressOf returned something for a class's method, how would anyone
use it? There's only one function pointer for each bit of code in a
function. If you were to call into a pointer returned by AddressOf, the
code in your class would have no way to access "Me". When you call a
function, VB has to pass the reference to the class, I'm sure you could
come up with limited uses for AddressOf in a class, but for the general
case of using it for a call back into some standard Windows API, it'd be
useless.

Other languages have similar issues with passing pointers to functions
in classes. The answer is always the same, either have a static
function, or a function outside of the class, with enough intelligence
to know how to call back into the object from some bit of data either
passed into the callback, or maintained somewhere else.

--
--------- Scott Seligman <scott at <firstname> and michelle dot net> ---------
Never underestimate the bandwidth of a station wagon full of tapes
hurtling down the highway.
-- Andrew S. Tanenbaum


winapi >> GetWindow - Infinite Loop?

by Jim Mack » Thu, 13 Mar 2008 05:19:49 GMT






I think not, but to expose a function like that would break
encapsulation. Anything not published in the interface should not be
accessible (by theory). Again, that's not to say you couldn't find a
way, but it would be a hack.

Having said that, if you exposed the function of interest as a method,
its address would be in the vtable, which is at a known (or
computable) offset from the ObjPtr. So, if you really needed to, I
guess you could.

--
Jim



winapi >> GetWindow - Infinite Loop?

by Karl E. Peterson » Thu, 13 Mar 2008 05:39:28 GMT







I was definitely thinking you'd have to point to a public method of the object, of
course. I guess the attempts I've seen at this are all based around that vtable
notion, yeah. Calling back into the object is a PITA, but doable.
--
.NET: It's About Trust!
http://vfred.mvps.org




Similar Threads

1. API VBA: Infinite Loop

Why doesn't escape end an infinite loop in SolidWorks VBA Editor.  It works
in the one for excel.  Is there something else I could do.

Corey Scheich


2. Problem with Form.ValidateChildren (infinite validation loop?)

3. Infinite loop querying remote WMI

I am using a GetObject statement to read the WMI on a remote pc. 

If the WinMgmt service is not working properly (remotely) the VB code hangs 
with a message ("waiting for an OLE.." etc etc).

As this is not an error message the VB code is not capturing it and will 
progress no further and not allow me to quit out.

Any Ideas?

Otherwise - is there a way to return the remote RAM of a pc without using WMI?

Matt

4. Infinite loop with crystal control viewer - VB Crystal Report

5. Calling code in DLL that has an "infinite Loop"

Hello,

I'm trying to tie some hardware my company builds into a PC.  I'm running
Win98 on the PC and can access my hardware C++ functions in a DLL.  Right
now I'm checking if the hardware puts up some information then when the PC
gets around to it, it reads the informaiton.  This is leading to a lag in
data because the PC can get busy with other things and not read the data
right away.

I'm wondering if there is a way to start a routine in the C++ dll that uses
a near infinite loop to "interrupt" the vb6 program when data comes in by
putting the data into something like text box.

I am not creating driver DLL yet, just a C++ program compiled into a DLL.

Can this be done?  Would someone have some advice on accomplishing this?

Thanks.

Mike


6. Infinite While Loops - Visual Basic/VB

7. Weird infinite loop

Hi!

I have a software server that uses Winsock API and connects to an
Oracle DB.

The server is located in a dual-core 3.6 Pentium D with 2 GB ram.

After some - random - time, sometimes less, sometimes more, the CPU use
of the process goes to 100% (50% of the CPU which is responding) and
the server stops responding (it appears as "not responding")

I have reviewed the code lots of times, all the loops are double -
checked, but I can't find any solution.

Any ideas?

8. XP Setup in an infinite loop - Visual Basic/VB