ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [C#] - WinForm WebBrowser 사용방법 및 팁
    .NET/CSharp 2021. 12. 17. 20:15

    C# WinForm WebBrowser 사용방법 및 팁

    현재 회사에서 WebBrowser 컨트롤을 활용한 프로그램을 개발중에 있습니다. 개발하면서 겪었던 점을 정리합니다.

    1.WebBrowser 레지스트리

    Internet Feature Control Keys

    https://msdn.microsoft.com/en-us/library/ee330720(v=vs.85).aspx

    위에 링크는 WebBrowser를 활용하기 위해 필요한 기능(레지스트리 정보)에 대해서 설명하고 있습니다.

    InternetFeatureControlKeys 클래스는 해당 레지스트리 정보들을 추가 할 수 있는 기능을 제공합니다.

    InternetFeatureControlKeys.cs

    using Microsoft.Win32;
    using System;
    using System.Collections.Generic;
    using System.Windows.Forms;
    
    namespace UseWebBrowser
    {
    
        public class InternetFeatureControlKeys
        {
            public const string FEATURE_BROWSER_EMULATION = "FEATURE_BROWSER_EMULATION";
    
            /// <summary>
            /// 현재 프로세스가 64 비트 프로세스인지 여부
            /// </summary>
            public static bool Is64BitProcess = IntPtr.Size == 8;
    
            public static bool Is64BitOperatingSystem = NativeMethods.IsOS64Bit();
    
            /// <summary>
            /// FEATURE_BROWSER_EMULATION 값 자동적으로 설정 여부
            /// </summary>
            public bool AutoBrowserEmulation
            {
                get { return _autoBrowserEmulation; }
                set { _autoBrowserEmulation = value; }
            }
            private bool _autoBrowserEmulation;
    
            /// <summary>
            /// FEATURE_BROWSER_EMULATION 값
            /// </summary>
            public int BrowserEmulation
            {
                get { return _browserEmulation; }
            }
            private int _browserEmulation = 7000;
    
            /// <summary>
            /// 레지스트리 HKEY 타입
            /// <para><see cref="HKEY.LocalMachine"/> 일때 관리자 권한 아닐 경우 예외발생</para>
            /// </summary>
            /// <exception cref="System.ArgumentException"></exception>
            public HKEY HKey
            {
                get { return _hKey; }
                set 
                {
                    if (value == HKEY.LocalMachine)
                    {
                        if (!Toolkit.IsExecuteAdministrator())
                        {
                            throw new System.ArgumentException("Usage Execute Administrator");
                        }
                    }
                    _hKey = value; 
                }
            }
            private HKEY _hKey = HKEY.CurrentUser;
    
            /// <summary>
            /// Internet Feature Control Keys 
            /// <para>Key,Value</para>
            /// </summary>
            public Dictionary<string, uint> Features
            {
                get { return _features; }
                private set { _features = value; }
            }
            private Dictionary<string, uint> _features;
    
            public InternetFeatureControlKeys()
            {
                Features = new Dictionary<string, uint>();
    
                SetBrowserEmulation();
            }
    
            #region BrowserEmulation
            private int GetRegisterBrowserVersion()
            {
                string ieBrowserVersion = RegistryUtility.GetInternetExplorerVersion();
                int indexOf = ieBrowserVersion.IndexOf('.'), result = 0;
                if (indexOf != -1)
                {
                    int.TryParse(ieBrowserVersion.Substring(0, indexOf), out result);
                }
                return result;
            }
    
            private void SetWebBrowserCtrlVersion(int webBrowserMajorVersion, out int outWebBrowserCtrlVersion)
            {
                Toolkit.TraceWriteLine("WebBrowser Version=" + webBrowserMajorVersion);
    
                // Set the appropriate Internet Explorer version
                if (webBrowserMajorVersion >= 11)
                {
                    outWebBrowserCtrlVersion = (int)BrowserEmulationVersion.Version11Edge;
                }
                else if (webBrowserMajorVersion == 10)
                {
                    outWebBrowserCtrlVersion = (int)BrowserEmulationVersion.Version10Standards;
                }
                else if (webBrowserMajorVersion == 9)
                {
                    outWebBrowserCtrlVersion = (int)BrowserEmulationVersion.Version9Standards;
                }
                else if (webBrowserMajorVersion == 8)
                {
                    outWebBrowserCtrlVersion = (int)BrowserEmulationVersion.Version8Standards;
                }
                else
                {
                    outWebBrowserCtrlVersion = (int)BrowserEmulationVersion.Version7;
                }
    
                Toolkit.TraceWriteLine("BrowserEmulationVersion=" + outWebBrowserCtrlVersion.ToString());
            }
    
            private void SetBrowserEmulation()
            {
                Toolkit.TraceWriteLine("Start");
    
                int webBrowserCtrlVersion = 0;
                using (WebBrowser Wb = new WebBrowser())
                {
                    SetWebBrowserCtrlVersion(Wb.Version.Major, out webBrowserCtrlVersion);
                }
    
                int.TryParse(webBrowserCtrlVersion.ToString().Substring(0, 2), out webBrowserCtrlVersion);
    
                int ieBrowserRegistryVersion = GetRegisterBrowserVersion();
                Toolkit.TraceWriteLine("WebBrowser Version=" + webBrowserCtrlVersion);
                Toolkit.TraceWriteLine("InternetExplorer Registry Version=" + ieBrowserRegistryVersion);
    
                if (webBrowserCtrlVersion == ieBrowserRegistryVersion)
                {
                    Toolkit.TraceWriteLine("Same WebBrowser Version == InternetExplorer Registry Version");
                    SetWebBrowserCtrlVersion(webBrowserCtrlVersion, out _browserEmulation);
                }
                else
                {
                    Toolkit.TraceWriteLine("Same WebBrowser Version != InternetExplorer Registry Version");
                    Toolkit.TraceWriteLine(String.Format("WebBrowser Version={0}, InternetExplorer Registry Version={1}", webBrowserCtrlVersion, ieBrowserRegistryVersion));
                    SetWebBrowserCtrlVersion(ieBrowserRegistryVersion, out _browserEmulation);
                }
    
                Toolkit.TraceWriteLine("End");
            }
    
            #endregion
    
            /// <summary>
            /// 레지스트리에 추가할 Internet Feature Control Key를 등록한다.
            /// </summary>
            /// <param name="key"></param>
            /// <param name="value"></param>
            public void AddFeature(string key, int value)
            {
                _features.Add(key, (uint)value);
            }
    
            /// <summary>
            /// appName 이름으로 Feature에 있는 내용을 레지스트리에 추가한다.
            /// </summary>
            /// <param name="appName"></param>
            public void WriteRegistry(string appName)
            {
                foreach (var item in _features)
                {
                    SetRegistryBrowserFeatureControlKey(
                        appName,
                        item.Key,
                        item.Value
                    );
                }
    
                if (_autoBrowserEmulation)
                {
                    SetRegistryBrowserFeatureControlKey(appName, FEATURE_BROWSER_EMULATION, (uint)_browserEmulation);
                }
            }
    
            public void AddDefaultFeature()
            {
                // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330720(v=vs.85)
    
                #region (A) 항목
    
                #endregion
    
                #region (B..C) 항목
    
                #endregion
    
                #region (D..H) 항목
    
                #endregion
    
                #region (I..L) 항목
    
                #endregion
    
                #region (M..R) 항목
    
    
                #endregion
    
                #region (S..T) 항목
    
                #endregion
    
                #region (U..Y) 항목
    
                #endregion
    
                #region (Z) 항목
    
                #endregion
    
                #region Obsolete Feature Controls
    
                #endregion
    
    
                // (B..C) 항목
                if (!Features.ContainsKey("FEATURE_BROWSER_EMULATION"))
                {
                    AddFeature("FEATURE_BROWSER_EMULATION", _browserEmulation);
                }
    
                // (U..Y) 항목
    
    
                // (U..Y) 항목
    
    
                foreach (var key in Features.Keys)
                {
                    int value = (int)Features[key];
                    AddFeature(key, value);
                }
            }
    
            /// <summary>
            /// 레지스트리를 추가한다.
            /// <para>CurrentUser</para>
            /// <para>Software\Microsoft\Internet Explorer\Main\FeatureControl\</para>
            /// <para>LocalMachine</para>
            /// <para>x64비트 32비트 프로그램 = Software\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\</para>
            /// <para>그외 = Software\Microsoft\Internet Explorer\Main\FeatureControl\</para>
            /// </summary>
            /// <param name="appName"></param>
            /// <param name="feature"></param>
            /// <param name="value"></param>
            public void SetRegistryBrowserFeatureControlKey(string appName, string feature, uint value)
            {
                if (_hKey == HKEY.LocalMachine)
                {
                    string subKey = String.Empty;
                    if (!Is64BitProcess && Is64BitOperatingSystem)
                    {
                        subKey = @"Software\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\";
                    }
                    else
                    {
                        subKey = @"Software\Microsoft\Internet Explorer\Main\FeatureControl\";
                    }
    
                    subKey = String.Concat(subKey, feature);
                    using (var key = Registry.LocalMachine.CreateSubKey(subKey, RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord);
                    }
                }
                else
                {
                    string subKey = String.Concat(@"Software\Microsoft\Internet Explorer\Main\FeatureControl\", feature);
                    using (var key = Registry.CurrentUser.CreateSubKey(subKey, RegistryKeyPermissionCheck.ReadWriteSubTree))
                    {
                        key.SetValue(appName, (UInt32)value, RegistryValueKind.DWord);
                    }
                }
            }
        }
    }

    InternetFeatureControlKeys 클래스 생성시 HKEY 기본값이 CurrentUser 인걸 볼 수 있습니다. LocalMachine 인 경우에는 관리자권한 실행이 필요하고 32비트 64비트 일때 등록시키는 위치가 틀립니다. 자세한 내용은 시간이 날때 해당 포스트에 추가적으로 정리 할 예정입니다.

    [ 그림 1 - 레지스트리 편집기 HKEY_CURRENT_USER ]

    Wow6432 는 64비트 윈도우에서 32비트 프로그램의 레지스트리를 등록합니다.

    32비트 윈도우에서 32비트 프로그램, 64비트 윈도우에서 64비트 프로그램
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\

    64비트 윈도우에서 32비트 프로그램
    HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\

    Form Load 이벤트에서 WeBrowser 레지스트리 정보 적용

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Reflection;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    using System.Xml;
    
    namespace UseWebBrowser
    {
        public partial class Form : System.Windows.Forms.Form
        {
            public Form()
            {
                InitializeComponent();
            }
    
            private void Form_Load(object sender, EventArgs e)
            {
                InternetFeatureControlKeys featureControlKeys = new InternetFeatureControlKeys();
                Assembly assembly = System.Reflection.Assembly.GetEntryAssembly();
                string path = Path.GetDirectoryName(assembly.Location) + Path.DirectorySeparatorChar + "InternetFeatureControlKeys.xml";
                if (File.Exists(path))
                {
                    try
                    {
                        XmlDocument doc = new XmlDocument();
                        doc.Load(path);
                        XmlNodeList xmlNodeList = doc.SelectNodes("InternetFeatureControlKeys/InternetFeature");
                        foreach (XmlNode xmlNode in xmlNodeList)
                        {
                            string name = (string)xmlNode.Attributes["name"].Value;
                            if (name == InternetFeatureControlKeys.FEATURE_BROWSER_EMULATION && xmlNode.InnerText == "%Auto%")
                            {
                                featureControlKeys.AutoBrowserEmulation = true;
                                continue;
                            }
    
                            uint value = (uint)int.Parse(xmlNode.InnerText);
                            featureControlKeys.Features.Add(name, value);
                        }
                    }
                    catch (Exception ex)
                    {
                        Toolkit.TraceWriteLine(ex.Message);
                        Toolkit.TraceWriteLine(ex.StackTrace);
    
                        featureControlKeys.AddDefaultFeature();
                    }
                }
                else
                {
                    featureControlKeys.AddDefaultFeature();
                }
    
                string appName = String.Empty;
                if (Debugger.IsAttached)
                {
                    // Debug [F5 실행]
                    Process process = Process.GetCurrentProcess();
                    appName = Path.GetFileName(process.MainModule.FileName);
                    featureControlKeys.WriteRegistry(appName);
                    Toolkit.DebugWriteLine("Debugger.IsAttached InternetFeatureControlKeys WriteRegistry appName - " + appName);
                }
    
                if (!appName.Equals(Application.ProductName + ".exe"))
                {
                    // Execute
                    appName = Application.ProductName + ".exe";
                    featureControlKeys.WriteRegistry(appName);
                    Toolkit.TraceWriteLine("InternetFeatureControlKeys WriteRegistry appName - " + appName);
                }
            }
        }
    }

    [ 그림 2 - 프로젝트 속성/응용 프로그램/어셈블리 정보 ]

    그림 2와 같이 Application.ProductName 값은 어셈블리 정보 창의 제품값에 해당됩니다. 만약에 해당값을 Entry 어셈블리명(실행 파일명 확장자 제외)과 틀릴 경우 문제가 될 수 있는 코드입니다. 그림2 같은 경우에는 어셈블리 명과 같아서 문제가 되질 않지만 문제가 될 만한 코드 이기 때문에 아래와 같이 Entry 어셈블리명.exe 로 추가적으로 레지스트리에 등록을 해줍니다.

    if (!appName.Equals(Application.ProductName + ".exe"))
    {
        // Execute
        appName = Application.ProductName + ".exe";
        featureControlKeys.WriteRegistry(appName);
        Toolkit.TraceWriteLine("InternetFeatureControlKeys WriteRegistry appName - " + appName);
    }
    
    appName = Assembly.GetEntryAssembly().GetName().Name;
    appName = appName + ".exe";
    featureControlKeys.WriteRegistry(appName);

    InternetFeatureControlKeys.xml

    <?xml version="1.0" encoding="utf-8" ?>
    <!-- https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/general-info/ee330720(v=vs.85) -->
    <InternetFeatureControlKeys>
      <!-- (A) 항목-->
    
    
      <!-- (B..C) 항목-->
    
      <!-- %Auto% 시 해당 값은 로컬 PC에 설치되어 있는 IE버전을 내부적으로 실행 시 설정 한다. -->
      <InternetFeature name="FEATURE_BROWSER_EMULATION">%Auto%</InternetFeature>
    
      <!-- (D..H) 항목-->
    
    
      <!-- (I..L) 항목 -->
    
      <!-- (M..R) 항목 -->
    
    
      <!-- (S..T) 항목 -->
    
    
      <!-- (U..Y) 항목 -->
    
    
      <!-- (Z) 항목 -->
    
      <!-- Obsolete Feature Controls -->
    
    
    </InternetFeatureControlKeys>

    Form Load 이벤트에서는 InternetFeatureControlKeys.xml 파일을 읽어들여 해당 파일에 추가되어있는 정보들을 레지스트리에 추가하고 있습니다.

    Visual Studio 출력

    [Form :: Form_Load] DEBUG - Debugger.IsAttached InternetFeatureControlKeys WriteRegistry appName - UseWebBrowser.vshost.exe
    [Form :: Form_Load] TRACE - InternetFeatureControlKeys WriteRegistry appName - UseWebBrowser.exe

    위와 같이 디버그 실행(F5), Ctrl + F5 실행 에 대한 파일 이름이 다르기 때문에 실행 파일 별로 레지스트리에 WebBrowser 레지스트리 정보를 추가하고 있습니다.

    [ 그림 3 - 추가된 레지스트리 정보 ]

    현재 그림 2와 같이 추가된 FEATURE_BROWSER_EMULATION 항목은 아래 내용을 참고하시기 바랍니다.

    브라우저 버전 (FEATURE_BROWSER_EMULATION)

    해당 값은 렌더링 되는 웹 페이지(JSP, HTML ..) 내용과 연관되어 있습니다. 자세한 내용은 추후 정리해보고자 합니다. content 값이 IE=edge 일 경우 11001로 설정해야합니다.

    <meta http-equiv="X-UA-Compatible" content="IE=edge"> 

    2.WebBrowser 에서 렌더링된 페이지와 데이터 통신

    전달되는 데이터 형태는 프로그램 개발시에 유동적으로 바뀌기 때문에 하나의 JSON 객체의 문자열로 전달하는게 바람직합니다.

    2-1. 렌더링된 페이지에서 WebBrowser 데이터 전달

    렌더링된 페이지에서 WebBrowser 로 데이터 전달은 아래와 같이 전달합니다.

    Test1.html

    <!DOCTYPE html>
    
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title>Test1</title>
        <script type="text/javascript">
            function callNative() {
                if ("CallNative" in window.external) {
                    var data = { eventName: "Btn1 OnClick" };
                    window.external.CallNative(JSON.stringify(data));
                }
            }
    
            function receiveNative(arg) {
                alert(JSON.stringify(arg));
            }
        </script>
    </head>
    <body>
        <div>
            <input type="button" id="Btn1" value="CallNative" onclick="callNative()"/>
        </div>
    </body>
    </html>

    CallNative 함수는 C# 클라이언트 프로그램에 정의되어야 하는 메서드입니다. 해당 메서드는 WebBrowser.ObjectForScripting 속성에 설정되는 Object 에 정의되어야 하는 public 메서드이며 클래스 접근지정자 또한 public 이어야만 합니다. 그리고 해당 클래스에는 아래와 같이 어트리뷰트 추가가 필요합니다.

    [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    [ComVisible(true)]

    되도록이면 해당 속성에 설정되는 클래스 객체는 별도의 클래스 (WebNativeManager)를 생성하여 작업하시기 바랍니다.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace UseWebBrowser 
    {
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        [ComVisible(true)]
        public class WebNativeManager {
            public void CallNative(object arg0) {
    
            }
        }
    }

    [ 그림 3 - ObjectForScripting System.ArgumentException ]

    그림 3과 같이 WebNativeManager 클래스 접근지정자가 public 이 아닐경우 System.ArgumentException 예외를 발생

    [ 그림 4 - 스크립트 오류 발생 ]

    그림 4와 같이 CallNative 메서드 접근지정자가 public 이 아닐경우 스크립트 오류 발생

    WebNativeManager.WindowExternal.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace UseWebBrowser
    {
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        [ComVisible(true)]
        public partial class WebNativeManager
        {
            private WebBrowser _WebBrowser;
            public WebNativeManager(WebBrowser webBrowser)
            {
                _WebBrowser = webBrowser;
            }
    
            public void CallNative(object arg0)
            {
                Toolkit.TraceWriteLine("Arg0=" + arg0);
            }
        }
    }

    Test1.html 페이지에서 WebBrowser 로 전달된 데이터

    [WebNativeManager :: CallNative] TRACE - Arg0={"eventName":"Btn1 OnClick"}

    CallNative 메서드가 try catch 문으로 예외처리가 되어 있지 않습니다. WebBrowser ScriptErrorsSuppressed 값이 False 일경우에는 에러를 확인 할 수 없는 상황이 오므로 반드시 try catch 문으로 감싸서 에러가 발생하였을 경우 로그처리를 해줘야 개발자가 의도치 않은 예외상황에 대처할 수 있습니다.

    2-2. WebBrowser 에서 렌더링된 페이지로 데이터 전달

    이번에는 반대로 WebBrowser 에서 렌더링된 페이지로 데이터를 전달합니다.

    WebBrowser.Document 속성을 이용하여 해당 객체의 InvokeScript 메서드를 호출하여 렌더링된 페이지로 데이터를 전달 합니다.

    WebNativeManager.InvokeScript.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace UseWebBrowser
    {
        partial class WebNativeManager
        {
            public object InvokeScript(string scriptName, object[] args)
            {
                return _WebBrowser.Document.InvokeScript(scriptName, args);
            }
        }
    }

    3. 속성 및 이벤트

    3-1. PreviewKeyDown 이벤트

    private void Body_KeyDown(object sender, HtmlElementEventArgs e)
    {
        // 86 ASCII CODE = 'V'
        if (e.KeyPressedCode == 86 && e.CtrlKeyPressed)
        {
            string text = Clipboard.GetText();
            _WebBrowser.Document.ExecCommand("Paste", false, text);
        }
    }

    기존에 위와 같이 WebBrowser.Document.Body.KeyDown 이벤트로 Paste(Ctrl + V) 처리하려고 하였으나 e.KeyPressedCode 값이 제대로 넘어오질 않아 PreviewKeyDown 이벤트로 처리하였습니다.

    해당 이벤트에서는 아래 코드가 정상적으로 동작을 합니다.

    private void WebBrowser_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.V)
        {
            string text = Clipboard.GetText();
            _WebBrowser.Document.ExecCommand("Paste", false, text);
        }
        else if (e.Control && e.KeyCode == Keys.A)
        {
             _WebBrowser.Document.ExecCommand("SelectAll", false, null);
        }
        else if (e.Control && e.KeyCode == Keys.C)
        {
             _WebBrowser.Document.ExecCommand("Copy", false, null);
        }
        else if (e.Control && e.KeyCode == Keys.X)
        {
            _WebBrowser.Document.ExecCommand("Cut", false, null);
        }
    
        if (e.KeyCode == Keys.Delete)
        {
            _WebBrowser.Document.ExecCommand("Delete", false, null);
        }
    }

    4. 기타

    4-1. WebBrowser 에서 HtmlElement로 마우스 이벤트 보내기

    Test2.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Test2</title>
            <script>
                var board = null; 
                function bodyOnLoad() { 
                    alert("bodyOnLoad()"); 
                    board = document.getElementById("board"); 
                    board.onmousedown = function(e) { 
                        if (e) { 
                            // 웹 브라우저에서만 테스트 할 경우 호출 됨
                            alert("board.onmousedown(e)"); 
                        } else { 
                            alert("e undefined mousedown"); 
                        } 
                    }; 
                } 
            </script> 
            <style> 
                div { 
                    background-color:lightblue; 
                    width:5000px; 
                    height:5000px; 
    
                } 
            </style> 
    </head>
     <body onload="bodyOnLoad()"> 
         <div id="board"> </div> 
     </body> 
    </html>

    WM_LBUTTONDOWN

    private void ButtonLButtonDown_Click(object sender, EventArgs e)
    {
        if (_TextBoxPosX.Text.Length > 0 && _TextBoxPosY.Text.Length > 0)
        {
            int posX = int.Parse(_TextBoxPosX.Text);
            int posY = int.Parse(_TextBoxPosX.Text);
    
            IntPtr handle = NativeMethods.FindWindowEx(_WebBrowser.Handle, IntPtr.Zero, "Shell Embedding", "");
    
            handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "Shell DocObject View", "");
            handle = NativeMethods.FindWindowEx(handle, IntPtr.Zero, "Internet Explorer_Server", "");
    
            const int WM_LBUTTONDOWN = 0x0201;
            NativeMethods.PostMessage(handle, WM_LBUTTONDOWN, 0, NativeMethods.PointToLParam(posX, posY));
        }
    }

    [ 그림 5 - Spy++ ]

    그림 5를 보시면 ButtonLButtonDown_Click 이벤트 메서드에서 왜 핸들을 위와 같이 찾는지 이해가 되실거라고 생각되어 집니다. CEF(Chromium Embedded Framework) 브라우저 또한 위와 같은 방식으로 핸들을 찾아서 마우스 클릭없이 onmousedown 이벤트를 보낼 수 있습니다.

    4-2. WebBrowser 컨트롤을 포함한 사용자 컨트롤 ActiveX

    WebBrowser 컨트롤을 포함한 사용자 컨트롤을 ActiveX 로 만들어 InternetExplorer 브라우저에 Embedd 하려고 하였으나 ObjectDisposeException 발생

    그리하여 MFC ActiveX 컨트롤에 해당 사용자 컨트롤을 래핑하여 올렸다.
    (해당 개념에 대해서는 CCW(COM Callable Wrapper) 를 찾아보시기 바랍니다.)

    4-3. WebBrowser 컨트롤에서 렌더링한 페이지 개발자 도구 열기

    해당 내용은 최근에서야 알게 되었으며 아래 링크를 통하여 확인 할 수 있습니다.

    https://docs.microsoft.com/ko-kr/microsoft-edge/devtools-guide-chromium/ie-mode/

    [ 그림 6 - 실행 창에서 IEChooser.exe 실행 ]

    그림 6과 같이 실행 창에서 IEChooser.exe 를 실행하면 그림 7과 같은 화면이 나오게 되는데 브라우저 컨트롤을 활용한 프로그램이 실행중일 경우 디버그할 대상에 목록이 나타나게 됩니다.

    [ 그림-7 IEChooser.exe ]

    자세하게 어떠한 환경에서 IEChooser.exe 가 설치되어 있으며 동작하게 되는지는 추후에 연구해 포스트에 추가하도록 하겠습니다.

     

    5. mshtml(Microsoft HTML Object Library)

    WebBrowser 컨트롤의 코어 기능을 사용하기 위해서는 mshtml.dll 을 활용하여 처리 할 수 있습니다. 프로젝트/참조 참조추가 메뉴를 클릭하여 COM 항목에서 Microsoft HTML Object Library 항목을 체크하여 추가합니다.

     

    5.1 Ctrl + MouseWheel 시 확대/축소 방지하기

    참고

    https://stackoverflow.com/questions/3971675/c-sharp-capturing-ctrl-mouse-wheel-in-webbrowser-control

     

    GitHub Source
    https://github.com/soultomind/Blog/tree/develop/UseWebBrowser

     

    댓글

Designed by Tistory.