본문

P/Invoke로 다이얼로그 창 제어하기 #1. 현재 프로세스 제어

우선 이 게시물은 c#.net 으로 제작된 CodeProject의 Suppressing Hosted WebBrowser Control Dialogs 를 보완하는 내용임을 밝힙니다. 이 게시물은 내장된 WebBrowser의 다이얼로그 창 생성 이벤트 메시지를 검출해서, 다이얼로그 생성 이전에 다이얼로그를 처리함으로서 더욱 더 편한 사용자 환경을 제공하는데 목적이 있습니다. 여기에는 보안경고창(인증서 오류) 또는 ~으로 연결(사용자 이름과 암호가 필요한 창) 다이얼로그를 제거하는 역할을 하는데, 이를 응용한다면 javascript에서 발생하는 경고창 또한 제어할 수도 있습니다.

[그림 1] Spy++에서 확인한 alert(), prompt(), confirm()시 발생하는 자원.

위에 링크된 사이트에서 프로젝트파일을 다운로드 받은 후 핵심 부분인 WindowsInterop.cs를 열어봅니다. 후킹 프로시져는 WH_CALLWNDPROCRET_PROC으로서, 그 안에서 if (cwp.message == WM_INITDIALOG)이하, 즉 다이얼로그 생성시점을 체크하는 부분 아래부분을 확인합니다. 이곳에서는 GetWindowText()을 통해 얻어낸 윈도우 제목을 기준과 비교함으로서 원하는 창에 대해서 다시 검사하는 구조를 가집니다. if, else if로 두가지의 경우를 검출해 내지만 이 외에는 분기가 설정되어있지 않아 메시지가 다른곳으로 흘러가게 됩니다. 따라서, else if문을 추가하여 다른 경우를 설정해 주어야 합니다.

alert()의 경우는 [그림 1]에서 보시면 "웹 페이지의 메시지"라고 창제목이 설정된것을 확인할 수 있습니다. 따라서 else if (sb.ToString().Equals("웹 페이지의 메시지"))인 경우를 생각하면 되겠습니다. 단, 이경우 confirm()과 동일한 창 제목을 가지므로 내부에서 처리하는 로직이 또한 필요합니다. (아니면 무조건 확인으로..)

IntPtr pOkButtonHwnd = IntPtr.Zero;

foreach
(IntPtr pChildOfDialog in WindowsInterop.listChildWindows(cwp.hwnd)){
// sbProbe에 현재 객체의 클래스명(Button, Static등)이 들어간다.
    StringBuilder sbProbe = new StringBuilder(255);
        if (GetClassName(pChildOfDialog, sbProbe, sbProbe.Capacity) != 0 &&
            !
String.IsNullOrEmpty(sbProbe.ToString())){
// 만약 현재 객체의 클래스명이 Button이라면,
            if (StringConstants.WindowTypeButton.Equals(sbProbe.ToString(),
                StringComparison.InvariantCultureIgnoreCase)){
// 현재 버튼의 텍스트길이를 받아와서,
                iLength = GetWindowTextLength(pChildOfDialog);
                if (iLength > 0){
                    StringBuilder sbText = new StringBuilder(iLength + 1);
                    GetWindowText(pChildOfDialog, sbText, sbText.Capacity);
// 문자열의 길이가 0보다 큰경우 확인버튼인가 체크.
                if (StringConstants.ButtonTextOk.Equals(sbText.ToString(),
                        StringComparison.InvariantCultureIgnoreCase)){
// 현재 객체의 포인터를 저장한다
                        pOkButtonHwnd = pChildOfDialog;
                    }
                }
           }
        }
    }
    if (pOkButtonHwnd != IntPtr.Zero){
// 확인 버튼이 존재할 경우 그 버튼을 가지는 윈도우 핸들을 가져오고, 거기에 메시지를 보낸다
        Int32 ctrlId = GetDlgCtrlID(pOkButtonHwnd);
        SendMessage(cwp.hwnd, WM_COMMAND, new IntPtr(ctrlId), pOkButtonHwnd);
// 처리 후 다이얼로그 생성 메시지가 다른곳으로 흘러가지 않도록 끊어준다
    return 1;
}


단, 이 경우는 현재 프로세스에 내장된 WebBrowser에서의 메시지만을 담당하기 때문에 다른 창에서의 메시지를 확인할 수 없습니다. 따라서 Global Hooking등을 통하여 iexplorer들의 메시지를 확인하는 방법을 찾아야 하며, 이에 대해서는 다음 게시물에서 다룰 예정입니다.

댓글

Holic Spirit :: Tistory Edition

design by tokiidesu. powerd by kakao.