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

发布于 2024-08-30 05:48:27 字数 816 浏览 6 评论 0 原文

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

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

我收到带有以下消息的 COMException

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

我引用了 AcroPDF.dll组件名称​​Adobe 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");

我无法弄清楚出了什么问题。帮助最感激!

When I try to instantiate a PDF browser control like this in C#:

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

I get a COMException with this message:

Creating an instance of the COM component with CLSID {CA8A9780-280D-11CF-A24D-444553540000} from the IClassFactory failed due to the following error: 80004005.

I have made a reference to AcroPDF.dll which has the component name Adobe Acrobat 7.0 Browser Control Type Library 1.0.

When I run Visual C# 2008 Express Edition as administrator I get another error message:

Unable to cast COM object of type 'AcroPDFLib.AcroPDFClass' to interface type 'AcroPDFLib.IAcroAXDocShim'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{3B813CE7-7C10-4F84-AD06-9DF76D97A9AA}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).

This happens at the next line when I try to use the object:

acrobat.LoadFile("book.pdf");

I can't figure out what is wrong. Help most appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

无言温柔 2024-09-06 05:48:27

.net COM 互操作不会将所有 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 签名是

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

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

[请注意,我在这里指的 IMessageFilter 与 System.Windows.Forms.IMessageFilter,因此请确保您不会意外使用 winforms。]

.net COM interop doesn't route all COM messages directly back to the caller. If you called COM from an STA, it won't understand how you app can handle re-entrance. This means that failure messages that could just be handled with a retry, end up causing exceptions.

Try implementing IMessageFilter interface. This will allow COM to understand how to pass messages back to your app. In particular, implement the RetryRejectedCall and check if the failure flags and possibly return a timeout value (something like 1000ms) to allow COM to retry after a brief pause.

It's a COM type, so this is the code you'll need to define the interface:

[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);
}

And this is an example of how you would implement it:

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;
    }
}

Once you've implemented a message filter you will need to register it using CoRegisterMessageFilter. This is a per-thread registration, so be aware of what thread you are calling it on. The PInvoke signiture is:

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

Even if this doesn't work, at the very least, if you log all the messages in the filter you should hopefully get some more information about what is going wrong. Look at the values of the parameters being passed into the message filter. If you look them up they will relate to error/state codes.

[Be aware, the IMessageFilter I'm referring to here is different from the System.Windows.Forms.IMessageFilter, so make sure you don't accidentally use the winforms one.]

美羊羊 2024-09-06 05:48:27

以下是使用 Adob​​e PDF Reader 控件的步骤:

  1. 创建新的 Windows 窗体应用程序:文件 → 新建项目…→ Windows 窗体应用程序 → 确定
  2. 添加对 Adob​​e Acrobat 7.0 浏览器控件类型库 1.0 的引用:项目→添加引用...→COM→Adobe Acrobat 7.0浏览器控件类型库1.0→确定
  3. 将Adobe PDF Reader控件添加到工具箱:工具→选择工具箱项目...→COM组件→Adobe PDF Reader → 确定
  4. 将 Adob​​e PDF Reader 控件从工具箱拖到窗体中。

我不知道为什么,但我必须以管理权限运行 Microsoft Visual C# 2008 Express Edition 才能使其正常工作。对于有限的用户,我在设计器中收到以下消息:

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

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

Adobe PDF Reader 控件的 API 参考文档位于此处: http://icio.us/ajukkr

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

These are the steps to use the Adobe PDF Reader control:

  1. Create a new Windows Forms Application: File → New Project… → Windows Forms Application → OK
  2. Add a reference to the 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. Add the Adobe PDF Reader control to the Toolbox: Tools → Choose ToolBox Items… → COM Components → Adobe PDF Reader → OK
  4. Drag an Adobe PDF Reader control from your toolbox into the Form

I'm not sure why but I have to run Microsoft Visual C# 2008 Express Edition with administrative privileges to get this working. With a limited user I get this message in the designer:

Error HRESULT E_FAIL has been returned from a call to a COM component.

Note that after adding the Adobe PDF Reader control to your toolbox a new .NET interop assembly has been created with the name AxInterop.AcroPDFLib.dll. A reference to this new assembly has been added to your project references.

API reference documentation for the Adobe PDF Reader control is located here: http://icio.us/ajukkr

This forum thread provides some more useful information: http://forums.adobe.com/thread/438362

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文