There may be times that a website will report back that your browser version is out of date even-though you have the most current version of Internet Explorer installed. This issue can be observed by navigating your browser application to the site: http://www.detectmybrowser.com/
How can that be? I have IE11 installed after all.
Some will tell you that it because the control is based on IE6, IE7 or some other out of date browser. This is patently wrong. The .Net WebBrowser (WB) control uses the installed version of Internet Explorer to display its content. The issue is that Microsoft decided that control should default to using the rendering standards of Internet Explorer 7 and this has been the case to date. Webpages can override this behavior by including certain directives to specify which rendering engine to use, but not all do. You can instruct the WB to use a particular rendering version for your application by creating a specific Key in the registry. This registry key must exist before you create an instance of the WB control (more on this later) for it to take effect.
This registry entry can either be created in the "HKEY_LOCAL_MACHINE" (HKLM) hive or in the "HKEY_CURRENT_USER" (HKCU) hive. Using the HKLM hive presents a few issues, the biggest one being that you will need Administrator Privileges to set it and the second one comes into play on 64-bit version of Windows; you have both a 32-bit hive and 64-bit hive to select from. For these reasons, I have chosen to use the current user hive in the code presented below. This particular key is:
There are two choices for this value for each Internet Explorer version since IE7. The details on these values can be found at: Internet Feature Controls (B..C).\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
The name of the entry under FEATURE_BROWSER_EMULATION must match your program's name. This becomes a headache during development as your application may be called "WindowsApplication1.exe", but when running under the debugger it is named "WindowsApplication1.vshost.exe". This makes creating the registry keys manually a bit of a pain.
I chose to write this code to use the VB.Net My Namespace to take advantage of the Startup and Shutdown events available to the My.Application object. As I mentioned earlier, the registry key must be set before an instance of the WB control is created and the Startup event is a great way to ensure that happens, but you do not need to use these events if you do not want to. You could create the key in shared constructor of the form that the WB control is on.
I know, quit blah-blahing and show me the code!
VB.Net Code:
Namespace My Partial Friend Class MyApplication ''' <summary> ''' This method is subscribed to the Application.Startup event. This event fires before the ''' main WinForm application begins. For any changes to Internet Explorer's registry settings ''' to be applied to the application, they must be set before the first instance of the browser is created. '''</summary> Private Sub _Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup If My.BrowserSetup.DocTypeDirectiveIsAvailable Then My.BrowserSetup.CreateBrowserKey() End If End Sub Private Sub _Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown If My.BrowserSetup.DocTypeDirectiveIsAvailable Then My.BrowserSetup.RemoveBrowserKey() End If End Sub End Class 'MyApplication End Namespace Namespace My Partial Friend Class BrowserSetup Public Shared BrowserMajorVersion As Byte Public Shared BrowserDirectiveVersion As Byte Public Shared ReadOnly DocTypeDirectiveIsAvailable As Boolean Public Shared ReadOnly honorDocTypeDirective As Int32 Public Shared ReadOnly ignoreDocTypeDirective As Int32 Private Shared Directives As New SortedDictionary(Of Byte, BrowserVersionDirective) Shared Sub New() BrowserMajorVersion = Version() SetDirectives() DocTypeDirectiveIsAvailable = Directives.ContainsKey(BrowserMajorVersion) If DocTypeDirectiveIsAvailable Then BrowserDirectiveVersion = BrowserMajorVersion honorDocTypeDirective = Directives.Item(BrowserMajorVersion).honorDocTypeDirective ignoreDocTypeDirective = Directives.Item(BrowserMajorVersion).ignoreDocTypeDirective Else ' use highest version directives available that For i As Int32 = Directives.Count - 1 To 0 Step -1 If Directives.Keys(i) < BrowserMajorVersion Then DocTypeDirectiveIsAvailable = True BrowserDirectiveVersion = Directives.Keys(i) Dim directive As BrowserVersionDirective = Directives.Values(i) honorDocTypeDirective = directive.honorDocTypeDirective ignoreDocTypeDirective = directive.ignoreDocTypeDirective Exit For End If Next End If Directives = Nothing End Sub Private Shared Function Version() As Byte Dim wb As New WebBrowser Dim majorVersion As Int32 = wb.Version.Major wb.Dispose() Return CByte(majorVersion) End Function ''' <summary>Sets Values for IE version 8 thru 11</summary> Private Shared Sub SetDirectives() ' Value reference: [url]http://msdn.microsoft.com/en-us/library/ee330730%28v=VS.85%29.aspx[/url] ' !DOCType Reference: [url]http://msdn.microsoft.com/en-us/library/ms535242%28v=vs.85%29.aspx[/url] With Directives .Add(7, New BrowserVersionDirective(7000, 7777)) .Add(8, New BrowserVersionDirective(8000, 8888)) .Add(9, New BrowserVersionDirective(9000, 9999)) .Add(10, New BrowserVersionDirective(10000, 10001)) .Add(11, New BrowserVersionDirective(11000, 11001)) End With End Sub Private Class BrowserVersionDirective Public honorDocTypeDirective As Int16 Public ignoreDocTypeDirective As Int16 Public Sub New(ByVal honorDocTypeDirective As Int16, ByVal ignoreDocTypeDirective As Int16) Me.honorDocTypeDirective = honorDocTypeDirective Me.ignoreDocTypeDirective = ignoreDocTypeDirective End Sub End Class #Region "Registry" Private Const BrowserKeyPath As String = "\SOFTWARE\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION" Friend Shared Sub CreateBrowserKey(Optional ByVal IgnoreDocTypeDirective As Boolean = False) Dim basekey As String = Microsoft.Win32.Registry.CurrentUser.ToString Dim value As Int32 Dim thisAppsName As String = My.Application.Info.AssemblyName & ".exe" If IgnoreDocTypeDirective Then value = My.BrowserSetup.ignoreDocTypeDirective Else value = My.BrowserSetup.honorDocTypeDirective End If Microsoft.Win32.Registry.SetValue(Microsoft.Win32.Registry.CurrentUser.ToString & BrowserKeyPath, _ Process.GetCurrentProcess.ProcessName & ".exe", _ value, _ Microsoft.Win32.RegistryValueKind.DWord) End Sub ' CreateBrowserKey Friend Shared Sub RemoveBrowserKey() Dim key As Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(BrowserKeyPath.Substring(1), True) key.DeleteValue(Process.GetCurrentProcess.ProcessName & ".exe", False) End Sub ' RemoveBrowerKey #End Region End Class ' BrowserSetup End Namespace 'My
That is it. Just copy and paste it to a WinForm project and you are good to go. To facilitate the insertion of this code to your project, I have created two "Item Templates" that you can add to your user templates folder. Then you can just add the code from the Project Menu->Insert New Item.
The first will insert the above code.
WebBrowser DocDirective AutoRegistry.zip
The second is one just includes the BrowserSetup class, if you do not want to have the registry key automatically created/deleted.
WebBrowser DocDirective.zip
Do not UnZip these template files; just place the Zip file to your templates folder. Templates are Zip files.
You can find your user templates folder from Tools Menu->Options->Projects and Solutions
For more information see: How to: Locate and Organize Project and Item Templates
If you choose not to have the registry key automatically created/deleted using the Application events, you can do something like the following in your start-up form.
VB.Net Code:
Public Class Form1 Shared Sub New() My.BrowserSetup.CreateBrowserKey() End Sub Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load My.BrowserSetup.RemoveBrowserKey() End Sub End Class
When I wrote my first version of this code a few years ago, I used a Select-Case block to select the proper code to write to the registry. This time I implemented it as a subroutine that loads a dictionary instance.
This version still suffers the problem that when new versions of Internet Explorer are released this code becomes out of date. However, the subroutine "SetDirectives" can be easily replaced with code that would load the dictionary from a setup file and thereby eliminating the need to recompile the application for each new version of Internet Explorer released. I also have it added logic to select the highest version emulation that it has values for even if it is not the most up to date one available.Code:''' <summary>Sets Values for IE version 8 thru 11</summary> Private Shared Sub SetDirectives() ' Value reference: http://msdn.microsoft.com/en-us/library/ee330730%28v=VS.85%29.aspx ' !DOCType Reference: http://msdn.microsoft.com/en-us/library/ms535242%28v=vs.85%29.aspx With Directives .Add(7, New BrowserVersionDirective(7000, 7777)) .Add(8, New BrowserVersionDirective(8000, 8888)) .Add(9, New BrowserVersionDirective(9000, 9999)) .Add(10, New BrowserVersionDirective(10000, 10001)) .Add(11, New BrowserVersionDirective(11000, 11001)) End With End Sub




Reply With Quote
