C interface to C++ classes

B

Bit byte

I have a set of C++ classes for which I want to provide a C API - and
compile into a C DLL, for use in an application that can only work with
a C interface DLL.

Any suggestions/pointers on how to proceed. Googling is not bringng
anything up that directly addresses the issue (parashift info is useful,
but does not deal specifically, with the isse)
 
G

Guest

I have a set of C++ classes for which I want to provide a C API - and
compile into a C DLL, for use in an application that can only work with
a C interface DLL.

Any suggestions/pointers on how to proceed. Googling is not bringng
anything up that directly addresses the issue (parashift info is useful,
but does not deal specifically, with the isse)

You are not using LabVIEW by any chance? :)
I have done something similar, and I created a dll with C functions that
forwarded the arguments to C++ objects. instead of using 'new' i provided a
function that created an object and then supplied the pointer as an output
parameter.
for each function you have to supply that pointer.

something like:

int fun(object* myObject, int arg1, int arg2)
{
myObject->fun(arg1, arg2);
}

If all you want is to have a 1 on 1 mapping of functions, you could probably
create a script that takes the class definitions, and then generates wrappers
for it.

Of course this only works if your classes use simple datatypes for passing
data because you cannot use std::string and others for passing data between
your app and dll. you also have to be careful with structures, since some
programming languages cannot create all types of structure.

I know that this is not what you wanted to hear, but unless your data and
your classes are trivial, You have to do a lot of things by hand.
Are there specific things that you still need to know?

--

Kind regards,
Bruno.
(e-mail address removed)
Remove only "_nos_pam"
 
D

Doug Harrison [MVP]

I have a set of C++ classes for which I want to provide a C API - and
compile into a C DLL, for use in an application that can only work with
a C interface DLL.

Any suggestions/pointers on how to proceed. Googling is not bringng
anything up that directly addresses the issue (parashift info is useful,
but does not deal specifically, with the isse)

You'll have to create a set of C functions that map to C++ counterparts,
and you'll have to pass the this pointer around in some way. Something like
this should work:

class X
{
public:

X();

void f();
};

// C interface

#ifdef __cplusplus
extern "C" {
#endif

// Type-safe, opaque pointer.
typedef struct C_X_* X_Handle;

// Export these using __declspec, for example

X_Handle CreateX();
void DestroyX(X_Handle x);

void X_f(X_Handle x);

#ifdef __cplusplus
}
#endif

// C++ implementation

X_Handle CreateX()
{
return reinterpret_cast<X_Handle>(new X);
}

void DestroyX(X_Handle x)
{
delete reinterpret_cast<X*>(x);
}

void X_f(X_Handle x)
{
reinterpret_cast<X*>(x)->f();
}

Just make sure you only ever store an X* in an X_Handle and vice versa. Oh,
and your C++ wrapper functions should not allow exceptions to propagate out
through C functions; they should return error codes instead.
 
B

Bit byte

Doug said:
You'll have to create a set of C functions that map to C++ counterparts,
and you'll have to pass the this pointer around in some way. Something like
this should work:

class X
{
public:

X();

void f();
};

// C interface

#ifdef __cplusplus
extern "C" {
#endif

// Type-safe, opaque pointer.
typedef struct C_X_* X_Handle;

// Export these using __declspec, for example

X_Handle CreateX();
void DestroyX(X_Handle x);

void X_f(X_Handle x);

#ifdef __cplusplus
}
#endif

// C++ implementation

X_Handle CreateX()
{
return reinterpret_cast<X_Handle>(new X);
}

void DestroyX(X_Handle x)
{
delete reinterpret_cast<X*>(x);
}

void X_f(X_Handle x)
{
reinterpret_cast<X*>(x)->f();
}

Just make sure you only ever store an X* in an X_Handle and vice versa. Oh,
and your C++ wrapper functions should not allow exceptions to propagate out
through C functions; they should return error codes instead.

Hi Doug,

Thanks for that. This is the skinda stuff I was looking for.

Npow, are there any gotchas etc w.r.t the ff:

1). virtual methods - can 'exported class ' class X (given in your
example), contain virtual methods?

2). invoking methods on derived classes (can 'exposed clsss' class X
have been derived from another C++ class ? ) - i.e. class X : public Y,
or can you only expose a C interface to classes that are not inheriting
from another class.?

3). Which of the ff do you reckon is the better approach:
(i). Create a C++ DLL and then create a C DLL that uses the C++ DLL
(ii). Compile the C++ classes with an exported C API in the DLL - i.e.
one Dll

4). How can callback functions be implemented in the C API?
suppose we have the ff:

void (CB_FUNC*)(const type1, cponst type2*);

//C++ header
class X {
public:
X();
virtual ~X(); // <- is virtual ok ?

registerCallback(CB_FUNC, void* data); //how is this exported
an used from the C API ?

};
 
D

Doug Harrison [MVP]

Hi Doug,

Thanks for that. This is the skinda stuff I was looking for.

Npow, are there any gotchas etc w.r.t the ff:

1). virtual methods - can 'exported class ' class X (given in your
example), contain virtual methods?

