Re: passing using "string" type in DLL Interface
Giovanni Dicanio wrote:
To add to what others said, there would be another option, i.e. you might
want to wrap your C++ data structures using an object-oriented C code.
e.g. in a C-interface header file you could expose functions which maps to
your C++ objects methods/properties, e.g.
This works, but looking at the code....
#ifdef __cplusplus
extern "C" {
#endif
// MYDATACOLLECTION is a kind of a "opaque handle"
// to a data collection instance.
// An handle uniquely identifies the collection instance.
typedef struct tagMyDataCollection
{
int dummy;
} * MYDATACOLLECTION;
What is the dummy for? No, seriously, firstly you can have empty structures
and secondly you don't have to define the structure at all!
// Creates an instance of the collection; returns its handle
MYDATACOLLECTION MyDataCollection_Create( int startSize );
Since this returns just an (obfuscated) pointer, you don't have to define
what it points to. A mere declaration is enough, dito for the other
functions you showed.
#ifdef __cplusplus
}; // extern "C"
#endif
If I'm not mistaken, that semicolon is syntactically wrong.
class MyDataCollection
{
public:
// Use std::vector to store collection of data
std::vector< MyData > Data;
}
// Creates an instance of the collection; returns its handle
extern "C"
MYDATACOLLECTION MyDataCollection_Create(int startSize)
{
MyDataCollection * d = new MyDataCollection();
d->Data.resize(startSize);
return (MYDATACOLLECTION)d;
}
If you had just a declaration, you could define your structure here,
allocate it (using nothrow new, of course!) and return it to the caller:
// header
struct collection;
collection* collection_create( size_t initial_size);
// implementation
struct collection {
collection( size_t initial_size);
std::vector<element> elements;
};
collection* collection_create( size_t initial_size) {
return new (nothrow) collection(initial_size);
}
In particular this doesn't introduce dummy types that only can be abused and
also avoids C-style casts which any sane C++ programmer should ban to the
furthest corner of their toolbox. In short, it simply provides type-safety.
extern "C"
void MyDataCollection_SetStr1(MYDATACOLLECTION x, int itemIndex, const
char * str)
{
MyDataCollection * d = (MyDataCollection *)x;
return d->Data.at(itemIndex).Str1 = std::string( str );
}
Using vector<>::at() implicitly says you don't trust the given index and
that it should throw an exception if it isn't valid. However, exceptions
are another thing that are not portable between compilers, so you
absolutely must no throw exceptions to the outside world.
Uli