我正在使用 NSIS 为需要在 NTFS 卷上运行的程序创建安装程序。如何检测安装到路径是否在 NTFS 卷上并采取相应措施(显示帮助/警告消息)?
3 回答
使用外部工具并不总是一个好主意(并非每个命令行工具都存在于 Windows 的家庭版本中)最好直接使用系统插件调用正确的 API。
!include LogicLib.nsh
StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i,t.r1,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
MessageBox mb_ok "fs=$1"
${EndIf}
但在这种情况下,您不应该检查文件系统类型,而应该寻找您需要的实际功能(压缩、加密、连接、稀疏文件等)
!define FILE_SUPPORTS_ENCRYPTION 0x00020000
!define FILE_READ_ONLY_VOLUME 0x00080000
!define FILE_VOLUME_QUOTAS 0x00000020
!macro MakeBitFlagYesNo flags bit outvar
IntOp ${outvar} ${flags} & ${bit}
${IfThen} ${outvar} <> 0 ${|} StrCpy ${outvar} "Yes" ${|}
${IfThen} ${outvar} == 0 ${|} StrCpy ${outvar} "No" ${|}
!macroend
StrCpy $0 "c:\"
System::Call 'Kernel32::GetVolumeInformation(t "$0",t,i ${NSIS_MAX_STRLEN},*i,*i,*i.r1,t,i ${NSIS_MAX_STRLEN})i.r0'
${If} $0 <> 0
!insertmacro MakeBitFlagYesNo $1 ${FILE_SUPPORTS_ENCRYPTION} $2
!insertmacro MakeBitFlagYesNo $1 ${FILE_READ_ONLY_VOLUME} $3
!insertmacro MakeBitFlagYesNo $1 ${FILE_VOLUME_QUOTAS} $4
MessageBox mb_ok "flags=$1 $\nFILE_SUPPORTS_ENCRYPTION=$2$\nFILE_READ_ONLY_VOLUME=$3$\nFILE_VOLUME_QUOTAS=$4"
${EndIf}
我对 NSIS 不熟悉,但您可能会发现这个“DOS”小技巧很有帮助。
我确实注意到可以使用 NSIS 打开文件,所以这可能会有所帮助——
chkntfs c: | find "file system" > yourfile.abc
CHKNTFS 是用于管理 CHKDSK 操作的实用程序,但如果您在没有命令行开关的情况下运行该命令,它只会报告结果。
“C:”是你感兴趣的驱动器——
您可以从命令提示符运行它来查看结果,当然,没有"> yourfile.abc" 部分,这就是将输出定向到该文件的原因。
在任何人对此投反对票之前,我只是把它作为一个发人深省的建议提供,也许会引发真正的解决方案并记住这样的座右铭——善良......哈哈......
编辑:这个片段可能会有所帮助——我没有办法真正测试这个——这是编译时使用——你很可能想要运行时间......但是,它可能会给你一个想法......
我“假设”没有一个已经命名为 NTFS 的定义——如果是这样,请相应地更改它。第一次调用创建包含文件,第二次调用它(双 > )... FIND 的 /C 选项只是计算包含搜索项的数字行。因此,0 或 1 结果。
!system 'echo "!define NTFS=" > newinclude.nsh'
!system 'chkntfs c: | find /c "NTFS" >> newinclude.nsh'
!include newinclude.nsh
!ifdef NTFS
!echo "NTFS is defined and value should reflect accordingly; 0=NO, 1=Yes it is NTFS"
!endif
编辑:(再次,大声笑)
这是一个片段,它将设置一个 ENVIRONMENT 变量,据我所知,它在运行时应该很容易阅读——您可以构造一个要执行的变量,相应地替换驱动器号。
ExecWait 'chkntfs c: | find /c "NTFS" > tempfile.abc'
ExecWait 'set /p NTFS= < tempfile.abc'
Exec 'del tempfile.abc'
现在,如果不是 NTFS,则名为 NTFS 的环境变量应该保存为 0,如果正在检查的卷是 NTFS,则保存为 1。
或者直接
ExecWait 'chkntfs c: | find /c "NTFS"' $0
$0 保存返回码;结果有点倒退,因为这是错误返回码。如果 0 你有 NTFS 并且 > 0 意味着没有 NTFS。
您的测试需要在运行时进行,因此Borzio 的答案本身不会起作用。
看起来 ExecWait 命令也不允许重定向,因此以这种方式执行它然后检查文件的内容是行不通的。
在我看来,您最好的选择是选择以下之一:
- 制作一个运行 chkntfs 的批处理文件,然后根据结果设置错误级别
- 编写 C/C++/VB/等。将运行 chkntfs 然后根据结果设置错误级别的应用程序
- 编写 C/C++/VB/等。将使用 Win32 API 来确定文件系统的应用程序
- 为 NSIS 编写一个插件,该插件将使用 Win32 API 来确定文件系统
编辑: Borzio 在我完成之前更新了他的 :)
您可能需要添加我在 Winamp 论坛上找到的内容:ExecWait with file redirection
ExpandEnvStrings $1 %COMSPEC%
ExecWait '"$1" /C chkntfs c: | find /c "NTFS"' $0
没有ExpandEnvStrings $1 %COMSPEC%
,它无法在我的系统上生成重定向文件。
我已经测试了上述内容,它确实有效,NTFS 为 0,非 NTFS 为 1。
这种方法唯一可能的缺点是在代码执行期间会短暂弹出一个命令窗口。