private void WB_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { if (!_AllowSecurityAlert) { // Tell the WidowsInterop to Unhook WindowsInterop.Unhook(); } }
private void WB_Navigating(object sender, WebBrowserNavigatingEventArgs e) { if (!_AllowSecurityAlert) { // Tell the WidowsInterop to Hook messages WindowsInterop.Hook(); } }
// Populate a list of all the child windows of a given parent // (Uses the Win32 API's EnumChildWindows() function) private static List <IntPtr> listChildWindows(IntPtr p) { List <IntPtr> lstChildWindows = new List <IntPtr>(); GCHandle gchChildWindows = GCHandle.Alloc(lstChildWindows); try { WindowsInterop.EnumChildWindows(p, new EnumerateWindowDelegate(WindowsInterop.enumWindowsCallback), GCHandle.ToIntPtr(gchChildWindows)); } finally { if (gchChildWindows.IsAllocated) { gchChildWindows.Free(); } } return(lstChildWindows); }
// Hook proceedure called by the OS when a message has been processed by the target Window private static Int32 WH_CALLWNDPROCRET_PROC(Int32 iCode, IntPtr pWParam, IntPtr pLParam) { if (iCode < 0) { return(CallNextHookEx(WindowsInterop._pWH_CALLWNDPROCRET, iCode, pWParam, pLParam)); } CWPRETSTRUCT cwp = (CWPRETSTRUCT) Marshal.PtrToStructure(pLParam, typeof(CWPRETSTRUCT)); if (cwp.message == WM_INITDIALOG) { // A dialog was initialised, find out what sort it was via it's Caption text Int32 iLength = GetWindowTextLength(cwp.hwnd); StringBuilder sb = new StringBuilder(iLength + 1); GetWindowText(cwp.hwnd, sb, sb.Capacity); if (StringConstants.DialogCaptionSecurityAlert.Equals(sb.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // A "Security Alert" dialog was initialised, now need // // a) To know what type it is - e.g. is it an SSL related one or a switching b/w // secure/non-secure modes etc one - and, // // b) A handle to the 'Yes' button so a user-click can be simulated on it // Boolean blnIsSslDialog = true; // assumed true for now IntPtr pYesButtonHwnd = IntPtr.Zero; // Check out further properties of the dialog foreach (IntPtr pChildOfDialog in WindowsInterop.listChildWindows(cwp.hwnd)) { // Go through all of the child controls on the dialog and see what they reveal via their text iLength = GetWindowTextLength(pChildOfDialog); if (iLength > 0) { StringBuilder sbProbe = new StringBuilder(iLength + 1); GetWindowText(pChildOfDialog, sbProbe, sbProbe.Capacity); if (StringConstants.DialogTextSecureToNonSecureWarning.Equals(sbProbe.ToString(), StringComparison.InvariantCultureIgnoreCase) || StringConstants.DialogTextNonSecureToSecureWarning.Equals(sbProbe.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Ok, the text says something about toggling secure/non-secure or vice-versa so, blnIsSslDialog = false; } if (StringConstants.ButtonTextYes.Equals(sbProbe.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Hey, this one says 'Yes', so cache a pointer to it pYesButtonHwnd = pChildOfDialog; // NB: Could also confim it is a button we're pointing at, at this point, and // not a label or something by using the Win32 API's GetClassName() function (see below for e.g.), // but in this case it is already known that a button is the only thing saying 'Yes' // on this particular dialog } } } // Ok, some sort of "Security Alert" dialog was initialised, fire a message // to anyone who's listening i.e. In this case, ask the event receiver if // they want to ignore it if (SecurityAlertDialogWillBeShown != null) { if (SecurityAlertDialogWillBeShown(blnIsSslDialog) && pYesButtonHwnd != IntPtr.Zero) { // Alert the dialog's message-pump that the 'Yes' button was 'Pressed' Int32 ctrlId = GetDlgCtrlID(pYesButtonHwnd); SendMessage(cwp.hwnd, WM_COMMAND, new IntPtr(ctrlId), pYesButtonHwnd); // Block any further processing of the WM_INITDIALOG message by anyone else // This is important: by doing this, the dialog never shows up on the screen return(1); } } } else if (sb.ToString().StartsWith(StringConstants.DialogCaptionConnectTo)) { // 'Connect to ...' style dialog shown IntPtr pComboHwnd = IntPtr.Zero; IntPtr pEditHwnd = IntPtr.Zero; IntPtr pOkButtonHwnd = IntPtr.Zero; foreach (IntPtr pChildOfDialog in WindowsInterop.listChildWindows(cwp.hwnd)) { // Go through all of the child controls on the dialog and see what they reveal via their type/text StringBuilder sbProbe = new StringBuilder(255); if (GetClassName(pChildOfDialog, sbProbe, sbProbe.Capacity) != 0 && !String.IsNullOrEmpty(sbProbe.ToString())) { if (sbProbe.ToString().Equals("SysCredential")) { // This control is actually a set of controls called a "SysCredential" // (as determined via Spy++), so cache it's child controls that are of // type "ComboBoxEx32" and "Edit" foreach (IntPtr pChildOfSysCredential in WindowsInterop.listChildWindows(pChildOfDialog)) { StringBuilder sbProbe2 = new StringBuilder(255); if (GetClassName(pChildOfSysCredential, sbProbe2, sbProbe2.Capacity) != 0 && !String.IsNullOrEmpty(sbProbe2.ToString())) { if (StringConstants.WindowTypeCombo.Equals(sbProbe2.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Hey, here's the Combo pComboHwnd = pChildOfSysCredential; } if (StringConstants.WindowTypeEdit.Equals(sbProbe2.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Hey, here's *an* Edit box. // // This will happen several times as there is an Edit box at the bottom of // the "ComboBoxEx" heirarchy as well, but luckily the last one encountered // is actually the required one pEditHwnd = pChildOfSysCredential; } } } } if (StringConstants.WindowTypeButton.Equals(sbProbe.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // This control is a Button, does it have text, if so what does it say iLength = GetWindowTextLength(pChildOfDialog); if (iLength > 0) { StringBuilder sbText = new StringBuilder(iLength + 1); GetWindowText(pChildOfDialog, sbText, sbText.Capacity); if (StringConstants.ButtonTextOk.Equals(sbText.ToString(), StringComparison.InvariantCultureIgnoreCase)) { // Hey, this one says 'OK', so cache a pointer to it pOkButtonHwnd = pChildOfDialog; } } } } } // Ok, a "Connect to" dialog was initialiased, fire a message to anyone who's interested // i.e. Ask the event receiver if they want to automate the dialog by providing // a username and password with which to populate the dialog if (ConnectToDialogWillBeShown != null) { String sUsername = null; String sPassword = null; if (ConnectToDialogWillBeShown(ref sUsername, ref sPassword) && sUsername != null && sPassword != null && pOkButtonHwnd != IntPtr.Zero && pComboHwnd != IntPtr.Zero && pEditHwnd != IntPtr.Zero) { // Yep, they do // Put the username and password into the boxes SetWindowText(pComboHwnd, sUsername); SetWindowText(pEditHwnd, sPassword); // Alert the dialog's message-pump that the 'OK' button was 'Pressed' Int32 ctrlId = GetDlgCtrlID(pOkButtonHwnd); SendMessage(cwp.hwnd, WM_COMMAND, new IntPtr(ctrlId), pOkButtonHwnd); // Block further processing of the WM_INITDIALOG message by anyone else // This is important: by doing this, the dialog never shows up on the screen return(1); } } } } // Call the next hook in the chain return(CallNextHookEx(WindowsInterop._pWH_CALLWNDPROCRET, iCode, pWParam, pLParam)); }