UnauthorizedAccessException in PDF Preview Handler


For my article on preview handlers in the January 2007 issue of MSDN Magazine, I wrote a sample preview handler for previewing PDF files.  This allows you to view PDF files in Outlook and in the Vista shell just as you would other document types for which there are built-in preview handlers, like for Word and Excel.



System.UnauthorizedAccessException: Access to the path ‘C:\Users\yourusername\AppData\Local\Temp\3373c62fe9214489828d0ee72cd53d30.PDF’ is denied.
   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
   at MsdnMag.FileBasedPreviewHandlerControl.MakeTemporaryCopy(FileInfo file)
   at MsdnMag.PdfPreviewHandler.PdfPreviewHandlerControl.Load(FileInfo file)
   at MsdnMag.FileBasedPreviewHandler.Load(PreviewHandlerControl c)
   at MsdnMag.PreviewHandler.<MsdnMag.IPreviewHandler.DoPreview>b__2()


What’s going on here?


This is due to a new integrity mechanism/security feature in Windows Vista that restricts write access to securable objects like processes, files, and registry keys with higher integrity levels than the current process.  By default, the prevhost.exe process hosting a preview handler runs as a low-integrity process, which means it doesn’t have write access to the current users profile.  The PDF preview handler I provided is attempting to write to the temp directory, and as a result it’s getting an UnauthorizedAccessException.


This begs the question: why does a preview handler need to write anything?  Isn’t it just reading data from disk and displaying it?  Yes, that should be the case.  However, I wrote the preview handler this way to work around a different problem.  As mentioned in the article in MSDN Magazine, when opening files to be displayed, preview handlers should open them to be sharable such that another process could read from or write to the same file, or even delete that file, while it’s being used by the preview handler.  In the case of my preview handler for PDF files, I’m using the Acrobat Reader ActiveX control to display the PDF files, and in doing so I give up some control over how it loads the file.  Unfortunately, while the PDF file is being loaded by the ActiveX control, it is not shared, preventing other processes such as the shell itself from working with the file.  This means that if a user tries to delete the PDF while it’s being rendered initially, they’ll receive an error saying that the file is currently in use by another process.  This isn’t usually an issue if the file is small or if it’s local, but if the PDF resides on a remote server and takes a while to download and/or load, it could be locked for an unacceptable amount of time.


To work around this, I first copy the PDF from wherever it resides to the user’s local temp folder, and then open the new file.  The copy operation is performed by opening the file for all sharing operations, and it doesn’t matter if the preview handler temporarily locks the temp copy. Unfortunately, this operation also causes the exception in question, which you can see by looking at the stack trace. The exception comes from a method MakeTemporaryCopy, and the exception is due to not being able to write to the user’s %temp% directory.


There are two quick solutions to this problem:
1) Modify the PDF preview handler by simply removing the line of code that calls MakeTemporaryCopy to create the copy and operate on it instead of on the original.
2) Turn off the low-integrity status of the prevhost.exe process.


The first solution is self-explanatory and requires a recompile and reinstallation of the assembly into the GAC.


The second solution requires adding a value to the registry.  Specifically, create a DWORD value on HKEY_CLASSES_ROOT\CLSID\{574fffaa-17f6-44b1-a1b4-177ab5900a51} named DisableLowILProcessIsolation and set it to 1.  This will cause all new prevhost processes for this PDF preview handler to be created as normal integrity, which means they will have the ability to write to the user’s %temp% directory.  If you look in the PreviewHandler.cs file, and specifically at the registration code, you’ll see that there’s a line of code in there that sets this value, but in the download prior to today, it’s commented out (I put up a new version of this code download with the line uncommented).  If you want all of your managed preview handlers to run in a normal-integrity process, just uncomment this line, recompile, and reinstall.  That should fix the error.

Comments (12)

  1. aaron says:

    FYI: the file-copying stuff you have to do in order to support delete-while-previewing is only relevant if the previewer opens the PDF via IPersistFile .. (which the adobe PDF browser control will be doing in this case) .. however, *if* it is opened via IPersistStream, as recommended by MS, you sidestep this problem and it all works just fine.

  2. mkirby says:

    Running windows xp w/office2K7 I get errors while registering classes (permission denial) even running as administrator.

    Is there something specific to vista?

    I did install .net 2 framework and j++ runtimes as well.

  3. Joe says:

    Any thoughts.  Whenever I try and use one of these sample preview handlers they don’t work.  Outlook just displays an error indicating an error occurred with the preview handler.

  4. Joe, are you running on Vista?

  5. Nuno says:

    Hi Stephen. I’m using Office 2K7 with windows XP. I’ve installed your latest version, with the DWORD already seted to 1 and the // file = MakeTemporaryCopy(file); It works on Vista doesn’t work on XP. Does this preview handlers are just for Vista? Thanks for the good work and help.

  6. Hi Nuno- See the sidebar “Preview Handlers and Windows XP” in the article (http://msdn.microsoft.com/msdnmag/issues/07/01/PreviewHandlers/).  As discussed, the code in the article will only work on Vista because prevhost.exe is only distributed on Vista and not on XP.  If you want to use the preview handlers in Outlook 2007 running XP, it’ll take additional work.

  7. Mkramer says:

    Well…make regedit…was already set to 1…i’ll try a reboot…but still getting error

  8. Mkramer says:

    and yes…am running vista lol

  9. tim mackey says:

    hi stephen.  i’ve just found your previewer add-ins and i’m very impressed.  i installed the MSI download from MSDN as admin and it finished ok.  but in outlook, i’m getting an exception when previewing a PDF file.  i’m wondering if there was a change to default security in vista with the recent windows updates?

    the main point of the exception seems to be "Windowless ActiveX controls are not supported", but it also says memory may be corrupted.  the machine is only 3 months old and the ram is high quality, i have no stability problems at all.

    System.Reflection.TargetInvocationException: Unable to get the window handle for the ‘PdfAxHost’ control. Windowless ActiveX controls are not supported. —> System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

      at System.Windows.Forms.UnsafeNativeMethods.IOleObject.DoVerb(Int32 iVerb, IntPtr lpmsg, IOleClientSite pActiveSite, Int32 lindex, IntPtr hwndParent, COMRECT lprcPosRect)

      at System.Windows.Forms.AxHost.DoVerb(Int32 verb)

      at System.Windows.Forms.AxHost.InPlaceActivate()

      — End of inner exception stack trace —

      at System.Windows.Forms.AxHost.InPlaceActivate()

      at System.Windows.Forms.AxHost.TransitionUpTo(Int32 state)

      at System.Windows.Forms.AxHost.CreateHandle()

      at System.Windows.Forms.Control.get_Handle()

      at MsdnMag.PdfPreviewHandler.PdfAxHost.LoadFile(String fileName)

      at MsdnMag.PdfPreviewHandler.PdfPreviewHandlerControl.Load(FileInfo file)

      at MsdnMag.FileBasedPreviewHandler.Load(PreviewHandlerControl c)

      at MsdnMag.PreviewHandler.<MsdnMag.IPreviewHandler.DoPreview>b__2()

    can you shed any light on this?  thanks

    tim.

  10. Tim, what kind of machine is it (x86, x64, etc.)? What OS are you running? What version of Acrobat Reader do you have installed?  Are you able to view PDFs in other contexts? I ask because based on the inner stack trace, the AV is coming from the PDF ActiveX control, though it’s possible something previous in the process corrupted memory such that the ActiveX control is just stumbling upon it and not actually doing anything wrong… it’s difficult to say based just on this trace.

  11. tim mackey says:

    hi stephen. thanks for the reply.  i’m running vista ultimate x86 on an intel dual core platform.  i had adobe reader 7.0 installed, and i had no difficulty opening PDFs directly, but i did notice problems using the ActiveX control in internet browsers.  i upgraded to v8.0 for vista and it runs like a champ now.  great code, thanks!

    tim

  12. Amirz says:

    Hello, based on my personal experience (I have tried it successfully) you can get more previews by integrating Vista Preview Pane with QuickView Plus (as IE plug in). (www.avantstar.com).

    Unfortunately it’s a shareware with 30 days trial. But there’s always another “way”.

    The vendor tells about it still doesnt fully support Vista, but the IE plug in will still be installed as well.

    It supports more than 400 file types included most of known documents, images, and even apps binaries. So superior in my opinion. No need to create specific preview handler any more. same thing due to other IE viewer activex plug in.

    1. Download and install QuickView Plus. Launch it, Configure your custom file for IE plug in by clicking View – Confifugure QuickView Plus – Applications – Internet Explorer (IE plug in). then add your custom files (e.g. .dwg, .psd, .dll etc with their correct content type (MIME)

    2. Download MSDN Preview Handler. Install it.

    3. Download Preview Handler Editor or Preview Handler Configure. Open it then Look for “MSDN Internet Explorer Preview Handler”. select and add your custom files

    4. Activate Vista preview pane. Select your file. the preview appears perfectly now.

    That’s it. Hopefully works. To me, it always works so far.

    Thanx and regards-Amirz