Question How can I programmatically locate an EXE file's path?

RobertAlanGustafsonII

Active member
Joined
Sep 16, 2023
Messages
37
Programming Experience
10+
WHAT I HAVE:
Visual Basic 2019, .NET Framework 4.6+, WinForms

MY ISSUE:

I would like my program to programmatically search for an exe file on my system drive and return its full path (so my program knows if and where it exists before trying to start the Process), but I've realized that the file is all but certain to be in a folder that one needs special permission to search (or a subfolder thereof)--i.e., "System", "Program Files", "Program Files (x86)"--complicating my efforts to use GetFiles/GetDirectories to look for it. Even trying do a single GetFiles method call on entire system drive with SearchOptions.AllDirectories causes an exception--and a targeted search within strategic folders (and their subfolders) causes many exceptions. Is there a (relatively) simple way for my app to programmatically obtain the necessary permissions for parent folders where program files are typically stored--or, better yet, a simple 1-step (or few-step) way to simply find the path of an arbitrary exe file? I want a VB.NET procedure that takes a String like ExeFile and returns a fully-qualified string for its entire path. Please give it to me ASAP in VB.NET, and as simply as possible.
 
Solution
Here is my solution(!!): To recursively go through the folders and subfolders looking for a given file or folder (or type thereof), starting with a parent folder, and skipping over subfolders that trigger access violations.
VB.NET:
    ''' <summary>
    ''' Recursively search for a file or folder from a given parent folder
    ''' (similar to Directory.GetFiles and Directory.GetDirectories with
    '''  SearchOption.AllDirectories, except that access errors are ignored,
    '''  and there is an option to stop once any match is found)
    ''' </summary>
    ''' <param name="PathName">Parent drive or folder to search from</param>
    ''' <param name="PathPattern">File/folder name pattern to search for
    ''' (defaults to search...
WHAT I HAVE:
Visual Basic 2019, .NET Framework 4.6+, WinForms

MY ISSUE:

I would like my program to programmatically search for an exe file on my system drive and return its full path (so my program knows if and where it exists before trying to start the Process), but I've realized that the file is all but certain to be in a folder that one needs special permission to search (or a subfolder thereof)--i.e., "System", "Program Files", "Program Files (x86)"--complicating my efforts to use GetFiles/GetDirectories to look for it. Even trying do a single GetFiles method call on entire system drive with SearchOptions.AllDirectories causes an exception--and a targeted search within strategic folders (and their subfolders) causes many exceptions. Is there a (relatively) simple way for my app to programmatically obtain the necessary permissions for parent folders where program files are typically stored--or, better yet, a simple 1-step (or few-step) way to simply find the path of an arbitrary exe file? I want a VB.NET procedure that takes a String like ExeFile and returns a fully-qualified string for its entire path. Please give it to me ASAP in VB.NET, and as simply as possible.

This is how I achieve what you are trying to accomplish:
Search for Executable File in VB.NET:
Imports System.IO
Imports System.Security.AccessControl

Module Module1
    Sub Main()
        Dim exeFile As String = "YourExecutable.exe"
        Dim fullPath As String = FindExecutablePath(exeFile)
        If Not String.IsNullOrEmpty(fullPath) Then
            Console.WriteLine("Executable found at: " & fullPath)
        Else
            Console.WriteLine("Executable not found.")
        End If
    End Sub

    Function FindExecutablePath(ByVal exeFile As String) As String
        Dim systemDrives As String() = Environment.GetLogicalDrives()
        For Each drive As String In systemDrives
            Dim path As String = SearchDirectory(drive, exeFile)
            If Not String.IsNullOrEmpty(path) Then
                Return path
            End If
        Next
        Return String.Empty
    End Function

    Function SearchDirectory(ByVal directory As String, ByVal exeFile As String) As String
        Try
            For Each subDir As String In Directory.GetDirectories(directory)
                Dim files As String() = Directory.GetFiles(subDir, exeFile, SearchOption.TopDirectoryOnly)
                If files.Length > 0 Then
                    Return files(0)
                End If
                Dim result As String = SearchDirectory(subDir, exeFile)
                If Not String.IsNullOrEmpty(result) Then
                    Return result
                End If
            Next
        Catch ex As UnauthorizedAccessException
            ' Handle the exception if access is denied
        Catch ex As Exception
            ' Handle other exceptions
        End Try
        Return String.Empty
    End Function
End Module
 
AccessViolationException has no place here, that is about exceptions regarding unmanaged memory, not file system access.

You may have noticed Directory and DirectoryInfo have iterator methods, like EnumerateFiles and EnumerateDirectories, the point of them is to return results as they are discovered and not wait until search is completed before returning. This has several benefits; it saves memory, consumer can process items early, and can also stop the search at any time when satisfied with what has been returned even if the iterator has not completed the source. See Iterators - Visual Basic about implementation details.

This is more a proof of concept, since as mentioned .Net has build in support now to ignore inacccessible, but if you're limited to .Net Framework you could do something like this. It is also an example of iterators. Since you intend to have a utility function for both files and directories the FileSystemInfo could be used like here:

VB.NET:
Private Shared Iterator Function EnumFileSystemInfos(folder As DirectoryInfo, lookForFile As Boolean,
    Optional recursive As Boolean = True) As IEnumerable(Of FileSystemInfo)

    Try
        For Each entry In folder.EnumerateFileSystemInfos
            If TypeOf entry Is FileInfo Then
                If lookForFile Then Yield entry
            Else
                If Not lookForFile Then Yield entry

                If recursive Then
                    Dim subfolder = DirectCast(entry, DirectoryInfo)
                    For Each recursiveEntry In EnumFileSystemInfos(subfolder, lookForFile)
                        Yield recursiveEntry
                    Next
                End If
            End If
        Next

    Catch ex As UnauthorizedAccessException
        'IgnoreInaccessible
    End Try
End Function

This method does not filter by pattern, but it will return either files or directories. So how to filter by pattern? This is called "globbing", see File globbing - .NET, and there exist a Nuget package for this called Microsoft.Extensions.FileSystemGlobbing. Then writing the SearchForPath method (also as iterator) becomes much simpler. It uses the previous EnumFileSystemInfos and "globs" the names, be it file or directory.

VB.NET:
Public Shared Iterator Function SearchForPath(pathName As String,
    Optional pathPattern As String = "*.*",
    Optional lookForFile As Boolean = True,
    Optional recursive As Boolean = True,
    Optional stopAtFirstFind As Boolean = False) As IEnumerable(Of String)

    Dim info As New DirectoryInfo(pathName)
    Dim globber As New Matcher
    globber.AddInclude(pathPattern)

    For Each entry In EnumFileSystemInfos(info, lookForFile, recursive)
        Dim result = globber.Match(entry.Name)
        If result.HasMatches Then
            Yield entry.FullName
            If stopAtFirstFind Then Return
        End If
    Next
End Function

It is not as fast as native file system filtering, but it does perform decently. It think it was also interesting to learn about "file globbing", imagine you have list of paths stored somewhere and want to filter them in memory like file system does, then that package is a simple solution. It also allows for more advanced filters with multiple inclusions and/or exclusions.

What namespaces/classes need to be imported for these two functions to work?
 
System.IO and Microsoft.Extensions.FileSystemGlobbing
 
I can't find the NuGet package for Microsoft.Extensions! When I lvrowse for it, I can't find it. When I try to install it with the PM console, it says "Object not set to an instance of an object".
 
Last edited by a moderator:
I'm using VS 2022 and it shows up when I search:

1741525946921.png
 
Back
Top