Alle programma executable file paths achterhalen in Windows.

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 12-05 19:27
Ik zit met een hardnekkig probleem waar ik graag de Tweakers community op los wil laten (als een soort laatste strohalm ;)). Wees niet afgeschrikt.
Het zit als volgt: ik wil graag alle 'executable' (.exe) file paths achterhalen van alle geïnstalleerde programma's in Windows (de volledige filepath van de installatie locatie van een programma zoals bijvoorbeeld:
C:\Program Files (x86)\CCleaner Browser\Update\CCleanerBrowserUpdate.exe).
Ik gebruik hiervoor C#.

Dit dacht ik met C# op de volgende manier te kunnen uitlezen uit het Windows registry:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static List<string> registryUserPrograms2()
        {
            List<string> installedProgramNames = new List<string>();
            string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
            using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
            {

                foreach (string subkey_name in key.GetSubKeyNames())
                {
                    using (RegistryKey subkey = key.OpenSubKey(subkey_name))
                    {

                        if (subkey.GetValue("InstallLocation") != null && subkey.GetValue("InstallLocation").ToString() != "")
                        {

                            string name = subkey.GetValue("InstallLocation").ToString();
                            installedProgramNames.Add(name.ToLower());
                        }

                    }
                }
            }
            return installedProgramNames;
        }
Echter het probleem is in dit geval dat niet elk programma een install location value krijgt toegewezen.
Ik dacht dat de oplossing zou kunnen zijn om eerst op de volgende manier alle .exe files op te halen uit de program files folder...:
code:
1
2
3
4
 string[] allexesx86 = Directory.GetFiles(programFilesX86, "*.EXE", SearchOption.AllDirectories);
  string[] allexesPro = Directory.GetFiles(programFiles, "*.EXE", SearchOption.AllDirectories);

 string[] allexes = allexesx86.Concat(allexesPro).ToArray();
.. en om dan vervolgens op de volgende manier door deze .exe files heen te 'loopen' om fileInfo objecten op te halen en uit te lezen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 int index = 0;
            foreach (var file in allexes)
            {
                FileInfo info = new FileInfo(file);
                FileVersionInfo myFileVersionInfo = FileVersionInfo.GetVersionInfo(info.FullName);

                ExeInfo exeInfo = new ExeInfo();
                exeInfo.size = info.Length;
                exeInfo.fullName = info.FullName;
                exeInfo.developer = [b]myFileVersionInfo.CompanyName[/b];
                exeInfo.productName = myFileVersionInfo.ProductName;
                exeInfo.directoryPath = info.DirectoryName;
                exeInfo.parentFolderName = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(exeInfo.fullName));
                exeInfo.fileDescription = myFileVersionInfo.FileDescription;
                exeInfo.iconicon = "";

                if (!exedirectories.Contains(info.DirectoryName))
                {      
                    exedirectories.Add(info.DirectoryName); 
                }
               

                

                if (info.Length > 0)
                {
                   exeInfo.iconicon = ExtractIconImagefromExe(info.FullName, index);
                }
                exeinfos.Add(exeInfo);
            }
Ik dacht vervolgens op deze manier de connectie te kunnen maken tussen de 'DisplayName" property in het windows registry en de fileInfoVersion productname property om zo alsnog via een omweg de .exe file paths te kunnen krijgen van alle geïnstalleerde programma's (m.b.v.: 'FileInfo.Fullname').

Maar dit pakt niet helemaal uit zoals ik dacht. De "displayname" uit het Windows registry is niet gelijk aan de de fileInfoVersion.productname property.

Nu zoek ik eigenlijk naar een manier om toch op deze manier een dergelijke koppeling te maken. Ik zag bijvoorbeeld dat de main executable vrijwel altijd het grootste .exe bestand is in een folder en dus zou je de .exe bestanden in een folder kunnen sorteren op 'size in MB' om zo de grootste eruit te kunnen pikken. Dit blijkt echter niet altijd een betrouwbare manier.

Nu is mijn concrete vraag eigenlijk of iemand weet op welke wijze je nou alle applicatie .exe file paths vind van al je geïnstalleerde programma's zoals weergegeven in het windows registry.

Heeft een main-executable van een geïnstalleerd programma misschien een bepaalde property die zo'n bestand uniek maakt t.o.v. andere .exe files in een folder?
Misschien 'productversion' of 'fileversion'?

