Share via


This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.

MIND

 

More Windows 2000 UI Goodies: Extending Explorer Views by Customizing Hypertext Template Files

Dino Esposito

This article assumes you're familiar with shell programming, JScript, and ATL
Level of Difficulty     1   2   3 
Code for this article: W2KUI2.exe (93KB)

The Web-style interface is the default Explorer folder view for the Desktop Update in Windows 2000. The Desktop Update uses HTML-based hypertext templates to create the Web view, and you can customize these templates to include your own views and commands.
       This article shows you how the Explorer Web view works and how to build your own custom templates for it. You'll see how to add a command prompt and task buttons to a new folder view using HTML, script, and ActiveX controls. The shell object model and thumbnail shell extensions are also examined, then used to build a simple icon viewer for Explorer. the user interface for Windows® 2000 is based on the well-known Active Desktop¯a shell update originally introduced with Microsoft® Internet Explorer 4.0 under both Windows 95 and Windows NT® 4.0. (Active Desktop is now called Desktop Update under Windows 2000.) A couple aspects of the Windows 2000 desktop are worth exploring.
      First, the Web-style view for each folder is enabled by default. Actually, this is the only typical browser functionality that the standard configuration activates. Another classic Web-style feature, underlining icons, is turned off in the default settings.
      Second, the MSDNâ„¢ documentation that accompanies Windows 2000 finally sheds light on some intriguing features of the Desktop Update and provides practical hints on how to reproduce them. The technical documentation may not explain enough, but it certainly will prepare you for more focused investigation.
      In this article, I'll continue where my March 2000 article, "Enhance Your User's Experience with New Infotip and Icon Overlay Shell Extensions," left off. I'll guide you through a tour of the Desktop Update architecture to discover how it was created, how it works, what its constituent elements are, and even how to extend it and build an enhanced version of Explorer.
      I'll also discuss the implementation details of a new type of shell extension that is not well documented. It allows you to provide your own image extractor that enables the shell to display thumbnails of your documents in the right panel of Explorer.

The Desktop Update

      Desktop Update merges two different paradigms for the user interface. One is the standard Windows desktop, where the system determines the folder layouts and content. The second is an emerging information retrieval paradigm¯the Web browser. In the standard desktop, you have an ordered list of directories and files that you can't easily customize. This makes it easier for novice users to work effectively with the system.
      With a Web-style layout you can fill the right panel of the Explorer window with virtually any sort of information. Better yet, you can use anything that you can embed in a Web page, including ActiveX® controls, Java-language applets, animations, hyperlinks, script code, images and more. Is this useful? Well, I can think of one really good use: a folder customized by an administrator might significantly help novice users work more efficiently, potentially saving a number of help desk calls. On the other hand, folder customization should be the exclusive domain of power-users, administrators, and programmers. Figure 1 shows a completely custom folder view.
Figure 1 Custom Folder View
Figure 1 Custom Folder View

      I have a personal experience that illustrates this point. A client company wanted me to help develop some Explorer extensions. I stayed about a week, wrote my code, taught my classes, and noticed how some staff members were not particularly skilled with Microsoft Excel and Word documents, although they understood the use of desktop icons and how to and print. For example, switching to a different document template, or even attaching it to an e-mail message, was often a problem. I soon realized that a slight customization of the folder view might have helped. I changed the template of the folders, adding some buttons that called specialized script functions to launch custom Microsoft Excel and Word documents. All of the computers in this group were running Windows 98. With Windows 2000, there are even more opportunities for customization.

How it's Done

      The dialog box shown in Figure 2 contains all the controls you need to enable Web-style content in your folders. In particular, the radio buttons in the Web View frame affect the structure of the Explorer's right panel. A classic-style view is based on a simple listview control through which you see all the items contained in that folder. A Web-style view requires a more complicated hierarchy of windows and ends up showing the content through a WebBrowser control and a template HTML page.
Figure 2 Selecting the Web View
Figure 2 Selecting the Web View

       Figure 3 illustrates the different sets of windows involved with both views. You can investigate this schema using a tool like Spy++. The blocks in Figure 3 contain the class names of the windows. ExploreWClass is the class name of the main Explorer window. Internet Explorer_Server is WebBrowser's main window. SHELLDLL_DefView acts as a container for any shell folder view that is available.
