Jump to content
  • Advertisement
Sign in to follow this  
Programmer16

DLL Programming help (C++)

This topic is 4850 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Ok, I've written this code hundrends of times and I've never had problems before. Can somebody point out what I did wrong? I'm working on a dll interface template class for my code base, and I'm having a slight problem. After everything is done and the app has returned, I get a bunch of "First-chance exception in Code Base.exe (KERNEL32.DLL): 0xC0000005: Access Violation." Can someone help me find my error? The code seems to work fine, up until the app closes. Here's my code:
	//######################################################################
	// Log
	//######################################################################
	void Log(const char* pStream, ...)
	{
#ifdef _DEBUG
		va_list VaList;
		char szBuffer[1024];

		va_start(VaList, pStream);
		vsprintf(szBuffer, pStream, VaList);
		va_end(VaList);

		std::ofstream fout("log.txt", std::ios::app);
		fout<<szBuffer;
		fout.close();
#endif
	}

	//######################################################################
	// DllLoader
	//######################################################################
	class DllLoader
	{
		HINSTANCE	m_Handle;
		std::string	m_FileName;
	public:
		DllLoader()
		{
			m_Handle = 0;
		}

		~DllLoader()
		{
		}

		bool Load(const char* pFileName)
		{
			// If a DLL was already loaded, we'll unload it for the new DLL
			if(m_Handle)
				Release();

			// If a filename wasn't supplied, we'll return false
			if(!pFileName)
			{
				Log("DllLoader::Load() - No filename was supplied.\n");
				return false;
			}

			// Load the library
			m_Handle = LoadLibrary(pFileName);

			// If the library wasn't loaded (for some reason) then we return false
			if(!m_Handle)
			{
				Log("DllLoader::Load() - Library could not be loaded.\n");
				return false;
			}
			Log("DllLoader::Load() - %s was loaded into memory.\n", pFileName);
			m_FileName = pFileName;
			return true;
		}

		void Release()
		{
			// If the DLL wasn't loaded, we can't unload it. So, we return
			if(!m_Handle)
			{
				Log("DllLoader::Release() - A DLL was never loaded into memory.\n");
				return;
			}

			// Free the library
			FreeLibrary(m_Handle);
			Log("DllLoader::Release() - %s was released.\n", m_FileName.c_str());
		}

		template <typename GF_FUNCTYPE>
		bool GetFunction(const char* pFuncName, GF_FUNCTYPE& fpFunc)
		{
			// If a DLL wasn't loaded then return false
			if(!m_Handle)
			{
				Log("DllLoader::GetFunction() - A DLL was never loaded into memory.\n");
				return false;
			}

			// If a function name wasn't supplied, then return false
			if(!pFuncName)
			{
				Log("DllLoader::GetFunction() - A function name was not supplied.\n");
				return false;
			}

			// Get the proc. address
			fpFunc = (GF_FUNCTYPE)GetProcAddress(m_Handle, pFuncName);

			// If the function failed to load, return false
			if(!fpFunc)
			{
				Log("DllLoader::GetFunction() - %s failed to load.\n", pFuncName);
				return false;
			}

			Log("DllLoader::GetFunction() - %s was loaded into memory.\n", pFuncName);
			return true;
		}
	};

	//######################################################################
	// DllInterface
	//######################################################################
	template <typename INTERFACETYPE>
	class DllInterface
	{
		// Type definitions for each INTERFACETYPE
		typedef bool (*CREATEINTERFACE)(INTERFACETYPE* pInterface, void* pData);
		typedef void (*DESTROYINTERFACE)(INTERFACETYPE* pInterface);
		INTERFACETYPE	m_pInterface;
		DllLoader		m_Loader;
	public:
		DllInterface()
		{
			m_pInterface = 0;
		}

		~DllInterface()
		{
		}

		bool Load(const char* pFileName, void* pData)
		{
			// If we can't load the dll, then return false
			if(!m_Loader.Load(pFileName))
				return false;

			// If we can't load the function, then return false
			CREATEINTERFACE CreateInterface = 0;
			if(!m_Loader.GetFunction("CreateInterface", CreateInterface))
				return false;

			// If we fail to create the interface, then return false
			if(!CreateInterface(&m_pInterface, pData))
				return false;
			
			// The interface was loaded, return true
			return true;
		}

		void Release()
		{
			// If the interface wasn't loaded, return
			if(!m_pInterface)
				return;

			// If we can't load the DestroyInterface function, then return false
			DESTROYINTERFACE DestroyInterface = 0;
			if(!m_Loader.GetFunction("DestroyInterface", DestroyInterface))
				return;

			// Destroy the interface
			DestroyInterface(&m_pInterface);

			// Release the DLL
			m_Loader.Release();
		}

		INTERFACETYPE GetInterface() const
		{
			return m_pInterface;
		}
	};




#include <windows.h>
#include "dftCommon.h"
#include "ITextOut.h"

