With the .NET Framework 2.0, Microsoft introduced the WebBrowser control, a managed code wrapper for the WebBrowser ActiveX control. Unfortunately, compared to the ActiveX version, the .NET version of the control lacks some functionality. You can navigate websites, local HTML documents and folder locations using respective protocol handler prefixes (“http://”, “file://”). What you cannot do with the .NET WebBrowser control is navigate special folders like “My Computer” or the control panel, as these folders are not identified by a path but by CSIDLs. So my goal was to extend the existing WebBrowser class to provide this ability.
First of all I did some research on the topic and found a Knowledge Base article describing the necessary steps to navigate a PIDL (pointer to an ITEMIDLIST) with the ActiveX version of the WebBrowser control. So all I had to do was convert the code sample to C#.
Here’s my resulting Navigate2CSIDL method:
public void Navigate2CSIDL(ShellEnums.CSIDLValues csidl) {
const int S_OK = 0;
IntPtr pidl = IntPtr.Zero;
if (SHGetSpecialFolderLocation(IntPtr.Zero, (int)csidl, ref pidl) == S_OK) {
uint cbpidl = LocalSize(pidl);
if (cbpidl > 0) {
byte[] abpidl = new byte[cbpidl];
Marshal.Copy(pidl, abpidl, 0, ((int)cbpidl - 1));
object location = (object)abpidl;
Marshal.FreeCoTaskMem(pidl);
try {
object nil = Type.Missing;
((SHDocVw.WebBrowser)base.ActiveXInstance).Navigate2 (
ref location, ref nil, ref nil, ref nil, ref nil);
}
catch (COMException exception) {
if (exception.ErrorCode != -2147023673
/*Operation was canceled by the user*/) {
throw;
}
}
}
}
else {
throw new ArgumentOutOfRangeException();
}
}
The method takes only one parameter: the CSIDL of the special folder to navigate to. First of all, I use SHGetSpecialFolderLocation() to obtain the PIDL of the desired special folder. Since the Navigate2() method of the ActiveX WebBrowser control takes the PIDL wrapped in a SAFEARRAY, we can copy the PIDL to a byte array. Next we call Navigate2() to navigate the WebBrowser control to the folder. ComInterop handles the marshalling of the byte array to a SAFEARRAY for us. And that’s all we have to do.
To be able to conveniently use this funcionality, I created a new class (“WebBrowserExt”) which inherits from System.Windows.Forms.WebBrowser. As the control consumer might want to interact with the special folder, I added two properties (FolderView and Folder) in analogy to the Document property of the WebBrowser control class:
/// <summary>
/// Returns the shell folder object displayed in the webbrowser control.
/// </summary>
public Shell32.Folder2 Folder {
get {
IShellFolderViewDual2 folderview = this.FolderView;
if (folderview != null) {
return folderview.Folder as Folder2;
}
else {
return null;
}
}
}
/// <summary>
/// Returns the shell folderview object displayed in the webbrowser control.
/// </summary>
public Shell32.IShellFolderViewDual2 FolderView {
get {
return ((SHDocVw.WebBrowser)base.ActiveXInstance).Document
as IShellFolderViewDual2;
}
}
See the documentation of IShellFolderViewDual2 and Folder2 to find out what you can do with these. These interfaces are supplied by adding references to ShDocVw.dll and Shell32.dll to the project. I put together a small sample project to demonstrate the capabilities of my WebBrowserExt control. This is a Visual Studio 2008 project, so you need at least the free Visual C# 2008 Express Edition to open it.
Here’s a screenshot of the sample project showing the control panel:

Download the sample project here. I also posted this on Channel9.