2). invoking methods on derived classes (can 'exposed clsss' class X
have been derived from another C++ class ? ) - i.e. class X : public Y,
or can you only expose a C interface to classes that are not inheriting
from another class.?

Neither (1) nor (2) should pose a problem as long as you "only ever store
an X* in an X_Handle and vice versa". For example, if Y were derived from
X, you would convert a Y* to X* before converting to X_Handle. Using
X_Handle per my previous message is really just a way to get some type
safety on the C side of the equation, for which it's much better than using
void*. Under the hood, however, it's not very different. (Windows uses a
similar technique for HWND, HFONT, etc.)
3). Which of the ff do you reckon is the better approach:
(i). Create a C++ DLL and then create a C DLL that uses the C++ DLL
(ii). Compile the C++ classes with an exported C API in the DLL - i.e.
one Dll

Hard to say. If the C API is as integral to your usage as the C++ API, I'd
go with the one DLL. If you go with two DLLs, your DLL clients will be able
to use either interface, which may or may not be good. Well, I guess you
could choose not to supply a C++ header, which would make things more
difficult for the would-be C++ user.
4). How can callback functions be implemented in the C API?
suppose we have the ff:

void (CB_FUNC*)(const type1, cponst type2*);

//C++ header
class X {
public:
X();
virtual ~X(); // <- is virtual ok ?

registerCallback(CB_FUNC, void* data); //how is this exported
an used from the C API ?

};

Again, as long as you keep your types consistent across the language
boundaries, "virtual" won't be a problem. As your callback takes a regular
function pointer (not a pointer to member function), you could use
something like this:

extern "C" void RegisterCallback(X_Handle obj, CB_FUNC cb, void* data)
{
// But don't propagate exceptions...
((X*) obj)->registerCallback(cb, data);
}

It would get more complicated if CB_FUNC's parameters were C++ types. I'd
consider hanging it up if CB_FUNC were a pointer to member.
 
G

Guest

You might get something close to virtual functions:

// With apologies to Doug, for borrowing his code
class X
{
public:
X();

virtual void f();
};

class Y : public X
{
public:
Y();

virtual void f();
};

// C interface

#ifdef __cplusplus
extern "C" {
#endif

// Type-safe, opaque pointer.
typedef struct C_X_* X_Handle;
typedef struct C_Y_* Y_Handle;

// Export these using __declspec, for example

X_Handle CreateX();
void DestroyX(X_Handle x);

Y_Handle CreateY();
void DestroyY(Y_Handle y);

void X_f(X_Handle x);
void Y_f(Y_Handle y);

#ifdef __cplusplus
}
#endif

// C++ implementation

X_Handle CreateX()
{
return reinterpret_cast<X_Handle>(new X);
}

void DestroyX(X_Handle x)
{
delete reinterpret_cast<X*>(x);
}

void X_f(X_Handle x)
{
reinterpret_cast<X*>(x)->f();
}

Y_Handle CreateY()
{
return reinterpret_cast<Y_Handle>(new Y);
}

void DestroyY(Y_Handle y)
{
delete reinterpret_cast<Y*>(y);
}

void Y_f(Y_Handle y)
{
reinterpret_cast<Y*>(y)->f();
}

So far, so good. If we have an X object, we can use the CreateX, DestroyX
and X_f functions; and if we have a Y object, we can use the CreateY,
DestroyY and Y_f functions. But to truly get the "virtual" part going, we
would need to do something like this and have it work:

Y_Handle y = CreateY();
X_f(y); // if this is really virtual, it will call the Y object's version of
f.

But here's the problem: The first parameter of X_f must be of type X_Handle
(really type C_X_*). But the variable y is of type Y_Handle (or type C_Y_*).
Therefore, the code X_f(y) won't compile, because the types don't match, and
there is no implicit conversion from C_Y_* to C_X_*.

Something like X_f(reinterpret_cast<X_Handle>(y)) might do it, though. I'd
give it a shot. Presumably the y variable, which has type C_Y_* would first
be cast to type X_Handle (or C_X_*), then cast again to type X* inside the
X_f function. Then the program would see a pointer to an X object try to
select its member f function. Since y really points to a Y object, and f is
virtual, you would theoretically get Y's version of f.

Even if it doesn't work, you'll learn something about just how far you can
cast a pointer before it breaks. :)

Sean
 
G

Guest

My apologies, I forgot what language I was in for a moment when I said:
Something like X_f(reinterpret_cast<X_Handle>(y)) might do it, though. I'd
give it a shot. Presumably the y variable, which has type C_Y_* would first
be cast to type X_Handle (or C_X_*), then cast again to type X* inside the
X_f function. Then the program would see a pointer to an X object try to
select its member f function. Since y really points to a Y object, and f is
virtual, you would theoretically get Y's version of f.

Of course, on the C side of things, you're not going to be able to use
reinterpret_cast. So you should try something like this instead:

X_f((X_Handle)(y));

Sean
 
C

Carl Daniel [VC++ MVP]

Bit said:
Hi Doug,

