Windows XP: where to write to registry from IE? - c#

I need to read/write some information in the Windows registry from my BHO. On Windows Vista/7, I create a new key under HKEY_CURRENT_USER\Software\AppDataLow\Software. This works fine, even in protected mode.
However, it does not work on XP. I tried to change the registry to HKEY_CURRENT_USER\Software\Classes\Software or HKEY_CURRENT_USER\Software, no luck.
What is the right registry key to use on Windows XP from a BHO?
IEGetWriteableHKCU does not exist on Windows XP, it was first added in Windows Vista

Before Vista you will have to use a different approach... during installation of the BHO you need to tell Windows/IE which key(s) you want to be writable from the BHO...
There is a whole API family to handle this (supported from WinXP SP2 and up according to MSDN):
IERegisterWritableRegistryKey is used at installation time
IERegisterWritableRegistryValue is used at installation time
IERegCreateKeyEx is used at runtime
IERegSetValueEx is used at runtime

IE 7,8,9,(desktop)10 run tabs in "Protected Mode" which limits registry writes to special "writable" section. You need to ask IE for a pointer to it.
(C#)
// C# PInvoke declaration for needed IE method.
[DllImport("ieframe.dll")]
public static extern int IEGetWriteableHKCU(ref IntPtr phKey);
// ...
// somewhere inside other method:
IntPtr phKey = new IntPtr();
var answer = IEGetWriteableHKCU(ref phKey);
RegistryKey writeable_registry = RegistryKey.FromHandle(
new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true)
);
RegistryKey registryKey = writeable_registry.OpenSubKey(RegistryPathString, true);
if (registryKey == null) {
registryKey = writeable_registry.CreateSubKey(RegistryPathString);
}
registryKey.SetValue("Mode", mode);
writeable_registry.Close();
See:
About Protected Mode:
http://www.codeproject.com/Articles/18866/A-Developer-s-Survival-Guide-to-IE-Protected-Mode
About Enhanced Protected Mode:
http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx

Related

C# WPF - Registry Access not Allowed, even with Administrator Privileges?

I've recently been working on a very nice Registry Editor.
However, certain Registry keys, pointed out below in Regedit, will not show up in my program, as they raise an error of insufficient privileges when opened, and so are caught by error handling and skipped:
Regedit:
My program:
As you can see, the SECURITY key is missing, and the SAM key is not expandable, even though I am running the program with administrator privileges.
This can obviously be fixed by making fake keys and putting them there, and just displaying an empty default value for them, however that isn't a concrete solution, just a way to make it seem to the user as if the issue is solved.
I was wondering if there is a way to fix the issue in a concrete way, or in other words, to receive registry access to those keys?
All they display is an empty default value any way, including the expandable SAM key - it just has a subkey named 'SAM' with an empty default value as well.
However, to the user, it's much better if the program displays exactly as in Regedit, as it means that it's a fully functional piece of software.
Thanks for the help.
Edit (code included):
public static void TreeViewItemExpanded(TreeViewItem sender)
{
if (sender.Items[0] is string)
{
sender.Items.Clear();
RegistryKey expandedKey = (RegistryKey)sender.Tag;
foreach (string key in expandedKey.GetSubKeyNames().OrderBy(x => x)) try { sender.Items.Add(CreateTreeViewItem(expandedKey.OpenSubKey(key))); } catch { }
}
}
private static TreeViewItem CreateTreeViewItem(RegistryKey key)
{
TreeViewItem treeViewItem = new TreeViewItem() { Header = new RegistryEditor_RegistryStructure_TreeView() { Name = Path.GetFileName(key.ToString()) }, Tag = key };
try { if (key.SubKeyCount > 0) treeViewItem.Items.Add("Loading..."); } catch { }
return treeViewItem;
}
You did not supply sample code to your routine, but I have a suspision that you are using a default registry security descriptor.
You can specify a security descriptor for a registry key when you call the RegCreateKeyEx or RegSetKeySecurity function.
When you call the RegOpenKeyEx function, the system checks the requested access rights against the key's security descriptor. If the user does not have the correct access to the registry key, the open operation fails. If an administrator needs access to the key, the solution is to enable the SE_TAKE_OWNERSHIP_NAME privilege and open the registry key with WRITE_OWNER access.
This information is taken from: MSDN:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878(v=vs.85).aspx
In C# You should be using the Registery Permission Class
https://msdn.microsoft.com/en-us/library/system.security.permissions.registrypermission(v=vs.110).aspx
A good example of how to handle Registry Permissions can be found here:
https://msdn.microsoft.com/en-us/library/microsoft.win32.registrykey.setaccesscontrol(v=vs.110).aspx
you need enable SE_RESTORE_PRIVILEGE and SE_BACKUP_PRIVILEGE and use RegOpenKeyEx or ZwOpenKeyEx with REG_OPTION_BACKUP_RESTORE flag (but this will be work only begin from Windows 7 and later versions of Windows)
If this flag is set, the function ignores the samDesired parameter and
attempts to open the key with the access required to backup or restore
the key. If the calling thread has the SE_BACKUP_NAME privilege
enabled, the key is opened with the ACCESS_SYSTEM_SECURITY and
KEY_READ access rights. If the calling thread has the SE_RESTORE_NAME
privilege enabled, beginning with Windows Vista, the key is opened
with the ACCESS_SYSTEM_SECURITY, DELETE and KEY_WRITE access rights.
If both privileges are enabled, the key has the combined access rights
for both privileges.
for example
#define LAA(se) {{se},SE_PRIVILEGE_ENABLED|SE_PRIVILEGE_ENABLED_BY_DEFAULT}
#define BEGIN_PRIVILEGES(tp, n) static const struct {ULONG PrivilegeCount;LUID_AND_ATTRIBUTES Privileges[n];} tp = {n,{
#define END_PRIVILEGES }};
ULONG AdjustBackupRestore()
{
HANDLE hToken;
if (OpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))
{
BEGIN_PRIVILEGES(tp, 2)
LAA(SE_RESTORE_PRIVILEGE),
LAA(SE_BACKUP_PRIVILEGE),
END_PRIVILEGES
AdjustTokenPrivileges(hToken, FALSE, (::PTOKEN_PRIVILEGES)&tp, 0, 0, 0);
ULONG err = GetLastError();
CloseHandle(hToken);
return err;
}
return GetLastError();
}
if (!AdjustBackupRestore())//called once on startup
{
HKEY hKey;
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SECURITY\\SAM", REG_OPTION_BACKUP_RESTORE|REG_OPTION_OPEN_LINK, 0, &hKey))
{
RegCloseKey(hKey);
}
}
however for get full power for registry editor/viewer I be use native api

