-1

I've developed a C# winforms application. The application requires another file to run, which is present in the same directory as the executable. Lets call this file a.abc. When I use command prompt, navigate to the program directory, and type the following to open a file with my program, it works fine:

my-prog.exe "path-to-file\file-name"

However, when I right click the file in explorer, go to open with, and select my program, the program for some reason tries to search for the file a.abc in the System32 directory and not in the application directory.

enter image description here

I know it will work fine if I use the complete file path instead of using the relative path, but I'm wondering why this is happening?

UPDATE #1

I have a string resource named reqdFileName with value toolset.f

And I'm accessing the file using

using (StreamReader sr = File.OpenText(@Properties.Resources.reqdFileName))
    // read lines and use it here
}
mrid
  • 5,782
  • 5
  • 28
  • 71
  • How exactly are you using that filename? What *is* the filename/path that you get through "open with" (could it be the absolute path you want, already)? – Hans Kesting Apr 07 '20 at 11:45
  • 1
    read about [process working directory](https://en.wikipedia.org/wiki/Working_directory) and [absolute and relative paths](https://en.wikipedia.org/wiki/Path_(computing)#Absolute_and_relative_paths) – vasily.sib Apr 07 '20 at 11:46
  • way to get the executing exe's path in .NET? https://stackoverflow.com/questions/1222190/what-is-the-best-way-to-get-the-executing-exes-path-in-net – user2316116 Apr 07 '20 at 11:52
  • What does your code do? Does it try to launch the second application with a *different* account, like System? That's a bad idea, isn't really needed, and *won't* use the working directory of the original application – Panagiotis Kanavos Apr 07 '20 at 11:54
  • @PanagiotisKanavos it doesn't. It simply just reads the required file with `File.ReadAllText("a.abc")` – mrid Apr 07 '20 at 12:39
  • @vasily.sib I already know about absolute and relative paths. I am asking why is it searching in the application directory when running via cmd and some other directory when using open with. Why is it searching in diff directories ? – mrid Apr 07 '20 at 12:44
  • @mrid post your code – Panagiotis Kanavos Apr 07 '20 at 12:51
  • @PanagiotisKanavos I've added the code i'm using to read the file as `Update #1` – mrid Apr 07 '20 at 13:38
  • Try adding your exe to your PATH environenment variable – Jonathan Alfaro Apr 07 '20 at 14:36
  • 1
    File extension association (Open with...) is complex and according to the error set a working directory in Windows directory (Windows Explorer's location). That's why you should always use absolute file paths. – Lex Li Apr 07 '20 at 15:43

1 Answers1

0

It's all about absolute and relative paths. As your path is relative, it is "prepended" with your process working directory.

So, when you run your program within your application dirrectory (say C:\MyProgram\) - path a.abc is equal to C:\MyProgram\a.abc. If you run it from different directory (say C:\) like this: .\MyProgram\my-prog.exe, then path a.abc is equal to C:\a.abc. You can get your current working directory with System.IO.Directory.GetCurrentDirectory() method to check this by your self.

When you use "Open with" menu - your current directory will be %windir%\system32 and this is "by-design", you shouldn't try to change this.


You can solve your problem by converting relative path to absolute path, like this:

using System.Reflection;
using System.IO;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
var reqdFilePath = Path.Combine(appPath, @Properties.Resources.reqdFileName);
using (StreamReader sr = File.OpenText(reqdFilePath))
    // read lines and use it here
}

Another option is to change your working directory somewhere in the beginning of your program:

using System.Reflection;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
Directory.SetCurrentDirectory(appPath);
// we are in your app directory now for sure

// ... Later in your code ...
using (StreamReader sr = File.OpenText(@Properties.Resources.reqdFileName))
    // read lines and use it here
}

However, in this case you should somehow restore your working directory at the end of your program, because this will be frustrating for your users if they will forcibly moved to some path at the end (i would hate such program if you ask me).

There is also a recomendation in some comment to add your app directory to the %PATH% evironment variable. This will do the trick, but please, don't pollute your %PATH% if you clearly don't need this. %PATH% is not limitless - here is a good explanation.


And just a side note. There is no real need to deal with streams and stream readers for reading a file line-by-line. There is a File.ReadAllLines() method:

using System.Reflection;
using System.IO;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
var reqdFilePath = Path.Combine(appPath, @Properties.Resources.reqdFileName);
foreach (var line in File.ReadAllLines(reqdFilePath))
{
    // use your line here
}

As I said, it will read it line-by-line, so it's ok to read a huge file (it will not load a whole file into your memory, just one single line at a time). If your file is not so big, you could also read it all in one shot into a single string with File.ReadAllText() method.

vasily.sib
  • 3,871
  • 2
  • 23
  • 26