dftlib::DllInterface<ITextOut*> g_TextOut;

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	g_TextOut.Load("TextOut.dll", 0);
	g_TextOut.GetInterface()->DrawText("Test 123");
	g_TextOut.Release();
	return 0;
}

[/soure]

ITextOut

#ifndef _ITEXTOUT_H_
#define _ITEXTOUT_H_

class ITextOut
{
public:
	virtual void DrawText(const char* pString)	= 0;
};

#endif




CTextOut.h
#ifndef _TEXTOUT_H_
#define _TEXTOUT_H_

#include <windows.h>
#include "ITextOut.h"

class CTextOut : public ITextOut
{
public:
	void DrawText(const char* pString);
};

extern "C" __declspec(dllexport) bool CreateInterface(ITextOut** pTextOut, void* pData);
extern "C" __declspec(dllexport) void DestroyInterface(ITextOut** pTextOut);

#endif




CTextOut.cpp (TextOut.dll)
#include "TextOut.h"

void CTextOut::DrawText(const char* pString)
{
	MessageBox(0, pString, "Message", MB_OK);
}

extern "C" __declspec(dllexport) bool CreateInterface(ITextOut** pTextOut, void* pData)
{
	if(*pTextOut)
		return false;

	*pTextOut = new CTextOut;
	return *pTextOut != 0;
}

extern "C" __declspec(dllexport) void DestroyInterface(ITextOut** pTextOut)
{
	if(!*pTextOut)
		return;
	delete *pTextOut;
}




Any help would be awesome! Also, any suggestions about fixing some of my code? (Mostly my CreateInterface and DestroyInterface) Thanks!

Share this post


Link to post
Share on other sites
Advertisement
Depending on your compiler it's possible that you're being bitten by mismatching calling conventions. Try making the calling conventions explicit for the exported functions and the function pointers:
// DllInterface

template <typename INTERFACETYPE>
class DllInterface
{
// Type definitions for each INTERFACETYPE
typedef bool (__cdecl *CREATEINTERFACE)(INTERFACETYPE* pInterface, void* pData);
typedef void (__cdecl *DESTROYINTERFACE)(INTERFACETYPE* pInterface);

// CTextOut.h

extern "C" __declspec(dllexport) bool __cdecl CreateInterface(ITextOut** pTextOut, void* pData);
extern "C" __declspec(dllexport) void __cdecl DestroyInterface(ITextOut** pTextOut);

// CTextOut.cpp

extern "C" __declspec(dllexport) bool __cdecl CreateInterface(ITextOut** pTextOut, void* pData)
{

// ...

extern "C" __declspec(dllexport) void __cdecl DestroyInterface(ITextOut** pTextOut)
{

Or equivalently with __stdcall.

Enigma

Share this post


Link to post
Share on other sites
I've tried that before, but I'll try it again.
I'm using MSVC++6

This has got me frustrated, since I've written this code so many times and never had problems with it.

Thanks!

Share this post


Link to post
Share on other sites
Ok, I tried that, and it didn't work :(

Ok, I've figured out that it isn't my dll loading (because I rewrote the app using Win32 calls instead of my wrapper class), so it must be in my DLL somewhere.

[Edited by - Programmer16 on August 9, 2005 12:20:48 PM]

Share this post


Link to post
Share on other sites
I think I spotted it. You don't have a virtual destructor on ITextOut. deleteing a pointer-to-derived via a pointer-to-base without a virtual destructor in base is a no-no.

Enigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Programmer16
Ok, I tried that, and it didn't work :(

Ok, I've figured out that it isn't my dll loading (because I rewrote the app using Win32 calls instead of my wrapper class), so it must be in my DLL somewhere.


If the exports in the DLL are not loading have you tried changing the __declspec(dllexport) symbol to __declspec(dllimport) in CTextOut.h? Try that with the existing DLL.

Share this post


Link to post
Share on other sites
Quote:
Original post by Zorbfish
Quote:
Original post by Programmer16
Ok, I tried that, and it didn't work :(

Ok, I've figured out that it isn't my dll loading (because I rewrote the app using Win32 calls instead of my wrapper class), so it must be in my DLL somewhere.


If the exports in the DLL are not loading have you tried changing the __declspec(dllexport) symbol to __declspec(dllimport) in CTextOut.h? Try that with the existing DLL.


When I try changing the one, it gives me a warning and says that dllexport is assumed. When I try changing the definition, it says that import definition not allowed.

The test app loads fine and the text is displayed, but then I get the errors after the app closes.

Share this post


Link to post
Share on other sites
Ok, I've narrowed it down to having something to do with my class. It doesn't give me errors until I call:

g_pTextOut->DrawText("Test 123");

Share this post


Link to post
Share on other sites
Can you try changing your CreateInterface and DestroyInterface functions to:
extern "C" __declspec(dllexport) ITextOut * __stdcall CreateInterface()
{
return new CTextOut;
}

extern "C" __declspec(dllexport) void __stdcall DestroyInterface(ITextOut* pTextOut)
{
delete pTextOut;
}

with the appropriate modifications to your dll loading classes. See if that makes any difference.

Enigma

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!