2

I have an application that involves a lot of communication between managed (C#) and unmanaged (C++) code. We are using Visual Studio 2005 (!), and we use the interop assembly generated automatically by tlbimp.

We have fairly good luck passing simple structs back and forth as function arguments. And because our objects are fairly simple, we can pack them into SAFEARRAYs using the IRecordInfo interface. Passing these arrays as arguments to COM methods seems to work properly.

We would like to be able to embed variable-length arrays in our UDTs, but this fails badly. I don't think I have been able to find a single piece of documentation showing how someone has accomplished this. Nor have I found documentation that says it can't be done.

1) Naive approach: Simply declare a safearray in the managed code:

struct MyUdt {
  int member1;
  BSTR member2;
  SAFEARRAY *m3;
};

The C++ compiler is happy with this, but the generated IDL confounds tblimp.exe. It reports that it is unable to convert the signature for member m3, and the signature for member tagSAFEARRAY.rgsabound. These are only warnings, but they are meaningful, the resulting assembly is not usable.

Using LPSAFEARRAY, oddly enough, fails in different ways, but for the same reason, tblimp just can't deal with it.

2) Trickier: Pack it into a variant:

struct MyUdt {
  int member1;
  BSTR member2;
  VARIANT m3;
};

We have code that builds safearrays of UDTs, and it never gives us any trouble. It's basically copied from MSDN. Using that code to create a safearray, then:

pVal->m3.vt = VT_SAFEARRAY | VT_RECORD;
pval->parray = p;

Fails in odd ways. It always breaks, some variations produce an OutOFMemoryException... odd, others fail in different ways. (I'm not sure if a pRecInfo pointer is required here or not, but it fails the same way, present or not.)

The Google search space for this is badly polluted with answers to questions that I am not asking:

  • How do you pass UDT/structs from unmanaged code.
  • How do you pass a SAFEARRAY of structs? (We're doing this fine.)
  • How do you use p/invoke or customer marshalling to pass UDTs.

And many answers describing how to define things from the managed side, not the unmanaged side.

And then there are a couple of Microsoft KBs describing problems with VT_RECORD in early versions of .NET. I don't think these are germane - VT_RECORD types work with VARIANT and with SAFEARRAY. (But maybe not with the UDT marshallling...)

If this won't ever work, it would be nice to at least know why.

  • Mark
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mark
  • 101
  • 1
  • 9
  • Are VT_RECORD natively supported by the CLR interop layers at all? I can't find any reference of this – Simon Mourier Jun 08 '13 at 07:41
  • Not being able to find references on the automatically generated interop assemblies is kind of par for the course. SAFEARRAYs of UDTs can be returned from unmanaged code to managed if they are populated with VT_RECORD using the IRecordInfo interface. We use these as out parameters and have never had any trouble, so I think it is really, truly working and supported. – Mark Jun 08 '13 at 13:36
  • 1
    As I understand it, VT_RECORD in a simple VARIANT is _not_ supported. I have given it a quick try and verified that it doesn't work with our development environment. Microsoft's bug report on the matter is posted for .NET 1.1, but still seems to be true: BUG: COM Interop: No Built-in Support VARIANT of Type VT_RECORD http://support.microsoft.com/kb/309329 – Mark Jun 08 '13 at 13:45
  • I've got too many battle-scars from VT_RECORD to answer this question, learned to avoid them like the plague they are a long time ago. You can turn any struct into a COM interface, make each field a property. Never a problem that way. – Hans Passant Jun 08 '13 at 15:27
  • @HansPassant: It's true that you can turn any struct into a COM interface, but really, it is quite annoying to have to take a nice, lightweight POD and burden it with all that crap. The auto-generated interop assembly exists just to avoid that kind of thinking. That said, your point is taken. – Mark Jun 08 '13 at 15:56
  • There just no P in POD in an interop scenario. Structure layout and memory management are nasty interop details. – Hans Passant Jun 08 '13 at 16:44

0 Answers0