“类型不匹配”从 COM+ 访问 ref 返回的数组时出错; (VB脚本)

发布于 2024-10-03 07:57:10 字数 2280 浏览 1 评论 0原文

我有一个 .NET 3.5 程序集,它作为 COM+ 服务器组件运行,我想从 VBScript(经典 ASP 页面)调用此类中的方法。

这是方法概要;

public bool FillArray(ref string[] arrayToFill)
{
    ...
}

我的 VBScript 如下;

Dim myComponent, result, myArray

Set myComponent = Server.CreateObject("MyComponentProgID")
result = myComponent.FillArray(myArray)

Response.Write("IsArray = " & IsArray(myArray) & "<br/>")
Response.Write("UBound = " & UBound(myArray) & "<br/>")
Response.Write("TypeName = " & TypeName(myArray) & "<br/>")
Response.Write("Element 1 = " & myArray(1))

这会导致以下错误(由我调用 FillArray 的行触发);

错误类型:Microsoft VBScript 运行时 (0x800A0005) 无效的过程调用或 参数:'FillArray'

启动 OLEView,IDL 如下所示;

HRESULT FillArray(
                [in, out] SAFEARRAY(BSTR)* arrayToFill, 
                [out, retval] VARIANT_BOOL* pRetVal);

我尝试将方法签名更改为以下内容;

public bool FillArray(ref object[] arrayToFill)

这导致了以下 IDL;

HRESULT FillArray(
                [in, out] SAFEARRAY(VARIANT)* arrayToFill, 
                [out, retval] VARIANT_BOOL* pRetVal);

但仍然是相同的“无效的过程调用或参数'FillArray'”错误。

最后,我尝试将我的方法签名更改为简单的:

public bool FillArray(ref object arrayToFill)

其中给出了以下 IDL;

HRESULT FillArray(
                [in, out] VARIANT* arrayToFill, 
                [out, retval] VARIANT_BOOL* pRetVal);

现在这会产生一个新的错误;

Microsoft VBScript 运行时 (0x800A000D) 类型不匹配

此错误现在仅在最后一行(即当我尝试访问数组的元素时)触发。如果我注释掉最后一行,那么我会得到以下输出;

IsArray = True

UBound = 39

类型名称 = String()

因此,显然该变体被识别为数组,且类型正确。此外,UBound 返回了正确数量的元素,但由于某种未知原因我无法访问任何元素。

有谁知道可能是什么原因造成的?我自己做了一些研究,发现了以下链接;

http://connect.microsoft.com/VisualStudio /feedback/details/331632/marshaler-bug-with-vbscript-arrays

我不能 100% 确定这是完全相同的问题,因为我没有在 VBScript 代码中以相同的方式声明我的数组。我真诚地希望这不是同一个问题,因为我没有升级到 .NET 4.0 的空间。

I have a .NET 3.5 assembly which is being run as a COM+ server component, and I want to call a method in this class from VBScript (a Classic ASP page).

This is the method outline;

public bool FillArray(ref string[] arrayToFill)
{
    ...
}

My VBScript is as follows;

Dim myComponent, result, myArray

Set myComponent = Server.CreateObject("MyComponentProgID")
result = myComponent.FillArray(myArray)

Response.Write("IsArray = " & IsArray(myArray) & "<br/>")
Response.Write("UBound = " & UBound(myArray) & "<br/>")
Response.Write("TypeName = " & TypeName(myArray) & "<br/>")
Response.Write("Element 1 = " & myArray(1))

This results in the following error (triggered by the line where I make the call to FillArray);

Error Type: Microsoft VBScript runtime
(0x800A0005) Invalid procedure call or
argument: 'FillArray'

Firing up OLEView, the IDL looks like this;

HRESULT FillArray(
                [in, out] SAFEARRAY(BSTR)* arrayToFill, 
                [out, retval] VARIANT_BOOL* pRetVal);

I tried changing my method signature to the following;

public bool FillArray(ref object[] arrayToFill)

Which resulted in the following IDL;

