0

I get a Win32Exception File not found when trying to run an external executable (with dependencies) from a C# solution with the following code.

public static string TestMethod()
{
    try
    {
        Process p = new Process();
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.FileName = Path.Combine("dist", @"test.exe");
        p.Start();
    }
    catch (Exception ex)
    {
        expMessage = ex.Message;
    }
    return expMessage;
}

Remarks:

  • No exception occurs when an absolute path is specified as FileName.
  • In MS Visual Studio the dist subfolder files properties are set to the following and the distdirectory is indeed copied into the output folder:
    • Build action: Content
    • Always copy in output directory
  • I have tried with a test.exe.config file as follows but with no success:

<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="dist"/>
    </assemblyBinding>
  </runtime>
</configuration>

EDIT The only solution proposed in Specifying a relative path which actually works in this case is the one eventually provided as a comment by Viacheslav Smityukh combining AppDomain.CurrentDomain.SetupInformation.ApplicationBase to reconstruct the absolute path. However there seems to be a potential issue at runtime as stated in Pavel Pája Halbich's answer below. From How can I get the application's path in a .NET console application? I found out another solution based on Mr.Mindor's comment using the following code:

string uriPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
string localPath = new Uri(uriPath).LocalPath;
string testpath = Path.Combine(localPath, "dist", @"test.exe");

Now I wonder which one is the proper way considering a future deployment of the solution with Window Installer.

Antoine Gautier
  • 623
  • 8
  • 25

2 Answers2

1

The path to dist in your case is the current working directory, which isn't aligning with your expectations.

Try changing your path to:

Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "dist", @"test.exe");

Connor
  • 807
  • 1
  • 10
  • 20
  • You have two flaws - first, you are using just string instead of `BaseDirectory` property in a first parameter in `Path.Combine`. Moreover, `BaseDirectory` could be set in runtime, thus it is not a good practice (but it could work) – Pavel Pája Halbich Jul 25 '17 at 16:49
  • @Connor Thanks: it works as expected when combining `AppDomain.CurrentDomain.BaseDirectory`. However as it seems not to be recommended, is it satisfactory? Especially if I want to distribute the solution with Windows Installer later? I am surprised there is no canonical way to perform such a standard task. – Antoine Gautier Jul 25 '17 at 20:03
  • @AntoineGautier It's the way I've always done it. Pavel is right in that it can be set to something different when the AppDomain is created, but unless you're working with AppDomains (creating or destroying), you should be safe to use this. – Connor Jul 25 '17 at 21:12
0

You need to specify full path to that executable. So you can use System.Reflection.Assembly.GetExecutingAssembly().Location resulting in

Path.Combine(System.IO.Path.GetDirectoryName( iSystem.Reflection.Assembly.GetExecutingAssembly().Location), "dist", @"test.exe");

As you can se in this question How can I get the application's path in a .NET console application?, using AppDomain.CurrentDomain.BaseDirectory could work, but it is not recommened - it could be changed in runtime.

EDIT corrected answer for getting directory instead of full location to executable.

Pavel Pája Halbich
  • 1,529
  • 2
  • 17
  • 22
  • I have already tried combining `System.IO.Path.GetDirectoryName( System.Reflection.Assembly.GetExecutingAssembly().Location`. In my case it returns `C:\Users\Ang\AppData\Local\assembly\dl3\967GPNG9.0M7\DMDMB1C2.7XQ\b710451e\c711a674_7f05d301` and does not solve the issue. Even manually adding `dist` subfolder to this location during runtime does not help. – Antoine Gautier Jul 25 '17 at 19:55
  • I think the challenge with this approach is that it doesn't account for shadow copies, like if you are running the program from a network share for example. The assembly and folder you are technically looking for reside on the server and are not in the local copy that is being executed. – Connor Jul 25 '17 at 21:15