GL calls access violation even after initializing Glew, when coding shared libs

Hello!

I have a problem when I’m trying to call GL calls. I get memory access violation. I know that this error is usually occurs if you haven’t initialize GLEW or any other OpenGL function retriever library correctly and you didn’t get the function pointers but I’m 100% sure I’m initializing glew.

I thing the problem is happening because I’m hiding the glfw and the gl calls inside a .dll and then use that in a Client app. Let me tell you briefly what is happening in my code.

The client is including a Window.h library that has the library implementation in c++ classes hardcoded. The client is creating a Window instance which the constructor is calling an extern “C” function which initializes GLFW and GLEW. After that, the client is calling another extern “C” function which instantiates a c++ class called Renderer which calls gl call functions, and there is where I get the access violation error. The Renderer.cpp and the Window.cpp which contains the GLFW and GLEW initialization code where compiled from the same project into a .dll. Also I’m linking GLEW and GLFW dynamicly to my .dll project.

I found on the internet these messages:

-Glew uses statics, so you need to call glewInit in each of your DLLs as well as your main app. Make sure the GL context is active when you do.

The reason I’m hiding GLFW and gl calls inside a dll is to prevent the Client to compile and link against GLFW and GLEW. So if i have to Init glew in the client code to
then there is no point of what I’m doing, since the Client will have to link against GLEW in order to call glewInit().

-If I remember correctly, OpenGL contexts are thread-local. That’s what wgl/glXMakeCurrent does. So you might encounter problems if you make your context current on one thread, but execute the OpenGL calls in another thread. Other than that, separating the code into libraries shouldn’t make a difference.

-Make sure you’re linking them both with the same c runtimes… or they won’t share a heap, and then also read the post here about resolving the linking later.

Do you know what is the problem?

If you want to see I will also post the dll code. The structure goes like this:

  1. The client is inheriting an VampApp class and defines an entry point.
  2. The entry point is instantiating a VampApp instance.
  3. The VampApp instance creates a Core object.
  4. That core object is creating a Window.
  5. The window is calling extern “c” functions to initialize GLEW and GLFW.
  6. The core object is calling an extern “C” funtion to create a Renderer object.
  7. Inside the constructor of the Renderer gl calls are failing due to access violation.

Window.h


#ifndef VAMP_ENGINE_WINDOW_H
#define VAMP_ENGINE_WINDOW_H
#include <iostream>
#include "ExportDLL.h"
#include "EngineError.h"

//GLFWwindow Decleration.
extern "C" struct GLFWwindow;




extern "C" 
{

	///WindowImpl Struct.
	/**
	You SHOULD NOT instantiate an instance of this Struct!
	The VampEngine::VampApp handle's instances of this Struct
	automatically. Also you SHOULD NOT read/write members of it.
	*/
	struct WindowImpl
	{
		GLFWwindow *m_GLFWwindow;
		const char *m_Error;
		const char *m_Title;
		int m_Width, m_Height;
	};

	//WindowImpl Class Functions.

	///InitializeWindowImpl Extern Func.
	/**
	DO NOT call this function. This is part of the VampEngine system.
	*/
	VAMP_ENGINE_EXPORT int InitializeWindowImpl(struct WindowImpl *window, const char *title, unsigned int width, unsigned int height);

	///DestroyWindowImpl Extern Func.
	/**
	DO NOT call this function. This is part of the VampEngine system.
	*/
	VAMP_ENGINE_EXPORT int DestroyWindowImpl(struct WindowImpl *window);
}




namespace VampEngine
{
	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//

	//Classes.

	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//

	///Window Class.
	/**
	You SHOULD NOT instantiate an instance of this class!
	The VampApp 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 EngineError(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


#include "Window.h"
#include "glcall.h"
#include <GLFW/glfw3.h>
#include "Logger.h"


//Constructor.
int InitializeWindowImpl(struct 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;
	}

	//OpenGL Version 3.3 Core Profile.
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

	/* 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;
	}

	//Set Viewport.
	glViewport(0, 0, width, height);

	//Succeeded.
	return 0;
}




//Deconstructor.
int DestroyWindowImpl(struct WindowImpl *window)
{

	//Destroy GLFW Window.
	glfwDestroyWindow(window->m_GLFWwindow);

	//Terminate GLFW.
	glfwTerminate();

	//Delete the window.
	delete window;

	//Succeeded.
	return 0;
}

Core.h:


#ifndef VAMP_ENGINE_CORE_H
#define VAMP_ENGINE_CORE_H
#include "Window.h"
#include "EngineError.h"
#include "ExportDLL.h"

//Class Declerations//
class Renderer;


extern "C"
{

	///CoreImpl Struct.
	/**
	You SHOULD NOT instantiate an instance of this Struct!
	The VampEngine::Core handle's instances of this Struct
	automatically.
	*/
	struct CoreImpl
	{
		const char *m_Error;
		Renderer   *m_Renderer;
	};


