Program crashes when run not from own directory - c#

A basic question:
I have a C# Windows application which runs fine when executed from its own directory, by typing
program1.exe
but when I execute it from another directory giving full path like
d:/progs/myprog/program1.exe
it crashes. And I really need to do it this way :)
I suppose it is connected to reading some files by the program which are in the same directory. My suspected line is:
using (XmlReader OdczytywaczXML = XmlReader.Create(#"config.xml"))
Can it be the problem? I wouldn't like to give full paths to files as I'd like my program to work anywhere just by copying the files.
Oh, and I have no idea how to simulate such condition (running from another directory) while debugging - is it possible?

You should detect your program location and construct full path to config.xml in this case, for example:
var filePath = Path.Combine(
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
#"config.xml");
To simulate condition, go to project properties, page "Debug" and set Working Directory.

This is surely the problem. You can add directory information on that line. In WinForms you can use Application.StartupPath for example.
In General you can use System.Reflection.Assembly.GetExecutingAssembly().Location

The issue is that the Working Directory isn't the same when you just execute it from the command-line. You'll want to safeguard this:
var path = Path.Combine(Assembly.GetExecutingAssembly().Location, "config.xml");
using (XmlReader OdczytywaczXML = XmlReader.Create(path))
The Location property will do the following for you:
Gets the full path or UNC location of the loaded file that contains the manifest.
One thing to note here is that if you added a shortcut to the Desktop and set the Working Directory, before changing the code, you would find the application runs fine. Do that first to verify the fix worked.

Related

call exe using Process without absolute path

I wrote a program need to call an external exe using
Process proc = Process.Start(filepath).
I specify the absolute path of the exe and it works fine. However, I need to use this program in different computers. Each time the exe has a different absolute path and I need to change the code for this part. I would like to know is there a way that I don't need to change the code? Thanks in advance!
You are asking the wrong question. Is not how to modify the API to work with your fixed requirements ("launch process w/o knowing the path", ignoring for a moment what huge security problem that is). The question you should ask is How can I modify my code to match the API I use?
Since starting a process works better if a full path is given (it also works if the executable name is in %PATH%, but that is a different topic), have you app figure out the correct path and then launch the process. There are countless ways to achieve this. Probably the safest option is to use an App.Setting that points to the path. At deployment the app is properly configured with the location of the required program. there are (many) more ways to do this, it will all depend on what you're actually trying to solve, more details would be needed.
If both exe-files are in the same folder, then
winforms:
var filepath = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), otherexename);
Process.Start(filepath);
wpf:
var filepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, otherexename)
Process.Start(filepath);
In a windows service, you can do the following to get the directory of the currently running assembly, then to generate the right path to your exe:
var directory = Path.GetDirectoryName(
new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
var exeLocation = Path.Combine(directory,"myExe.exe");

Finding Install path of a program

I am new to C# and I have made a simple Windows Forms Application that basically updates the persons files for a game.
They have to manually move and delete certain folders just to change version every time. I have successfully accomplished this.
However before I start giving it out I really should improve it. I know I need to change the name of the processes and remove my descriptions ETC.
I have stumbled onto an error and instead of me taking a guess I think it is best to get an opinion from a more experienced person about how to do this.
I am going to use Inno Setup to make the installer for my application, this way I can be sure it will go into their program files 32 and 64 bit. So I know this will be in program files.
So now I am wondering if I have done this the correct way or not? I was using this format to find their program files:
string programFilesFolder = Environment.GetEnvironmentVariable("PROGRAMFILES(X86)") ?? Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
However, would this work on all windows systems(XP, Vista, Win7, Win8) and is it completely accurate? I was going to use the above, and then use this:
string PATCHSELECTOR = Path.Combine(programFiles, #"PATCH SELECTOR");
if (Directory.Exists(PATCHSELECTOR))
{
string GamereliteFolder = Path.Combine(programFiles, #"GAMERELITE~1");
if (Directory.Exists(GamereliteFolder))
And then I move the files using the string method. If the file exists it is deleted before I copy the file over from PATCH SELECTOR to GAMERELITE.
Also will windows XP support using the .exe with an assembly resource embedded which is making the program need to be ran as administrator? I previously was making the assembly work through UAC however that wouldnt always work if they have UAC off or if it is XP so I thought I would try the admin assembly instead.
Can anyone possibly give me some insight, ideas or links?
For executables (not sure for websites & web application) this returns the directory where the executable lives (it's actually the base path where the framework will probe for Assemblies to load, 99% of the the that's the same thing).
System.AppDomain.CurrentDomain.BaseDirectory
This method works for any executable located in a folder which is defined in the windows PATH variable:
private string LocateEXE(String fileName)
{
string path = Environment.GetEnvironmentVariable("path");
string[] folders = path.Split(';');
foreach (var folder in folders)
{
if (File.Exists(Path.Combine(folder, fileName)))
{
return Path.Combine(folder, fileName);
}
}
return String.Empty;
}
Usage:
string pathToEXE = LocateEXE("Example.exe");
Reference:
how to find the execution path of a installed software
How can I get another application's installation path programmatically?
Couple things:
Among the already stated answers, Assembly.GetExecutingAssembly().Location will also give you the full file path of the currently "executing" Assembly. (Alternatively, GetCurrentAssembly)
If I'm reading your question correctly, you're trying to find both your own location as well as another application's. I would highly recommend seeing if the other application has a registry key that specifies the exact location - it'll make your copy step WAY more stable.

Using WritePrivateProfileString to write path issue

I am using WritePrivateProfileString in c# (through DllImport) to store paths taken from textboxes on the interface. And the .ini file name is hardcoded in my application
string ini_file = ".\\config.ini";
However, when the file writing happens, the configuration file is written to the first path taken from the interface instead of writing it to the exe directory. Which is quite odd.
Debugging shows that the values are sent correctly to the WritePrivateProfileString but it still is written to the wrong location. Anyone knows why is that happenening?
I'd guess that something is changing the working directory of your process, most likely your code in the process. Note that the documentation has this to say:
If the lpFileName parameter does not contain a full path and file name for the file, WritePrivateProfileString searches the Windows directory for the file. If the file does not exist, this function creates the file in the Windows directory.
Now my guess is that this applies if you supply just a file name. Because your file name starts with . I believe that will force the function to start from the current working directory.
Having said all of that, and no matter what the cause of the problem is, you should use a fully-qualified path in order to make sure the file is written where you want it to be written. Whenever you want the file to go in a specific directory, it's always easiest to force that by using fully-qualified paths.
You can find the path to your executable using Application.ExecutablePath and then remove the file name part.
Another point to make is that the same directory as the executable may be a bad choice. If your program is installed under the Program Files directory then the directory which contains the executable will not be generally writeable. I think you should consider using a directory under in the user profile. Look for one of the Environment.SpecialFolder values.
Further to David Heffernan's answer - you can use
Path.GetDirectoryName(Application.ExecutablePath);
to safely get just the running application's folder part.
If you're in a dll rather than an executable, you can use
Path.GetDirectoryName(Assembly.GetAssembly(typeof(MyClass)).CodeBase);
Both require System.IO, and were originally posted here. Second example also requires System.Reflection).
Application data files are supposed to be written to the LocalApplicationData special folder.
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
You typically will not have permissions to write into the Program Files folder etc.

How do I debug my C# app and simulate that its running from a specfic folder?

How do I debug my C# app when it really needs to be running from a specific folder and not from bin/debug? One of the first things my program does for example is determine what set of tools will be presented based on the executable file it finds. But since its running from the debug folder it can't find them. I can add the file there but that seems silly. There has to be a better way. Plus, there's really a bunch of other thighs it does that really requires it to be running from the proper folder eg. Z:\test.
I thought it might be the "Working Directory" setting under the "Debug" tab in Properties but that didn't seem to do anything. I'm using VS2010 and C# btw...
I hope I'm making sense.
Thanks
You can specify another output folder for your build.
Try setting Environment.CurrentDirectory to the directory you want to simulate.
Environment.CurrentDirectory = #"C:\SimulateThisDirectory\";
You can use
System.IO.Directory.SetCurrentDirectory("your-path");
from your code.
You need to differ between two things:
path from which process is started
current working directory of the process
First one you can't simulate easily. It would probably involve creating a symbolic link or creating some sort of rootkit.
As for second one, your method is fine, and you can check working directory in runtime by using Directory.GetCurrentDirectory or set it using Directory.SetCurrentDirectory.
Take note that if you are looking up directory of executing assembly, you will get path from which process is started.
You can run your program from as normal from the specific directory and then just attach the debugger
http://msdn.microsoft.com/en-us/library/c6wf8e4z.aspx

What would cause the current directory of an executing app to change?

I have a C# application that includes the following code:
string file = "relativePath.txt";
//Time elapses...
string contents = File.ReadAllText(file);
This works fine, most of the time. The file is read relative to the directory that the app was started from. However, in testing, it has been found that if left alone for about 5 hours, the app will throw a FileNotFoundException saying that "C:\Documents and Settings\Adminstrator\relativePath.txt" could not be found. If the action that reads the file is run right away though, the file is read from the proper location, which we'll call "C:\foo\relativePath.txt"
What gives? And, what is the best fix? Resolving the file against Assembly.GetEntryAssembly().Location?
One spooky place that can change your path is the OpenFileDialog. As a user navigates between folders it's changing your application directory to the one currently being looked at. If the user closes the dialog in a different directory then you will be stuck in that directory.
It has a property called RestoreDirectory which causes the dialog to reset the path. But I believe the default is "false".
If the file is always in a path relative to the executable assembly, then yes, use Assembly.Location. I mostly use Assembly.GetExecutingAssembly if applicable though instead of Assembly.GetEntryAssembly. This means that if you're accessing the file from a DLL, the path will be relative to the DLL path.
I think the lesson should be don't rely on relative paths, they are prone to error. The current directory can be changed by any number of things in your running process like file dialogs (though there is a property to prevent them changing it), so you can never really guarantee where a relative path will lead at all times unless you use the relative path to generate a fixed one from a known path like Application.StartupPath (though beware when launching from Visual Studio) or some other known path.
Using relative paths will make your code difficult to maintain as a change in a totally unrelated part of your project could cause another part to fail.
In System.Environment, you have the SpecialFolder enum, that will help you get standard relative paths.
This way at least, the path is gotten internally and handed back to you, so hopefully if the system is changing the path somehow, the code will just handle it.
if you do somehting like
> cd c:\folder 1
c:\folder 1 > ../folder 2/theApplication.exe
The current working directory of the applicaiton will be c:\folder 1 .
Here is an example program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace CWD {
class Program {
static void Main (string[] args) {
Console.WriteLine(Application.StartupPath);
}
}
}
Build this in visualstudio then open a command prompt in the debug/bin directory and do
bin/debug > CWD.exe
then do
bin/debug > cd ../../
> bin/debug/CWD.exe
you will see the difference in the startup path.
In relation to the original question...
"if left alone for about 5 hours, the app will throw a FileNotFoundException"
Once the application is running, only moving, or removing that file from the expected location should cause this error.
greg
If you use an openfiledialog and the remember path property (not sure about the exact name) is true then it will change your current directory I think.

Categories