tags:

views:

377

answers:

2

Last Updated: 2009-08-11 2:30pm EDT

A few days ago I posted this question about some very strange problems. Well, I figured out what specifically was causing a build on one machine to not run on others and even came up with a work-around, but now it leaves me with a nice, specific question: Why?

To reproduce the problem, I create a new InteropUserControl and do the following:

  1. Add a new public struct MyStruct:
  2. Give it a GUID and ComVisible attributes
  3. Add a GetMyStruct member to the _InteropUserControl interface and implement it in InteropUserControl.

MyStruct:

[Guid("49E803EC-BED9-4a08-B42B-E0499864A169")]
[ComVisible(true)]
public struct MyStruct {
    public int mynumber;
}

_InteropUserControl.GetMyStruct():

[DispId(7)]
void getMyStruct( int num, ref MyStruct data );

(I have tried returning MyStruct instead of passing by reference, as well.)

InteropUserControl.GetMyStruct() implementation:

public void getMyStruct( int num, ref MyStruct data ) {
    data = new MyStruct();
    data.mynumber = num * 2;
}

I also sign the assembly and install it to the GAC and register with Regasm. Upon adding it to a new VB6 project and adding a call to GetMyStruct() and compiling on our build machine, it refuses to run on other machines.

To get around this, I had to expose a class to COM instead of the struct, and basically change GetMyStruct to this:

public void GetMyData( int num, MyClass data ) {
    data.mynumber = num * 2;
}

In my actual project, I retrieve the struct internally, and then copy all the field values from the struct to the matching members on the instance of the class passed to the method by the client.

So why did a struct cause this behavior and a class worked fine? Is there some magic to exposing a struct to COM for using in VB6?

I think it may have something to do with OLE Automation.

Note: I also tried returning the struct rather than using a ref parameter, but that did not change the behavior.

Edit to add link to project template:

Interop Forms Toolkit 2.0 is the original VB.NET project template and dll. I don't reference the dll, so you may not need to install this.

C# Translations of templates on CodeProject is what I used to create mine (the project template, not the item template). The VB.NET version generates the __InteropUserControl event interface, the _InteropUserControl interface, and a few relevant attributes automagically. Those are explicitly coded in the C# version, and that's about all that's different between the two.

+1  A: 

Is there some magic to exposing a struct to COM for using in VB6?

The article COM Data Types on MSDN says that structs are supported. Specifically, the MSDN article says that COM structures are defined as:

ByRef VALUETYPE< MyStruct >

There are also a couple of articles on customing your COM-callable wrappers at the bottom of the page, you may wish to review those.

Mike Mustaine
+1: I appreciate the try. I know they're supposed to work (and to an extent, they do). I've also tried a number of customizations, particularly with `MarshalAsAttribute`, but nothing has changed the behavior I described.
Joel B Fant
+1  A: 

I think I found a solution to this problem. I had the same exact problem, vb6 breaks when calling a method of an interop library by passing an structure. This is a project I created for testing a DLL interop, so all I have in my project was a form. But I had another project (the main application) with the same reference and it works fine.

After reading Joel post, I wanted to test his solution and in fact id did work (using a class instead a structure). But I have other interops where I'm using structures, so I was quite worried that at any point my application might fail. Additionally I didn't want to do the extra work of creating and exposing interface and a class to replace the structure.

So, I took the code from my form and move it to a public sub in a module. It Worked immediately. By the way, that's how i had implemented the call in the main application which was working ok.

I hope it might help others.

Gerardo H
Interesting. I'll have to try setting such a test project up again and calling from a module in VB6. Unfortunately, that won't help in my app because the main interop object is a control which has to reside on the form (visual display). But, this is a very interesting bit of information.
Joel B Fant
I decided to go ahead and give mark your answer as accepted. Moving the calling code to a module wasn't possible in my case, but it does seem to be 1 of the 2 solutions.
Joel B Fant