Sometimes we need determine if a particular windows hotfix or update is installed in the system. to do this task you can use two approaches
WMI (Windows Management Instrumentation)
using the Win32_QuickFixEngineering class, you can retrieve a small system-wide update, commonly referred to as a quick-fix engineering (QFE) update.
check this code which list the updates installed in the system
procedure GetWin32_QuickFixEngineeringInfo; const wbemFlagForwardOnly = $00000020; var FSWbemLocator : OLEVariant; FWMIService : OLEVariant; FWbemObjectSet: OLEVariant; FWbemObject : OLEVariant; oEnum : IEnumvariant; iValue : LongWord; begin; FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', ''); FWbemObjectSet:= FWMIService.ExecQuery('SELECT * FROM Win32_QuickFixEngineering','WQL',wbemFlagForwardOnly); oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant; while oEnum.Next(1, FWbemObject, iValue) = 0 do begin Writeln(Format('Caption %s',[FWbemObject.Caption]));// String //Writeln(Format('CSName %s',[FWbemObject.CSName]));// String Writeln(Format('Description %s',[FWbemObject.Description]));// String Writeln(Format('FixComments %s',[FWbemObject.FixComments]));// String Writeln(Format('HotFixID %s',[FWbemObject.HotFixID]));// String Writeln(Format('InstallDate %s',[FWbemObject.InstallDate]));// Datetime Writeln(Format('InstalledBy %s',[FWbemObject.InstalledBy]));// String Writeln(Format('InstalledOn %s',[FWbemObject.InstalledOn]));// String Writeln(Format('Name %s',[FWbemObject.Name]));// String Writeln(Format('ServicePackInEffect %s',[FWbemObject.ServicePackInEffect]));// String Writeln(Format('Status %s',[FWbemObject.Status]));// String Writeln(''); FWbemObject:=Unassigned; end; end;
Now to find if a particular update is installed you can check the HotFixID property value (which is the Unique identifier associated with a particular update) and write a function like this
//use in this way ISHotFixID_Installed('KB982799') function ISHotFixID_Installed(const HotFixID : string): Boolean; const wbemFlagForwardOnly = $00000020; wbemFlagReturnImmediately = $00000010; var FSWbemLocator : OLEVariant; FWMIService : OLEVariant; FWbemObjectSet: OLEVariant; FWbemObject : OLEVariant; oEnum : IEnumvariant; iValue : LongWord; begin; FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); FWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', ''); FWbemObjectSet:= FWMIService.ExecQuery(Format('SELECT * FROM Win32_QuickFixEngineering Where HotFixID="%s"',[HotFixID]),'WQL',wbemFlagForwardOnly OR wbemFlagReturnImmediately); oEnum := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant; Result:= oEnum.Next(1, FWbemObject, iValue) = 0; end;
Ok this is fine, but Starting with Windows Vista, the Win32_QuickFixEngineering class returns only the updates supplied by Component Based Servicing (CBS), so some updates are not listed.
WUA (Windows Update Agent)
using the Windows Update Agent API is a best option to retrieve the list of updates, you can access the interfaces and objects from this API from delphi importing the wuapi.dll file or creating a late-binding com object using the Microsoft.Update.Session GUID. the next samples uses the late-binding way.
from the MSDN site :
The Windows Update Agent (WUA) API is a set of COM interfaces that enable system administrators and programmers to access Windows Update and Windows Server Update Services (WSUS). Scripts and programs can be written to examine which updates are currently available for a computer, and then you can install or uninstall updates.
to implement a search of the installed updates we need to use the IUpdateSearcher Interface using the Search method setting the search criteria.
check this sample
//create the Com object instance updateSession:= CreateOleObject('Microsoft.Update.Session'); updateSearcher := updateSession.CreateUpdateSearcher; //set the search criteria, installed =1 means updates that are installed on the destination computer, Type='Software' retrieve only applications updates updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 1 and Type=%s',[QuotedStr('Software')]));
Now to find if a particular update is installed you can parse the Title property of the IUpdate Interface which contains the name of the update like this Security Update for Windows 7 for x64-based Systems (KB978542)
//use in this way ISHotFixID_Installed('KB982799') function ISHotFixID_Installed(const HotFixID : string): Boolean; var updateSession : OleVariant; updateSearcher : OleVariant; updateEntry : OleVariant; updateSearchResult : OleVariant; UpdateCollection : OleVariant; oEnum : IEnumvariant; iValue : LongWord; begin result:=False; updateSession:= CreateOleObject('Microsoft.Update.Session'); updateSearcher := updateSession.CreateUpdateSearcher; //this line improves the performance , the online porperty indicates whether the UpdateSearcher goes online to search for updates. so how we are looking for already installed updates we can set this value to false updateSearcher.online:=False; updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 1 and Type=%s',[QuotedStr('Software')])); UpdateCollection := updateSearchResult.Updates; oEnum := IUnknown(UpdateCollection._NewEnum) as IEnumVariant; while oEnum.Next(1, updateEntry, iValue) = 0 do begin Result:=Pos(HotFixID,updateEntry.Title)>0; updateEntry:=Unassigned; if Result then break; end; end;
check these another useful functions
Getting the installed updates list
procedure GetListInstalledUpdates; var updateSession : OleVariant; updateSearcher : OleVariant; updateSearchResult : OleVariant; updateEntry : OleVariant; UpdateCollection : OleVariant; oEnum : IEnumvariant; iValue : LongWord; begin updateSession:= CreateOleObject('Microsoft.Update.Session'); updateSearcher := updateSession.CreateUpdateSearcher; Writeln('Searching'); //IUpdateSearcher::Search Method http://msdn.microsoft.com/en-us/library/aa386526%28v=VS.85%29.aspx updateSearcher.online:=False; updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 1 and Type=%s',[QuotedStr('Software')])); UpdateCollection := updateSearchResult.Updates; oEnum := IUnknown(UpdateCollection._NewEnum) as IEnumVariant; //IUpdate Interface http://msdn.microsoft.com/en-us/library/aa386099%28v=VS.85%29.aspx while oEnum.Next(1, updateEntry, iValue) = 0 do begin Writeln(updateEntry.Title); updateEntry:=Unassigned; end; Writeln('Done'); end;
Getting the not installed updates list (slow because need to check online)
procedure GetListNotInstalledUpdates; var updateSession : OleVariant; updateSearcher : OleVariant; updateSearchResult : OleVariant; updateEntry : OleVariant; UpdateCollection : OleVariant; oEnum : IEnumvariant; iValue : LongWord; begin updateSession:= CreateOleObject('Microsoft.Update.Session'); updateSearcher := updateSession.CreateUpdateSearcher; Writeln('Searching'); updateSearchResult:= updateSearcher.Search(Format('IsInstalled = 0 and Type=%s',[QuotedStr('Software')])); UpdateCollection := updateSearchResult.Updates; oEnum := IUnknown(UpdateCollection._NewEnum) as IEnumVariant; while oEnum.Next(1, updateEntry, iValue) = 0 do begin Writeln(updateEntry.Title); updateEntry:=Unassigned; end; Writeln('Done'); end;
Getting the hidden installed updates list
procedure GetListInstalledHiddenUpdates; var updateSession : OleVariant; updateSearcher : OleVariant; updateSearchResult : OleVariant; updateEntry : OleVariant; UpdateCollection : OleVariant; oEnum : IEnumvariant; iValue : LongWord; begin updateSession:= CreateOleObject('Microsoft.Update.Session'); updateSearcher := updateSession.CreateUpdateSearcher; Writeln('Searching'); updateSearcher.online:=False; updateSearchResult:= updateSearcher.Search(Format('IsHidden=1 and IsInstalled = 1 and Type=%s',[QuotedStr('Software')])); UpdateCollection := updateSearchResult.Updates; oEnum := IUnknown(UpdateCollection._NewEnum) as IEnumVariant; while oEnum.Next(1, updateEntry, iValue) = 0 do begin Writeln(updateEntry.Title); updateEntry:=Unassigned; end; Writeln('Done'); end;