Home Full Site
간단한 IE 컨트롤

C#에서 웹브라우져를 컨트롤하는 방법은 크게 직접 IE와 같은 외부 웹브라우져를 띄워서 이를 컨트롤 하는 것과 윈폼과 같은 C# 프로그램 내에 WebBrowser 컨트롤을 삽입하고 이를 제어하는 방식이 있다. 여기서는 전자의 방식을 알아본다.

C#에서 IE를 띄우기 위해서는 Shell Document Object and Control Library라고 불리우는 SHDocVw.dll 을 참조하여 사용한다. 이 DLL은 프로젝트 레퍼런스 추가에서 COM 탭에서 추가하게 되는데, COM DLL이므로 Interop 방식으로 사용하게 된다. (주: COM 탭에 없는 경우 Browse 해서 Windows 폴더 밑의 System32 에서 찾아 추가)

IE를 띄우기 위해서는 아래 예제에서 처럼 SHDocVw.InternetExplorer 객체를 생성하면 된다. (주: SHDocVw.InternetExplorer는 인터페이스명이며, 이 인터페이스를 구현한 클래스명은 SHDocVw.InternetExplorerClass 이다. 만약 VS2012에서 이 클래스명을 사용한다면, Interop type 'SHDocVw.InternetExplorerClass' cannot be embedded. Use the applicable interface instead 라는 에러가 발생할 수 있다. 이 에러를 막기 위해서는 SHDocVw 참조 레퍼런스의 클릭하고 속성창에서 Embed Interop Types를 false로 한다. Embed Interop Types 기능은 DLL의 인터페이스만을 정적 링크할 때 사용하는데, 구체적 코드를 갖는 클래스명을 사용하지 못하게 한다)

IE를 띄운 후, IWebBrowserApp 인터페이스를 얻고 Navigate() 메서드를 호출하면 특정 사이트로 이동하게 된다. 아래 예제는 IE로 구글 웹사이트를 띄운 후, 5초후에 IE를 닫는 코드이다.


예제

using SHDocVw;
using System.Threading;

namespace IEApp
{
    class Program
    {
        static void Main(string[] args)
        {                        
            var ie = new InternetExplorer();
            // var ie = new InternetExplorerMedium(); // InPrivate 모드
            var webBrowser = (IWebBrowserApp)ie;
            webBrowser.Visible = true;

            webBrowser.Navigate("http://www.google.com");

            Thread.Sleep(5000);
            webBrowser.Quit();
        }
    }
}



IE 내부 컨트롤에 대한 동작처리

IWebBrowserApp 인터페이스는 웹브라우져 자체와 관련된 여러 속성들을 갖고 있다. 이 인터페이스를 통해 IE의 크기 및 메뉴, 상태바 등 여러 사항들을 제어할 수 있다.

IE에 특정 URL에 대해 웹페이지를 가져온 경우, IWebBrowserApp.Document를 Microsoft.mshtml.dll (.NET 레퍼런스 추가 - Assemblies 의 Extensions 에서 추가)의 IHTMLDocument 혹은 IHTMLDocument2, IHTMLDocument3, IHTMLDocument4 등으로 캐스팅하여 해당 인터페이스의 속성 및 메서드를 사용할 수 있다.

예를 들어 아래에서 처럼 IHTMLDocument2.title, IHTMLDocument2.url 등의 속성을 사용할 수 있고, HTML의 특정 요소를 찾기 위해 IHTMLDocument3.getElementsByName(), IHTMLDocument3.getElementById() 등의 메서드를 사용할 수 있다. 아래 예제는 구글 웹사이트에서 Microsoft라는 검색어를 입력하고 결과를 찾는 코드이다.


예제

using SHDocVw; // SHDocVw.dll
using mshtml;  // Microsoft.mshtml.dll
using System;
using System.Threading;

namespace IEApp
{
    class Program
    {
        static void Main(string[] args)
        {
            new Program().RunIE();
        }