Thanks for that. This is the skinda stuff I was looking for.

Npow, are there any gotchas etc w.r.t the ff:

1). virtual methods - can 'exported class ' class X (given in your
example), contain virtual methods?

Yes, but you'll have to be careful in some circumstances. One thing you
might consider is exposing a COM interface, which can be consumed from C as
well as C++ and provides in essense a mapping of C++ virtual function
dispatching to C.
2). invoking methods on derived classes (can 'exposed clsss' class X
have been derived from another C++ class ? ) - i.e. class X : public
Y, or can you only expose a C interface to classes that are not
inheriting from another class.?

Derivation doesn't matter. What matters is how you cast the 'this' pointer.
As long as there's no multiple inheritance involved, you don't really have
to worry about it.
3). Which of the ff do you reckon is the better approach:
(i). Create a C++ DLL and then create a C DLL that uses the C++ DLL
(ii). Compile the C++ classes with an exported C API in the DLL - i.e.
one Dll

Whichever is more appropriate to your project. I've used both techniques,
depending on circumstances either might be better for you. If you don't
have a good reason to implement two DLLs, I'd for for the single DLL
solution just because it's simpler.
4). How can callback functions be implemented in the C API?
suppose we have the ff:

void (CB_FUNC*)(const type1, cponst type2*);

//C++ header
class X {
public:
X();
virtual ~X(); // <- is virtual ok ?

registerCallback(CB_FUNC, void* data); //how is this exported
an used from the C API ?

Callbacks of this type aren't really anything special, since the callback is
an ordinary function pointer.

you'd export the callback registration function using something along the
lines of:

registerCallback(X_Handle, CB_FUNC, void*);

HTH

-cd
 
B

Bit byte

Doug said:
You'll have to create a set of C functions that map to C++ counterparts,
and you'll have to pass the this pointer around in some way. Something like
this should work:

class X
{
public:

X();

void f();
};

// C interface

#ifdef __cplusplus
extern "C" {
#endif

// Type-safe, opaque pointer.
typedef struct C_X_* X_Handle;

// Export these using __declspec, for example

X_Handle CreateX();
void DestroyX(X_Handle x);

void X_f(X_Handle x);

#ifdef __cplusplus
}
#endif

// C++ implementation

X_Handle CreateX()
{
return reinterpret_cast<X_Handle>(new X);
}

void DestroyX(X_Handle x)
{
delete reinterpret_cast<X*>(x);
}

void X_f(X_Handle x)
{
reinterpret_cast<X*>(x)->f();
}

Just make sure you only ever store an X* in an X_Handle and vice versa. Oh,
and your C++ wrapper functions should not allow exceptions to propagate out
through C functions; they should return error codes instead.

Hi Doug,

Just needed to clarify - where does one actually define struct C_X ?

I mean do I need to create a similar structure in the C code (similar to
class X?).

I mean I can't see how we can enforce type safety of the pointers since
struct C_X is not defined anywhere. Am I missing something?

Please explain
 
D

Doug Harrison [MVP]

Hi Doug,

Just needed to clarify - where does one actually define struct C_X ?

I mean do I need to create a similar structure in the C code (similar to
class X?).

I mean I can't see how we can enforce type safety of the pointers since
struct C_X is not defined anywhere. Am I missing something?

Please explain

No, you shouldn't try to mimic the C++ type in C. The idea is for the C
side of things to work only with the opaque pointer type X_Handle, which is
declared like this:

typedef struct C_X_* X_Handle;

The struct C_X_ is an incomplete type that is never completed. You can
declare such a type inline in the typedef, like I did, and it's equivalent
to:

struct C_X_;
typedef struct C_X_* X_Handle;

You can't even dereference an X_Handle; about all you can do is copy it,
such as when you pass it to functions, and take its address. Think of
X_Handle as analogous to HWND, HDC, etc, and you've got it. The typedef
X_Handle is safer than using void*, since each C++ type exposed to C in
this way will have its own personal handle type. The name C_X_ is
arbitrary; Windows does this so much, MS created a macro to ease the
declaration of handles, and IIRC, it's called DECLARE_HANDLE.
 
B

Bit byte

Doug said:
No, you shouldn't try to mimic the C++ type in C. The idea is for the C
side of things to work only with the opaque pointer type X_Handle, which is
declared like this:

typedef struct C_X_* X_Handle;

The struct C_X_ is an incomplete type that is never completed. You can
declare such a type inline in the typedef, like I did, and it's equivalent
to:

struct C_X_;
typedef struct C_X_* X_Handle;

You can't even dereference an X_Handle; about all you can do is copy it,
such as when you pass it to functions, and take its address. Think of
X_Handle as analogous to HWND, HDC, etc, and you've got it. The typedef
X_Handle is safer than using void*, since each C++ type exposed to C in
this way will have its own personal handle type. The name C_X_ is
arbitrary; Windows does this so much, MS created a macro to ease the
declaration of handles, and IIRC, it's called DECLARE_HANDLE.

Thanks Doug, you've been a real help. I can finally get to doing some
coding now...
 

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