Skip to content

Instantly share code, notes, and snippets.

@iwantedue
Created December 10, 2013 08:24
Show Gist options
  • Save iwantedue/7887305 to your computer and use it in GitHub Desktop.
Save iwantedue/7887305 to your computer and use it in GitHub Desktop.
Method to watch a child windows messages specifically for use with CefSharp Chromium Embedded Web Browser
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
namespace WindowsFormsApplication1
{
public partial class Form2 : Form
{
private const int GWL_WNDPROC = -4;
[DllImport("User32.Dll")]
public static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
private static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll", EntryPoint = "SetWindowLong")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[SuppressUnmanagedCodeSecurity, SecurityCritical, DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr CallWindowProc(IntPtr wndProc, IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate IntPtr WndProcDelegate(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
var result = new List<IntPtr>();
var listHandle = GCHandle.Alloc(result);
try
{
var childProc = new EnumWindowsProc(EnumWindow);
EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
{
listHandle.Free();
}
}
return result;
}
private static bool EnumWindow(IntPtr handle, IntPtr pointer)
{
var gch = GCHandle.FromIntPtr(pointer);
var list = gch.Target as List<IntPtr>;
if (list == null)
{
throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
}
list.Add(handle);
return true;
}
private readonly WebView _webView;
private IntPtr _oldWebViewWndProc;
public Form2()
{
InitializeComponent();
if (CEF.Initialize(new Settings { PackLoadingDisabled = true }))
{
_webView = new WebView("http://www.google.com", new BrowserSettings()) {Dock = DockStyle.Fill};
_webView.PropertyChanged += WebViewPropertyChanged;
Controls.Add(_webView);
}
}
private void WebViewPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsBrowserInitialized" && _webView.IsBrowserInitialized)
{
//this is on the WebView UI thread need to invoke back into the Form UI thread
BeginInvoke(new Action(() =>
{
//get through child windows looking for the WebViewHost
foreach (var childWindow in GetChildWindows(Handle))
{
var className = new StringBuilder(100);
GetClassName(childWindow, className, className.Capacity);
if (className.ToString() == "WebViewHost")
{
//add a watcher to the WebView wndproc messages
WatchWebViewWndProc(childWindow);
}
}
}));
}
}
private void WatchWebViewWndProc(IntPtr hwnd)
{
//get current WndProc to pass message onto
_oldWebViewWndProc = GetWindowLong(hwnd, GWL_WNDPROC);
//overwrite WebView wndprox with our own
SetWindowLong(hwnd, GWL_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WndProcDelegate(WebViewWndProc)));
}
private IntPtr WebViewWndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam)
{
if (msg == 0x0084) //WM_NCHITEST
{
Debug.Print("WEBVIEW WM_NCHITEST");
}
//always pass onto original WndProc
return CallWindowProc(_oldWebViewWndProc, hWnd, msg, wParam, lParam);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0083) //WM_NCAlSIZE
{
}
if (m.Msg == 0x0084) //WM_NCHITEST
{
Debug.Print("FORM WM_NCHITEST");
}
base.WndProc(ref m);
}
}
}
@Joshua-Anderson
Copy link

Hello. This looks good, however I am using Xilium.Cefglue, which as far as I can tell does not have the WebViewPropertyChanged event. Is there a way to work around that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment