我正在将代码从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?
非常感谢你的帮助
答案 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将其添加到项目中。不完全确定这仍然值得一点轻松的麻烦,你可以打电话。