This topic is 3843 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Is there a way to find and list of all the programs installed on Windows using WIN32 and C++? If NOT, is there any alternative way in finding the installed program on Windows? Any help would be appreciated. Thank you in advance.

##### Share on other sites
Why on earth would you care?

The closest you can get would be to use SHGetFolderPath to get the location of the "Program Files" directory and grovel around under there but not all programs install themselves there and some stuff aren't really "programs" in the sense the end-user thinks about. You could also grovel around in the add/remove programs data in the registry but not all programs register themselves there.

It depends greatly what you mean by "install". I prefer to use apps that I can "install" via xcopy and don't go mucking around leaving turds pointing to themselves all over the system - are those apps "installed"?

##### Share on other sites
see this:
http://www.codeproject.com/system/installed_programs.asp

Also check contents for problems with that method.

##### Share on other sites
Where you look for programs really depends on what types of programs you are interested in. If you're interested in a list of programs that the user would recognize and use then you could (and probably should) enumerate the programs in the Start Menu. If you're looking to get a list of programs which can be removed then you should enumerate Add/Remove Programs as already suggested.

Note, however, that there is a difference.

For example, if you enumerate the Start Menu then you can find that the user had Word, Excel, and Powerpoint installed. If you enumerate Add/Remove Programs then you can only know that they have Office installed. Further, when enumerating the Start Menu you might pick up on some programs that dont have uninstallers.

As a secondary note, if you choose to go with enumerating the Start Menu then you should also be familiar with using IShellLink. If you want to handle Office (and others) gracefully you will also need to be familiar with MSI as you will most likely need to call MsiGetShortcutTarget() and MsiGetComponentPath().

##### Share on other sites
I am sorry for the confusion.
What I am trying to accomplish is to find and list the programs/applications that are installed, but commonly used by the user. They are in the start menu, for example, Word, Photoshop, Outlook, etc. I guess I was a little misleading by saying "all the program installed".

Antheus, I actually came across that code project website when I did research. However, I convert what they have to VS2005 and when I tried to compile and run the code, it crashed. And I have no idea how to fix the problem.

By the way, Colin Jeanne, I am not sure what you mean by "enumerating the Start Menu". Can you please give me an example or maybe a code snippets?
And your suggestion, is it using regular WIN32 or MFC or anything like that? because I don't have that much knowledge using MFC.

Thank you for all the input, guys. I really appreciate it.

##### Share on other sites
These two places in the registry may be of interest to you:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\UninstallHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssist

##### Share on other sites
Thank you.
I am assuming we can get the list of the file if we can get access to the "DisplayName" of the applications in the registry.

Do you have any good article I can use?
I found this online:
http://www.codersource.net/win32_registry_operations.html

Any tips and tricks on how to access the registry?
And is there any other alternative to find these application?
I will eventually need to find out the most and least used application on the computer. :)

[Edited by - nekobasu33 on June 29, 2007 11:57:35 AM]

##### Share on other sites
Quote:
 Original post by nekobasu33I will eventually need to find out the most and least used application on the computer. :)

You cannot do that, since that criteria doesn't exist. If someone has installed MS Office, but only uses Word, how often is MS Office used? And if they use word only, but only from browser, are they really using word?

And what about applications that get started automatically and stay resident? Like MySQL?

The criteria that Add/Remove panel offers is useless. In my case, Microsoft Visual Studio is labeled "rarely", yet I use it daily for 8+ hours for past 6 months. Then there's "Multiverse Client", which I have launched exactly once 7 months ago, and is labeled "frequently".

Just to save you time - you cannot find out frequency of use.

##### Share on other sites
Quote:
 Original post by nekobasu33By the way, Colin Jeanne, I am not sure what you mean by "enumerating the Start Menu". Can you please give me an example or maybe a code snippets?And your suggestion, is it using regular WIN32 or MFC or anything like that? because I don't have that much knowledge using MFC.

