IPreviewHandler抛出无法捕获的exception
我已经将COM接口IPreviewHandler
导入到WinForms应用程序中并使用它来显示各种类型文档的预览(我在注册表中查找相应预览处理程序的GUID,然后使用Activator.CreateInstance(guid)
来实例化特定的COM类。
这适用于绝大多数文件类型 – Office格式,PDF,video等 – 但是,在我实例化“Microsoft Windows TXT预览处理程序” {1531d583-8375-4d3f-b5fb-d23bbd169f22}
,使用流初始化它包含一个普通的.txt文件,设置预览窗口的边界,然后最后调用DoPreview()
,我得到一个无法使用try … catch捕获的exception:
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 }
当我逐步使用调试器时,Visual Studio Hosting Process崩溃了。 如果没有调试器,应用程序将崩溃而不会触发AppDomain.UnHandledException
或Application.ThreadException
事件。
我真的不介意我无法使用这种技术预览纯文本文件(Office格式的工作预览处理程序等足以满足我的应用程序的要求),但我担心如果用户选择我的应用程序会无法控制地崩溃一个.txt文件。 有什么方法可以捕捉到这个错误并优雅地处理它吗? 更好的是,有什么办法可以克服它并让处理程序工作吗?
我无法让GetPreviewHandlerGUID()识别.txt文件并且必须直接注入GUID。 使用Project + Properties,Debug,tick启用非托管代码调试时,您可以看到出了什么问题。
调试器现在将停止问题并显示
遇到`STATUS_STACK_BUFFER_OVERRUN
调用堆栈的顶部如下所示:
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
问题位于StreamInCallback()函数中。 它由RichTextBox调用,用于显示加载文件的预览(msftedit.dll)。 此回调函数中的代码有一个错误,它会破坏用于检测堆栈帧因缓冲区溢出而损坏的“canary”。
这是微软采取的防止病毒通过缓冲区溢出注入自身的措施的一部分。 Visual Studio中用于C / C ++语言的/ GS编译选项。 一旦检测到,CRT就会非常迅速地终止程序。 这种情况发生时没有exception提升,堆栈无法安全解除,因为它已被泄露。 因此,CLR无法捕获exception。
此错误特定于TXT文件查看器。 除了不使用它之外,你无能为力。 将此错误报告给connect.microsoft.com可能没用,他们会将其关闭为“外部”。 这是一个微妙的提示,当您让非托管代码在您的程序中运行时会发生什么;)
我有同样的问题,我能够通过在x64而不是AnyCPU
编译来使TXT PreviewHandler工作。
我在Windows 7(64位)上使用Visual Studio 2010,因此如果您使用的是32位操作系统,则此答案将不适用。
在Visual Studio 2010中
- 单击
Configurations
下拉列表 - 选择
Configuration Manager...
- 单击项目旁边的“
Platform
单元格 - 选择
New...
并选择目标平台x64
- 从
AnyCPU
复制设置,然后离开。
它不太可能,但可能是这里的问题 – catch(Exception)将只捕获Exception类型的exception – 尝试使用catch w / o任何类型过滤。
catch(Exception ex) { // Normal logging etc } catch { // Exception of types other than System.Exception. }
我想我找到了解决这个问题的方法。 问题是你正在创建的流要么被垃圾收集器清理,要么被其他东西清理掉。 如果使用下面代码创建的流调用initialize方法,它应该工作:
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);
我在Windows窗体应用程序中使用上面的代码显式设置为32位(x86)并在单线程公寓模式下运行。
归功于Sherlock Homes( http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2010-09/msg00003.html )
- 在C#中使用https的HttpWebRequest
- IIS应用程序池回收触发器:没有足够的存储空间可用于完成此操作(Azure应用程序服务)
- Linq2Sql很多:很多问题,你会怎么做?
- “’:’字符,hex值0x3A,不能包含在名称中”
- 在没有第三方库的情况下设置Twitter OAuth
- 如何在.net代码中向GridView表添加圆角?
- UWP应用程序:无法加载文件或程序集’System.Runtime.WindowsRuntime,Version = 4.0.14.0
- 如何从字节数组创建Microsoft.Office.Interop.Word.Document对象,而不将其保存到磁盘?
- 将VS 2005解决方案文件(.sln)打开到内存中