2010-08-30 5 views
3

Я импортировал COM-интерфейс IPreviewHandler в приложение WinForms и использую его для отображения превью для различных типов документов (я просматриваю GUID соответствующего обработчика предпросмотра в реестре, а затем используйте Activator.CreateInstance(guid) для экземпляр определенного класса COMIPreviewHandler выдает исключение uncatchable

Это работает удивительно для подавляющего большинства типов файлов -. форматов Office, PDF-файлы, видео и т.д. - однако, после того, как я экземпляр «Microsoft Windows TXT Preview Handler» {1531d583-8375-4d3f-b5fb-d23bbd169f22}, отформатируйте ее с поток, содержащий обычный .txt-файл, устанавливает границы окна предварительного просмотра, а затем, наконец, вызывает DoPreview(), я получаю исключение, которое невозможно поймать с помощью 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 
} 

Когда я пошагово с отладчиком, то Visual Studio хостинг Process аварий. Без отладчика приложение аварийно завершает работу, не запуская события AppDomain.UnHandledException или Application.ThreadException.

На самом деле я не имею в виду, что я не могу просматривать текстовые файлы, используя эту технику (рабочие обработчики предварительного просмотра для форматов Office и т. Д. Достаточны для требований моего приложения), но я обеспокоен тем, если пользователь выбирает файл .txt. Есть ли способ поймать эту ошибку и обработать ее изящно? Еще лучше, можно ли каким-то образом преодолеть это и заставить обработчик работать?

+0

Отсутствует тип библиотеки. Как вы «импортировали» объявления интерфейса? –

+0

@Hans Passant: объявление вручную с использованием атрибутов '[ComImport]' и '[Guid]'. Посмотрите исходный код в своем блоге: http://www.brad-smith.info/blog/archives/79 –

ответ

6

Я не мог получить GetPreviewHandlerGUID(), чтобы распознать файл .txt и пришлось вводить GUID непосредственно. Вы можете увидеть, что пойдет не так, когда вы используете Project + Properties, Debug, tick. Включите неуправляемую отладку кода.

отладчик теперь остановится на проблеме и отображения

`STATUS_STACK_BUFFER_OVERRUN столкнулись

В верхней части стека вызовов выглядит следующим образом:

[email protected]() + 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 
[email protected]() + 0x13d bytes 

Проблема находится в функции StreamInCallback(). Он вызывается RichTextBox, который используется для отображения предварительного просмотра (msftedit.dll) для загрузки файла. Код в этой функции обратного вызова имеет ошибку, он уничтожает «канарейку», которая используется для обнаружения того, что фрейм стека поврежден из-за переполнения буфера.

Это часть контрмер, предпринятых Microsoft для предотвращения проникновения вирусов самим путем переполнения буфера. Параметр/GS компиляции в Visual Studio для языков C/C++. После обнаружения CRT очень быстро завершает программу. Это происходит без какого-либо исключения, вызванного сбоем, стек не может быть безопасно размотан, потому что он был скомпрометирован. Соответственно, CLR не может устранить исключение.

Эта ошибка относится только к средству просмотра файлов TXT. Вы ничего не можете с этим поделать, кроме как не использовать его. Сообщать об этой ошибке на connect.microsoft.com, вероятно, не полезно, они закрывают ее как «внешнюю».В противном случае это тонкий намек на то, что может произойти, если вы допустили неуправляемый код в вашей программе;)

+0

Спасибо, ваш ответ, конечно, проливает некоторый свет на него. Я заметил, что обработчик предварительного просмотра Windows TXT, по сути, не связан с расширением .txt в Windows 7, только в Vista.Возможно, MS поняла, что разрешить сторонним приложениям размещать этот глючный обработчик - плохая идея? Я мог бы просто занести в черный список этот CLSID в своем приложении. –

+0

какой отличный ответ. Брэдли Смит, вы писали свой собственный обработчик для txt-файлов? Или как вы обошли эту проблему? – SwissCoder

+0

Необратимое исключение, похоже, также бросается на файлы * .reg * .bat и * .vbs. –

0

Его очень маловероятно, но может быть проблема здесь - catch (Exception) поймает только исключения типа Exception - попробуйте использовать catch без фильтрации любого типа.

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

Скорее неудивительно, но это не работает. Я также уверен, что CLR по определению не может поймать ничего, кроме 'System.Exception'. Если возникает какое-то низкоуровневое исключение, «Маршал» должен бросить «COMException» или «Win32Exception». –

+0

Я согласен - должно было быть COMException. FYI, я прочитал в книге J Ritcher, что CLR не предусматривает, чтобы объект исключения имел тип System.Exception, но языки (C#, Vb.NET) не поддерживают его. Еще один длинный вариант для вашей проблемы - если вы используете .NET4, проверьте, не попали ли вы в поврежденные исключения из состояния - поскольку они должны маркировать ваш код с помощью атрибута HandleProcessCorruptedStateExceptions. – VinayC

+0

Все еще живем в .NET 2.0, к сожалению. Можете дать эту попытку в изолированном проекте, который нацелен на .NET 4 ... –

1

У меня была такая же проблема, и я смог получить TXT PreviewHandler, работая, компилируя в x64 вместо AnyCPU.

Я использую Visual Studio 2010 на Windows 7 (64 бит), поэтому этот ответ не будет применяться, если вы находитесь в 32-битной ОС.

В Visual Studio 2010

  • нажмите на Configurations выпадающий список
  • выберите Configuration Manager...
  • нажмите на Platform ячейку рядом с вашим проектом
  • выберите New... и выберите целевую платформу x64
  • Настройки копирования от AnyCPU и прочь вы идете.
0

Я думаю, что нашел решение этой проблемы. Дело в том, что создаваемый вами поток очищается сборщиком мусора или чем-то еще. Если вызвать метод инициализации с использованием потока, созданного с помощью кода ниже, он должен работать:

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 Forms Application явно установлен на 32-битной (x86) и работает в однопоточных Режим апартаментов.

Заслуга Sherlock Homes (http://www.tech-archive.net/Archive/DotNet/microsoft.public.dotnet.framework.interop/2010-09/msg00003.html)

Смежные вопросы