I do believe then that enumerating the items in the Start Menu is the most correct as not all programs have registered uninstallers nor is it true that it is possible to map from the uninstaller to the program itself for those that do.

The Start Menu is just a folder on your system which contains (mostly) shortcuts. You can enumerate the objects in the Start Menu by using FindFirstFile(), FindNextFile(), etc. or via IShellFolder::EnumObjects() or whatever your file system enumeration preference is. To get the path to the Start Menu you have two options

1) If you only need your program to work on Vista and above, I recommend you use the SHGetKnownFolderPath() with FOLDERID_StartMenu.

2) Otherwise use SHGetFolderPath() with CSIDL_STARTMENU.

For each item that you find in the folders you will need to see if it is a .lnk file (if you're using FindFirstFile() and friends) or if it has the SFGAO_LINK property (if you're using IShellFolder). If it is then you create an IShellLink to the item to get information such as the actual path to the binary.

As for deciding which programs are the most frequently used and least frequently used, the Start Menu already does this. You dont have access to that information, but creating a program to do this is a bit redundant.

##### Share on other sites
I got the path to the windows programs in the Start menu. The path is in LPCTSTR type.

Here's the path:

However, I am still not quite sure how to enumerate the programs. How do you actually go into each folder?

When I did this:
	WIN32_FIND_DATA FindFileData;	HANDLE hFind;	hFind = FindFirstFile(path, &FindFileData);

I got "Programs" as the result. Isn't it the current folder? How can I go into the "Programs" folder and iterate through?

Also, I need to find the .exe files, and since the files in the start menu programs are .lnk, which is Windows shortcut, how can I accomplish this? Is there a way I can get access to the file's properties to know that a particular file is an "Application" under "Target Type" (if you right click and go to properties)?

##### Share on other sites
If the file you find has FILE_ATTRIBUTE_DIRECTORY then you know its a directory. In the past I've used a recursive function which enumerates all the objects in a directory and calls itself if that object is itself a directory.

NB: The directories '.' and '..' are also returned. You will need to special case these or will feel the burn of an infinite loop.

##### Share on other sites
Colin,

Could you please explain more on how to iterate through a folder? maybe post some examples?
I think I kind of get the idea, but I cannot get it to work properly.

Here's what I did:
CFileFind finder;bool bWorking = finder.FindFile((path));while (bWorking){	bWorking = finder.FindNextFile();	if (finder.MatchesMask(FILE_ATTRIBUTE_DIRECTORY))	{		_tprintf_s(_T("%s\n"), (LPCTSTR) finder.GetFileName());	}}

This code ONLY prints "Programs". Which I think makes sense. But how can I get the files inside the "Programs" directory?

