我正在努力研究如何访问 C++ 应用程序提供的 COM 接口并从 C# .NET 应用程序中使用它。
我尝试从我的 C# 应用程序访问我的 COM 对象(由正在运行的进程提供),如下所示:
object obj = Marshal.GetActiveObject("MyLibrary.Application");
MyLibrary.IMainApp app = (MyLibrary.IMainApp)obj;
的值obj
是非空的,但是当我尝试转换它时,我得到System.InvalidCastException
.
我尝试实现自定义包装器并链接到由TlbImp.exe
. 两者都产生了相同的异常。
似乎有很多关于互操作的文档,但这对我来说没有意义——主要是因为我不精通 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 );
}
}
有人可以帮我理解一下吗?也许指出我犯的一个完全明显的愚蠢错误?=)