Thread: Proper DLL class interfaces

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

    Proper DLL class interfaces

    I'm having problems getting a DLL interface to work on multiple compilers. The actual DLL is compiled in VC2003 and the client prog using it compiles and works fine in VC2003 also. However if compiled in another compiler (in this case DevCpp) it raises a seg fault exception when calling a class member.

    How do you make proper class interfaces that works on multiple compilers?

    Dll:
    Code:
    #include <windows.h>
    
    class C
    {
    	public:
    		virtual VOID Set(INT NewInt) = 0;
    		virtual INT Get() CONST = 0;
    };
    
    class CC : public C
    {
    	public:
    		CC()  { i = new INT(); }
    		~CC() { delete i;      }
    
    		virtual VOID Set(INT NewInt) { (*i) = NewInt; }
    		virtual INT Get() CONST      { return (*i);   }
    
    	protected:
    		INT* i;
    };
    
    C* c = NULL;
    
    extern "C" __declspec(dllexport) C* GetC()
    {
    	return c;
    }
    
    BOOL WINAPI DllMain(HINSTANCE Dll, DWORD Reason, LPVOID Reserved)
    {
    	switch(Reason)
    	{
    		case DLL_PROCESS_ATTACH:
    		{
    			c = new CC();
    			break;
    		}
    
    		case DLL_PROCESS_DETACH:
    		{
    			delete c;
    			break;
    		}
    	}
    
    	return TRUE;
    }
    Client:
    Code:
    #include <windows.h>
    
    class C
    {
    	public:
    		virtual VOID Set(INT NewInt) = 0;
    		virtual INT Get() CONST = 0;
    };
    
    typedef C* (*GET_C)();
    
    INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
    {
    	C* c;
    	GET_C GetC;
    
    	HINSTANCE Dll = LoadLibrary("..\\Release\\DllMultiCompilerTest.dll");
    	if(Dll == NULL)
    	{
    		MessageBox(NULL, "No dll!", "Message", MB_OK);
    		return 0;
    	}
    
    	GetC = reinterpret_cast<GET_C>(GetProcAddress(Dll, "GetC"));
    	if(GetC == NULL)
    	{
    		FreeLibrary(Dll);
    		MessageBox(NULL, "No func!", "Message", MB_OK);
    		return 0;
    	}
    
    	c = GetC();
    	if(c == NULL)
    	{
    		FreeLibrary(Dll);
    		MessageBox(NULL, "No object!", "Message", MB_OK);
    		return 0;
    	}
    
    	//*****************************************
    	//* This crashes DevCpp (but not VC++)
    	//*****************************************
    	c->Set(1337);
    	INT i = c->Get();
    
    	FreeLibrary(Dll);
    	MessageBox(NULL, "Success!", "Message", MB_OK);
    	return 0;
    }
    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
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Does it work on other compilers?
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    chococoder
    Join Date
    Nov 2004
    Posts
    515
    When compiling both with bcc32 5.5.1 I get "no func" so the DLL loads but the function can't be looked up in it.
    But that seems to be a problem with my setup, as other samples yield the same result.
    Trying a static linking gives a linker error on the method name but it's shown in all capitals.

    Attempting to compile the dll with VC2003 free compiler yields "windows.h not found", guess it needs to have the platform SDK installed which I don't have available on this machine.

  4. #4
    chococoder
    Join Date
    Nov 2004
    Posts
    515
    PS, when trying to compile the listed DLL source under VC2003 after installing the PSDK it won't link because of "unresolved external _main referenced in function _mainCRTStartup".

    compiling another sample DLL and then using it with an application compiled using bcc32 yields no problem, so I guess there's something weird in the DLL bcc32 compiled causing lookup errors.

  5. #5
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    I solved this a little while back, I had to add the keyword __stdcall to all class methods.
    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.

  6. #6
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Hm, it is not 100% solved apparently. In general it works very well but in some very rare cases the DevCPP code calls the wrong method.

    The methods have the same name, but different argument lists:
    Code:
    class C
    {
      virtual void m(const char* Name) = 0;
      virtual void m(const char* Name, int width, int height) = 0;
    }
    calling c->m("file.ext"); will in some cases call the 2nd method instead of the first for some odd reason (in DevCPP, not VC). There is no default argument values and the stubs (see other DLL post) points to the correct method. All methods have the same order in their declrations, no virtual destructors etc...

    I guess it can be hard to guess without code but the project is very large at the moment. I can only hope someone has experienced similar problems before and get an aha!-experience...

    It's the randomness that confuses me. If it were some error in the way I implement class interfaces it *should* be errors in all calls I make...
    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.

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

    I found the problem, the ordering of overloaded names (with different aegument lists) gets reversed on some compilers. Just watch this example program, when compiled in VC it gives the sequence 1 2 3 while in DevCPP it gives 3 2 1. So, what causes this and how can I solve it?

    The DLL is ALWAYS compiled in VC++2003 (the client in both VC and DevCPP).

    Dll:
    Code:
    #include <windows.h>
    
    interface I
    {
    	virtual INT __stdcall Get() = 0;
    	virtual INT __stdcall Get(INT X) = 0;
    	virtual INT __stdcall Get(INT X, INT Y) = 0;
    };
    
    class C : public I
    {
    	public:
    		C() { }
    		~C() { }
    
    		virtual INT __stdcall Get() { return 1; };
    		virtual INT __stdcall Get(INT X) { return 2; };
    		virtual INT __stdcall Get(INT X, INT Y) { return 3; };
    };
    
    I* c = NULL;
    
    extern "C" __declspec(dllexport) I* GetC()
    {
    	return c;
    }
    
    BOOL WINAPI DllMain(HINSTANCE Dll, DWORD Reason, LPVOID Reserved)
    {
    	switch(Reason)
    	{
    		case DLL_PROCESS_ATTACH:
    		{
    			c = new C();
    			break;
    		}
    
    		case DLL_PROCESS_DETACH:
    		{
    			delete c;
    			break;
    		}
    	}
    
    	return TRUE;
    }
    Client:
    Code:
    #include <windows.h>
    #include <sstream>
    
    interface I
    {
    	virtual INT __stdcall Get() = 0;
    	virtual INT __stdcall Get(INT X) = 0;
    	virtual INT __stdcall Get(INT X, INT Y) = 0;
    };
    
    typedef I* (*GET_C)();
    
    INT WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, INT)
    {
    	I* c;
    	GET_C GetC;
    	std::stringstream Stream;
    
    	HINSTANCE Dll = LoadLibrary("DllMultiCompilerTest.dll");
    	if(Dll == NULL)
    	{
    		MessageBox(NULL, "No dll!", "Message", MB_OK);
    		return 0;
    	}
    
    	GetC = reinterpret_cast<GET_C>(GetProcAddress(Dll, "GetC"));
    	if(GetC == NULL)
    	{
    		FreeLibrary(Dll);
    		MessageBox(NULL, "No func!", "Message", MB_OK);
    		return 0;
    	}
    
    	c = GetC();
    	if(c == NULL)
    	{
    		FreeLibrary(Dll);
    		MessageBox(NULL, "No object!", "Message", MB_OK);
    		return 0;
    	}
    
    	Stream << "Get (should be 1 2 3):\n" << c->Get() << " " << c->Get(0) << " " << c->Get(0, 0);
    	MessageBox(NULL, Stream.str().c_str(), "Message", MB_OK);
    
    	FreeLibrary(Dll);
    
    	return 0;
    }
    Last edited by Magos; 02-21-2006 at 04:13 PM.
    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
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    Forgot to mention, the DLL is ALWAYS compiled in VC++2003 (the client in both VC and DevCPP).
    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.

  9. #9
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    DirectX and COM can do this just fine, how do they do it? I couldn't find much technical information (implementation techniques) of how it works...
    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.

  10. #10
    semi-colon generator ChaosEngine's Avatar
    Join Date
    Sep 2005
    Location
    Chch, NZ
    Posts
    597
    Quote Originally Posted by Magos
    DirectX and COM can do this just fine, how do they do it? I couldn't find much technical information (implementation techniques) of how it works...
    DirectX is a COM component.

    have a read of this article on msdn. It explains how COM evolved from C++. It should help you fix your problem too.
    "I saw a sign that said 'Drink Canada Dry', so I started"
    -- Brendan Behan

    Free Compiler: Visual C++ 2005 Express
    If you program in C++, you need Boost. You should also know how to use the Standard Library (STL). Want to make games? After reading this, I don't like WxWidgets anymore. Want to add some scripting to your App?

  11. #11
    Confused Magos's Avatar
    Join Date
    Sep 2001
    Location
    Sweden
    Posts
    3,145
    I know that. But as I recently read in this article method overloading is not possible in COM, so all hope is lost (well, not really, but I have to rename each method uniquely, 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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. DLL question
    By cboard_member in forum Game Programming
    Replies: 1
    Last Post: 04-24-2006, 02:19 AM
  2. Replies: 8
    Last Post: 10-02-2005, 12:27 AM
  3. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  4. DLL and std::string woes!
    By Magos in forum C++ Programming
    Replies: 7
    Last Post: 09-08-2004, 12:34 PM