HRESULT FillArray(
                [in, out] SAFEARRAY(VARIANT)* arrayToFill, 
                [out, retval] VARIANT_BOOL* pRetVal);

But still the same "Invalid procedure call or argument 'FillArray'" error.

Finally, I tried changing my method signature to simply this;

public bool FillArray(ref object arrayToFill)

Which gave the following IDL;

HRESULT FillArray(
                [in, out] VARIANT* arrayToFill, 
                [out, retval] VARIANT_BOOL* pRetVal);

This gives a new error now;

Microsoft VBScript runtime
(0x800A000D) Type mismatch

This error is only fired off on the final line now, which is when I try to access an element of the array. If I comment the last line out, then I get the following output;

IsArray = True

UBound = 39

TypeName = String()

So, apparently the variant is being recognised as an array, and of the correct type. Also, the correct number of elements are returned by UBound, but I cannot access any of the elements for some unknown reason.

Does anyone have any idea what might be causing this? I've done some research myself, and came across the following link;

http://connect.microsoft.com/VisualStudio/feedback/details/331632/marshaler-bug-with-vbscript-arrays

I'm not 100% certain that it's the exact same issue, as I am not declaring my arrays in the same way in my VBScript code. I sincerely hope it's not the same issue, as I have no scope for upgrading to .NET 4.0.

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

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

发布评论

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

