我正在努力研究如何訪問由C++應用程序提供的COM接口並從C#.NET應用程序中使用它。無法爲COM互操作包裝器投射Marshal.GetActiveObject的結果
我試圖從我的C#應用程序訪問我的COM對象(被正在運行的進程提供)這樣的:
object obj = Marshal.GetActiveObject("MyLibrary.Application");
MyLibrary.IMainApp app = (MyLibrary.IMainApp)obj;
的obj
值不爲null,但是當我嘗試將其強制轉換我得到System.InvalidCastException
。
我試着實現一個自定義的包裝,並鏈接到由TlbImp.exe
產生的DLL。兩者都產生了相同的例外。
似乎有很多關於interop的文檔,但它對我來說沒什麼意義 - 主要是因爲我不懂COM(我堅持保留其他人開發的代碼),並且正在進入可怕通過深入研究C#,.NET和WPF的世界。
這就是我對C++結束....
IDL文件
實際上,擴展名是.odl
。我不知道這是不是一回事。請注意,我把它換成了GUID的佔位符像GUID-1
,GUID-2
等 ...
import "oaidl.idl";
[ uuid(GUID-1), helpstring("My Type Library"), version(1.1) ]
library MyLibrary
{
importlib("stdole32.tlb");
// Primary dispatch interface for CMainApp
[ uuid(GUID-2) ]
dispinterface IMainApp
{
properties:
[id(1)] BOOL Mode;
methods:
[id(2)] void Quit();
[id(3)] void LogEventMessage(BSTR szMessageType, BSTR szMessage);
[id(4)] BOOL GetNoteDetails(BSTR szQualifiedName, BSTR* lpbstrOperator, DATE* lpdtDate);
};
// Class information for CMainApp
[ uuid(GUID-3) ]
coclass Application
{
[default] dispinterface IMainApp;
};
};
使用示例
當其他C++應用程序想要調用一個函數(如Quit
) ,他們這樣做:
CLSID clsid;
HRESULT hr;
LPUNKNOWN lpUnk;
LPDISPATCH lpDisp;
BOOL bReturn = FALSE;
// Get Class ID
if (CLSIDFromProgID(OLESTR("MyLibrary.Application"), &clsid) == S_OK)
{
// Get Active Object from ROT
if ((hr = GetActiveObject(clsid, NULL, &lpUnk)) == S_OK)
{
hr = lpUnk->QueryInterface(IID_IDispatch, (LPVOID*)&lpDisp);
lpUnk->Release();
if (hr == S_OK)
{
CMainApp oMainApp;
oMainApp.AttachDispatch(lpDisp);
TRY
{
oMainApp.Quit();
bReturn = TRUE;
}
CATCH(CException, e)
{
bReturn = FALSE;
}
END_CATCH
}
}
}
該類CMainApp
似乎已經由IDL編譯器自動生成。該文件被編譯到想要使用它的項目中,並且基本上完成了很多InvokeHelper
調用。我很高興接受這只是它的工作方式,我希望C#不太複雜。
嘗試包裹在C#
我接着在C#上COM互操作的MSDN指南。它建議我可以使用TlbImp.exe
,但是會有足夠的警告讓我失望。此外,我不想分發另一個DLL。所以我採取了寫封裝的另一種方法。
這是我寫的:
using System.Runtime.InteropServices;
namespace MyLibrary
{
// Declare MainApp COM coclass
[ComImport, Guid("GUID-3")]
class MainApp
{
}
[Guid("GUID-2"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
interface IMainApp
{
public void Quit();
public void LogEventMessage(
[In, MarshalAs(UnmanagedType.BStr)] string szMessageType,
[In, MarshalAs(UnmanagedType.BStr)] string szMessage);
public bool GetNoteDetails(
[In, MarshalAs(UnmanagedType.BStr)] string szQualifiedName,
[Out, MarshalAs(UnmanagedType.BStr)] out string lpbstrOperator);
out DateTime lpdtDate);
}
}
有人可以給我一個手理解?也許指出我犯了一個完全明顯的愚蠢錯誤? =)
看看這個,它可能會幫助你:http://stackoverflow.com/a/16209219/2095843 – mtsiakiris 2013-05-01 07:03:55