IPreviewHandler выдает неуловимое исключение - PullRequest
3 голосов
/ 30 августа 2010

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

Это прекрасно работает для подавляющего большинства типов файлов - форматов Office, PDF, видео и т. д. - однако после создания экземпляра «Обработчик предварительного просмотра TXT в Microsoft Windows»"{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. При отсутствии отладчика происходит сбой приложения без запуска событий AppDomain.UnHandledException или Application.ThreadException.

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

Ответы [ 5 ]

7 голосов
/ 31 августа 2010

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

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

`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) для загрузки файла.В коде этой функции обратного вызова есть ошибка, она уничтожает «канарейку», которая используется для обнаружения повреждения фрейма стека из-за переполнения буфера.

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

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

2 голосов
/ 14 января 2019

Реальная причина возникновения этой проблемы заключается в том, что вы создаете объект обработчика предварительного просмотра в процессе .Правильный способ - создать его вне процесса .

DISCLOSURE Ниже приводится реклама моего блога / фрагмента кода.

См.https://github.com/GeeLaw/PreviewHost для примера.В частности, см. Строка 219 файла PreviewHandler.cs , где вы должны передать CLSCTX_LOCAL_SERVER в CoCreateInstance.Как объяснено в одна из моих записей в блоге , Activator.CreateInstance разрешает внутрипроцессный сервер, который не соответствует ожиданию обработчиков предварительного просмотра, поскольку они должны быть созданы в правильном суррогатном процессе, как описано на MSDN .

1 голос
/ 05 октября 2012

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

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

В Visual Studio 2010

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

Я думаю, что нашел решение этой проблемы.Дело в том, что создаваемый вами поток очищается сборщиком мусора или чем-то еще.Если вы вызываете метод 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 Forms, для которого явно задано значение 32bit (x86), и он работает в режиме Single-Потоковый режим квартир.

Кредит поступает в дома Шерлока (http://www.tech -archive.net / Архив / DotNet / microsoft.public.dotnet.framework.interop / 2010-09 / msg00003.html )

0 голосов
/ 30 августа 2010

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

catch(Exception ex) {
   // Normal logging etc
}
catch
{
   // Exception of types other than System.Exception.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...