Thread: DLL and std::string woes!

  1. #1
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145

    DLL and std::string woes!

    After a lot of testing and searching I've managed to make a short program containing the error. I have a program that loads a DLL with a class that has a method that returns an std::string. Now, the problem is if the stirng is destroyed before FreeLibrary() is called everything is fine, but if it's destroyed after FreeLibrary() is called the program crashes.

    Here is the public header for the DLL:
    (DllPublic.h)
    Code:
    #ifndef DLL
    #ifdef DLL_EXPORT
    #define DLL __declspec(dllexport)
    #else
    #define DLL __declspec(dllimport)
    #endif
    #endif
    
    #include <windows.h>
    #include <string>
    
    class StringClass
    {
    	public:
    		virtual std::string GetString() = 0;
    };
    
    typedef StringClass* (*FUNCTION_CREATE)(VOID);
    typedef VOID (*FUNCTION_DESTROY)(StringClass*);
    
    extern "C" DLL StringClass* CreateStringClass();
    extern "C" DLL VOID DestroyStringClass(StringClass* Object);
    Here is the DLL header only used when compiling the DLL:
    (Dll.h)
    Code:
    #include "DllPublic.h"
    
    class DllStringClass : public StringClass
    {
    	public:
    		DllStringClass();
    		virtual std::string GetString();
    
    	private:
    		std::string String;
    };
    Here is the body for the DLL:
    (Dll.cpp)
    Code:
    #define DLL_EXPORT
    #include "Dll.h"
    
    DllStringClass::DllStringClass()
    {
    	String = "Some random string!";
    }
    
    std::string DllStringClass::GetString()
    {
    	return String;
    }
    
    extern "C" DLL StringClass* CreateStringClass()
    {
    	return new DllStringClass;
    }
    
    extern "C" DLL VOID DestroyStringClass(StringClass* Object)
    {
    	delete Object;
    }
    Now, consider these two testprograms. I use dynamic memory for the std::string to easier see when it is destroyed. It makes no difference if it was created staticly.

    This program, where the std::string destructor is called before FreeLibrary() runs fine and as expected:
    Code:
    #include "Dll\\DllPublic.h"
    
    INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
    {
    	HINSTANCE Dll = LoadLibrary("Dll.dll");
    	std::string* S = new std::string;
    
    	FUNCTION_CREATE Create = reinterpret_cast<FUNCTION_CREATE>(GetProcAddress(Dll, "CreateStringClass"));
    	FUNCTION_DESTROY Destroy = reinterpret_cast<FUNCTION_DESTROY>(GetProcAddress(Dll, "DestroyStringClass"));
    
    	StringClass* SC = Create();
    	(*S) = SC->GetString();
    	Destroy(SC);
    
    	MessageBox(NULL, S->c_str(), "Message", MB_OK);
    	delete S;
    	FreeLibrary(Dll);
    	return 0;
    }
    ...but if you delete it after FreeLibrary you get a crash:
    Code:
    #include "Dll\\DllPublic.h"
    
    INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
    {
    	HINSTANCE Dll = LoadLibrary("Dll.dll");
    	std::string* S = new std::string;
    
    	FUNCTION_CREATE Create = reinterpret_cast<FUNCTION_CREATE>(GetProcAddress(Dll, "CreateStringClass"));
    	FUNCTION_DESTROY Destroy = reinterpret_cast<FUNCTION_DESTROY>(GetProcAddress(Dll, "DestroyStringClass"));
    
    	StringClass* SC = Create();
    	(*S) = SC->GetString();
    	Destroy(SC);
    
    	MessageBox(NULL, S->c_str(), "Message", MB_OK);
    	FreeLibrary(Dll);
    	delete S;
    	return 0;
    }
    Um, why? Suggestions? Solutions? Help?
    Last edited by Magos; 09-08-2004 at 07:16 AM.
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  2. #2
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    What compiler are you using?

    It seems to work either way for me on VC++7

  3. #3
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Vc++6 :/
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  4. #4
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Have you tried as I suggested before and had the function return a char array as opposed to a std::string? I know you dont like the practicalities of that, but see if it makes a difference

  5. #5
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    You cannot share STL data between modules in VC++6. The STL implementation uses class-static members, which will differ between modules (DLL and EXE).

    Use a different STL and you will be fine.

    There is a knowledge-base article about this somewhere.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  6. #6
    &TH of undefined behavior Fordy's Avatar
    Join Date
    Aug 2001
    Posts
    5,793
    Quote Originally Posted by Sang-drax
    You cannot share STL data between modules in VC++6. The STL implementation uses class-static members, which will differ between modules (DLL and EXE).

    Use a different STL and you will be fine.

    There is a knowledge-base article about this somewhere.
    http://support.microsoft.com/default...NoWebContent=1

  7. #7
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Have you tried as I suggested before and had the function return a char array as opposed to a std::string?
    Yes, returning a const char* seems to work fine.

    Use a different STL and you will be fine.
    Different STL? What do you mean?

    http://support.microsoft.com/defaul...&NoWebContent=1
    The suggested workaround ( http://support.microsoft.com/default...b;EN-US;168958 ) is a bit confusing. You cannot use the __declspec(dllexport) template class on a std::string like you can on a std::vector or other container. Any suggestions? Or is my only hope to either upgrade to VC7.0 (or whatever version is the current one) or degrade to returning char pointers (yuck)?
    MagosX.com

    Give a man a fish and you feed him for a day.
    Teach a man to fish and you feed him for a lifetime.

  8. #8
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> Use a different STL [implementation] and you will be fine.
    Like STL Port

    You should also be aware of this knowledge base article as well.

    Because of all these issues, I personally don't allow STL or CRT objects to cross module boundaries. I don't mind allowing allocated memory to cross module boundaries as long as the allocation and dealloction is done in the same module.

    gg
    Last edited by Codeplug; 09-08-2004 at 12:36 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to solve warnings that appear when building my DLL...
    By starcatcher in forum Windows Programming
    Replies: 6
    Last Post: 12-14-2008, 11:47 AM
  2. Need Partners (D&D fan preferably)
    By C_ntua in forum Game Programming
    Replies: 44
    Last Post: 11-22-2008, 09:21 AM
  3. dll testing
    By axr0284 in forum Windows Programming
    Replies: 1
    Last Post: 03-26-2006, 10:25 PM
  4. Pipe the console from a DLL
    By loobian in forum Windows Programming
    Replies: 12
    Last Post: 11-30-2003, 08:55 PM
  5. std::string vs char* DLL problem
    By aker_y3k in forum C++ Programming
    Replies: 13
    Last Post: 10-02-2002, 09:05 AM