2013-10-20 62 views
1

這是從我的previous post開始的後續操作。閱讀該文章的上下文。請注意,它不是嚴格的COM互操作 - 但C++接口是COM兼容的。在COM互操作中不從C++調用的返回管理對象方法

我試着去實現這個C++在C#接口

class IPluginFactory : public FUnknown 
{ 
    virtual tresult PLUGIN_API createInstance (FIDString cid, FIDString iid, void** obj) = 0; 
}; 

我的C#代碼如下所示:

[ComImport] 
[Guid(Interfaces.IPluginFactory)] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IPluginFactory 
{ 
    [PreserveSig] 
    [return: MarshalAs(UnmanagedType.Error)] 
    Int32 CreateInstance([In] ref Guid classId, [In] ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown), In, Out] ref object instance); 
} 

實施一個新的對象實例分配給 '實例' 參數,返回0 (S_OK)。我甚至投射到預期的(託管)界面。

instance = (IPluginBase)new PluginBase(); 
return 0; 

返回的對象是由這個C表示++接口:

class IPluginBase: public FUnknown 
{ 
public: 
    virtual tresult PLUGIN_API initialize (FUnknown* context) = 0; 
    virtual tresult PLUGIN_API terminate() = 0; 
}; 

它看起來像這樣在我的C#實現:

[ComImport] 
[Guid(Interfaces.IPluginBase)] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IPluginBase 
{ 
    [PreserveSig] 
    [return: MarshalAs(UnmanagedType.Error)] 
    Int32 Initialize([MarshalAs(UnmanagedType.IUnknown), In] object context); 

    [PreserveSig] 
    [return: MarshalAs(UnmanagedType.Error)] 
    Int32 Terminate(); 
} 

在非託管C++測試應用程序我寫的,我可以成功調用createInstance並接收代碼用作IPluginBase *的非空指針。

當我嘗試調用此IPluginBase *指針的「初始化」方法時,問題就出現了。它永遠不會到達託管代碼(沒有發生斷點 - 其他斷點工作正常),返回碼是0x80004003。它看起來像包裝在這裏做一些攔截...

我的問題是:CreateInstance的託管表示形式的聲明是否正確? 我在這裏錯過了什麼? (這應該是普通的香草互通,不是嗎?)

其他關於申報'風格'的建議也受到歡迎。 Thanx,Marc。 Thanx,Marc。

編輯:問題似乎在於createInstance方法。我無法獲取iid參數要求返回的接口。

[PreserveSig] 
[return: MarshalAs(UnmanagedType.Error)] 
Int32 CreateInstance([In] ref Guid classId, [In] ref Guid interfaceId, [MarshalAs(UnmanagedType.IUnknown, IidParameterIndex = 1), In, Out] ref object instance); 

我也曾嘗試UnmanagedType.Interface結合的IidParameterIndex但兩者導致的IUnknown被編回來。如果我重新查詢IPluginBase接口,則IPluginBase :: initialize方法將工作(託管代碼中的斷點命中)。

+0

這就是E_POINTER,「無效的指針」。對你傳遞的觀點不滿意,不傳null。很難猜測「背景」可能是什麼。請與此代碼的作者聯繫以獲得支持。 –

+0

爲什麼你不能傳遞NULL作爲參數值?是否有可用的'AllowNull'屬性? ;-)'上下文'是一個IUnknown *。代碼的作者是我 - 那就是C++接口定義是我試圖在.NET中進行互操作的第三方標準。 – obiwanjacobi

回答

1

編輯:問題似乎在於createInstance方法。我是 無法獲得由iid 參數要求返回的接口。

指定IidParameterIndex在這裏沒有幫助。你的實施createInstance應該看起來像這樣:

public int createInstance(ref Guid classId, ref Guid riid, ref IntPtr instance) 
{ 
    if (instance != IntPtr.Zero) 
     return E_POINTER; 

    // substitute your actual object creation code for CreateObject 
    object obj = CreateObject(classId) 

    // return the correct interface 
    IntPtr unk = Marshal.GetIUnknownForObject(obj); 
    try 
    { 
     return Marshal.QueryInterface(unk, ref riid, out instance); 
    } 
    finally 
    { 
     Marshal.Release(unk); 
    } 
} 
+1

啊,拍!有沒有辦法得到這個對象作爲返回(出)類型的工作?你的解決方案確實有效感謝名單! – obiwanjacobi

+0

我不知道有更好的方法,剛剛處理了[類似問題](http://stackoverflow.com/questions/19351840/is-there-any-purpose-of-comdefaultinterface-for-a- COM可調用的包裝器)。 – Noseratio