An example about synchronizing the WebBrowser Control's viewport scale, both Zoom and Text Size, to the settings applied by other applications (e.g., Internet Explorer or, as in this case, Help Viewer).
The Problem:
- When Zoom a FontSize scale options are applied by an application that uses the Internet Explorer Engine to render HTML content, the WebBrowser Control, when first initialized, applies these settings to its view.
Expected Behavior:
- The Application should provide means to change Zoom and FontSize scale, independently of what other applications may have set.
- The new settings should be applied without recreating the Control's Handle
In the sample code, a specialized class, WebBrowserHelper
, contains a method that reads from the Registry the current Zoom and FontSize settings, to update the MenuItems to the current value:
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Zoom
=> ZoomFactor Key
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\International\Scripts\3
=> IEFontSize Key
The ZoomFactor
Key stores Zoom levels multiplied by 1000
: e.g., 150%
Zoom has a value of 150000
, 75%
Zoom has a value of 75000
The WebBrowserHelper
's SetZoom()
method uses the WebBrowser ActiveX instance to set the Zoom level, calling its ExecWb method, passing as OLECMDID
argument the OLECMDID_OPTICAL_ZOOM
value, the OLECMDEXECOPT
argument is set to OLECMDEXECOPT_DONTPROMPTUSER
and the pvaIn
argument (the Zoom value) is set to the Integer value of the Zoom level specified.
▶ This also updates the ZoomFactor
Registry Key.
public static void SetZoom(WebBrowser browser, int zoomValue)
{
dynamic activex = browser.ActiveXInstance;
activex.ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, zoomValue, 0);
}
The IEFontSize
and IEFontSizePrivate
Keys store a binary value, in the rage [0-4]
. These values loosely correspond to the x-small
, small
, medium
, large
, x-large
CSS settings.
The FontSize
scale is applied to the Document Body, using a multiplier: [Value + 1] * 4
.
The SetTextScale()
method uses the WebBrowser ActiveX instance to set the FonSize scale, calling its ExecWb()
method, passing as OLECMDID
argument the OLECMDID_ZOOM
value, the OLECMDEXECOPT
argument is set to OLECMDEXECOPT_DONTPROMPTUSER
and the pvaIn
argument (the Font scale value) is set to an Integer value in the range [0, 4]
as specified.
▶ This also updates the IEFontSize
Registry Key.
public static void SetTextScale(WebBrowser browser, int textValue)
{
dynamic activex = browser.ActiveXInstance;
activex.ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, textValue, 0);
}
Another option is to reset both Zoom and FontSize to default values before a WebBrowser session is started.
You can call the WebBrowserHelper.InternetResetZoomAndFont()
method. Setting both arguments to true
, it will reset the Zoom level to 100%
and FontSize to Medium
.
WebBrowserHelper.InternetResetZoomAndFont(true, true);
▶ Here, I'm adding some ToolStripMenuItems that allow to set the Zoom value and FontSize - which is set to a pre-defined scale - as applied by Internet Explorer 11.
- All ToolStripMenuItem that sets the Zoom are grouped in a collection, named
zoomMenuItems
. All use the same Click
event handler, zoomToolStripMenuItems_Click
- All ToolStripMenuItem that sets the FontSize scale are grouped in a collection named
textMenuItems
. All use the same Click
event handler, textToolStripMenuItems_Click
- The Zoom and Fontscale values are set to the
Tag
property of each ToolStripMenuItem (you can of course use any other means to associate a value to a specific ToolStripMenuItem)
- The current values of Zoom and FontSize as stored in a named Value Tuple,
browserViewSettings
Assume the WebBrowser Control is named webBrowser1
:
public partial class SomeForm : Form
{
private List<ToolStripMenuItem> textMenuItems = null;
private List<ToolStripMenuItem> zoomMenuItems = null;
private (int Zoom, int TextSize) browserViewSettings = (100, 2);
public SomeForm()
{
InitializeComponent();
textMenuItems = new List<ToolStripMenuItem> { textSmallestMenuItem, textSmallerMenuItem, textMediumMenuItem, textLargerMenuItem, textLargestMenuItem };
zoomMenuItems = new List<ToolStripMenuItem> { zoom75MenuItem, zoom100MenuItem, zoom125MenuItem, zoom150MenuItem, zoom175MenuItem, zoom200MenuItem, zoom250MenuItem, zoom300MenuItem, zoom400MenuItem };
// On startup, reads the current settings from the Registry
// and updates the MenuItems, to reflect the current values
UpdateMenus(true);
}
// MenuItems that sets the Font scale value
private void textToolStripMenuItems_Click(object sender, EventArgs e)
{
var item = sender as ToolStripMenuItem;
int newTextValue = Convert.ToInt32(item.Tag);
if (newTextValue != browserViewSettings.TextSize) {
browserViewSettings.TextSize = newTextValue;
UpdateDocumentSettings(this.webBrowser1);
UpdateMenus(false);
}
}
// MenuItems that sets the Zoom level value
private void zoomToolStripMenuItems_Click(object sender, EventArgs e)
{
var item = sender as ToolStripMenuItem;
int newZoomValue = Convert.ToInt32(item.Tag);
if (newZoomValue != browserViewSettings.Zoom) {
browserViewSettings.Zoom = newZoomValue;
UpdateDocumentSettings(this.webBrowser1);
UpdateMenus(false);
}
}
// Sets the new selected values and the related MenuItem
private void UpdateDocumentSettings(WebBrowser browser)
{
if (browser == null || browser.Document == null) return;
WebBrowserFeatures.WebBrowserHelper.SetZoom(browser, browserViewSettings.Zoom);
WebBrowserFeatures.WebBrowserHelper.SetTextScale(browser, browserViewSettings.TextSize);
}
// Updates the MenuItem to the current values
private void UpdateMenus(bool refresh)
{
if (refresh) {
browserViewSettings = WebBrowserFeatures.WebBrowserHelper.InternetGetViewScale();
}
zoomMenuItems.ForEach(itm => {
int refValue = Convert.ToInt32(itm.Tag);
itm.Checked = refValue == browserViewSettings.Zoom;
if (itm.Checked) {
zoomToolStripMenuItem.Text = $"Zoom ({refValue}%)";
}
});
textMenuItems.ForEach(itm => itm.Checked = Convert.ToInt32(itm.Tag) == browserViewSettings.TextSize);
}
WebBrowserHelper
class:
using System.Security;
using System.Security.AccessControl;
using Microsoft.Win32;
public class WebBrowserHelper
{
private const int OLECMDID_ZOOM = 19;
private const int OLECMDID_OPTICAL_ZOOM = 63;
private const int OLECMDEXECOPT_DONTPROMPTUSER = 2;
// Applies the Zoom value. It also updates the Registry
public void SetZoom(WebBrowser browser, int zoomValue)
{
dynamic activex = browser.ActiveXInstance;
activex.ExecWB(OLECMDID_OPTICAL_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, zoomValue, 0);
}
// Applies the FontSize scale. It also updates the Registry
public void SetTextScale(WebBrowser browser, int textValue)
{
dynamic activex = browser.ActiveXInstance;
activex.ExecWB(OLECMDID_ZOOM, OLECMDEXECOPT_DONTPROMPTUSER, textValue, 0);
}
private static string keyZoomName = @"Software\Microsoft\Internet Explorer\Zoom";
private static string keyTextName = @"Software\Microsoft\Internet Explorer\International\Scripts\3";
private static string keyValueTextReset = "ResetZoomOnStartup";
private static string keyValueZoomReset = "ResetZoomOnStartup2";
public static (int Zoom, int TextSize) InternetGetViewScale()
{
int zoomValue, textValue;
using (var zoomKey = Registry.CurrentUser.OpenSubKey(keyZoomName,
RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey)) {
zoomValue = (int)zoomKey.GetValue("ZoomFactor", 100000) / 1000;
}
using (var textKey = Registry.CurrentUser.OpenSubKey(keyTextName,
RegistryKeyPermissionCheck.ReadSubTree, RegistryRights.ReadKey)) {
var keyBValue = BitConverter.GetBytes(2);
textValue = BitConverter.ToInt32((byte[])textKey.GetValue("IEFontSize", keyBValue), 0);
}
return (zoomValue, textValue);
}
public static void InternetResetZoomAndFont(bool resetZoom, bool resetFontSize)
{
int keyZoomValue = resetZoom ? 1 : 0;
int keyFontValue = resetFontSize ? 1 : 0;
using (var zoomKey = Registry.CurrentUser.OpenSubKey(keyZoomName,
RegistryKeyPermissionCheck.ReadWriteSubTree,
RegistryRights.WriteKey)) {
zoomKey.SetValue(keyValueZoomReset, keyZoomValue, RegistryValueKind.DWord);
zoomKey.SetValue(keyValueTextReset, keyFontValue, RegistryValueKind.DWord);
}
var current = InternetGetViewScale();
if (resetZoom) current.Zoom = 100;
if (resetFontSize) current.TextSize = 2;
InternetSetViewScale(current.Zoom, current.TextSize);
}
}
This is how it works:
