2010-04-23 82 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