11

To clarify: The question is really: How do I locate the Mercurial command line client. If the answer is applicable to any executable, so much the better, but I'm really interested in the hg.exe executable file.

If I know the name of an executable, say hg.exe, the Mercurial command line client, and Windows knows where it is because I can execute just hg log from a command prompt and it executes, what steps are involved in order for me to find that executable myself, in the same manner that the command prompt and Windows does it?

Basically, if Windows is able to locate it, I want my program to be able to locate it.

Is there a WinAPI function, or similar? The code will run in .NET, written in C#, so if there's anything built into .NET for this that would be the preferred solution, but otherwise I'm not adverse to using P/Invoke for this.

I've seen one potential duplicate of this question: c# Check if an executable exists in the windows path, but is that all there is to it? Just iterate over the contents of the PATH environment variable and looking in each of those directories for the executable?

I have a vague notion that that's just one of the steps involved, and possibly that there are registry overrides that Windows can use that I should be aware of, so I'll post the question here.

If, on the other hand, there really is just the PATH variable in play here, it can probably safely be closed as a duplicate.

Community
  • 1
  • 1
Lasse V. Karlsen
  • 380,855
  • 102
  • 628
  • 825

4 Answers4

5

you can cheat and use the where.exe command

public GetFullPath(string program)
{
    string result;

    Process myProcess = new Process()
    {
        UseShellExecute = false,
        RedirectStandardOutput = true,
        StartInfo = new ProcessStartInfo(@"%SYSTEMDIR%\where.exe" )
    };

    using (StreamReader sr = myProcess.StandardOutput)
    {
        myProcess.Start();
        result = myStreamReader.ReadLine();
        myProcess.Close();
    }

    return result;
}
Greg Buehler
  • 3,897
  • 3
  • 32
  • 39
3

It depends on how the program is registered with the system. Since hg is generally run from either tools or the command line, it's not going to be registered with the system. If it were there's a set of registry keys that has the exe name and path. Otherwise, you just iter the path from the first entry to the last till you find the file you need. First one found on the path wins.

Examples of such a "registered" program, excel or winword.

EDIT:

@BillyONeal makes a good point below, that only works for "run" command programs, but my point was there was a second place to look.

Additionally, for those who haven't seen this, here's the install procedures:

An alternative scheme that works better for some is to search for hg on the PATH

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
jcolebrand
  • 15,889
  • 12
  • 75
  • 121
  • Ok, then that's what I'll do. The code isn't set in stone anyway, so if I find out more later, I can always change it. The PATH-method works nicely right now on the machines I tested it on, so I'll just stick with that for the time being. Thanks. – Lasse V. Karlsen Nov 09 '10 at 22:34
  • 1
    Not quite. "Registration" (or rather, the App Paths registry key) is only used when starting a process with ShellExecute (as done by "Run..."), but not by CreateProcess (as done by the command processor) – Billy ONeal Nov 09 '10 at 22:35
  • @BillyOneal good point, but I was about to post the URL from the hg group about how it's hinged on %PATH% anyways. – jcolebrand Nov 09 '10 at 22:36
  • Since it seems that HG.exe should always be in PATH, as per the documentation (I've found a couple of references to that now), I'll accept this answer. – Lasse V. Karlsen Nov 09 '10 at 22:48
  • This is what I ended up with: http://bitbucket.org/lassevk/mercurial.net/src/728f85d67447/Mercurial.Net/ClientWrapper.cs#cl-89 – Lasse V. Karlsen Nov 09 '10 at 22:50
2

Executables load according to the first matching instance in the system path. If executed from a shortcut or other mode that uses an absolute path, of course that's the version that runs, though.

DLLs are a bit more complicated - for native DLLs there are overrides, perhaps that's what you are thinking about? See here.

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • @drachenstern - just trying to speak to what the vague notion might be that spoken of in the question. – Steve Townsend Nov 09 '10 at 22:47
  • ~ true enough. And for dlls I wouldn't try to look on the path anyways, would that even work? system path YES, looking manually on %path% tho? – jcolebrand Nov 09 '10 at 23:03
  • @jcolebrand For libraries I would read the relevant manual. Otherwise I would basically always cheat and deliver all required libraries and therefore know the paths. – The incredible Jan Jan 20 '23 at 08:03
2

Windows provides the SearchPath function. If you pass NULL as the lpPath parameter, it uses the system search path. In your case you should call:

SearchPath(NULL, "hg", NULL, ...)

The C# declaration is:

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern int SearchPath(string path, string fileName, string extension, int numBufferChars, StringBuilder buffer, int[] filePart);
Michael
  • 8,920
  • 3
  • 38
  • 56