C#COM函数的默认数组参数设置为null

时间:2013-07-16 09:57:41

标签: c# com

我正在将代码从VSTO移到ExcelDna,我遇到了一个奇怪的错误。

我在Visual Studio中创建了一个新项目,它将包含我以前的VSTO函数。为了生成.tlb文件,我将在Excel VBA中引用该文件以访问VBA中的这些函数,我选中了“注册COM互操作”选项

对于一个函数,我有错误:

“程序集”C:\ MyProj.dll“无法转换为类型库。类型库导出程序在处理'GetArrayObject'时遇到错误。错误:类型不匹配。”

Com可见界面中函数GetArrayObject的定义是:

[ComVisible(true)]
//[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IAddInUtilities
{
    object[,] GetArrayObject(string[] rows = null);
}

以下定义有效:

object[,] GetArrayObject(string[] rows);

这是COM中的已知限制吗?是否可能是由于C ++(Default values for array arguments)的限制?它是否适用于VSTO而不适用于COM?

非常感谢你的帮助

1 个答案:

答案 0 :(得分:3)

这不是一个很好的错误消息。在您的工作版本的界面上运行Oleview.exe文件+视图Typelib时,您可以看到问题。你会看到:

interface IAddInUtilities : IDispatch {
    [id(0x60020000)]
    HRESULT GetArrayObject(
                    [in] SAFEARRAY(BSTR) rows, 
                    [out, retval] SAFEARRAY(VARIANT)* pRetVal);
};

注意字符串[]是如何编组为SAFEARRAY的,它是数组的标准自动化类型。并注意它是如何通过值传递的,而不是通过引用传递的。这意味着它不能为空。否则,不支持为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 + Add Reference将其添加到项目中。不完全确定这仍然值得一点轻松的麻烦,你可以打电话。