[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

microsoft.public.dotnet.framework.interop

Marshalling SAFEARRAY only works when early bound.

Patrick Steele

2/2/2007 12:52:00 AM


I've created a simple reproduction case highlighting my problem. I've
got a VB6 app using a .NET 2.0 component exposed to COM (this .NET
component is replacing a COM component). The component is pretty
simple:

using System;
using System.Runtime.InteropServices;

namespace DotNetLibrary
{
[Guid("FF7E820A-9F60-4B4C-BE17-93704377A65F")]
public interface IClass1
{
[DispId(0x60030011)]
int TheMethod(
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType =
VarEnum.VT_BSTR)]
ref string[] Parameters);
}

[Guid("FFA1B994-66A3-4715-91C9-91468961ADB2")]
[ClassInterface(ClassInterfaceType.None)]
public class Class1 : IClass1
{
public int TheMethod(
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType =
VarEnum.VT_BSTR)]
ref string[] Parameters)
{
return 0;
}
}
}

This assembly is strong-named. I use REGASM with the /codebase switch
and generate a type library with the /tlb switch. Here's the sample VB6
code that highlights the problem (the VB6 project has a reference to the
generated type library). NOTE: If you're going to test this, make sure
you save your project before running since this sample blows up
VB6.EXE... ;)

Dim lateObj As Object
Dim earlyObj As DotNetLibrary.Class1

Dim parameters() As String

Set lateObj = CreateObject("DotNetLibrary.Class1")
Set earlyObj = CreateObject("DotNetLibrary.Class1")

Debug.Print earlyObj.TheMethod(parameters)
Debug.Print lateObj.TheMethod(parameters)

As you see I create two instance of the object. One is early-bound, one
is late-bound. The first call (via the early-bound object) works fine.
The second (via the late-bound object) kills VB6.EXE (or kills the
compiled application when run outside the VB6 IDE). If I run the .NET
component in debug mode inside VS.NET and set "VB6.EXE" as the startup
project, the Managed Debugging Assistent pops up with a
FatalExecutionEngineError:

-----------------
FatalExecutionEngineError was detected

Message: The runtime has encountered a fatal error. The address of the
error was at 0x7a03d1be, on thread 0x1498. The error code is 0xc0000005.
This error may be a bug in the CLR or in the unsafe or non-verifiable
portions of user code. Common sources of this bug include user
marshaling errors for COM-interop or PInvoke, which may corrupt the
stack.
-----------------

Two things that don't make sense to me:

1) If I change the declaration of "parameters" in the VB6 code to
include an upperbound (i.e. "Dim parameters(0) As String"), the code
works in both early and late-bound.

2) #1 above leads me to believe it's something to do with null/non-null
values -- but then why would it work when early-bound and not late-
bound?

Has anyone ever seen anything like this before?

PS - The obvious solution of "always define an upperbound" isn't an
option since there's already tons of code written (both by my client and
other third parties) using the above style. The .NET component is being
developed to be binary-compatible with the old COM component so the VB6
client apps are not going to be recompiled.

Thanks!!

--
Patrick Steele
http://weblogs.asp.n...