Example of how to get a list of installed programs (like Add and Remove Programs)
First of all I just want to say that this is different to every other example of programmatically retrieving a list of installed software that I have seen on the internet. All of the other examples seem to get way too many programs compared to what you would see in Add/Remove Programs in Windows and sometimes miss programs as well - both of these issues are caused by the fact that they rely on just looping through the Uninstall key in the registry or using WMI (which probably does the same thing). Add/Remove Programs looks in several other registry locations as well and I spent a considerable amount of time trying to figure out exactly how it decides which programs to include and which to ignore... but think I have finally got my code to produce an identical list to the list that Add/Remove Programs produces.
So as you have probably guessed, my code does not use WMI, it is all done by just reading registry keys
Description
Retrieves the names (and version) of all installed programs on a computer just like Add/Remove Programs. This was made to work as similarly to Add/Remove programs as possible, so whilst you could actually retrieve more programs (such as system components and drivers), my code should only get the ones that you would normally expect to see.
One advantage my code has over the built in Add/Remove Programs window is that you can run my code against a remote computer just as easily as you can run it on your local computer See below for details.
Usage
The DLL contains just one class, InstalledProgram, which has a single Shared method named GetInstalledPrograms which returns a generic List(Of InstalledProgram) and you can specify whether or not you want the returned list to include updates or not. The class also has several properties such as DisplayName, Version and IsUpdate.
I have included an example project with the solution attached to this post that demonstrates how you could use the InstalledProgram class to populate a ListView with all installed programs and their version numbers. If you want to get the list of installed programs from another computer on the network then there is an overloaded version of the GetInstalledPrograms method that accepts a computer name or IP address as an additional parameter. The demo project shows how to use this as well.
Here is a screenshot of the example application included with the attached solution that uses the InstalledProgram class to populate a listview:
As you can see, some items do not have the Version information but this is the same in Add/Remove Programs.
Per User Programs
There is one distinct difference in the way that my code works compared to Add/Remove Programs and that is the way in which user specific programs are handled. When you install a program that just installs for the currently logged on user, such as a ClickOnce app, then Add/Remove Programs will only show you that program if you are logged in as the user that the program was installed for. With my code however, you will see any user specific programs for every user no matter who you are logged on as (as long as the account you are logged in with has the relevant permissions). I made it this way intentionally but let me know if you dont think it should work like that.
Known Problems
Windows/Program Updates
I have not really concentrated on this side of things, I just wanted it to retrieve all installed programs and didnt care about windows updates etc but it does get the majority of them, just not all of them. If I get some spare time I'll try and sort that out but at the moment its not a priority
64 bit
The code seems to work perfectly fine on a 64 bit system if the code is built to target x64 (or AnyCpu) but if you set the code to target x86 then Windows hides/redirects one of the registry keys from the process and that key contains some of the installed programs - the end result being that not all programs may be displayed in this scenario. No such issues on 32 bit operating systems of course.
Version history is now attached to this post
So yeah, try it out and let me know if you find it useful or have any problems/feedback Of course if anyone has any suggestions for improvements to the code as well then feel free to point them out.
Chris
Download latest version below
Last edited by chris128; Aug 28th, 2010 at 11:51 AM.
Re: Enumerate installed programs (like Add and Remove Programs)
I just tried it even though I don't have any real need for it, but it works fine. I was surprised how fast it was, especially compared to the 'real thing' in windows. What does the real windows programs list do that makes it so slow? The only large difference I can see is the icons, do they cost that much time to retrieve? And while on that subject, perhaps a nice update would be to also retrieve the icons, or the publisher, installed date, size, basically everything the programs list also shows? I would imagine the information to be found in a similar place, although that is just a guess
EDIT
On second look, the real programs list shows 5 programs that are not in your list:
- ATI Catalyst Install Manager
- Microsoft .NET Compact Framework 2.0 SP2
- Microsoft .NET Compact Framework 3.5
and as you mentioned Office 2010 and Visio 2010
Not sure why the the first three are not listed..?
But otherwise very nice job!
Last edited by NickThissen; Jan 12th, 2010 at 12:13 PM.
Re: Enumerate installed programs (like Add and Remove Programs)
Thanks for the feedback Nick yeah I imagine it is the icons that make it take longer in the Windows program manager... oh and the fact that it queries each relevant registry key about 9 times and tries to read from several keys which dont seem to exist on any OS I have found, where as my program only does it once and only looks in the keys that do actually exist and do have programs in. Not sure why those 3 apps are not showing, I'm disappointed as I thought I had finally got it to get ALL programs apart from Office 2010! I'll install the compact framework on my PC and see if I can figure that one out. Cheers
Last edited by chris128; Jan 12th, 2010 at 04:19 PM.
Re: Enumerate installed programs (like Add and Remove Programs)
Damn you Nick! I've got to re-write half of this now that I've discovered something quite important after investigating the entries for the programs you mentioned. I dont understand how I managed to test this on over 15 machines and have it work perfectly though...
Re: Enumerate installed programs (like Add and Remove Programs)
Actually it wasnt as much hassle as I thought It now detects the compact framework for me and I've also fixed the bug that stopped office 2010 from being detected at all so can you give the new version a go and let me know if it now detects everything? New solution (version 1-5) attached to original post Thanks
Re: Enumerate installed programs (like Add and Remove Programs)
Fixed a stupid bug in the way that I was comparing instances of the InstalledProgram class. For some reason I made it so that when comparing two InstalledProgram instances, it first checks to see if the display name is the same (which makes sense), then checks to see if the versions are the same (still making sense), then if the versions are not the same it checks to see if one of them has a version that is not string.empty and if they do then it classes them as being the same (huh???)... dont ask, I must have been tired when I wrote that bit. It now just checks to see if DisplayName and Version are the same and if they are then it classes them as the same, if not then they are not the same.
This means that if you have multiple versions of the same program installed then they might not have been detected before, where as now in version 1.7 they will Version 1.7 uploaded to original post.
Re: Enumerate installed programs (like Add and Remove Programs)
I think adding icons would be great. It seems to work just fine for me. But I think most of us are visual people. I know when I'm getting ready to uninstall an application, I look for the familiar icon first.
Not a huge deal and will probably make the load time increase significantly. I know it does in my process manager.
Re: Enumerate installed programs (like Add and Remove Programs)
Yeah, to be honest the reason I didnt add that originally was because I didnt realise how easy it was to get the icon from a file, I thought it required API calls and all sorts but thanks to your process manager code I realised it can be done in a couple of lines
I may well include that in the next version but to be honest this wasnt really meant to be a complete replica of Add/Remove Programs (I wanted the program discovery process to work exactly the same though) as it was never intended to be able to uninstall programs, it was just for anyone wanting to list the installed programs on a PC from within their app (like I am doing in my auditing project that I am currently working on). I think if I do include it then I will add an overloaded method of the GetInstalledPrograms method that lets you specify that you do want it to retrieve the icons (so not getting the icons is the default) because as you have said, it does add considerable performance overhead and it would also be impossible to make it work reliably on remote computers as well.
where lstprograms is my listbox
server is the remote computer
Like I said remote WinXP box works fine, remote Win7 doesn't seem to work, your try/catch ex/end try statement catches the "the network path was not found" error. (calling from a winxp to a win7 btw, havent tried win7 to win7 if that matters)
Great job BTW, if I could get this thing working for Win7 it would be amazing!!!
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
Hmm its probably something to do with permissions being more restrictive on Windows 7. If you open registry editor on your PC and go to File -> Connect Network Registry, can you connect to the Win7 machine's registry?
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
wow good call:
"Unable to connect to xxx. Make sure that this computer is on the network, has remote administration enabled, and that both computers are running the remote registry server."
any idea how to enable those permissions on a win7 box off hand? I have a domain admin account that should have full access to the win7 machine.
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
New version uploaded to original post. Just fixed a stupid bug where a program would not be detected if the UninstallString registry value was not in the correct case - only found one program so far (some random screen saver app) that does not create the registry value as "UninstallString" but instead creates it as "Uninstallstring". I've changed the code now so that it is no longer case sensitive.
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
Chris,
Thanks again for your work you've done on this!
I wanted to see if it were possible to implement a way for a non-admin user to browse these remote registry keys if they were to provide an administrator username/password.
i.e. some of my coworkers have both admin accounts and non-admin accounts, they are generally logged in with the non-admin accounts. I've had to reconfigure my program to prompt for admin user credentials on program start, I wanted to see if there was a way I could pass those credentials to your "InstalledProgram" class and it uses those credentials when making the registry connection.
Hope that made sense, I believe this is doable but it's a bit out of my expertise. This would be an incredibly useful function.
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
The problem is the VB.NET methods for connecting to the registry dont let you supply a username and password so I think the only way to do that is a bit of a messy method (and I've never tested it against a Windows 7 machine). Basically you would just map to the C$ share on the remote PC (which you can provide credentials for) and then when you attempt to connect to the registry on that remote machine it uses the connection that was already established by the C$ mapping so lets you on. I'm afraid I wouldn't really want to include that as a 'feature' of my InstalledProgram class as like I said its a bit messy and relies on quite a few external items but you should be able to implement it yourself and still use my InstalledProgram class - you would just do the C$ mapping from your own program before calling my class. If you do not know what I mean by C$ mapping, you could just execute the Net Use command from your program via Process.Start. The Net Use command goes like this:
Code:
Net Use \\RemoteMachineName\C$ /User:MyAdminUsername MyAdminPassword
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
thanks for the reply chris.
In regards to the messiness and reliability of other items are you talking about making a managementscope connection to the remote machine? If that is so that is pretty simple, I'm doing that for a bunch of WMI queries already. (but I may be underestimating how to implement that in your code)
the "Net Use" commands didn't seem to work like I had hoped, it could be because the remote machines I've been connecting to are windows 7.
Last edited by Drewster727; Apr 6th, 2010 at 09:16 PM.
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
Nah I wasnt talking about WMI, I just meant using the Net Use command I mentioned. What problems did you have with them and how exactly did you try to do it?
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
sorry for the late reply.
basically I ran the 'net use' commands to connect to the remote machine that I wanted to enumerate the apps from. This was done outside of my application. Next, with my app I attempted to load the programs (using your code) and it fails, on the visual studio immediate window it says there was a security exception 'registry access is not allowed'
This occurs when attempting to connect to a win7 box, the strange thing is I can connect to our winXP boxes and enumerate the apps just fine not even using the 'net use' commands. My win7 image and winXP image both have the same registry access permissions and both have the 'Remote Registry' service enabled.
So basically it seems like the 'net use' commands did nothing, really not sure what can be done here.
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
Ah ok I didnt realise this was just happening for your Windows 7 machines. Unfortunately I havent got one that is on a domain to test with but I'm guessing it is some new security feature in Windows 7 that locks down remote registry access. If you launch regedit from another PC and try and connect it to the Windows 7 machine remotely (File -> Connect network registry) does that work? I'm guessing it wont do, but can you just confirm? If it doesnt, might be worth checking the permissions on the registry key mentioned in the second half of this article to see if that is what is restricting it: http://www.windowsreference.com/secu...ss-in-windows/
Re: Example of how to enumerate installed programs (like Add and Remove Programs)
Originally Posted by pcmechanix
Can you set this up to output to a text file, or at least cut and paste the output? Great program!
As all of the main program logic is contained in the InstalledProgram class, which is in its own DLL project, you can just create your own application that references that DLL and calls the GetInstalledPrograms method, then write the returned data to a text file yourself.
The application shown in the screenshot is just a demo of what you could do with the InstalledProgram class - the whole point of separating the core functionality into its own class is that you can use it to get the data and then do whatever you want with it (display it on a form like in my example, write it to a database, write it to a text file, etc etc)
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Very nice job!
But I have to say I would be interested in a way to say, select a bunch to be batch uninstalled. I did read post #13, I guess we should be able to expand on this ourselves, so thanks for sharing this awesome code!!
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Thanks Uninstalling will be tricky if you want it to work on remote PCs as well. If you want to do it only on a local PC then it should be fairly easy - just grab the UninstallString value from the registry (if you look at my code you will see where the code checks to make sure this value exists, so thats where you need to get it from) and then pass whatever you got from that in to Process.Start. The problem with any kind of bulk uninstall (assuming you mean you want them all to run at the same time) is that you can't run more than one installation/uninstall at once if the installers use the Windows installer packages (MSI files).
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
I was kind of thinking of garbing that UninstallString and putting it in a toRemove arraylist then loop that list using process wait on a local pc only. Of course the user would have to select what programs would go in that arraylist.......I will have to look at this more closely though cause this is just off the top of my head.
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Chris,
How did you get your program to separate out the version number from the program name? I'm trying to use your class to dump program names into a column in a datagridview, and the version number of the program into a different column of the datagridview.
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Well my class has a separate property for the name and the version, so just use each property wherever you need to use that value...
When you call GetInstalledPrograms it returns a List(Of InstalledProgram) so you can loop through that and for each item in the list you add the relevant property to the relevant column. Here's a brief example of how to just show the program name and version on separate lines in a MessageBox - hopefully you can figure out how to apply this to your situation
vb Code:
For Each Program As InstalledProgram In InstalledProgram.GetInstalledPrograms
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Thank you very much for this application. I'm doing a job in class a it's very useful for me. I'm serching for an app like this because no one works in 64.
I don't know if you still see this forum. But i have a trouble and i want to make you a question. I need where the installed programs are installed, i.e i need the dir of each program installed.
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Have a look in the registry keys that my code works with, I think there might be a registry value in some of them for each program that lists where the app was installed to.
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Chris,
I'm trying to use the InstalledProgram class in a vb.net console application.
Everything seems to work when I try to list out the programs but I'm running into two problems and I can't figure out why:
1. duplicates, I see each program twice in the list I'm outputting to the console.
here is a snapshot of part of the console output:
2. some programs seem to be missing... one of them would be autodesk autocad 2010 off the top of my head. I'll have to find the registry location. It's odd though... I'm using the installed programs class in a winforms app and it seems to list all of the software, including the example I gave (autodesk autocad 2010).
here is my code:
Code:
For Each Program As InstalledProgram In InstalledProgram.GetInstalledPrograms(True)
Console.WriteLine(Program.DisplayName & " -- " & Program.Version)
Next
Any input on this would be great, I'm kinda stumped and would love to have this in my console program! thanks!
Last edited by Drewster727; Jan 24th, 2011 at 06:52 PM.
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
I would guess that your console app is running on a 64 bit OS and is not set to target the x64 CPU type - see this part of my original post:
64 bit
The code seems to work perfectly fine on a 64 bit system if the code is built to target x64 (or AnyCpu) but if you set the code to target x86 then Windows hides/redirects one of the registry keys from the process and that key contains some of the installed programs - the end result being that not all programs may be displayed in this scenario. No such issues on 32 bit operating systems of course.
Re: Example of how to get a list of installed programs (like Add and Remove Programs)
Quick question. First of all, I'm just starting with VB.Net so I'm kinda new to this (not new to programming though).
Your test application works fine.
I created a new project and just pasted the code from InstalledProgram.vb into a new class (didn't want to use a DLL). Now when I run my little test program, when it enters "GetUserInstallerKeyPrograms()" it croaks on the line
Code:
For Each UserDataKeyName As String In HklmRootKey.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Installer\UserData").GetSubKeyNames
Apparantly, "HklmRootKey.OpenSubKey("Software\Microsoft\Windows\CurrentVersion\Installer\UserData").GetSubKeyNam es" contains "Nothing". Oddly enough, in your test app it's not empty (even with the same CuInstallerKey).
So what am I doing wrong?
Also, have you ever implemented getting the Icons as well?