Re: Array Marshalling different between VB6 & Script to an interop C#



I think you need to be declaring a Variant which contains an array or
strings, as opposed to an array of strings.

The scripts require all data types to be Variants.

Tom

KirkViehland wrote:
I have a very simple C# library that demonstrates a problem that I am trying
to figure out right now. I could post a full example, if this forum allowed
posting attachments.

Anyway, like I said, I have a very simple C# class...

namespace ScriptMarshalTester
{
using System;
using System.Reflection;
using System.Runtime.InteropServices;

[ComVisible(true)]
[Guid("AD07359C-D5D6-4A22-89D7-7DA80D3C4973")]
[ProgId("ScriptMarshalTester.StringTester")]
[ClassInterface(ClassInterfaceType.None)]
public class StringTester
: ScriptMarshalTester.IStringTester
{
public StringTester(){}

public void TestString
(
[In, MarshalAs(UnmanagedType.BStr)]
string value
)
{
Console.WriteLine( "\r\n" + MethodInfo.GetCurrentMethod().Name +
"\r\n" );
Console.WriteLine( new String('-',20) );
Console.WriteLine( "value=" + value );
}

public void TestStringArray
(
[MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType=VarEnum.VT_BSTR)]
ref string[] values
)
{
Console.WriteLine( "\r\n" + MethodInfo.GetCurrentMethod().Name +
"\r\n" );
Console.WriteLine( new String('-',20) );

for ( int i = 0; i < values.Length; i++ )
Console.WriteLine( "values[" + i.ToString() + "]=" +
values[i]);
}

public void TestStringAndStringArray
(
[In, MarshalAs(UnmanagedType.BStr)]
string value,

[In, Out, MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType=VarEnum.VT_BSTR)]
ref string[] values
)
{
Console.WriteLine( "\r\n" + MethodInfo.GetCurrentMethod().Name +
"\r\n" );
Console.WriteLine( new String('-',20) );

Console.WriteLine( "value=" + value );

for ( int i = 0; i < values.Length; i++ )
Console.WriteLine( "values[" + i.ToString() + "]=" +
values[i]);
}
}
}

And its interface definition is as follows...

namespace ScriptMarshalTester
{
using System;
using System.Runtime.InteropServices;

[ComVisible(true)]
[Guid("10F83921-A0EA-4270-8574-5D7577EB72EA")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface IStringTester
{
[DispId(1)]
void TestString
(
[In, MarshalAs(UnmanagedType.BStr)]
string value
);

[DispId(2)]
void TestStringArray
(
[In, MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType=VarEnum.VT_BSTR)]
ref string[] values
);

[DispId(3)]
void TestStringAndStringArray
(
[In, MarshalAs(UnmanagedType.BStr)]
string value,

[In, MarshalAs(UnmanagedType.SafeArray,
SafeArraySubType=VarEnum.VT_BSTR)]
ref string[] values
);
}
}

Now, if I compile this and try to execute it with the following VB6 code
everything works as expected, ** Meaning no exceptions are thrown **. Here is
some sample VB6 code. You will notice in this snippet that the original
library has been compiled and registered with COM as ScriptMarshalTester. The
ProgId for the class that we will be interacting with is
ScriptMarshalTester.StringTester. Here is the VB6 subroutine...

Private Sub TestStrings()
Dim tester As ScriptMarshalTester.StringTester
Dim testValue As String
Dim testValues() As String

ReDim testValues(1)

Set tester = New ScriptMarshalTester.StringTester

testValue = "Hello World"
testValues(0) = "Hello"
testValues(1) = "World"

Call tester.TestString(testValue)
Call tester.TestStringArray(testValues())
Call tester.TestStringAndStringArray(testValue, testValues())
End Sub

At this point, everything behaves as expected. Once we introduce the script
client into the mix things start to take a quick downhill. I have 2 script
clients which both exhibit the same behavior, a VBScript client and a JScript
client. Here is the same method as the TestStrings method above in VBScript...

private sub TestStrings()

dim tester
dim testValue
dim testValues()

ReDim testValues(1)

set tester = WSCript.CreateObject("ScriptMarshalTester.StringTester")
testValue = "Hello World"
testValues(0) = "Hello"
testValues(1) = "World"

call tester.TestString(testValue)
call tester.TestStringArray(testValues)
call tester.TestStringAndStringArray(testValue,testValues)

end sub

And also in the following JScript...

function testStrings()
{
var tester = new ActiveXObject("ScriptMarshalTester.StringTester");

var testValue = new String("Hello World");
var testValues = new Array();

testValues[0] = "Hello";
testValues[1] = "World";

try
{
tester.TestString(testValue);
tester.TestStringArray
(
CreateSafeArray(testValues)
);
tester.TestStringAndStringArray
(
testValue,
CreateSafeArray(testValues)
);
}
catch(e)
{
WScript.StdOut.WriteLine(e);
WScript.StdOut.WriteLine(e.number & 0xFFFF);
WScript.StdOut.WriteLine(e.description);
}
}

// Converts a JScript Array to a SAFEARRAY
function CreateSafeArray( jsArray )
{
var dictionary = new ActiveXObject("Scripting.Dictionary");

for ( var i = 0; i < jsArray.length; i++ )
dictionary.add( i, jsArray[i] );

return(new VBArray(dictionary.Items()));
}

The problem surfaces in that the tester.TestStringArray method gets an
"Invalid procedure call or argument" while trying to pass the array of
strings to the TestStringArray method. Likewise, if the same script is coded
in JScript and the argument is converted to a SAFEARRAY the executing script
gets an "Invalid Procedure call or argument" while trying to marshall the
array parameter to the managed code.

Unless I have missed something in the documentation, I think that I have
declared these interfaces correctly. I know that it is something very simple,
but I can't seem to make this work. One requirement however is that the same
.Net component should be useable from both VB6 as well as script components.

Any help would be appreciated.

Thanks,
Kirk A. Viehland

.



Relevant Pages

  • Array Marshalling different between VB6 & Script to an interop C#
    ... public void TestString ... ref string[] values ... Dim testValue As String ... Once we introduce the script ...
    (microsoft.public.dotnet.framework.interop)
  • Re: Need to be able to add print option or save as option to the outpout of this script....
    ... First get all the names and shove them in an array. ... building script, then, start building the page, when you get to the section ... Then write the end bit of code into a string. ... If I'm right then this will display the html in a browser. ...
    (microsoft.public.scripting.vbscript)
  • Re: How to rewrite with awk?
    ... > I'm unfamiliar with tools such as sed & awk. ... Extract the string that matches a RE. ... This script will not only expand all the lines that say "include ... file) and not resetting ARGV(the tmp file), it then lets awk do any ...
    (comp.unix.shell)
  • Re: Slow string
    ... I see virtually no difference in execution time for the code you posted when using cscript versus using wscript; to confirm, I bracketed the code with an initial ... Are you actually entering the script name into a console window? ... You can use the exact same line for every wrapper script - and that includes wsf and js scripts; all you need to do is change the final "vbs" to "wsf" or "js" as appropriate. ... If you build a large string by small concatenations, the performance degrades geometrically - so does array resizing, because they both use the same nasty technique inherited from VB1 of copying the entire data structure to a new structure with the added element. ...
    (microsoft.public.scripting.vbscript)
  • Re: REQ - Help in editing a file - Script or Utility
    ... deal with it as an array. ... As the string gets bigger you're dealing with the need to ... going through the string 1 character at a time. ... I tested the script below on a 1.6 MB ...
    (microsoft.public.scripting.vbscript)