评论(4

抠脚大汉 2024-10-10 07:57:10

我自己设法解决了这个问题。

事实证明,VBScript 不处理非 Variant 类型的数组。所以,在我的 C# 代码中我尝试了这个;

public bool FillArray(ref object arrayToFill)
{
    string[] tmpArrayToFill = (string[])arrayToFill;
    ...
    arrayToFill = (object[])tmpArrayToFill
}

“...”指的是通过 ref 传递 arrayToFill 的进一步调用。

不幸的是,这产生了完全相同的错误。

让我走上解决这个问题的道路的是“TypeName()”VBScript 函数仍然将类型视为“String()”。我很好奇 .NET 代码中发生了什么,因此编写了一个小测试;

string[] stringArray = new string[1];
Console.WriteLine(stringArray.GetType());

object[] objectArray = (object[])stringArray;
Console.WriteLine(objectArray.GetType());

产生以下内容;

系统字符串[]

系统字符串[]

这对我来说是新闻 - 我没有意识到情况会如此。我认为预期 Object[] 为第二种类型是合理的。

无论如何,无论如何,我编写了一个小的扩展方法来生成一个新对象[],

public static Array ToObjectArray(this Array input)
{
    if (input != null)
    {
        object[] objArray = new object[input.Length];
        input.CopyTo(objArray, 0);
        return objArray;
    }
    else
    {
        return null;
    } 
 }

这只是一个粗略的初步尝试 - 将添加更强大的错误处理和对锯齿状数组的支持。

所以我的代码现在看起来像;

public bool FillArray(ref object arrayToFill)
{
    string[] tmpArrayToFill = (string[])arrayToFill;
    ...
    arrayToFill = tmpArrayToFill.ToObjectArray();
}

现在,在 VBScript 中,TypeName 返回 Variant(),我可以按预期访问该数组。

希望这对将来遇到此问题的其他人有所帮助。

I managed to work this one out myself.

It turns out that VBScript does not handle arrays which are not of type Variant. So, in my C# code I tried this;

public bool FillArray(ref object arrayToFill)
{
    string[] tmpArrayToFill = (string[])arrayToFill;
    ...
    arrayToFill = (object[])tmpArrayToFill
}

The "..." refers to further calls which pass along arrayToFill by ref.

Unfortunately, this produced the exact same error.

What put me on the path to solving this was that the "TypeName()" VBScript function STILL saw the type as "String()". I was curious what was going on in the .NET code, so wrote a small test;

string[] stringArray = new string[1];
Console.WriteLine(stringArray.GetType());

object[] objectArray = (object[])stringArray;
Console.WriteLine(objectArray.GetType());

Which produced the following;

System.String[]

System.String[]

This was news to me - I didn't realise that this would be the case. I thought it reasonable to expect Object[] for the second type.

Anyway, regardless of that, I wrote up a small extension method to generate a new object[]

public static Array ToObjectArray(this Array input)
{
    if (input != null)
    {
        object[] objArray = new object[input.Length];
        input.CopyTo(objArray, 0);
        return objArray;
    }
    else
    {
        return null;
    } 
 }

This is just a rough first go at it - more robust error handling and support for jagged arrays are going to be added.

So my code now looks like;

public bool FillArray(ref object arrayToFill)
{
    string[] tmpArrayToFill = (string[])arrayToFill;
    ...
    arrayToFill = tmpArrayToFill.ToObjectArray();
}

And now, in the VBScript, TypeName returns Variant() and I can access the array as expected.

Hopefully this will help anybody else who runs into this problem in the future.

腻橙味 2024-10-10 07:57:10

很难理解为什么脚本解释器在索引数组时犹豫不决。这可能与数组的下限为零有关,VBScript 中没有 Option Base 语句。在 .NET 中创建一个不从零开始的数组在技术上可以通过 Array.CreateInstance() 实现,它的重载之一允许您创建一个具有非零下限的数组。我会提到 VariantWrapper 类,但认为它不相关。使数组作为返回值是另一种可以尝试的解决方法。

Hard to see why the script interpreter balks at indexing the array. This might have something to do with the lower-bound of the array being zero, there is no Option Base statement in VBScript. Creating an array that doesn't start at zero in .NET is technically possible through Array.CreateInstance(), one of its overloads lets you create an array that has non-zero lower bounds. I'll mention the VariantWrapper class but don't think it's relevant. Making the array the return value is something else to try as a workaround.

心房的律动 2024-10-10 07:57:10

这是我根据 C.McAtackney 的回答所做的:

Private _lastErrors As List(Of Object)
''' <summary>
''' Expose error array to COM object consumer
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks>Type is Object() because VBScript requires a variant type.</remarks>
Public Property LastErrors As Object()

    Get
        If _lastErrors Is Nothing Then
            _lastErrors = New List(Of Object)
        End If

        Return _lastErrors.ToArray
    End Get
    Private Set(value As Object())
        If _lastErrors Is Nothing Then
            _lastErrors = New List(Of Object)
        End If

        _lastErrors.AddRange(value)
    End Set
End Property

This is what I did based on C.McAtackney's answer:

Private _lastErrors As List(Of Object)
''' <summary>
''' Expose error array to COM object consumer
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks>Type is Object() because VBScript requires a variant type.</remarks>
Public Property LastErrors As Object()

    Get
        If _lastErrors Is Nothing Then
            _lastErrors = New List(Of Object)
        End If

        Return _lastErrors.ToArray
    End Get
    Private Set(value As Object())
        If _lastErrors Is Nothing Then
            _lastErrors = New List(Of Object)
        End If

        _lastErrors.AddRange(value)
    End Set
End Property
把昨日还给我 2024-10-10 07:57:10

我在将双精度数组从 VB 6.0 程序传递到
用 VB.net (2010) 编写的 COM 服务器。

将 VB.net 函数声明为:

Public Function GetSpatialResults(ByRef Results() As Double) As Long

会给我一个类型不匹配错误,其中 as :

Public Function GetSpatialResults(ByRef Results As Object) As Long
    Results(1) = 1
    Results(2) = 2
    Results(3) = 3
    GetSpatialResults = 0

工作正常,但是,我必须使用从 1 开始的数组索引,而不是 0

I had a similar problem passing an array of doubles from a VB 6.0 program into
a COM server written in VB.net (2010).

Declaring the VB.net function as:

Public Function GetSpatialResults(ByRef Results() As Double) As Long

would give me a type mismatch error where as :

Public Function GetSpatialResults(ByRef Results As Object) As Long
    Results(1) = 1
    Results(2) = 2
    Results(3) = 3
    GetSpatialResults = 0

Works fine, however, I had to use array indexes starting at 1 not 0.

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