我的 NSIS 脚本的卸载没有从 ProgramData 目录中删除链接

Posted

技术标签:

【中文标题】我的 NSIS 脚本的卸载没有从 ProgramData 目录中删除链接【英文标题】:My NSIS script's Uninstall isn't deleting links from ProgramData directory 【发布时间】:2011-10-24 11:47:10 【问题描述】:

有另一个新手 NSIS 问题。这是脚本:

; -*-nsis-*-    
Name "ndhtest"
OutFile "FooStartMenuTest.exe"    
XPStyle on
!define FOO_SRC c:\users\nhughes\foo

InstallDir "$PROGRAMFILES\Initech\"
Icon $FOO_SRC\foo_logo.ico
UninstallIcon $FOO_SRC\uninstall.ico

Page instfiles
UninstPage uninstConfirm
UninstPage instfiles

Section
  SetOutPath $INSTDIR
  File $FOO_SRC\foo.bat
  WriteUninstaller "$INSTDIR\uninstall.exe"
  CreateDirectory $SMPROGRAMS\Initech
  CreateShortCut $SMPROGRAMS\Initech\Foo.lnk $INSTDIR\foo.bat "" \
    "$FOO_SRC\foo_logo.ico"
  CreateShortCut $SMPROGRAMS\Initech\Uninstall.lnk $INSTDIR\uninstall.exe "" \
    "$FOO_SRC\uninstall.ico"
SectionEnd

Section "Uninstall"
  Delete $SMPROGRAMS\Initech\Foo.lnk
  Delete $SMPROGRAMS\Initech\Uninstall.lnk
  RMDir $SMPROGRAMS\Initech
  Delete $INSTDIR\Foo.bat
  Delete $INSTDIR\uninstall.exe
  RMDir $INSTDIR
SectionEnd

除了将快捷方式留在 ProgramData 下之外,卸载似乎有效:

 Directory of c:\ProgramData\Microsoft\Windows\Start Menu\Programs\Initech

08/10/2011  04:07 PM    <DIR>          .
08/10/2011  04:07 PM    <DIR>          ..
08/10/2011  04:23 PM             1,847 Foo.lnk
08/10/2011  04:23 PM             1,885 Uninstall.lnk
               2 File(s)          3,732 bytes
               2 Dir(s)  1,387,345,117,184 bytes free

我的脚本出了什么问题,导致这些东西到处乱跑?

这是卸载程序写入其控制台的内容(我添加了一条列出 $SMPROGRAMS 的 DetailPrint 消息):

smprograms=C:\Users\nhughes\AppData\Roaming\Microsoft\Windows\Start Menu\Programs
Remove folder: C:\Users\nhughes\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Initech\
Delete file: C:\Program Files (x86)\Initech\foo.bat
Delete file: C:\Program Files (x86)\Initech\uninstall.exe
Remove folder: C:\Program Files (x86)\Initech\
Completed

所以 ProgramData 下的链接永远不会被引用,它正在寻找 AppData\Roaming 下的链接。

我正在 Windows 7 上对此进行测试,但这里的核心问题是我希望能够编写一个适用于从 XP 到 Windows 7 的所有内容的脚本,而不管 Windows 如何将内容隐藏在不同版本的不同点。这看起来可能很痛苦。

【问题讨论】:

这是在什么操作系统上发生的?经验?远景? Windows 7? 【参考方案1】:

来自规范:

4.9.1.8 RMDir

[/r] [/REBOOTOK] directory_name

Remove the specified directory (fully qualified path with no wildcards). Without /r, the directory will only be removed if it is completely empty. If /r is specified, the directory will be removed recursively, so all directories and files in the specified directory will be removed. If /REBOOTOK is specified, any file or directory which could not have been removed during the process will be removed on reboot -- if any file or directory will be removed on a reboot, the reboot flag will be set. The error flag is set if any file or directory cannot be removed.

尝试将/r 添加到 RMDir 行以强制它刷新内容。要么单独删除链接。

【讨论】:

他删除了他创建的所有文件,因此不需要 /r 开关。问题是目录被映射并且快捷方式是在不同的地方创建的。使用RMDir /r时请务必小心。它应该是经过深思熟虑的,而不是鲁莽地应用。【参考方案2】:

如果将DetailPrint 添加到 nsis 脚本中,则 NSIS 会尝试在 C:\Users 下创建文件,但它们实际上是在 c:\ProgramData 中创建的。这个ProgramData 目录很奇怪,因为dir C:\ 看不到它,但是cd 可以进入目录。这些谜团是由 Virtual Store 造成的,这是 Windows 7 的一项棘手功能。

现在来解决问题。 Windows 应用程序应定义其执行级别,否则系统可能会以意想不到的方式运行。您还记得一些应用程序询问是否安装“仅适用于当前用户”或“适用于所有用户”?这就是我们需要声明的东西。

如果我们插入 nsis 指令RequestExecutionLevel user,则为当前用户创建快捷方式。如果我们使用RequestExecutionLevel admin,那么我们还应该在安装和卸载部分添加SetShellVarContext all

此答案基于 nsis wiki 中的文章:Shortcuts removal fails on Windows Vista,其中提供了两种方法的示例。

【讨论】:

以上是关于我的 NSIS 脚本的卸载没有从 ProgramData 目录中删除链接的主要内容,如果未能解决你的问题,请参考以下文章

NSIS 卸载程序工作目录

向 NSIS 卸载程序欢迎页面添加复选框

NSIS 卸载程序不删除目录

为啥安装游戏出现nsis错误?

NSIS 打包脚本基础

NSIS根据安装文件log 卸载文件(防止误删)