//This source code is the intellectual property of Sam G Harrison III (Trey). //Compilation of this code is prohibited by law. #ifndef GLOBALS_H #define GLOBALS_H //I apologize for the unreadability of this file. Macros get very confusing and //honestly, when writing them its pretty much trial and error until it works. //the scheme: //There are variables and functions that exist in the main .exe code that .dll's //need to access. To minimize OS dependent calls for GetProcAddress(), etc, I came //up with these GLOBAL_DECLARATION macros. When building the main .exe (as determined by //checking for a #define of DLL_LINKAGE), the macro will do these //things: //1) first, actually declare the variable/function/array //2) also declare a function that returns a reference to the memory location where that variable/array/function is //3) add that information (the type name, variable name, and the address of the reference function) into // a linked list, which ends up being built by the constructor of lots of globaly declared GlobalVariableClasses //when building the .dll (#define DLL_LINKAGE), the macro does this //1) declare the variable/function/array - as a pointer to a reference function that returns // a reference to that variable/function/array. // if you globally declare, for instance, int blah in the main exe, // in the .dll what gets declared is int &(* blah)(). Thus, global variables in the main exe // are actually reference functions in the .dll code // //2) add that info (the type name, variable name, and a pointer the reference function pointer) into the linked // list which gets built the same way as the main .exe //see how its gonna work yet? //when a Dll is loaded, the main .exe will GetProcAddress the .dll for a single function (DLLInit) which will //then call GlobalVariableClass::ResolveSymbols (on the .dll side), passing in a linked list of the symbols //passed from (and declared in) the main .exe. The dll will fill in its function/array/variable pointers by //matching names with the functions/arrays/variables declarated in the main .exe. Any mixups will bring up //an assert. //usage example - in the main codebase, one might do PrimaryDrawingSurface->Blit(whatever) //to do the same thing in a dll, one would do PrimaryDrawingSurface()->Blit(whatever). //since we're using reference functions, doing something like PrimaryDrawingSurface() = 0 in the dll //will actually directly change the value of PrimaryDrawingSurface in the main .exe - just the way we'd //expect it to. If you don't want .dll's to be able to change the value of a variable, then turn it //into a function. //obviously, the .dll's incur a pointer dereference or two each time you use a global variable so be //smart and cache pointers where speed is important //by design, .dll's can't export any global variables - only the main .exe can. if the main .exe //needs to get to a variable in the dll, it'll have to occur through an interface that both the dll //and the main .exe know about (CreateAudioModule, the AudioModuleClass, WindowClass, //DrawingSurfaceClass, FontClass, etc) class GlobalVariableClass { public: static GlobalVariableClass *RegisteredGlobalVariables; static void ResolveSymbols(GlobalVariableClass *MainExeGlobals); enum DeclarationType { VARIABLE=1, FUNCTION=2, ARRAY=3 }; GlobalVariableClass(char *_type, char *_name, void *_function, int _declaration_type) { type = _type; name = _name; function = (void **)_function; declaration_type = _declaration_type; next = RegisteredGlobalVariables; RegisteredGlobalVariables = this; } char *type; char *name; void **function; int declaration_type; GlobalVariableClass *next; }; //macros for declaring a global variables and arrays #ifdef DLL_LINKAGE #ifdef GLOBALS_CPP #define GLOBAL_DECLARATIONV(type,name,initial_value) \ type &(* name)() = 0; \ GlobalVariableClass GlobalVariableClass_##name(#type,#name,&name,GlobalVariableClass::VARIABLE); #define GLOBAL_DECLARATIONA(type,name,size) \ type *(* name)() = 0; \ GlobalVariableClass GlobalVariableClass_##name(#type,#name,&name,GlobalVariableClass::ARRAY); #else #define GLOBAL_DECLARATIONV(type,name,initial_value) \ extern type &(* name)(); #define GLOBAL_DECLARATIONA(type,name,size) \ extern type *(* name)(); #endif #else #ifdef GLOBALS_CPP #define GLOBAL_DECLARATIONV(type,name,initial_value) \ type name = initial_value; \ type & _function_##name() \ { \ return name; \ } \ GlobalVariableClass GlobalVariableClass_##name(#type,#name,_function_##name,GlobalVariableClass::VARIABLE); #define GLOBAL_DECLARATIONA(type,name,size) \ type name[size]; \ type *_function_##name() \ { \ return name; \ } \ GlobalVariableClass GlobalVariableClass_##name(#type,#name,_function_##name,GlobalVariableClass::ARRAY); #else #define GLOBAL_DECLARATIONV(type,name,initial_value) \ extern type name; #define GLOBAL_DECLARATIONA(type,name,size) \ extern type name[size]; #endif #endif //Macro for declaring a global function #ifdef DLL_LINKAGE #ifdef GLOBALS_CPP #define GLOBAL_DECLARATIONF(return_type,name,params) \ return_type (* name) params = 0; \ GlobalVariableClass GlobalVariableClass_##name(#return_type,#name,&name,GlobalVariableClass::FUNCTION); #else #define GLOBAL_DECLARATIONF(return_type,name,params) \ extern return_type (* name) params; #endif #else #ifdef GLOBALS_CPP #define GLOBAL_DECLARATIONF(return_type,name,params) \ return_type name params; \ GlobalVariableClass GlobalVariableClass_##name(#return_type,#name,name,GlobalVariableClass::FUNCTION); #else #define GLOBAL_DECLARATIONF(return_type,name,params) \ return_type name params; #endif #endif //macro for declaring a global classes/functions //this really .. doesn't work. /* #define GLOBAL_CLASS(classdec, classname) \ classdec classname \ #define CURCLASSNAME classname \ #define EXPORTEDNAMES #ifdef DLL_LINKAGE #define GLOBAL_CLASSF(return_type,name,params) \ static return_type (* name_ptr) params = 0; \ return_type name params \ { \ if (!name_ptr) \ name_ptr = GlobalClassLookup(CURCLASSNAME ##name); \ else \ (*name_ptr)params; \ } #else #define GLOBAL_CLASSF(return_type,name,params) \ return_type name params; \ #define EXPORTEDNAMES EXPORTEDNAMES,name GlobalVariableClass GlobalVariableClass_##name(#return_type,#name,name,GlobalVariableClass::FUNCTION); #endif */ //GLOBAL VARIABLES GLOBAL_DECLARATIONV(void *, Global_hInstance, 0); GLOBAL_DECLARATIONF(const char *, Global_GetCommandLine, ()); GLOBAL_DECLARATIONV(char *, Global_ExePath, 0); #endif