0

Hi!

I am trying to design and build a plugin-system to a project of mine. The basic design is to use DLL's for each plugin. Each plugin have a special function that loads all of its functions as macros to the main engine, which has been passed as a pointer to the loader function which acts as a interface to the main program. Everything of the main program resides in the form of objects within the engine class.

A "macro" is a loaded plugin function which the main engine handles. A macro can call other macros via the engine pointer. A plugin function returns void and takes one parameter: the engine pointer. This way the macro can manipulate the main program.

Now you might be asking: "Doesn't this restrict their use due to their lack of parameters?". Here comes the idea - and the problem. You see, the engine keeps track of a very special object that keeps track of an internal environment, where variables accessable for both writing and reading - both temporary ones (if it's read, it gets deleted automatically) - and permanent ones. These variables are stored in an internal std::map object. The error is - like you've already suspected - an access violation. My guess is that it's due to a violation to the rule where memory allocated in one thread may not be read or written in another, but I can't find the source of the problem.

Please, also note me about design flaws and other design errors.

As you surely would like to have if you want to help, I will post all the involved source and header files.

Headers:

Main program & Plugin - YAMP_Generic.h

#ifndef _YAMP_GENERIC_H_
#define _YAMP_GENERIC_H_

#include <string>
#include <vector>
#include <windows.h>
#include <map>
#include <sstream>
#include <deque>
#include <fstream>
#include <cctype>
#include <iomanip>

#define  STLString	std::string
#define  STLStringStream  std::stringstream
#define  STLVector  std::vector
#define  STLMap std::map
#define  STLDeque std::deque
#define  STLInFileStream std::ifstream
#define  STLOutFileStream std::ofstream
#define  EndLine std::endl

#define YAMPMain()	int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, char *cmdParam, int cmdShow) {
#define YAMPEnd() MSG  msg; int status; while ((status = GetMessage(&msg, 0, 0, 0)) != 0) { if (status == -1) { return -1; } DispatchMessage(&msg); } return msg.wParam; }

class YAMP_Engine;

typedef void (*YAMP_Macro) (YAMP_Engine*);



#endif

Main program - YAMP_Engine.h

#ifndef _YAMP_ENGINE_H_
#define _YAMP_ENGINE_H_

#include "YAMP_Generic.h"
#include "YAMP_MacroHandler.h"
#include "YAMP_PluginHandler.h"
#include "YAMP_Environment.h"


class YAMP_Engine
{

public:  
	
YAMP_Engine(HINSTANCE, const char*, UINT);
~YAMP_Engine();

void Init();
void Exit();

YAMP_MacroHandler macro;
YAMP_PluginHandler plugin;
YAMP_Environment env;


private: 
	
void parseArgs(const char *);
void addArg(STLString);

HINSTANCE win32_instance;
UINT win32_cmdshow;

int win32_argi;

};

#endif

Main program & Plugin - YAMP_Environment.h

#ifndef _YAMP_ENVIRONMENT_H_
#define _YAMP_ENVIRONMENT_H_

#include "YAMP_Generic.h"

class YAMP_Engine;

class YAMP_Environment
{

public:			
	
YAMP_Environment();
~YAMP_Environment();

void setVar(STLString name, STLString value="", bool temp=false);
void setVar(STLString name, int value=0, bool temp=false);
void setEngine(YAMP_Engine *_yamp);

int getVarInt(STLString name);
STLString getVarStr(STLString name);

STLVector<STLString> getVarList();


private:		
	
YAMP_Engine *yamp;
STLMap<STLString, STLString> vars;
STLMap<STLString, bool> vars_tempflags;

};


#endif

Main program - YAMP_MacroHandler.h

#ifndef _YAMP_MACROHANDLER_H_
#define _YAMP_MACROHANDLER_H_

#include "YAMP_Generic.h"
#include "YAMP_Variable.h"

class YAMP_Engine;

class YAMP_MacroHandler
{

public:            
	
YAMP_MacroHandler();
~YAMP_MacroHandler();

void setEngine(YAMP_Engine*);
STLVector<STLString> getMacroList();
void registerMacro(STLString, YAMP_Macro macro);
void Error(STLString);
bool macroExists(STLString);

void operator() (STLString name);


private:		   
	
STLMap<STLString, YAMP_Macro>   macros;       
YAMP_Engine                     *yamp;

};




#endif

Plugin - in_yamp32.h

#ifndef _IN_YAMP32_H_
#define _IN_YAMP32_H_

#define DLLIMPORT __declspec (dllexport)


class YAMP_Engine;


extern "C" DLLIMPORT void getMacroList(YAMP_Engine*);
extern "C" DLLIMPORT void test(YAMP_Engine*);



#endif

Sources

Main program - YAMP_Engine.cpp

#include "include/YAMP_Engine.h"
#include "include/YAMP_CoreMacros.h"


YAMP_Engine::YAMP_Engine(HINSTANCE hinstance, const char *cmdParam, UINT cmdShow)
{
	        win32_instance = hinstance;
			win32_cmdshow = cmdShow;

			win32_argi = 1;

			parseArgs(cmdParam);
}


YAMP_Engine::~YAMP_Engine()
{
}


void YAMP_Engine::Init()
{ 
	        env.setEngine(this);
	        plugin.setEngine(this);
			plugin.Load("plugins\\in_yamp32.dll");
}


void YAMP_Engine::Exit()
{
	        exit(0);
}

void YAMP_Engine::addArg(STLString arg)
{
	        if (arg.length() > 0)
			{
				    STLStringStream ss;
					ss << "arg_" << win32_argi;
			        env.setVar(ss.str(), arg);
					win32_argi++;
			}
}

void YAMP_Engine::parseArgs(const char *args)
{
	        STLString argstr = args;
			STLStringStream *parsed = new STLStringStream();
			bool quoted = false;
			for(unsigned int i = 0; i < argstr.length(); i++)
			{
				     if (argstr[i] == '"')
					 {
						    if (quoted)
							{
								   quoted = false;
								   addArg(parsed->str());
								   delete parsed;
								   parsed = new STLStringStream();
								   i++;
							}
							else
							{
								   quoted = true;
								   i++;
							}
					 }
					 if (!quoted)
					 {
						    if (argstr[i] != ' ')
							{
								    (*parsed) << argstr[i];
							}
							else
							{
								    addArg(parsed->str());
								    delete parsed;
								    parsed = new STLStringStream();
							}
					 }
					 else
					 {						 
						    (*parsed) << argstr[i];
					 }
			}
			if (parsed->str().length() > 0)
			{
				     addArg(parsed->str());
					 delete parsed;
					 parsed = new STLStringStream();
			}
			delete parsed;
}

Main program & Plugin - YAMP_Environment.cpp

#include "include/YAMP_Environment.h"
#include "include/YAMP_Engine.h"


YAMP_Environment::YAMP_Environment()
{
}

YAMP_Environment::~YAMP_Environment()
{
	       vars.clear();
		   vars_tempflags.clear();
}


STLVector<STLString> YAMP_Environment::getVarList()
{
	       STLVector<STLString> r;
		   for(STLMap<STLString, STLString>::iterator it = vars.begin(); it != vars.end(); it++)
		   {
			        r.push_back(it->first);
		   }
		   return r;
}


int YAMP_Environment::getVarInt(STLString name)
{
	       if (vars.find(name) != vars.end())
		   {
			         STLString value = vars[name];
			         if (vars_tempflags[name])
					 {
						      vars_tempflags.erase(vars_tempflags.find(name));
							  vars.erase(vars.find(name));
					 }
			         return atoi(value.c_str());
		   }
		   else
		   {
			         STLStringStream ss;
					 ss << "No YAMP-environment variable called '" << name << "' is defined.";
					 MessageBox(0, ss.str().c_str(), "Error", MB_ICONHAND);
					 return 0;
		   }
}


STLString YAMP_Environment::getVarStr(STLString name)
{
	       STLString _name = name;
	       if (vars.find(_name) != vars.end()) // <--- Access violation
		   {
			         STLString value = vars[_name];
			         if (vars_tempflags[_name])
					 {
						      vars_tempflags.erase(vars_tempflags.find(_name));
							  vars.erase(vars.find(_name));
					 }
				     return value;
		   }
		   else
		   {
			         STLStringStream ss;
					 ss << "No YAMP-environment variable called '" << _name << "' is defined.";
					 MessageBox(0, ss.str().c_str(), "Error", MB_ICONHAND);
					 return "";
		   }
}

void YAMP_Environment::setVar(STLString name, STLString value, bool temp)
{
	       vars[name] = value;
		   vars_tempflags[name] = temp;
}

void YAMP_Environment::setVar(STLString name, int value, bool temp)
{
	       char *buffer = new char[255];	   
		   _itoa_s(value, buffer, 255, 10);
	       vars[name] = buffer;
		   vars_tempflags[name] = temp;
		   delete buffer;
}

void YAMP_Environment::setEngine(YAMP_Engine *_yamp)
{
	       yamp = _yamp;
}

Main program - YAMP_MacroHandler.cpp

#include "include/YAMP_Generic.h"
#include "include/YAMP_MacroHandler.h"
#include "include/YAMP_Engine.h"



YAMP_MacroHandler::YAMP_MacroHandler()
{
}


YAMP_MacroHandler::~YAMP_MacroHandler()
{
}


void YAMP_MacroHandler::setEngine(YAMP_Engine *_yamp)
{
	     yamp = _yamp;
}

STLVector<STLString> YAMP_MacroHandler::getMacroList()
{
	     STLVector<STLString> macrolist;

		 for(STLMap<STLString, YAMP_Macro>::iterator it = macros.begin(); it != macros.end(); it++)
		 {			        
			        macrolist.push_back(it->first);
		 }

		 return macrolist;
}


bool YAMP_MacroHandler::macroExists(STLString name)
{
	     bool r = true;
	     if (macros.find(name) == macros.end())
		 {
				    r = false;
		 }
		 return r;
}


void YAMP_MacroHandler::operator() (STLString name)
{
	     if (macroExists(name))
		 {
			      macros[name](yamp);
		 }
		 else
		 {
		          STLStringStream ss;
		          ss << "Running macro: '" << name << "' failed." << EndLine;
		          ss << "    Macro does not exist." << EndLine;
		          Error(ss.str());
		 }
}



void YAMP_MacroHandler::Error(STLString error)
{
	     MessageBox(0, error.c_str(), "Macro Error", MB_ICONHAND);
}


void YAMP_MacroHandler::registerMacro(STLString name, YAMP_Macro macro)
{
	     if(!macroExists(name))
		 {
	       macros[name] = macro;
		 }
		 else
		 {
		   STLStringStream ss;
		   ss << "yamp->macro.registerMacro(\"" << name << "\", " << macro << ");" << EndLine;
		   ss << "    Unable to register macro. (A macro by that name is already registered)." << EndLine;
		   Error(ss.str());
		 }
}

Plugin - in_yamp32.cpp

#include "include/in_yamp32.h"
#include "../../include/YAMP_Engine.h"
#include "../../include/YAMP_Environment.h"
#include "../../include/YAMP_Generic.h"
#include <windows.h>


void test(YAMP_Engine *yamp)
{
          MessageBox(0, yamp->env.getVarStr("message_test").c_str(), "test", MB_ICONHAND);
}


void getMacroList(YAMP_Engine *yamp)
{
	      YAMP_Macro pt_test = test;
		  yamp->macro.registerMacro("test", pt_test);
		  yamp->macro("test");
}


BOOL APIENTRY DllMain (HINSTANCE hInst, DWORD reason, LPVOID reserved)
{
         switch (reason)
         {
                 case DLL_PROCESS_ATTACH: break;
                 case DLL_PROCESS_DETACH: break;
                 case DLL_THREAD_ATTACH: break;
                 case DLL_THREAD_DETACH: break;
         }
         return TRUE;
}
2
Contributors
1
Reply
2
Views
7 Years
Discussion Span
Last Post by ganbree
0

First, that is a scary amount of source to post as an example.

I wouldn't use DLL for this, I would use a scripting language such as Lua or Python (actually I wouldn't because I hate these languages with a vengeance). There should be one appropriate for the task to hand.

Now, your use of #define STLmap std::map I find particularly disturbing, what were you thinking? Maybe you've forgotten how to use that 'using' statement, defining the string almost could be defended for swapping between std::string and std::wstring; however; use typedef, seriously!

What's with prefixing your classes with YAMP_ learn to namespace. You give other people, if other will use this, the choice between typing YAMP a million times or not, your way may not be everyone's; if they really want to type YAMP_classname then they can use typedefs like you seem to like doing.

I'll try to get back on topic now...

If you want to go down the DLL path:
I'm not exactly sure what can cross the DLL barrier, but look into functors instead of the function pointers. With the memory allocated thing I think the DLLs belong to a separate process and you may need shared memory things, I never use DLLs if I can help it. Unless this is an exercise in creating a monstrous hybrid of interconnected DLLs and interprocess dynamic dispatch then I'd advise against pursuing this path. If that is the aim of this then forget this.

Very sorry if you find any/all of the content posted above slightly/quite/very offensive/disturbing in any/every way. Now to flog a dead horse....

This topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.