Simple patch to add explicit 32/64-bit registry support
Let me start off by saying that NSIS rocks and I really appreciate everyone who has worked so hard on this software.
The biggest problem I've run into is my need to install a .NET application on a 64-bit system using this 32-bit installer. I realized that the simplest solution to my problem was to explicitly write into the 64-bit registry space from 32-bit land. This patch provides a very simple way to accomplish this by allowing the user to pass in additional flags to the "REGSAM samDesired" parameter of the Win32 RegXXX functions.
This is probably not the correct way to do this but my total experience with the NSIS source code is about 1 hour. It definitely does what I need and I hope it helps someone else in a similar situation. If the concept fits the NSIS development model, it would be great if someone else wants to refine this code (maybe make the flags an optional parameter?).
Anyways, thanks again to the NSIS developers.
Cheers,
Ben Martz
Index: D:/SVN/3.0/installer/nsis-2.22-src/Source/tokens.cpp
===================================================================
--- D:/SVN/3.0/installer/nsis-2.22-src/Source/tokens.cpp (revision 586)
+++ D:/SVN/3.0/installer/nsis-2.22-src/Source/tokens.cpp (revision 587)
@@ -69,8 +69,8 @@
{TOK_DBOPTIMIZE,"SetDatablockOptimize",1,0,"(off|on)",TP_ALL},
{TOK_DELETEINISEC,"DeleteINISec",2,0,"ini_file section_name",TP_CODE},
{TOK_DELETEINISTR,"DeleteINIStr",3,0,"ini_file section_name entry_name",TP_CODE},
-{TOK_DELETEREGKEY,"DeleteRegKey",2,1,"[/ifempty] root_key subkey\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
-{TOK_DELETEREGVALUE,"DeleteRegValue",3,0,"root_key subkey entry_name\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_DELETEREGKEY,"DeleteRegKey",3,1,"[/ifempty] root_key subkey rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_DELETEREGVALUE,"DeleteRegValue",4,0,"root_key subkey entry_name rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
{TOK_DELETE,"Delete",1,1,"[/REBOOTOK] filespec",TP_CODE},
{TOK_DETAILPRINT,"DetailPrint",1,0,"message",TP_CODE},
{TOK_DIRTEXT,"DirText",0,4,"[directory_page_description] [directory_page_subtext] [browse_button_text] [browse_dlg_text]",TP_PG},
@@ -82,8 +82,8 @@
{TOK_ROOTDIRINST,"AllowRootDirInstall",1,0,"(true|false)",TP_GLOBAL},
{TOK_CHECKBITMAP,"CheckBitmap",1,0,"local_bitmap.bmp",TP_GLOBAL},
{TOK_ENABLEWINDOW,"EnableWindow",2,0,"hwnd (1|0)",TP_CODE},
-{TOK_ENUMREGKEY,"EnumRegKey",4,0,"$(user_var: output) rootkey subkey index\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
-{TOK_ENUMREGVAL,"EnumRegValue",4,0,"$(user_var: output) rootkey subkey index\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_ENUMREGKEY,"EnumRegKey",5,0,"$(user_var: output) rootkey subkey index rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_ENUMREGVAL,"EnumRegValue",5,0,"$(user_var: output) rootkey subkey index rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
{TOK_EXCH,"Exch",0,1,"[$(user_var)] | [stack_item_index]",TP_CODE},
{TOK_EXEC,"Exec",1,0,"command_line",TP_CODE},
{TOK_EXECWAIT,"ExecWait",1,1,"command_line [$(user_var: return value)]",TP_CODE},
@@ -117,7 +117,7 @@
{TOK_IFFILEEXISTS,"IfFileExists",2,1,"filename label_to_goto_if_file_exists [label_to_goto_otherwise]",TP_CODE},
{TOK_IFREBOOTFLAG,"IfRebootFlag",1,1,"jump_if_set [jump_if_not_set]",TP_CODE},
{TOK_IFSILENT,"IfSilent",1,1,"jump_if_silent [jump_if_not_silent]",TP_CODE},
-{TOK_INSTALLDIRREGKEY,"InstallDirRegKey",3,0,"root_key subkey entry_name\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD)",TP_GLOBAL},
+{TOK_INSTALLDIRREGKEY,"InstallDirRegKey",4,0,"root_key subkey entry_name rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD)",TP_GLOBAL},
{TOK_INSTCOLORS,"InstallColors",1,1,"(/windows | (foreground_color background_color))",TP_GLOBAL},
{TOK_INSTDIR,"InstallDir",1,0,"default_install_directory",TP_GLOBAL},
{TOK_INSTPROGRESSFLAGS,"InstProgressFlags",0,-1,"[flag [...]]\n flag={smooth|colored}",TP_GLOBAL},
@@ -155,8 +155,8 @@
{TOK_PUSH,"Push",1,0,"string",TP_CODE},
{TOK_QUIT,"Quit",0,0,"",TP_CODE},
{TOK_READINISTR,"ReadINIStr",4,0,"$(user_var: output) ini_file section entry_name",TP_CODE},
-{TOK_READREGDWORD,"ReadRegDWORD",4,0,"$(user_var: output) rootkey subkey entry\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
-{TOK_READREGSTR,"ReadRegStr",4,0,"$(user_var: output) rootkey subkey entry\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_READREGDWORD,"ReadRegDWORD",5,0,"$(user_var: output) rootkey subkey entry rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_READREGSTR,"ReadRegStr",5,0,"$(user_var: output) rootkey subkey entry rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
{TOK_READENVSTR,"ReadEnvStr",2,0,"$(user_var: output) name",TP_CODE},
{TOK_REBOOT,"Reboot",0,0,"",TP_CODE},
{TOK_REGDLL,"RegDLL",1,1,"dll_path_on_target.dll [entrypoint_symbol]",TP_CODE},
@@ -229,10 +229,10 @@
{TOK_UNREGDLL,"UnRegDLL",1,0,"dll_path_on_target.dll",TP_CODE},
{TOK_WINDOWICON,"WindowIcon",1,0,"on|off",TP_GLOBAL},
{TOK_WRITEINISTR,"WriteINIStr",4,0,"ini_file section_name entry_name new_value",TP_CODE},
-{TOK_WRITEREGBIN,"WriteRegBin",4,0,"rootkey subkey entry_name hex_string_like_12848412AB\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
-{TOK_WRITEREGDWORD,"WriteRegDWORD",4,0,"rootkey subkey entry_name new_value_dword\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
-{TOK_WRITEREGSTR,"WriteRegStr",4,0,"rootkey subkey entry_name new_value_string\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
-{TOK_WRITEREGEXPANDSTR,"WriteRegExpandStr",4,0,"rootkey subkey entry_name new_value_string\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_WRITEREGBIN,"WriteRegBin",5,0,"rootkey subkey entry_name hex_string_like_12848412AB rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_WRITEREGDWORD,"WriteRegDWORD",5,0,"rootkey subkey entry_name new_value_dword rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_WRITEREGSTR,"WriteRegStr",5,0,"rootkey subkey entry_name new_value_string rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
+{TOK_WRITEREGEXPANDSTR,"WriteRegExpandStr",5,0,"rootkey subkey entry_name new_value_string rootkeyflags\n root_key=(HKCR|HKLM|HKCU|HKU|HKCC|HKDD|HKPD|SHCTX)",TP_CODE},
{TOK_WRITEUNINSTALLER,"WriteUninstaller",1,0,"uninstall_exe_name",TP_CODE},
{TOK_XPSTYLE, "XPStyle",1,0,"(on|off)",TP_GLOBAL},
{TOK_REQEXECLEVEL, "RequestExecutionLevel",1,0,"none|user|highest|admin",TP_GLOBAL},
Index: D:/SVN/3.0/installer/nsis-2.22-src/Source/script.cpp
===================================================================
--- D:/SVN/3.0/installer/nsis-2.22-src/Source/script.cpp (revision 586)
+++ D:/SVN/3.0/installer/nsis-2.22-src/Source/script.cpp (revision 587)
@@ -5005,7 +5005,7 @@
int k=line.gettoken_enum(2,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(2,rootkeys[1]);
if (ent.offsets[0] == -1 || k == -1) PRINTHELP()
- ent.offsets[1]=(int)rootkey_tab[k];
+ ent.offsets[1]=(int)rootkey_tab[k] | line.gettoken_int(5); // benmartz: add support for root key flags
ent.offsets[2]=add_string(line.gettoken_str(3));
ent.offsets[3]=add_string(line.gettoken_str(4));
if (which_token == TOK_READREGDWORD) ent.offsets[4]=1;
@@ -5013,8 +5013,8 @@
if (line.gettoken_str(3)[0] == '\\')
warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
- SCRIPT_MSG("%s %s %s\\%s\\%s\n",line.gettoken_str(0),
- line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
+ SCRIPT_MSG("%s: %s\\%s\\%s\\%s flags=0x%08x\n",line.gettoken_str(0),
+ line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_int(5));
}
return add_entry(&ent);
case TOK_DELETEREGVALUE:
@@ -5031,21 +5031,21 @@
a++;
ent.offsets[4]=3;
}
- if (line.gettoken_str(a+2)[0]) PRINTHELP()
+ if (line.gettoken_str(a+3)[0]) PRINTHELP()
}
int k=line.gettoken_enum(a,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(a,rootkeys[1]);
if (k == -1) PRINTHELP()
ent.which=EW_DELREG;
- ent.offsets[1]=(int)rootkey_tab[k];
+ ent.offsets[1]=(int)rootkey_tab[k] | line.gettoken_int(a+3); // benmartz: add support for root key flags
ent.offsets[2]=add_string(line.gettoken_str(a+1));
ent.offsets[3]=(which_token==TOK_DELETEREGKEY)?0:add_string(line.gettoken_str(a+2));
if (line.gettoken_str(a+1)[0] == '\\')
warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
if (which_token==TOK_DELETEREGKEY)
- SCRIPT_MSG("DeleteRegKey: %s\\%s\n",line.gettoken_str(a),line.gettoken_str(a+1));
+ SCRIPT_MSG("DeleteRegKey: %s\\%s flags=0x%08x\n",line.gettoken_str(a),line.gettoken_str(a+1),line.gettoken_int(a+2));
else
- SCRIPT_MSG("DeleteRegValue: %s\\%s\\%s\n",line.gettoken_str(a),line.gettoken_str(a+1),line.gettoken_str(a+2));
+ SCRIPT_MSG("DeleteRegValue: %s\\%s\\%s flags=0x%08x\n",line.gettoken_str(a),line.gettoken_str(a+1),line.gettoken_str(a+2),line.gettoken_int(a+3));
}
return add_entry(&ent);
case TOK_WRITEREGSTR:
@@ -5057,15 +5057,15 @@
if (k == -1) k=line.gettoken_enum(1,rootkeys[1]);
if (k == -1) PRINTHELP()
ent.which=EW_WRITEREG;
- ent.offsets[0]=(int)rootkey_tab[k];
+ ent.offsets[0]=(int)rootkey_tab[k] | line.gettoken_int(5); // benmartz: add support for root key flags
ent.offsets[1]=add_string(line.gettoken_str(2));
if (line.gettoken_str(2)[0] == '\\')
warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
ent.offsets[2]=add_string(line.gettoken_str(3));
if (which_token == TOK_WRITEREGSTR || which_token == TOK_WRITEREGEXPANDSTR)
{
- SCRIPT_MSG("%s: %s\\%s\\%s=%s\n",
- line.gettoken_str(0),line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
+ SCRIPT_MSG("%s: %s\\%s\\%s=%s flags=0x%08x\n",
+ line.gettoken_str(0),line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_int(5));
ent.offsets[3]=add_string(line.gettoken_str(4));
ent.offsets[4]=ent.offsets[5]=REG_SZ;
if (which_token == TOK_WRITEREGEXPANDSTR)
@@ -5102,8 +5102,8 @@
data[data_len++]=c;
}
if (*p) PRINTHELP()
- SCRIPT_MSG("WriteRegBin: %s\\%s\\%s=%s\n",
- line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
+ SCRIPT_MSG("WriteRegBin: %s\\%s\\%s=%s flags=%08x\n",
+ line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_int(5));
ent.offsets[3]=add_db_data(data,data_len);
if (ent.offsets[3] < 0) return PS_ERROR;
ent.offsets[4]=ent.offsets[5]=REG_BINARY;
@@ -5113,8 +5113,8 @@
ent.offsets[3]=add_string(line.gettoken_str(4));
ent.offsets[4]=ent.offsets[5]=REG_DWORD;
- SCRIPT_MSG("WriteRegDWORD: %s\\%s\\%s=%s\n",
- line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
+ SCRIPT_MSG("WriteRegDWORD: %s\\%s\\%s=%s flags=%08x\n",
+ line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_int(5));
}
}
return add_entry(&ent);
@@ -5126,13 +5126,13 @@
int k=line.gettoken_enum(2,rootkeys[0]);
if (k == -1) k=line.gettoken_enum(2,rootkeys[1]);
if (ent.offsets[0] == -1 || k == -1) PRINTHELP()
- ent.offsets[1]=(int)rootkey_tab[k];
+ ent.offsets[1]=(int)rootkey_tab[k] | line.gettoken_int(5); // benmartz: add support for root key flags
ent.offsets[2]=add_string(line.gettoken_str(3));
ent.offsets[3]=add_string(line.gettoken_str(4));
ent.offsets[4]=which_token == TOK_ENUMREGKEY;
if (line.gettoken_str(3)[0] == '\\') warning_fl("%s: registry path name begins with \'\\\', may cause problems",line.gettoken_str(0));
- SCRIPT_MSG("%s %s %s\\%s\\%s\n",which_token == TOK_ENUMREGKEY ? "EnumRegKey" : "EnumRegValue",
- line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4));
+ SCRIPT_MSG("%s %s %s\\%s\\%s flags=%08x\n",which_token == TOK_ENUMREGKEY ? "EnumRegKey" : "EnumRegValue",
+ line.gettoken_str(1),line.gettoken_str(2),line.gettoken_str(3),line.gettoken_str(4),line.gettoken_int(5));
}
return add_entry(&ent);
#else//!NSIS_SUPPORT_REGISTRYFUNCTIONS
Index: D:/SVN/3.0/installer/nsis-2.22-src/Source/exehead/exec.c
===================================================================
--- D:/SVN/3.0/installer/nsis-2.22-src/Source/exehead/exec.c (revision 586)
+++ D:/SVN/3.0/installer/nsis-2.22-src/Source/exehead/exec.c (revision 587)
@@ -131,7 +131,7 @@
static LONG NSISCALL myRegDeleteKeyEx(HKEY thiskey, LPCTSTR lpSubKey, int onlyifempty)
{
HKEY key;
- int retval=RegOpenKeyEx(thiskey,lpSubKey,0,KEY_ENUMERATE_SUB_KEYS,&key);
+ int retval=RegOpenKeyEx((HKEY)(((int)thiskey) & ~0x300),lpSubKey,0,KEY_ENUMERATE_SUB_KEYS | ((int)thiskey & 0x300),&key);
if (retval==ERROR_SUCCESS)
{
// NB - don't change this to static (recursive function)
@@ -163,7 +163,7 @@
static HKEY NSISCALL myRegOpenKey(REGSAM samDesired)
{
HKEY hKey;
- if (RegOpenKeyEx(GetRegRootKey(parms[1]), GetStringFromParm(0x22), 0, samDesired, &hKey) == ERROR_SUCCESS)
+ if (RegOpenKeyEx(GetRegRootKey(parms[1] & ~0x300), GetStringFromParm(0x22), 0, samDesired | (parms[1] & 0x300), &hKey) == ERROR_SUCCESS)
{
return hKey;
}
@@ -1187,7 +1187,7 @@
const char *rkn=RegKeyHandleToName(rootkey);
exec_error++;
- if (RegCreateKeyEx(rootkey,buf1,0,0,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE,0,&hKey,0) == ERROR_SUCCESS)
+ if (RegCreateKeyEx((HKEY)(((int)parm0) & ~0x300),buf1,0,0,REG_OPTION_NON_VOLATILE,KEY_SET_VALUE | ((int)parm0 & 0x300),0,&hKey,0) == ERROR_SUCCESS)
{
LPBYTE data = (LPBYTE) buf2;
DWORD size = 0;
Index: D:/SVN/3.0/installer/nsis-2.22-src/JPR README.txt
===================================================================
--- D:/SVN/3.0/installer/nsis-2.22-src/JPR README.txt (revision 0)
+++ D:/SVN/3.0/installer/nsis-2.22-src/JPR README.txt (revision 587)
@@ -0,0 +1,16 @@
+1. Install Python and SCONS as specified.
+2. Open your VS2005 command line and run
+ scons TEMP_MSVC2005=yes PREFIX="C:\Program Files\NSIS" install
+
+That's it! All RegXXX commands now have an additional parameter where we can pass
+${KEY_WOW64_64KEY} or ${KEY_WOW64_32KEY} as needed.
+
+You may need the following defines if not including CDMS_Common.nsh:
+
+!define KEY_WOW64_64KEY 0x0100 ; always access 64-bit key
+!define KEY_WOW64_32KEY 0x0200 ; always access 32-bit key
+
+
+Have fun!
+Ben Martz
+4 December 2006