Re: passing using "string" type in DLL Interface
"Sarath" <CSarath@gmail.com> ha scritto nel messaggio
news:a0efb03d-c918-4329-8229-f2650468b6b6@i12g2000prf.googlegroups.com...
On Dec 21, 2:41 am, "Brian Muth" <bm...@mvps.org> wrote:
I had planned like this to share the data
between the DLL interface and EXE. But I heard like it's not advisable
to share stl containers across. So I really got confused. vector<data>
could be a good bet.
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.
<header>
// (DLL) Header file: MyCollection.h
#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;
// Creates an instance of the collection; returns its handle
MYDATACOLLECTION MyDataCollection_Create( int startSize );
// Cleanups an instance of data collection, given its handle
void MyDataCollection_Destroy(MYDATACOLLECTION x);
// Reads string #1 of a data in a collection,
// given collection handle and item index (0-based)
const char * MyDataCollection_GetStr1(MYDATACOLLECTION x, int itemIndex);
// Sets the string #1 value of a data in a collection,
// given collection handle and data index
void MyDataCollection_SetStr1(MYDATACOLLECTION x, int itemIndex, const char
* str);
....
.... other "methods" (MyDataCollection_Xxxxxx) prototypes here
....
#ifdef __cplusplus
}; // extern "C"
#endif
</header>
Then you can have a C++ implementation in a DLL file (not exposed to the
extern):
<implementation>
// MyCollection.cpp
//
// A single data class
//
class MyData
{
public:
// I would prefer exposing Get/Set methods
// instead of "raw" data members here...
std::string Str1;
std::string Str2;
};
//
// A collection of data
//
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;
}
// Cleanups an instance of data collection, given its handle
extern "C"
void MyDataCollection_Destroy(MYDATACOLLECTION x)
{
MyDataCollection * d = (MyDataCollection *)x;
delete d;
}
// Reads string #1 of a data in a collection,
// given collection handle and item index (0-based)
extern "C"
const char * MyDataCollection_GetStr1(MYDATACOLLECTION x, int itemIndex)
{
MyDataCollection * d = (MyDataCollection *)x;
return d->Data.at(itemIndex).Str1.c_str();
}
// Sets the string #1 value of a data in a collection,
// given collection handle and data index
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 );
}
....
....
</implementation>
However, I think that for complex data structures or lots of operations on
these data structures, this kind of C-interface-wrapper solution could
produce "boilerplate" code.
Instead, I would consider directly exposing C++ STL data/string/containers,
if you are sure that your DLL and EXE can be built using the *same*
compiler.
Else, you may consider investing time in learning COM (and ATL, as a good
tool for COM development), and expose robust reusable COM objects
(interfaces) from your DLL; so you can use them in very different contexts
and languages (different C++ compilers, C#, VB6, VB.NET...).
In that case, I think you may find the ATL group microsoft.public.vc.atl a
very good place to ask for advice (there are experts like Brian M. or Igor
T. who give valuable quality help there).
Giovanni