2 February 2009

VB.Net - Enumerate the windows update history using the windows update api

Someone in the forum wanted to get the Description for each windows update, and WMI/the registry were no help. They were going to try to dig the information out of "C:\Windows\SoftwareDistribution\DataStore\DataStore.edb", which is undocumented. Some people say it is a Jet database, but I'm not sure. Exchange server uses that extension too.

Anyway the windows update api will do it. This pic shows the interfaces involved:


First you need to get an IUpdateSession. That has a CreateUpdateSearcher method to get an IUpdateSearcher. That has GetTotalHistoryCount to get the number of IUpdateHistoryEntry items inside the IUpdateHistoryCollection. To get the collection you call QueryHistory on the IUpdateSearcher, passing in the count from before. Each IUpdateHistoryEntry has a bunch of properties, some of which have custom types, but they are all simple to retrieve. To get your hands on the interfaces, the easiest way is to use tlbimp from the Visual studio command line (or the one with the platform sdk, or the one with the framework sdk). Copy the wuapi.dll file from .../Windows/System32 to some directory of your choice, navigate there and run...
tlbimp.exe wuapi.dll /out=WUApiInterop.dll

This creates managed signatures for all the COM interfaces in wuapi.dll and sticks them in WuApiInterop.dll. You can  then create a windows forms project, add a reference to WuApiInterop.dll and get your paws on all the interfaces. I made a .Net dll that has a friendly version of the IUpdateHistoryEntry object, and a method to return a collection of them. This is the code that gets the information.

    <SecurityPermission(SecurityAction.LinkDemand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Public Shared Function GetHistory() As ReadOnlyCollection(Of HistoryItem)
        Dim session As UpdateSession = Nothing
        Dim searcher As IUpdateSearcher = Nothing
            session = New UpdateSession
            If session Is Nothing Then Throw New InvalidOperationException("Couln't create an IUpdateSearcher.")
            searcher = session.CreateUpdateSearcher
            If session IsNot Nothing Then Marshal.ReleaseComObject(session)
        End Try
        If searcher Is Nothing Then Throw New InvalidOperationException("Couldn't create an IUpdateSession.")
        Dim count As Integer = searcher.GetTotalHistoryCount
        If count = 0 Then
            Return New ReadOnlyCollection(Of HistoryItem)(Nothing)
        End If
        Dim historyCollection As IUpdateHistoryEntryCollection = Nothing
            historyCollection = searcher.QueryHistory(0, count)
        End Try
        If historyCollection Is Nothing Then Throw New InvalidOperationException("Couldn't get an IUpdateHistoryEntryCollection.")
        Dim items As New List(Of HistoryItem)(count)
            For i As Integer = 0 To count - 1
                Dim item As IUpdateHistoryEntry = historyCollection.Item(i)
                Dim friendlyItem As New HistoryItem
                With friendlyItem
                    .ClientApplicationId = item.ClientApplicationID
                    .Date = item.Date
                    .Description = item.Description
                    .HResult = item.HResult
                    Select Case item.Operation
                        Case WUApiInterop.UpdateOperation.uoInstallation
                            .Operation = UpdateOperation.Installation
                        Case WUApiInterop.UpdateOperation.uoUninstallation
                            .Operation = UpdateOperation.Uninstallation
                    End Select
                    Select Case item.ResultCode
                        Case WUApiInterop.OperationResultCode.orcAborted
                            .ResultCode = OperationResultCode.Aborted
                        Case WUApiInterop.OperationResultCode.orcFailed
                            .ResultCode = OperationResultCode.Failed
                        Case WUApiInterop.OperationResultCode.orcInProgress
                            .ResultCode = OperationResultCode.InProgress
                        Case WUApiInterop.OperationResultCode.orcNotStarted
                            .ResultCode = OperationResultCode.NotStarted
                        Case WUApiInterop.OperationResultCode.orcSucceeded
                            .ResultCode = OperationResultCode.Succeeded
                        Case WUApiInterop.OperationResultCode.orcSucceededWithErrors
                            .ResultCode = OperationResultCode.SucceededWithErrors
                    End Select
                    Select Case item.ServerSelection
                        Case WUApiInterop.ServerSelection.ssDefault
                            .ServerSelection = ServerSelection.Default
                        Case WUApiInterop.ServerSelection.ssManagedServer
                            .ServerSelection = ServerSelection.ManagedServer
                        Case WUApiInterop.ServerSelection.ssOthers
                            .ServerSelection = ServerSelection.Others
                        Case WUApiInterop.ServerSelection.ssWindowsUpdate
                            .ServerSelection = ServerSelection.WindowsUpdate
                    End Select
                    .ServiceId = item.ServiceID
                    Uri.TryCreate(item.SupportUrl, UriKind.Absolute, .SupportUrl)
                    .Title = item.Title
                    .UninstallationNotes = item.UninstallationNotes
                    .UninstallationSteps = New System.Collections.Specialized.StringCollection
                    For j As Integer = 0 To item.UninstallationSteps.Count - 1
                    .UnmappedResultCode = item.UnmappedResultCode
                    Dim identity As New UpdateIdentity(item.UpdateIdentity.RevisionNumber, item.UpdateIdentity.UpdateID)
                    .UpdateIdentity = identity
                End With
        End Try
        Return New ReadOnlyCollection(Of HistoryItem)(items)
    End Function

Attached is an example project:

1 comment:

  1. I need some help in reading CID for SD card. Is there any way to read CID via USB?