How to set IE9 by default for web browser?

I am developing an application in C#.NET. I want to use the IE9 version for WebBrowser; either IE9 is installed on system or not.
Is it possible that using IE9 with WebBrower and it may be that IE9 is not installed in my system?
With Windows Internet Explorer 8 or later the FEATURE_BROWSER_EMULATION feature defines the default emulation mode for Internet Explorer. Value 9999 - forces webpages to be displayed in IE9 Standards mode, regardless of the !DOCTYPE directive. You need IE9 or later installed on the target system. Check Internet Feature Controls (B..C)
private static void WebBrowserVersionEmulation()
{
const string BROWSER_EMULATION_KEY =
#"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
//
// app.exe and app.vshost.exe
String appname = Process.GetCurrentProcess().ProcessName + ".exe";
//
// Webpages are displayed in IE9 Standards mode, regardless of the !DOCTYPE directive.
const int browserEmulationMode = 9999;
RegistryKey browserEmulationKey =
Registry.CurrentUser.OpenSubKey(BROWSER_EMULATION_KEY,RegistryKeyPermissionCheck.ReadWriteSubTree) ??
Registry.CurrentUser.CreateSubKey(BROWSER_EMULATION_KEY);
if (browserEmulationKey != null)
{
browserEmulationKey.SetValue(appname, browserEmulationMode, RegistryValueKind.DWord);
browserEmulationKey.Close();
}
}
Insert
"<meta http-equiv=\"X-UA-Compatible\" content=\"IE="\9\" >"
Into your html page,but you have to know Web_browser control dependent on version of IE that already installed on target OS
For this, you have to lookup
What is the version of the underlying browser (registry key may return former installed version). Simplest code I use is asking the WebBrowser control
WebBrowser browser= new WebBrowser
Version ver= browser.Version(); // With ver.Major you can decide the EMULATION
The app-exe-name of your app (differs, while running in vs debug environment to "myapp".vshost.exe). This code I found somewhere:
// This code detects the .vshost. when running in vs ide
[DllImport("kernel32.dll", SetLastError=true)]
private static extern int GetModuleFileName([In]IntPtr hModule,
[Out]StringBuilder lpFilename,
[In][MarshalAs(UnmanagedType.U4)] int nSize);
public static String getAppExeName()
{
StringBuilder appname= new StringBuilder(1024);
GetModuleFileName(IntPtr.Zero, appname, appname.Capacity);
return Path.GetFileName(appname.ToString()); // return filename part
}
Now, you can calculate the Registry-Entry which is necessary for the browser compatibility. The Entry may be in Registry.LocalMachine (access rights required) or Registry.CurrentUser. I check the registry on every program start, so, I first test the existence of the entry
string regSubKey= #"Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION";
string version= "" + ver.Version + "0000"; // installed version x 10000
string appname= getAppExeName();
RegistryKey rs = Registry.CurrentUser.OpenSubKey(regSubKey);
keyval = rs.GetValue(appname);
rs.Close();
if (keyval != null && keyval.ToString().Equals(version))
return; // already done and no browser update installed.
//
// Create key for this app and this version
rs = Registry.LocalMachine.CreateSubKey(regSubKey);
rs.SetValue(app, sversion, RegistryValueKind.DWord);
rs.Flush();
rs.Close();
In 64bit + 32bit modes, may be you have to create an entry in "Software\Wow6432Node" too
After setting the registry key, the WebBrowser control should start with the required emulation
No, the webbrowser-element (I think you mean this) is on base of IE6. You only can start the process of IE9 (don't know the name but for firefox its simply "firefox.exe") form the program.
You can read the version from the registry:
var ieVersion = Registry.LocalMachine.OpenSubKey(#"Software\Microsoft\Internet Explorer").GetValue("Version");
or
If you have a WebBrowser control you can grab it from there:
WebBrowser browser = new WebBrowser();
Version ver = browser.Version;

Where's the wallpaper registry key in Windows 8?

I'm working on a tool that needs to get the current user's wallpaper path.
On Windows 7, I can get that by reading
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Desktop\General\WallpaperSource.
On my Windows 8 installation, that key always has the value
C:\Users\Peter\AppData\Roaming\Microsoft\Windows Photo Viewer\Windows Photo Viewer Wallpaper.jpg
which is not even the wallpaper that's currently set.
Is there any other key I can rely on?
You are FAR better off calling SystemParametersInfo with the SPI_SETDESKWALLPAPER option to set the desktop wallpaper. As far as I can tell, registry key you're using is undocumented and thus can change at any time without warning.
See this stack overflow question for an example of how to call the SystemParametersInfo with SPI_SETDESKWALLPAPER.
Based heavily on the code available at pinvoke.net, the correct way to retrieve the current users desktop wallpaper is to use the SystemParametersInfo function. A sample of doing this is as follows:
using System;
using System.Runtime.InteropServices;
namespace WallpaperPathRetrieval
{
class Program
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern Int32 SystemParametersInfo(UInt32 action,
UInt32 uParam, string vParam, UInt32 winIni);
private static readonly UInt32 SPI_GETDESKWALLPAPER = 0x73;
private static uint MAX_PATH = 260;
static void Main(string[] args)
{
string wallpaper = new string('\0', (int)MAX_PATH);
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0);
wallpaper = wallpaper.Substring(0, wallpaper.IndexOf('\0'));
}
}
}
The key you are mentioning isn't the correct one. Sounds to me that you've placed an image as your desktop background from Internet Explorer, and that key was opened to register it.
The correct key to get the desktop background location is: Confirmed on: XP, CE, Vista, 7, 8
HKEY_CURRENT_USER\Control Panel\Desktop\Wallpaper
Details:
Main key: HKEY_CURRENT_USER
Sub key: Control Panel\Desktop
Value name: WallPaper
Value type: REG_SZ
Value data: full path for the image being used as the desktop background
Also, under HKEY_CURRENT_USER\Control Panel\Desktop\ you will find other wallpaper related options to apply different styles: Center, Tile, and Stretch.
HKEY_CURRENT_USER\Control Panel\Desktop\WallpaperStyle
HKEY_CURRENT_USER\Control Panel\Desktop\TileWallpaper
In order to apply the styles use the following guide:
Center
WallpaperStyle = 0
TileWallpaper = 0
Tile
WallpaperStyle = 0
TileWallpaper = 1
Stretch
WallpaperStyle = 2
TileWallpaper = 0
It's stored in a value named TranscodedImageCache (REG_BINARY). Here is a VBScript that reads/converts to plain text and outputs the value.
How to Determine the Current Wallpaper File Name and Path in Windows 8 - The Winhelponline Blog

