Window가 두 개 있는데 한 Window에서 다른 Window로 Message를 보내고 싶다.
그리고, 이 두 개의 Window 모두 한 사람(회사)의 개발자가 개발
이럴 때 어쩔까나..
가장 쉬운 방법인SendMessage를 이용하기로 한다.
SendMessage를 사용하기 위해서 Target Window의 Handle(HWND)를 찾아야 한다.
이 때 가장 먼저 생각할 수 있는 것이 FindWindow이다.
즉,
CWnd* pWnd = FindWindow("", Target Window caption) ;
::SendMessage(pWnd->m_hWnd, WM_보낼메시지, wParam, lParam) ;
요렇게 하면 된다.
흠..
그런데 문제는 이제 시작이다.
망할 Target Window는 Caption이 없다..
즉, Title bar가 없다는 것이다.
그렇다고, Class Name을 알아내자니, 망할 VS는 알려주지 않고 꽁꽁 숨겨놓았다.
이럴 경우에 어쩔까나..
이 때는 Process ID로부터 HWND를 가져올 수 있다.
일단 해당 Target Window의 Process ID를 가져온다.
가져오는 방법은 저~~ 아래를 참고하여 약간 변형하면 된다.
이 때, 우리가 만드는 프로그램이니깐 실행파일 이름 정도는 알 수 있다.
DWORD get_processid(char* psz_exec_name)
{
DWORD a_proc[1024], dw_needed, dw_proc ;
unsigned int i ;
CString proc_name ;
TCHAR sz_exec_name[MAX_PATH] = {0, } ;
if(!EnumProcesses(a_proc, sizeof(a_proc), &dw_needed))
return ERROR_FIND ;
dw_proc = dw_needed / sizeof(DWORD) ;
for(i=0 ; i<dw_proc ; i++)
{
HANDLE h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, a_proc[i]) ;
if(NULL != h_proc)
{
HMODULE h_module ;
if(EnumProcessModules(h_proc, &h_module, sizeof(h_module), &dw_needed))
{
GetModuleBaseName(h_proc, h_module, sz_exec_name, sizeof(sz_exec_name)/sizeof(TCHAR)) ;
if(psz_process_name == CString(sz_exec_name))
return a_proc[i] ;
}
}
}
return ERROR_FIND ;
}
자.. 이제 Process ID를 알았으니, HWND를 알아보자.
이 때 사용되는 API는 EnumWindows이다.
BOOL EnumWindows(
WNDENUMPROC lpEnumFunc,
LPARAM lParam
);
typedef struct _PROC_HWND
{
DWORD dw_pid ;
HWND h_wnd ;
CString str_class ;
CString str_title ;
} PROC_HWND, *PPROC_HWND ;
BOOL CALLBACK EnumWindowsHWND(HWND hWnd, LPARAM lParam)
{
char sz_class[_MAX_PATH] = {0, } ;
char sz_title[_MAX_PATH] = {0, } ;
DWORD dw_pid = 0 ;
PPROC_HWND proc = (PROC_HWND*)lParam ;
GetWindowThreadProcessId(hWnd, &dw_pid) ;
if(proc->dw_pid == dw_pid)
{
GetClassName(hWnd, sz_class, _MAX_PATH) ; // 테스트를 위해서 찍어보자.
GetWindowText(hWnd, sz_title, _MAX_PATH) ; // 테스트를 위해서 찍어보자.
proc->str_class = sz_class ;
proc->str_title = sz_title ;
proc->h_wnd = hWnd ;
return FALSE ;
}
return TRUE ;
}
HWND CFindNoTitleDlg::get_Window_handle(DWORD dw_pid)
{
PROC_HWND ph ;
ph.dw_pid = dw_pid ;
ph.h_wnd = NULL ;
ph.str_class.Empty() ;
EnumWindows((WNDENUMPROC)EnumWindowsHWND, (LPARAM)&ph) ;
return ph.h_wnd ;
}
이렇게 작성한 후, get_Window_handle을 호출하면 Target Window의 HWND를 구할 수 있다.
그리고, 구한 값들 중 Class name은 SPY++로 알아본 Target Window의 Class Name과 동일함을 알 수 있다.
물론 Target Window의 Title은 ""일 것이고..
내 경우엔 Class Name이 "#37728"로 나왔다.
이제 HWND를 알아왔으니, 가볍게 SendMessage를 호출하여 메시지를 날릴 수 있다.
이 때 생성할 수 있는 메시지의 범위는 아래와 같다.(MSDN)
| Range | Meaning |
|---|---|
| 0 through WM_USER–1 | Messages reserved for use by the system. |
| WM_USER through 0x7FFF | Integer messages for use by private window classes. |
| WM_APPthrough 0xBFFF | Messages available for use by applications. |
| 0xC000 through 0xFFFF | String messages for use by applications. |
| Greater than 0xFFFF | Reserved by the system. |
그리고, 덧붙여 한 가지 더..
위 방법이 번거롭다면 두 프로그램이 같은 Window Message를 등록한 후, 한 쪽에서 보낼 Message를 Broadcast 해 버리는 방법이다.
정말 간단하다.. ㅡㅡ;;
UINT RegisterWindowMessage(
LPCTSTR lpString
);
RegisterWindowMessage 함수를 이용하면 OS가 System에서 고유한 Message를 생성해주며, 이 때 생성되는 메시지는 0xC000에서 0XFFFF 사이의 값이다.
즉, 양쪽 프로그램에서
UINT g_msg = RegisterWindowMessage(_T("TEST_PRG_MESSSAGE")) ;
처럼 메시지를 등록하고, 보내는 쪽에서
SendMessage(HWND_BROADCAST, g_msg, 0, 0) ;
한 후, Target Window에서 알맞은 Event Handler를 작성하면 되겠다.
위 메시지는 Top-level Window에 모두 날라가겠지만, 메시지를 등록한 프로그램만 받을테니깐..





최근 덧글