        void RunIE()
        {
            InternetExplorer ie = new InternetExplorer();
            IWebBrowserApp webBrowser = (IWebBrowserApp)ie;
            // 브라우져 크기 지정
            webBrowser.Height = 700;
            webBrowser.Width = 900;
            webBrowser.Visible = true;

            webBrowser.Navigate("http://www.google.com");

            Thread.Sleep(3000);
                  
            IHTMLDocument2 doc2 = (IHTMLDocument2)webBrowser.Document;
            IHTMLDocument3 doc3 = (IHTMLDocument3)webBrowser.Document;

            // Cookie 읽기
            string cookie = doc2.cookie;
            Console.WriteLine("Cookie: {0}", cookie);
            
            // Document 속성 읽기
            string title = doc2.title;
            string url = doc2.url;
            Console.WriteLine("{0} - {1}", url, title);

            // 특정 Element 컨트롤
            IHTMLElement q = doc3.getElementsByName("q").item("q", 0);
            q.setAttribute("value", "microsoft");

            /*
               [참고 표현]
               // 콤보박스 값 선택
               IHTMLDocument3 doc3 = (IHTMLDocument3)webBrowser.Document;
               doc3.getElementById("comboCode").setAttribute("value", "01");                        
               // 텍스트박스 텍스트 입력
               var txtDate = (IHTMLInputElement) doc3.getElementById("DOB");
               txtDate.value = "2000-10-29";
            */

            // Form Submit
            IHTMLFormElement form = doc2.forms.item(Type.Missing, 0);
            form.submit();  
        }
    }
}



IHTMLElement의 JavaScript 실행

HTML의 태그 안에 onclick, onchange 같은 이벤트 핸들러를 지정하는 경우가 있다. 이렇게 HTML 태그에 추가된 핸들러는 보통 JavaScript로 작성되는데, 이러한 JavaScript를 실행하기 위해서는 IHTMLElement로부터 .NET Reflection의 InvokeMember()를 통해 해당 이벤트 메서드를 호출하면 된다.

아래 HTML 예제는 select 태그에서 하나의 값을 선택했을 때, (onchange 에서) 변경된 값을 alert로 출력하는 JavaScript 를 갖고 있다. 아래 C# 코드는 이렇게 select 태그 값을 변경하고, onchange 이벤트핸들러까지 호출하는 예제이다.


예제

// HTML
<form id="form1">        
    <select id="choice" name="choice" onchange="javascript:alert(this.value)">
        <option value="1">Item1</option>
        <option value="2">Item2</option>
        <option value="3">Item3</option>
        <option value="4">Item4</option>
    </select>                
    <input type="submit" value="Submit" />          
</form>

// C#
InternetExplorer ie = new InternetExplorer();
IWebBrowserApp webBrowser = (IWebBrowserApp)ie;
webBrowser.Visible = true;

webBrowser.Navigate("http://localhost/test.aspx");
Thread.Sleep(3000);

IHTMLDocument2 doc2 = (IHTMLDocument2)webBrowser.Document;
IHTMLDocument3 doc3 = (IHTMLDocument3)webBrowser.Document;

// select 태그 옵션값 지정
IHTMLElement choiceElem = doc3.getElementById("choice");
choiceElem.setAttribute("value", "3");
choiceElem.GetType().InvokeMember("onchange", System.Reflection.BindingFlags.InvokeMethod, null, choiceElem, null);




기존에 실행된 IE를 찾아서 제어

기존에 실행되어 있는 IE를 찾기 위해서는 SHDocVw.ShellWindows 컬렉션을 검색하여 특정 웹브라우져를 찾게 된다. 예를 들어, 특정 URL을 오픈한 IE를 찾거나 특정 웹 브라우져 제목을 갖는 IE를 찾을 수 있다. SHDocVw.ShellWindows 인터페이스 객체는 IEnumerable을 구현하고 컬렉션을 리턴하는데, 이를 다시 WebBrowser, IWebBrowser2 등 필요한 방식으로 캐스팅하여 특정 속성을 검색하는 것이다.

