How to reach unmanaged API functions from managed code?

  • Thread starter Tommy Svensson \(InfoGrafix\)
  • Start date
T

Tommy Svensson \(InfoGrafix\)

I've been instructed to work againt a huge unmanaged C++ API from a C#
application.

Now, the only way, as I've understood it, is to go the Managed Extensions
for C++ way. This means I have to write a wrapper between unmanaged API and
my managed app.

Now on to the question:

If there's an unmanaged API class called X with a defined method

TypeA* foobar(TypeB* b, TypeC* c);

then how can my managed code (my c# app) deal with the problem of inputing
TypeB and TypeC since they are not known or compatible with managed code,
and how should my c# app deal with the TypeA* return type?

Is there a way to "use" the unmanaged types "as they are" in the managed
code (maybe by uisng the API include files?) or do I have to do something
like this in my wrapper:

TypeA, TypeB and TypeC consists only of a public int member for simplicity.

public __gc class wrapper
{
public:
wrapper() {m_obj = new X;}
X* m_obj;
....

// exposed to the managed code to be able to
// talk to the API foobar method
int wrappedFoobar(int b, int c)
{
TypeB* bTmp = new TypeB(b);
TypeC* cTmp = new TypeC(c);

TypeA* aTmp = m_obj->foobar(bTmp, cTmp);
return aTmp->m_nInt;
}
}

This is EXTREMELY cumbersome if I want to use large parts of the API... or
not even doable if the types are really complex. Is there a way to reach
the unmanaged API where I'm not forced to practically rewrite the entire
library in managed code?

PLEASE, reply also to (e-mail address removed).

Sincerely,

/Tommy
 
W

William DePalo [MVP VC++]

Tommy Svensson (InfoGrafix) said:
I've been instructed to work againt a huge unmanaged C++ API from a C#
application.

Now, the only way, as I've understood it, is to go the Managed Extensions
for C++ way. This means I have to write a wrapper between unmanaged API
and
my managed app.

Well, sometimes what developers do is to define a managed class in MC++
(soon to be C++/CLI) which exposes the same public interface. That done,
callers written in any CLS compliant language can create objects of the MC++
class.

Another option is to wrap up the C++ class into a COM object and then take
advanatge of the fact that .Net applications can consume COM objects.

A third option is to "flatten" the existing object oriented interface into a
procedural one which exposes its interface via exported DLL functions and
then use .Net's Platform/Invoke (aka P/Invoke) from .Net.
Now on to the question:

If there's an unmanaged API class called X with a defined method

TypeA* foobar(TypeB* b, TypeC* c);
then how can my managed code (my c# app) deal with the problem of inputing
TypeB and TypeC since they are not known or compatible with managed code,
and how should my c# app deal with the TypeA* return type?

Well, you can always treat the pointers as opaque cookies or handles on the
managed side of things. If you do that you will need to validate the
"handles" before you dereference them (or suffer the consequences <g>).
Depending on how complicated the types are you may be able to define
equivalent "structs" for C#.

IMO, the most elegant way, and the one that often involves the most work is
to define a .Net proxy class each of whose instances contain a pointer to an
instance of a ntaive object. The constructor of the proxy class would take
advantage of MC++'s "it just works" capbility to hop the fence into
unmanaged code and invoke the constructore for the managed object. Every
public method in the proxy class would then marshall its arguments, delegate
to the corresponding in the native object and unmarshall the result.

These articles address some basic interop issues from the perspective of teh
C# developer:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp09192002.asp

http://msdn.microsoft.com/library/d...us/dncscol/html/csharp09192002.asp?frame=true

http://msdn.microsoft.com/library/d...us/dncscol/html/csharp09192002.asp?frame=true

And the book "Essential Guide to Managed Extensions for C++" (APRESS
1-893115-28-3) written by Challa and Laksberg (of the VC++ team) does a good
job of explaining interop from the perspective of a C++ programmer.

Note that VS2005 is going to change the syntax of managed C++ in a major
way.
PLEASE, reply also to ...

Post it here, read it here.

Regards,
Will
 
T

Tommy Svensson \(InfoGrafix\)

Well, sometimes what developers do is to define a managed class in MC++
(soon to be C++/CLI) which exposes the same public interface. That done,
callers written in any CLS compliant language can create objects of the MC++
class.


Yes, this is what I'm trying to do as it seems to be the fastest option.

Another option is to wrap up the C++ class into a COM object and then take
advanatge of the fact that .Net applications can consume COM objects.


No can do, the API is huge, more than 2 000 files and thousands of classes
and functions.

A third option is to "flatten" the existing object oriented interface into a
procedural one which exposes its interface via exported DLL functions and
then use .Net's Platform/Invoke (aka P/Invoke) from .Net.


No, for the same reason as above.


Well, you can always treat the pointers as opaque cookies or handles on the
managed side of things. If you do that you will need to validate the
"handles" before you dereference them (or suffer the consequences <g>).
Depending on how complicated the types are you may be able to define
equivalent "structs" for C#.


Ok, so in the API I have a type called WString which is a unicode string
type only.

If I try to return a string of type WString from a MC++ class to managed
code like this

char* wrapper::returnString()
{
return m_apiObj->my_WString.c_str();
}

then how should I receive this string? Like this:

String str = wrapperObj.returnString();

Will this work? How will I know what unmanaged string are compatible with
..NETs single string type String?

IMO, the most elegant way, and the one that often involves the most work is
to define a .Net proxy class each of whose instances contain a pointer to an
instance of a ntaive object. The constructor of the proxy class would take
advantage of MC++'s "it just works" capbility to hop the fence into
unmanaged code and invoke the constructore for the managed object. Every
public method in the proxy class would then marshall its arguments, delegate
to the corresponding in the native object and unmarshall the result.


Is there a list somewhere of what unmanaged types get unmarshalled to what
managed types?

These articles address some basic interop issues from the perspective of teh
C# developer:



Thx!
 
W

William DePalo [MVP VC++]

Tommy Svensson (InfoGrafix) said:
Ok, so in the API I have a type called WString which is a unicode string
type only.

If I try to return a string of type WString from a MC++ class to managed
code like this

char* wrapper::returnString()
{
return m_apiObj->my_WString.c_str();
}

Well, why do you want to a null terminated array of characters to your
managed proxy? That's done in the unmanaged world mostly because in the
beginning (K&R days) that's all there was. .Net has a string class, so it
seems more nature to invoke the constructor of System::String(). And if your
managed class is going to be used by, say C# clients or VB.Net clients, you
certainly don't want to be exposing character strings of null terminated
characters. Or do you?
Will this work? How will I know what unmanaged string are compatible with
.NETs single string type String?

Instances of System::String are composed of wide characters. Take a look at
its constructors and build one from your unmanaged array of characters.
Is there a list somewhere of what unmanaged types get unmarshalled to what
managed types?

I don't know. Perhaps someone else here has an idea.

You are welcome.

Regards,
Will
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top