dcsimg
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16

Thread: C++ Library with DLL exports for hiding implementation.

  1. #1
    Join Date
    Jul 2017
    Posts
    78

    C++ Library with DLL exports for hiding implementation.

    After a long time of asking you about DLLs, I think I'm finally ready to move on with my project. I'm creating a game engine which I'm going to use to make a game. But this game engine is going to be also an API for those who wish to make their own games, and also extensible in order for others to be able to extend (Create Modes) a game made by this game engine, with dynamic loading. One of the obstacles I found along the way was to hide the Graphics implementation which is very low level and the Client doesn't need to use. Also another reason I want to hide the graphics implementation is because I don't want the Client to compile and Link against the Libraries which I'm using.

    My engine's API is going to be defined into header files only because it's c++ (So i won't have compatibility problems with DLL exporting). The graphics code, since the Libraries which I'm using are all in pure c dlls, I decided to do a trick of hiding the implementation into .cpp files which contain only c functions and compile those to a dll. So the user only needs to include my header files and link against that dll in order to use my library.

    I want to make sure that everything is well structured and defined for compatibility so I'm inviting you to check that for me. I will demonstrate to you some code of my project to show you if I'm doing everything OK.

    To give you a quick overview, basically what I'm doing is that code which I want to hide and it's pure c, i'm coding it into a cpp file and I'm declaring those function as extern "C" in order to export them into a dll.
    Then into my header file, i'm declaring my class (which the clientis going to use) by calling these extern functions. The client is going to use only the Window Class.

    Window Class
    Code:
    #ifndef VAMP_ENGINE_WINDOW_H
    #define VAMP_ENGINE_WINDOW_H
    #include <iostream>
    #include "ExportDLL.h"
    
    struct GLFWwindow;
    
    namespace VampEngine
    {
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	//Classes.
    	class WindowImpl;
    
    	//WindowImpl Class Functions.
    	extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, std::string title, unsigned int width, unsigned int height);
    	extern "C" VAMP_ENGINE_EXPORT int DestroyWindowImpl(WindowImpl *window);
    
    	//Core Class Functions.
    	extern "C" VAMP_ENGINE_EXPORT int MainLoopImpl(WindowImpl *window);
    
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	///WindowImpl Struct.
    	/**
    	You SHOULD NOT instantiate an instance of this struct!
    	The Application handle's instances of this struct
    	automatically.
    	*/
    	class WindowImpl
    	{
    
    		//Friends.
    		friend class Window;
    		friend class Core;
    
    	//Private Members.
    	private:
    		GLFWwindow *m_GLFWwindow;
    		const char *m_Error;
    		const char *m_Title;
    		int m_Width, m_Height;
    
    	//Function Friends.
    	public:
    		friend int InitializeWindowImpl(WindowImpl *window, std::string title, unsigned int width, unsigned int height);
    		friend int DestroyWindowImpl(WindowImpl *window);
    		friend int VampEngine::MainLoopImpl(WindowImpl *window);
    	};
    
    	///Window Class.
    	/**
    	You SHOULD NOT instantiate an instance of this class!
    	The Application handle's instances of this class
    	automatically.
    	*/
    	class Window
    	{
    
    		//Friends.
    		friend class Core;
    
    	//Private Members.
    	private:
    
    		WindowImpl *m_PtrToImpl;
    
    
    
    	//Public Methods.
    	public:
    
    		///Constrcutor.
    		Window(std::string title, unsigned int width, unsigned int height)
    		{
    			//Create and initialize the Window.
    			m_PtrToImpl = new WindowImpl();
    			int error   = InitializeWindowImpl(m_PtrToImpl, title, width, height);
    
    			//Initialization Failed.
    			if (error) throw m_PtrToImpl->m_Error;
    		}
    
    		///Deconstructor.
    		~Window() 
    		{
    			//Destroy the implementation.
    			DestroyWindowImpl(m_PtrToImpl);
    		}
    
    		///GetWidth() Method.
    		/**
    		Return's the width of the window.
    		*/
    		inline int GetWidth() { return m_PtrToImpl->m_Width; }
    
    		///GetHeight() Method.
    		/**
    		Return's the height of the window.
    		*/
    		inline int GetHeight() { return m_PtrToImpl->m_Height; }
    
    		///GetTitle() Method.
    		/**
    		Return's the title of the window.
    		*/
    		inline std::string GetTitle() { return m_PtrToImpl->m_Title; }
    
    	};
    }
    
    #endif

    Window Graphics Implementation
    Code:
    #include "Window.hpp"
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    
    //Constructor.
    int VampEngine::InitializeWindowImpl(WindowImpl *window, std::string title, unsigned int width, unsigned int height)
    {
    
    	//----------Initialize----------//
    	window->m_Error  = "";
    	window->m_Width  = width;
    	window->m_Height = height;
    	window->m_Title  = title.c_str();
    
    	/* Initialize the library */
    	if (!glfwInit())
    	{
    		window->m_Error = "GLFW failed to be initialized.";
    		return 1;
    	}
    
    	/* Create a windowed mode window and its OpenGL context */
    	window->m_GLFWwindow = glfwCreateWindow(width, height, title.c_str(), NULL, NULL);
    	if (!window->m_GLFWwindow)
    	{
    		window->m_Error = "GLFW failed to create a Window.";
    		glfwTerminate();
    		return 1;
    	}
    
    	/* Make the window's context current */
    	glfwMakeContextCurrent(window->m_GLFWwindow);
    
    	//Initialize Glew.
    	if (glewInit() != GLEW_OK)
    	{
    		window->m_Error = "GLEW failed to be initialized.";
    		glfwDestroyWindow(window->m_GLFWwindow);
    		glfwTerminate();
    		return 1;
    	}
    
    	//Succeeded.
    	return 0;
    }
    
    
    
    
    //Deconstructor.
    int VampEngine::DestroyWindowImpl(WindowImpl *window)
    {
    
    	//Destroy GLFW Window.
    	glfwDestroyWindow(window->m_GLFWwindow);
    
    	//Terminate GLFW.
    	glfwTerminate();
    
    	//Delete the window.
    	delete window;
    
    	//Succeeded.
    	return 0;
    }
    The code is working fine, but I would like to take some advises from you about compatibility.

    Also, I want to ask about the function extern "C" VAMP_ENGINE_EXPORT int MainLoopImpl(WindowImpl *window);
    This is a function from another file, but I'm also declaring it on Window.hpp because I need to make it friend to the WindowImpl class.
    The compiler is warning me about inconsistent dll linkage . On google i found that this warning is mostly generated when you have duplicates
    of __declspec() function definitions. Will I have a problem with that? I'm 100% sure that both definitions will have __declspec(dllexport)
    when compiling the dll and __declspec(dllimport) when the Client include's the header file. (the macro VAMP_ENGINE_EXPORT is responsible for the __declspec()) .

    Thank you.
    Last edited by babaliaris; December 4th, 2018 at 01:42 PM.

  2. #2
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    12,845

    Re: C++ Library with DLL exports for hiding implementation.

    If your dll functions reference classes, your plugin devs will have to use the same compiler & version as the version your main program was compiled with; otherwise the c++ name mangling on the classes could be different.

    If you look at exported function examples of the windows api, you won't find exported classes in the public api. There's a reason for this.

  3. #3
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by Arjay View Post
    If your dll functions reference classes, your plugin devs will have to use the same compiler & version as the version your main program was compiled with; otherwise the c++ name mangling on the classes could be different.

    If you look at exported function examples of the windows api, you won't find exported classes in the public api. There's a reason for this.
    You mean something like this?
    Code:
    extern "C" __declspec(dllexport) int foo(){
        MyClass *obj = new MyClass();
        obj->HelloWorld();
        delete obj;
    }
    In other words, the functions below which are from my project, will have compatibility issues because they are using a WindowImpl reference which is a c++ class?

    Code:
    extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, std::string title, unsigned int width, unsigned int height);
    	extern "C" VAMP_ENGINE_EXPORT int DestroyWindowImpl(WindowImpl *window);
    So in general, extern c functions must be completely coded in pure c? Even that std::string title parameter will cause compatibility issues?
    Last edited by babaliaris; December 5th, 2018 at 04:33 AM.

  4. #4
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    6,516

    Re: C++ Library with DLL exports for hiding implementation.

    So in general, extern c functions must be completely coded in pure c? Even that std::string title parameter will cause compatibility issues?
    The .dll function interface must be of a c form. The language used for the code of the actual dll doesn't matter. The .dll code itself can be coded in c++ as long as the interface functions have a c-style interface.

    Yes, the std::string title parameter could cause compatibility issues. The point here is that until you try with different versions of .dll compile and .exe compile etc you don't know if there is going to be a problem or not with a c++ interface. You only know once you try it! With a pure c interface you know there's not going to be a problem.

    title would be passed as either type LPSTR or LPCSTR as required.
    Last edited by 2kaud; December 5th, 2018 at 06:41 AM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++17 Compiler: Microsoft VS2017 (15.9.4)

  5. #5
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by 2kaud View Post
    The .dll function interface must be of a c form. The language used for the code of the actual dll doesn't matter. The .dll code itself can be coded in c++ as long as the interface functions have a c-style interface.

    Yes, the std::string title parameter could cause compatibility issues. The point here is that until you try with different versions of .dll compile and .exe compile etc you don't know if there is going to be a problem or not with a c++ interface. You only know once you try it! With a pure c interface you know there's not going to be a problem.

    title would be passed as either type LPSTR or LPCSTR as required.
    Thank god! Also it make's sense, because the dll will be binary machine code anyway. I prefer to use const char * for cross platform compatibility.
    So in conclusion, my code is fine as long as I change that std::string from the extern functions interface and I'm 100% sure that I will not have linking issues with different compilers right?

    But I still can't understand this:
    Quote Originally Posted by Arjay View Post
    If your dll functions reference classes, your plugin devs will have to use the same compiler & version as the version your main program was compiled with; otherwise the c++ name mangling on the classes could be different.

    If you look at exported function examples of the windows api, you won't find exported classes in the public api. There's a reason for this.
    Can someone give me a sort example in code?
    Last edited by babaliaris; December 5th, 2018 at 08:05 AM.

  6. #6
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Also what is this inconsistent dll linkage warning that I'm getting? It's happening int the code below:
    Code:
    	//WindowImpl Class Functions.
    	extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    	extern "C" VAMP_ENGINE_EXPORT int DestroyWindowImpl(WindowImpl *window);
    
    	//Core Class Functions.
    	extern "C" VAMP_ENGINE_EXPORT int MainLoopImpl(WindowImpl *window);
    
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	///WindowImpl Struct.
    	/**
    	You SHOULD NOT instantiate an instance of this struct!
    	The Application handle's instances of this struct
    	automatically.
    	*/
    	class WindowImpl
    	{
    
    		//Friends.
    		friend class Window;
    		friend class Core;
    
    	//Private Members.
    	private:
    		GLFWwindow *m_GLFWwindow;
    		const char *m_Error;
    		const char *m_Title;
    		int m_Width, m_Height;
    
    	//Function Friends.
    	public:
    		friend int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    		friend int DestroyWindowImpl(WindowImpl *window);
    		friend int MainLoopImpl(WindowImpl *window);
    	};
    Code:
    2>c:\users\babaliaris\source\repos\vampenginesolution\vampengine\src\headers\window.hpp(46): warning C4273: 'VampEngine::InitializeWindowImpl': inconsistent dll linkage
    2>c:\users\babaliaris\source\repos\vampenginesolution\vampengine\src\headers\window.hpp(16): note: see previous definition of 'InitializeWindowImpl'
    2>c:\users\babaliaris\source\repos\vampenginesolution\vampengine\src\headers\window.hpp(47): warning C4273: 'VampEngine::DestroyWindowImpl': inconsistent dll linkage
    2>c:\users\babaliaris\source\repos\vampenginesolution\vampengine\src\headers\window.hpp(17): note: see previous definition of 'DestroyWindowImpl'
    2>c:\users\babaliaris\source\repos\vampenginesolution\vampengine\src\headers\window.hpp(48): warning C4273: 'VampEngine::MainLoopImpl': inconsistent dll linkage
    2>c:\users\babaliaris\source\repos\vampenginesolution\vampengine\src\headers\window.hpp(20): note: see previous definition of 'MainLoopImpl'
    46,47,48 are the lines where I have the friend functions inside the WindowImpl Class.

  7. #7
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    6,516

    Re: C++ Library with DLL exports for hiding implementation.

    Code:
    extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    ...
    friend int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    These two definitions aren't the same - and hence don't have the same .dll linkage and hence the warning messages.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++17 Compiler: Microsoft VS2017 (15.9.4)

  8. #8
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by 2kaud View Post
    Code:
    extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    ...
    friend int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    These two definitions aren't the same - and hence don't have the same .dll linkage and hence the warning messages.
    Well the code is compiling and running without problems.


    If I try to put it like this:
    Code:
    friend extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    I get an error: linkage specification is not allowed.

    Is anything that I should do? Or I can leave it like this and ignore the warning?

    Or maybe I shouldn't make friends with extern c functions (And use structs instead of class for public members);
    Last edited by babaliaris; December 5th, 2018 at 09:26 AM.

  9. #9
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    6,516

    Re: C++ Library with DLL exports for hiding implementation.

    Assuming the code in post #6 is not in the .dll, then you are trying to get a function in a .dll to access the private members of a class to which the .dll has no knowledge. This is a no-no! Functions referenced in a class need to be defined in the same .exe/.dll as the class (although they can be in a different compilation unit of the .exe or .dll).
    Last edited by 2kaud; December 5th, 2018 at 09:30 AM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++17 Compiler: Microsoft VS2017 (15.9.4)

  10. #10
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by 2kaud View Post
    Assuming the code in post #6 is not in the .dll, then you are trying to get a function in a .dll to access the private members of a class to which the .dll has no knowledge.
    If the members are public, is this a yes-yes??? Or I should not reference any class objects through a .dll function (in general) and instead use only C struct objects?
    Last edited by babaliaris; December 5th, 2018 at 09:37 AM.

  11. #11
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    6,516

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by babaliaris View Post
    If the members are public, is this a yes-yes??? Or I should not reference any class objects through a .dll function (in general) and instead use only C struct objects?
    You have the class definition (without the member function implementations) in a header file which is included in both .exe and .dll. The .dll contains the complete class implementation. The .dll interface function(s) use a pointer to a class and are of 'C' form. Within the .exe you reference public elements of the class via the pointer (as -> ).

    Welcome to .dll hell!
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++17 Compiler: Microsoft VS2017 (15.9.4)

  12. #12
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by 2kaud View Post
    You have the class definition (without the member function implementations) in a header file which is included in both .exe and .dll. The .dll contains the complete class implementation. The .dll interface function(s) use a pointer to a class and are of 'C' form. Within the .exe you reference public elements of the class via the pointer (as -> ).

    Welcome to .dll hell!
    I need a guide that explains everything in detail... I sort of understand what you're saying but still I'm sure I don't know exactly what is going on.

  13. #13
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    I noticed something really important!!!! Take a look again into my code:

    Window.hpp
    Code:
    #ifndef VAMP_ENGINE_WINDOW_H
    #define VAMP_ENGINE_WINDOW_H
    #include <iostream>
    #include "ExportDLL.h"
    
    struct GLFWwindow;
    
    namespace VampEngine
    {
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	//Classes.
    	class WindowImpl;
    
    	//WindowImpl Class Functions.
    	extern "C" VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    	extern "C" VAMP_ENGINE_EXPORT int DestroyWindowImpl(WindowImpl *window);
    
    	//Core Class Functions.
    	extern "C" VAMP_ENGINE_EXPORT int MainLoopImpl(WindowImpl *window);
    
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	///WindowImpl Class.
    	/**
    	You SHOULD NOT instantiate an instance of this Class!
    	The Application handle's instances of this Class
    	automatically.
    	*/
    	class WindowImpl
    	{
    
    		//Friends.
    		friend class Window;
    		friend class Core;
    
    	//Private Members.
    	private:
    		GLFWwindow *m_GLFWwindow;
    		const char *m_Error;
    		const char *m_Title;
    		int m_Width, m_Height;
    
    	//Function Friends.
    	public:
    		friend int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    		friend int DestroyWindowImpl(WindowImpl *window);
    		friend int MainLoopImpl(WindowImpl *window);
    	};
    
    	///Window Class.
    	/**
    	You SHOULD NOT instantiate an instance of this class!
    	The Application handle's instances of this class
    	automatically.
    	*/
    	class Window
    	{
    
    		//Friends.
    		friend class Core;
    
    	//Private Members.
    	private:
    
    		WindowImpl *m_PtrToImpl;
    
    
    
    	//Public Methods.
    	public:
    
    		///Constrcutor.
    		Window(std::string title, unsigned int width, unsigned int height)
    		{
    			//Create and initialize the Window.
    			m_PtrToImpl = new WindowImpl();
    			int error   = InitializeWindowImpl(m_PtrToImpl, title.c_str(), width, height);
    
    			//Initialization Failed.
    			if (error) throw m_PtrToImpl->m_Error;
    		}
    
    		///Deconstructor.
    		~Window() 
    		{
    			//Destroy the implementation.
    			DestroyWindowImpl(m_PtrToImpl);
    		}
    
    		///GetWidth() Method.
    		/**
    		Return's the width of the window.
    		*/
    		inline int GetWidth() { return m_PtrToImpl->m_Width; }
    
    		///GetHeight() Method.
    		/**
    		Return's the height of the window.
    		*/
    		inline int GetHeight() { return m_PtrToImpl->m_Height; }
    
    		///GetTitle() Method.
    		/**
    		Return's the title of the window.
    		*/
    		inline std::string GetTitle() { return m_PtrToImpl->m_Title; }
    
    	};
    }
    
    #endif
    Window.cpp
    Code:
    #include "Window.hpp"
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    
    //Constructor.
    extern "C" VAMP_ENGINE_EXPORT int VampEngine::InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height)
    {
    
    	//----------Initialize----------//
    	window->m_Error  = "";
    	window->m_Width  = width;
    	window->m_Height = height;
    	window->m_Title  = title;
    
    	/* Initialize the library */
    	if (!glfwInit())
    	{
    		window->m_Error = "GLFW failed to be initialized.";
    		return 1;
    	}
    
    	/* Create a windowed mode window and its OpenGL context */
    	window->m_GLFWwindow = glfwCreateWindow(width, height, title, NULL, NULL);
    	if (!window->m_GLFWwindow)
    	{
    		window->m_Error = "GLFW failed to create a Window.";
    		glfwTerminate();
    		return 1;
    	}
    
    	/* Make the window's context current */
    	glfwMakeContextCurrent(window->m_GLFWwindow);
    
    	//Initialize Glew.
    	if (glewInit() != GLEW_OK)
    	{
    		window->m_Error = "GLEW failed to be initialized.";
    		glfwDestroyWindow(window->m_GLFWwindow);
    		glfwTerminate();
    		return 1;
    	}
    
    	//Succeeded.
    	return 0;
    }
    
    
    
    
    //Deconstructor.
    extern "C" VAMP_ENGINE_EXPORT int VampEngine::DestroyWindowImpl(WindowImpl *window)
    {
    
    	//Destroy GLFW Window.
    	glfwDestroyWindow(window->m_GLFWwindow);
    
    	//Terminate GLFW.
    	glfwTerminate();
    
    	//Delete the window.
    	delete window;
    
    	//Succeeded.
    	return 0;
    }
    Do I need to put extern "C" VAMP_ENGINE_EXPORT in the implementation too (.cpp) or only in the header file? If you see post #1 , the .cpp file does not have the extern "C" VAMP_ENGINE_EXPORT in each function Implementation.

    Also what about this?
    Code:
    extern "C" VAMP_ENGINE_EXPORT int VampEngine::DestroyWindowImpl(WindowImpl *window)
    As you can see, the functions which I'm exporting are inside a namespace. Should I avoid putting them inside namespaces? How will the c++ compiler is going to see that? I'm saying that this function is extern "C" but this
    function also lives inside a namespace, so the compiler has to do name mangling right? Or because the extern keyword I'm already sure that the compiler will ignore the namespace name and don't do any name mangling?
    Last edited by babaliaris; December 5th, 2018 at 01:45 PM.

  14. #14
    Arjay's Avatar
    Arjay is offline Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    12,845

    Re: C++ Library with DLL exports for hiding implementation.

    Quote Originally Posted by babaliaris View Post
    Thank god! Also it make's sense, because the dll will be binary machine code anyway. I prefer to use const char * for cross platform compatibility.
    So in conclusion, my code is fine as long as I change that std::string from the extern functions interface and I'm 100% sure that I will not have linking issues with different compilers right?

    But I still can't understand this:


    Can someone give me a sort example in code?
    Can you look at the windoes api in msdn? There are 1000s of examples.

  15. #15
    Join Date
    Jul 2017
    Posts
    78

    Re: C++ Library with DLL exports for hiding implementation.

    Anyway, I think i got this.

    I compiled the code below with visual c++ into a dll and then used that into a Client program which I compiled it with mingW g++. It worked like a charm.

    Window.hpp
    Code:
    #ifndef VAMP_ENGINE_WINDOW_H
    #define VAMP_ENGINE_WINDOW_H
    #include <iostream>
    #include "ExportDLL.h"
    
    //GLFWwindow Decleration.
    extern "C" struct GLFWwindow;
    
    
    
    
    extern "C" 
    {
    
    	///WindowImpl Struct.
    	/**
    	You SHOULD NOT instantiate an instance of this Struct!
    	The Application handle's instances of this Struct
    	automatically.
    	*/
    	struct WindowImpl
    	{
    		GLFWwindow *m_GLFWwindow;
    		const char *m_Error;
    		const char *m_Title;
    		int m_Width, m_Height;
    	};
    
    	//WindowImpl Class Functions.
    	VAMP_ENGINE_EXPORT int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height);
    	VAMP_ENGINE_EXPORT int DestroyWindowImpl(WindowImpl *window);
    }
    
    
    
    
    namespace VampEngine
    {
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	//Classes.
    
    	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//
    
    	///Window Class.
    	/**
    	You SHOULD NOT instantiate an instance of this class!
    	The Application handle's instances of this class
    	automatically.
    	*/
    	class Window
    	{
    
    		//Friends.
    		friend class Core;
    
    	//Private Members.
    	private:
    
    		WindowImpl *m_PtrToImpl;
    
    
    
    	//Public Methods.
    	public:
    
    		///Constrcutor.
    		Window(std::string title, unsigned int width, unsigned int height)
    		{
    			//Create and initialize the Window.
    			m_PtrToImpl = new WindowImpl();
    			int error   = InitializeWindowImpl(m_PtrToImpl, title.c_str(), width, height);
    
    			//Initialization Failed.
    			if (error) throw m_PtrToImpl->m_Error;
    		}
    
    		///Deconstructor.
    		~Window() 
    		{
    			//Destroy the implementation.
    			DestroyWindowImpl(m_PtrToImpl);
    		}
    
    		///GetWidth() Method.
    		/**
    		Return's the width of the window.
    		*/
    		inline int GetWidth() { return m_PtrToImpl->m_Width; }
    
    		///GetHeight() Method.
    		/**
    		Return's the height of the window.
    		*/
    		inline int GetHeight() { return m_PtrToImpl->m_Height; }
    
    		///GetTitle() Method.
    		/**
    		Return's the title of the window.
    		*/
    		inline std::string GetTitle() { return m_PtrToImpl->m_Title; }
    
    	};
    }
    
    #endif


    Window.cpp
    Code:
    #include "Window.hpp"
    #include <GL/glew.h>
    #include <GLFW/glfw3.h>
    
    
    //Constructor.
    int InitializeWindowImpl(WindowImpl *window, const char *title, unsigned int width, unsigned int height)
    {
    
    	//----------Initialize----------//
    	window->m_Error  = "";
    	window->m_Width  = width;
    	window->m_Height = height;
    	window->m_Title  = title;
    
    	/* Initialize the library */
    	if (!glfwInit())
    	{
    		window->m_Error = "GLFW failed to be initialized.";
    		return 1;
    	}
    
    	/* Create a windowed mode window and its OpenGL context */
    	window->m_GLFWwindow = glfwCreateWindow(width, height, title, NULL, NULL);
    	if (!window->m_GLFWwindow)
    	{
    		window->m_Error = "GLFW failed to create a Window.";
    		glfwTerminate();
    		return 1;
    	}
    
    	/* Make the window's context current */
    	glfwMakeContextCurrent(window->m_GLFWwindow);
    
    	//Initialize Glew.
    	if (glewInit() != GLEW_OK)
    	{
    		window->m_Error = "GLEW failed to be initialized.";
    		glfwDestroyWindow(window->m_GLFWwindow);
    		glfwTerminate();
    		return 1;
    	}
    
    	//Succeeded.
    	return 0;
    }
    
    //Deconstructor.
    int DestroyWindowImpl(WindowImpl *window)
    {
    
    	//Destroy GLFW Window.
    	glfwDestroyWindow(window->m_GLFWwindow);
    
    	//Terminate GLFW.
    	glfwTerminate();
    
    	//Delete the window.
    	delete window;
    
    	//Succeeded.
    	return 0;
    }
    I also tried to not define the exported functions as extern "C" and when I was trying to link from mingW g++ I was getting a linking error (so I know that it works).

    To end this discussion I ended up following these rules:

    1) NEVER export c++ classes to a .dll
    2) Export only C functions declared as extern "C" to avoid name mangling.
    3) These functions must have a C interface (don't use stuff like STL data types in a C function declaration).
    4) Do not put these C functions into a namespace.
    5) These extern "C" functions can be implemented with whatever code I like (c/c++) .
    6) Don't make friends with extern "C" functions, instead use public members if you want that function to have access on them.

    Well, from what I learned all this time from you guys, I guess if i follow those rules I won't have any compatibility issues with dlls and c++.
    What do you thing? Have I learned anything since I started posting in this forum
    I thing code guru took me to another whole level in programming! Not even my professors and the University gave me too much knowledge in a time period of a month!
    Last edited by babaliaris; December 5th, 2018 at 03:52 PM.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width




On-Demand Webinars (sponsored)