Discussion:
Passing Variant SafeArrays from C# into C++ DLL
(too old to reply)
praetor
2009-04-21 15:55:01 UTC
Permalink
I haven't found any comprehensive sample code on this topic. Lots of pages
cover C++ VARIANT and SAFEARRAYS, but nothing covering C# interoperability.

I need to consume an existing service in C++ using C#. Previous clients
used VB6 arrays. To paraphrase, I have a method in C++:

int __stdcall DoSomething( VARIANT *pvArray );

I have tried calling this method using the following:

TRIAL #1
[DllImport("binary.dll")]
private static extern DoSomething( ref [] object vArray );
(...)
Object [] variant;
System.Collections.ArrayList vP = new System.Collections.ArrayList();
vP.Add( (ulong)12345 );
variant = vP.ToArray();
CAScc_CompleteWorkVariant(m_hAgent, "101", 0, ref variant, "");

TRIAL #2
[DllImport("binary.dll")]
private static extern DoSomething( ref object vArray );
(...)
Object variant;
System.Collections.ArrayList vP = new System.Collections.ArrayList();
vP.Add( (ulong)12345 );
variant = vP.ToArray();
CAScc_CompleteWorkVariant(m_hAgent, "101", 0, ref variant, "");

TRIAL #3
[DllImport("binary.dll")]
private static extern DoSomething( ref object vArray );
(...)
Object variant;
System.Collections.ArrayList vP = new System.Collections.ArrayList();
vP.Add( (ulong)12345 );
variant = new VariantWrapper(vP.ToArray());
CAScc_CompleteWorkVariant(m_hAgent, "101", 0, ref variant, "");

I have tried a bunch of other stuff; but I have ommitted them for brevity.
Everytime I debug the C++, by variant pointer is ALWAYS null.

Are there any comprehensive samples out there on how to get something like
this done?

Thanks,

James
Beverly, MA
Giovanni Dicanio
2009-04-21 23:34:23 UTC
Permalink
Post by praetor
I need to consume an existing service in C++ using C#. Previous clients
int __stdcall DoSomething( VARIANT *pvArray );
[...]
Post by praetor
I have tried a bunch of other stuff; but I have ommitted them for brevity.
Everytime I debug the C++, by variant pointer is ALWAYS null.
I'm not sure what your VARIANT stores (a SAFEARRAY of VT_UI4 ?).
Moreover, is this VARIANT an input only parameter?

However, if you can't find the proper marshaling on the C# side, I would
suggest you to just write a C++/CLI bridging layer wrapper over your
original DoSomething().
e.g.

// in C++/CLI
int DoSomethingWrapper( array<UInt32>^ data )
{
... create a VARIANT to pass to DoSomething().
VARIANT var;
...
fill VARIANT with data stored in 'data' input variable
...

// Call your original DoSomething:
return DoSomething( &var );
}

You can call the DoSomethingWrapper() directly from C#, passing a simple C#
array to it.

HTH,
Giovanni
praetor
2009-04-22 15:59:03 UTC
Permalink
I like your suggestion; but if it is not a managed DLL, would I need to do
any .NET library initialization?

In answer to your question,
It is a Variant SAFEARRAY of VARIANT SAFEARRAY's.
The inner array has two elements. One a uint, the other either a
String, Date, our Double. With this info, could you come up with a direct
signature?

Let me know,

James
Beverly, MA
Post by Giovanni Dicanio
Post by praetor
I need to consume an existing service in C++ using C#. Previous clients
int __stdcall DoSomething( VARIANT *pvArray );
[...]
Post by praetor
I have tried a bunch of other stuff; but I have ommitted them for brevity.
Everytime I debug the C++, by variant pointer is ALWAYS null.
I'm not sure what your VARIANT stores (a SAFEARRAY of VT_UI4 ?).
Moreover, is this VARIANT an input only parameter?
However, if you can't find the proper marshaling on the C# side, I would
suggest you to just write a C++/CLI bridging layer wrapper over your
original DoSomething().
e.g.
// in C++/CLI
int DoSomethingWrapper( array<UInt32>^ data )
{
... create a VARIANT to pass to DoSomething().
VARIANT var;
...
fill VARIANT with data stored in 'data' input variable
...
return DoSomething( &var );
}
You can call the DoSomethingWrapper() directly from C#, passing a simple C#
array to it.
HTH,
Giovanni
Giovanni Dicanio
2009-04-22 16:36:00 UTC
Permalink
Post by praetor
I like your suggestion; but if it is not a managed DLL, would I need to do
any .NET library initialization?
I don't understand this question well, i.e: I'm not sure I understand what
you mean by "do any .NET library initialization".