Figure 3 Window Class Hierarchy Per View
Figure 3 Window Class Hierarchy Per View

      Today there are only two possible views. One is the Web view, available for both folders and file system directories. The other, available for directories only, is the thumbnails view. Under previous versions of Desktop Update¯those for Windows 9x and Windows NT 4.0¯both choices were listed on the View menu in Explorer. In Windows 2000, things have been clarified quite a bit. The thumbnails let you render the content of a directory. The Web view is a template-driven way to organize the entire folder, not just the part of it that shows the content. In other words, only the thumbnails view, not the Web view, is an option in the View menu, along with the regular options¯large and small icons, list, and details.
Figure 4 Views
Figure 4 Views       In principle, it seems possible to write custom views for the folder content to be made available from the View menu in Explorer (see Figure 4). In practice, this is undocumented so you should resort to a namespace extension if you need to create a virtual folder with custom content. For more information on this topic, see the article "Implementing a Web View Namespace Extension Using Active Directory Services" in the August 1998 issue of Microsoft Systems Journal.

Working in Web View Mode

      When Explorer works in the Web view mode, each selected folder is displayed through a COM component called Shell DefView. (If you want to know more about its internals, look at it with the OLEView tool at https://www.microsoft.com/com/resources/oleview.asp.) Shell DefView is an ActiveX control that uses a listview to show all the files contained in a given folder. As I explained in my March 2000 article, the Windows 2000 shell allows you to change the standard set of columns this listview presents.
      A classic-style view simply forces the control to occupy the entire right pane in Explorer. The listview is created as a child of the control's main window, and the control acts as a message router between the Explorer framework and the hosted listview. The listview programming interface is replicated by the standard folder and desktop view. Thus it's hard to say whether the four listview states (large and small icons, list, and details) or the shell's different views came first. As a matter of fact, all changes in the overall user interface of the listviews (item underlining, hot-tracking, full row selection, and background bitmap) have been extended to folders and the desktop. Or was it the other way around? Confirming once more that the listview control plays a central role in the Explorer infrastructure, Spy++ reveals that the listview control is used to implement the thumbnails view and to arrange the icons on your desktop.
Figure 5 Classic and Web-style Views
Figure 5 Classic and Web-style Views

      The key differences between a classic and a Web-style view are shown in Figure 5. You can see the structure of the right pane in Explorer in Web mode. The file list control is now just one of the elements that form the folder view. The right pane is fully occupied by a WebBrowser control. This fact has two important consequences. First, you can preview in the right pane any document that you can view in Internet Explorer¯including Microsoft Excel, Word, and PowerPoint® documents, and HTML pages.
      Using the WebBrowser control as the default viewer for the folder content also enables you to see that content embedded in a host HTML page. Using an HTML page as a container will do more than simply provide a cool textured background. Windows uses this Web page to provide additional information about the folder, the currently selected file, and links to frequently visited folders. The background page turns out to be a sort of template for the folder view. The template is normally applied on a per-folder basis. Folders of the same type share the same template. For example, file folders or file system directories use a file called folder.htt, which is different from the one used for the Recycle Bin, My Network Places, or My Pictures. However, you can choose a particular template for a given folder or create one from scratch.
Figure 6 Folder Customization Wizard
Figure 6 Folder Customization Wizard

      You create a custom template through the folder customization wizard available from the folder's context menu (see Figure 6). Once you've worked through the wizard, the HTML template is stored in a hidden child subdirectory called Folder Settings. A desktop.ini file maintains the link to it like so:

  [{5984FFE0-28D4-11CF-AE66-08002B2E1262}]
  
PersistMoniker=file://Folder Settings/folder.htt

 

      The HTML template page, also known as a hypertext template (HTT), is the HTML page that the shell displays through the embedded WebBrowser control. The page is expected to include the ActiveX control showing the folder content. However, the HTT can have any content and can exploit any available object model to process its data. Any Dynamic HTML (DHTML) page can be used as a folder template. In doing so, you put an entire DHTML application into a folder in Windows. It's just like a namespace extension, but slightly less powerful. It's also much easier and quicker to write than a namespace extension.

The Role of Hypertext Templates

      An HTT file is not very different from an HTML page except for one small addition: an HTT may include some environment variables that you cannot access from a regular HTML file. Figure 7 describes all of these variables. They store information about the current folder (both path and folder name) and the system directory where all the system-provided HTT files can be found. Normally, HTTs are stored in the Web subdirectory of your Windows folder. Here you should find HTTs and all the helper files, like GIFs, JPGs, scripts, and so on. By default, all these files are hidden unless you turn on the "Show hidden files and folders" flag in the Folder Options dialog box.
      When the Web view mode is active and you attempt to open or explore a folder, Explorer attempts to locate a desktop.ini file via the specified path. If the file is found and the directory has the read-only attribute set, then the file content is read and processed. If desktop.ini has an entry called PersistMoniker as shown earlier, the specified HTT file is used as the template. If there's no HTT file in the current folder, then the system HTT for that type of folder is loaded and used. When the shell loads an HTT file, it does some extra work to initialize the environment and assign a consistent value to all the system variables.
       Figure 8 lists the primary HTT files found in Windows 2000. Notice that templates can also be used for floppy disks or shared folders. An HTT serves two main purposes. First, it allows you to insert facilities specific to the types of files the folder primarily contains. For example, My Pictures is a directory expected to contain mostly images (see Figure 9). The template adds a toolbar with image-specific functions such as zoom, print, preview, and size adjustments. The same pattern could be applied to folders and documents. HTTs are also quite useful for improving the overall Explorer user interface by adding facilities for things such as file selection and quick folder creation.
Figure 9 Using imgview.htt
Figure 9 Using imgview.htt

      Through HTTs, namespace extensions¯shell folders with custom content¯can have Web views. A namespace extension that wants to expose a Web view must implement some extra interfaces, particularly IShellView2 and IPersistFolder2. Figure 10 shows how the special folders in Windows 2000 store information about their Web templates. In particular, the registry settings shown are taken from the My Network Places configuration. The registration schema, though, is always the same. Under the node of the extension's CLSID, create the following subtree

  \Shellex
  
\ExtShellFolderViews
\{5984FFE0-28D4-11CF-AE66-08002B2E1262}

 

and set the PersistMoniker key to the HTT file you want to use.

Changing Templates on the Fly

      So far I've promoted the idea that an HTT is a fixed attribute of a folder or category of folders. The template for a folder is identified by name, and any file with that name located in the correct directory can be used. But is there a way to write ASP-like HTTs? In other words, can you bind the choice of the folder template to runtime conditions, such as the name of the user who is currently logged in or the access privileges that are assigned to the user and stored in a particular database?
      Right now you simply cannot use an ASP page in place of an HTT. If you specify the template through an HTTP URL, nothing happens and the folder appears with the classic look. However, this doesn't mean there's no way to choose a template based on runtime conditions.
      One approach that comes to mind relies heavily on DHTML. You could use DHTML methods to populate the page with text that best suits the given runtime conditions. The code of the page may look like this:

  <html>
  
<script language="jscript">
function init()
���
</script>
<body onload="init()">
</body>
</html>

 

The initialization function checks the global status and generates the proper code. This code might be embedded in the HTT itself, or it might come from an external file.
      Another approach to producing a dynamic HTT is based on XML and XSL. I covered this in the May/June 1999 MSDN News article, "A Brand New Web Look for Your Folders". By providing an XML description of the desired folder's appearance, you should be able to isolate all the runtime differences in the XSL stylesheet.
      A tricky aspect of using XML for your HTT is that the WebBrowser control won't process it as XML if you give it an .htt file extension. On the other hand, if you don't give it the .htt extension, all the system variables like %THISDIRPATH% won't be expanded properly. These variables are important because they tell your template about the current folder or the template directory where all the accessory files should be located. Using XML/XSL and system variables appears to be mutually exclusive. If you decide on XML/XSL, then you must figure out a way to obtain at least the current folder path, which is by far the most important of all the runtime information. A template that contains the file list Shell DefView control might query it for the name of the folder. This way you get the information through scripting and can associate it with a page event.
      In a previous article, I used a slightly different approach: obtain the folder name during the window.onload event and then store it in the document.cookie object for further use. Of course, using document.cookie is not mandatory; any technique you use to keep data persistent is fine. If you plan to use a COM object within an HTT template, remember that you're still working within an HTML page so all the typical security restrictions will apply unless you use components marked safe for scripting.

An Improved Explorer Shell

      Let's concentrate now on the source code of the HTT template normally used for all file folders that haven't been customized yet through the folder customization wizard. This file is called folder.htt, as the PersistMoniker value of the following registry key confirms:

  Directory
  
\Shellex
\ExtShellFolderViews
\{5984FFE0-28D4-11CF-AE66-08002B2E1262}

 

Folder.htt is a hidden file that can be found in the Web subdirectory of the Windows folder. The source code can be found in Figure 11.
      By modifying this file you change the way in which Explorer presents the content of directories. Your changes don't actually affect the ActiveX control with the file list. Instead, you manipulate all the surrounding text, graphics, and script code. You wouldn't modify folder.htt to change one or two bitmaps, but to enrich the template with more advanced tools to enhance Explorer.
      Remember, since folder.htt is a system file, you should be sure you have a backup copy before making any changes. Don't forget that HTT files are used only if you're working with the Web view mode turned on. By having a backup copy of folder.htt, you could restore a good configuration simply by turning off Web mode from the Folder Options dialog box and renaming a few files.
      There are three features that I would like Explorer to provide: quick-access buttons to create a new folder, the ability to open the command prompt from the current folder, and the option to select all the files matching a given pattern. The last one is a very handy feature that was in the old File Manager but not in Explorer.
      To create these three new buttons, figure out where in the source code you want to add the buttons, and enter the following code:

  <input type="button" value="New">
  

 

Instead of using the standard gray buttons you usually find in HTML forms, I decided to utilize the HTML 4.0 and Internet Explorer-specific button tag.

  <button style='width:40px'>New</button>
  

 

The final effect, however, is the same. The buttons in Figure 1 are white and have a nonstandard appearance because they were modified by applying a Cascading Style Sheet (CSS) style like so:

  button {
  
font: 8pt Tahoma;
margin-left: 12px;
background: white;
color: black;
}

 

If you apply the same CSS style to an <input> tag, you obtain exactly the same result. The template uses DHTML absolute positioning tables to place the various elements.
Figure 12 folder.htt Layout
Figure 12 folder.htt Layout

      In Figure 12 you can see the layout of the folder.htt template. Basically, it is created by a sequence of <div> tags with an overlapped ActiveX control¯the Shell DefView control¯placed 200 pixels from the left border. The distance of the file list control from the browser bar with the treeview is therefore permanently fixed, and doesn't change if you change the Explorer window size.
      To add a block of HTML code with customized controls, define a new <div> and place it just above the Details panel.

  <div id=CustomPanel>
  
<input style='width:144px' id=textbox
class=textbox type=text></input><br>
<button style='width:40px'
onclick="NewFolder()">New</button>
<button style='width:40px'
onclick="DosPrompt()">DOS</button>
<button style='width:40px'
onclick="SelectItems()">Select</button>
</div>

 

A repeated separator would also graphically separate this new <div> from the rest of the page.

  <img id=LogoLine src="wvline.gif">
  

 

Creating a New Folder

      So much for the presentation. Now let's focus on the code necessary to create a new folder. Open the command prompt and select all the files that match a pattern. The input box placed over the buttons is used to accept the text that the clicked button will interpret. For example, the text in the input box may be the name of the new folder, the command to execute (such as dir *.*), or the pattern for the files to select in the view (such as *.gif).
      Creating a new folder is as easy as calling a Win32® API function such as CreateDirectory or SHCreateDirectoryEx, which is more powerful and specific to Windows 2000. However, this is not something that can be accomplished from within a piece of script code. To work around this, I wrote an ATL COM Automation object tailored to the needs of the modified template. The progID is ShellUtils.Exec, and its dispatch table counts the following methods: NewFolderHere, DosFromHere, and ExecCommand. Since this object should be used from within an HTML page, I marked it safe for scripting. In ATL, this means you derive the class from the following:

  IObjectSafetyImpl<CExec, INTERFACESAFE_FOR_UNTRUSTED_CALLER>
  

 

To make the IObjectSafety interface externally available, you use this code:

  BEGIN_COM_MAP(CExec)
  
COM_INTERFACE_ENTRY(IExec)
COM_INTERFACE_ENTRY(IObjectSafety)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

 

      The New button associates the JScript® NewFolder function with an onclick event. The function reads in the value of the textbox and calls NewFolderHere, passing the name of the current folder and the new subdirectory.

  function NewFolder() {
  
folderName = textbox.value;
if (folderName == "") folderName = "New Folder";

obj = new ActiveXObject("ShellUtils.Exec");
obj.NewFolderHere(curPath, folderName);
}

 

Since the ShellUtils.Exec object has been declared safe for scripting, you won't see any warning.
      How does the script code know the current folder name? Consider that the shell treats %THISDIRPATH% more like an expandable macro than an environment variable whose value you could retrieve later. Before navigating to the HTT file, the shell expands all occurrences of the macros within the text. As a result, code like this

  curPath = "%THISDIRPATH%"
  

 

should assign the current path to the variable curPath. It works, but not in JScript. Suppose for a moment that the path evaluates to c:\winnt\web. In JScript, it ends up being:

  curPath = "c:\winnt\web"
  

 

      As you should know, this is not valid because JScript, like C and C++, assigns a special meaning to the slash character. The same assignment should be rewritten with double slashes:

  curPath = "c:\\winnt\\web"
  

 

Unfortunately, this is not something you can ask the template preprocessor to do. The simplest solution is wrapping the variable assignment in a block of VBScript code:

  <script language="VBScript">
  
curPath = "%THISDIRPATH%"
</script>

 

Now you can use curPath as a global variable. If the input box is empty, the new folder takes the standard name New Folder.
      If you create a new folder through the regular Explorer menus, you'll notice that a new item is added immediately, in edit mode, at the bottom of the listview. The directory is actually created only when you exit edit mode and confirm the name. Using the NewFolder function, it takes a little longer to get the visible feedback. The ShellUtils's NewFolderHere method creates the new directory directly and then notifies Explorer.

  SHCreateDirectoryEx(NULL, szDir, NULL);
  
SHChangeNotify(SHCNE_MKDIR, SHCNF_PATH,
OLE2T(newFolderName), NULL);

 

      At this point Explorer refreshes its user interface and displays the newly created subfolder. Notice that the call to SHChangeNotify is not strictly necessary to cause Explorer to refresh, but may help get the user feedback a little faster. A call to SHChangeNotify isn't mandatory since Explorer automatically installs a file notification object (FNO) in the folder that is currently opened. The FNO is a kernel object that gets signaled when any file system change occurs in the monitored subtree. An FNO tells you nothing about the particular change, just that something did occur. Thus, Explorer waits for an FNO notification, then refreshes its user interface. A direct call to SHChangeNotify may speed up this process.

An Embedded Command Console

      To open the command prompt from the current folder, you might use the following code:

  ZeroMemory(&si, sizeof(si));
  
si.cb = sizeof(si);
CreateProcess( NULL,
szCommand,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
OLE2T(curFolderName),
&si,
&pi);

 

Under Windows 2000, the command prompt is cmd.exe or the value returned by the ComSpec environment variable. The working directory argument of CreateProcess causes the prompt to open where specified. The ShellUtils object runs this code through the DosFromHere method.
      After reading my March 2000 article on Windows 2000 shell extensions, a reader asked me how to run an MS-DOS® command from Explorer and process its results without displaying the console window. Of course, not all MS-DOS commands can be run this way. For example, a delete command may require you to confirm the operation. As an interactive command, it cannot be run without the prompt. A dir or a copy command, on the other hand, can execute in batch mode; therefore you can run them from the shell and see the results.
      ExecCommand is the ShellUtils method that takes care of this. You can see its source code in Figure 13. It simply dumps the output of the command to a temporary file using the traditional > redirect operator. Then it reads the output back in a string that is returned to the caller. The HTT template contains script like this:

  function DosPrompt() {
  
cmdText = textbox.value;
obj = new ActiveXObject("ShellUtils.Exec");

// empty command means "Show DOS Prompt"
if (cmdText == "") {
obj.DosFromHere(curPath);
return;
}

// assume any other string is an MS-DOS command
buf = obj.ExecCommand(curPath, cmdText);
ShowResults(buf);
}

 

      The buf variable contains all the text captured from the command execution. The problem is how to display the text in a consistent and effective way. You can create a hidden <div> below the FileList control and toggle its display state when there's a string to show. The <div> can occupy half the space of the FileList control, as shown in Figure 14. Using DHTML helps considerably in the implementation of this solution because its object model allows you to dynamically resize the FileList control and toggle the result panel's visibility.
Figure 14 DIV for Directory Listing
Figure 14 DIV for Directory Listing

      To obtain the most flexibility, I chose to employ a DHTML scriptlet to render the output of the command. However, a simpler <div> or <span> tag would have worked just as well.

  <div id=DosPanel style="display:none">
  
<table border=0 class=mytext><tr>
<td width=30>
<img align=absmiddle onclick="OnDosPanelClick()"
src=opened.gif></td>
<td><span id=DosPanelLabel></span><br></td>
</tr></table>

<object id=DosPanelResults type="text/x-scriptlet"
data="textview.htm" style="width:100%">
</object>
</div>

 

      The scriptlet is implemented by textview.htm, a Web component with just one property: Text. The little pin icon simulates the button that closes the view. The MS-DOS command runs synchronously since WaitForSingleObject is used (see Figure 13). The code that resizes the FileList component, leaving space for the command prompt panel, looks like this:

  function ShowResults(buf) {
  
FileList.style.height = "50%";
DosPanelLabel.innerHTML = "<b>Results of: </b>" + cmdText;
DosPanel.style.display = "";
DosPanelResults.style.setExpression("height",
"FileList.style.pixelHeight");
DosPanelResults.Text = buf;
}

 

      The panel requires absolute positioning 200 pixels to the left and occupies the lower half of the frame.

  position:absolute; left:200px; top:50%; border=0
  

 

      While you can force a scriptlet to take all the available width (100 percent), there's no way to make it fully resizable for both width and height. Try assigning 100% to both width and height and you'll see that the latter will be ignored. In this scenario, dynamic properties, a little known feature of Internet Explorer 5.0 (the browser in Windows 2000) turns out to be quite useful.
      A dynamic property is an expression that you can assign to an attribute of a DHTML element. When these expressions are set, Internet Explorer takes care of recalculating them when the browser's size changes. You use the setExpression method of the style object to give the specified property the runtime value of an expression. Notice that the expression must be passed as a string. For example,

  setExpression("height", "FileList.style.pixelHeight/2");
  

 

mandates that the height of the element must always be half the height in pixels of the FileList control. Internet Explorer 5.0 ensures this and guarantees that, whatever the size of the Explorer window, the command prompt panel and the FileList control will share the vertical room if both are visible. The text that the command prompt panel displays is selectable and could be copied to the clipboard. This is another reason for using a scriptlet (namely an overlapping page) instead of a simpler <div>¯the browser prevents you from selecting anything in the template page. A scriptlet, though, is entirely in a separate page.
      With a simple embedded console like this, users with nostalgia for the MS-DOS prompt can continue copying or deleting files the old-fashioned way. This embedded console also allows you to create new directories through the mkdir command that Explorer will detect through its FNO mechanism.

Selecting Matching Files

      Suppose you need to copy all the files with a certain extension or that match a given pattern. Explorer doesn't provide any facility for this¯usually you have to select the files one at a time or sort them and select manually.
      Windows 2000 provides a rich shell object model that, when invoked from the HTT template, allows you to access any single item in the current folder. Shell.Application has been available since the inception of the Active Desktop. If you never bothered to install the Active Desktop you'll probably be surprised by what Shell.Application allows you to do.
      Once you've created an instance of the root object, you can connect to any folder using the NameSpace method. The Visual Basic code necessary to access the Windows NT folder is:

  Dim sao As Shell
  
Dim f As Folder
set sao = CreateObject("Shell.Application")
set f = sao.Namespace("c:\winnt")

 

This C++ code shows how to connect to the desktop folder:

  IShellDispatch *pSD = NULL;
  
Folder *pFolder = NULL;
CoCreateInstance(CLSID_Shell, NULL, CLSCTX_SERVER,
IID_IShellDispatch, (LPVOID *) &pSD);
VARIANT vDir;
VariantInit(&vDir);
vDir.vt = VT_I4;
vDir.lVal = CSIDL_DESKTOP;
pSD->NameSpace(vDir, &pFolder);

 

The Folder object represents a folder or a directory. The FolderItem object renders an element of a folder. You can access the items within a folder through the Items collection.
      The FileList control (see Figure 11) shows the content of the folder. Its programming interface is rendered by an object called ShellFolderView. The ShellFolderView object has properties like Folder and FocusedItem and methods such as SelectItem and SelectedItems all straightforward stuff. SelectItem can be used to select and deselect an item. This is the key method for implementing a selection mechanism within Explorer.
      The input box may be used to specify the string to be matched, such as *.gif, as in this JScript code:

  var sfvDeSelect = 0;
  
var sfvSelected = 1;

function SelectItems() {
fileSpec = textbox.value;
e = new Enumerator(FileList.Folder.Items());
for (; !e.atEnd(); e.moveNext()) {
oSFI = e.item();
FileList.SelectItem(oSFI, sfvDeSelect);
sSFIName = oSFI.Name;
if (IsLike(sSFIName, fileSpec))
FileList.SelectItem(oSFI, sfvSelected);
}
FileList.focus();
}

 

As you can see, its logic is not really complex. The script walks through all the items stored in the current folder

  e = new Enumerator(FileList.Folder.Items());
  

 

and makes sure no items are selected. Then it selects all of the items that match the specified pattern. To verify the match, I'm using a VBScript function that emulates the behavior of the Visual Basic for Applications Like operator. You can find the source code for that in the helpers.vbs file in this month's source archive.
Figure 15 Using the Select Button
Figure 15 Using the Select Button

       Figure 15 demonstrates the behavior of the Select button when it's called to select all the HTML files whose names begin with t. Notice that the Desktop Update template used for the Windows system folders (usually c:\winnt and c:\winnt\system32) is not folder.htt, so this functionality doesn't apply to those folders.
Figure 16 New My Services Folder
Figure 16 New My Services Folder

      Windows 2000 extends the shell object model by defining the new IShellDispatch2 interface. This interface exposes additional methods that basically allow you to start, stop, and control system services. You usually do this through the Control Panel and the MMC application services.msc. Furthermore, with Windows Management Instrumentation (WMI) you can enumerate all the services available and create a new My Services folder, as shown in Figure 16. The HTT for that folder (included in this month's source archive) utilizes the ShellUtils.ExecCommand method to run a JScript batch operation that outputs on stdout all the services information retrieved through WMI.

  var wmi = GetObject("winmgmts:{impersonationLevel=impersonate}");
  
ts = WScript.StdOut;
e = new Enumerator(wmi.InstancesOf("win32_service"));
for(; !e.atEnd(); e.moveNext()) {
var s = e.item();
ts.Write(s.Name + SEP + s.Description + SEP + s.State + "|");
}

 

      Wscript.StdOut is a new feature of Windows Script Host (WSH) 2.0 that ships with Windows 2000. Notice that StdOut returns a valid text stream object only if you run the script through cscript.exe, the console engine for WSH. Here's the code that the HTT template employs to run the script and capture the console output for presentation:

  set obj = CreateObject("ShellUtils.Exec")
  
s = obj.ExecCommand("%THISDIRPATH%",
"cscript.exe /nologo enumservices.js")
tableText = FormatData(s)

 

The FormatData function simply creates an HTML table to present the data in an orderly fashion.

Document Image Extractors

      A very handy feature that has been around since the introduction of the Active Desktop is the thumbnail viewer. It is an ActiveX control embedded in the standard HTT template that the shell utilizes to display a preview of a document when it is selected in the file list. You can use a control like this (ThumbCtl class) from within C++ applications to display GIF and JPEG images as well as to preview Microsoft Office documents. The control has a method called displayFile that does the whole job. It only takes the BSTR name of the file you want to display as an argument.

  displayFile(BSTR bFileName)
  

 

      Windows 2000 uses this mechanism to let you preview a number of different file types, including BMP, GIF, JPEG, PNG, DOC, PPT, XLS, WMF, HTML, and even e-mail messages (*.eml). Notice that Office documents can be previewed only if they've been saved with an embedded preview picture. (There's a specific checkbox in the Properties dialog that enables this.)
      The thumbnail viewer can be extended to support other document types. To enable this you need to create some keys in the system registry and a new shell extension. For example, suppose your application manages documents with a file extension of *.xyz. Under the HKEY_CLASSES_ROOT tree, locate or create the following subtree

  .xyz
  
\Shellex
\{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}

 

      The default value for the key is a CLSID pointing to the shell extension that actually provides the preview. This registration schema is similar to the one used by the infotip shell extensions I described in the March 2000 issue. The CLSID under the Shellex key is the GUID of an interface called IExtractImage, which turns out to be the key interface for implementing image extractors that extend the thumbnail viewer. Windows 2000 comes with a number of image extractors and you can add your own to the list.
      A thumbnail shell extension is a COM object that implements at least two interfaces: IPersistFile to know about the file currently selected in the shell, and IExtractImage to access the document and return a bitmap that renders its content. To demonstrate how it works in practice, let's create an image extractor for icon files (.ico). Windows 2000 doesn't provide an extractor for icons¯and actually there's no real need for one since icon files use themselves as the icon in the standard folder view.
       Figure 17 shows the source code for the shell extension. IExtractImage defines only two methods: GetLocation and Extract. GetLocation is intended to inform the shell about the full path name of the document and to specify how it should be rendered. Although the documentation mostly refers to images, almost any document could be previewed since you just provide a bitmap that represents the content of a document.

  HRESULT GetLocation(
  
LPWSTR pszPathBuffer,
DWORD cchMax,
DWORD *pdwPriority
const SIZE *prgSize
DWORD dwRecClrDepth
DWORD *pdwFlags
);

 

      The arguments pszPathBuffer and cchMax might be used to tell Explorer the path of the document so that it could be stored for later use. This is how you enable caching. The priority is normally used to indicate the amount of time needed to extract the image. The argument of type SIZE defines the space available for the image to display. Your extension will be responsible for providing bitmaps that fit into this area. The suggested color depth for the bitmap is passed via dwRecClrDepth.
      The flag argument is used as a two-way channel for the shell and the object to exchange information. For example, the shell can ask the object if it supports asynchronous extraction. If so, the IEIFLAG_ASYNC bit would be turned on. If the IEIFLAG_ CACHE is returned, the shell will cache the image and won't require it again until the logon session ends. The shell utilizes other flags like IEIFLAG_ASPECT and IEIFLAG_ORIGSIZE to let the extension know to stick with the given aspect ratio or to crop the part of the image that exceeds the specified boundaries.
      The GetLocation method should return E_PENDING only if the object is freethreaded and supports asynchronous extraction. In this case, the object must also implement IRunnableTask to allow the shell to control the extraction process.
      But what if your shell extension isn't freethreaded? In this case, you should return NOERROR and clear the IEIFLAG_ASYNC bit so the shell knows you're working synchronously and aren't freethreaded. However, any value you return different from E_ PENDING causes Explorer to stop processing the thumbnail. As a result, Extract¯the method that actually performs the extraction and returns the bitmap to display¯is never invoked.
      The prototype of Extract is quite self-explanatory:

  HRESULT Extract(
  
HBITMAP phBmpImage
);

 

The method returns NOERROR or an OLE-defined error code. It is responsible for retrieving the HBITMAP from the selected file. The shell extension receives the name of the selected file through the Load method of the IPersistFile interface. The name is typically stored in a member variable of the coclass implementing the shell extension. The shell will release the bitmap handle when it's no longer needed.
       Figure 18 shows a simple non-freethreaded extension for icon thumbnails. It's worth noting that this shell extension works under previous versions of Active Desktop and Desktop Update, including under Windows 98.
Figure 18 Showing Icon Thumbnails
Figure 18 Showing Icon Thumbnails

      If you ask the shell to cache images, your extension won't be called when the user selects the same document again. In particular, the shell won't be capable of detecting any change in the file you may have entered in the meantime. To work around this limitation, a new and improved interface has been added with the introduction of Windows 2000: IExtractImage2. This interface defines one more function called GetDateStamp.

  HRESULT GetDateStamp(
  
FILETIME *pDateStamp
);

 

This function is supposed to return the timestamp when the image was last modified. Explorer compares this timestamp to the one it already holds and reloads the image when needed.
      It may seem strange that the shell asks the object for this information. Why can't the shell retrieve that timestamp through a Win32 API without involving a COM method? There are some reasons that justify this choice. First, the thumbnail timestamp doesn't necessarily coincide with the document's timestamp. Think of PowerPoint documents, for example. Usually, the preview picture is of the first slide, and the thumbnail is stored within the file itself. If you just add a comma to a label in the final slide of the presentation, you modify the document and therefore the timestamp, but this won't change the thumbnail.
      Second, you might want to store thumbnails and documents in separate files. In this case, there's no way for the shell to know about the timestamp for the thumbnails. The shell attempts to invoke IExtractImage2::GetDateStamp only under Windows 2000 and¯of course¯only if its query for the interface pointer succeeds.

Conclusion

      HTT templates allow you to customize both the appearance and the content of a folder. Writing an HTT template is surprisingly simple as compared to namespace extensions, which are more powerful and capable of a tighter integration with Explorer, but far more complex to understand and write.
      An HTT template is really a simple type of namespace extension. At the same time it's a way to improve the behavior and features of Explorer itself. By modifying the standard templates, you can add new facilities to the Windows 2000 shell user interface.
      In this article I showed you some new interfaces like IExtractImage and IExtractImage2, and demonstrated how to extend the system thumbnail viewer to work with your documents. Other shell interfaces you might want to look at are IDropTargetHelper and IDropSourceHelper. They allow you to provide more meaningful feedback when the user drags a shell object. These interfaces have been covered in MSDN Online (see https://msdn.microsoft.com/library/techart/ddhelp_pt2.htm).

 

For related articles see:
https://msdn.microsoft.com/library/techart/ddhelp_pt1.htm
https://msdn.microsoft.com/library/techart/ddhelp_pt2.htm
https://msdn.microsoft.com/msdnmag/issues/0300/w2kui/w2kui.asp
https://msdn.microsoft.com/library/techart/shellinstobj.htm
Dino Esposito is a senior trainer and consultant based in Rome. He has recently written Windows Script Host Programmer's Reference (WROX, 1999). You can reach Dino at desposito@vb2themax.com.

From the June 2000 issue of MSDN Magazine.