Не удается создать экземпляр управления PDF-браузером из AcroPDF.dll с помощью взаимодействия COM и .NET - PullRequest
1 голос
/ 24 апреля 2010

Когда я пытаюсь создать экземпляр элемента управления браузером PDF, как это в C #:

AcroPDFLib.AcroPDFClass acrobat = new AcroPDFLib.AcroPDFClass();

Я получаю COMException с этим сообщением:

Создание экземпляра компонента COM с CLSID {CA8A9780-280D-11CF-A24D-444553540000} из IClassFactory не удалось из-за следующей ошибки: 80004005.

Я сделал ссылку на AcroPDF.dll с именем компонента Библиотека типов элементов управления браузера Adobe Acrobat 7.0 1.0 .

Когда я запускаю Visual C # 2008 Express Edition от имени Администратор Я получаю еще одно сообщение об ошибке:

Невозможно привести объект COM типа «AcroPDFLib.AcroPDFClass» к типу интерфейса «AcroPDFLib.IAcroAXDocShim». Эта операция завершилась неудачно, поскольку вызов QueryInterface для компонента COM для интерфейса с IID '{3B813CE7-7C10-4F84-AD06-9DF76D97A9AA}' завершился ошибкой из-за следующей ошибки: такой интерфейс не поддерживается (Исключение из HRESULT: 0x80004002 (E_NOINTERFACE)) .

Это происходит на следующей строке, когда я пытаюсь использовать объект:

acrobat.LoadFile("book.pdf");

Я не могу понять, что не так. Помощь наиболее ценится!

Ответы [ 2 ]

4 голосов
/ 24 апреля 2010

.net COM-взаимодействие не направляет все COM-сообщения непосредственно обратно к вызывающей стороне. Если вы вызвали COM из STA, он не поймет, как ваше приложение может справиться с повторным входом. Это означает, что сообщения об ошибках, которые могут быть обработаны с повторной попыткой, в конечном итоге вызывают исключения.

Попробуйте реализовать интерфейс IMessageFilter . Это позволит COM понять, как передавать сообщения обратно в ваше приложение. В частности, реализуйте RetryRejectedCall и проверьте, указывают ли ошибки и, возможно, возвращают ли значение тайм-аута (что-то вроде 1000 мс), чтобы COM мог повторить попытку после короткой паузы.

Это тип COM, поэтому этот код вам понадобится для определения интерфейса:

[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000016-0000-0000-C000-000000000046")]
public interface IMessageFilter
{
    [PreserveSig]
    int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);

    [PreserveSig]
    int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);

    [PreserveSig]
    int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}

И это пример того, как вы бы это реализовали:

public class MyMessageFilter : IMessageFilter
{
    int IMessageFilter.HandleInComingCall(int dwCallType, IntPtr hTaskCaller,int dwTickCount, IntPtr lpInterfaceInfo)
    {
        // 0 means that it's handled.
        return 0;
    }

    int IMessageFilter.RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
    {
        // The return value is the delay (in ms) before retrying.
        return 1000;
    }

    int IMessageFilter.MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
    {
        // 1 hear means that the message is still not processed and to just continue waiting.
        return 1;
    }
}

После того, как вы внедрили фильтр сообщений, вам необходимо зарегистрировать его, используя CoRegisterMessageFilter . Это регистрация для каждого потока, поэтому знайте, в каком потоке вы ее вызываете. Подпись PInvoke: :

[DllImport("ole32.dll")]
static extern int CoRegisterMessageFilter(IMessageFilter lpMessageFilter, out IMessageFilter lplpMessageFilter);

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

[Помните, что IMessageFilter, о котором я здесь говорю, отличается от System.Windows.Forms.IMessageFilter , поэтому убедитесь, что вы случайно не используете winforms.]

2 голосов
/ 24 апреля 2010

Ниже приведены инструкции по использованию элемента управления Adobe PDF Reader:

  1. Создание нового приложения Windows Forms: Файл & rarr; Новый проект & hellip; & Rarr; Приложение Windows Forms & rarr; OK
  2. Добавить ссылку на библиотеку типов элементов управления браузера Adobe Acrobat 7.0 1.0: Project & rarr; Добавить ссылку & hellip; & Rarr; COM & rarr; Adobe Acrobat 7.0 Browser Control Type Library 1.0 & rarr; OK
  3. Добавьте элемент управления Adobe PDF Reader на панель инструментов: Инструменты & rarr; Выберите ToolBox Items & hellip; & Rarr; COM-компоненты & rarr; Adobe PDF Reader & rarr; OK
  4. Перетащите элемент управления Adobe PDF Reader из панели инструментов в форму

Я не уверен, почему, но мне нужно запустить Microsoft Visual C # 2008 Express Edition с правами администратора, чтобы это работало. С ограниченным пользователем я получаю это сообщение в конструкторе:

Ошибка HRESULT E_FAIL возвращена после вызова COM-компонента.

Обратите внимание, что после добавления элемента управления Adobe PDF Reader к вашей панели инструментов была создана новая сборка взаимодействия .NET с именем AxInterop.AcroPDFLib.dll . Ссылка на эту новую сборку была добавлена ​​к ссылкам вашего проекта.

Справочная документация по API для элемента управления Adobe PDF Reader находится здесь: http://icio.us/ajukkr

В этой ветке форума содержится еще несколько полезной информации: http://forums.adobe.com/thread/438362

...