Webbrowser control ignores FEATURE_BROWSER_EMULATION reg entry

Im developing a custom browser solution with .net's Webbrowser control.
To disable the IE-Compatibilty View, I set the registry entry
Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION:
[Sreenshot regedit] http://zbirk.mirk.at/browserreg.png "Screenshot"
i tried to use the values: dword=8000,dword=8888,dword=9000, but the webbrowser control seems to ignore these reg entries.
Maybe someone had this problems too and may help me.
The WebBrowser control definately DOES respect these keys.
Remember that while taskman may show application.exe in the name column, if you are debugging the exe name is application.vshost.exe
So in my application sI just attempt to create the key every time the app runs. If it fails to create it (because it already exists) then I continue running, if it creates the key then I inform the user that they need to restart the application.
ensure that you are not running within vshost
the app name would be different ie appname.vshost.exe
Thx for your reply, now its working.
Her is my working peace of code:
public void setIEcomp()
{
String appname = Process.GetCurrentProcess().ProcessName+".exe";
RegistryKey RK8 = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION",RegistryKeyPermissionCheck.ReadWriteSubTree);
int value9 = 9999;
int value8 = 8888;
Version ver = webBrowser1.Version;
int value = value9;
try
{
string[] parts = ver.ToString().Split('.');
int vn = 0;
int.TryParse(parts[0], out vn);
if (vn != 0)
{
if (vn == 9)
value = value9;
else
value = value8;
}
}
catch
{
value = value9;
}
//Setting the key in LocalMachine
if (RK8 != null)
{
try
{
RK8.SetValue(appname, value, RegistryValueKind.DWord);
RK8.Close();
}
catch(Exception ex)
{
//MessageBox.Show(ex.Message);
}
}
}
I too could not see that FEATURE_BROWSER_EMULATION made any difference in my application.
I was testing the FEATURE_BROWSER_EMULATION functionality by manually editing the registry with regedit. Nothing I did made any difference. My hosted page was still failing on any new-ish JavaScript and could not load external libraries.
I found my mistake:
I was editing the 64-bit view of the registry with regedit. My app was running as a 32-bit app and looking at the 32-bit view of the registry. That's why my changes to the registry seemed to have no impact on my application. By the way, the WPF project template defaults to "Prefer 32-bit."
Manually editing with regedit within the Wow6432Node key worked:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\MAIN\FeatureControl\FEATURE_BROWSER_EMULATION
Of course, setting the DWORD value programmatically within your application will also work, since your 32-bit application will edit within the Wow6432Node.
An older post and solution is no longer accurate.
Running procmon and watching for FEATURE_BROWSER_EMULATION shows the following registry variables actually checked. This was for WINWORD.exe but other than that - take your pick...
HKU\S-1-5-21-[my-sid-paws-off]\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\WINWORD.EXE
HKU\S-1-5-21-[my-sid-paws-off]\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION*
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION(Default)
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\WINWORD.EXE
HKLM\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION\WINWORD.EXE
HKLM\SOFTWARE\Microsoft\Office\ClickToRun\REGISTRY\MACHINE\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION*
HKLM\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION*

