Accessing Global Variables Across DLL -------------------------------------- In lasts months WPJ I wrote an introductory DLL article. This month I wish to share with the many readers of the WPJ (at least that's what Pete and Mike keep telling us) of a way that I discovered by necessity of handling global variables across DLLs. I describe my approach as a 'kludge' but, to me it is a fairly good 'kludge'. Like anything done against the norm there are some risks; like receiving flammable E-mail about going against Windows standards, and possibilities that Microsoft will change some things and therefore in later versions my approach will not work. All of these are possibilities but, I can live with those for now. Why? Because I think that it is a feasible kludge and what I will show you is nothing that Windows has not been doing since version 2.0 and it has not changed yet. That is not to say that they will not change, but that for now it seems safe to say that they will not. Here's some background information on why I chose to use the method I came up with. Windows already supplies ways of handling global variables across DLLs, for instance, shared memory, passing far pointers and redeclaring the variables in the DLL. These methods are workable and I strongly suggest that they be used. Well, here's the background. I was given the task of converting two DOS applications over to Windows and making them into one package. My mission was to get it up and running as quickly as possible. The original DOS application made use of numerous global variables. So, I decided to do a straight port, and after demoing the port and management making their decision, I would convert the App over to DLLs. Well, the first two steps (ported and mgmt. decision) were completed 7 months later. So, now the big job was to fix up everything over to DLLs. This was no problem except for the numerous global variables. Hind sight told me I was stupid for not dealing with them initially. Handling the global variables the way Microsoft suggests would mean that a great portion of the code would have to be rewritten, and you know that there just is never any time to do that. So, I began to think to myself, and I remembered reading about Micheal Geary's FIXDS. The same logic he applied to not having to call 'MakeProcInstance' also applied to what I was thinking. The stack segment (SS) for DLLs is that of the calling application. And, the calling apps. DS == SS. Therefore, any global variables (CONST and BSS) defined in the application is shared with the DLL via SS. The only problem is that you have no clear way of accessing those variables. In Windows global variables in segments do not change their offsets, only the segments can be changed due to memory management. Thus, the offset values of the global variables will always be at the same location inside the segment. Knowing this, how do we determine those offsets? The answer is the MAP file that the compiler will supply for you. The MAP file lists all global symbols defined in the object file(s), sorted by name and a list sorted by address. With this information in hand we can make a file of all the global variables used in the program. The global list should use the same case as the actual definitions. Also, since the MAP file sorts the variables by name and thats what we are looking for, the matching variable names and their offsets, our list file should be sorted, this will speed the search. I wrote a utility program that I call "getoff.exe", that searches the MAP file and creates an output constants file of the variables, i.e., GLOBAL HEADER FILE INPUT FILE FORMAT OUTPUT FILE FORMAT ------------------ ----------------- ------------------- int variableA; variableA #define VARIABLEA 0x0001 int variableB; variableB #define VARIABLEB 0x0002 int variableC; variableC #define VARIABLEC 0x0003 The outputed constant file is to be inlcuded in the DLL modules. I forgot to mention one thing. The global variables must be declared inside the DLLs also. The cleanest way would be to include them in a global header file. Now with the use of some in-line assembly code the global variables can be accessed and updated inside the DLL. #include "consts.h" #include "global.h" . . . /* this code sets up the variables inside the DLL */ _asm mov ax, ss:[VARIABLEA] _asm mov [variableA], ax _asm mov ax, ss:[VARIABLEB] _asm mov [variableB], ax _asm mov ax, ss:[VARIABLEC] _asm mov [variableC], ax /* now use the variables like normal */ variableC= variableB; variableB= variableA; variableA= variableC; /* when finish reasign the values to the global */ /* variables defined in the application */ _asm mov ax, [variableA] _asm mov ss:[VARIABLEA], ax _asm mov ax, [variableB] _asm mov ss:[VARIABLEB], ax _asm mov ax, [variableC] _asm mov ss:[VARIABLEC], ax This is all it takes to accomplish the task of using global variables across DLLs. I created for my companies purposes entry/exit routines that handle the assigning and re-assigning of the variables, only because our application has over some 75 to 100 global variables. Included with this document is the "getoff.exe" utility and its source, and source and executable example of a DLL accessing a global variable. To run "getoff" type 'getoff '. As I stated this is only a kludge, this method should only be used if you do not have time to rewrite code and you have too many global variables. If you have the fortunate pleasure of creating your own application try to stay away from global variables, and if you must handle them the way Microsoft suggests. Rod Haxton can be reached at (703) 883-0226 or (202) 269-3780.