Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

FindWindow is hanging....

333 views
Skip to first unread message

Wes Jones

unread,
Jun 11, 2004, 1:49:16 PM6/11/04
to
Hi all,

I have an app that uses FindWindow to find the window handle to another
app's window, and it looks like it is hanging. It doesn't do it every
time, but from my logging statements, I can tell that FindWindow is the
last thing called when it's hung up.

I've seen the various articles/comments about the dangers of using
FindWindow, ie: uses SendMessage internally & can hang if another app's
thread is waiting/hung, etc.

I have written an alternative function for some other purpose that works
similarly to FindWindow but checking all the top level windows, starting
w/ the desktop window, but that too uses GetWindowText (ie:
SendMessage()) & I think will have the same liability.

My question is: What's a good alternative to using FindWindow ?

I would alter my similar function to use SendMessageTimeout, but I am
using Windows CE, and that function is not supported.

Please help, won't you?

What are the alternatives to using FindWindow?

Here are some details about how I'm using FindWindow:
-------------
LPCTSTR szPossibleNames[] = { _T("name1"), _T("name2"),...,_T("nameN") };
for(int i=0; i < X; ++i){
if( FindWindow(NULL, szPossibleNames[i]) )
break;
}
//other stuff...
-------------


Is using FindWindow in a loop like this just asking for trouble? It's
like I'm making it do risky things over & over again....


Just for fun, and in the case it can help somebody point out an
alternative to me, here's the code for my 'alternative func':

-----------------------------------
HWND FindChildAmongManyChildDialogs(
HWND hWndMain,
LPCTSTR szClassName,
LPCTSTR szWindowTitle)
//
//This function was written to
//find a child window when there is a main
//window, and then several dialogs that
//are children, and the window we want
//is on one of those dialogs.
//
//This is based on the AirCard 555 watcher program,
//and Remote Spy++
//
//
//
{
CString str, strTitle;
TCHAR szClass[ 200 + 1 ] = {0};
CWnd * pChild = CWnd::FromHandle(::GetWindow(hWndMain, GW_CHILD)
); CWnd * pLast = NULL;
if( pChild )
pLast = pChild->GetWindow(GW_HWNDLAST);
if( !pChild )
return NULL;

do{
GetClassName(pChild->GetSafeHwnd(), szClass, 200);
pChild->GetWindowText(strTitle);
if(_tcsicmp(szClass, _T("Dialog")) == 0 )
{
HWND hChild = FindChildWindow(pChild,
szClassName,
szWindowTitle);
if( hChild )
return hChild;
}
pChild = pChild->GetWindow(GW_HWNDNEXT);
}while( pChild && (pChild != pLast) );

return NULL;
}

HWND FindChildWindow(CWnd * pParent,
LPCTSTR szClassName,
LPCTSTR szWindowTitle)
{
ASSERT( szClassName || szWindowTitle );
ASSERT( pParent );
CString strTitle;
TCHAR szClass[ 200 + 1] = {NULL};

CWnd * pChild = pParent->GetWindow(GW_CHILD);
ASSERT( pChild );
CWnd * pLast = NULL;
if( pChild )
pLast = pChild->GetWindow(GW_HWNDLAST);
if( !pChild )
return NULL;
do
{
GetClassName(pChild->GetSafeHwnd(), szClass, 200);
pChild->GetWindowText(strTitle);

if( (!szClassName || _tcsicmp(szClass, szClassName) == 0)
&& (!szWindowTitle || strTitle.CompareNoCase(szWindowTitle)
== 0) )
{
return pChild->GetSafeHwnd();
}
pChild = pChild->GetWindow(GW_HWNDNEXT);
}while( pChild && (pChild != pLast) );

return NULL;
}
-----------------------------------


Last question:
Is using FindWindow(_T("dialog"), )
better than using FindWindow("dialog", ) ?
Does specifying the class name prevent it from using the sendmessage
call internally for those cases where the window is obviously not a dialog?

Thanks for any help...
Wes

Joseph M. Newcomer

unread,
Jun 11, 2004, 5:27:55 PM6/11/04
to
Personally, I believe this is not only the worst possible way to find another window, but
it is so unreliable that it cannot be trusted. Not because the call is unreliable, but
because any string you have depends on the fact that you are looking for a specific window
in a specific version of the app, in a spectic language. So while the call works reliably,
the program that uses it would have to take all of these conditions into account, and
therefore the chances that it will work correctly in all conditions is minimal. For
example, it is possible to edit the resource segment of an app and merely change the
language strings (our European distributors do this all the time), so another app that
expects to find English language strings would be doomed. I've had to fix these problems
in many of my clients' programs, which is one reason I never do anything that has the
potential to be language-specific, and I never hardwire an English-language string
anywhere in my apps.

Since you are on CE, you could have additional problems that we don't see in desktop
systems.

But if you are writing both apps, there are a number of things you can do. For example, a
shared data segment in a DLL where the app that is the "service" puts its handle, and the
app that is the "client" can read the handle, would be a more reliably approach. Of
course, the "server" should, on its ExitInstance, set this handle to NULL, and the
"client" should occasionaly do an ::IsWindow, just to be sure everything is valid

If you are looking for some other app that you didn't write, you are probably in trouble.