아래 예제는 구글 웹사이트가 띄워져 있는 IE를 검색하여 이를 bing.com으로 변경하는 코드이다.

(업데이트: SHDocVw.ShellWindows에서 한가지 주의할 점은 SHDocVw.ShellWindows()이 Internet Explorer 뿐 만 아니라 File Explorer와 같은 다른 Explorer들도 리턴한다는 것이다. 따라서, 이들을 구분하는 코드를 넣어 주는데, 아래 예제의 경우 wb.LocationURL 이 비어있는지를 체크하였다. wb.Name을 체크할 수도 있다.)


예제

static void Main(string[] args)
{
    // 특정 URL을 갖는 IE 찾기
    WebBrowser wb = FindIE("https://www.google.com");

    // URL을 다른 것으로 변경
    if (wb != null)
    {
       wb.Navigate("www.bing.com");
    }
}        

static SHDocVw.WebBrowser FindIE(string url)
{
    Uri uri = new Uri(url);
    var shellWindows = new SHDocVw.ShellWindows();
    foreach (SHDocVw.WebBrowser wb in shellWindows)
    {
        //File Explorer인 경우 LocationURL가 비어있음. 제외.
        if (!string.IsNullOrEmpty(wb.LocationURL))
        {
            Uri wbUri = new Uri(wb.LocationURL);
            Debug.WriteLine(wbUri);
            if (wbUri.Equals(uri))
            {
                return wb;
            }
        }
    }
    return null;
}



오픈소스 활용

웹브라우져를 컨트롤하는 또 다른 방식으로 오픈소스를 이용하는 방법이 있다. 예를 들어 WatiN 은 웹브라우져를 편리하게 컨트롤하도록 SHDocVw를 기반으로 한 Wrapper 클래스들을 제공하고 있다.

[참고] 웹브라우져를 컨트롤하는 Web Test Automation 도구로 Selenium이 널리 이용되고 있는데, 이에 대해서는 Web Automation (Selenium) 아티클을 참고.

아래 예제는 위의 2번째 예제와 같이 구글 사이트에서 Microsoft라는 검색어를 입력하고 결과를 찾는 코드이다. SHDocVw 내부 기능을 모두 Wrapping하고 있으므로 보다 간편하게 코딩할 수 있다.


예제

var browser = new IE("http://www.google.com");

browser.TextField(Find.ByName("q")).TypeText("Microsoft");
browser.Button(Find.ByName("btnG")).Click();
  
//browser.Dispose();



IE 프로세스 생성

직접 IE 프로세스를 생성하기 위해서는 System.Diagnostics.Process 클래스를 사용한다. 가장 간단하게는 iexplore.exe 프로그램 파일을 Process.Start()의 파라미터에 넣고 실행하면 된다. iexplore.exe의 커맨드라인 옵션들을 지정하기 위해서는 아래 두번째 예제처럼 Argument에 옵션들을 문자열로 지정하면 된다. 마지막 세번째 예제는 여러 옵션을 사용한 예로 특정 웹사이트 URL을 지정하여 IE 실행과 동시에 특정 웹사이트로 이동하는 예이다.

예제

using System.Diagnostics;

namespace ProcessApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // 1. IE 프로세스 생성
            Process p = Process.Start("iexplore");
            p.WaitForInputIdle();

            // 2. IE 옵션을 지정하기
            ProcessStartInfo psi = new ProcessStartInfo("iexplore", "-private");
            Process p2 = Process.Start(psi);            
            p2.WaitForInputIdle();

            // 3. IE 옵션을 지정하면서 특정 웹사이트로 이동
            ProcessStartInfo psi3 = new ProcessStartInfo("iexplore", "-private -noframemerging www.google.com");
            Process p3 = Process.Start(psi3);
            p3.WaitForInputIdle();
        }
    }
}



© csharpstudy.com