How to get started with developing Internet Explorer extensions?

Does anyone here have experience with/in developing IE extensions that can share their knowledge? This would include code samples, or links to good ones, or documentation on the process, or anything.
I really want to do this, but I'm hitting a giant wall with lousy documentation, lousy code/example code/lack thereof. Any help/resources you could offer would be greatly appreciated.
Specifically, I would like to start with how to get access to/manipulate the DOM from within a IE extension.
EDIT, even more details:
Ideally, I would like to plant a toolbar button that, when clicked, popped a menu up that contains links to external sites. I would also like to access the DOM and plant JavaScript on the page depending on some conditions.
What is the best way to persist information in an IE extension? In Firefox/Chrome/Most modern browsers, you use window.localStorage, but obviously with IE8/IE7, that's not an option. Maybe a SQLite DB or such? It is okay to assume that .NET 4.0 will be installed on a user's computer?
I don't want to use Spice IE as I want to build one that is compatible with IE9 as well. I've added the C++ tag to this question as well, because if it's better to build one in C++, I can do that.
[UPDATE] I'm updating this answer to work with Internet Explorer 11, in Windows 10 x64 with Visual Studio 2017 Community.
The previous version of this answer (for Internet Explorer 8, in Windows 7 x64 and Visual Studio 2010) is at the bottom of this answer.
Creating a Working Internet Explorer 11 Add-on
I am using Visual Studio 2017 Community, C#, .Net Framework 4.6.1, so some of these steps might be slightly different for you.
You need to open Visual Studio as Administrator to build the solution, so that the post-build script can register the BHO (needs registry access).
Start by creating a class library.
I called mine InternetExplorerExtension.
Add these references to the project:
Interop.SHDocVw: COM tab / search for "Microsoft Internet Controls"
Microsoft.mshtml: Assemblies tab / search for "Microsoft.mshtml"
Note: Somehow MSHTML was not registered in my system, even though I could find in in the Add Reference window. This caused an error while building:
Cannot find wrapper assembly for type library "MSHTML"
The fix can be found at http://techninotes.blogspot.com/2016/08/fixing-cannot-find-wrapper-assembly-for.html
Or, you can run this batch script:
"%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\Tools\VsDevCmd.bat"
cd "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\Common7\IDE\PublicAssemblies"
regasm Microsoft.mshtml.dll
gacutil /i Microsoft.mshtml.dll
Create the following files:
IEAddon.cs
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Microsoft.Win32;
using mshtml;
using SHDocVw;
namespace InternetExplorerExtension
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("D40C654D-7C51-4EB3-95B2-1E23905C2A2D")]
[ProgId("MyBHO.WordHighlighter")]
public class WordHighlighterBHO : IObjectWithSite, IOleCommandTarget
{
const string DefaultTextToHighlight = "browser";
IWebBrowser2 browser;
private object site;
#region Highlight Text
void OnDocumentComplete(object pDisp, ref object URL)
{
try
{
// #Eric Stob: Thanks for this hint!
// This was used to prevent this method being executed more than once in IE8... but now it seems to not work anymore.
//if (pDisp != this.site)
// return;
var document2 = browser.Document as IHTMLDocument2;
var document3 = browser.Document as IHTMLDocument3;
var window = document2.parentWindow;
window.execScript(#"function FncAddedByAddon() { alert('Message added by addon.'); }");
Queue<IHTMLDOMNode> queue = new Queue<IHTMLDOMNode>();
foreach (IHTMLDOMNode eachChild in document3.childNodes)
queue.Enqueue(eachChild);
while (queue.Count > 0)
{
// replacing desired text with a highlighted version of it
var domNode = queue.Dequeue();
var textNode = domNode as IHTMLDOMTextNode;
if (textNode != null)
{
if (textNode.data.Contains(TextToHighlight))
{
var newText = textNode.data.Replace(TextToHighlight, "<span style='background-color: yellow; cursor: hand;' onclick='javascript:FncAddedByAddon()' title='Click to open script based alert window.'>" + TextToHighlight + "</span>");
var newNode = document2.createElement("span");
newNode.innerHTML = newText;
domNode.replaceNode((IHTMLDOMNode)newNode);
}
}
else
{
// adding children to collection
var x = (IHTMLDOMChildrenCollection)(domNode.childNodes);
foreach (IHTMLDOMNode eachChild in x)
{
if (eachChild is mshtml.IHTMLScriptElement)
continue;
if (eachChild is mshtml.IHTMLStyleElement)
continue;
queue.Enqueue(eachChild);
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
#endregion
#region Load and Save Data
static string TextToHighlight = DefaultTextToHighlight;
public static string RegData = "Software\\MyIEExtension";
[DllImport("ieframe.dll")]
public static extern int IEGetWriteableHKCU(ref IntPtr phKey);
private static void SaveOptions()
{
// In IE 7,8,9,(desktop)10 tabs run in Protected Mode
// which prohibits writes to HKLM, HKCU.
// Must ask IE for "Writable" registry section pointer
// which will be something like HKU/S-1-7***/Software/AppDataLow/
// In "metro" IE 10 mode, tabs run in "Enhanced Protected Mode"
// where BHOs are not allowed to run, except in edge cases.
// see http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx
IntPtr phKey = new IntPtr();
var answer = IEGetWriteableHKCU(ref phKey);
RegistryKey writeable_registry = RegistryKey.FromHandle(
new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true)
);
RegistryKey registryKey = writeable_registry.OpenSubKey(RegData, true);
if (registryKey == null)
registryKey = writeable_registry.CreateSubKey(RegData);
registryKey.SetValue("Data", TextToHighlight);
writeable_registry.Close();
}
private static void LoadOptions()
{
// In IE 7,8,9,(desktop)10 tabs run in Protected Mode
// which prohibits writes to HKLM, HKCU.
// Must ask IE for "Writable" registry section pointer
// which will be something like HKU/S-1-7***/Software/AppDataLow/
// In "metro" IE 10 mode, tabs run in "Enhanced Protected Mode"
// where BHOs are not allowed to run, except in edge cases.
// see http://blogs.msdn.com/b/ieinternals/archive/2012/03/23/understanding-ie10-enhanced-protected-mode-network-security-addons-cookies-metro-desktop.aspx
IntPtr phKey = new IntPtr();
var answer = IEGetWriteableHKCU(ref phKey);
RegistryKey writeable_registry = RegistryKey.FromHandle(
new Microsoft.Win32.SafeHandles.SafeRegistryHandle(phKey, true)
);
RegistryKey registryKey = writeable_registry.OpenSubKey(RegData, true);
if (registryKey == null)
registryKey = writeable_registry.CreateSubKey(RegData);
registryKey.SetValue("Data", TextToHighlight);
if (registryKey == null)
{
TextToHighlight = DefaultTextToHighlight;
}
else
{
TextToHighlight = (string)registryKey.GetValue("Data");
}
writeable_registry.Close();
}
#endregion
[Guid("6D5140C1-7436-11CE-8034-00AA006009FA")]
[InterfaceType(1)]
public interface IServiceProvider
{
int QueryService(ref Guid guidService, ref Guid riid, out IntPtr ppvObject);
}
#region Implementation of IObjectWithSite
int IObjectWithSite.SetSite(object site)
{
this.site = site;
if (site != null)
{
LoadOptions();
var serviceProv = (IServiceProvider)this.site;
var guidIWebBrowserApp = Marshal.GenerateGuidForType(typeof(IWebBrowserApp)); // new Guid("0002DF05-0000-0000-C000-000000000046");
var guidIWebBrowser2 = Marshal.GenerateGuidForType(typeof(IWebBrowser2)); // new Guid("D30C1661-CDAF-11D0-8A3E-00C04FC9E26E");
IntPtr intPtr;
serviceProv.QueryService(ref guidIWebBrowserApp, ref guidIWebBrowser2, out intPtr);
browser = (IWebBrowser2)Marshal.GetObjectForIUnknown(intPtr);
((DWebBrowserEvents2_Event)browser).DocumentComplete +=
new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
}
else
{
((DWebBrowserEvents2_Event)browser).DocumentComplete -=
new DWebBrowserEvents2_DocumentCompleteEventHandler(this.OnDocumentComplete);
browser = null;
}
return 0;
}
int IObjectWithSite.GetSite(ref Guid guid, out IntPtr ppvSite)
{
IntPtr punk = Marshal.GetIUnknownForObject(browser);
int hr = Marshal.QueryInterface(punk, ref guid, out ppvSite);
Marshal.Release(punk);
return hr;
}
#endregion
#region Implementation of IOleCommandTarget
int IOleCommandTarget.QueryStatus(IntPtr pguidCmdGroup, uint cCmds, ref OLECMD prgCmds, IntPtr pCmdText)
{
return 0;
}
int IOleCommandTarget.Exec(IntPtr pguidCmdGroup, uint nCmdID, uint nCmdexecopt, IntPtr pvaIn, IntPtr pvaOut)
{
try
{
// Accessing the document from the command-bar.
var document = browser.Document as IHTMLDocument2;
var window = document.parentWindow;
var result = window.execScript(#"alert('You will now be allowed to configure the text to highlight...');");
var form = new HighlighterOptionsForm();
form.InputText = TextToHighlight;
if (form.ShowDialog() != DialogResult.Cancel)
{
TextToHighlight = form.InputText;
SaveOptions();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return 0;
}
#endregion
#region Registering with regasm
public static string RegBHO = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects";
public static string RegCmd = "Software\\Microsoft\\Internet Explorer\\Extensions";
[ComRegisterFunction]
public static void RegisterBHO(Type type)
{
string guid = type.GUID.ToString("B");
// BHO
{
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegBHO, true);
if (registryKey == null)
registryKey = Registry.LocalMachine.CreateSubKey(RegBHO);
RegistryKey key = registryKey.OpenSubKey(guid);
if (key == null)
key = registryKey.CreateSubKey(guid);
key.SetValue("Alright", 1);
registryKey.Close();
key.Close();
}
// Command
{
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegCmd, true);
if (registryKey == null)
registryKey = Registry.LocalMachine.CreateSubKey(RegCmd);
RegistryKey key = registryKey.OpenSubKey(guid);
if (key == null)
key = registryKey.CreateSubKey(guid);
key.SetValue("ButtonText", "Highlighter options");
key.SetValue("CLSID", "{1FBA04EE-3024-11d2-8F1F-0000F87ABD16}");
key.SetValue("ClsidExtension", guid);
key.SetValue("Icon", "");
key.SetValue("HotIcon", "");
key.SetValue("Default Visible", "Yes");
key.SetValue("MenuText", "&Highlighter options");
key.SetValue("ToolTip", "Highlighter options");
//key.SetValue("KeyPath", "no");
registryKey.Close();
key.Close();
}
}
[ComUnregisterFunction]
public static void UnregisterBHO(Type type)
{
string guid = type.GUID.ToString("B");
// BHO
{
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegBHO, true);
if (registryKey != null)
registryKey.DeleteSubKey(guid, false);
}
// Command
{
RegistryKey registryKey = Registry.LocalMachine.OpenSubKey(RegCmd, true);
if (registryKey != null)
registryKey.DeleteSubKey(guid, false);
}
}
#endregion
}
}
Interop.cs
using System;
using System.Runtime.InteropServices;
namespace InternetExplorerExtension
{
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("FC4801A3-2BA9-11CF-A229-00AA003D7352")]
public interface IObjectWithSite
{
[PreserveSig]
int SetSite([MarshalAs(UnmanagedType.IUnknown)]object site);
[PreserveSig]
int GetSite(ref Guid guid, [MarshalAs(UnmanagedType.IUnknown)]out IntPtr ppvSite);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct OLECMDTEXT
{
public uint cmdtextf;
public uint cwActual;
public uint cwBuf;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 100)]
public char rgwz;
}
[StructLayout(LayoutKind.Sequential)]
public struct OLECMD
{
public uint cmdID;
public uint cmdf;
}
[ComImport(), ComVisible(true),
Guid("B722BCCB-4E68-101B-A2BC-00AA00404770"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleCommandTarget
{
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int QueryStatus(
[In] IntPtr pguidCmdGroup,
[In, MarshalAs(UnmanagedType.U4)] uint cCmds,
[In, Out, MarshalAs(UnmanagedType.Struct)] ref OLECMD prgCmds,
//This parameter must be IntPtr, as it can be null
[In, Out] IntPtr pCmdText);
[return: MarshalAs(UnmanagedType.I4)]
[PreserveSig]
int Exec(
//[In] ref Guid pguidCmdGroup,
//have to be IntPtr, since null values are unacceptable
//and null is used as default group!
[In] IntPtr pguidCmdGroup,
[In, MarshalAs(UnmanagedType.U4)] uint nCmdID,
[In, MarshalAs(UnmanagedType.U4)] uint nCmdexecopt,
[In] IntPtr pvaIn,
[In, Out] IntPtr pvaOut);
}
}
and finally a form, that we will use to configure the options. In this form place a TextBox and an Ok Button. Set the DialogResult of the button to Ok. Place this code in the form code:
using System.Windows.Forms;
namespace InternetExplorerExtension
{
public partial class HighlighterOptionsForm : Form
{
public HighlighterOptionsForm()
{
InitializeComponent();
}
public string InputText
{
get { return this.textBox1.Text; }
set { this.textBox1.Text = value; }
}
}
}
In the project properties, do the following:
Sign the assembly with a strong-key;
In the Debug tab, set Start External Program to C:\Program Files (x86)\Internet Explorer\iexplore.exe
In the Debug tab, set Command Line Arguments to http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
In the Build Events tab, set Post-build events command line to:
"%ProgramFiles(x86)%\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
"%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
"%windir%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
Attention: even though my computer is x64, I used the path of the non-x64 gacutil.exe and it worked... the one specific for x64 is at:
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\x64\gacutil.exe
64bit IE Needs 64bit-compiled and 64bit-registered BHO. Though I could only debug using 32bit IE11, the 32bit registered extension also worked by running 64bit IE11.
This answer appears to have some additional info about this: https://stackoverflow.com/a/23004613/195417
If you need to, you can use the 64bit regasm:
%windir%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe
How this add-on works
I didn't change the behavior of the add-on... take a look at IE8 section bellow for description.
## Previous Answer for IE8
Man... this has been a lot of work!
I was so curious about how to do this, that I did it myself.
First of all... credit is not all mine. This is a compilation of what I found, on these sites:
CodeProject article, how to make a BHO;
15seconds, but it was not 15 seconds, it took about 7 hours;
Microsoft tutorial, helped me adding the command button.
And this social.msdn topic, that helped me figure out that the assembly must be in the GAC.
This MSDN blog post contains a fully-working example
many other sites, in the discovery process...
And of course, I wanted my answer to have the features you asked:
DOM traversal to find something;
a button that shows a window (in my case to setup)
persist the configuration (I will use registry for that)
and finally execute javascript.
I will describe it step by step, how I managed to do it working with Internet Explorer 8, in Windows 7 x64... note that I could not test in other configurations. Hope you understand =)
Creating a Working Internet Explorer 8 Add-on
I am using Visual Studio 2010, C# 4, .Net Framework 4, so some of these steps might be slightly different for you.
Created a class library. I called mine InternetExplorerExtension.
Add these references to the project:
Interop.SHDocVw
Microsoft.mshtml
Note: These references may be in different places in each computer.
this is what my references section in csproj contains:
<Reference Include="Interop.SHDocVw, Version=1.1.0.0, Culture=neutral, PublicKeyToken=90ba9c70f846762e, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<EmbedInteropTypes>True</EmbedInteropTypes>
<HintPath>C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\Interop.SHDocVw.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.mshtml, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<EmbedInteropTypes>True</EmbedInteropTypes>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
Create the files the same way as the updated IE11 files.
IEAddon.cs
You can uncomment the following lines from IE11 version:
...
// #Eric Stob: Thanks for this hint!
// This was used to prevent this method being executed more than once in IE8... but now it seems to not work anymore.
if (pDisp != this.site)
return;
...
Interop.cs
Same as IE11 version.
and finally a form, that we will use to configure the options. In this form place a TextBox and an Ok Button. Set the DialogResult of the button to Ok. The code is the same for IE11 addon.
In the project properties, do the following:
Sign the assembly with a strong-key;
In the Debug tab, set Start External Program to C:\Program Files (x86)\Internet Explorer\iexplore.exe
In the Debug tab, set Command Line Arguments to http://msdn.microsoft.com/en-us/library/ms976373.aspx#bho_getintouch
In the Build Events tab, set Post-build events command line to:
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /f /i "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /unregister "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
Attention: as my computer is x64, there is a specific x64 inside the path of gacutil executable on my machine that may be different on yours.
64bit IE Needs 64bit-compiled and 64bit-registered BHO. Use 64bit RegAsm.exe (usually lives in C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe)
How this add-on works
It traverses all DOM tree, replacing the text, configured using the button, by itself with a yellow background. If you click on the yellowed texts, it calls a javascript function that was inserted on the page dynamically. The default word is 'browser', so that it matches a lot of them!
EDIT: after changing the string to be highlighted, you must click the URL box and press Enter... F5 will not work, I think that it is because F5 is considered as 'navigation', and it would require to listen to navigate event (maybe). I'll try to fix that later.
Now, it is time to go. I am very tired.
Feel free to ask questions... may be I will not be able to answer since I am going on a trip... in 3 days I'm back, but I'll try to come here in the meantime.
The state for IE extensions is actually pretty sad. You have the old model of IE5 Browser Helper Object (yeah, those infamous BHOs that everyone liked to block back in the day), toolbars and the new accelerators for IE.
Even then, compatibility will break sometimes. I used to maintain an extension for IE6 that broke with IE7, so there are some things that have changed. For the most part, as far as I know (I haven't touch BHOs in years) you still need to code them using Active Template Libraries (kind of like an STL for Microsoft's COM) and well as such is only for C++.
You could do COM Interop with C# and get away with doing it in C# but its probably going to be too hard for what it is worth.
Anyway, if you are interested in coding your own extension for IE (which is plausible if you want to have your extensions available in all major browsers) here are the official Microsoft Resources.
http://msdn.microsoft.com/en-us/library/aa753587(v=vs.85).aspx
And for the accelerators that are new in IE8 you could check this one.
http://msdn.microsoft.com/en-us/library/cc289775(v=vs.85).aspx
I agree the documentation is terrible, and the APIs are quite outdated. Still I hope this helps.
EDIT: I guess I can throw one last source of information here. I was looking through my notes of back when I was working on BHOs. And this is the article that got me started with them. It is kind of old, but has a good explanation of the ATL interfaces that you will be using when working with IE BHOs (IObjectWithSite for example). I think it is pretty well explained and helped me a lot back then.
http://msdn.microsoft.com/en-us/library/bb250436.aspx
I also checked the example that GregC posted. It does work with at least IE8, and it is compatible with VS 2010, so if you want to do C# you can get started there and take a look at Jon Skeet's Book. (C# in Depth 2nd edition) Chapter 13 has a good deal of information about the new features in C# 4 that you can use to make the interaction with COM nicer. (I would still recommend you doing your addin in C++)
Another cool approach would be to check out:
http://www.crossrider.org
It's a framework based on JS with jquery which lets you develop browsers extensions for IE, FF and Chrome using a single common JS code.
Basically the framework does all the nasty work and you're left with writing your applications code.
Developing C# BHOs is a pain-in-the-arse. It involves a lot of icky COM code and p/invoke calls.
I have a mostly finished C# BHO here, which you are free to use the source for whatever you want. I say "mostly", because I never did figure out how to save appdata under IE Protected Mode.
I've been working with IE's webbrowser control for years now, and over the course of them, one name comes up over and over again with helpful postings: Igor Tandetnik
If I were developing an extension, I would target a BHO, and start googling for:
BHO Igor Tandetnik
OR
Browser Helper Object Igor Tandetnik
His postings are often very detailed, and he knows what he is talking about.
You're going to find yourself up to your ears in COM and ATL programming.
For a sample walkthrough, check out:
http://msdn.microsoft.com/en-us/library/ms976373.aspx
I agree with Robert Harvey, C# 4.0 features improved COM interop. Here's a bit of older C# code, in desperate need of a re-write.
http://www.codeproject.com/KB/cs/Attach_BHO_with_C_.aspx
This is an attempt to simplify things by avoiding ATL and going with Spartan COM:
C++ and COM to get BHOs going
If you are not trying to reinvent the wheel, you might try Add In Express for IE . I have used the product for the VSTO stuff, and its pretty good. Also they have a helpful forum and quick support.
It is obviously solved, but for the other users, I would recommend SpicIE framework. I have made my own extension based on it. It only supports Internet Explorer 7/8 officialy, but I tested that on Internet Explorer 6-10 (from Windows XP to Windows 8 Consumer Preview) and it works fine.
Unfortunately there were some bugs in the latest release, so I had to fix them and made my own release:
http://archive.msdn.microsoft.com/SpicIE/Thread/View.aspx?ThreadId=5251
I warmly suggest you this post of Pavel Zolnikov published in 2002!
http://www.codeproject.com/Articles/2219/Extending-Explorer-with-Band-Objects-using-NET-and
It is based on the use of Band objects and is compiled using .Net 2.0.
Source code is provided and opens and compiles well with Visual Studio 2013.
As you will read on the post comments it works perfectly well for IE 11 and on Windows 7 and Windows 10.
It worked perfectly well for me on Windows 7 + SP1 and IE 11
Enjoy!
The question is from 2013, now it's 2020, but it may be helpful for future visitors.
I tried to implement #Miguel Angelo's answer, it didn't worked at the beginning.
There still some settings that you be defined.
on internet explorer (I'm using IE-11) go to Tools-->Internet Options-->Advanced:
Also see this SO question and this example from github
In the Build Events tab, set Post-build events command line to: (x64) is listed below
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\NETFX 4.0 Tools\x64\gacutil.exe" /if "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" /u "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"
I want the Build Events tab , set Post-build events command line to (32 bit operating system)
"C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\gacutil.exe" /if "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" /u "$(TargetDir)$(TargetFileName)"
"C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe" "$(TargetDir)$(TargetFileName)"

Categories

Resources