2010-04-23 155 views
1

实例从AcroPDF.dll PDF浏览器控件当我尝试实例在C#这样的PDF浏览器控件:无法使用COM和.NET互操作

​​

我得到一个COMException此消息:

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

我做出了AcroPDF.dll具有组件名称安装Adobe Acrobat 7.0浏览器控件的类型库1.0参考。

当我运行Visual C#2008 Express Edition的作为管理员我收到其他错误消息:

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)).

这种情况下一行,当我尝试使用对象:

acrobat.LoadFile("book.pdf"); 

我无法弄清楚什么是错的。最赞赏的帮助!

回答

2

这些都是使用Adobe PDF阅读器控件的步骤:

  1. 创建一个新的Windows窗体应用程序:文件→新建项目… → Windows窗体应用程序→ OK
  2. 添加到Adobe的Acrobat 7.0浏览器控件的类型库1.0的引用:项目→添加引用… → COM →安装Adobe Acrobat 7.0浏览器控件的类型库1.0 → OK
  3. 在Adobe PDF阅读器控件添加到工具箱:工具→选择工具箱项… → COM组件→的Adobe PDF阅读器→ OK
  4. 拖动从工具箱一个Adobe PDF阅读器控制到表格

我不知道为什么,但我要运行的Microsoft Visual C#2008年行政快捷版获得这项工作的特权。用有限的用户,我得到在设计这条消息:

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

注意添加的Adobe PDF阅读器控件工具箱后,一个新的.NET互操作程序集已名为AxInterop.AcroPDFLib.dll创建。对此新组件的引用已添加到您的项目参考中。适用于Adobe PDF阅读器控制

API参考文档位于:http://icio.us/ajukkr

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

+0

我很好奇这个新创建的互操作程序集。如果有人能解释为什么这是必要的,我会很感激。控件是否必须托管在某个容器内?是否可以在脚本方案中使用该控件?这个JScript像原始问题中的例子一样失败:WScript.CreateObject(“AcroPDFLib.AcroPDF”) – knut 2010-04-24 13:59:44

4

.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 signiture is

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

即使这是不行的,至少是,如果您登录在过滤器中的所有邮件,你应该希望得到关于什么错误一些更多的信息。查看传递给消息过滤器的参数的值。如果你查看它们,它们将涉及错误/状态代码。

[请注意,我在这里提到的IMessageFilter不同于System.Windows.Forms.IMessageFilter,所以请确保您不会意外地使用winforms。]

+0

是对IMessageFilter C++接口?如果是这样,我需要提到我不是一名C++程序员,并且可能会在我头上实现这一点。 – knut 2010-04-23 22:16:22

+1

@knut,是的,IMessageFilter是一个COM接口。我已经添加了您需要的所有代码。让我知道如果你卡住了。 – 2010-04-23 22:30:05

+0

我想我已经按照你的步骤。我已经在每个处理程序中放了一个断点。没有中断点被击中。我在这里粘贴了我的代码:http://codepaste.net/b9ody9。我做错了什么? – knut 2010-04-23 22:46:46