Fixed SetRegView and $ProgramFiles[32|64] in 64-bit installers

git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6841 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
anders_k 2017-03-22 00:46:25 +00:00
parent a9b56a63fd
commit c1c2ccb4a6
7 changed files with 33 additions and 36 deletions

View file

@ -2,7 +2,7 @@
In all of the below registry instructions use an empty string (just two quotes with nothing between them - "") as the key name to specify the default key which is shown as (Default) in regedit.exe. In all of the below registry instructions use an empty string (just two quotes with nothing between them - "") as the key name to specify the default key which is shown as (Default) in regedit.exe.
Use \R{setregview}{SetRegView} on Windows x64 to choose which registry view is used. Use \R{setregview}{SetRegView} on 64-bit Windows to choose which registry view is used.
If a full path is not specified for any of the INI handling instructions, the Windows directory will be used. If a full path is not specified for any of the INI handling instructions, the Windows directory will be used.
@ -198,7 +198,7 @@ Writes a multi-string value. The /REGEDIT5 switch must be used and specifies tha
\S2{setregview} SetRegView \S2{setregview} SetRegView
\c \\<b\\>32\\</b\\>|64|lastused \c 32|64|\\<b\\>default\\</b\\>|lastused
Sets the registry view affected by \R{registry}{registry commands}. On 64-bit versions of Windows there are two views; one for 32-bit applications and one for 64-bit applications. By default, 32-bit applications running on 64-bit systems (WOW64) only have access to the 32-bit view. Using \c{SetRegView 64} allows the installer to access keys in the 64-bit view of the registry. Sets the registry view affected by \R{registry}{registry commands}. On 64-bit versions of Windows there are two views; one for 32-bit applications and one for 64-bit applications. By default, 32-bit applications running on 64-bit systems (WOW64) only have access to the 32-bit view. Using \c{SetRegView 64} allows the installer to access keys in the 64-bit view of the registry.

View file

@ -642,6 +642,9 @@ typedef DWORDLONG ULONGLONG,*PULONGLONG;
# define HKEY_DYN_DATA ((HKEY)0x80000006) # define HKEY_DYN_DATA ((HKEY)0x80000006)
#endif #endif
#ifndef KEY_WOW64_32KEY
# define KEY_WOW64_32KEY 0x200
#endif
#ifndef KEY_WOW64_64KEY #ifndef KEY_WOW64_64KEY
# define KEY_WOW64_64KEY 0x100 # define KEY_WOW64_64KEY 0x100
#endif #endif

View file

