Tuesday, December 28, 2004

Window Finder

Sometimes you just have to find a window by trundling through the whole windows hierarchy. I know, however, that our apps are supposed to communicate in a more sophisiticated way. The MSDN section on inter-process communications just contains three sub-sections; DDE, mailslots and pipes. I just think they're trying to be generic here by suggesting approaches that can be published and used by third parties. If both the apps are mine however, then I personally prefer mutexes and windows messages (by preference) or events and shared memory(if necessary).

Applying this philosophy means that from time to time i need to play "find the window" and I have finally got round to writing a relatively generic class to do this. Being that kind of guy, I thought i'd share it with you all so you can have a good snigger.

Here it is: surprisingly named: WindowFinder

#pragma once
#include "../../StdString.h"
 
struct WinFindData
{
    WinFindData(CStdString sTextToFind) :    m_sTextToFind(sTextToFind), 
                                            m_bFound(false)              , 
                                            m_hWnd(NULL)             {}
 
    CStdString m_sTextToFind;
    bool m_bFound;
    HWND m_hWnd;
};
 
class WindowFinder
{
public:
    WindowFinder(CStdString sWindowTitle);
    virtual ~WindowFinder(){};
    bool Find(HWND hWnd, HWND& pHwndFound);
    HWND GetHWND()
    {
        return m_hWnd;
    }
 
private:
    CStdString m_sWindowTitle;
    HWND m_hWnd;
    static BOOL CALLBACK EnumChildProc( HWND hwnd, LPARAM lParam);
};
 
 
WindowFinder::WindowFinder(CStdString sWindowTitle) 
            : m_sWindowTitle(sWindowTitle)
{
}
 
bool WindowFinder::Find(HWND hWnd, HWND& pHwndFound)
{
    WinFindData winFindData(m_sWindowTitle);
 
    LPARAM lParam =(LPARAM)&winFindData;
    EnumChildWindows(hWnd, WindowFinder::EnumChildProc, lParam);
    pHwndFound = winFindData.m_hWnd;
    return winFindData.m_bFound;
}
 
BOOL CALLBACK WindowFinder::EnumChildProc( HWND hWnd, LPARAM lParam)
{
    WinFindData* pData = (WinFindData*)lParam;
    if(pData->m_bFound)
        return TRUE;
 
    CStdString sWindowTitle = pData->m_sTextToFind;
    CStdString sText;
    ::GetWindowText(hWnd, sText.GetBuffer(MAX_PATH),MAX_PATH);
 
    sText.ReleaseBuffer();
    if(sWindowTitle.CompareNoCase(sText) ==0)
    {
        pData->m_bFound = true;
        pData->m_hWnd    = hWnd;
        return TRUE;
    }
    else
    {
        WindowFinder finder(pData->m_sTextToFind);
        if( finder.Find(hWnd, pData->m_hWnd))
        {
            pData->m_bFound = true;
            pData->m_hWnd   = finder.GetHWND();
        }
    }
    return TRUE;
}

No comments: