IPreviewHandler throws uncatchable exception

I imported the IPreviewHandler COM interface into a WinForms application and use it to display a preview for various types of documents (I look at the GUID of the corresponding preview handler in the registry, and then use Activator.CreateInstance(guid) to create an instance of a specific COM class.

This works great for the vast majority of file types - Office formats, PDF files, videos, etc. However, after I create the instance of the "Microsoft Windows TXT Preview Handler" {1531d583-8375-4d3f-b5fb-d23bbd169f22} , initialize its stream containing the regular .txt file, set the borders of the preview window, and then finally call DoPreview() , I get an exception that cannot be caught with try ... catch:

 try { Type comType = Type.GetTypeFromCLSID(guid); object handler = Activator.CreateInstance(comType); if (handler is IInitializeWithStream) { Stream s = File.Open(filename, FileMode.Open); // this just passes the System.IO.Stream as the COM type IStream ((IInitializeWithStream)handler).Initialize(new StreamWrapper(s), 0); } else { throw new NotSupportedException(); } RECT r = new RECT(); r.Top = 0; r.Left = 0; r.Right = hostControl.Width; r.Bottom = hostControl.Height; ((IPreviewHandler)handler).SetWindow(hostControl.Handle, ref r); ((IPreviewHandler)handler).DoPreview(); // <-- crash occurs here } catch (Exception) { // this will never execute } 

When I go to the debugger, the Visual Studio hosting process crashes. Without a debugger, the application crashes without AppDomain.UnHandledException or Application.ThreadException events.

Actually, I do not mind that I cannot view text files using this technique (preview handlers for Office formats, etc. are sufficient for my applications), but I am worried that the user selects a .txt file. Is there a way to catch this error and handle it gracefully? Even better, is there a way to overcome it and make the handler work?

+3
c # winforms com
source share
4 answers

I could not get GetPreviewHandlerGUID () to recognize the .txt file and had to enter the GUID directly. You can see what went wrong when you use Project + Properties, Debug, tick. Enable unmanaged code debugging.

The debugger will now stop at the problem and display

`STATUS_STACK_BUFFER_OVERRUN has encountered

The top of the call table is as follows:

 kernel32.dll!_UnhandledExceptionFilter@4 () + 0x1a368 bytes shell32.dll!___report_gsfailure() + 0xc8 bytes shell32.dll!CRTFPreviewHandler::_StreamInCallback() + 0x74 bytes msftedit.dll!CLightDTEngine::ReadPlainText() + 0xed bytes msftedit.dll!CLightDTEngine::LoadFromEs() + 0x202b3 bytes msftedit.dll!CTxtEdit::TxSendMessage() + 0x1e25f bytes msftedit.dll!_RichEditWndProc@16 () + 0x13d bytes 

The problem is in the StreamInCallback () function. It is called by RichTextBox, which was used to display the preview (msftedit.dll) for downloading the file. The code in this callback function has an error; it destroys the "canary", which is used to detect that the stack frame is damaged due to a buffer overflow.

This is part of Microsoft’s countermeasures to prevent the entry of viruses by buffer overflows themselves. The / GS Compilation Option in Visual Studio for C / C ++ Languages. After detection, CRT very quickly terminates the program. This happens without any exception caused by a failure, the stack cannot be safely unwound because it has been compromised. Accordingly, the CLR cannot eliminate the exception.

This error is specific to the TXT file viewer. There you can do nothing but use it. Reporting this error to connect.microsoft.com is probably not useful; they close it as "external." Otherwise, this is a subtle hint of what might happen if you allowed unmanaged code in your program;)

+6
source share

I had the same problem and I was able to get the TXT PreviewHandler while working compiling to x64 instead of AnyCPU .

I am using Visual Studio 2010 on Windows 7 (64 bit), so this answer will not apply if you are on a 32-bit OS.

In Visual Studio 2010

  • select the Configurations dropdown
  • select Configuration Manager...
  • Click in the Platform cell next to your project.
  • select New... and select the target x64 platform
  • copy settings from AnyCPU and off.
+1
source share

Its very unlikely, but there may be a problem here - catch (Exception) will catch only exceptions of type Exception - try using catch without filtering any type.

 catch(Exception ex) { // Normal logging etc } catch { // Exception of types other than System.Exception. } 
0
source share

I think I found a solution to this problem. The fact is that the stream you create is cleared by the garbage collector or something else. If you call the initialize method using a stream created using the code below, it should work:

 System.Runtime.InteropServices.ComTypes.IStream stream; byte[] fileData = System.IO.File.ReadAllBytes(filename); System.IntPtr hGlobal = System.Runtime.InteropServices.Marshal.AllocHGlobal(fileData.Length); System.Runtime.InteropServices.Marshal.Copy(fileData, 0, hGlobal, fileData.Length); NativeMethods.CreateStreamOnHGlobal(hGlobal, false, out stream); //[DllImport("ole32.dll")] //internal static extern int CreateStreamOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease, out IStream ppstm); 

Im using the above code in a Windows Forms application explicitly set to 32 bit (x86) and working in single-threaded apartments mode.

The loan goes to Sherlock Homes ( http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2010-09/msg00003.html )

0
source share

All Articles