如何正确地将 VB-Script 数组编组到用 C# 编写的 COM 组件或从中编组

发布于 2024-10-19 04:28:33 字数 119 浏览 6 评论 0原文

我正在 C# (.Net 4.0) 中构建一个 COM 对象,以便在经典的 asp 站点中使用。现在我想知道在组件和 asp 站点之间来回编组 VB-Script 数组(单维和多维)的正确方法是什么?代码示例将受到高度赞赏。

I'm building a COM object in C# (.Net 4.0) to be used in an classic asp site. Now I'd like to know what's the proper way to marshal VB-Script arrays (single and multidimensional) back and forth between the component and the asp site? A code sample would be highly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

醉生梦死 2024-10-26 04:28:33

VBScript 只喜欢处理包含 VARIANTS 的 SAFEARRAY。它喜欢将这些传递到 COM 方法或属性的 VARIANTS 中。因此,您需要构造一个包含 VARIANT 类型的 SAFEARRAY 的 VARIANT 属性。以下 C# 代码执行此操作。首先仅使用一个普通的对象数组,然后还表明我们可以将任何其他托管类型的数组转换为对象数组,以便编组代码将其转换为我们的 VARIANT 的 SAFEARRAY。

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
Count 10 type: Variant() names: Variant()
0
1
1
2
3
5
8
13
21
34
one
two
three
four
five

VBScript only likes to handle SAFEARRAY's that contain VARIANTS. And it likes to have these passed arround in VARIANTS on the COM methods or properties. So you need to construct a VARIANT property that contains a SAFEARRAY of VARIANT type. The following C# code does this. First using just a plain array of objects and then also showing we can cast an array of any other managed type into an array of objects such that the marshalling code will convert this into a SAFEARRAY of VARIANTs for us.

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(); } }
    }
}

This can be tested using the following 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

You can see the type reported here as Variant() - ie: an array of variants.

C:\Users\pat>\windows\SysWOW64\cscript.exe -nologo arraytest.vbs
Count 10 type: Variant() names: Variant()
0
1
1
2
3
5
8
13
21
34
one
two
three
four
five
腹黑女流氓 2024-10-26 04:28:33

与其说是答案,不如说是一些附加信息:

This is how to Consumer patthoyts' answer in Classic ASP using VBScript:

<%@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
%>

I无法访问单个数组元素(例如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]);
%>

Not so much an answer but some additional information:

This is how to consume patthoyts' answer in Classic ASP using VBScript:

<%@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
%>

I cannot access the individual array elements (eg. o.Names(2)) which indicates that it isn't an array but acting more like a collection.

JScript version:

<%@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]);
%>
甩你一脸翔 2024-10-26 04:28:33

有点晚了,但以防将来有人需要这个:

我设法将 HashtablesArrayList 传递给 Classic ASP。看来命名空间 System.Collections 的类型可以传递,而 System.Collections.Generic 则不可以。

.cs-File:

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-File:

<%
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# 传递到经典 ASP(也应该在 VB 脚本中工作,但未经测试),这非常方便,因为您可以使用以下命令循环访问对象任何属性。也没有测试相反的方式,因为我只需要将数据从 C# 传递到经典 ASP。

A bit late, but in case someone needs this in the future:

I managed to pass an ArrayList of Hashtables to Classic ASP. It seems that types of the namespace System.Collections can be passed, System.Collections.Generic can not.

.cs-File:

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-File:

<%
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
%>

Output:

Results: 5

Test0
0

Test1
1

Test2
2

Test3
3

Test4
4

This is pretty convenient if you have to pass a lot of data from C# to Classic ASP (Should work in VB Script too, but not tested), as you can loop through objects with any attributes. Also didn't test the other way around, because I only needed to pass data from C# to Classic ASP.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文