根据 lindexi 的建议,可以用如下更优的方案:
根据 C 厂的长期实践经验,最佳做法是写一个 UpdateFix 类似的程序集,
然后通过命令行参数调用起来,靠 C# 代码编写逻辑处理防火墙。
一方面可以实现较高控制,避免各种脚本的奇异表现和让杀毒软件开森,
另一方面可以比较方便编写代码进行调试以及在后续 OTA 时执行统一的行为
在 Windows 上运行需要访问网络或者提供网络服务的程序,需要防火墙放行。默认情况下,在首次运行程序时,可能会有如下弹窗,只有用户点击运行才能继续使用网络。部分情况,可能是直接被拦截,都没有这个提示。
Windows 防火墙规则 | Microsoft Learn
如果出现问题,手动处理的话,可以在 Windows 防火墙的高级设置中,添加入站或出站规则,或者配置 “允许应用或功能通过 Windows Defender 防火墙”。
这里介绍的是,如果在应用安装时(使用 NSIS 打包),自动添加防火墙规则,避免上述问题。
基本思路是使用 netsh advfirewall
命令来进行防火墙规则的添加,
添加规则命令参考:
Terminal window
netsh advfirewall firewall add rule name="ruleName" program="C:\Program Files\7-Zip\7z.exe" action=allow dir=in enable=yes
移除规则命令参考(卸载时调用):
Terminal window
netsh advfirewall firewall delete rule name="ruleName"
关于 netsh advfirewall 的更多资料
Use netsh advfirewall firewall context - Windows Server | Microsoft Learn
在 NSIS 脚本中,可以通过 ExecWait 直接执行命令,参考如下
#define FIREWALL_NAME "my dicom viewer"
Function .onInstSuccess ExecWait 'netsh advfirewall firewall add rule name="${FIREWALL_NAME}" program="$INSTDIR\DicomViewer.exe" dir=in action=allow' ExecWait 'netsh advfirewall firewall add rule name="${FIREWALL_NAME}" program="$INSTDIR\DicomViewer.exe" dir=out action=allow'FunctionEnd
Function un.onUninstSuccess ExecWait 'netsh advfirewall firewall delete rule name="${FIREWALL_NAME}"' HideWindow MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) 已成功地从您的计算机移除"FunctionEnd
上述写法能成功执行,但是有个问题,在执行时,会打开 CMD 命令行窗口。看起来的效果就是会有黑框框一闪而过,如果是内部使用的工程板软件,勉强可以接受,如果是面向用户的软件,这个问题还需要进一步处理。
这里使用的方式是,在 NSIS 中,调用 vbs 脚本,可以做到没有命令行窗口。
添加规则的脚本如下
Dim arg1arg1 = WScript.Arguments(0)
Dim shellSet shell = CreateObject("WScript.Shell")
Dim ruleNameruleName = "my dicom viewer"
Dim command1command1 = "netsh advfirewall firewall add rule name=""" & ruleName & """ program=""" & arg1 & """ action=allow dir=in enable=yes"Dim command2command2 = "netsh advfirewall firewall add rule name=""" & ruleName & """ program=""" & arg1 & """ action=allow dir=out enable=yes"
shell.Run command1, 0, True ' 0 表示静默,True 表示等待命令执行完成shell.Run command2, 0, True
删除规则的脚本如下
Dim shellSet shell = CreateObject("WScript.Shell")
Dim ruleNameruleName = "my dicom viewer"
Dim command1command1 = "netsh advfirewall firewall delete rule name=""" & ruleName & """ "
shell.Run command1, 0, True ' 0 表示静默,True 表示等待命令执行完成
因为要在安装或者卸载时调用,所以这个文件要被放到安装包中。
Section "MainSection" SEC01 SetOutPath "$INSTDIR" SetOverwrite ifnewer File "Script\after-install.vbs" File "Script\after-uninstall.vbs"SectionEnd
在安装成功之后调用
; 安装成功之后调用Function .onInstSuccess ExecWait '"wscript.exe" "$INSTDIR\after-install.vbs" "$INSTDIR\DicomViewer.exe"'FunctionEnd
在卸载删除全部文件之前调用。因为这里是调用安装目录下的文件,所以不能放在 Function un.onUninstSuccess 中处理,因为那时候,文件都已经被删除了,无法被调用。
Section Uninstall Delete "$INSTDIR\uninst.exe" Delete "$INSTDIR\DicomViewer.exe"
ExecWait '"wscript.exe" "$INSTDIR\after-uninstall.vbs" ' Delete "$INSTDIR\*.*" RMDir /r "$INSTDIR"SectionEnd
netsh advfirewall 命令操作,需要管理员权限。通常安装程序会以管理员身份运行,如果不是,则需要注意这个问题。
原文链接: https://cloud.tencent.com/developer/article/2481579
本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。