如何正确地将VB-Script数组与以C#编写的COM组件进行封送

问题描述 投票:14回答:3

我正在用C#(.Net 4.0)构建COM对象,以在经典的ASP网站中使用。现在,我想知道在组件和asp站点之间来回配置VB-Script数组(单个和多维)的正确方法是什么?代码示例将不胜感激。

.net arrays asp-classic marshalling com-interop
3个回答
18
投票

VBScript只喜欢处理包含VARIANTS的SAFEARRAY。它喜欢在COM方法或属性的VARIANTS中传递这些参数。因此,您需要构造一个包含VARIANT类型的SAFEARRAY的VARIANT属性。下面的C#代码执行此操作。首先只使用一个简单的对象数组,然后显示我们可以将任何其他托管类型的数组转换为对象数组,这样编组代码将为我们将其转换为SAFEARRAY of VARIANTs。

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()01个1个2358132134一二三四五

2
投票

不是太多的答案,而是一些其他信息:

这是使用VBScript在Classic ASP中消耗爱国者的答案的方法:

<%@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]);
%>

0
投票

有点晚,但是如果将来有人需要它:

我设法将ArrayListHashtables传递给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

这非常方便,因为您必须将大量数据从C#传递到Classic ASP(也应在VB Script中工作,但未经测试),因为您可以遍历具有任何属性的对象。也没有进行其他测试,因为我只需要将数据从C#传递到Classic ASP。

© www.soinside.com 2019 - 2024. All rights reserved.