I tried the following "FindNextFile", but it always fails and never go into the while loop.
WIN32_FIND_DATA FindFileData;HANDLE hFind;hFind = FindFirstFile(path, &FindFileData);while (FindNextFile(hFind, &FindFileData) != 0){	//do something}

Am I going to the wrong direction?

Any help would be appreciated.

[Edited by - nekobasu33 on July 11, 2007 5:37:58 PM]

##### Share on other sites
FindFirstFile()/FindNextFile() can only find things within the current working directory. If you want to see into a subdirectory you need to start a new search with that subdirectory as the current working directory. I've used a function similar to

void findFileInDirectory(PTSTR pszFile, PTSTR pszDirectory){   // Set up find and such   ...   // We've found a directory   if (found file is a directory)   {      TCHAR szNewDir[MAX_PATH];      StringCchPrintf(szNewDir, ARRAYSIZE(szNewDir), TEXT("%s\\%s"), pszDirectory, find_data.cFileName);      findFileInDirectory(pszFile, szNewDir);   }}

##### Share on other sites
In the following line of code that you posted

void findFileInDirectory(PTSTR pszFile, PTSTR pszDirectory)

Is "pszDirectory" the current child directory? and what about the "pszFile"?

So, I need to do the FindFirstFile() and FindNextFile() in this function?

I am sorry, I am a little confused now.

##### Share on other sites
I found this:
http://msdn2.microsoft.com/En-US/library/aa365200.aspx

It shows how to iterate through C:\ and list all the files and folders in there.
However, when I change the file path to C:\ProgramData\Microsoft\Windows\Start Menu\Programs

by using
[source lang="cpp]TCHAR buf[BUFSIZE];SHGetSpecialFolderPath(NULL, // HWND	               buf,	               CSIDL_COMMON_PROGRAMS,	               NULL); // don't create

the FindNextFile() is not working at all. It never goes into the following function:
      // List all the other files in the directory.      while (FindNextFile(hFind, &FindFileData) != 0)       {         _tprintf (TEXT("Next file name is: %s\n"), FindFileData.cFileName);      }

Do you have any idea why? Maybe I am not creating the path correctly?

[Edited by - nekobasu33 on July 11, 2007 5:51:25 PM]

##### Share on other sites
Thank you for all the help.

I got it to work.
I figured out (unless I completely doing something wrong) that we cannot just simply do FindFirstFile() and FindNextFile() without allocating some stuff before that.

Here'e my code snippet to accomplish that:
//finding the path and store it in "buf"TCHAR buf[MAX_PATH];SHGetSpecialFolderPath(NULL, buf, CSIDL_COMMON_PROGRAMS, NULL);DirSpec = (LPTSTR) malloc (MAX_PATH);// Prepare string for use with FindFile functions. Copy the string to a bufferStringCbCopyN (DirSpec, MAX_PATH, buf, length_of_arg+1);//then append '\*' to the directory name.StringCbCatN (DirSpec, MAX_PATH, TEXT("\\*"), 2*sizeof(TCHAR));//then do the FindFirstFile() and FindNextFile() ...

##### Share on other sites
Quote:
 Original post by iMalcThese two places in the registry may be of interest to you:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\UninstallHKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\UserAssistGoogle should be able to tell you plenty about them.
I'd avoid touching especially the latter key. That's an undocumented key and may mysteriously change without warning, breaking your app and generally making people sad.

##### Share on other sites
Thank you for the warning.
I decided not to mess around with the registry because it is just too risky.

##### Share on other sites
Dont use StringCb* functions here. Use StringCch* functions instead. The difference is that StringCb* works by counting bytes while StringCch* works by counting characters.

Otherwise, yes, you do need to have allocated memory before using the Find* functions.

##### Share on other sites
Thank you for the suggestion. Anyway, what is the advantage of using StringCch* instead of StringCb* function?

Earlier, you also mentioned about creating a special case for "." and "..", I was thinking to just do FindNextFile() a couple of times to skip those ("." and ".."). Do you think there will be a drawback in doing so? is there a better way?

I tried the following code, but it didn't work (I think I'm doing it completely wrong):
CFileFind finder;if (finder.FindFile(TEXT("\."))){    //do something}else if (finder.FindFile(TEXT("\.."))){    //do something}

Could you please guide me on this?

Thank you

[Edited by - nekobasu33 on July 12, 2007 12:15:28 PM]

##### Share on other sites
It's better to use the StringCch* family of functions since it is natural to think of strings as collections of characters. The StringCb* family should be used when it is natural to thing of them as buffers.

You dont want to simply call FindFirstFile() and FindNextFile() a few times to skip '.' and '..' since the order that directories and files are returned is not guaranteed. There is nothing preventing these two from being the last things returned, or the 2nd and 50th, or any other combination. You need to check for them explicitly.

The strings returned from FindFirstFile() and FindNextFile() that represent the names of the discovered items also do not have the initial slash. When '.' is returned the string will be "." not "\\.".

##### Share on other sites
Thank you so much for all the help.
I got it working, including the "." and ".."

:)