9

I have a problem sharing "std::string" data between MS Visual C++ DLL library and Qt program.

What I have are:

  • DLL library written in Visual C++ 2010 Express, which exports one method:

    extern "C" __declspec(dllexport) int Init(ITest* commandTest);
    
  • Abstract interface "ITest" and a class implementing it:

    class CTest: public ITest
    {
    public:
        CTest();
        virtual ~CTest();
        virtual void getVersion(std::string & version) const;
    };
    
  • Qt GUI application that needs to:

    * load the DLL dynamically
    * instantiate CTest and pass it to exported Init method.
    

In DLL's "Init" a "CTest::getVersion()" method is called. I'd expect it would get the "&version" string filled in. What I get instead are crashes on the line when I fill "&version" with new string.

What I already did:

  • downloaded "Qt libraries 4.8.3 for Windows (VS 2010, 235 MB)" from http://qt-project.org/downloads, installed it and selected it in QtCreator's project settings.

  • in QtCreator switched from MinGW toolchain to the one installed with MS Visual Studio 2010 Express.

    I thought that it will overcome the problem , because I used Qt libraries compiled with VS 2010 and the Qt GUI was also compiled with VS C++ toolchain then. Unfortunately the problem was not gone, so I tried the last step:

  • created Win32 Console application in Visual Studio, loaded my DLL via LoadLibrary, used "Init" method the same way as I did in Qt GUI... and it worked!!

Small observation

In "CTest::getVersion()" I am printing this "version" string passed by reference to the console. When using VS C++ console app as a host it is printed out correctly. When using Qt app - the "version" string is printed with some garbage around (e.g. ┌►☻qwerty27)

This makes me think that ABI of Qt app and my DLL is still incompatible, even when using Qt VS 2010 libraries mentioned above.

Questions:

  • Is using Qt libraries for Windows (VS 2010) and Visual Studio toolchain not enough to overcome ABI compatibility issues?
  • Does it mean I should compile the Qt framework on my own?
  • Please help - any ideas are welcome...
schedar
  • 419
  • 6
  • 21
  • Can you show the calling code where it crashes with the `version` string? – Tony The Lion Oct 02 '12 at 12:46
  • Which calling convention are you using? __cdecl, __stdcall or __fastcall? And are you using the same in your app and in your DLL? – Benj Oct 02 '12 at 12:51
  • Compare your project settings with those of the command line application that is working. I'd bet your problem is not in the source code. – Alexander Tobias Bockstaller Oct 02 '12 at 12:52
  • The default calling convention is in C/C++ -> Advanced -> Calling Convention although it's possible to override in your __declspec. – Benj Oct 02 '12 at 12:53
  • 5
    What runtime library are you using for each of the projects (dll and exe)? Also, if the pre-built binary you downloaded was built with a different implementation of `std::string` than VS2010 express, that would be a problem and could be fixed by building Qt yourself. – tmpearce Oct 02 '12 at 12:58
  • Are there Qt dlls from some different version of Qt or different compiler in your path? – drescherjm Oct 02 '12 at 13:28
  • Check your ANSI vs Unicode settings. Make sure it is the same in both DLLs. – Zan Lynx Oct 02 '12 at 15:58
  • 4
    This sounds like mixing release and debug builds. The `std::string` objects in MSVC have a different representation by default in release and debug builds (specifically due to the `_ITERATOR_DEBUG_LEVEL` macro setting). If your DLL and the Qt application have a different `_ITERATOR_DEBUG_LEVEL` setting, then the `std::string` objects will be different. – Michael Burr Oct 03 '12 at 06:36
  • 1
    Thank you all for response. I fixed the problem after checking @tmpearce comment, although the comment of michael-burr is good as well. I have checked the runtime libraries with Dependency Walker. DLL was built with "Debug" configuration active which in turn caused loading MSVCP100D.dll and MSVCR100D.dll debug libs. When using the same libraries, Qt VS 10 that I've downloaded is working fine. Here's the link to sample projects if anyone would like to try: http://dl.dropbox.com/u/176393/SO/12690457.ZIP There are the sample sources of Dll library, VS C++ console app and a Qt app. – schedar Oct 03 '12 at 17:44
  • Since I can't accept two answers, I'll accept the first one that came. @tmpearce - I'll accept your answer if you post it. – schedar Oct 03 '12 at 17:49
  • 3
    @schedar I think it would be more instructive if you were to answer the question yourself with the details of what you did to fix it, so that future searchers would benefit most from your experience. You can answer and accept your own question. – tmpearce Oct 03 '12 at 17:51
  • You should never pass a std::string or other classes from stl through a dll interface since it depends on the runtime and as in your case on the compiler switches. You could pass a char* or create a small wrapper around stl::string and export this class instead. – David Feurle Oct 10 '12 at 14:41
  • Even if you should not pass any stl classes through dll borders - you could try to compile your programm without wchar_t as builtin type. Qt binaries are compile without. – David Feurle Oct 29 '12 at 14:27
  • @schedar Why don't you post the solution you found so this question can be closed as solved? – sashoalm Nov 28 '12 at 16:16

2 Answers2

1

In a project I had a situation much like yours, two DLLs, same compiler (VC++ 2010). I was passing std::string from one to the other and getting a lot of crashes.

The problem was one DLL was compiled with Multi-threaded Debug DLL (/MDd) and the other with Multi-threaded Debug (/MTd) this caused binary incompatibility between the two DLLs (crashes). Also the versions have to match, either use DEBUG or RELEASE for both DLLs.

Looking at your project, both DLLs seem to be using Multi-threaded Debug DLL (/MDd). this means both are using MSVCP100D.dll. This is ok, the only problem is that the VC++ version of qt from the QT website is compiled in RELEASE mode and is using MSVCP100.DLL

My recommendation is to change your runtime library to Multi-threaded DLL (/MD) for your DEBUG configuration.

My second recommendation is to follow Rebert's advice and use char* instead of std::string. char* will be compatible no matter what.

You can also recompile QT with Multi-threaded Debug DLL (/MDd) and use that version of QT for your DEBUG configuration (but this seems like to much work).

0

Nominally I would not venture into passing complex data (out of my control, codewise) between an application and a DLL. I would resort to only pass POD structures, i.e. I would change the interface to this instead:

class CTest: public ITest
{
public:
    CTest();
    virtual ~CTest();
    virtual void getVersion(char* versionBuffer, unsigned length) const;
};

Makes life a lot easier ;)

Robert
  • 2,330
  • 29
  • 47