无法使用COM和.NET互操作从AcroPDF.dll实例化PDF浏览器控件

时间:2010-04-23 21:48:22

标签: c# com interop activex acrobat

当我尝试在C#中实例化这样的PDF浏览器控件时:

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

我收到COMException这条消息:

  

由于以下错误,从IClassFactory创建具有CLSID {CA8A9780-280D-11CF-A24D-444553540000}的COM组件实例失败:80004005。

我引用了 AcroPDF.dll ,其组件名称为 Adob​​e Acrobat 7.0浏览器控件类型库1.0

当我以管理员运行Visual C#2008 Express Edition时,我收到另一条错误消息:

  

无法将“AcroPDFLib.AcroPDFClass”类型的COM对象强制转换为接口类型“AcroPDFLib.IAcroAXDocShim”。此操作失败,因为IID为“{3B813CE7-7C10-4F84-AD06-9DF76D97A9AA}”的接口的COM组件上的QueryInterface调用由于以下错误而失败:不支持此类接口(HRESULT异常:0x80004002(E_NOINTERFACE))

当我尝试使用该对象时,会发生在下一行:

acrobat.LoadFile("book.pdf");

我无法弄清楚出了什么问题。非常感谢!

2 个答案:

答案 0 :(得分:4)

.net COM interop不会将所有COM消息直接路由回调用方。如果您从STA调用COM,它将无法理解您的应用程序如何处理重新进入。这意味着可以通过重试处理的失败消息最终导致异常。

尝试实施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 signiture is

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

即使这不起作用,至少,如果您记录过滤器中的所有消息,您应该希望获得有关出错的更多信息。查看传递给消息过滤器的参数的值。如果您查找它们,它们将与错误/状态代码相关。

[请注意,我在这里指的IMessageFilter与System.Windows.Forms.IMessageFilter不同,所以请确保你不小心使用winforms。]

答案 1 :(得分:2)

以下是使用Adobe PDF Reader控件的步骤:

  1. 创建新的Windows窗体应用程序:文件→新建项目...→Windows窗体应用程序→确定
  2. 添加对Adobe Acrobat 7.0 Browser Control Type Library 1.0的引用: Project→Add Reference ...→COM→Adobe Acrobat 7.0 Browser Control Type Library 1.0→OK
  3. 将Adobe PDF Reader控件添加到工具箱:工具→选择工具箱项...→COM组件→Adobe PDF阅读器→确定
  4. 将Adobe PDF Reader控件从工具箱拖到窗体
  5. 我不确定为什么,但我必须运行具有管理权限的Microsoft Visual C#2008 Express Edition才能使其正常运行。对于有限的用户,我在设计师中收到此消息:

      

    错误HRESULT E_FAIL已从调用COM组件返回。

    请注意,在将Adobe PDF Reader控件添加到工具箱后,已创建名为 AxInterop.AcroPDFLib.dll 的新.NET互操作程序集。对您的项目引用添加了对此新程序集的引用。

    Adob​​e PDF Reader控件的API参考文档位于:http://icio.us/ajukkr

    此论坛主题提供了一些更有用的信息:http://forums.adobe.com/thread/438362