윈도우에 떠 있거나 숨어 있거나 간에 모든 창의 핸들 그리고
클래스명, 캡션(WindowText)명 중에 원하는 것만 뽑아 내고 싶을 때가 있습니다.
이건 홍익인간 정신에 의해 이미 널리 알려진 것이라,
구현하는 것은 매우 쉽습니다.
그러나 아는 것이고 자료가 풍부하지만 막상 구현하려고 하면 일정한 시간이 걸리게 마련입니다.
또 이 기능을 멋지게 클래스화 까지 시키려면 한두시간 소비하기도 합니다. 콜백 함수가 있어
클래스화 하지 않으면 소스가 좀 방만해지기도 하죠.
그래서 이 기능을 일반성 있게 클래스로 구현한 김에 올려 둡니다.
붙여넣기 신공으로 쉽게 쓸수 있게 만들었습니다.
소스는 아래와 같고, 첨부 파일 내용과 같습니다.
#ifndef __CFindEnumWindow_H
#define __CFindEnumWindow_H
//---------------------------------------------------------------------------
// 지정한 클래스와 특정 문자열을 포함하는 윈도 찾기 클래스
// 복수개를 찾아주는데, 핸들, 그 윈도 클래스명, 윈도 캡션명을 쉽게 조회할 수 있다.
//
// Written by KTS
class CFindEnumChildWindow
{
private:
HWND hParent;
TList *List;
char *sClassName;
bool bClassNameSubString;
char *sTitle;
bool bTitleSubString;
char Buffer[1024];
private:
static BOOL CALLBACK EnumChildWndProc(HWND hwnd, LPARAM lParam)
{
CFindEnumChildWindow *This = reinterpret_cast(lParam);
char *text = This->Buffer;
if (This->sClassName != NULL)
{
if (GetClassName(hwnd, text, 1023))
{
//TRACE("%s", text);
if ((!This->bClassNameSubString && !strcmp(text, This->sClassName)) ||
(This->bClassNameSubString && strstr(text, This->sClassName)))
{
if (This->sTitle != NULL)
{
text[0] = 0;
GetWindowText(hwnd, text, 1023);
if ((!This->bTitleSubString && !strcmp(text, This->sTitle)) ||
(This->bTitleSubString && strstr(text, This->sTitle)))
{
This->List->Add(hwnd);
}
}
else
This->List->Add(hwnd);
}
}
}
else
{
if (This->sTitle != NULL)
{
text[0] = 0;
GetWindowText(hwnd, text, 1023);
if ((!This->bTitleSubString && !strcmp(text, This->sTitle)) ||
(This->bTitleSubString && strstr(text, This->sTitle)))
{
This->List->Add(hwnd);
}
}
}
return TRUE;
}
int GetCount()
{
return List->Count;
}
HWND GetHandle(int index)
{
if (index >= List->Count || List->Count <= 0)
return NULL;
return List->Items[index];
}
String _GetClassName(int index)
{
if (index >= List->Count || List->Count <= 0)
return NULL;
char *text = Buffer;
GetClassName(Handles[index], text, 1023);
return text;
}
String _GetWindowText(int index)
{
if (index >= List->Count || List->Count <= 0)
return NULL;
char *text = Buffer;
GetWindowText(Handles[index], text, 1023);
return text;
}
public:
CFindEnumChildWindow()
{
List = new TList;
}
~CFindEnumChildWindow()
{
delete List;
}
bool Scan(HWND parent, char *class_name, char *title, bool class_substring = true, bool title_substring = true)
{
List->Clear();
hParent = parent;
sClassName = class_name;
sTitle = title;
bClassNameSubString = class_substring;
bTitleSubString = title_substring;
return EnumChildWindows(hParent, (FARPROC)EnumChildWndProc, (long)this);
}
// 찾은 데이타 핸들링.
//
__property String ClassName[int index] = { read=_GetClassName };
__property String WindowText[int index] = { read=_GetWindowText };
__property HWND Handles[int index] = { read=GetHandle };
__property int Count = { read=GetCount };
};
class CFindEnumWindow
{
private:
TList *List;
char *sClassName;
bool bClassNameSubString;
char *sTitle;
bool bTitleSubString;
char Buffer[1024];
private:
static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lParam)
{
CFindEnumWindow *This = (CFindEnumWindow *)lParam;
char *text = This->Buffer;
if (This->sClassName != NULL)
{
if (GetClassName(hwnd, text, 1023))
{
if ((!This->bClassNameSubString && !strcmp(text, This->sClassName)) ||
(This->bClassNameSubString && strstr(text, This->sClassName)))
{
if (This->sTitle != NULL)
{
text[0] = 0;
GetWindowText(hwnd, text, 1023);
if ((!This->bTitleSubString && !strcmp(text, This->sTitle)) ||
(This->bTitleSubString && strstr(text, This->sTitle)))
{
This->List->Add(hwnd);
}
}
else
This->List->Add(hwnd);
}
}
}
else
{
if (This->sTitle != NULL)
{
text[0] = 0;
GetWindowText(hwnd, text, 1023);
if ((!This->bTitleSubString && !strcmp(text, This->sTitle)) ||
(This->bTitleSubString && strstr(text, This->sTitle)))
{
This->List->Add(hwnd);
}
}
}
return TRUE;
}
int GetCount()
{
return List->Count;
}
HWND GetHandle(int index)
{
if (index >= List->Count || List->Count <= 0)
return NULL;
return List->Items[index];
}
String _GetClassName(int index)
{
if (index >= List->Count || List->Count <= 0)
return NULL;
char *text = Buffer;
GetClassName(Handles[index], text, 1023);
return text;
}
String _GetWindowText(int index)
{
if (index >= List->Count || List->Count <= 0)
return NULL;
char *text = Buffer;
GetWindowText(Handles[index], text, 1023);
return text;
}
public:
CFindEnumChildWindow Child;
public:
CFindEnumWindow()
{
List = new TList;
}
~CFindEnumWindow()
{
delete List;
}
bool Scan(char *class_name, char *title, bool class_substring = true, bool title_substring = true)
{
List->Clear();
sClassName = class_name;
sTitle = title;
bClassNameSubString = class_substring;
bTitleSubString = title_substring;
return EnumWindows((FARPROC)EnumWndProc, (long)this);
}
// 찾은 데이타 핸들링.
//
__property String ClassName[int index] = { read=_GetClassName };
__property String WindowText[int index] = { read=_GetWindowText };
__property HWND Handles[int index] = { read=GetHandle };
__property int Count = { read=GetCount };
};
#endif
클래스는 빌더6에서 제작되었기 때문에 RS2010에서 쓰시려면 조금만 손보면 됩니다.
그 정도는 누워서 껌먹기라서 아무나 할수 있을 것입니다.
요건 테스트입니다.
내부가 어떻게 동작하는지 굳이 알지 않아도 아래처럼 아주 쉽게 쓸수 있습니다.
//---------------------------------------------------------------------------
void __fastcall TForm100::Button1Click(TObject *Sender)
{
CFindEnumWindow win;
win.Scan("TAppBuilder", "Embarcadero RAD Studio 2010", false, true);
if (win.Count > 0)
{
Edit1->Text = win.WindowText[0];
Edit2->Text = win.ClassName[0];
}
}
//---------------------------------------------------------------------------
클래스명은 TAppBuilder인 윈도 중에서(빌더6, 델파이, RS 등 모두 TAppBuilder 죠)
제목 줄에 Embarcadero RAD Studio 2010을
포함하는 창을 찾는 예제입니다.
숙지할 것은 Scan 메소드 정도겠군요.
Scan(char *ClassName, char *WindowTextCaption, bool class_substring = true, bool title_substring = true);
FindWindow 할때와 거의 같습니다.
Scan("TAppBuilder", NULL);
Scan(NULL, "Embarcadero RAD Studio 2010", false, true );
이런 식으로도 할 수 있습니다. 뒤쪽에 붙은 false, true는 Title은 "Embarcadero RAD Studio 2010" 문자열을 포함하는 것은 모두 찾으라 이런 뜻이 되겠죠. false, false 이렇게 주면 완전히 일치하는 것을 찾으라가 됩니다.
찾은 윈도에 대해 새끼 윈도 즉 Child Window를 찾으려면 Child 멤버객체를 이용하면 됩니다.
그럼..