My suggestion is to build a C++/CLI class library that exposes methods to
wrap the native DLL exported functions:
Add New Project | Visual C++ | CLR | Class Library.

Then you can build the VARIANT in some method of the C++/CLI class, and pass
this VARIANT to the native DLL.

The C# client talks to the C++/CLI class directly (not to the native DLL;
the C++/CLI class talks to the native DLL).
Post by praetor
In answer to your question,
It is a Variant SAFEARRAY of VARIANT SAFEARRAY's.
The inner array has two elements. One a uint, the other either a
String, Date, our Double. With this info, could you come up with a direct
signature?
I think that if the native function uses a VARIANT * as parameter, the
corresponding C# signature should be 'ref object'.
There is also a class called VariantWrapper, but I'm not sure that it can
help you in this particular case:

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.variantwrapper.aspx

I still think that the simplest way would be to just use the C++/CLI
bridging technique, and build the VARIANT directly from C++/CLI.

HTH,
Giovanni
praetor
2009-04-23 15:39:06 UTC
Permalink
I already have a dll. If I were to write this wrapper method, I would simply
add it to the existing binary. It gets released to customers/3rd parties; so
I don't want to add the burden of deploying an extra binary.

That said, my existing binary is not managed. Could I initialize the .NET
library dynamically in a non dotnet C++ dll? If so, how?

Thanks,

James
Beverly, MA
Post by Giovanni Dicanio
Post by praetor
I like your suggestion; but if it is not a managed DLL, would I need to do
any .NET library initialization?
I don't understand this question well, i.e: I'm not sure I understand what
you mean by "do any .NET library initialization".
Giovanni Dicanio
2009-04-24 08:05:10 UTC
Permalink
Post by praetor
I already have a dll. If I were to write this wrapper method, I would simply
add it to the existing binary. It gets released to customers/3rd parties; so
I don't want to add the burden of deploying an extra binary.
That said, my existing binary is not managed. Could I initialize the .NET
library dynamically in a non dotnet C++ dll? If so, how?
I've never done a DLL that exposes both unmanaged code and managed code at
its public interface, but I think it is possible.
Of course, building a simple test project on Visual Studio would answer
that. You may want to try Add New Project | Visual C++ | CLR | Class Library
template, and then expose also pure C native functions.

Or, if you have an existing native DLL, you may want to go to Project
Properties | Configuration Properties | General and select "Common Language
Runtime Support (/clr)" in "Common Language Runtime support" field, and then
add C++/CLI code, e.g.

namespace TestLibNative {

public ref class SomeWrapperClass
{
public:
void DoSomething()
{
...
}
};
}


HTH,
Giovanni
Ben Voigt [C++ MVP]
2009-05-13 21:41:03 UTC
Permalink
Post by praetor
I already have a dll. If I were to write this wrapper method, I
would simply add it to the existing binary. It gets released to
I think that if you try that, your dll will take a dependency on mscoree and
it won't run anymore except in a .NET program. Maybe you can work around
that by marking the mscoree dependency as delayload. Definitely avoid
compiling your native entrypoints with /clr, if you want native clients to
be able to call them (this requires putting your managed wrapper in a
separate .cpp file, then combining managed code with purely native object
files at the link step).
Post by praetor
customers/3rd parties; so I don't want to add the burden of deploying
an extra binary.
That said, my existing binary is not managed. Could I initialize the
.NET library dynamically in a non dotnet C++ dll? If so, how?
You can't use .NET data types directly from native code, because the garbage
collector needs the metadata describing stack variables.
Post by praetor
Thanks,
James
Beverly, MA
Post by Giovanni Dicanio
Post by praetor
I like your suggestion; but if it is not a managed DLL, would I
need to do any .NET library initialization?
I don't understand this question well, i.e: I'm not sure I
understand what you mean by "do any .NET library initialization".
Loading...