默认数组参数设置为null的C#COM函数
本文关键字:C#COM 函数 null 数组 参数 设置 默认 | 更新日期: 2023-09-27 18:22:25
我正在将代码从VSTO移动到ExcelDna,遇到了一个奇怪的错误。
我在Visual Studio中创建了一个新项目,该项目将包含我以前的VSTO函数。为了生成.tlb文件,然后我将在Excel VBA中引用该文件,以访问VBA中的这些函数,我选中了选项"注册COM互操作"
对于一个功能,我有错误:
程序集"C:''MyProj.dll"无法转换为类型库。类型库导出程序在处理"GetArrayObject"时遇到错误。错误:类型不匹配。
Com-visible接口中函数GetArrayObject的定义为:
[ComVisible(true)]
//[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAddInUtilities
{
object[,] GetArrayObject(string[] rows = null);
}
以下定义有效:
object[,] GetArrayObject(string[] rows);
这是COM中已知的限制吗?这可能是由于C++(数组参数的默认值)中的限制吗?它是否适用于VSTO而不适用于COM?
非常感谢您的帮助
这不是一个好的错误消息。当您在接口的工作版本上运行Oleview.exe File+View Typelib时,您可以看到问题。你会看到:
interface IAddInUtilities : IDispatch {
[id(0x60020000)]
HRESULT GetArrayObject(
[in] SAFEARRAY(BSTR) rows,
[out, retval] SAFEARRAY(VARIANT)* pRetVal);
};
请注意字符串[]是如何封送为SAFEARRAY(数组的标准Automation类型)的。注意它是如何通过值而不是通过引用传递的。这意味着它不能为null。否则就不支持为SAFEARRAY指定默认值。
您必须通过引用传递数组,C#中的ref关键字。但是,您会遇到C#语言规则的问题,您不能再指定默认值了。
下一次尝试是强制将数组封送为指针BSTR*。这与SAFEARRAY相反,因为COM服务器再也无法从普通指针中计算出数组中元素的数量,因此您现在必须添加一个额外的参数来说明数组中的元素数量。像这样:
public interface IAddInUtilities {
object[,] GetArrayObject(
int rowcnt,
[MarshalAs(UnmanagedType.LPArray)]string[] rows = null
);
它转换得很好。然而,当您现在使用Oleview.exe查看类型库时,您会看到:
interface IAddInUtilities : IDispatch {
[id(0x60020000)]
HRESULT GetArrayObject(
[in] long rowcnt,
[in, optional, defaultvalue("")] BSTR* rows,
[out, retval] SAFEARRAY(VARIANT)* pRetVal);
};
啊,错误的默认值。您唯一的其他选择是使用从Oleview.exe获得的IDL,编辑它以更改defaultvalue(),使用midl.exe编译它以生成类型库,并使用Tlbimp.exe生成互操作库。然后可以使用project+添加引用将其添加到项目中。不太确定这是否仍然值得为一个小小的便利而烦恼,这取决于你打电话。