2010-11-18 5 views
1

J'ai un assembly .NET 3.5 qui est en cours d'exécution en tant que composant serveur COM +, et je souhaite appeler une méthode de cette classe à partir de VBScript (un Page ASP classique).Erreur "Type Mismatch" lors de l'accès à un tableau renvoyé par COM + (VBScript)

Ceci est le contour de la méthode;

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

Mon VBScript est le suivant;

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

Cela provoque l'erreur suivante (déclenchée par la ligne où j'appelle l'appel à FillArray);

Type d'erreur: exécution Microsoft VBScript (0x800A0005) d'appel de procédure non valide ou argument: 'FillArray'

Firing up OLEView, l'IDL ressemble à ceci;

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

J'ai essayé de changer ma signature de la méthode à ce qui suit;

public bool FillArray(ref object[] arrayToFill) 

Qui a abouti à l'IDL suivant;

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

Mais toujours la même "Appel de procédure non valide ou argument" FillArray "" erreur.

Enfin, j'ai essayé de changer ma signature de méthode pour simplement ceci;

public bool FillArray(ref object arrayToFill) 

Qui a donné le IDL suivant;

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

Cela donne une nouvelle erreur maintenant;

exécution Microsoft VBScript (0x800A000D) Type de non-concordance

Cette erreur ne se décocha sur la dernière ligne maintenant, ce qui est quand je tente d'accéder à un élément du tableau. Si je commente la dernière ligne, alors j'obtiens la sortie suivante;

IsArray = True

UBound = 39

TypeName = Chaîne()

Apparemment donc, la variante est reconnue comme un tableau, et du type correct. En outre, le nombre correct d'éléments est renvoyé par UBound, mais je ne peux accéder à aucun des éléments pour une raison inconnue.

Est-ce que quelqu'un a une idée de ce qui pourrait être à l'origine de cela?J'ai moi-même fait quelques recherches et suis tombé sur le lien suivant;

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

Je ne suis pas certain à 100% que c'est exactement le même problème, que je ne suis pas déclarais mes tableaux de la même manière dans mon code VBScript. J'espère sincèrement que ce n'est pas le même problème, car je n'ai aucune possibilité de passer à .NET 4.0.

Répondre

3

J'ai réussi à travailler celui-ci moi-même.

Il s'avère que VBScript ne gère pas les tableaux qui ne sont pas de type Variant. Donc, dans mon code C# j'ai essayé ça; Le "..." fait référence à d'autres appels qui passent le long de arrayToFill par réf.

Malheureusement, cela a produit exactement la même erreur. Ce qui m'a mis sur la voie pour résoudre ceci était que la fonction VBScript "TypeName()" STILL voyait le type comme "String()". J'étais curieux de savoir ce qui se passait dans le code .NET, donc j'ai écrit un petit test;

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

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

Qui a produit ce qui suit:

System.String []

System.String []

Cela me était nouvelles à - je ne savais pas que ce serait le cas. J'ai pensé qu'il était raisonnable d'attendre Object [] pour le second type.

Quoi qu'il en soit, peu importe, j'écrit une petite méthode d'extension pour générer un nouvel objet []

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

Ceci est juste un premier rugueux aller à elle - la manipulation et la gestion des erreurs plus robuste pour les tableaux déchiquetés vont être ajoutés.

Donc, mon code ressemble maintenant;

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

Et maintenant, dans le VBScript, TypeName renvoie Variant() et je peux accéder au tableau comme prévu.

Espérons que cela aidera n'importe qui d'autre qui rencontre ce problème à l'avenir.

+0

Merci pour votre mise à jour! Je pense que cela m'aurait pris du temps pour comprendre. J'ai posté ma variante VB.Net ci-dessous. –

+0

Glad it helps! –

+0

Grande réponse - à votre santé! –

1

Difficile de voir pourquoi l'interpréteur de script rechigne à indexer le tableau. Cela peut avoir quelque chose à voir avec la borne inférieure du tableau étant zéro, il n'y a pas d'instruction Option Base dans VBScript. Array.CreateInstance() permet techniquement de créer un tableau qui ne commence pas à zéro dans .NET. L'une de ses surcharges permet de créer un tableau dont les limites inférieures ne sont pas nulles. Je vais mentionner la classe VariantWrapper mais je ne pense pas que ce soit pertinent. Faire le tableau la valeur de retour est quelque chose d'autre à essayer comme une solution de contournement.

+0

Je pris votre suggestion d'utiliser Array.CreateInstance(), et l'a utilisé pour convertir mon tableau zéro indexé à un unique indexé avant de revenir. Malheureusement, je reçois toujours le même message d'erreur. J'ai débogué mon composant COM + pour garder un oeil sur quel type il passait en arrière, et quand zéro-indexé c'était String [], mais quand one-indexed c'était String [*]. En outre, il s'agit d'un exemple dépouillé d'un code hérité qui transmet effectivement quatre de ces tableaux par référence, ce qui rend malheureusement la valeur de retour du tableau pas vraiment réalisable. –

+0

Eh bien, ça valait le coup. Mettez une prime là-dessus si vous ne voulez pas appeler le support de Microsoft. –

+0

le fera une fois que la limite de 48 heures est écoulée :) –

0

J'ai eu un problème similaire en passant un tableau de doubles à partir d'un programme VB 6.0 en un serveur COM écrit en VB.net (2010).

Déclaration du VB.fonction nette:

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

me donnerait une erreur d'incompatibilité de type alors que:

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

fonctionne très bien, mais je devais utiliser les index de tableau à partir de 1 pas 0.

0

C'est ce que je ne basé sur la réponse 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 
Questions connexes