How to get the IPreviewHandler of a file type in the latest version of .Net

687 views Asked by At

Recently at work I received a project that requires me to get a preview of a specific file type and display it in a preview pane (similar to the preview pane found in windows file explorer). After 3 or 4 days of extensive study on how to achieve this I'm completely stumped.

At first I tried to follow this post How to get the IPreviewHandler for a file extension? but I could never get AssocQueryString to return anything other than some really long random error code. After searching around for another solution I stumbled upon this article here https://www.brad-smith.info/blog/archives/183 After following his tutorial and downloading the example code I was able to generate a preview for word documents, but not for any other file type. The code that made this possible was these lines here

var comType = Type.GetTypeFromCLSID(CurrentPreviewHandler, true);
_mCurrentPreviewHandler = Activator.CreateInstance(comType);

if (_mCurrentPreviewHandler is IPreviewHandler handler)
{
   // bind the preview handler to the control's bounds and preview the content
   var r = ClientRectangle;
   handler.SetWindow(Handle, ref r);
   handler.DoPreview();
   return true;
}

After playing around with the debugger I discovered that word documents return a System.__ComObject whereas the file type that I was trying to generate a preview for was returning an instance of the class that was used to create the ShellExtension. So I went back to the internet for more research and found this CodeProject example https://www.codeproject.com/Articles/25465/Using-Vista-Preview-Handlers-in-a-WPF-Application. This project actually generated the preview for the file type that I was looking for! I was super excited until I noticed that the project used The Exact Same Code As Above to generate the preview! I was super confused until I noticed that the System.dll's of the two projects were different versions. The one that worked targeted .Net 3.5 and the other targeted .Net 4.6.1, which is unfortunate because our project uses .Net 4.6.1.

So now that you're up to speed, here is my question. Is there anyway to get the Preview of a file in .Net 4.6.1 similarly to how it's done in .Net 3.5? Does anyone know what changed between the two versions? Or maybe there is a completely different way of doing this that works better? Thanks in advance!

P.S. While playing with the debugger in the .Net 3.5 project I noticed that Type.GetTypeFromCLSID was returning a System.__ComObject which is what it was also returning for the word document. Does that have something to do with it? Also while the .Net 3.5 does generate the preview it throws this exception System.Runtime.Serialization.SerializationException: "Attempting to deserialize an empty stream." I don't know if that is helpful or not, but I thought I'd include it just in case.

1

There are 1 answers

0
Täuscherpferd On

After about a month and a half of trying to figure this out, I finally found a solution... kind of. I discovered that the C++ API functions still work for generating my preview, so I created a C++ dll for generating my preview. I created a border element on the C# side of things and set it's child element to be a class inheriting from HwndHost so that the border gains a window handle. I then passed the window handle into my C++ dll and let the dll take care of the rest of the work of drawing the preview.

I'll be the first to admit that this isn't a perfect solution, but it got the preview working for now. I submitted a trouble ticket with Microsoft's support and if they come up with a better solution than I'll provide that here. Also if anyone has any questions about how this works leave a comment and I'll try and add a more detailed explanation of what I did.