Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Passing Variant SafeArrays from C# into C++ DLL

710 views
Skip to first unread message

praetor

unread,
Apr 21, 2009, 11:55:01 AM4/21/09
to
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

unread,
Apr 21, 2009, 7:34:23 PM4/21/09
to

"praetor" <pra...@discussions.microsoft.com> ha scritto nel messaggio
news:30787F61-C8F4-4650...@microsoft.com...

> 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:

[...]


> 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

unread,
Apr 22, 2009, 11:59:03 AM4/22/09
to
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

Giovanni Dicanio

unread,
Apr 22, 2009, 12:36:00 PM4/22/09
to

"praetor" <pra...@discussions.microsoft.com> ha scritto nel messaggio
news:D56454AE-8F88-4DD0...@microsoft.com...

>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).

> 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

unread,
Apr 23, 2009, 11:39:06 AM4/23/09
to
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

Giovanni Dicanio

unread,
Apr 24, 2009, 4:05:10 AM4/24/09
to

"praetor" <pra...@discussions.microsoft.com> ha scritto nel messaggio
news:DEE45A57-4AEC-463B...@microsoft.com...

>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]

unread,
May 13, 2009, 5:41:03 PM5/13/09
to
praetor wrote:
> 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).


> 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.

0 new messages