diff --git a/Contrib/EnVar/EnVar.vcproj b/Contrib/EnVar/EnVar.vcproj
new file mode 100644
index 0000000..ae3cbad
--- /dev/null
+++ b/Contrib/EnVar/EnVar.vcproj
@@ -0,0 +1,666 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Contrib/EnVar/envar.c b/Contrib/EnVar/envar.c
new file mode 100644
index 0000000..eb0cff3
--- /dev/null
+++ b/Contrib/EnVar/envar.c
@@ -0,0 +1,571 @@
+/*
+ * EnVar plugin for NSIS
+ *
+ * 2014-2016, 2018 MouseHelmet Software.
+ *
+ * Created By Jason Ross aka JasonFriday13 on the forums
+ *
+ * Checks, adds and removes paths to environment variables.
+ *
+ * envar.c
+ */
+
+/* Include relevent files. */
+#include
+#include
+#include "nsis\pluginapi.h" /* This means NSIS 2.42 or higher is required. */
+
+/* Registry defines. */
+#define HKCU HKEY_CURRENT_USER
+#define HKCU_STR _T("Environment")
+#define HKLM HKEY_LOCAL_MACHINE
+#define HKLM_STR _T("System\\CurrentControlSet\\Control\\Session Manager\\Environment")
+
+/* I would have used ints, but removing pushint() also
+ removes a dependency on wsprintf and user32.dll. */
+#define ERR_SUCCESS _T("0")
+#define ERR_NOREAD _T("1")
+#define ERR_NOVARIABLE _T("2")
+#define ERR_NOVALUE _T("3")
+#define ERR_NOWRITE _T("4")
+
+/* The amount of extra room to allocate to prevent overflows. */
+#define APPEND_SIZE 4
+
+/* Unicode and odd value finder. */
+#define IS_UNICODE_AND_ODD(x) ((sizeof(TCHAR) > 1 && (x) & 0x1) ? 1 : 0)
+
+/* Global declarations. */
+BOOL bRegKeyHKLM = FALSE;
+HINSTANCE hInstance;
+PTCHAR gptVarName, gptPathString, gptBuffer;
+
+/* Allocates a string. */
+PTCHAR StrAlloc(SIZE_T strlen)
+{
+ return (PTCHAR)GlobalAlloc(GPTR, strlen*sizeof(TCHAR));
+}
+
+/* Frees a string. */
+void StrFree(PTCHAR hVar)
+{
+ GlobalFree(hVar);
+ hVar = NULL;
+}
+
+/* Returns the string size. */
+int StrSize(PTCHAR hVar)
+{
+ return (int)((GlobalSize(hVar)-IS_UNICODE_AND_ODD(GlobalSize(hVar)))/sizeof(TCHAR));
+}
+
+/* Returns the string length. */
+int StrLen(PTCHAR hVar)
+{
+ return lstrlen(hVar);
+}
+
+/* Reallocs a buffer. It's more efficient to free and alloc than realloc. */
+BOOL StrReAlloc(PTCHAR hVar, int strlen)
+{
+ int i;
+ PTCHAR temp;
+
+ if (GlobalSize(hVar) >= strlen*sizeof(TCHAR)) return 1;
+ temp = StrAlloc(strlen);
+ if (!temp) return 0;
+ for (i = 0; i < StrSize(hVar); i++)
+ temp[i] = hVar[i];
+ StrFree(hVar);
+ hVar = temp;
+
+ return 1;
+}
+
+/* Initializes the default string size for variables. */
+void AllocStrs(void)
+{
+ if (!gptVarName) gptVarName = StrAlloc(g_stringsize);
+ if (!gptPathString) gptPathString = StrAlloc(g_stringsize);
+ if (!gptBuffer) gptBuffer = StrAlloc(g_stringsize);
+}
+
+/* Frees allocated buffers. */
+void CleanUp(void)
+{
+ if (gptVarName) StrFree(gptVarName);
+ if (gptPathString) StrFree(gptPathString);
+ if (gptBuffer) StrFree(gptBuffer);
+
+ SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, (WPARAM)NULL, (LPARAM)HKCU_STR, 0, 100, 0);
+}
+
+/* Our callback function so that our dll stays loaded. */
+UINT_PTR __cdecl NSISPluginCallback(enum NSPIM Event)
+{
+ if (Event == NSPIM_UNLOAD) CleanUp();
+
+ return 0;
+}
+
+/* This function initializes the plugin variables. */
+void Initialize(extra_parameters* xp)
+{
+ xp->RegisterPluginCallback(hInstance, NSISPluginCallback);
+ AllocStrs();
+}
+
+/* Appends a semi-colon to a string. Auto-expands the buffer
+ if there isn't enough room. */
+BOOL AppendSemiColon(PTCHAR bufStr)
+{
+ int len;
+
+ if (!bufStr) return FALSE;
+ len = StrLen(bufStr);
+ if (!len) return TRUE;
+ if (bufStr[len-1] != ';' && bufStr[0] != ';')
+ {
+ if (!StrReAlloc(bufStr, len+APPEND_SIZE)) return FALSE;
+ bufStr[len] = ';';
+ bufStr[len+1] = 0;
+ }
+ return TRUE;
+}
+
+/* Removes the trailing semi-colon if it exists. */
+void RemoveSemiColon(PTCHAR bufStr)
+{
+ if (!bufStr) return;
+ if (StrLen(bufStr) < 1) return;
+ if (bufStr[StrLen(bufStr)-1] == ';') bufStr[StrLen(bufStr)-1] = 0;
+}
+
+/* Sets the current root key. */
+void SetRegKey(BOOL bKeyHKLM)
+{
+ bRegKeyHKLM = bKeyHKLM;
+}
+
+/* Gets the current root key. */
+BOOL GetRegKey(void)
+{
+ return bRegKeyHKLM;
+}
+
+/* Registry helper functions. */
+ULONG CreateRegKey(void)
+{
+ DWORD dwRet, dwDisType = 0;
+ HKEY hKey;
+
+ if (bRegKeyHKLM)
+ dwRet = RegCreateKeyEx(HKLM, HKLM_STR, 0, 0, 0, KEY_WRITE, 0, &hKey, &dwDisType);
+ else
+ dwRet = RegCreateKeyEx(HKCU, HKCU_STR, 0, 0, 0, KEY_WRITE, 0, &hKey, &dwDisType);
+
+ RegCloseKey(hKey);
+
+ return dwRet;
+}
+
+/* Custom ReadRegVar function with ERROR_MORE_DATA handling. */
+ULONG ReadRegVar(PTCHAR ptName, PDWORD pdwType, PTCHAR ptDest, PDWORD pdwStrLen)
+{
+ DWORD dwRet, dwSize = *pdwStrLen*sizeof(TCHAR), dwType = *pdwType;
+ HKEY hKey;
+
+ ptDest[0] = 0;
+ if (bRegKeyHKLM)
+ dwRet = RegOpenKeyEx(HKLM, HKLM_STR, 0, KEY_READ, &hKey);
+ else
+ dwRet = RegOpenKeyEx(HKCU, HKCU_STR, 0, KEY_READ, &hKey);
+
+ if (dwRet == ERROR_SUCCESS)
+ {
+ dwRet = RegQueryValueEx(hKey, ptName, 0, &dwType, (LPBYTE)ptDest, &dwSize);
+ while (dwRet == ERROR_MORE_DATA)
+ {
+ DWORD dwSizeTemp = dwSize + APPEND_SIZE + IS_UNICODE_AND_ODD(dwSize);
+
+ if (!StrReAlloc(ptDest, dwSizeTemp/sizeof(TCHAR))) return 4; /* ERR_NOWRITE */
+ dwRet = RegQueryValueEx(hKey, ptName, 0, &dwType, (LPBYTE)ptDest, &dwSizeTemp);
+ if (dwRet == ERROR_SUCCESS) dwSize = dwSizeTemp;
+ }
+ RegCloseKey(hKey);
+ if (dwRet == ERROR_SUCCESS && (dwType == REG_SZ || dwType == REG_EXPAND_SZ))
+ {
+ ptDest[((dwSize+IS_UNICODE_AND_ODD(dwSize))/sizeof(TCHAR))-1] = 0;
+ *pdwType = dwType;
+ *pdwStrLen = (dwSize-IS_UNICODE_AND_ODD(dwSize))/sizeof(TCHAR);
+
+ return 0;
+ }
+ else
+ {
+ ptDest[0] = 0;
+ /* dwRet can still be ERROR_SUCCESS here, so return an absolute value. */
+ return 1; /* ERR_NOREAD */
+ }
+ }
+ else
+ return 1; /* ERR_NOREAD */
+}
+
+/* Custom WriteRegVar function, writes a value to the environment. */
+ULONG WriteRegVar(PTCHAR ptName, DWORD dwKeyType, PTCHAR ptData, DWORD dwStrLen)
+{
+ DWORD dwRet;
+ HKEY hKey;
+
+ if (bRegKeyHKLM)
+ dwRet = RegOpenKeyEx(HKLM, HKLM_STR, 0, KEY_WRITE, &hKey);
+ else
+ dwRet = RegOpenKeyEx(HKCU, HKCU_STR, 0, KEY_WRITE, &hKey);
+
+ if (dwRet != ERROR_SUCCESS) return dwRet;
+ dwRet = RegSetValueEx(hKey, ptName, 0, dwKeyType, (LPBYTE)ptData, dwStrLen*sizeof(TCHAR));
+ RegCloseKey(hKey);
+
+ return dwRet;
+}
+
+/* Checks for write access and various conditions about a variable and it's type. */
+LPCTSTR CheckVar(void)
+{
+ DWORD dwStrSize, dwKeyType;
+ HKEY hKeyHandle;
+
+ SecureZeroMemory(gptBuffer, GlobalSize(gptBuffer));
+
+ popstring(gptVarName);
+ popstring(gptPathString);
+
+ if (!StrLen(gptVarName)) return ERR_NOVARIABLE;
+ if (lstrcmpi(gptVarName, _T("NULL")) == 0)
+ {
+ DWORD dwRet;
+
+ if (bRegKeyHKLM)
+ dwRet = RegOpenKeyEx(HKLM, HKLM_STR, 0, KEY_WRITE, &hKeyHandle);
+ else
+ dwRet = RegOpenKeyEx(HKCU, HKCU_STR, 0, KEY_WRITE, &hKeyHandle);
+
+ if (dwRet == ERROR_SUCCESS)
+ {
+ RegCloseKey(hKeyHandle);
+ return ERR_SUCCESS;
+ }
+ else
+ return ERR_NOWRITE;
+ }
+ dwStrSize = StrSize(gptBuffer);
+ if (ReadRegVar(gptVarName, &dwKeyType, gptBuffer, &dwStrSize) != ERROR_SUCCESS)
+ return ERR_NOVARIABLE;
+
+ if (!StrLen(gptPathString)) return ERR_NOVARIABLE;
+ if (lstrcmpi(gptPathString, _T("NULL")) != 0)
+ {
+ if (!AppendSemiColon(gptPathString)) return ERR_NOWRITE;
+ if (!AppendSemiColon(gptBuffer)) return ERR_NOWRITE;
+ if (StrStrI(gptBuffer, gptPathString) == NULL)
+ return ERR_NOVALUE;
+ else
+ return ERR_SUCCESS;
+ }
+ else
+ if (dwKeyType != REG_SZ && dwKeyType != REG_EXPAND_SZ)
+ return ERR_NOVALUE;
+ else
+ return ERR_SUCCESS;
+}
+
+/* Adds a value to a variable if it's the right type. */
+LPCTSTR AddVarValue(DWORD dwKey)
+{
+ DWORD dwStrSize;
+
+ SecureZeroMemory(gptBuffer, GlobalSize(gptBuffer));
+
+ popstring(gptVarName);
+ popstring(gptPathString);
+
+ if (!StrLen(gptPathString)) return ERR_NOVALUE;
+
+ if (CreateRegKey() != ERROR_SUCCESS)
+ return ERR_NOWRITE;
+ else
+ {
+ DWORD dwKeyType;
+
+ dwStrSize = StrSize(gptBuffer);
+ ReadRegVar(gptVarName, &dwKeyType, gptBuffer, &dwStrSize);
+
+ if (dwKeyType == REG_EXPAND_SZ) dwKey = dwKeyType;
+ if (!AppendSemiColon(gptPathString)) return ERR_NOWRITE;
+ if (!AppendSemiColon(gptBuffer)) return ERR_NOWRITE;
+
+ if (StrStrI(gptBuffer, gptPathString) == NULL)
+ {
+ int i, len = StrLen(gptBuffer);
+
+ /* Add one for separator and one for terminating NULL character. */
+ if (!StrReAlloc(gptBuffer, len+StrLen(gptPathString)+APPEND_SIZE))
+ return ERR_NOWRITE;
+
+ for (i = 0; i <= StrLen(gptPathString); i++)
+ gptBuffer[len+i] = gptPathString[i];
+
+ RemoveSemiColon(gptBuffer);
+ if (WriteRegVar(gptVarName, dwKey, gptBuffer, StrLen(gptBuffer)+1) != ERROR_SUCCESS)
+ return ERR_NOWRITE;
+ else
+ return ERR_SUCCESS;
+ }
+ else
+ return ERR_SUCCESS;
+ }
+}
+
+/* Deletes a value from a variable if it's the right type. */
+LPCTSTR DeleteVarValue(void)
+{
+ DWORD dwStrSize, dwKeyType;
+
+ SecureZeroMemory(gptBuffer, GlobalSize(gptBuffer));
+
+ popstring(gptVarName);
+ popstring(gptPathString);
+
+ dwStrSize = StrSize(gptBuffer);
+ if (ReadRegVar(gptVarName, &dwKeyType, gptBuffer, &dwStrSize) != ERROR_SUCCESS)
+ return ERR_NOVARIABLE;
+
+ if (!AppendSemiColon(gptPathString)) return ERR_NOWRITE;
+ if (!AppendSemiColon(gptBuffer)) return ERR_NOWRITE;
+
+ if (StrStrI(gptBuffer, gptPathString) == NULL)
+ return ERR_NOVALUE;
+ else
+ {
+ do
+ {
+ int i, len;
+ const PTCHAR str = StrStrI(gptBuffer, gptPathString);
+
+ if (str[StrLen(gptPathString)] == ';')
+ {
+ len = StrLen(str);
+ for (i = StrLen(gptPathString); i < len; i++)
+ str[i] = str[i+1];
+ }
+ len = StrLen(gptBuffer) - StrLen(str);
+ for (i = StrLen(gptPathString); i <= StrLen(str); i++, len++)
+ gptBuffer[len] = str[i];
+
+ } while (StrStrI(gptBuffer, gptPathString) != NULL);
+
+ RemoveSemiColon(gptBuffer);
+ if (WriteRegVar(gptVarName, dwKeyType, gptBuffer, StrLen(gptBuffer)+1) != ERROR_SUCCESS)
+ return ERR_NOWRITE;
+ else
+ return ERR_SUCCESS;
+ }
+}
+
+/* Deletes a variable from the environment. */
+LPCTSTR DeleteVar(void)
+{
+ DWORD dwRet, res;
+ HKEY hKey;
+
+ popstring(gptVarName);
+
+ if (!lstrcmpi(gptVarName, _T("path")))
+ return ERR_NOWRITE;
+
+ if (bRegKeyHKLM)
+ dwRet = RegOpenKeyEx(HKLM, HKLM_STR, 0, KEY_WRITE, &hKey);
+ else
+ dwRet = RegOpenKeyEx(HKCU, HKCU_STR, 0, KEY_WRITE, &hKey);
+
+ if (dwRet == ERROR_SUCCESS)
+ {
+ res = RegDeleteValue(hKey, gptVarName);
+ RegCloseKey(hKey);
+ if (res == ERROR_SUCCESS)
+ return ERR_SUCCESS;
+ }
+
+ return ERR_NOWRITE;
+}
+
+/* Updates the installer environment from the registry. */
+LPCTSTR UpdateVar(void)
+{
+ PTCHAR ptRegRoot = gptVarName, ptVarName = gptPathString;
+ DWORD dwRet, dwStrSize, dwKeyType;
+ BOOL bOldKey = GetRegKey();
+ int i;
+
+ popstring(ptRegRoot);
+ popstring(ptVarName);
+
+ if (!lstrcmpi(ptRegRoot, _T("HKCU")) || !lstrcmpi(ptRegRoot, _T("HKLM")))
+ {
+ if (!lstrcmpi(ptRegRoot, _T("HKLM")))
+ SetRegKey(TRUE);
+ else
+ SetRegKey(FALSE);
+
+ dwRet = ReadRegVar(ptVarName, &dwKeyType, gptBuffer, &dwStrSize);
+ SetRegKey(bOldKey);
+ if (dwRet != ERROR_SUCCESS)
+ return ERR_NOVARIABLE;
+ }
+ else
+ {
+ int len;
+
+ SetRegKey(FALSE);
+ dwRet = ReadRegVar(ptVarName, &dwKeyType, gptBuffer, &dwStrSize);
+ if (dwRet != ERROR_SUCCESS)
+ *ptRegRoot = 0;
+ else
+ {
+ if (!StrReAlloc(ptRegRoot, StrLen(gptBuffer)+APPEND_SIZE))
+ {
+ SetRegKey(bOldKey);
+ return ERR_NOWRITE;
+ }
+ /* Update global pointer if ptRegRoot was changed. */
+ gptVarName = (gptVarName != ptRegRoot) ? ptRegRoot : gptVarName;
+ for (i = 0; i <= StrLen(gptBuffer); i++)
+ ptRegRoot[i] = gptBuffer[i];
+ AppendSemiColon(ptRegRoot);
+ }
+ SetRegKey(TRUE);
+ dwRet = ReadRegVar(ptVarName, &dwKeyType, gptBuffer, &dwStrSize);
+ SetRegKey(bOldKey);
+ if (dwRet != ERROR_SUCCESS)
+ if (!(*ptRegRoot))
+ return ERR_NOVARIABLE;
+ else
+ *gptBuffer = 0;
+
+ AppendSemiColon(gptBuffer);
+ len = StrLen(gptBuffer);
+
+ /* Add one for separator and one for terminating NULL character. */
+ if (!StrReAlloc(gptBuffer, len+StrLen(ptRegRoot)+APPEND_SIZE))
+ return ERR_NOWRITE;
+
+ for (i = 0; i <= StrLen(ptRegRoot); i++)
+ gptBuffer[len+i] = ptRegRoot[i];
+
+ RemoveSemiColon(gptBuffer);
+ }
+ if (SetEnvironmentVariable(ptVarName, gptBuffer))
+ return ERR_SUCCESS;
+ else
+ return ERR_NOWRITE;
+}
+
+/* This routine sets the environment root, HKCU. */
+__declspec(dllexport) void SetHKCU(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ SetRegKey(FALSE);
+}
+
+/* This routine sets the environment root, HKLM. */
+__declspec(dllexport) void SetHKLM(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ SetRegKey(TRUE);
+}
+
+/* This routine checks for a path in an environment variable. */
+__declspec(dllexport) void Check(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ pushstring(CheckVar());
+}
+
+/* This routine adds a REG_SZ value in a environment variable (checks for existing paths first). */
+__declspec(dllexport) void AddValue(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ pushstring(AddVarValue(REG_SZ));
+}
+
+/* This routine adds a REG_EXPAND_SZ value in a environment variable (checks for existing paths first). */
+__declspec(dllexport) void AddValueEx(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ pushstring(AddVarValue(REG_EXPAND_SZ));
+}
+
+/* This routine deletes a value in an environment variable if it exists. */
+__declspec(dllexport) void DeleteValue(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ pushstring(DeleteVarValue());
+}
+
+/* This routine deletes an environment variable if it exists. */
+__declspec(dllexport) void Delete(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ pushstring(DeleteVar());
+}
+
+/* This routine reads the registry and updates the process environment. */
+__declspec(dllexport) void Update(HWND hwndParent, int string_size, TCHAR *variables, stack_t **stacktop, extra_parameters* xp)
+{
+ /* Initialize the stack so we can access it from our DLL using
+ popstring and pushstring. */
+ EXDLL_INIT();
+ Initialize(xp);
+
+ pushstring(UpdateVar());
+}
+
+/* Our DLL entry point, this is called when we first load up our DLL. */
+BOOL WINAPI _DllMainCRTStartup(HINSTANCE hInst, DWORD ul_reason_for_call, LPVOID lpReserved)
+{
+ hInstance = hInst;
+
+ if (ul_reason_for_call == DLL_PROCESS_DETACH)
+ CleanUp();
+
+ return TRUE;
+}
\ No newline at end of file
diff --git a/Contrib/EnVar/nsis/api.h b/Contrib/EnVar/nsis/api.h
new file mode 100644
index 0000000..85d41c4
--- /dev/null
+++ b/Contrib/EnVar/nsis/api.h
@@ -0,0 +1,83 @@
+/*
+ * apih
+ *
+ * This file is a part of NSIS.
+ *
+ * Copyright (C) 1999-2013 Nullsoft and Contributors
+ *
+ * Licensed under the zlib/libpng license (the "License");
+ * you may not use this file except in compliance with the License.
+ *
+ * Licence details can be found in the file COPYING.
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.
+ */
+
+#ifndef _NSIS_EXEHEAD_API_H_
+#define _NSIS_EXEHEAD_API_H_
+
+// Starting with NSIS 2.42, you can check the version of the plugin API in exec_flags->plugin_api_version
+// The format is 0xXXXXYYYY where X is the major version and Y is the minor version (MAKELONG(y,x))
+// When doing version checks, always remember to use >=, ex: if (pX->exec_flags->plugin_api_version >= NSISPIAPIVER_1_0) {}
+
+#define NSISPIAPIVER_1_0 0x00010000
+#define NSISPIAPIVER_CURR NSISPIAPIVER_1_0
+
+// NSIS Plug-In Callback Messages
+enum NSPIM
+{
+ NSPIM_UNLOAD, // This is the last message a plugin gets, do final cleanup
+ NSPIM_GUIUNLOAD, // Called after .onGUIEnd
+};
+
+// Prototype for callbacks registered with extra_parameters->RegisterPluginCallback()
+// Return NULL for unknown messages
+// Should always be __cdecl for future expansion possibilities
+typedef UINT_PTR (*NSISPLUGINCALLBACK)(enum NSPIM);
+
+// extra_parameters data structures containing other interesting stuff
+// but the stack, variables and HWND passed on to plug-ins.
+typedef struct
+{
+ int autoclose;
+ int all_user_var;
+ int exec_error;
+ int abort;
+ int exec_reboot; // NSIS_SUPPORT_REBOOT
+ int reboot_called; // NSIS_SUPPORT_REBOOT
+ int XXX_cur_insttype; // depreacted
+ int plugin_api_version; // see NSISPIAPIVER_CURR
+ // used to be XXX_insttype_changed
+ int silent; // NSIS_CONFIG_SILENT_SUPPORT
+ int instdir_error;
+ int rtl;
+ int errlvl;
+ int alter_reg_view;
+ int status_update;
+} exec_flags_t;
+
+#ifndef NSISCALL
+# define NSISCALL __stdcall
+#endif
+
+typedef struct {
+ exec_flags_t *exec_flags;
+ int (NSISCALL *ExecuteCodeSegment)(int, HWND);
+ void (NSISCALL *validate_filename)(TCHAR *);
+ int (NSISCALL *RegisterPluginCallback)(HMODULE, NSISPLUGINCALLBACK); // returns 0 on success, 1 if already registered and < 0 on errors
+} extra_parameters;
+
+// Definitions for page showing plug-ins
+// See Ui.c to understand better how they're used
+
+// sent to the outer window to tell it to go to the next inner window
+#define WM_NOTIFY_OUTER_NEXT (WM_USER+0x8)
+
+// custom pages should send this message to let NSIS know they're ready
+#define WM_NOTIFY_CUSTOM_READY (WM_USER+0xd)
+
+// sent as wParam with WM_NOTIFY_OUTER_NEXT when user cancels - heed its warning
+#define NOTIFY_BYE_BYE 'x'
+
+#endif /* _PLUGIN_H_ */
diff --git a/Contrib/EnVar/nsis/nsis_tchar.h b/Contrib/EnVar/nsis/nsis_tchar.h
new file mode 100644
index 0000000..0664768
--- /dev/null
+++ b/Contrib/EnVar/nsis/nsis_tchar.h
@@ -0,0 +1,229 @@
+/*
+ * nsis_tchar.h
+ *
+ * This file is a part of NSIS.
+ *
+ * Copyright (C) 1999-2013 Nullsoft and Contributors
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.
+ *
+ * For Unicode support by Jim Park -- 08/30/2007
+ */
+
+// Jim Park: Only those we use are listed here.
+
+#pragma once
+
+#ifdef _UNICODE
+
+#ifndef _T
+#define __T(x) L ## x
+#define _T(x) __T(x)
+#define _TEXT(x) __T(x)
+#endif
+
+#ifndef _TCHAR_DEFINED
+#define _TCHAR_DEFINED
+#if !defined(_NATIVE_WCHAR_T_DEFINED) && !defined(_WCHAR_T_DEFINED)
+typedef unsigned short TCHAR;
+#else
+typedef wchar_t TCHAR;
+#endif
+#endif
+
+
+// program
+#define _tenviron _wenviron
+#define __targv __wargv
+
+// printfs
+#define _ftprintf fwprintf
+#define _sntprintf _snwprintf
+#if (defined(_MSC_VER) && (_MSC_VER<=1310||_MSC_FULL_VER<=140040310)) || defined(__MINGW32__)
+# define _stprintf swprintf
+#else
+# define _stprintf _swprintf
+#endif
+#define _tprintf wprintf
+#define _vftprintf vfwprintf
+#define _vsntprintf _vsnwprintf
+#if defined(_MSC_VER) && (_MSC_VER<=1310)
+# define _vstprintf vswprintf
+#else
+# define _vstprintf _vswprintf
+#endif
+
+// scanfs
+#define _tscanf wscanf
+#define _stscanf swscanf
+
+// string manipulations
+#define _tcscat wcscat
+#define _tcschr wcschr
+#define _tcsclen wcslen
+#define _tcscpy wcscpy
+#define _tcsdup _wcsdup
+#define _tcslen wcslen
+#define _tcsnccpy wcsncpy
+#define _tcsncpy wcsncpy
+#define _tcsrchr wcsrchr
+#define _tcsstr wcsstr
+#define _tcstok wcstok
+
+// string comparisons
+#define _tcscmp wcscmp
+#define _tcsicmp _wcsicmp
+#define _tcsncicmp _wcsnicmp
+#define _tcsncmp wcsncmp
+#define _tcsnicmp _wcsnicmp
+
+// upper / lower
+#define _tcslwr _wcslwr
+#define _tcsupr _wcsupr
+#define _totlower towlower
+#define _totupper towupper
+
+// conversions to numbers
+#define _tcstoi64 _wcstoi64
+#define _tcstol wcstol
+#define _tcstoul wcstoul
+#define _tstof _wtof
+#define _tstoi _wtoi
+#define _tstoi64 _wtoi64
+#define _ttoi _wtoi
+#define _ttoi64 _wtoi64
+#define _ttol _wtol
+
+// conversion from numbers to strings
+#define _itot _itow
+#define _ltot _ltow
+#define _i64tot _i64tow
+#define _ui64tot _ui64tow
+
+// file manipulations
+#define _tfopen _wfopen
+#define _topen _wopen
+#define _tremove _wremove
+#define _tunlink _wunlink
+
+// reading and writing to i/o
+#define _fgettc fgetwc
+#define _fgetts fgetws
+#define _fputts fputws
+#define _gettchar getwchar
+
+// directory
+#define _tchdir _wchdir
+
+// environment
+#define _tgetenv _wgetenv
+#define _tsystem _wsystem
+
+// time
+#define _tcsftime wcsftime
+
+#else // ANSI
+
+#ifndef _T
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#ifndef _TCHAR_DEFINED
+#define _TCHAR_DEFINED
+typedef char TCHAR;
+#endif
+
+// program
+#define _tenviron environ
+#define __targv __argv
+
+// printfs
+#define _ftprintf fprintf
+#define _sntprintf _snprintf
+#define _stprintf sprintf
+#define _tprintf printf
+#define _vftprintf vfprintf
+#define _vsntprintf _vsnprintf
+#define _vstprintf vsprintf
+
+// scanfs
+#define _tscanf scanf
+#define _stscanf sscanf
+
+// string manipulations
+#define _tcscat strcat
+#define _tcschr strchr
+#define _tcsclen strlen
+#define _tcscnlen strnlen
+#define _tcscpy strcpy
+#define _tcsdup _strdup
+#define _tcslen strlen
+#define _tcsnccpy strncpy
+#define _tcsrchr strrchr
+#define _tcsstr strstr
+#define _tcstok strtok
+
+// string comparisons
+#define _tcscmp strcmp
+#define _tcsicmp _stricmp
+#define _tcsncmp strncmp
+#define _tcsncicmp _strnicmp
+#define _tcsnicmp _strnicmp
+
+// upper / lower
+#define _tcslwr _strlwr
+#define _tcsupr _strupr
+
+#define _totupper toupper
+#define _totlower tolower
+
+// conversions to numbers
+#define _tcstol strtol
+#define _tcstoul strtoul
+#define _tstof atof
+#define _tstoi atoi
+#define _tstoi64 _atoi64
+#define _tstoi64 _atoi64
+#define _ttoi atoi
+#define _ttoi64 _atoi64
+#define _ttol atol
+
+// conversion from numbers to strings
+#define _i64tot _i64toa
+#define _itot _itoa
+#define _ltot _ltoa
+#define _ui64tot _ui64toa
+
+// file manipulations
+#define _tfopen fopen
+#define _topen _open
+#define _tremove remove
+#define _tunlink _unlink
+
+// reading and writing to i/o
+#define _fgettc fgetc
+#define _fgetts fgets
+#define _fputts fputs
+#define _gettchar getchar
+
+// directory
+#define _tchdir _chdir
+
+// environment
+#define _tgetenv getenv
+#define _tsystem system
+
+// time
+#define _tcsftime strftime
+
+#endif
+
+// is functions (the same in Unicode / ANSI)
+#define _istgraph isgraph
+#define _istascii __isascii
+
+#define __TFILE__ _T(__FILE__)
+#define __TDATE__ _T(__DATE__)
+#define __TTIME__ _T(__TIME__)
diff --git a/Contrib/EnVar/nsis/pluginapi-amd64-unicode.lib b/Contrib/EnVar/nsis/pluginapi-amd64-unicode.lib
new file mode 100644
index 0000000..e256434
Binary files /dev/null and b/Contrib/EnVar/nsis/pluginapi-amd64-unicode.lib differ
diff --git a/Contrib/EnVar/nsis/pluginapi-x86-ansi.lib b/Contrib/EnVar/nsis/pluginapi-x86-ansi.lib
new file mode 100644
index 0000000..462070c
Binary files /dev/null and b/Contrib/EnVar/nsis/pluginapi-x86-ansi.lib differ
diff --git a/Contrib/EnVar/nsis/pluginapi-x86-unicode.lib b/Contrib/EnVar/nsis/pluginapi-x86-unicode.lib
new file mode 100644
index 0000000..c83d942
Binary files /dev/null and b/Contrib/EnVar/nsis/pluginapi-x86-unicode.lib differ
diff --git a/Contrib/EnVar/nsis/pluginapi.h b/Contrib/EnVar/nsis/pluginapi.h
new file mode 100644
index 0000000..ca671a8
--- /dev/null
+++ b/Contrib/EnVar/nsis/pluginapi.h
@@ -0,0 +1,104 @@
+#ifndef ___NSIS_PLUGIN__H___
+#define ___NSIS_PLUGIN__H___
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "api.h"
+#include "nsis_tchar.h"
+
+#ifndef NSISCALL
+# define NSISCALL __stdcall
+#endif
+
+#define EXDLL_INIT() { \
+ g_stringsize=string_size; \
+ g_stacktop=stacktop; \
+ g_variables=variables; }
+
+typedef struct _stack_t {
+ struct _stack_t *next;
+ TCHAR text[1]; // this should be the length of string_size
+} stack_t;
+
+enum
+{
+INST_0, // $0
+INST_1, // $1
+INST_2, // $2
+INST_3, // $3
+INST_4, // $4
+INST_5, // $5
+INST_6, // $6
+INST_7, // $7
+INST_8, // $8
+INST_9, // $9
+INST_R0, // $R0
+INST_R1, // $R1
+INST_R2, // $R2
+INST_R3, // $R3
+INST_R4, // $R4
+INST_R5, // $R5
+INST_R6, // $R6
+INST_R7, // $R7
+INST_R8, // $R8
+INST_R9, // $R9
+INST_CMDLINE, // $CMDLINE
+INST_INSTDIR, // $INSTDIR
+INST_OUTDIR, // $OUTDIR
+INST_EXEDIR, // $EXEDIR
+INST_LANG, // $LANGUAGE
+__INST_LAST
+};
+
+extern unsigned int g_stringsize;
+extern stack_t **g_stacktop;
+extern TCHAR *g_variables;
+
+void NSISCALL pushstring(const TCHAR *str);
+void NSISCALL pushintptr(INT_PTR value);
+#define pushint(v) pushintptr((INT_PTR)(v))
+int NSISCALL popstring(TCHAR *str); // 0 on success, 1 on empty stack
+int NSISCALL popstringn(TCHAR *str, int maxlen); // with length limit, pass 0 for g_stringsize
+INT_PTR NSISCALL popintptr();
+#define popint() ( (int) popintptr() )
+int NSISCALL popint_or(); // with support for or'ing (2|4|8)
+INT_PTR NSISCALL nsishelper_str_to_ptr(const TCHAR *s);
+#define myatoi(s) ( (int) nsishelper_str_to_ptr(s) ) // converts a string to an integer
+unsigned int NSISCALL myatou(const TCHAR *s); // converts a string to an unsigned integer, decimal only
+int NSISCALL myatoi_or(const TCHAR *s); // with support for or'ing (2|4|8)
+TCHAR* NSISCALL getuservariable(const int varnum);
+void NSISCALL setuservariable(const int varnum, const TCHAR *var);
+
+#ifdef _UNICODE
+#define PopStringW(x) popstring(x)
+#define PushStringW(x) pushstring(x)
+#define SetUserVariableW(x,y) setuservariable(x,y)
+
+int NSISCALL PopStringA(char* ansiStr);
+void NSISCALL PushStringA(const char* ansiStr);
+void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr);
+void NSISCALL GetUserVariableA(const int varnum, char* ansiStr);
+void NSISCALL SetUserVariableA(const int varnum, const char* ansiStr);
+
+#else
+// ANSI defs
+
+#define PopStringA(x) popstring(x)
+#define PushStringA(x) pushstring(x)
+#define SetUserVariableA(x,y) setuservariable(x,y)
+
+int NSISCALL PopStringW(wchar_t* wideStr);
+void NSISCALL PushStringW(wchar_t* wideStr);
+void NSISCALL GetUserVariableW(const int varnum, wchar_t* wideStr);
+void NSISCALL GetUserVariableA(const int varnum, char* ansiStr);
+void NSISCALL SetUserVariableW(const int varnum, const wchar_t* wideStr);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//!___NSIS_PLUGIN__H___
diff --git a/Docs/EnVar/license.txt b/Docs/EnVar/license.txt
new file mode 100644
index 0000000..a4e466a
--- /dev/null
+++ b/Docs/EnVar/license.txt
@@ -0,0 +1,18 @@
+EnVar plugin for NSIS
+
+Coded by Jason Ross aka JasonFriday13 on the forums.
+
+Copyright (C) 2014-2016, 2018 MouseHelmet Software
+
+
+EULA - End User License Agreement
+
+This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
+
+2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source distribution.
\ No newline at end of file
diff --git a/Docs/EnVar/readme.txt b/Docs/EnVar/readme.txt
new file mode 100644
index 0000000..508b25b
--- /dev/null
+++ b/Docs/EnVar/readme.txt
@@ -0,0 +1,68 @@
+EnVar plugin for NSIS
+
+Coded by Jason Ross aka JasonFriday13 on the forums.
+
+Copyright (C) 2014-2016, 2018 MouseHelmet Software
+
+
+Introduction
+------------
+
+This plugin manages environment variables. It allows checking for environment
+variables, checking for paths in those variables, adding paths to variables,
+removing paths from variables, removing variables from the environment, and
+updating the installer enviroment from the registry. This plugin is provided
+with 32bit ansi and unicode versions, as well as a 64bit unicode version.
+
+Functions
+---------
+
+There are eight functions in this plugin. Returns an error code on the
+stack (unless noted otherwise), see below for the codes.
+
+ERR_SUCCESS 0 Function completed successfully.
+ERR_NOREAD 1 Function couldn't read from the environment.
+ERR_NOVARIABLE 2 Variable doesn't exist in the current environment.
+ERR_NOVALUE 3 Value doesn't exist in the Variable.
+ERR_NOWRITE 4 Function can't write to the current environment.
+
+EnVar::SetHKCU
+EnVar::SetHKLM
+
+ SetHKCU sets the environment access to the current user. This is the default.
+ SetHKLM sets the environment access to the local machine.
+ These functions do not return a value on the stack.
+
+EnVar::Check VariableName Path
+
+ Checks for a Path in the specified VariableName. Passing "null" as a Path makes
+ it check for the existance of VariableName. Passing "null" for both makes it
+ check for write access to the current environment.
+
+EnVar::AddValue VariableName Path
+EnVar::AddValueEx VariableName Path
+
+ Adds a Path to the specified VariableName. Does does not modify existing variables if
+ they are not the right type. AddValueEx is for expandable paths, ie %tempdir%. Both
+ functions respect expandable variables, so if the variable already exists, they
+ try to leave it intact. AddValueEx converts the variable to its expandable version.
+ If the path already exists, it returns a success error code.
+
+EnVar::DeleteValue VariableName Path
+
+ Deletes a path from a variable if it's the right type. The delete is also
+ recursive, so if it finds multiple paths, all of them are deleted as well.
+
+EnVar::Delete VariableName
+
+ Deletes a variable from the environment. Note that "path" cannot be deleted. Also,
+ variables that aren't the right type are not deleted.
+
+EnVar::Update RegRoot VariableName
+
+ Updates the installer environment by reading VariableName from the registry
+ and can use RegRoot to specify from which root it reads from: HKCU for the
+ current user, and HKLM for the local machine. Anything else (including an
+ empty string) for RegRoot means it reads from both roots, appends the paths
+ together, and updates the installer environment. This function is not affected
+ by EnVar::SetHKCU and EnVar::SetHKLM, and does not write to the registry.
diff --git a/Examples/EnVar/example.nsi b/Examples/EnVar/example.nsi
new file mode 100644
index 0000000..49bc323
--- /dev/null
+++ b/Examples/EnVar/example.nsi
@@ -0,0 +1,90 @@
+Name "EnVar Example"
+OutFile "EnVarExample.exe"
+
+RequestExecutionLevel User
+ShowInstDetails Show
+
+Page InstFiles
+
+Unicode True
+
+Section
+
+ ; Check for write access
+ EnVar::Check "NULL" "NULL"
+ Pop $0
+ DetailPrint "EnVar::Check write access HKCU returned=|$0|"
+
+ ; Set to HKLM
+ EnVar::SetHKLM
+
+ ; Check for write access
+ EnVar::Check "NULL" "NULL"
+ Pop $0
+ DetailPrint "EnVar::Check write access HKLM returned=|$0|"
+
+ ; Set back to HKCU
+ EnVar::SetHKCU
+ DetailPrint "EnVar::SetHKCU"
+
+ ; Check for a 'temp' variable
+ EnVar::Check "temp" "NULL"
+ Pop $0
+ DetailPrint "EnVar::Check returned=|$0|"
+
+ ; Add a value
+ EnVar::AddValue "ZTestVariable" "C:\Test"
+ Pop $0
+ DetailPrint "EnVar::AddValue returned=|$0|"
+
+ EnVar::AddValue "ZTestVariable" "C:\TestJas"
+ Pop $0
+ DetailPrint "EnVar::AddValue returned=|$0|"
+
+ ; Add an expanded value
+ EnVar::AddValue "ZTestVariable1" "C:\Test"
+ Pop $0
+ DetailPrint "EnVar::AddValue returned=|$0|"
+
+ EnVar::AddValueEx "ZTestVariable1" "C:\Test"
+ Pop $0
+ DetailPrint "EnVar::AddValue returned=|$0|"
+
+ EnVar::AddValueEx "ZTestVariable1" "C:\TestVariable"
+ Pop $0
+ DetailPrint "EnVar::AddValue returned=|$0|"
+
+ ; Update the installer environment so that new
+ ; paths are available to the installer
+ EnVar::Update "HKCU" "ZTestVariable"
+ Pop $0
+ DetailPrint "EnVar::Update returned=|$0|"
+
+ EnVar::Update "" "ZTestVariable1"
+ Pop $0
+ DetailPrint "EnVar::Update returned=|$0|"
+
+ ; Delete a value from a variable
+ EnVar::DeleteValue "ZTestVariable1" "C:\Test"
+ Pop $0
+ DetailPrint "EnVar::DeleteValue returned=|$0|"
+
+ EnVar::DeleteValue "ZTestVariable1" "C:\Test"
+ Pop $0
+ DetailPrint "EnVar::DeleteValue returned=|$0|"
+
+ EnVar::DeleteValue "ZTestVariable1" "C:\TestJason"
+ Pop $0
+ DetailPrint "EnVar::DeleteValue returned=|$0|"
+
+ ; Delete a variable
+ EnVar::Delete "ZTestVariable"
+ Pop $0
+ DetailPrint "EnVar::Delete returned=|$0|"
+
+ ; Try deleting "path", this should give an error
+ EnVar::Delete "path"
+ Pop $0
+ DetailPrint "EnVar::Delete returned=|$0|"
+
+SectionEnd
\ No newline at end of file
diff --git a/Plugins/amd64-unicode/EnVar.dll b/Plugins/amd64-unicode/EnVar.dll
new file mode 100644
index 0000000..87c5135
Binary files /dev/null and b/Plugins/amd64-unicode/EnVar.dll differ
diff --git a/Plugins/x86-ansi/EnVar.dll b/Plugins/x86-ansi/EnVar.dll
new file mode 100644
index 0000000..9fe7565
Binary files /dev/null and b/Plugins/x86-ansi/EnVar.dll differ
diff --git a/Plugins/x86-unicode/EnVar.dll b/Plugins/x86-unicode/EnVar.dll
new file mode 100644
index 0000000..08d60de
Binary files /dev/null and b/Plugins/x86-unicode/EnVar.dll differ