You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Electron-builder:以管理员身份安装时指向当前用户LocalAppdata的方案

问题:管理员身份运行安装程序时,Electron应用安装到错误的LocalAppData目录

我开发了一个Electron应用,计划将其安装到当前用户的$LocalAppData目录下,当前Electron-builder的NSIS配置如下:

"nsis": {
    "oneClick": true,
    "perMachine": false,
    "createDesktopShortcut": true,
    "createStartMenuShortcut": true,
    "runAfterFinish": false,
    "include": "installer.nsh"
}

配套的installer.nsh内容为:

!macro preInit
  SetRegView 64
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$LocalAppdata\Programs\My App"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$LocalAppdata\Programs\My App"
 SetRegView 32
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$LocalAppdata\Programs\My App"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$LocalAppdata\Programs\My App"
!macroend

遇到的问题:

  • 普通用户或管理员直接运行安装程序时,应用能正常安装到$LocalAppdata\Programs\My App目录;
  • 但普通用户右键选择「以管理员身份运行」安装程序时,应用会被安装到管理员账户的$LocalAppdata目录,而非当前用户的目录。尝试将$LocalAppdata替换为$PROFILE也无法解决。

请问能否通过.nsh脚本实现将应用安装到当前用户的$LocalAppdata目录?


解决方案

问题根源在于:当以管理员身份运行安装程序时,进程运行在管理员的安全上下文下,此时环境变量$LocalAppData指向的是管理员账户的目录,而非发起操作的普通用户目录。要解决这个问题,需要在NSIS脚本中获取当前交互式登录用户的LocalAppData路径,而非运行进程的用户路径。

以下提供两种可靠的实现方式:

方式1:使用Windows API获取已知文件夹路径(推荐)

替换installer.nsh中的preInit宏为以下代码:

!macro preInit
  Var CurrentUserLocalAppData
  ; 调用SHGetKnownFolderPath获取当前用户的LocalAppData目录(FOLDERID_LocalAppData)
  System::Call 'shell32.dll::SHGetKnownFolderPath(g "{F1B32785-6FBA-4FCF-9D55-7B8E7F157091}", i 0, i 0, *p.r0)'
  ; 转换宽字符到多字节字符串
  System::Call 'user32.dll::MultiByteToWideChar(i 0, i 0, t r0, i -1, *t.r1, i 0)'
  StrCpy $CurrentUserLocalAppData $r1
  System::Free $r0

  ; 设置安装目录为当前用户的LocalAppData下的目标路径
  StrCpy $INSTDIR "$CurrentUserLocalAppData\Programs\My App"

  ; 写入注册表记录安装路径
  SetRegView 64
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
  SetRegView 32
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
!macroend

方式2:通过注册表读取当前用户SID获取路径

如果系统兼容性要求更高,可以通过读取当前用户的SID来获取Profile路径,再拼接LocalAppData:

!macro preInit
  Var CurrentUserLocalAppData
  Var UserSID

  ; 获取当前进程令牌并读取SID
  System::Call 'advapi32.dll::OpenProcessToken(i -1, i 0x0008, *i.r0)'
  System::Call 'advapi32.dll::GetTokenInformation(i r0, i 1, *i.r1, i 4, *i.r2)'
  System::Call 'advapi32.dll::ConvertSidToStringSidA(i r1, *t.r2)'
  StrCpy $UserSID $r2
  System::Free r1
  System::Call 'advapi32.dll::CloseHandle(i r0)'

  ; 从当前用户的注册表项读取LocalAppData
  ReadRegStr $CurrentUserLocalAppData HKU "${UserSID}\Environment" LocalAppData
  ; 如果读取失败,从Profile路径拼接LocalAppData
  ${If} $CurrentUserLocalAppData == ""
    ReadRegStr $CurrentUserLocalAppData HKU "${UserSID}" "ProfileImagePath"
    StrCpy $CurrentUserLocalAppData "$CurrentUserLocalAppData\AppData\Local"
  ${EndIf}

  ; 设置安装目录
  StrCpy $INSTDIR "$CurrentUserLocalAppData\Programs\My App"

  ; 写入注册表
  SetRegView 64
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
  SetRegView 32
    WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
    WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$INSTDIR"
!macroend

内容的提问来源于stack exchange,提问作者Algorys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 06:32:13