	VAMP_ENGINE_EXPORT int MainLoopImpl(struct WindowImpl *window, struct CoreImpl *core);
	VAMP_ENGINE_EXPORT int InitializeCoreImpl(struct CoreImpl *core);
	VAMP_ENGINE_EXPORT int DestroyCoreImpl(struct CoreImpl *core);
}


namespace VampEngine
{

	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//

	//Classes.
	class Window;
	class Input;

	//Functions.
	//-_-_-_-_-_-_-_-_-_-Declarations-_-_-_-_-_-_-_-_-_-//

	///Core Class.
	/**
	You SHOULD NOT instantiate an instance of this class!
	The VampApp handle's instances of this class
	automatically.
	*/
	class Core
	{

	//Private Members.
	private:
		CoreImpl *m_PtrToImpl;
		Window   *m_Window;
		Input    *m_Input;
		float     m_Time;
		int       m_FPS;


	//Public Methods.
	public:

		///Constrcutor.
		Core(std::string title, unsigned width, unsigned height) 
		{

			//Create the Implementation.
			m_PtrToImpl = new CoreImpl();
			InitializeCoreImpl(m_PtrToImpl);


			//Create a new Window.
			m_Window = new Window(title, width, height);
		}

		///Deconstructor.
		~Core() 
		{
			DestroyCoreImpl(m_PtrToImpl);

			delete m_Window;
		}

		///GetWindow() Method.
		/**
		Use this method to get a refernce of the Window object.
		Use that object to get info like the size of the window
		or make changes to it.
		*/
		inline Window *GetWindow() { return m_Window; }

		///GetInput() Method.
		/**
		Use this method to get a refernce of the Input object.
		Use that object to get input from the keyboard or the mouse.
		*/
		inline Input *GetInput() { return m_Input; }

		///GetTime() Method.
		/**
		Return's the time in seconds, since the Application
		has started.
		*/
		inline float GetTime() { return m_Time; }

		///GetFPS() Method.
		/**
		Return's the FPS of the Application.
		*/
		inline int GetFPS() { return m_FPS; }

		///MainLoop() Method.
		/**
		You SHOULD NOT MESS with this method. The VampApp
		handle's it.
		*/
		void MainLoop()
		{ 

			//Call MainLoop.
			int error = MainLoopImpl(m_Window->m_PtrToImpl, m_PtrToImpl);

			//If an error occur, throw an exception.
			if (error) throw EngineError(m_Window->m_PtrToImpl->m_Error);
		}


	};
}

#endif


Core.cpp:


#include "Core.h"
#include "Renderer.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>

int MainLoopImpl(struct WindowImpl *window, struct CoreImpl *core)
{

	/* Loop until the user closes the window */
	while (!glfwWindowShouldClose(window->m_GLFWwindow))
	{
		/* Render here */
		glClear(GL_COLOR_BUFFER_BIT);

		//core->m_Renderer->RenderElements();

		/* Swap front and back buffers */
		glfwSwapBuffers(window->m_GLFWwindow);

		/* Poll for and process events */
		glfwPollEvents();
	}

	return 0;
}




//Core Implementation Constructor.
int InitializeCoreImpl(struct CoreImpl *core)
{
	core->m_Error    = "";
	core->m_Renderer = new Renderer();

	return 0;
}



//Core Implementation Deconstructor.
int DestroyCoreImpl(struct CoreImpl *core)
{
	delete core->m_Renderer;
	delete core;

	return 0;
}

Renderer.h


#ifndef VAMP_ENGINE_RENDERER_H
#define VAMP_ENGINE_RENDERER_H

class Shader;

class Renderer
{

private:

	unsigned int VAO, VBO, EBO;

	Shader *m_shader;

public:

	Renderer();
	~Renderer();

	void RenderElements();

};
#endif


Renderer.cpp:


#include "Renderer.h"
#include "glcall.h"
#include "shader.h"
#include <GLM/glm.hpp>
#include <GLM/gtc/matrix_transform.hpp>


