我正在使用C# (.Net 4.0)构建一个COM对象,用于经典asp网站。现在我想知道如何在组件和asp站点之间传递VB-Script数组(单维和多维)的正确方法是什么?非常感谢提供示例代码。
我正在使用C# (.Net 4.0)构建一个COM对象,用于经典asp网站。现在我想知道如何在组件和asp站点之间传递VB-Script数组(单维和多维)的正确方法是什么?非常感谢提供示例代码。
VBScript只支持处理包含VARIANT的SAFEARRAY。而且它喜欢在COM方法或属性中将这些传递给包含VARIANT的VARIANT。因此,您需要构建一个包含VARIANT类型的SAFEARRAY的VARIANT属性。以下C#代码可以实现此目的。首先使用普通对象数组,然后还展示了我们可以将任何其他托管类型的数组转换为对象数组,以便封送代码将其转换为SAFEARRAY的VARIANT。
using System;
using System.Runtime.InteropServices;
using System.Linq;
namespace StackOverflow
{
[ComVisible(true)]
[Guid("2F4C19A6-9BB9-4ACF-90D1-BAF48696740A")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IMyArrayDemo
{
[DispId(1)]
int Count
{
[return: MarshalAs(UnmanagedType.I4)]
get;
}
[DispId(2)]
object Data
{
[return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
get;
}
[DispId(3)]
object Names
{
[return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
get;
}
}
[ComVisible(true)]
[Guid("7EF75834-22BE-4861-879B-EA0CE20E46E9")]
[ClassInterface(ClassInterfaceType.None)]
[ProgId("StackOverflow.MyArrayDemo")]
public class MyArrayDemo : IMyArrayDemo
{
object[] mData = new object[10] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };
string[] mNames = new string[5] {"one", "two", "three", "four", "five"};
public int Count { get { return mData.Length; } }
public object Data { get { return mData; } }
public object Names { get { return mNames.Cast<object>().ToArray(); } }
}
}
这可以通过以下VBScript进行测试: Option Explicit
Sub Main
Dim o, v
Set o = CreateObject("StackOverflow.MyArrayDemo")
WScript.Echo "Count " & o.Count & " type: " & TypeName(o.Data) & " names: " & TypeName(o.Names)
For Each v in o.Data : WScript.Echo CStr(v) : Next
For Each v in o.Names : WScript.Echo v : Next
End Sub
Main
这里报告的类型是Variant(),也就是一组变量数组。
C:\Users\pat>\windows\SysWOW64\cscript.exe -nologo arraytest.vbs 总数为10,类型为:Variant(),名称为:Variant() 0 1 1 2 3 5 8 13 21 34 one two three four five
这不是一个答案,而是一些额外的信息:
以下是使用VBScript在Classic ASP中消耗patthoyts答案的方法:
<%@Language=VBScript%>
<%
Dim o, v
Set o = CreateObject("StackOverflow.MyArrayDemo")
Response.Write "Count " & o.Count & " type: " & TypeName(o.Data) & " names: " & TypeName(o.Names)
For Each v in o.Data
Response.Write "<br />" & v
Next
For Each v in o.Names
Response.Write "<br />" & v
Next
%>
我无法访问单个数组元素(例如o.Names(2)),这表明它不是一个数组,而更像是一个集合。
JScript版本:
<%@Language=JScript%>
<%
var o, v;
o = Server.CreateObject("StackOverflow.MyArrayDemo")
Response.Write ("Count " + o.Count + " type: " + (typeof o.Data) + " names: " + (typeof o.Names));
var a = o.Data.toArray();
for (v=0; v<a.length; v++)
Response.Write ("<br />" + a[v]);
var b = o.Names.toArray();
for (v=0; v<b.length; v++)
Response.Write ("<br />" + b[v]);
%>
有点晚了,但以备后人需要:
我成功地将一个Hashtable
的ArrayList
传递给了Classic ASP。似乎可以传递System.Collections
命名空间的类型,但不能传递System.Collections.Generic
。
.cs文件:
using System;
using System.Runtime.InteropServices;
using System.Collections;
namespace Test
{
[ComVisible(true)]
[Guid("D3A3F3E7-F1A9-4E91-8D7B-D9E19CF38165")]
public interface iDemo
{
[return: MarshalAs(UnmanagedType.Struct, SafeArraySubType = VarEnum.VT_ARRAY)]
ArrayList DemoMethod();
}
[ProgId("Test.Demo")]
[ClassInterface(ClassInterfaceType.None)]
[Guid("F53257DD-9275-4D6C-A758-EFF6932FF8B2")]
[ComVisible(true)]
public class Demo : iDemo
{
[ComVisible(true)]
public ArrayList DemoMethod()
{
ArrayList Results = new ArrayList();
for (int i = 0; i < 5; i++)
{
Hashtable table = new Hashtable();
table.Add("Text", "Test"+i);
table.Add("Number", i);
Results.Add(table);
}
return Results;
}
}
}
.asp文件:
"<%
set test = server.createObject("Test.Demo")
set results = test.DemoMethod()
response.write "Results: " & results.count & "<br><br>"
for each result in results
response.write result("Text") & "<br>"
response.write result("Number") & "<br><br>"
next
%>
输出:
Results: 5
Test0
0
Test1
1
Test2
2
Test3
3
Test4
4
Cast
方法位于System.Linq命名空间中,且在System.Core程序集中提供(请参阅http://msdn.microsoft.com/en-us/library/bb341406.aspx),因此默认项目应该已包含所有所需的引用。我拥有的项目副本只包含System、System.Core和Microsoft.CSharp三个引用,没有其他引用。上面显示了using块。我使用Visual Studio 2010构建了这个项目,但2008也应该可以。 - patthoytspublic object Names { get { return mNames.Cast<object>().ToArray(); } }
。 - patthoyts[MarshalAs(...)]
属性都可以被删除,因为默认情况下已经使用了 VARIANT 和 SAFEARRAY。此外,我找不到任何关于你在UnmanagedType.Struct
中使用SafeArraySubType = VarEnum.VT_ARRAY
(而不是UnmanagedType.SafeArray
)的参考。它可能没有效果并被忽略。(文档说:“指示 UnmanagedType.SafeArray 的元素类型。”)。这篇博客文章(http://blogs.msdn.com/b/adam_nathan/archive/2003/04/24/56642.aspx)可能会有所帮助。 - Micha Wiedenmann