Coding Powers

in

Hosting Vista File Previews in Managed Code

As part of my work on the Coding4Fun Developer Kit 2008, I created a WinForm control encapsulating the flow to display file previews.  The host is dependent on an improved version of Stephen Toub's framework, originally published here.  My enhancements were basically to make the COM wrapper classes public so that they can be used by the Managed PreviewHandlers and also by my Preview Handler Host.  The source for this project including the updated framework, Stephen's sample preview handlers, my host control and a sample application using the host control are available here.  Also, they can be downloaded from the codeplex project for the Coding4Fun Developer Kit 2008.

A couple of quick notes before I describe how the managed preview handler host works. 

  1. For any of this to work, the C4F.DevKit.PreviewHandlerFramework.dll needs to be installed in GAC.
  2. Also, this host will work with all non-managed preview handlers and any managed preview handlers that were built against the PreviewHandlerFramework mentioned above.  Any Managed Preview Handlers that were compiled using Stephen's original framework or another method will not work with this host. 

 

To host the results generated by any registered file preview handler in managed code, the PreviewHandlerFramework’s COM Wrappers are leveraged. In addition, part of this host needs to look up the preview handler that is currently registered with a particular file extension. To accomplish this, the PreviewHandlerHost leveraged the registry code from Stephen Toub’s Preview Handler Association Editor (http://blogs.msdn.com/toub/archive/2006/12/14/preview-handler-association-editor.aspx). With the code to find the registered handler in hand, we constructed a control to implement the preview handler Data Flow as shown below (all of this code is part of PreviewHandlerHost project, PreviewHandlerHostControl.cs):

  • Declare an object that is the PreviewHandler (this will be cast to different COM Interfaces as needed)
  • Unload any existing previews before generating a new preview
    • Call Unload of IPreviewHandler Interface (dDefined in PreviewHandlerFramework as a wrapper to existing COM interface)

Visual C#

private object _comInstance = null; private void GeneratePreview() { if (_comInstance != null) { ((IPreviewHandler)_comInstance).Unload(); }

Visual Basic

 

Private _filePath As String Private Sub GeneratePreview() If Not _comInstance Is Nothing Then CType(_comInstance, IPreviewHandler).Unload() End If
  • Build a RECT struct using the bounds of the visible area where the preview handler can draw. In this case, that is the full bounds of the PreviewHandlerHostControl

Visual C#

RECT r; r.top = 0; r.bottom = this.Height; r.left = 0; r.right = this.Width;

Visual Basic

 

Dim r As RECT r.top = 0 r.bottom = Me.Height r.left = 0 r.right = Me.Width

  • Find the CLSID of the preview handler registered for the file extension of the file using registry lookup. This is typically done by looking in the registry under HKEY_CLASSES_ROOT\%file_extension%\shellex\{8895b1c6-b41f-4c1c-a562-0d564250836f}. This Registry key will have a value pointed to the Class ID (CLSID) of the COM registration of the registered preview handler. For more information about how preview handlers can be found in the registry, see this article.
  • Create an instance of the preview handler using Reflection and the CLSID found in the registry.

Visual C#

Type comType = Type.GetTypeFromCLSID(new Guid(handler.ID)); _comInstance = Activator.CreateInstance(comType);

Visual Basic

 

Dim comType As Type = Type.GetTypeFromCLSID(New Guid(handler.ID)) _comInstance = Activator.CreateInstance(comType)

  • Call the appropriate initialize for the create preview handler (either passing in a stream or filepath)
    • If the preview handler is a stream previewhandler, using a COM IStream Wrapper to handle Stream marshalling to COM

Visual C#

if (_comInstance is IInitializeWithFile) { ((IInitializeWithFile)_comInstance).Initialize(_filePath, 0); } else if (_comInstance is IInitializeWithStream) { if (File.Exists(_filePath)) { StreamWrapper stream = new StreamWrapper(File.Open(_filePath, FileMode.Open)); ((VSExpressDevPack.PreviewHandlerFramework.IInitializeWithStream)_comInstance).Initialize(stream, 0); } else { throw new Exception("File not found"); } }

Visual Basic

 

If TypeOf _comInstance Is IInitializeWithFile Then CType(_comInstance, IInitializeWithFile).Initialize(_filePath, 0) ElseIf TypeOf _comInstance Is IInitializeWithStream Then If File.Exists(_filePath) Then Dim stream As StreamWrapper = New StreamWrapper(File.Open(_filePath, FileMode.Open)) CType(_comInstance, VSExpressDevPack.PreviewHandlerFramework.IInitializeWithStream).Initialize(stream, 0) Else Throw New Exception("File not found") End If End If

  • Call SetWindow on the PreviewHandler, passing in a handle to the control and the bounds (RECT created earlier)

Visual C#

((IPreviewHandler)_comInstance).SetWindow(this.Handle, ref r);

Visual Basic

 

CType(_comInstance, IPreviewHandler).SetWindow(Me.Handle, r)
  • Call DoPreview on the PreviewHandler

Visual C#

 

((IPreviewHandler)_comInstance).DoPreview();

Visual Basic

CType(_comInstance, IPreviewHandler).DoPreview()

If you are interested in more information, the zip file included with this project has all of the source and a document describing a walkthrough of using this control.  Additionally, the Coding4Fun Developer Pack 2008 Vol.1 Codeplex project has all the info and will also have any fixes/enhancements.

Comments

Dmitry P said:

Perfect !!!
# January 13, 2008 1:32 PM

credit buildup said:

Nice Site!

http://google.com

# June 30, 2008 12:07 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)