2

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

我在 Visual Studio 中创建了一个新项目,其中将包含我以前的 VSTO 函数。为了生成 .tlb 文件,然后我将在 Excel VBA 中引用该文件以访问 VBA 中的这些函数,我选中了“Register for COM interop”选项

对于一个功能,我有错误:

“程序集“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++ 的限制(数组参数的默认值)吗?它是否适用于 VSTO 而不适用于 COM?

非常感谢你的帮助

4

1 回答 1

3

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

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

请注意如何将 string[] 编组为 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 将其添加到您的项目中。不完全确定这是否仍然值得为一个小便利所带来的麻烦,由您来决定。

于 2013-07-16T11:01:07.713 回答