6月12日
Customizing the Stock Previews
Ok so I thought I’d get the ball rolling by talking about how you can customize the item previews displayed in the large search results UI. This is a big topic which isn’t easily covered by a single post so I thought I’d first talk broadly about how the previews work and how to perform basic modifications. In future posts I can drill into more details if there’s interest. But before any of that I need to throw out a disclaimer:
Modifying the previews shipped with Windows Desktop Search is not a supported feature. Any new previews you build will not be guaranteed to work in future versions of the product. The documentation that follows should be considered “unofficial” at best.
Preview Selection
The first topic I should touch on is how the appropriate preview gets chosen when a user selects an item. When a new item is selected, the first thing the preview pane does is it identifies what type of previewer it’s going to display. It currently only has two choices, the folder previewer or the content previewer. The folder previewer is chosen if the item is a file system folder and is simply a shell view over the contents of the folder. All other items get mapped to the content previewer which is an embedded WebBrowser control. At this point we’re only interested in items mapped to the content previewer because they’re the only ones we can modify.
Once an item has been mapped to the content previewer it then goes through a second round of analysis to see what type of content should actually be displayed for the item. This decision process is driven by the registry which means you can modify the registry to influence most of the preview selection decisions made. Open RegEdit and look for the key:
HKEY_CURRENT_USER\Software\Microsoft\RSSearch\ContentIndexCommon\Previewers
You’ll notice a few values and a set of 3 sub-keys Extension, PerceivedType, and Default. Let’s start with the sub-keys. The contents of those 3 keys are used to determine what preview an item gets and I’ve listed them in the order in which they get consulted. The previewer first gets the file extension of the item being previewed (if any) and tries to find a sub-key under the Extensions key. If a sub-key is found preview selection stops and the values of the found key are used to drive preview generation. If no extension key is found then selection moves on to type based selection. Every item in the index has, or at least should have, a value called its perceived type. The perceived type of an item is the value used to tie it to the type filters displayed within the UI and it’s also the value used to tie the item a type wide preview. So for type based selection we simply get the items perceived type and look for a sub-key of the same name under the PerceivedType key. Once found preview selection stops and the values of the found key are used to drive preview generation. If the item has no perceived type or the perceived type isn’t found then the value of the Default key is chosen and selection stops anyway.
Preview Generation
So the items been mapped to a key within the registry but what do the values mean? We’ll those values bind the previewer to a COM based plug-in that knows how to generate preview content for the item. The content generated by the plug-in can be essentially anything render-able by IE. We currently ship with 3 preview plug-ins and the COM interface they implement isn’t public so you can’t add any new ones. So why are we talking about customizing the previews then? Because one of those plug-ins is pretty special…
If you were to look through all of the previewer keys you’d not two recurring patterns. The keys either contain a single default value, one of two GUID’s. Or they contain no default value but several named values. The keys with one of the two GUID’s map the items preview to either the Native (“{015CA7C6-DECD-40dc-AAAC-73EA9940E0F9}”) or Office (“{7A35A3A8-3DEA-40e5-B2AA-21DEF91A219A}”) Previewer plug-ins. Of those two the Native Previewer is the most interesting because it acts as a pass through for the items URL. When an item is bound to this preview we simply navigate our embedded WebBrowser to the URL of the item which is useful for items that IE already does a good job of rendering like PDFs. Even more interesting are the keys without a GUID because they get mapped to a special internal previewer called the Registry Based Previewer.
The Registry Based Previewer turns preview creation into an authoring process by generating preview content on the fly from HTML templates containing a set of ASP’ish (read NOT ASP) macros. The remaining bulk of this post will talk about the structure of these templates but first let me break down the registry entries that control what template is used and how it’s rendered. Looking at:
HKEY_CURRENT_USER\Software\Microsoft\RSSearch\ContentIndexCommon\Previewers\PerceivedType\contact
We see the values:
(Default):
ContentType: 0x00000001 (1)
ScriptOK: 0x00000001 (1)
TemplateUrl: res://msnlExt.dll/contact.htm
The blank value for (Default) is what maps this items preview to the Registry Based Previewer. The ContentType value controls the type of content generated by the previewer and can be either 0 for HTML or 1 for MSHTML. I’d recommend you always use 1 as it’s the most flexible and most tested. The ScriptOK value is used to override one of the security decisions we make based upon what store the item we’re previewing lives in. If the item resides on your hard-drive it’s partially trusted so we let script execute by default. But if the item lives anywhere else like say Outlook or OE we treat it as un-trusted and disable script execution by default. The ScriptOK value lets us re-enable script execution on a per type basis. Security is deep topic worthy of its own post but I should also point out at this time that we NEVER let ActiveX controls execute and there’s currently no way to override that decision. Finally, the TemplateUrl value specifies the actual template to use when generating the preview content. As you can see, all of our templates get pulled from a resource dll but you can change these values to point to a file on the users hard-drive which is the key to replacing the stock previews with custom ones!
Creating new Preview Templates
Probably the easiest way to figure out how to customize the previews is to dive in and start changing them. You’ll notice that I’ve posted several listing which should act as a good starting point for your adventures. Before you download and install any of the listings you need to be very sure that this is something you want to explore. You’ll need to be comfortable working with HTML and modifying the registry. Executing the UseDebugPreviews.reg command will replace all of you’re type based previews (meaning most of them) with a new Debug.htm preview that dumps out most of the available properties within a given view. I’ve also provided a UseStockPreviews.rgs command which should roll everything back to stock but I can’t provide any warranties for any of this so USE AT YOUR OWN RISK!
After you’ve downloaded all 3 of the listings you’ll want to run the UseDebugPreviews.reg command to update the registry to use Debug.htm as the preview template for all type wide previews. There’s an assumption made in UseDebugPreviews.reg that Debug.htm is located in the root of your C-Drive so you’ll need to modify that file if that’s not the case. It’s very important that Debug.htm is saved as a UTF-8 encoded file. The macro replacement done by the Registry Based Previewer will not work if you save the file as Unicode which is the default for Notepad.exe. You’ll also need to either reboot your machine or kill/restart Explorer.exe to get the new previews to take effect. It’s worth noting at this point that changes made to an already mapped preview template do not require a reboot. In fact you can modify your template and simply select another item from the results list to see your changes take effect which is nice.
So once you have Debug.htm installed you should try some queries out and notice what properties are available to your previews in what views. I said above that Debug.htm will show you MOST of the properties available because some of the views like contacts have a ton of properties. There are around 200 total but not all of the properties for an item are available in every view. For instance when an item is displayed in the Contacts view it has a rich set of properties available. But that same item displayed in the Communications or Everything view has only a subset of its total properties available. The Debug.htm preview displays the availability of the properties that can be shown for an item no matter what view its in and is therefore quite useful.
Another thing you might notice while browsing around is that image previews still get mapped to the stock image previewer. That’s because that mapping is done on a per extension basis and UseDebugPreviews.reg only updates the type wide previews. To map an extension say .JPG you’ll need to modify the registry by hand. Change the TemplateUrl value of HKEY_CURRENT_USER\Software\Microsoft\RSSearch\ContentIndexCommon\Previewers\Extension\.jpg to “c:\debug.htm” and re-boot. The previews of .JPG items should now map to the debug preview.
Understanding Preview Templates
Without getting into too much depth I’ll give you an overview of the templates and the macros we currently support. The templates themselves are just UTF-8 encoded HTML files with some special macros added in the form of <%cmd:property%>. At preview generation time the template along with the meta data of the currently selected item gets run through a transform engine to generate a valid HTML file for rendering within the Content Previewers embedded WebBrowser control. Most of the macros are about inserting the dynamic values of the currently selected item but there are a few control commands as well. Here’s a quick list of the major (but not all) commands:
-
<%if:{property}%>, <%else%>, and <%endif%> commands. These commands let you include or exclude a block of code based upon the availability of a property for an item. For instance contact have don’t have a MusicAlbum property so you can conditionally display HTML specific to music albums by placing it between “<%if:MusicAlbum%>Only shown if <b>MusicAlbum</b> exists.<%endif%>” commands.
-
<%ifValue:{property}%> command is an extension to the <%if:{property}%> command that also checks to make sure a property has an actually value before including a fragment of HTML.
-
<%value:{property}%> command injects that properties value into the output HTML. Things like quotes & ampersands get escaped out so its safe to place quotes around this content for passing as an argument to a JavaScript routine.
-
<%title:{property}%> command injects the label of the property into the HTML. This helps to make sure the column names used in your preview match those used in the results list view.
-
<%url:{property}%> command is an interesting one. If you recall I recommended you always specify MSHTML as the content type generated by the Regsitry Based Previewer. When you do that the output from the previewer is a dynamically built multi-part MIME file. So why do we do that? Well for items that live in a store like Outlook we sometimes need to render content that doesn’t physically exist as a file on the hard-drive, like say an image sent as an attachment. Well we still want to be able to preview those items so what we do is embed them as part of the MSHTML file we’re building. Now from an authoring perspective you want to be able to write an image preview that can preview images that exist either on your hard-drive or within Outlook and the <%url:url%> command lets you do just that. Take a look at Debug.htm and notice that we use this command to populate the src attribute of an <img /> tag. If the item is a physical file within the file system you’ll get back the URL for the item but if it’s an item within Outlook, the item gets embedded as a part of MSHTML file being built and you get back a relevant URL to the added part. The <%url:characterization%> command is another useful one when passed as the src of an <iframe /> because it embeds the body of any Outlook item and returns a URL to the linked content. For non Outlook items you get back the first 1k or so of text from the item.
There are a few other interesting commands but I won’t dive into them at this point. This is more then enough to get you started. Just use Debug.htm as a starting point and be sure to send me a link to any interesting previews you come up with.
Important Notes and Tips
-
There’s no way to map the preview for a file system folder to a content previewer.
-
All preview templates MUST be saved as UTF-8 encoded files.
-
You shouldn’t reference a property using <%url:{property}%> more than once per template. This cause the property to get embedded multiple times and for e-mail bodies you may get some other weirdness.
-
Tip: Use the View Source content menu option off the preview panes browser to see the HTML being generated by your template.
-
Tip: You can view the stock templates using IE. You’ll need to first do a search so the WDS results view is displayed. Then you can past the “res:” URL of the template you want to view into IE’s address bar. IE should then display a malformed HTML page. Do a View Source from within IE to view the template.
-
Tip: You can find the MSHTML file for the current preview under the “%temp%\msnl” directory. If something isn’t rendering the way you think it should make sure IE renders the raw preview file correctly before blaming the preview pane. Then let us know. J