NSIS安装程序运行时提示环境变量为空的问题求助
NSIS安装程序读取环境变量失败的问题
尝试用NSIS制作安装程序时,运行时读取环境变量多次失败,以下是尝试的方法及结果:
1. 使用ReadEnvStr方法
创建basic.nsi脚本:
!include "LogicLib.nsh" Outfile "TestInstaller.exe" Name "Test Installer" InstallDir $DESKTOP\MyApp Section "Install" ReadEnvStr $R0 "MY_VAR" ${If} $R0 == "" MessageBox MB_OK "MY_VAR is not set or is empty" ${Else} MessageBox MB_OK "MY_VAR value: $R0" ${EndIf} SectionEnd
在PowerShell中执行:
> makensis basic.nsi > set MY_VAR=1 > ./TestInstaller.exe
运行后提示MY_VAR is not set or is empty。
2. 使用系统调用GetEnvironmentVariableA
编写NSIS脚本:
Outfile "TestInstaller.exe" Name "Test Installer" InstallDir $DESKTOP\MyApp Section "Install" System::Call 'kernel32::GetEnvironmentVariableA(t "MY_VAR", t .R0, i ${NSIS_MAX_STRLEN}) i .r1' IntCmp $R1 0 env_not_found env_found env_not_found: MessageBox MB_OK "MK_UPDATE_INSTALLER is not set or is empty" Goto end env_found: MessageBox MB_OK "MK_UPDATE_INSTALLER value: $R0" end: SectionEnd
运行后仍提示环境变量未设置或为空。
3. 遍历所有环境变量
编写遍历脚本:
Outfile "PrintEnvVarsInstaller.exe" Name "Print Env Vars Installer" InstallDir $DESKTOP\MyApp Section "Install" ; Get a pointer to the environment block System::Call 'kernel32::GetEnvironmentStringsA() p .r0' ; Initialize a pointer variable to iterate over the environment block StrCpy $R1 $R0 loop: ; Get the current string pointed to by $R1 System::Call '*$R1(&t0 .R2)' ; Check if we reached the end of the environment block (null string) StrCmp $R2 "" done ; Display the current environment variable MessageBox MB_OK "$R2" ; Move the pointer to the next string (environment variable) System::Call 'kernel32::lstrlenA(t $R2) i .r3' IntOp $R1 $R1 + $R3 IntOp $R1 $R1 + 1 ; Repeat the loop Goto loop done: ; Free the environment strings block System::Call 'kernel32::FreeEnvironmentStringsA(p $R0) i .r1' MessageBox MB_OK "done" SectionEnd
运行后直接弹出done,未检测到任何环境变量。
注意:使用Python的os.getenv和PowerShell的Write-Host "MY_VAR is set to: $env:MY_VAR"均可正常读取该环境变量。
问题原因与解决方法
核心原因
NSIS默认以管理员权限运行安装程序时,会触发Windows的UAC虚拟化机制,导致程序运行在不同的环境上下文,无法继承当前普通用户PowerShell会话中的环境变量。
解决方法
方法1:禁用UAC虚拟化(推荐)
在NSIS脚本中添加UAC相关配置,明确指定不使用虚拟化,并确保安装程序以当前用户权限运行(如果不需要管理员权限):
!include "LogicLib.nsh" !include "UAC.nsh" Outfile "TestInstaller.exe" Name "Test Installer" InstallDir $DESKTOP\MyApp ; 禁用UAC虚拟化,确保环境变量继承 RequestExecutionLevel user ; 以当前用户权限运行,不提升 SetShellVarContext all Section "Install" ReadEnvStr $R0 "MY_VAR" ${If} $R0 == "" MessageBox MB_OK "MY_VAR is not set or is empty" ${Else} MessageBox MB_OK "MY_VAR value: $R0" ${EndIf} SectionEnd
方法2:如果必须以管理员权限运行
若安装程序需要管理员权限,可通过以下方式传递环境变量:
- 在PowerShell中设置用户级环境变量并刷新:
[Environment]::SetEnvironmentVariable("MY_VAR", "1", "User") # 重启PowerShell后运行安装程序,管理员进程可读取用户级环境变量
- 或者在启动安装程序时直接传递参数:
修改NSIS脚本接收命令行参数:
!include "LogicLib.nsh" Outfile "TestInstaller.exe" Name "Test Installer" InstallDir $DESKTOP\MyApp Section "Install" ; 读取命令行参数中的MY_VAR值 ${GetParameters} $R0 StrCpy $R1 "" ${GetOptions} $R0 "/MY_VAR=" $R1 ${If} $R1 == "" MessageBox MB_OK "MY_VAR is not provided" ${Else} MessageBox MB_OK "MY_VAR value: $R1" ${EndIf} SectionEnd
然后在PowerShell中运行:
> ./TestInstaller.exe /MY_VAR=1
方法3:修复遍历环境变量的脚本
原遍历脚本中System::Call '*$R1(&t0 .R2)'的写法有误,正确的读取内存中字符串的方式如下:
Outfile "PrintEnvVarsInstaller.exe" Name "Print Env Vars Installer" InstallDir $DESKTOP\MyApp Section "Install" System::Call 'kernel32::GetEnvironmentStringsA() p .r0' StrCpy $R1 $R0 loop: ; 正确读取内存中的C字符串 System::Call 'kernel32::lstrcpynA(t .R2, p $R1, i ${NSIS_MAX_STRLEN})' StrCmp $R2 "" done MessageBox MB_OK "$R2" ; 计算下一个字符串的指针 System::Call 'kernel32::lstrlenA(p $R1) i .r3' IntOp $R1 $R1 + $R3 IntOp $R1 $R1 + 1 Goto loop done: System::Call 'kernel32::FreeEnvironmentStringsA(p $R0) i .r1' MessageBox MB_OK "done" SectionEnd
内容的提问来源于stack exchange,提问作者user236529
相关产品推荐
相关产品推荐

