I have some strange problem (for me).
There is an application which is a windows form application "firstapp.exe".
There is another application which is windows form application too "launcher.exe".
And there is a console application with name "server.exe".
Both firstapp and launcher are in the same directory. In that directory there is also a "Config" folder with some other files in it.
The code which I use to read one file from config folder in firstapp:
StreamReader reader = new StreamReader("Config\\launcher.txt");
string readed_config = reader.ReadToEnd();
reader.Close();
If I run the firstapp application with launcher (using process.start) all goes fine.
When I run it with console application, which is not in the same directory as firstapp I get the "directory not found exception" from that part of code (posted above).
How can I solve the problem?
Why is console application adding its own path to another application which should run independently?
Sounds like you need to set the WorkingDirectory property of your Process before calling Process.Start.
string launcherPath = #"C:\SomePathToLauncher\Launcher.exe";
myProcess.StartInfo.FileName = launcherPath;
myProcess.StartInfo.WorkingDirectory = Path.GetDirectoryName(launcherPath);
myProcess.Start();
StreamReader reader = new StreamReader("Config\\launcher.txt");
Never use hard-coded relative file paths in your code. It critically depends on Environment.CurrentDirectory and that's way too unpredictable. External code can kill you as you found out. Internal code as well, use OpenFileDialog and your code will crash. You can always get a full path with Assembly.GetEntryAssembly().Location and the Path class:
var exedir = Path.GetDirectory(Assembly.GetEntryAssembly().Location);
var path = Path.Combine(exedir, #"Config\launcher.txt");
using (var reader = new StreamReader(path)) {
//...
}
Now it always works.
It's because your path is relative and the Current Working Directory is different when the console app kicks off your winform. Also, you should wrap the stream reader in a using statement. As it stands, unless you explicitly call Dispose() elsewhere in your code you're holding on to resources that should be freed.
To fix your problem either change the WorkingDirectory when you start the process using Process.StartInfo.WorkingDirectory or change the path in your code so it is not relative. Or another option would be to pass the path to the application or read it from a resource file so that it can be given the appropriate path when it executes.
the answer is in the question. you are saying that "When I run it with console application, which is not in the same directory". if it's not in the same directory how will it find a directory "Config" if it diesn't exist there. make sure that the directory exist there
Related
I have this code that creates, check the existence, deletes, etc a file:
string _myFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MyFile.txt");
Debug.Print(_myFilePath);// C:\Users\leode\AppData\Local\MyFile.txt
Debug.Print(File.Exists(_myFilePath).ToString());// False
File.Create(_myFilePath).Close();
Debug.Print(File.Exists(_myFilePath).ToString());// True
File.Delete(_myFilePath);
Debug.Print(File.Exists(_myFilePath).ToString());// False
When I run it, the file is not created in LocalApplicationData directory (in my case "C:\Users\userName\AppData\Local\"), but in a different subdirectory that I found doing a search with the windows file explorer (in my case this subfolder was "C:\Users\userName\AppData\Local\Packages\F0C6F5FC-4B4B-478D-958D-BAD69252637E_9zz4h110yvjzm\LocalCache\Local").
The program runs correctly, but How can I get this real directory where File.Create(), File.Exists() and File.Delete() are interacting with "MyFile.txt"?
Here is the answer, in a Microsoft Learn course.
You can access the sandbox using the AppDataDirectory static property of the FileSystem class:
string path = FileSystem.AppDataDirectory;
Example. FileSystem.AppDataDirectory returns
"C:\Users\{UserName}\AppData\Local\Packages\8BD0CA74-EE25-4D2F-8CF1-FCA28BBCD548_9zz4h110yvjzm\LocalState"
This is the right place to store local data in a device.
I have an IE plugin which adds buttons in a page where there are pdf links and opens them in a specific application when clicked.
Lets say I need to open a xyz.pdf file in abc.exe application. abc is not the default application for file type .pdf.
In one machine the below works
Process p = Process.Start("pathtoabc.exe", "pathtoxyz.pdf");
In another machine it only works if I make abc.exe as the default app and then use the below
Process p = Process.Start("pathtoxyz.pdf");
Can you give me any pointers please? I also tried using ProcessStartInfo with no change
Updates:
I tried using the default Acrobat reader with an argument
Argument for processstartinfo looks like this "C:\PDF Files\Professional-Letters-Guide.pdf"
FileName = "C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.exe"
Result - Acrobat reader opens but with an error message "File not found". The is available in the path though.
Solved:
It was a space in the Foldername.. solved it by enclosing the filename with quotes "\""
Thank you all for the suggestions.. they helped me think it through.
Have you tried qualifying the Process.StartInfo.Arguments value with quotes and the full path to the file? What about the WorkingDirectory property? Also, the previous assertion regarding confirmation of the application being called supporting command line parameters is absolutely valid. You can be fooled into thinking that it does due to operating system file extension associations specific to a machine.
The second parameter of the Process.Start is passed to the application you are trying to start and it wont open the file using this application "pathtoabc.exe" unless the application "pathtoabc.exe" accepts the file name as a startup argument.
So you need to check if the application you are trying to use supports this kind of argument.
I'm trying to find out a way to run a CMD process in my WPF application without the need to write the CMD application to the user's temp directory.
The application I have created is essentially a wrapper to execute another CMD application and the intent is as follows:
Install the application to the user's Program Files directory.
The directory that the app installs would also have a folder labeled something like "resources" that would hold the CMD application (upgrade.exe) and a file that the CMD application requires (image.bin).
Run the application either from a shortcut on the desktop or from the Start menu.
When the application needs to, call the upgrade.exe CMD application from the Program Files location it resides ("C:\Program Files\appname\resources\upgrade.exe").
What I have right now is code that writes the file to the user's temp directory and then runs it from there (code below). Both of the files are added to my solution as Resources to the project but if I need to do something different with them to use them, that's no problem. I don't know if there is a way to know exactly the location as I described it above but, if there is, how would I go about changing my code to work that way?
path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "upgrade.exe");
File.WriteAllBytes(path, Properties.Resources.upgrade);
imagepath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "image.bin");
File.WriteAllBytes(imagepath, Properties.Resources.image);
ProcessStartInfo processSetup = new ProcessStartInfo(path)
{
WorkingDirectory = System.IO.Path.GetTempPath(),
Arguments = String.Format("-F -p {0} -f image.bin, UserComPort),
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardOutput = true
};
update = Process.Start(processSetup);
I don't love this method because it puts my files into a different location than where I would like them to reside permanently on the user's PC, even though I know I can delete them after I'm done using them.
Any help would be greatly appreciated.
EDIT: As indicated below, the correct solution was to use the AppDomain.CurrentDomain.BaseDirectory location and then append the known directory location to that path. You have to know where your resource is going to go in your program's directory structure to use this method (I used Inno Setup and defined the "Dir" that I wanted those resources to reside). The final solution is below:
path = AppDomain.CurrentDomain.BaseDirectory + "resources\\upgrade.exe";
imagepath = AppDomain.CurrentDomain.BaseDirectory + "resources\\image.bin";
This results in a much cleaner solution that does not require writing the file to a new location on the user's PC. Thank you to Phil N DeBlanc for this solution!
If I understand what you're asking, I think you can find a solution here. You can get the current executing directory then append the necessary remaining path information to your CMD directory.
So I'm making a Tic Tac Toe application and have created a Text file linked to the program to hold the following information:
the name
the time took to win
the difficulty
I know the timer is redundant for a quick game like Tic Tac Toe but I'll use it in the future for other programs.
My question is how can I find the full path of the file while only knowing the name of the file?
I want to do this using the program so it can be transferred to any computer and still be able to access the file without the user having to input it.
The code I've tried is:
string file_name = Path.Combine(Environment.CurrentDirectory, "Tic Tac Toe\\HighScores.txt");
But this just looks in the Debug folder, where the file isn't located. The application is entirely a console application.
Try to dedicate the file in a fixed sub directory:
\TicTacToe.exe
\settings\settings.cfg
So the path is dependent of your executable file.
You'll fetch the directory by calling Directory.GetCurrentDirectory()
You can set a desired directory by setting Environment.CurrentDirectory
A common way to handle this case is the one described above.
Another would be to use user specifiy directories like the %appdata% path and create a dedicated directory there.
%appdata%\TicTacToe\settings.cfg
Everytime your application starts it should lookup the folder %appdata%\TicTacToe\
If it is present, your application has been executed with this user.
If not, just create a new one, so we know it's the first run.
You can get the %appdata% path by calling
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
Example of what i would have done
private void setUp(){
string filename = "settings.cfg";
string dir = "TicTacToe";
string appdata =Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string fullpath = Path.Combine(Path.Combine(appdata,dir),filename);
//check if file exists, more accurate than just looking for the folder
if(File.Exists(fullpath )){
//read the file and process its content
}else{
Directory.CreateDirectory(Path.Combine(appdata,dir)); // will do nothing if directory exists, but then we have a bug: no file, but directory available
using (FileStream fs = File.Create(fullpath))
{
Byte[] info = new UTF8Encoding(true).GetBytes("This is some text in the file.");
// Add some information to the file.
fs.Write(info, 0, info.Length);
}
}
}
Hope it helped.
Perhaps have a configuration file for your application and store the directory name in there.
An old example from MS, but should still be applicable...
How to store and retrieve custom information from an application configuration file by using Visual C#
I have created a .msi by using VS2008 setup project. My application frequently writes some value in a .txt file in the application directory (C:\Program Files\MyApp\MyFile.txt). After insalling it in Win7, it raises an exception "Access to the path .... is denied."
But whenever I run it as administrator, no such exception occurs. Here is my sscce
string FilePath=Application.StartupPath + #"\AppSettings\CurrentUserName.inf";
using (StreamWriter writer=new StreamWriter(FilePath,false))
{
writer.Write(txtLoginName.Text.Trim());
}
MainForm.ProcessLogIn();
this.DialogResult = DialogResult.OK;
I don't know how to solve this problem. Any suggestion?
Move your file out of Program Files directory. In Win7 is readonly for normal users.
You could move the file in the ProgramData directory.
Your installer should create a directory for your application there.
Then inside your code you could retrieve the correct full pathname using these lines of code
string dataPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
string appFile = Path.Combine(dataPath, "MyAppDir", "MyFile.txt");
usually (on Win7) this result in a path like this
c:\programdata\MyAppDir\MyFile.txt
but using the SpecialFolder enum you are guaranteed to use a folder available in readwrite to your application not depending on the current operating system.
The only way to solve this problem is to not write to that folder. You are not allowed to write to that folder by convention, unfortunately, older versions of Windows did not hold you to this.
Instead, you can use Environment.SpecialFolder to help you find where you need to go:
// your application data for just that User running the app
var perUserAppData = Environment.GetFolderPath(
Environment.SpecialFolder.ApplicationData);
// your application data for ALL users running the app
var allUsersAppData = Environment.GetFolderPath(
Environment.SpecialFolder.CommonApplicationData);
// better!
var path = Path.Combine(perUserAppData, #"MyApp\MyFile.txt");
Basically, Windows 7 is telling you that you're going to have to stop driving on the sidewalks and use the street as was intended.
As a short-term fix, you can use ICACLS to grant write access to the file. Note: NOT the whole directory.
As a longer term fix, you should NOT write to the program directory if you are running as unprivileged users, but instead somewhere like %LOCALAPPDATA% or %APPDATA%.