Monday, April 6, 2015

Visual C++ 다른 프로그램의 메세지 박스 자동 Yes 클릭하기

다른 Application을 띄워서 매번 실행해야되는데 시작시 수동으로 매번 MessageBox에서 Yes를 선택해야 되는 경우 자동으로 Yes를 누르는 프로그램이다.

Win32 Application을 만든다. 메인 메세지 루프에서 다음과 같이 타이머를 설정하자.

switch (message)
{
case WM_CREATE:
hwndMain = hWnd;
SetTimer(hWnd, 1, 100, NULL);
...
  case WM_TIMER:
switch(wParam){
case 1:
KillTimer(hWnd, 1);
EnumWindows(FIndMessageBoxProc, lParam);
SetTimer(hWnd, 1, 100, NULL);
...

메세지 박스는 기본적으로 IDYES와 IDNO를 아이디로 가진다. 그리고 메세지 박스의 WindowText를 알아두자. (Spy++을 사용하면 쉽다.)

EnumWindows라는 함수로 Desktop이하의 모든 윈도우를 Enumerate 한 후에 해당 MessageBox를 찾자.
BOOL CALLBACK FIndMessageBoxProc(HWND hWnd, LPARAM lParam)
{
char text[512];
GetWindowTextA(hWnd, text, 512);

if(!strcmp(text, "MessageBoxApplication")) {// 메세지 박스 이름
EnumChildWindows(hWnd, FIndYesBtnProc, lParam);
SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(BN_SETFOCUS, IDYES), (LPARAM)hwndYes);
OutputDebugStringA("ManusHider WM_COMMAND BN_SETFOCUS");

SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(BN_CLICKED, IDYES), (LPARAM)hwndYes);
OutputDebugStringA("ManusHider WM_COMMAND BN_CLICKED");

//KillTimer(hwndMain, 1);
//SetTimer(hwndMain, 2, 100, NULL);
return false;
}
return true;
}

그리고 IDYES라고 아이디를 알고 있더라도 BN_CLICKED를 발생시키려면 그 버튼의 HWND도 알아야 한다.

BOOL CALLBACK FIndYesBtnProc(HWND hWnd, LPARAM lParam)
{
char text[512];
GetWindowTextA(hWnd, text, 512);
if(!strcmp(text,"&Yes")) {
hwndYes = hWnd;
return false;
}
return true;
}

중요한 점은 현재 작성하는 프로그램에 Focus가 와있기 때문에 대상 프로그램에 BN_CLICKED를 SendMessage하기전에 BN_SETFOCUS를 먼저 줘야 한다는 점이다. 그리고 또하나는 Yes가 아니라 &Yes가 Yes버튼의 WindowText이다.

이렇게 하면 원하는 메세지박스에서 항상 Yes/No를 선택해야 되는 프로그램 테스트 실행시 자동으로 Yes를 클릭할 수 있다. 서비스 프로그램으로 만들어도 되고 위에처럼 매번 같이 실행하면서 종료해도 된다.

No comments:

Post a Comment