2016-09-13 101 views
3

當試圖將接口作爲參數從.NET傳遞到DLL時,我得到一個System.InvalidCastException運行時錯誤。代碼在.NET方面失敗了,從來沒有交給Delphi方面。將COM接口傳遞迴庫的正確方法是什麼?

在Delphi中構建一個簡單的ActiveX庫dll。兩個自動化對象:MyContentMyContainerMyContainer具有單一方法Add,其需要由IMyContent繼承的IBase接口。 IBaseIDispatch

[ 
    uuid(E29018FF-F142-4BAE-B7A4-AE0A8847E930), 
    version(1.0) 

] 
library DelphiComLib 
{ 

    importlib("stdole2.tlb"); 

    interface IMyBase; 
    interface IMyContainer; 
    coclass MyContainer; 
    interface IMyContent; 
    coclass MyContent; 


    [ 
    uuid(07D17021-9E7F-4D7A-B861-59A35EC686A0), 
    dual, 
    oleautomation 
    ] 
    interface IMyBase: IDispatch 
    { 
    }; 

    [ 
    uuid(A6AB6F7D-8BEB-459F-A2F8-BC06FF81A45D), 
    helpstring("Dispatch interface for MyContainer Object"), 
    dual, 
    oleautomation 
    ] 
    interface IMyContainer: IDispatch 
    { 
    [id(0x000000C9)] 
    HRESULT _stdcall Add([in] IMyBase* AMyBase); 
    }; 

    [ 
    uuid(AB82964C-13D7-423B-9B16-A789D5D30421), 
    helpstring("Dispatch interface for MyContent Object"), 
    dual, 
    oleautomation 
    ] 
    interface IMyContent: IMyBase 
    { 
    }; 

    [ 
    uuid(DDDF77E5-E6A6-4429-BD4A-D9695E9E6CED), 
    helpstring("MyContainer Object") 
    ] 
    coclass MyContainer 
    { 
    [default] interface IMyContainer; 
    }; 

    [ 
    uuid(134BF8B2-30C3-4C37-8F74-3F677808300A), 
    helpstring("MyContent Object") 
    ] 
    coclass MyContent 
    { 
    [default] interface IMyContent; 
    }; 

}; 

類的實現並不重要。爲了保持最小的樣本,Add的實現可以留空。這裏是集裝箱

unit Unit1; 

{$WARN SYMBOL_PLATFORM OFF} 

interface 

uses 
    ComObj, ActiveX, DelphiComLib_TLB, StdVcl; 

type 
    TMyContainer = class(TAutoObject, IMyContainer) 
    protected 
    procedure Add(const AMyBase: IMyBase); safecall; 

    end; 

implementation 

uses ComServ; 

procedure TMyContainer.Add(const AMyBase: IMyBase); 
begin 

end; 

initialization 
    TAutoObjectFactory.Create(ComServer, TMyContainer, Class_MyContainer, 
    ciMultiInstance, tmApartment); 
end. 

...和內容

unit Unit2; 

{$WARN SYMBOL_PLATFORM OFF} 

interface 

uses 
    ComObj, ActiveX, DelphiComLib_TLB, StdVcl; 

type 
    TMyContent = class(TAutoObject, IMyContent) 
    protected 

    end; 

implementation 

uses ComServ; 

initialization 
    TAutoObjectFactory.Create(ComServer, TMyContent, Class_MyContent, 
    ciMultiInstance, tmApartment); 
end. 

註冊庫並添加引用到一個控制檯應用程序。如果我在實現IBase我可以通過接口回成功.NET創建一個類,下面的代碼將產生運行時錯誤

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using DelphiComLib; 
namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      IMyContainer container = new MyContainer(); 
      IMyContent content = new MyContent(); 
      container.Add(content); 


     } 
    } 
} 

這裏是.NET

堆棧跟蹤
at System.StubHelpers.InterfaceMarshaler.ConvertToNative(Object objSrc, IntPtr itfMT, IntPtr classMT, Int32 flags) 
    at DelphiComLib.IMyContainer.Add(IMyBase AMyBase) 
    at ConsoleApplication2.Program.Main(String[] args) in c:\users\jaspers\documents\visual studio 2015\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 15 
    at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 

回答

2

您的問題無關的接口是如何傳遞到您的COM DLL。

錯誤System.InvalidCastException僅僅是因爲從Delphi實現端投射IMyContentIMyBase失敗。原因是嚴格地說你的實現並不直接實現IMyBase接口(儘管它實現了派生的IMyContent接口)。你可以嘗試一下:

var 
    MyContent: IMyContent; 
    MyBase: IMyBase; 
begin 
    MyContent := CoMyContent.Create; 
    MyBase := MyContent as IMyBase; // EIntfCastError is raised 
end; 

你的實現類必須實現IMyBase明確的鑄造工作:

Implement all interfaces explicitly

這將改變你的實現類的聲明:

type 
    TMyContent = class(TAutoObject, IMyContent, IMyBase) 
    ... 
    end; 

這反過來將使任何COM clie的鑄造工作nt代碼(Delphi,C++,.NET等)

相關問題