我有一个由 C# 制作的 dll,需要从现有的 native C++ exe 调用它。 学习了COM的基础,做了一个简单的例子。
但是,如果一个 C# 函数有一个引用类型(尤其是用户定义类的引用)参数,我是否可以为它编写一个接口(interface)并正常工作?
我在 Google 中搜索但得到的信息很少。
更新:
我试着写了一个,看到了它生成的 tlh 文件。
C#代码是
void Test2(ref float num);
而生成的tlh是
HRESULT Test2 ( float * num );
引用类型被转换为指针类型。似乎 COM 不支持引用类型。
最佳答案
正如汉斯所说,这个问题不是关于 reference types 的.关于 passing parameters by reference .
当您在任何语言中通过引用传递参数时,您就是在显式或隐式地使用指针。在 C# 中,ref
表示“此参数将采用指向已初始化数据的指针”。 out
声明“此参数将采用指向可能已初始化或未初始化的数据的指针。”通过使用 ref
或 out
,您可以使自己免受指针语义的影响。也就是说,您不必在方法签名中指定 float*
。但请放心,您仍在使用指针。
COM 完全支持通过引用传递参数。下面举个例子来说明。
C#:
[Guid("962232c8-90b2-4b61-8ef3-83298901c63e")]
[ComVisible(true)]
public interface ICSCOMCLASS
{
[DispId(1)]
void TestInParameter(double num);
[DispId(2)]
void TestRefParameter(ref double num);
}
编译后,您可以在生成的程序集上运行 tlbexp.exe
以导出 COM 类型库。然后,您可以通过在 oleview.exe
中打开 .tlb
文件来查看 IDL。
[
odl,
uuid(962232C8-90B2-4B61-8EF3-83298901C63E),
version(1.0),
dual,
oleautomation,
custom(0F21F359-AB84-41E8-9A78-36D110E6D2F9, "CSCOMLIB.ICSCOMCLASS")
]
interface ICSCOMCLASS : IDispatch
{
[id(0x00000001)]
HRESULT TestInParameter([in] double num);
[id(0x00000002)]
HRESULT TestRefParameter([in, out] double* num);
};
注意参数上的修饰符。关于您关于ref
参数的问题,请注意TestRefParameter()
方法的参数是[in, out] double* num
。这相当于 C# 的 ref double num
。
如果您从 C/C++ 使用此程序集或类型库(例如,通过使用 #import
语句),您将看到如下内容:
struct ICSCOMCLASS : IDispatch
{
virtual HRESULT __stdcall TestInParameter(double num) = 0;
virtual HRESULT __stdcall TestRefParameter(double* num) = 0;
};
COM 设计用于 C 级别及更高级别。大多数用于 C++ COM 工作的工具都被实现为使用 C(而非 C++)作为支持的基线。尽管 C++ 支持使用 &
传递引用(例如 HRESULT TestRefParameter(double& num)
,但 C 不支持。此外,C++ 的 &
不是与 C# 的 ref
和 out
一样具体。(大多数现代 C++ 编译器假定您希望在通过引用传递之前初始化数据,如果您这样做,它们将产生错误或警告不。)因此,在 C# 定义中定义为 ref
或 out
的任何参数将在 C++ 中简单地定义为指针。
关于c# - 是否可以通过 COM 公开引用类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50576949/