Renderer::Renderer()
{

	//Vertices.
	float vertices[] =
	{

		//Positions    Texture Coordinates.

		0.0f, 0.0f,    0.0f, 0.0f, //Left Bottom.
		0.0f, 1.0f,    0.0f, 1.0f, //Left Top.
		1.0f, 1.0f,    1.0f, 1.0f, //Right Top.
		1.0f, 0.0f,    1.0f, 0.0f  //Right Bottom.
	};

	//Indices.
	unsigned int indices[] = 
	{
		0, 1, 2, //Left Up Triangle.
		0, 3, 2  //Right Down Triangle.
	};

	glCreateProgram();
	
	/*
	//Create and bind a Vertex Array.
	GLCall(glGenVertexArrays(1, &VAO));
	GLCall(glBindVertexArray(VAO));

	
	//Create and bind a Vertex Buffer.
	GLCall(glGenBuffers(1, &VBO));
	GLCall(glBindBuffer(GL_ARRAY_BUFFER, VBO));

	//Create and bind an Index Buffer.
	GLCall(glGenBuffers(1, &EBO));
	GLCall(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO));

	//Transfer the data to the VBO and EBO.
	GLCall(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));
	GLCall(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));

	//Enable and create the attribute for both Positions and Texture Coordinates.
	GLCall(glEnableVertexAttribArray(0));
	GLCall(glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void *)0));

	//Create the shader program.
	m_shader = new Shader("Shaders/sprite_vertex.glsl", "Shaders/sprite_fragment.glsl");
	*/
}


Renderer::~Renderer()
{
	//Clean Up.
	GLCall(glDeleteVertexArrays(1, &VAO));
	GLCall(glDeleteBuffers(1, &VBO));
	GLCall(glDeleteBuffers(1, &EBO));
	delete m_shader;
}



void Renderer::RenderElements()
{

	glm::mat4 model = glm::mat4(1.0f);
	model = glm::scale(model, glm::vec3(20.0f, 20.0f, 1.0f));

	glm::mat4 proj = glm::ortho(0.0f, 600.0f, 600.0f, 0.0f, -1.0f, 1.0f);

	m_shader->SetUniform1i("diffuse", 0);

	m_shader->SetUniformMat4f("model", model);
	m_shader->SetUniformMat4f("proj", proj);

	//Draw Call.
	GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL));
}

Application Class (Is getting inherited by the client):


#ifndef VAMP_ENGINE_VAMP_APP
#define VAMP_ENGINE_VAMP_APP
#include <iostream>
#include "Core.h"
#include "Logger.h"

namespace VampEngine
{

	///VampApp Class.
	/**
	Inherit this class to create a Vamp Application.
	YOU ALSO HAVE to implement the function VampEngine::CreateVampApp
	in order to return an instance of your Application.
	*/
	class VampApp
	{

	//Public Members.
	public:

		Core * const core;

	//Public Methods.
	public:

		///Constructor.
		VampApp(std::string title, unsigned int width, unsigned int height) 
			: core(new Core(title, width, height))
		{
		}

		///Deconstructor.
		virtual ~VampApp()
		{
			delete core;
		}
	};
}

#endif

Client’s Entry Point:


#define VAMP_ENGINE_ENTRY_POINT
#include <VampEngine.h>

#ifdef VAMP_ENGINE_ENTRY_POINT


#include "VampApp.h"
#include <iostream>

namespace VampEngine
{
	///VampApp Funtion.
	/**
	YOU MUST implement this function to return
	an instance of your VampApp class. Don't forget to
	define VAMP_ENGINE_ENTRY_POINT before you include 
	VampEngine.h in order to enable this function and
	the entry point of your application.
	*/
	VampApp *CreateVampApp();
}


///main Funtion.
/**
This is the main function of your VampEngine::VampApp.
YOU MUST define VAMP_ENGINE_ENTRY_POINT in ONLY ONE
.cpp file, to get this entry point function.
*/
int main(int argc, char *argv[])
{
	VampEngine::VampApp *app = VampEngine::CreateVampApp();
	app->core->MainLoop();
	delete app;

	//On Debug Mode Pause the console before exiting.
	#ifdef _MSC_BUILD
	#	ifdef _DEBUG
			std::cout << "Press ENTER to exit..." << std::endl;
			std::cin.get();
	#	endif
	#else
	#	ifdef VAMP_ENGINE_LINUX_DEBUG
			std::cout << "Press ENTER to exit..." << std::endl;
			std::cin.get();
	#	endif
	#endif
}
#endif

class MyApp : public VampEngine::VampApp
{
public:

	MyApp()
		: VampApp("Test", 600, 600)
	{
	}
};


VampEngine::VampApp *VampEngine::CreateVampApp()
{
	return new MyApp();
}

Problem solved. I was calling gl functions before initializing glew.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.