Hosting vista/office 2007 previewers in winform application
The new vista and office 2007 offers a way to write managed preview handlers for various extensions, a thorough article is available in January issue of the MSDN Magazine.
However if there are already various preview handlers implement for your then why not leverage this functionality and use those handlers within you managed winform application.
I'll start by saying that i started from the following code and created a new class library project only for the Com interfaces used in the example code. I reinstalled the entire thing and reused new class library within my code below, this is important because otherwise you wan't be able host custom written preview handler (interface type is incorrect - (they not marshaled because they are dot net types and not com interfaces).
Lets get familiar with the key interface that will be used throught the code.
IObjectWithSite - set's the hosting site for the previewer (implementing IPreviewHandlerFrame).
IPreviewHandler - the preview handler itself (supports resizing, positioning etc).
IInitializeWithFile - file path based initializer
IInitializeWithStream - stream based initializer (IStream implementation).
Let's dive in...
Each preview handler has a clsid (registery mention in the article above), we need to initialize an instace of the type based on the clsid.
public void PreView(Guid guid, string file)
{
//get type by clsid
Type previewerType = Type.GetTypeFromCLSID(guid);
//create instance
object instance = Activator.CreateInstance(previewerType);
//now we need to querry interface for the required interfaces.
IObjectWithSite ows = (IObjectWithSite)instance;
IPreviewHandler ph = (IPreviewHandler)instance;
IInitializeWithFile iwf = instance as IInitializeWithFile;
IInitializeWithStream iws = instance as IInitializeWithStream;
//now we need to initialize the object
if (iwf != null)
{
iwf.Initialize(file, 0);
}
else
{
if (iws != null)
{
StreamWrapper stream = new StreamWrapper(File.Open(form.file, FileMode.Open));
iws.Initialize(stream, 0);
}
}
//set the current form (implements IPreviewHandlerFrame)
ows.SetSite(this);
//set size
RECT rect = new RECT();
rect.left = 0;
rect.top = 0;
rect.bottom = this.Height;
rect.right = this.Width;
ph.SetWindow(this.Handle, ref rect);
ph.SetRect(ref rect);
//perform the preview
ph.DoPreview();
ph.SetFocus();
}
the StreamWrapper is a simple implementaion for a IStream wrapper and a stream.
internal class StreamWrapper : IStream
{
~StreamWrapper()
{
if (stream != null)
{
stream.Close();
stream.Dispose();
stream = null;
}
}
Stream stream = null;
public StreamWrapper(Stream stream)
{
this.stream = stream;
}
#region IStream Members
public void Clone(out IStream ppstm)
{
}
public void Commit(int grfCommitFlags)
{
}
public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
{
}
public void LockRegion(long libOffset, long cb, int dwLockType)
{
}
public void Read(byte[] pv, int cb, IntPtr pcbRead)
{
int actual = stream.Read(pv,0, cb);
Marshal.WriteInt32(pcbRead, actual);
}
public void Revert()
{
}
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
long actual = stream.Seek(dlibMove, (SeekOrigin)dwOrigin);
}
public void SetSize(long libNewSize)
{
}
public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
{
pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
}
public void UnlockRegion(long libOffset, long cb, int dwLockType)
{
}
public void Write(byte[] pv, int cb, IntPtr pcbWritten)
{
}
#endregion
}
All that is left is to run it :-)
Notes:
1. IPreviewHandlerFrame is implemented as simple winform (no code for the methods in IPreviewHandlerFrame)
2. in the dispose method of form we need to call ph.Unload and to Marshal.ReleaseComObject (if IsCOMObject).