If you use "Dialog", this gives you an 8-bit character string. This will not work on CE,
which uses Unicode. You could explicitly say L"Dialog", and it would only work in Unicode
versions, which would be fine for CE but if you wanted a desktop version, this might be an
annoyance. _T("Dialog") says "Make this an 8-bit or 16-bit literal depending on the
compilation mode", and is the preferred method.

Since I don't trust FindWindow as far as I can throw a mainframe, I can't answer the
question about whether or not there would be any difference in the nature of the calls.
And I've never written a CE program, so I'm not sure what other properties of CE differ
from desktop systems (CE is a totally separate code base, written from scratch, and shares
only the abstract API interface with the desktop systems. There are substantial
differences, some necessary, some merely gratuitous).

joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

KS

unread,
Jun 11, 2004, 6:27:18 PM6/11/04
to
Here's one of my futile attempts on WindowCE to get a list of all the
windows and it's attributes ....

void CEnumChildrenDlg::EnumerateWindows(HWND tWnd)
{

//
HWND hWnd = ::GetWindow(tWnd, GW_CHILD);
//
if(hWnd != NULL && hWnd != tWnd)
{
//
hWnd = ::GetWindow(hWnd, GW_HWNDFIRST);
//
while(hWnd != NULL)
{
//
[ ... add your processing here with the hWnd ... for example GetWindowText()
... ]
//
EnumerateWindows(hWnd);
//
hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}
}

}

void CWndProc::DisplayWindow(HWND tWnd)
{

TCHAR sWindowClass[81];
TCHAR sWindowText[81];
long nCount;

if(tWnd != NULL)
{

nCount = ::GetClassName(tWnd, sWindowClass, 80);
if(nCount > 80)
{
nCount = 0;
}
sWindowClass[nCount] = '\0';

CString aWindowClass = sWindowClass;
if(aWindowClass == _T("DesktopExplorerWindow"))
{
sWindowText[0] = '\0';
}
else
{
nCount = ::GetWindowText(tWnd, sWindowText, 80);
if(nCount > 80)
{
nCount = 0;
}
sWindowText[nCount] = '\0';
}

CString aWindowText = sWindowText;
if(aWindowText.GetLength() > 0)
{
if(aWindowText.GetAt(0) == 65535)
{
aWindowText = _T("");
}
}

CString aTrace;
aTrace.Format(_T("%ld %30s %30s\n"), tWnd, sWindowClass, sWindowText);
TRACE(aTrace);

}

}

This will get all the windows if you initially pass it a NULL ... however
... trying to get the window text can and has hung my application ... that's
why I gave up this approach also. So not sure if this will get you any
further than using the FindWindow()

KS


Joseph M. Newcomer

unread,
Jun 12, 2004, 2:37:54 AM6/12/04
to
Interesting. With two reports of FindWindow hanging on CE, this may be a bug in CE.
joe

Joseph M. Newcomer [MVP]

Michael J. Salamone [eMVP]

unread,
Jun 12, 2004, 8:39:19 AM6/12/04
to
Actually SendMessageTimeout is supported in WinCE 4.0.

FindWindow(pszClassName, NULL) won't hang, so if you can get by with that,
then use that.

Otherwise your stuck. You could create a thread to do the work, and then,
if the thread hasn't completed within some time, terminate it and consider
it a failure. There's actually a problem with this approach, too, but you
might decide it's such a rare case that it doesn't matter. Consider: let's
say you give the thread a second to do the job. If it doesn't complete
within a second, you terminate the thread. The thread, by calling
FindWindow/GetWindowText/SendMessage(WM_TEXT) essentially *posted* a
WM_GETTEXT message to the thread of an owner window, passing a buffer. So
the message is sitting in the message queue of some thread. Let's say, now,
that the message does get processed, but after the one second threshold, and
your thread is no longer there.

What are the potential problems in this scenario:
1) If the thread passed a stack buffer, the stack is no longer there,
and you have a crash.
2) If you use a global buffer instead, it could be that it overwrites it
(think that your FindWindow search moved on to a new window, after having
given up on the one you timed out, and that new window responded and, at the
same time, the one you timed out responded).
3) If you use a dynamically allocated buffer, then you must leak that
buffer. If you don't, you get heap corruption.

Choose your poison: hang, crash, buffer contention, corruption. Buffer
contention (number 2 above) won't hang/crash/corrupt, so that's the "best"
case in terms of execution, but can lead to unpredictable results.
--

Michael Salamone [eMVP]
Entrek Software, Inc.
www.entrek.com

"Wes Jones" <nos...@spam.com> wrote in message
news:eU37wx9T...@TK2MSFTNGP12.phx.gbl...

KS

unread,
Jun 12, 2004, 5:21:41 PM6/12/04
to
Actually it was the GetWindowText() that was hanging WindowsCE. That's why
I had to check to see if the class was "DesktopExplorerWindow" before trying
to do a GetWindowText(). It appears trying to GetWindowText() on the
DesktopExplorerWindow would do something to block the call .... So if the
FindWindow() uses GetWindowText() somewhere in it's call, then yep ... looks
like a bug to me ...

KS

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:259lc0ptmprpp7n3l...@4ax.com...

0 new messages