Wat ik trouwens ook geprobeerd heb is om het via de ManagementObjectSearcher te doen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public static List<string> getProgramsMOS()
        {
            List<string> mosPrograms = new List<string>();

            ManagementObjectSearcher mos = new ManagementObjectSearcher("SELECT * FROM Win32_Product");
            foreach (ManagementObject mo in mos.Get())
            {
                //Console.WriteLine(mo["Name"]);
                if (mo["Name"] != null)
                {
                    mosPrograms.Add(mo["Name"].ToString().ToLower());

                }
                if (mo["InstallLocation"] != null)
                {
                    mosPrograms.Add(mo["InstallLocation"].ToString());
                }
            }

            return mosPrograms;
        }
Echter dit levert ook niet het gewenste resultaat op. Dan ontbreken er ook een hoop applicatie executable file paths.

Weet iemand een oplossing? Ik heb al een hoop gezocht online maar ik vind geen sluitende oplossing voor dit probleem.

...

Alle reacties


Acties:
  • +1 Henk 'm!

  • Boeryepes
  • Registratie: Januari 2016
  • Niet online
Hieronder geef ik misschien meer dan 1 kant en klare oplossing maar naar mijn mening is het snuffelen in verschillende benaderingen altijd verhelderend voor mijn eigen begrip en is Stackoverflow daarvoor, voor mij, de site.

Onder bij oplossing 1 staat iets wat misschien ook jouw 'probleem' is.

Oplossing 1:
https://stackoverflow.com...n-executables-windows10-c

... hier staat hetvolgende: misschien is dat je probleem:
"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" represents applications for 32 bit. For 64 bit you also need to traverse "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall" and since not every software has a 64 bit version the total applications installed are a union of keys on both locations that have "UninstallString" Value with them.

Oplossing 2:
Als je alleen wilt zoeken in de 'Program Files' folders is as simple as it gets: dir /s /b *.exe | findstr /v .exe (uiteraard de juiste top directory toevoegen)
https://stackoverflow.com...-command-line-for-windows

Je krijgt dan dit: en daar zitten natuurlijk ook hulpprogramma's bij.
Afbeeldingslocatie: https://tweakers.net/i/VShU1yAjySJyGy9zisWM1pL_q9o=/800x/filters:strip_exif()/f/image/hh0UV6m1zJzf8Y4nOAMG7UnL.png?f=fotoalbum_large

Multithreaded uitvoeren:
https://stackoverflow.com...n-command-prompt-commands
var result = await Cli.Wrap("cmd")
.WithArguments("dir /s /b *.exe | findstr /v .exe")
.ExecuteBufferedAsync();

var stdOut = result.StandardOutput;


Nog wat leuke hits:
https://stackoverflow.com...exe-files-on-disk-using-c

En je kunt ook "Shell:AppsFolder" openen in explorer. Je krijgt dan alle geinstalleerde apps en daar kun je denk ik wel de filefolder van opgraven (niet zelf geprobeerd).
Afbeeldingslocatie: https://tweakers.net/i/b0Qna4zVswEWwOhuViasAueZVeg=/800x/filters:strip_exif()/f/image/Po2kdUC5ybDZgrQDKPoOVpXb.png?f=fotoalbum_large

The biggest communication problem is we do not listen to understand. We listen to reply.


Acties:
  • 0 Henk 'm!

  • martyw
  • Registratie: Januari 2018
  • Laatst online: 01:38
Eens met optie 2 van @Boeryepes, dit is typisch iets voor een command line - een C# programma is flinke overkill hiervoor. Of heb je deze gegevens nodig in een groter programma?

Acties:
  • 0 Henk 'm!

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 12-05 19:27
Boeryepes. Bedankt voor de reactie. De eerste twee oplossingen had ik al geprobeerd maar die boden geen oplossing.

Die laatste optie die je aandraagt is echter wel de oplossing die dicht in de buurt komt. Je kan dan op deze manier alle application paths ophalen via de "Shell:AppsFolder":
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        public static List<string> getInstalledProgramPaths3()
        {
            List<string> allInstalledProgramPaths = new List<string>();
            var FOLDERID_AppsFolder = new Guid("{1e87508d-89c2-42f0-8a7e-645a0f50ca58}");
            ShellObject appsFolder = (ShellObject)KnownFolderHelper.FromKnownFolderId(FOLDERID_AppsFolder);

            foreach (var app in (IKnownFolder)appsFolder)
            {
                string name = app.Name;
                string applicationPath = app.Properties.System.Link.TargetParsingPath.Value;

                if (applicationPath != null)
                {
                    string extension = Path.GetExtension(applicationPath);

                    if (extension.ToLower() == ".exe")
                    {
                        allInstalledProgramPaths.Add(applicationPath);
                    }
                }
            }

            return allInstalledProgramPaths;
        }
