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;