Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to expose STL list over DLL boundary?

Tags:

c++

stl

abi

I have a DLL which needs to access data stored in STL containers in the host application. Because C++ has no standard ABI, and I want to support different compilers, the interface between the application and DLL basically has to remain plain-old-data.

For vectors this is relatively straightforward. You can simply return the memory block of the vector, because it is guaranteed to be contigious:

// To return vector<int> data
virtual void GetVectorData(const int*& ptr, size_t& count) const
{
    if (!vec.empty())
        ptr = &(vec.front());

    count = vec.size();
}

Now the DLL can have safe read-only access to the vector's data via that interface. The DLL can also wrap this to copy the contents in to a vector for itself as well.

What about STL lists (and deques) though? Is there another straightforward way to allow access via a DLL boundary? Or will I have to resort to some kind of GetFirst()/GetNext() interface? I might need to do this for a lot of lists, so it'd be nice to have a solution as simple as vector's.

like image 240
AshleysBrain Avatar asked Dec 10 '09 14:12

AshleysBrain


2 Answers

You can pass stl objects between DLLs and support different compilers if you are careful where you instantiate each stl type. You need some intelligent "DLLEXPORT" macros -- I use the following set to successfully support VC and gcc.

#ifdef WIN32
#ifdef MYDLLLIB_EXPORTS      // DLL export macros
#define MYDLLLIB_API __declspec(dllexport)
#define MYDLLLIB_TEMPLATE
#else
#define MYDLLLIB_API __declspec(dllimport)
#define MYDLLLIB_TEMPLATE extern
#endif
#else                       // Not windows --- probably *nix/bsd
#define MYDLLLIB_API
#ifdef MYDLLLIB_EXPORTS
#define MYDLLLIB_TEMPLATE
#else
#define MYDLLLIB_TEMPLATE extern
#endif
#endif // WIN32

When compiling your DLL, define MYDLLLIB_EXPORTS. In the DLL you can then instantiate each stl type you wish to use, for example, lists or vectors of strings

MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::vector<std::string>;
MYDLLLIB_TEMPLATE template class MYDLLLIB_API std::list<std::string>;

Consumers of your DLL (who don't have MYDLLLIB_EXPORTS defined) will then see

extern template class __declspec(dllimport) std::vector<std::string>;

and use the binary code exported from your DLL instead of instantiating their own.

like image 97
mcdave Avatar answered Oct 01 '22 09:10

mcdave


Perhaps you can pass something like "handles" to list/deque iterators? These handle types would be opaque and declared in a header file you would ship to the users. Internally, you would need to map the handle values to list/deque iterators. Basically, the user would write code like:

ListHandle lhi = GetListDataBegin();
const ListHandle lhe = GetListDataEnd();

while (lhi != lhe)
{
  int value = GetListItem(lhi);
  ...
  lhi = GetNextListItem(lhi);
}
like image 25
Nemanja Trifunovic Avatar answered Oct 01 '22 09:10

Nemanja Trifunovic