none
Obtaining a list of all installed software and details of it like path etc RRS feed

  • Question

  • Can anyone point me in the right direction to be able to retrieve a list of all installed apps on a computer, basically like add/remove programs does, so it lists all installed software and other useful information such as date installed, path etc

    Reason I am asking for advice is I have tried various code samples, but some get a small subset of what shows in add/remove, others get nothing

    I believe it is to do with some apps putting information in different registry locations than others, so wanting to see if anyone else has done this, and if so got better results than me

    Thank you


    Darren Rose

    Monday, October 22, 2018 9:42 PM

Answers

  • okay thanks that is interesting, could you possibly explain how you enumerate it?


    Darren Rose

    For example by using the Shell interfaces, like in C++ =>

    I just display the Installation date for testing, compiled in x64 to get all items =>

    Dim pidlPrograms As IntPtr = IntPtr.Zero
    Dim psfgaoOut As SFGAO = 0
    Dim hr As HRESULT = SHParseDisplayName("shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", IntPtr.Zero, pidlPrograms, 0, psfgaoOut)
    If (hr = HRESULT.S_OK) Then
        Dim pshDesktop As IShellFolder = Nothing
        hr = SHGetDesktopFolder(pshDesktop)
        Dim psf As IShellFolder = Nothing
        Dim IID_IShellFolder As New Guid("000214E6-0000-0000-C000-000000000046")
        hr = pshDesktop.BindToObject(pidlPrograms, IntPtr.Zero, IID_IShellFolder, psf)
        If (hr = HRESULT.S_OK) Then
            Dim ppenum As IEnumIDList
            Dim pidlChild As IntPtr = IntPtr.Zero
            Dim celtFetched As UInteger = 0
            hr = psf.EnumObjects(IntPtr.Zero, SHCONTF.SHCONTF_ENABLE_ASYNC Or SHCONTF.SHCONTF_FLATLIST Or SHCONTF.SHCONTF_FOLDERS Or SHCONTF.SHCONTF_INCLUDEHIDDEN Or SHCONTF.SHCONTF_NONFOLDERS, ppenum)
            If (hr = HRESULT.S_OK) Then
                Dim nCpt As Integer = 0
                hr = ppenum.Next(1, pidlChild, celtFetched)
                While ((hr = HRESULT.S_OK) AndAlso (celtFetched = 1))
                    nCpt += 1
    
                    Dim pFolderName As IntPtr = IntPtr.Zero
                    Dim strretFolderName As STRRET
                    hr = psf.GetDisplayNameOf(pidlChild, SHGDNF.SHGDN_INFOLDER, strretFolderName)
                    Dim sDisplayName As String = Nothing
                    If (hr = HRESULT.S_OK) Then
                        Dim sbDisplayName As System.Text.StringBuilder
                        sbDisplayName = New System.Text.StringBuilder(256)
                        StrRetToBuf(strretFolderName, pidlChild, sbDisplayName, CType(sbDisplayName.Capacity, UInteger))
                        sDisplayName = sbDisplayName.ToString
                    End If
    
                    Dim psf2 As IShellFolder2 = CType(psf, IShellFolder2)
                    Dim vVariantInstallLocation As Object = Nothing, vVariantItemName = Nothing, vVariantInstallDate = Nothing
                    Dim pk As PROPERTYKEY = PROPERTYKEY.PKEY_Software_InstallDate
                    hr = psf2.GetDetailsEx(pidlChild, pk, vVariantInstallDate)
    
                    Console.WriteLine(String.Format("Name : {0} - Install Date: {1}", sDisplayName, vVariantInstallDate))
    
                    hr = ppenum.Next(1, pidlChild, celtFetched)
                End While
                Console.WriteLine(String.Format("Nb Items : {0}", nCpt))
            End If
        End If
    End If

    With the declarations :

        Public Enum HRESULT As Integer
            S_OK = 0
            S_FALSE = 1
            E_FAIL = &H80004005
        End Enum
    
        Public Enum SHCONTF As UShort
            SHCONTF_CHECKING_FOR_CHILDREN = &H10
            SHCONTF_FOLDERS = &H20
            SHCONTF_NONFOLDERS = &H40
            SHCONTF_INCLUDEHIDDEN = &H80
            SHCONTF_INIT_ON_FIRST_NEXT = &H100
            SHCONTF_NETPRINTERSRCH = &H200
            SHCONTF_SHAREABLE = &H400
            SHCONTF_STORAGE = &H800
            SHCONTF_NAVIGATION_ENUM = &H1000
            SHCONTF_FASTITEMS = &H2000
            SHCONTF_FLATLIST = &H4000
            SHCONTF_ENABLE_ASYNC = &H8000
        End Enum
    
        Public Enum SFGAO As Integer
            CANCOPY = &H1
            CANMOVE = &H2
            CANLINK = &H4
            STORAGE = &H8
            CANRENAME = &H10
            CANDELETE = &H20
            HASPROPSHEET = &H40
            DROPTARGET = &H100
            CAPABILITYMASK = &H177
            ENCRYPTED = &H2000
            ISSLOW = &H4000
            GHOSTED = &H8000
            LINK = &H10000
            SHARE = &H20000
            [READONLY] = &H40000
            HIDDEN = &H80000
            DISPLAYATTRMASK = &HFC000
            STREAM = &H400000
            STORAGEANCESTOR = &H800000
            VALIDATE = &H1000000
            REMOVABLE = &H2000000
            COMPRESSED = &H4000000
            BROWSABLE = &H8000000
            FILESYSANCESTOR = &H10000000
            FOLDER = &H20000000
            FILESYSTEM = &H40000000
            HASSUBFOLDER = &H80000000
            CONTENTSMASK = &H80000000
            STORAGECAPMASK = &H70C50008
            PKEYSFGAOMASK = &H81044000
        End Enum
    
        Public Enum SHGDNF
            SHGDN_NORMAL = 0
            SHGDN_INFOLDER = &H1
            SHGDN_FOREDITING = &H1000
            SHGDN_FORADDRESSBAR = &H4000
            SHGDN_FORPARSING = &H8000
        End Enum
    
        <StructLayout(LayoutKind.Explicit, Size:=264)>
        Public Structure STRRET
            <FieldOffset(0)>
            Public uType As UInteger
            <FieldOffset(4)>
            Public pOleStr As IntPtr
            <FieldOffset(4)>
            Public uOffset As UInteger
            <FieldOffset(4)>
            Public cString As IntPtr
        End Structure
    
        <StructLayout(LayoutKind.Sequential, Pack:=4)>
        Public Structure PROPERTYKEY
            Private fmtid As Guid
            Private pid As Integer
            Public ReadOnly Property FormatId() As Guid
                Get
                    Return Me.fmtid
                End Get
            End Property
            Public ReadOnly Property PropertyId() As Integer
                Get
                    Return Me.pid
                End Get
            End Property
            Public Sub New(ByVal formatId As Guid, ByVal propertyId As Integer)
                Me.fmtid = formatId
                Me.pid = propertyId
            End Sub
            Public Shared ReadOnly PKEY_Software_InstallLocation As PROPERTYKEY = New PROPERTYKEY(New Guid("841E4F90-FF59-4D16-8947-E81BBFFAB36D"), 9)
            Public Shared ReadOnly PKEY_ItemNameDisplay As PROPERTYKEY = New PROPERTYKEY(New Guid("B725F130-47EF-101A-A5F1-02608C9EEBAC"), 10)
            Public Shared ReadOnly PKEY_Software_InstallDate As PROPERTYKEY = New PROPERTYKEY(New Guid("841E4F90-FF59-4D16-8947-E81BBFFAB36D"), 11)
        End Structure
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
        Public Structure SHELLDETAILS
            Public fmt As Integer
            Public cxChar As Integer
            Public str As STRRET
        End Structure
    
        Public Enum SHCOLSTATEF
            SHCOLSTATE_DEFAULT = 0
            SHCOLSTATE_TYPE_STR = &H1
            SHCOLSTATE_TYPE_INT = &H2
            SHCOLSTATE_TYPE_DATE = &H3
            SHCOLSTATE_ONBYDEFAULT = &H10
            SHCOLSTATE_SLOW = &H20
            SHCOLSTATE_EXTENDED = &H40
            SHCOLSTATE_SECONDARYUI = &H80
            SHCOLSTATE_HIDDEN = &H100
            SHCOLSTATE_PREFER_VARCMP = &H200
            SHCOLSTATE_PREFER_FMTCMP = &H400
            SHCOLSTATE_NOSORTBYFOLDERNESS = &H800
            SHCOLSTATE_VIEWONLY = &H10000
            SHCOLSTATE_BATCHREAD = &H20000
            SHCOLSTATE_NO_GROUPBY = &H40000
            SHCOLSTATE_FIXED_WIDTH = &H1000
            SHCOLSTATE_NODPISCALE = &H2000
            SHCOLSTATE_FIXED_RATIO = &H4000
        End Enum
    
        <ComImport, Guid("000214F2-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Friend Interface IEnumIDList
            <PreserveSig>
            Function [Next](ByVal celt As UInteger, <Out()> ByRef rgelt As IntPtr, <Out()> ByRef pceltFetched As UInteger) As HRESULT
    
            <PreserveSig>
            Function Skip(<[In]()> ByVal celt As UInteger) As HRESULT
    
            <PreserveSig>
            Function Reset() As HRESULT
    
            <PreserveSig>
            Function Clone(<Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppenum As IEnumIDList) As HRESULT
        End Interface
    
        <ComImport, Guid("000214E6-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss>
        Friend Interface IShellFolder
            Function ParseDisplayName(ByVal hwnd As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDisplayName As String, <[In](), Out()> ByRef pchEaten As UInteger, <Out()> ByVal ppidl As IntPtr, <[In](), Out()> ByRef pdwAttributes As UInteger) As HRESULT
            <PreserveSig>
            Function EnumObjects(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByVal grfFlags As SHCONTF, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppenumIDList As IEnumIDList) As HRESULT
    
            <PreserveSig>
            Function BindToObject(<[In]()> ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]()> ByRef riid As Guid, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppv As IShellFolder) As HRESULT '[In, MarshalAs(UnmanagedType.Interface)] IBindCtx
    
            'Function BindToObject(ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
    
            Function BindToStorage(<[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Function CompareIDs(<[In]()> ByVal lParam As IntPtr, <[In]()> ByRef pidl1 As IntPtr, <[In]()> ByRef pidl2 As IntPtr) As HRESULT
    
            Function CreateViewObject(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Function GetAttributesOf(<[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In](), Out()> ByRef rgfInOut As UInteger) As HRESULT
    
            Function GetUIObjectOf(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In]()> ByRef riid As Guid, <[In](), Out()> ByRef rgfReserved As UInteger, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Function GetDisplayNameOf(ByVal pidl As IntPtr, uFlags As Integer, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pName As STRRET) As HRESULT
    
            Function SetNameOf(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, <[In]()> ByVal uFlags As UInteger, <Out()> ByVal ppidlOut As IntPtr) As HRESULT
        End Interface
    
        <ComImport, Guid("93F2F68C-1D1B-11d3-A30E-00C04F79ABD1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss>
        Friend Interface IShellFolder2
            Inherits IShellFolder
            Overloads Function ParseDisplayName(<[In]()> ByVal hwnd As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDisplayName As String, <[In](), Out()> ByRef pchEaten As UInteger, <Out()> ByVal ppidl As IntPtr, <[In](), Out()> ByRef pdwAttributes As UInteger) As HRESULT
    
            Overloads Function EnumObjects(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByVal grfFlags As SHCONTF, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppenumIDList As IEnumIDList) As HRESULT
    
            Overloads Function BindToObject(<[In]()> ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]()> ByRef riid As Guid, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppv As IShellFolder) As HRESULT '[In, MarshalAs(UnmanagedType.Interface)] IBindCtx
    
            Overloads Function BindToStorage(<[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Overloads Function CompareIDs(<[In]()> ByVal lParam As IntPtr, <[In]()> ByRef pidl1 As IntPtr, <[In]()> ByRef pidl2 As IntPtr) As HRESULT
    
            Overloads Function CreateViewObject(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Overloads Function GetAttributesOf(<[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In](), Out()> ByRef rgfInOut As UInteger) As HRESULT
    
            Overloads Function GetUIObjectOf(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In]()> ByRef riid As Guid, <[In](), Out()> ByRef rgfReserved As UInteger, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Overloads Function GetDisplayNameOf(ByVal pidl As IntPtr, uFlags As Integer, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pName As STRRET) As HRESULT
    
            Overloads Function SetNameOf(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, <[In]()> ByVal uFlags As UInteger, <Out()> ByVal ppidlOut As IntPtr) As HRESULT
    
            Function GetDefaultSearchGUID(<Out()> ByRef pguid As Guid) As HRESULT
    
            Function EnumSearches(<Out()> ByVal ppenum As IntPtr) As HRESULT
    
            Function GetDefaultColumn(<[In]()> ByVal dwRes As UInteger, <Out()> ByRef pSort As UInteger, <Out()> ByRef pDisplay As UInteger) As HRESULT
    
            Function GetDefaultColumnState(<[In]()> ByVal iColumn As UInteger, <Out()> ByRef pcsFlags As UInteger) As HRESULT
    
            '<PreserveSig>
            'Function GetDetailsEx(<[In]()> pidl As IntPtr, <[In]()> ByRef pscid As PROPERTYKEY, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pv As PROPVARIANT) As HRESULT
    
            <PreserveSig>
            Function GetDetailsEx(<[In]()> pidl As IntPtr, <[In]()> ByRef pscid As PROPERTYKEY, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pv As Object) As HRESULT
    
    
            Function GetDetailsOf(<[In]()> pidl As IntPtr, <[In]()> ByVal iColumn As UInteger, <Out()> ByRef psd As IntPtr) As HRESULT
    
            Function MapColumnToSCID(<[In]()> ByVal iColumn As UInteger, <Out()> ByRef pscid As PROPERTYKEY) As HRESULT
        End Interface
    
        <DllImport("Shell32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Friend Shared Function SHParseDisplayName(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, ByVal pbc As IntPtr, <Out()> ByRef ppidl As IntPtr, ByVal sfgaoIn As SFGAO, <Out()> ByRef psfgaoOut As SFGAO) As HRESULT
        End Function
    
        <DllImport("Shell32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Friend Shared Function SHGetDesktopFolder(<Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppshf As IShellFolder) As HRESULT
        End Function
    
        <DllImport("Shlwapi.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Friend Shared Function StrRetToBuf(ByRef pstr As STRRET, ByVal pidl As IntPtr, ByVal pszBuf As System.Text.StringBuilder, <MarshalAs(UnmanagedType.U4)> ByVal cchBuf As UInteger) As HRESULT
        End Function

    • Marked as answer by wingers Tuesday, October 23, 2018 2:52 PM
    Tuesday, October 23, 2018 11:12 AM

All replies

  • I get the same list as in add/remove by enumerating the Shell (IShellFolder.EnumObjects) from 

    shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}

    but only compiled in x64

    (tested on Windows 10)

    Monday, October 22, 2018 10:39 PM
  • I get the same list as in add/remove by enumerating the Shell (IShellFolder.EnumObjects) from 

    shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}

    but only compiled in x64

    (tested on Windows 10)

    okay thanks that is interesting, could you possibly explain how you enumerate it?

    Darren Rose

    Monday, October 22, 2018 10:46 PM
  • plenty of wmi examples, you dont have to look to hard to find them

    Live as if you were going to die today, learn as if you were going to live forever -Mahatma Gandhi

    Tuesday, October 23, 2018 1:06 AM
  • okay thanks that is interesting, could you possibly explain how you enumerate it?


    Darren Rose

    For example by using the Shell interfaces, like in C++ =>

    I just display the Installation date for testing, compiled in x64 to get all items =>

    Dim pidlPrograms As IntPtr = IntPtr.Zero
    Dim psfgaoOut As SFGAO = 0
    Dim hr As HRESULT = SHParseDisplayName("shell:::{26EE0668-A00A-44D7-9371-BEB064C98683}\0\::{7B81BE6A-CE2B-4676-A29E-EB907A5126C5}", IntPtr.Zero, pidlPrograms, 0, psfgaoOut)
    If (hr = HRESULT.S_OK) Then
        Dim pshDesktop As IShellFolder = Nothing
        hr = SHGetDesktopFolder(pshDesktop)
        Dim psf As IShellFolder = Nothing
        Dim IID_IShellFolder As New Guid("000214E6-0000-0000-C000-000000000046")
        hr = pshDesktop.BindToObject(pidlPrograms, IntPtr.Zero, IID_IShellFolder, psf)
        If (hr = HRESULT.S_OK) Then
            Dim ppenum As IEnumIDList
            Dim pidlChild As IntPtr = IntPtr.Zero
            Dim celtFetched As UInteger = 0
            hr = psf.EnumObjects(IntPtr.Zero, SHCONTF.SHCONTF_ENABLE_ASYNC Or SHCONTF.SHCONTF_FLATLIST Or SHCONTF.SHCONTF_FOLDERS Or SHCONTF.SHCONTF_INCLUDEHIDDEN Or SHCONTF.SHCONTF_NONFOLDERS, ppenum)
            If (hr = HRESULT.S_OK) Then
                Dim nCpt As Integer = 0
                hr = ppenum.Next(1, pidlChild, celtFetched)
                While ((hr = HRESULT.S_OK) AndAlso (celtFetched = 1))
                    nCpt += 1
    
                    Dim pFolderName As IntPtr = IntPtr.Zero
                    Dim strretFolderName As STRRET
                    hr = psf.GetDisplayNameOf(pidlChild, SHGDNF.SHGDN_INFOLDER, strretFolderName)
                    Dim sDisplayName As String = Nothing
                    If (hr = HRESULT.S_OK) Then
                        Dim sbDisplayName As System.Text.StringBuilder
                        sbDisplayName = New System.Text.StringBuilder(256)
                        StrRetToBuf(strretFolderName, pidlChild, sbDisplayName, CType(sbDisplayName.Capacity, UInteger))
                        sDisplayName = sbDisplayName.ToString
                    End If
    
                    Dim psf2 As IShellFolder2 = CType(psf, IShellFolder2)
                    Dim vVariantInstallLocation As Object = Nothing, vVariantItemName = Nothing, vVariantInstallDate = Nothing
                    Dim pk As PROPERTYKEY = PROPERTYKEY.PKEY_Software_InstallDate
                    hr = psf2.GetDetailsEx(pidlChild, pk, vVariantInstallDate)
    
                    Console.WriteLine(String.Format("Name : {0} - Install Date: {1}", sDisplayName, vVariantInstallDate))
    
                    hr = ppenum.Next(1, pidlChild, celtFetched)
                End While
                Console.WriteLine(String.Format("Nb Items : {0}", nCpt))
            End If
        End If
    End If

    With the declarations :

        Public Enum HRESULT As Integer
            S_OK = 0
            S_FALSE = 1
            E_FAIL = &H80004005
        End Enum
    
        Public Enum SHCONTF As UShort
            SHCONTF_CHECKING_FOR_CHILDREN = &H10
            SHCONTF_FOLDERS = &H20
            SHCONTF_NONFOLDERS = &H40
            SHCONTF_INCLUDEHIDDEN = &H80
            SHCONTF_INIT_ON_FIRST_NEXT = &H100
            SHCONTF_NETPRINTERSRCH = &H200
            SHCONTF_SHAREABLE = &H400
            SHCONTF_STORAGE = &H800
            SHCONTF_NAVIGATION_ENUM = &H1000
            SHCONTF_FASTITEMS = &H2000
            SHCONTF_FLATLIST = &H4000
            SHCONTF_ENABLE_ASYNC = &H8000
        End Enum
    
        Public Enum SFGAO As Integer
            CANCOPY = &H1
            CANMOVE = &H2
            CANLINK = &H4
            STORAGE = &H8
            CANRENAME = &H10
            CANDELETE = &H20
            HASPROPSHEET = &H40
            DROPTARGET = &H100
            CAPABILITYMASK = &H177
            ENCRYPTED = &H2000
            ISSLOW = &H4000
            GHOSTED = &H8000
            LINK = &H10000
            SHARE = &H20000
            [READONLY] = &H40000
            HIDDEN = &H80000
            DISPLAYATTRMASK = &HFC000
            STREAM = &H400000
            STORAGEANCESTOR = &H800000
            VALIDATE = &H1000000
            REMOVABLE = &H2000000
            COMPRESSED = &H4000000
            BROWSABLE = &H8000000
            FILESYSANCESTOR = &H10000000
            FOLDER = &H20000000
            FILESYSTEM = &H40000000
            HASSUBFOLDER = &H80000000
            CONTENTSMASK = &H80000000
            STORAGECAPMASK = &H70C50008
            PKEYSFGAOMASK = &H81044000
        End Enum
    
        Public Enum SHGDNF
            SHGDN_NORMAL = 0
            SHGDN_INFOLDER = &H1
            SHGDN_FOREDITING = &H1000
            SHGDN_FORADDRESSBAR = &H4000
            SHGDN_FORPARSING = &H8000
        End Enum
    
        <StructLayout(LayoutKind.Explicit, Size:=264)>
        Public Structure STRRET
            <FieldOffset(0)>
            Public uType As UInteger
            <FieldOffset(4)>
            Public pOleStr As IntPtr
            <FieldOffset(4)>
            Public uOffset As UInteger
            <FieldOffset(4)>
            Public cString As IntPtr
        End Structure
    
        <StructLayout(LayoutKind.Sequential, Pack:=4)>
        Public Structure PROPERTYKEY
            Private fmtid As Guid
            Private pid As Integer
            Public ReadOnly Property FormatId() As Guid
                Get
                    Return Me.fmtid
                End Get
            End Property
            Public ReadOnly Property PropertyId() As Integer
                Get
                    Return Me.pid
                End Get
            End Property
            Public Sub New(ByVal formatId As Guid, ByVal propertyId As Integer)
                Me.fmtid = formatId
                Me.pid = propertyId
            End Sub
            Public Shared ReadOnly PKEY_Software_InstallLocation As PROPERTYKEY = New PROPERTYKEY(New Guid("841E4F90-FF59-4D16-8947-E81BBFFAB36D"), 9)
            Public Shared ReadOnly PKEY_ItemNameDisplay As PROPERTYKEY = New PROPERTYKEY(New Guid("B725F130-47EF-101A-A5F1-02608C9EEBAC"), 10)
            Public Shared ReadOnly PKEY_Software_InstallDate As PROPERTYKEY = New PROPERTYKEY(New Guid("841E4F90-FF59-4D16-8947-E81BBFFAB36D"), 11)
        End Structure
    
        <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
        Public Structure SHELLDETAILS
            Public fmt As Integer
            Public cxChar As Integer
            Public str As STRRET
        End Structure
    
        Public Enum SHCOLSTATEF
            SHCOLSTATE_DEFAULT = 0
            SHCOLSTATE_TYPE_STR = &H1
            SHCOLSTATE_TYPE_INT = &H2
            SHCOLSTATE_TYPE_DATE = &H3
            SHCOLSTATE_ONBYDEFAULT = &H10
            SHCOLSTATE_SLOW = &H20
            SHCOLSTATE_EXTENDED = &H40
            SHCOLSTATE_SECONDARYUI = &H80
            SHCOLSTATE_HIDDEN = &H100
            SHCOLSTATE_PREFER_VARCMP = &H200
            SHCOLSTATE_PREFER_FMTCMP = &H400
            SHCOLSTATE_NOSORTBYFOLDERNESS = &H800
            SHCOLSTATE_VIEWONLY = &H10000
            SHCOLSTATE_BATCHREAD = &H20000
            SHCOLSTATE_NO_GROUPBY = &H40000
            SHCOLSTATE_FIXED_WIDTH = &H1000
            SHCOLSTATE_NODPISCALE = &H2000
            SHCOLSTATE_FIXED_RATIO = &H4000
        End Enum
    
        <ComImport, Guid("000214F2-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)>
        Friend Interface IEnumIDList
            <PreserveSig>
            Function [Next](ByVal celt As UInteger, <Out()> ByRef rgelt As IntPtr, <Out()> ByRef pceltFetched As UInteger) As HRESULT
    
            <PreserveSig>
            Function Skip(<[In]()> ByVal celt As UInteger) As HRESULT
    
            <PreserveSig>
            Function Reset() As HRESULT
    
            <PreserveSig>
            Function Clone(<Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppenum As IEnumIDList) As HRESULT
        End Interface
    
        <ComImport, Guid("000214E6-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss>
        Friend Interface IShellFolder
            Function ParseDisplayName(ByVal hwnd As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDisplayName As String, <[In](), Out()> ByRef pchEaten As UInteger, <Out()> ByVal ppidl As IntPtr, <[In](), Out()> ByRef pdwAttributes As UInteger) As HRESULT
            <PreserveSig>
            Function EnumObjects(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByVal grfFlags As SHCONTF, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppenumIDList As IEnumIDList) As HRESULT
    
            <PreserveSig>
            Function BindToObject(<[In]()> ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]()> ByRef riid As Guid, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppv As IShellFolder) As HRESULT '[In, MarshalAs(UnmanagedType.Interface)] IBindCtx
    
            'Function BindToObject(ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]> ByRef riid As Guid, <Out> <MarshalAs(UnmanagedType.[Interface])> ByRef ppv As Object) As HRESULT
    
            Function BindToStorage(<[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Function CompareIDs(<[In]()> ByVal lParam As IntPtr, <[In]()> ByRef pidl1 As IntPtr, <[In]()> ByRef pidl2 As IntPtr) As HRESULT
    
            Function CreateViewObject(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Function GetAttributesOf(<[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In](), Out()> ByRef rgfInOut As UInteger) As HRESULT
    
            Function GetUIObjectOf(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In]()> ByRef riid As Guid, <[In](), Out()> ByRef rgfReserved As UInteger, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Function GetDisplayNameOf(ByVal pidl As IntPtr, uFlags As Integer, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pName As STRRET) As HRESULT
    
            Function SetNameOf(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, <[In]()> ByVal uFlags As UInteger, <Out()> ByVal ppidlOut As IntPtr) As HRESULT
        End Interface
    
        <ComImport, Guid("93F2F68C-1D1B-11d3-A30E-00C04F79ABD1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), ComConversionLoss>
        Friend Interface IShellFolder2
            Inherits IShellFolder
            Overloads Function ParseDisplayName(<[In]()> ByVal hwnd As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszDisplayName As String, <[In](), Out()> ByRef pchEaten As UInteger, <Out()> ByVal ppidl As IntPtr, <[In](), Out()> ByRef pdwAttributes As UInteger) As HRESULT
    
            Overloads Function EnumObjects(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByVal grfFlags As SHCONTF, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppenumIDList As IEnumIDList) As HRESULT
    
            Overloads Function BindToObject(<[In]()> ByVal pidl As IntPtr, ByVal pbc As IntPtr, <[In]()> ByRef riid As Guid, <Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppv As IShellFolder) As HRESULT '[In, MarshalAs(UnmanagedType.Interface)] IBindCtx
    
            Overloads Function BindToStorage(<[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.Interface)> ByVal pbc As IBindCtx, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Overloads Function CompareIDs(<[In]()> ByVal lParam As IntPtr, <[In]()> ByRef pidl1 As IntPtr, <[In]()> ByRef pidl2 As IntPtr) As HRESULT
    
            Overloads Function CreateViewObject(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByRef riid As Guid, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Overloads Function GetAttributesOf(<[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In](), Out()> ByRef rgfInOut As UInteger) As HRESULT
    
            Overloads Function GetUIObjectOf(<[In]()> ByVal hwndOwner As IntPtr, <[In]()> ByVal cidl As UInteger, <[In]()> ByVal apidl As IntPtr, <[In]()> ByRef riid As Guid, <[In](), Out()> ByRef rgfReserved As UInteger, <Out()> ByRef ppv As IntPtr) As HRESULT
    
            Overloads Function GetDisplayNameOf(ByVal pidl As IntPtr, uFlags As Integer, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pName As STRRET) As HRESULT
    
            Overloads Function SetNameOf(<[In]()> ByVal hwnd As IntPtr, <[In]()> ByRef pidl As IntPtr, <[In](), MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, <[In]()> ByVal uFlags As UInteger, <Out()> ByVal ppidlOut As IntPtr) As HRESULT
    
            Function GetDefaultSearchGUID(<Out()> ByRef pguid As Guid) As HRESULT
    
            Function EnumSearches(<Out()> ByVal ppenum As IntPtr) As HRESULT
    
            Function GetDefaultColumn(<[In]()> ByVal dwRes As UInteger, <Out()> ByRef pSort As UInteger, <Out()> ByRef pDisplay As UInteger) As HRESULT
    
            Function GetDefaultColumnState(<[In]()> ByVal iColumn As UInteger, <Out()> ByRef pcsFlags As UInteger) As HRESULT
    
            '<PreserveSig>
            'Function GetDetailsEx(<[In]()> pidl As IntPtr, <[In]()> ByRef pscid As PROPERTYKEY, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pv As PROPVARIANT) As HRESULT
    
            <PreserveSig>
            Function GetDetailsEx(<[In]()> pidl As IntPtr, <[In]()> ByRef pscid As PROPERTYKEY, <Out(), MarshalAs(UnmanagedType.Struct)> ByRef pv As Object) As HRESULT
    
    
            Function GetDetailsOf(<[In]()> pidl As IntPtr, <[In]()> ByVal iColumn As UInteger, <Out()> ByRef psd As IntPtr) As HRESULT
    
            Function MapColumnToSCID(<[In]()> ByVal iColumn As UInteger, <Out()> ByRef pscid As PROPERTYKEY) As HRESULT
        End Interface
    
        <DllImport("Shell32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Friend Shared Function SHParseDisplayName(<MarshalAs(UnmanagedType.LPWStr)> ByVal pszName As String, ByVal pbc As IntPtr, <Out()> ByRef ppidl As IntPtr, ByVal sfgaoIn As SFGAO, <Out()> ByRef psfgaoOut As SFGAO) As HRESULT
        End Function
    
        <DllImport("Shell32.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Friend Shared Function SHGetDesktopFolder(<Out(), MarshalAs(UnmanagedType.Interface)> ByRef ppshf As IShellFolder) As HRESULT
        End Function
    
        <DllImport("Shlwapi.dll", CharSet:=CharSet.Unicode, SetLastError:=True)>
        Friend Shared Function StrRetToBuf(ByRef pstr As STRRET, ByVal pidl As IntPtr, ByVal pszBuf As System.Text.StringBuilder, <MarshalAs(UnmanagedType.U4)> ByVal cchBuf As UInteger) As HRESULT
        End Function

    • Marked as answer by wingers Tuesday, October 23, 2018 2:52 PM
    Tuesday, October 23, 2018 11:12 AM
  • Thanks Castorix

    Darren Rose

    Tuesday, October 23, 2018 2:52 PM
  • Have also found a way using ALL of the various registry locations to pull out the information I need - sample code below

    This seems to get me comparable results to what is shown in add/remove

    I am then showing it in a grid with checkboxes to enable easily hiding all microsoft apps and also to show/hide system components (e.g. bits that don't show in add/remove)

    Structure AppInfo Dim Name As String Dim Publisher As String Dim DisplayVersion As String Dim UnInstallPath As String Dim SilentUnInstallPath As String Dim InstallDate As String Dim SystemComponent As Integer Dim EstimatedSize As Long End Structure

    Function GetInstalledApps() As List(Of AppInfo) Dim iList As New List(Of AppInfo) Try Dim DestKey1 As String = "SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" For Each App As String In RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1).GetSubKeyNames iList.Add(New AppInfo With {.Name = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("DisplayName"), .Publisher = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("Publisher"), .DisplayVersion = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("DisplayVersion"), .UnInstallPath = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("UninstallString"), .InstallDate = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("InstallDate"), .SystemComponent = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("SystemComponent"), .EstimatedSize = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey1 & App & "\").GetValue("EstimatedSize")}) Next Catch ex As Exception End Try Try Dim DestKey2 As String = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" For Each App As String In RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2).GetSubKeyNames iList.Add(New AppInfo With {.Name = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("DisplayName"), .Publisher = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("Publisher"), .DisplayVersion = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("DisplayVersion"), .UnInstallPath = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("UninstallString"), .InstallDate = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("InstallDate"), .SystemComponent = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("SystemComponent"), .EstimatedSize = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64).OpenSubKey(DestKey2 & App & "\").GetValue("EstimatedSize")}) Next Catch ex As Exception End Try Try Dim DestKey3 As String = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\" For Each App As String In RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3).GetSubKeyNames iList.Add(New AppInfo With {.Name = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("DisplayName"), .Publisher = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("Publisher"), .DisplayVersion = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("DisplayVersion"), .UnInstallPath = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("UninstallString"), .InstallDate = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("InstallDate"), .SystemComponent = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("SystemComponent"), .EstimatedSize = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64).OpenSubKey(DestKey3 & App & "\").GetValue("EstimatedSize")}) Next Catch ex As Exception End Try Return iList End Function



    Darren Rose

    Tuesday, October 23, 2018 2:55 PM