默认数组参数设置为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?

非常感谢您的帮助

默认数组参数设置为null的C#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+添加引用将其添加到项目中。不太确定这是否仍然值得为一个小小的便利而烦恼,这取决于你打电话。