Skip to content

Instantly share code, notes, and snippets.

@jimevans
Last active March 17, 2021 23:29
Show Gist options
  • Save jimevans/7268760 to your computer and use it in GitHub Desktop.
Save jimevans/7268760 to your computer and use it in GitHub Desktop.
Sample console application demonstrating unexpected firing of OnQuit event from IE11.
Prerequisites:
* A machine with Visual Studio 2013 installed
* A machine with IE11 installed
* The Protected Mode settings of all zones must be set to the same value
(on or off, it doesn't matter, as long as all zones are the same value)
* Enhanced Protected Mode should be disabled
Steps to reproduce:
1. Create a Visual Studio Solution with a C# Console Application project
consisting of the attached C# code, with references to MSHTML (Microsoft
HTML Object Library) and SHDocVw (Microsoft Internet Controls).
2. Created a new asp.net web site in the same solution, and add a blank
page called main.html
3. In the Solution Explorer, right-click on main.html and select "View in
Browser...". This will launch IIS Express and load the page in Internet
Explorer.
4. Note the port the IIS Express instance is using for the ASP.NET
application, and close the instance of Internet Explorer.
5. Configure IIS Express to allow any pages to be browsed from any host
names (see http://stackoverflow.com/a/14967651/374693 for a sample set
of instructions how to configure this).
6. Launch the console application, entering the port number when prompted.
IE11 will be launched, navigated to http://localhost:<port>/main.html.
7. In the address bar of the opened Internet Explorer window, navigate to
http://127.0.0.1:<port>/main.html. The same page will be browsed to,
only using the IP address. You'll see the events firing in the console
window.
8. In the address bar, navigate back to http://localhost:<port>/main.html.
Result in console:
Enter the port on which the local website is running:
54744
IE is started, and events are connected.
Called BeforeNavigate2 event (URL = http://127.0.0.1:54744/main.html)
Called DocumentComplete event (URL = http://127.0.0.1:54744/main.html)
Called BeforeNavigate2 event (URL = http://localhost:54744/main.html)
OnQuit event fired!
Expect:
The OnQuit should not be fired.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MSHTML;
using SHDocVw;
namespace OnQuitDemo
{
public delegate bool EnumWindowsProc(IntPtr hwnd, ref ProcessWindowInfo lParam);
[StructLayout(LayoutKind.Sequential)]
public struct ProcessWindowInfo
{
public int processId;
public IntPtr windowHandle;
}
[Flags]
public enum SendMessageTimeoutFlags : uint
{
SMTO_NORMAL = 0x0,
SMTO_BLOCK = 0x1,
SMTO_ABORTIFHUNG = 0x2,
SMTO_NOTIMEOUTIFNOTHUNG = 0x8
}
[ComImport]
[Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IServiceProvider
{
void QueryService(
ref Guid serviceInterfaceId,
ref Guid requestedInterfaceId,
[MarshalAs(UnmanagedType.Interface)] out object requestedObject);
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessInformation
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
public static class NativeMethods
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int SendMessageTimeout(
IntPtr hWnd,
uint Msg,
UIntPtr wParam,
IntPtr lParam,
SendMessageTimeoutFlags fuFlags,
uint uTimeout,
out UIntPtr lpdwResult);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern uint RegisterWindowMessage(string lpString);
[DllImport("oleacc.dll", PreserveSig = false)]
[return: MarshalAs(UnmanagedType.Interface)]
public static extern object ObjectFromLresult(
UIntPtr lResult,
[MarshalAs(UnmanagedType.LPStruct)] Guid refiid,
IntPtr wParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumWindows(
EnumWindowsProc lpEnumFunction,
ref ProcessWindowInfo lParam);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(
IntPtr handle,
EnumWindowsProc lpEnumFunction,
ref ProcessWindowInfo lParam);
[DllImport("user32.dll")]
public static extern int GetClassName(
IntPtr hwnd,
StringBuilder lpClassName,
int nMaxCount);
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(
IntPtr handle,
out uint processId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("ieframe.dll", CharSet = CharSet.Unicode)]
public static extern int IELaunchURL(
[In]string url,
out ProcessInformation procInfo,
IntPtr ipInfo);
}
class Program
{
static string DemoPageUrlTemplate = "http://localhost:{0}/main.html";
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("Enter the port on which the local website is running:");
string portString = Console.ReadLine();
int port = 0;
if (!int.TryParse(portString, out port))
{
Console.WriteLine("Port isn't a valid number!");
}
else
{
LaunchAndAttach(port);
}
while (true)
{
Thread.Sleep(100);
}
}
private static void LaunchAndAttach(int port)
{
IntPtr windowHandle = LaunchInternetExplorer(port);
IHTMLDocument2 doc = GetDocumentFromWindowHandle(windowHandle);
IWebBrowser2 browser = GetBrowserFromDocument(doc);
InternetExplorer app = browser as InternetExplorer;
if (app != null)
{
app.BeforeNavigate2 += new DWebBrowserEvents2_BeforeNavigate2EventHandler(BeforeNavigate2);
app.DocumentComplete += new DWebBrowserEvents2_DocumentCompleteEventHandler(DocumentComplete);
app.OnQuit += new DWebBrowserEvents2_OnQuitEventHandler(OnQuit);
app.NewProcess += new DWebBrowserEvents2_NewProcessEventHandler(NewProcess);
Console.WriteLine("IE is started, and events are connected.");
}
else
{
Console.WriteLine("Was unable to connect to IE and wire up events.");
}
}
private static IntPtr LaunchInternetExplorer(int port)
{
ProcessInformation processInfo = new ProcessInformation();
NativeMethods.IELaunchURL(string.Format(DemoPageUrlTemplate, port), out processInfo, IntPtr.Zero);
IntPtr foundWindowHandle = IntPtr.Zero;
DateTime end = DateTime.Now.Add(TimeSpan.FromSeconds(10));
while (foundWindowHandle == IntPtr.Zero && DateTime.Now < end)
{
ProcessWindowInfo info = new ProcessWindowInfo();
info.windowHandle = IntPtr.Zero;
info.processId = processInfo.dwProcessId;
EnumWindowsProc finder = FindBrowserWindow;
NativeMethods.EnumWindows(finder, ref info);
foundWindowHandle = info.windowHandle;
}
if (processInfo.hThread != IntPtr.Zero)
{
NativeMethods.CloseHandle(processInfo.hThread);
}
if (processInfo.hProcess != IntPtr.Zero)
{
NativeMethods.CloseHandle(processInfo.hProcess);
}
return foundWindowHandle;
}
static bool FindBrowserWindow(IntPtr handle, ref ProcessWindowInfo lParam)
{
StringBuilder classBuilder = new StringBuilder(8);
NativeMethods.GetClassName(handle, classBuilder, 8);
if (classBuilder.ToString() != "IEFrame")
{
return true;
}
EnumWindowsProc finder = FindChildWindowForProcess;
return NativeMethods.EnumChildWindows(handle, finder, ref lParam);
}
private static bool FindChildWindowForProcess(IntPtr handle, ref ProcessWindowInfo lParam)
{
StringBuilder classBuilder = new StringBuilder(25);
NativeMethods.GetClassName(handle, classBuilder, 25);
if (classBuilder.ToString() != "Internet Explorer_Server")
{
return true;
}
uint processId = 0;
uint threadId = NativeMethods.GetWindowThreadProcessId(handle, out processId);
if (processId == lParam.processId)
{
lParam.windowHandle = handle;
return false;
}
return true;
}
static void DocumentComplete(object pDisp, ref object URL)
{
Console.WriteLine("Called DocumentComplete event (URL = {0})", URL.ToString());
}
static void BeforeNavigate2(object pDisp, ref object URL, ref object Flags, ref object TargetFrameName, ref object PostData, ref object Headers, ref bool Cancel)
{
Console.WriteLine("Called BeforeNavigate2 event (URL = {0})", URL.ToString());
}
private static void NewProcess(int lCauseFlag, object pWB2, ref bool Cancel)
{
Console.WriteLine("Called NewProcess event");
if (pWB2 == null)
{
Console.WriteLine("web browser pointer is null");
}
}
private static void OnQuit()
{
Console.WriteLine("OnQuit event fired!");
}
private static IHTMLDocument2 GetDocumentFromWindowHandle(IntPtr windowHandle)
{
uint msg = NativeMethods.RegisterWindowMessage("WM_HTML_GETOBJECT");
UIntPtr documentPtr = UIntPtr.Zero;
int result = NativeMethods.SendMessageTimeout(windowHandle, msg, UIntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out documentPtr);
if (result == 0)
{
Console.WriteLine("SendMessageTimeout failed with error code {0}", Marshal.GetLastWin32Error());
}
return NativeMethods.ObjectFromLresult(documentPtr, typeof(IHTMLDocument2).GUID, IntPtr.Zero) as IHTMLDocument2;
}
private static IWebBrowser2 GetBrowserFromDocument(IHTMLDocument2 document)
{
if (document == null)
{
Console.WriteLine("Document was null");
return null;
}
IServiceProvider windowServiceProvider = document.parentWindow as IServiceProvider;
if (windowServiceProvider == null)
{
Console.WriteLine("Cast to IServiceProvider on parentWindow returned null");
return null;
}
Guid browserAppInterfaceId = typeof(IWebBrowserApp).GUID;
Guid webBrowserInterfaceId = typeof(IWebBrowser2).GUID;
try
{
object webBrowserObject;
windowServiceProvider.QueryService(ref browserAppInterfaceId, ref webBrowserInterfaceId, out webBrowserObject);
return webBrowserObject as IWebBrowser2;
}
catch (Exception)
{
Console.WriteLine("QueryService failed with error code {0}", Marshal.GetLastWin32Error());
}
return null;
}
}
}
@kostokasp
Copy link

Did you resolve this? I am getting the same result.

@YukiSabri
Copy link

YukiSabri commented Jul 3, 2017

Got the same issue....
[Facebook\WebDriver\Exception\NoSuchWindowException] Unable to get browser (WARNING: The server did not provide any stacktrace information) Command duration or timeout: 13 milliseconds Build info: version: '3.4.0', revision: 'unknown', time: 'unknown' System info: host: 'DESKTOP-RU3IGJ2', ip: '192.168.33.1', os.name: 'Windows 10', os.arch: 'amd64', os.ve rsion: '10.0', java.version: '1.8.0_131' Driver info: org.openqa.selenium.ie.InternetExplorerDriver Capabilities [{se:ieOptions={browserAttachTimeout=0.0, ie.enableFullPageScreenshot=true, enablePersisten tHover=true, ie.forceCreateProcessApi=false, ie.forceShellWindowsApi=false, ignoreZoomSetting=false, ie. fileUploadDialogTimeout=3000.0, ie.useLegacyFileUploadDialogHandling=false, nativeEvents=true, ie.ensure CleanSession=false, elementScrollBehavior=0.0, ie.browserCommandLineSwitches=, requireWindowFocus=false, initialBrowserUrl=http://localhost:6330/, ignoreProtectedModeSettings=false, enableElementCacheCleanup= true}, browserName=internet explorer, pageLoadStrategy=normal, javascriptEnabled=true, version=11, platf orm=WINDOWS, unexpectedAlertBehaviour=dismiss}] Session ID: 38f4fb31-a749-47ad-85cb-315ab641afe6

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