https://stackoverflow.com/questions/62934534/get-a-file-path-from-a-parsingpath-of-a-shellobject

Dit werkt goed. Het bovenstaande stukje code geeft dan 145 application paths terug. Kijk ik dan vervolgens in "Control Panel\Programs\Programs and Features" dan zie ik daar 138 geïnstalleerde programma's staan. Als ik het registry uitlees dan zijn het er meer dan 145, maar ik denk dat dit zo ongeveer correct werkt. In het registry staan ook programma's die niet relevant zijn voor de gebruiker. Daar worden volgens mij teveel programma's weergegeven.

Dit lijkt mij zo de juiste oplossing :). Weet iemand trouwens of de Folder ID (de GUID code) die ik in dit stukje code opgeef op alle Windows systemen zou moeten werken?

[ Voor 3% gewijzigd door MasterTweaker op 09-05-2021 19:53 ]


Acties:
  • 0 Henk 'm!

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 12-05 19:27
martyw schreef op zondag 9 mei 2021 @ 19:29:
Eens met optie 2 van @Boeryepes, dit is typisch iets voor een command line - een C# programma is flinke overkill hiervoor. Of heb je deze gegevens nodig in een groter programma?
Ja ik heb dit nodig voor een windows desktop applicatie die ik momenteel ontwikkel. Een onderdeel hiervan is het ophalen van alle geïnstalleerde programma's met de bijbehorende application paths.

Acties:
  • 0 Henk 'm!

  • RagingPenguin
  • Registratie: December 2012
  • Niet online
MasterTweaker schreef op zondag 9 mei 2021 @ 19:35:
Dit lijkt mij zo de juiste oplossing :). Weet iemand trouwens of de Folder ID (de GUID code) die ik in dit stukje code opgeef op alle Windows systemen zou moeten werken?
{1e87508d-89c2-42f0-8a7e-645a0f50ca58}, je kan hier alle GIUD's zien.

Acties:
  • 0 Henk 'm!

  • MasterTweaker
  • Registratie: Maart 2010
  • Laatst online: 12-05 19:27
RagingPenguin schreef op zondag 9 mei 2021 @ 20:08:
[...]


{1e87508d-89c2-42f0-8a7e-645a0f50ca58}, je kan hier alle GIUD's zien.
These folders are installed with Windows Vista and later operating systems, and a computer will have only folders appropriate to it installed.
Ok dit zou dus moeten werken vanaf Windows Vista.

[ Voor 22% gewijzigd door MasterTweaker op 09-05-2021 20:12 ]


Acties:
  • 0 Henk 'm!

  • downtime
  • Registratie: Januari 2000
  • Niet online

downtime

Everybody lies

MasterTweaker schreef op zondag 9 mei 2021 @ 16:19:

Weet iemand een oplossing? Ik heb al een hoop gezocht online maar ik vind geen sluitende oplossing voor dit probleem.
Or all of the above...

Windows mist een uniforme methode om geinstalleerde applicaties te registreren. Er is zelfs geen noodzaak om uberhaupt iets te registreren. Iemand kan gewoon een executable in een random folder gooien met een shortcut in het start menu en dat werkt. Je mist dan misschien wat extra functionaliteit maar voor simpele applicaties is dat soms geen probleem.

Die Uninstall key is een goed voorbeeld. Als jij de gebruiker geen Uninstall functie wilt aanbieden dan is er geen reden om jouw applicatie daar te registreren.

De simpelste manier om de belangrijkste executables te scannen is misschien wel om gewoon de shortcuts in het Start menu uit te lezen. Vrijwel elke applicatie zet een shortcut in het Start menu en doorgaans wijst die naar de belangrijkste executable.

Het beste is om nog eens goed na te denken of je deze functionaliteit echt nodig hebt in de vorm die jij in gedachten hebt want eigenlijk probeer je nu te doen wat Microsoft zelf niet wil (of kan) doen. Probeer er omheen te werken of accepteer dat er geen perfecte oplossing is.

Acties:
  • 0 Henk 'm!

  • Rowwan
  • Registratie: November 2000
  • Laatst online: 23:50
Je hebt het ook over de 'main-executable'. Alhoewel ik begrijp wat je bedoelt, is dat ook nogal tricky. Vaak is deze er niet. Neem bijvoorbeeld een directory met een hoop tools (bijv. de bin directory van je compiler), of een directory met 'setup.exe', 'run32.exe' en 'run64.exe'?
Neem daarna de opmerkingen van andere Tweakers (niet alles registreerd zichzelf), en je zult zien dat het lastig is om het betrouwbaar te krijgen.
Pagina: 1