Bind environment variable value to application
I have several versions of an application (Wolfram Mathematica) installed. By default, all versions share the same settings directory, which leads to several conflicts and broken things. The only way to change the settings directory is to set an environment variable (MATHEMATICA_USERBASE
) to the directory before starting the application.
I am therefore looking for the easiest way to tell Windows to start the different versions with different settings for that environment variable. What is the easiest way to do this?
My attempt
The best I could come up with is to create a wrapper script that sets the environment variable before launching the application. The problem with this approach is that it is extremely difficult to redirect all places to use this wrapper application instead of the original one. This includes the start menu entries, but also all the "Open with..." context menu entries. I am therefore looking for a way to more efficiently "bind" the environment variable to the application, so there is no way it's started with the wrong one.
I finally found a solution that seems to require fairly limited effort: The basic idea is to inject a DLL into the target application that sets the environment variable on startup. This makes sure that the variable is set no matter how the application is started, and doesn't require any wrapper applications or similar.
The steps are roughly as follows:
-
Create the DLL: The code I am using is the following (saved as
main.cpp
)#define WIN32_LEAN_AND_MEAN #include <windows.h> #include <stdlib.h> BOOL WINAPI DllMain( HINSTANCE hinstDLL, // handle to DLL module DWORD fdwReason, // reason for calling function LPVOID lpReserved ) // reserved { if (fdwReason == DLL_PROCESS_ATTACH) putenv("MATHEMATICA_USERBASE=C:\\Users\\lukas\\AppData\\Roaming\\Mathematica_12_0"); return TRUE; } __declspec(dllexport) void dummy() {}
The main part is the line with
putenv
at sets the environment variable, where the syntax isputenv("VARIABLE=VALUE")
. Thedummy
function is only needed such that we can actually add the DLL to the import table. Next compile the file using your favorite compiler. I used MSVC, with the following command:cl.exe /Zi /LD /EHsc /nologo /Fe:SetEnviromentVariable.dll main.cpp
Make sure the DLL is 32 bit if the application if 32 bit, and 64 bit if the application is 64 bit.
-
Copy the DLL to the directory of the application
-
(Optional) make a backup of the application executable
-
Add the DLL to the import table. I used CFF Explorer, but there are other tools. For CFF explorer, open the executable, go to "Import Added", click "Add" and select the DLL you copied to the executables directory. Then, select the "dummy" function from the list "Exported functions", press "Import By Name", then "Rebuild import table", and finally save the file.