C++ Dll to C++

Started by
5 comments, last by eq 14 years, 11 months ago
Hi all. I'm trying to rewrite an engine of mine and I tough I'd put it into a DLL. This is because later on I'd like to have it working in C# as well. I know how to export a normal function like "int RandomNumber() { return rand();}" or a variable but those won't help me. I'd like to have classes exported. Untill now I've understood how this thing works "#ifdef DLLTEST_EXPORTS #define DLLTEST_API __declspec(dllexport) #else #define DLLTEST_API __declspec(dllimport) #endif" but from what I read on the internet only the same version of visualC++ can compile that and that's a big nono for me. I'm not worried about the classes themselves as I'd like to introduce a procedural style of work first. (Functions like PositionEntity(CEntity ent,CVec3 vec); ). But how would I export a function like that. It needs to know what a CEntity is and what a CVec3 is and thus I'd have to export the classes right? If someone could help me I'd be very thankfull.
Advertisement
Quote:Original post by LorinAtzberger
from what I read on the internet only the same version of visualC++ can compile that and that's a big nono for me.
That's a fact of life with C++ - there is no standard for how the binary should look AFAIK, so a C++ DLL built with one compiler won't necessarily work with another compiler.

You've got to define a procedural interface with plain C functions for that to work.
Quote:I'm not worried about the classes themselves as I'd like to introduce a procedural style of work first. (Functions like PositionEntity(CEntity ent,CVec3 vec); ).
But how would I export a function like that. It needs to know what a CEntity is and what a CVec3 is and thus I'd have to export the classes right?
Instead of passing by value (e.g. func( CEntity ) ), pass by pointer (e.g. func( CEntity* ) ), and then all the compiler needs to know is that such a class exists - it doesn't need to know anything about it.
I was anyway going to place pointers there but I forgot to write them here.
So how do I tell the compiler that such a class exists?

Here is my code for the engine.
If I can get this up running from the DLL then I can figure out the rest.
class CEngine{private:	bool  m_FullScreen;							// Set full screen as default	HWND  m_HWnd;								// This is the handle for the window	RECT  m_Rect;								// This holds the window dimensions	HDC   m_HDC;								// General HDC - (handle to device context)	HGLRC m_HGLRC;								// General OpenGL_DC - Our Rendering Context for OpenGL	int   m_Depth;public:	CEngine(HWND hWnd)	{		m_HWnd = hWnd;		GetClientRect(hWnd,&m_Rect);		m_HDC = GetDC(hWnd);		m_Depth = 32;		SetupPixelFormat(m_HDC);		m_HGLRC = wglCreateContext(m_HDC);		wglMakeCurrent(m_HDC,m_HGLRC);		SizeOpenGLScreen(m_Rect.left -m_Rect.right,m_Rect.top -m_Rect.bottom);	}private:	bool SetupPixelFormat(HDC dc)	{		PIXELFORMATDESCRIPTOR pfd = {0}; 		int pixelformat;  		pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);			// Set the size of the structure		pfd.nVersion = 1;									// Always set this to 1														// Pass in the appropriate OpenGL flags		pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 		pfd.dwLayerMask = PFD_MAIN_PLANE;					// We want the standard mask (this is ignored anyway)		pfd.iPixelType = PFD_TYPE_RGBA;						// We want RGB and Alpha pixel type		pfd.cColorBits = m_Depth;						// Here we use our #define for the color bits		pfd.cDepthBits = m_Depth;						// Depthbits is ignored for RGBA, but we do it anyway		pfd.cAccumBits = 0;									// No special bitplanes needed		pfd.cStencilBits = 0;								// We desire no stencil bits		if ( (pixelformat = ChoosePixelFormat(m_HDC, &pfd)) == FALSE ) 		{ 			MessageBox(NULL, L"ChoosePixelFormat failed", L"Error", MB_OK); 			return FALSE; 		}  		// This sets the pixel format that we extracted from above		if (SetPixelFormat(m_HDC, pixelformat, &pfd) == FALSE) 		{ 			MessageBox(NULL, L"SetPixelFormat failed", L"Error", MB_OK); 			return FALSE; 		} 	 		return TRUE;	}	void SizeOpenGLScreen(int width,int height)	{		if(height==0)			height=1;		glViewport(0,0,width,height);		glMatrixMode(GL_PROJECTION);		glLoadIdentity();		gluPerspective(45.0f,(float)width/(float)height,1,150.0f);		glMatrixMode(GL_MODELVIEW);		glLoadIdentity();	}	void ClearDevice()	{		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear The Screen And The Depth Buffer	}public:	void Render()	{		ClearDevice();		SwapBuffers(m_HDC);	}};typedef CEngine * TEngine;TEngine CreateEngine(HWND hWnd){	return new CEngine(hWnd);}void Render(){}void Render(TEngine eng){	eng->Render();}

Thank you! You are very helpfull
Quote:Original post by LorinAtzberger
I was anyway going to place pointers there but I forgot to write them here.
So how do I tell the compiler that such a class exists?



I'm sorry, I don't really have time to read the code but I can answer this question for you.

What you want is something called "Forward declaration"


Basically before you declare a pointer variable in your code you just write:

class CEntity;

That just tells to the compiler that such a class exists somewhere and at some point it will get defined. That is enough for the compiler to understand declarations of form:

CEntity *pEnt;

All pointers are essentially the same, the compiler just needs to know that CEntity is some kind of class.
-----------------Always look on the bright side of Life!
Quote:Original post by LorinAtzberger
But from what I read on the internet only the same version of visualC++ can compile that and that's a big nono for me.


Why is it a nogo for you? Do you plan to release binaries only for others to use? Well... simply offer binaries for the most common compilers.
If that's not the case why do you care?

To export a class:
class DLLTEST_API foo{};


I'll ask again. Why is it a nogo for you? If you're the only one working on your engine then just stick with a c++ approach and forget the COM approach (for gods sake, don't overcomplicate things if it's not even necessary).
When you create a DLL that's to be consumed from multiple languages, you need to use an agreed binary interface - the most common ones are the C ABI, COM+ and the Microsoft CLR (.NET).

Quote:Original post by SiS-Shadowman
Why is it a nogo for you? Do you plan to release binaries only for others to use? Well... simply offer binaries for the most common compilers.


This approach is pretty useless. You don't need to release seperate DLLs for each compiler, you need to release seperate DLLs for each compiler option that affects either the binary interface; for Visual Studio you need [Release|Debug]*[Static CRT|Dynamic CRT]*[Checked STL | Unchecked STL] - that's 8 versions just for the commonly altered options.

And then you still can't use it from C# without either creating either a C or C++/CLI wrapper.


Please note that passing an object as a pointer doesn't solve anything.

You're passing from one binary to another, a pointer to a piece of memory that represents an object.

If the compilers doesn't agree on that exact memory layout to be an object, there will be a problem (member alignment, order optimizations, v-table location etc).


This topic is closed to new replies.

Advertisement