在Innosetup打包软件的程序时安装时遇到SWbemObjectSet:无效查询的问题怎么解决?
目录
首先此问题是出在Innosetup一个公有的作为安装程序都会使用的一个判断程序是否正在运行的函数,目前个人可以明白发生的原因但是没有很完美的解决方案,大家如果有更好的方案也可以一起分享!
function IsAppRunning(const FileName : string): Boolean;
var
FSWbemLocator: Variant;
FWMIService : Variant;
FWbemObjectSet: Variant;
begin
Result := false;
FSWbemLocator := CreateOleObject('WBEMScripting.SWBEMLocator');
FWMIService := FSWbemLocator.ConnectServer('', 'root\CIMV2', '', '');
FWbemObjectSet := FWMIService.ExecQuery(Format('SELECT Name FR2OM Win32_Process Where Name="%s"',[FileName]));
Result := (FWbemObjectSet.Count > 0);
FWbemObjectSet := Unassigned;
FWMIService := Unassigned;
FSWbemLocator := Unassigned;
end;
利用这个函数可以在输入进程名的同时查询到windows是否正在运行此程序,但是在查询过程中会在ExecQuery函数时发送问题所以导致此问题的发生。
发生原因:
首先这个函数的撰写是基于微软的WMI的COM API来实现的,调用的都是微软底层的接口,在ExecQuery函数执行后,根据微软的文档,会返回一个Swbemobjectset
对象(Swbemobject对象的集合),但是如果用户此时电脑里WMI服务发生错误,执行WQL查询失败时,会返回一个Err的错误
而此时调用Count函数列举set的数量时就会报错
个人的解决方案:
首先我的方法其实也不算解决,目前个人是在安装时写入程序注册表,如果检测到已经安装过则可能开启软件,此时要检测软件是否正在运行,而如果是首次安装,就不进行检测防止用户无法安装。
理想的解决方案(未实现)
根据微软的官方文档,查询返回空结果集不是错误。无论strQuery参数中是否请求了键属性,ExecQuery 方法都会返回键属性。如果在执行此方法时发生错误并且您不使用wbemFlagReturnImmediately标志,则在您尝试访问返回的对象集之前不会设置Err对象。但是,如果您使用wbemFlagReturnWhenComplete标志,则会在调用ExecQuery方法时设置 Err 对象。
但是Pascal脚本似乎不支持这样的方法,没有办法让他检测Err对象并抛出异常,但是这种错误发生还是少数,只有当WMI服务发生问题或根本没有提供这种服务的情况下才会出现,如果有更好的解决方法也欢迎大家在底下评论留言。