How to Pass Std::String to a Dll

C++ Passing std::string by reference to function in dll

The issue has little to do with STL, and everything to do with passing objects across application boundaries.

1) The DLL and the EXE must be compiled with the same project settings. You must do this so that the struct alignment and packing are the same, the members and member functions do not have different behavior, and even more subtle, the low-level implementation of a reference and reference parameters is exactly the same.

2) The DLL and the EXE must use the same runtime heap. To do this, you must use the DLL version of the runtime library.

You would have encountered the same problem if you created a class that does similar things (in terms of memory management) as std::string.

Probably the reason for the memory corruption is that the object in question (std::string in this case) allocates and manages dynamically allocated memory. If the application uses one heap, and the DLL uses another heap, how is that going to work if you instantiated the std::string in say, the DLL, but the application is resizing the string (meaning a memory allocation could occur)?

Can you use std::string in a 3rd party dll?

Using a pointer to the string buffer like LPWSTR, or wchar_t*, etc will always be safe as long as your dll code is not invoking an unspecified behavior (memory is allocated correctly, pointer is initialized, you are not passing pointer to the local buffer, etc). Using an std::string will be safe only as long, as your dll and a host are using the same CRT version. If versions differ, your strings could cause an Access Violations on any execution stage (usually it happens on the string destruction). You may insure CRT matching by distributing your dll sources or by compiling different dll versions for all existing CRTs (Oracle, for example, does this for their OCCI library). This approach of course would not work if a client is not using C++.

Can a std::string be passed by value across DLL boundries?

No, because templated code is generated separately per module.

So, when your EXE instantiates a std::string and passes it to the DLL, the DLL will begin using a completely different implementation on it. The result is a total mess, but it often sorta almost works because implementations are very similar, or the mess is hard to detect because it's some kind of subtle heap corruption.

Even if they're both built with the same version of VS, it's very precarious / fragile, and I would not recommend it. Either use a C-style interface between modules (for example, COM), or just don't use a DLL.

More detailed explanation here: Creating c++ DLL without static methods

and here: How can I call a function of a C++ DLL that accepts a parameter of type stringstream from C#?

Passing std::string with dllexport

I think the problem is different string encoding.

Try adding CharSet = CharSet.Ansi in C#, like this:

[DllImport(@"Bridge.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

However, please read the documentation of that C++ dll API. A lot of C++ code, especially if that’s cross-platform code, expect UTF8-encoded strings. If that’s your case, instead change the bridge to

extern "C" __declspec(dllexport) void initCppClass(const wchar_t* foo, int something)

And write code to convert the string from UTF16-encoded C pointer into UTF8-encoded std::string, see this answer for an example.

Update: another possible reason is different STL, or different CRT. When you pass std::string or any other STL objects objects across DLL boundaries, you have to use same compiler & same version of it, same build settings for (e.g. in VC++, std::strings memory layout differs between debug and release builds), and also both DLLs must link to CRT dynamically., e.g. Multi-threaded DLL (/MD)



Related Topics



Leave a reply



Submit