@ -426,24 +426,25 @@ void CEXEBuild::init_shellconstantvalues()
static bool done = false; static bool done = false;
if (done) return ; else done = true; if (done) return ; else done = true;
const int orgunmode = uninstall_mode; const int orgunmode = uninstall_mode, t64 = is_target_64bit(), reg = 0x80, r32 = t64 ? 0xC0 : reg, r64 = r32 ^ 0x40;
set_uninstall_mode(0); set_uninstall_mode(0);
// Note: The order matters because some of the strings are preprocessed and cf must be <= 0x40 // Note: The order matters because some of the strings are preprocessed and cf must be <= 0x40
unsigned int pf = add_asciistring(_T("ProgramFilesDir"), 0); unsigned int pf = add_asciistring(_T("ProgramFilesDir"), 0);
unsigned int cf = add_asciistring(_T("CommonFilesDir"), 0); unsigned int cf = add_asciistring(_T("CommonFilesDir"), 0);
unsigned int pf_def = add_asciistring(_T("C:\\Program Files")); unsigned int pf_def = add_asciistring(_T("C:\\Program Files")); // Ultimate fallback
m_ShellConstants.set_values(_T("PROGRAMFILES"), 0x80 | pf, pf_def); // TODO: 64-bit targets could use CSIDL_PROGRAM_FILES+CSIDL_PROGRAM_FILESX86?
unsigned int pf64_def = add_asciistring(_T("$PROGRAMFILES")); m_ShellConstants.set_values(_T("PROGRAMFILES"), reg | pf, pf_def);
m_ShellConstants.set_values(_T("PROGRAMFILES32"), 0x80 | pf, pf_def); unsigned int pf_var = add_asciistring(_T("$PROGRAMFILES")); // Fallback for the 32/64 specific constants if the WOW registry view fails
m_ShellConstants.set_values(_T("PROGRAMFILES64"), 0xC0 | pf, pf64_def); m_ShellConstants.set_values(_T("PROGRAMFILES32"), r32 | pf, reg != r32 ? pf_var : pf_def);
m_ShellConstants.set_values(_T("PROGRAMFILES64"), r64 | pf, reg != r64 ? pf_var : pf_def);
unsigned int cf_def = add_asciistring(_T("$PROGRAMFILES\\Common Files")); unsigned int cf_def = add_asciistring(_T("$PROGRAMFILES\\Common Files"));
m_ShellConstants.set_values(_T("COMMONFILES"), 0x80 | cf, cf_def); m_ShellConstants.set_values(_T("COMMONFILES"), reg | cf, cf_def);
unsigned int cf64_def = add_asciistring(_T("$COMMONFILES")); unsigned int cf_var = add_asciistring(_T("$COMMONFILES"));
m_ShellConstants.set_values(_T("COMMONFILES32"), 0x80 | cf, cf_def); m_ShellConstants.set_values(_T("COMMONFILES32"), r32 | cf, reg != r32 ? cf_var : cf_def);
m_ShellConstants.set_values(_T("COMMONFILES64"), 0xC0 | cf, cf64_def); m_ShellConstants.set_values(_T("COMMONFILES64"), r64 | cf, reg != r64 ? cf_var : cf_def);
if ( (pf >= 0x40 || pf_def >= 0xFF || pf64_def > 0xFF) // BUGBUG: pf_def should be ">"? if ( (pf >= 0x40 || pf_def >= 0xFF || pf_var > 0xFF) // BUGBUG: pf_def should be ">"?
|| (cf > 0x40 || cf_def > 0xFF || cf64_def > 0xFF) ) || (cf > 0x40 || cf_def > 0xFF || cf_var > 0xFF) )
{ {
// see Source\exehead\util.c for implementation details // see Source\exehead\util.c for implementation details
// basically, it knows it needs to get folders from the registry when the 0x80 is on // basically, it knows it needs to get folders from the registry when the 0x80 is on
@ -456,17 +457,13 @@ void CEXEBuild::init_shellconstantvalues()
unsigned int unpf = add_asciistring(_T("ProgramFilesDir"), 0); unsigned int unpf = add_asciistring(_T("ProgramFilesDir"), 0);
unsigned int uncf = add_asciistring(_T("CommonFilesDir"), 0); unsigned int uncf = add_asciistring(_T("CommonFilesDir"), 0);
unsigned int unpf_def = add_asciistring(_T("C:\\Program Files")); unsigned int unpf_def = add_asciistring(_T("C:\\Program Files"));
unsigned int unpf64_def = add_asciistring(_T("$PROGRAMFILES")); unsigned int unpf_var = add_asciistring(_T("$PROGRAMFILES"));
unsigned int uncf_def = add_asciistring(_T("$PROGRAMFILES\\Common Files")); unsigned int uncf_def = add_asciistring(_T("$PROGRAMFILES\\Common Files"));
unsigned int uncf64_def = add_asciistring(_T("$COMMONFILES")); unsigned int uncf_var = add_asciistring(_T("$COMMONFILES"));
set_uninstall_mode(orgunmode); set_uninstall_mode(orgunmode);
if ( unpf != pf if ( unpf != pf || unpf_def != pf_def || unpf_var != pf_var
|| unpf_def != pf_def || uncf != cf || uncf_def != cf_def || uncf_var != cf_var )
|| unpf64_def != pf64_def
|| uncf != cf
|| uncf_def != cf_def
|| uncf64_def != cf64_def)
{ {
const char* msg = "Internal compiler error: installer's shell constants are different than uninstallers!"; const char* msg = "Internal compiler error: installer's shell constants are different than uninstallers!";
ERROR_MSG(_T("%") NPRIns, msg); ERROR_MSG(_T("%") NPRIns, msg);

View file

@ -645,14 +645,14 @@ void NSISCALL MoveFileOnReboot(LPCTSTR pszExisting, LPCTSTR pszNew)
// The value of registry->sub->name is stored in out. If failure, then out becomes // The value of registry->sub->name is stored in out. If failure, then out becomes
// an empty string "". // an empty string "".
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int x64) void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int altview)
{ {
HKEY hKey; HKEY hKey;
const REGSAM wowsam = altview ? (sizeof(void*) > 4 ? KEY_WOW64_32KEY : KEY_WOW64_64KEY) : 0;
*out=0; *out=0;
if (RegOpenKeyEx(root,sub,0,KEY_READ|(x64?KEY_WOW64_64KEY:0),&hKey) == ERROR_SUCCESS) if (RegOpenKeyEx(root,sub,0,KEY_READ|wowsam,&hKey) == ERROR_SUCCESS)
{ {
DWORD l = NSIS_MAX_STRLEN*sizeof(TCHAR); DWORD l = NSIS_MAX_STRLEN*sizeof(TCHAR), t;
DWORD t;
// Note that RegQueryValueEx returns Unicode strings if _UNICODE is defined for the // Note that RegQueryValueEx returns Unicode strings if _UNICODE is defined for the
// REG_SZ type. // REG_SZ type.
if (RegQueryValueEx(hKey,name,NULL,&t,(LPBYTE)out,&l ) != ERROR_SUCCESS || (t != REG_SZ && t != REG_EXPAND_SZ)) *out=0; if (RegQueryValueEx(hKey,name,NULL,&t,(LPBYTE)out,&l ) != ERROR_SUCCESS || (t != REG_SZ && t != REG_EXPAND_SZ)) *out=0;

View file

@ -32,7 +32,7 @@ TCHAR * NSISCALL GetNSISString(TCHAR *outbuf, int strtab);
// use the LANG_STR_TAB() macro to decode it. // use the LANG_STR_TAB() macro to decode it.
#define GetNSISTab(strtab) (strtab < 0 ? LANG_STR_TAB(strtab) : strtab) #define GetNSISTab(strtab) (strtab < 0 ? LANG_STR_TAB(strtab) : strtab)
void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int x64); void NSISCALL myRegGetStr(HKEY root, const TCHAR *sub, const TCHAR *name, TCHAR *out, int altview);
#define myatoi(s) ( (int)strtoiptr(s) ) #define myatoi(s) ( (int)strtoiptr(s) )
INT_PTR NSISCALL strtoiptr(const TCHAR *s); INT_PTR NSISCALL strtoiptr(const TCHAR *s);
#define myitoa iptrtostr #define myitoa iptrtostr

View file

@ -4023,15 +4023,12 @@ int CEXEBuild::doCommand(int which_token, LineParser &line)
{ {
ent.which=EW_SETFLAG; ent.which=EW_SETFLAG;
ent.offsets[0]=FLAG_OFFSET(alter_reg_view); ent.offsets[0]=FLAG_OFFSET(alter_reg_view);
// "64" results in setting the flag to 1 which alters the view int k=line.gettoken_enum(1,_T("32\0") _T("64\0default\0lastused\0")); // TODO: Can we support "native" without OS sniffing? Must verify on 9x, NT4 and 2000!
int k=line.gettoken_enum(1,_T("32\0") _T("64\0lastused\0"));
if (k<0) PRINTHELP() if (k<0) PRINTHELP()
if (k == 0) // 32 if (k == 0) ent.offsets[1]=add_intstring(is_target_64bit() ? KEY_WOW64_32KEY : 0); // 32
ent.offsets[1]=add_intstring(0); else if (k == 1) ent.offsets[1]=add_intstring(KEY_WOW64_64KEY); // 64
else if (k == 1) // 64 else if (k == 2) ent.offsets[1]=add_intstring(0); // default
ent.offsets[1]=add_intstring(KEY_WOW64_64KEY); else if (k == 3) ent.offsets[2]=1; // last used
else if (k == 2) // last used
ent.offsets[2]=1;
SCRIPT_MSG(_T("SetRegView: %") NPRIs _T("\n"),line.gettoken_str(1)); SCRIPT_MSG(_T("SetRegView: %") NPRIs _T("\n"),line.gettoken_str(1));
} }
return add_entry(&ent); return add_entry(&ent);

View file

@ -203,7 +203,7 @@ static tokenType tokenlist[TOK__LAST] =
{TOK_SETOVERWRITE,_T("SetOverwrite"),1,0,_T("on|off|try|ifnewer|ifdiff"),TP_ALL}, {TOK_SETOVERWRITE,_T("SetOverwrite"),1,0,_T("on|off|try|ifnewer|ifdiff"),TP_ALL},
{TOK_SETPLUGINUNLOAD,_T("SetPluginUnload"),1,0,_T("deprecated - plug-ins should handle this on their own"),TP_ALL}, {TOK_SETPLUGINUNLOAD,_T("SetPluginUnload"),1,0,_T("deprecated - plug-ins should handle this on their own"),TP_ALL},
{TOK_SETREBOOTFLAG,_T("SetRebootFlag"),1,0,_T("true|false"),TP_CODE}, {TOK_SETREBOOTFLAG,_T("SetRebootFlag"),1,0,_T("true|false"),TP_CODE},
{TOK_SETREGVIEW,_T("SetRegView"),1,0,_T("32|64|lastused"),TP_CODE}, {TOK_SETREGVIEW,_T("SetRegView"),1,0,_T("32|64|default|lastused"),TP_CODE},
{TOK_SETSHELLVARCONTEXT,_T("SetShellVarContext"),1,0,_T("all|current"),TP_CODE}, {TOK_SETSHELLVARCONTEXT,_T("SetShellVarContext"),1,0,_T("all|current"),TP_CODE},
{TOK_SETSILENT,_T("SetSilent"),1,0,_T("silent|normal"),TP_CODE}, {TOK_SETSILENT,_T("SetSilent"),1,0,_T("silent|normal"),TP_CODE},
{TOK_SHOWDETAILS,_T("ShowInstDetails"),1,0,_T("(hide|show|nevershow)"),TP_GLOBAL}, {TOK_SHOWDETAILS,_T("ShowInstDetails"),1,0,_T("(hide|show|nevershow)"),TP_GLOBAL},