To put it simply, if process A starts application B.
Whenever application B tries to do a relative file access such as
using(StreamReader sr = new StreamReader("log.txt"))
It accesses log.txt in the folder that process A is inside of, not the folder that application B is inside of.
Right now my current fix for this is to get my application's module file name + path, remove the file name and prepend the path variable onto all my relative file access calls.
What causes this and how can I avoid it?
In process A, where you launch application B, you should have specified the working folder.
Take a look at this: http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.workingdirectory.aspx
EDIT (after clarification from OP that process A is the task scheduler, and therefore cannot be modified)
I think the task scheduler allows you to specify the working directory for the application that you schedule. But in any case, even if you cannot, you can always set the current directory of your application to the right place first thing as soon as it starts, using SetCurrentDirectory().
Once you have access to the Process, you can try getting the Module. From here, you can access the full path of the process (using the FileName property) and, in turn, its directory.
string fullPath = myProcess.Modules[0].FileName;
string workingDirectory = System.IO.Directory.GetParent(fullPath);
According to this thread, 32-bit modules won't be able to enumerate modules of 64-bit assemblies, so you'll need to recompile your program to 64-bit if your target processes will be running in that mode.
Related
So i'm trying to write a program that will list all the installed programs on Windows and let user decided which one to be blocked(Killed).
I found the solution of List Installed program here. Get installed applications in a system
And to kill a program you just need the .exe name and kill all the process with that name.
But my problem is the names in the list of installed program is not necccesary the .exe name, and you couldn't find a process without the .exe name. For example, the installed program name is "Google Chrome" but the .exe or the process name would be chrome.
The current solution I can think of is to find out the installed directory of the installed program, find all the .exe files under it. And kill all of them if required. But I don't know how to get the directory of all the installed programs.
So, I can't help wonder, is there a more elegant of doing it. Any suggestions would be appreciated.
You have to split this question on 2 parts:
1. Find all the programs
What does it mean? It means that You want to find all the executable files (*.exe) on the hard drive of the client. This executable files does include the code which will run in the memory and do some work.
BUT: The code located on harddisk cannot be "killed", as the code (exe file) will start first new instance of application (via OS interface). Once You got the instance we can start talking about other part of question.
Also as stated there, You are unable to get easily 1 exe file, as multiple application might have multiple exe files. And if You really want to have them, You got to run analysis on the harddisk, like there:
var allExePaths =
from drive in Environment.GetLogicalDrives()
from exePath in Directory.GetFiles(drive, "*.exe", SearchOption.AllDirectories)
select exePath;
Also as Ivar stated in comments, there are multiple executables, like *.jar, *.pyc, ... which might be run via other executable file.
2. Kill the required program
If You want to kill some program/application, You need to get it's instance. Instance are distinguished by PID (process ID). Once You got this of the instance, You can kill it. Answer for this is there: How do I kill a process using Vb.NET or C#?
The code below will take all process with particular name and kill them all.
Code:
foreach ( Process p in System.Diagnostics.Process.GetProcessesByName("winword") )
{
try
{
p.Kill();
p.WaitForExit(); // possibly with a timeout
}
catch ( Win32Exception winException )
{
// process was terminating or can't be terminated - deal with it
}
catch ( InvalidOperationException invalidException )
{
// process has already exited - might be able to let this one go
}
}
I currently have a FileHandler.cs class which does various things with a file. The default directory for C# running within VisualStudio is Project/bin/Debug or Project/bin/release depending on which you are running. As such in the constructor of my file class I do the following:
System.IO.Directory.SetCurrentDirectory("..\\..\\TextFiles");
to go from either bin or debug to the main folder where I have my TextFiles folder. The issue with this is the next time I create a FileHandlerthe working directory goes up 2 more levels where TextFiles doesn't exist.
How can I set the working directory to the default bin/debug again without using an absolute path?
There are several hacks I could use such as making it static or incremnting a counter for each FileHandler created and raising the current directory by 2 levels for each one past the first, but both those solutions are rather messy.
Thanks, Kalen
I would not rely on the default directory. It can change depending on how the application starts. Instead, you can try to detect location of the executable and use it to construct the data path. Something like this:
var exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
// or AppDomain.CurrentDomain.BaseDirectory, see http://stackoverflow.com/a/837501/3246555
var dataPath = Path.Combine(exePath, #"..\..\TextFiles");
//Directory.SetCurrentDirectory(dataPath);
Also, it might be better to avoid SetCurrentDirectory and construct the full file path instead:
var filePath = Path.Combile(dataPath, "MyFile.txt");
I have a (rather huge) application which is depending on some resources residing in the same folder as the application (e.g. settings files, unmanaged libraries etc.).
I also have registered a URI-protocol for this application, so that every URI-call starting with xyz://... will launch my application with the respective parameters.
The problem is, that if you use the URI-call, the application will run from the %windir%/system32-folder, or the ../ProgramFiles/Chrome/...-folder (when the URI is called from my webbrowser). It will not run my application from the folder, which it resides in.
(you can probably see my problem already...)
If my app runs from the sys32-folder it will (naturally) not have access to the local libraries, which some of my P/Invoke functions need.
My question is: how can I run my application from the correct folder or prevent it being run from a folder like sys32?
And no - I do not like following idea:
if (Directory.GetCurrentDirectory().ToLower() != "/my/home/dir") {
MessageBox.Show("You have no power over here!");
Exit(1);
}
OK - this comment written by #MutantNinjaCodeMonkey helped me out in the end:
Directory.SetCurrentDirectory(#"c:\path\to\app");
"resets" the working directory to the desired path. In my specific case I used:
FileInfo nfo = new FileInfo(Assembly.GetExecutingAssembly().Location);
Directory.SetCurrentDirectory(nfo.Directory.FullName);
I have written a C# program that copys itself and moves in a precise source directory. It is working fine the first time it moves, but the second time the value of the current directory is wrong. To determine the file path I use :
string current = Directory.GetCurrentDirectory();
The second time the program wants to move, I call GetCurrentDirectory again but the value of "current" is still the old path and it gives me FileNotFound Error.
What can I do to make GetCurrentDirectory() read the new path ?
You need to execute your application in a new process. You are likely using the original process and its current directory won't change to wherever you copied your application to.
I don't know what you are trying to achieve with your application, but definitely execute each copy as a new process and allow the current process to terminate itself.
Keep track of where you moved it.
GetCurrentDirectory() is the working directory the program is executed from. That wont change when you simply move the executable ( it would change if you executed it again from the new location). So either create a new process and exec the exe in its new location, or just keep track location you moved it to. The later is far easier.
As a note, copying the exe file doesn't have any effect on the running instance of the program, since it's still running from the "old" location ( likely its actually loaded in memory at this point). To the running program, the exe file copy is just a file. Why are you doing this ?
If you want to execute the new exe and exit the old one then use this api and call
Process.start("new/path/to/exe");
Environment.exit(0);
If you are just in main, you could simply return instead of calling exit.
This should work, it might cause both programs to exit ( if this kills child processes) but I don't think it does.
Imagine I have a picture viewer application made with C# and .NET. I have already set the preferred application to view pictures to use the C# application.
I want to somehow let my program know where it has been invoked. How can I achieve this?
If you're using it to view pictures via shell associations, you can just check the picture filenames passed in on the command line. You can use Environment.GetCommandLineArgs to get the first filename:
// Should check to make sure there is at least one filename passed first...
string imageFilename = Environment.GetCommandLineArgs[1];
string directory = System.IO.Path.GetDirectoryName(imageFilename);
If you want the working directory, just check Environment.CurrentDirectory at startup...
I think you can use Environment.CurrentDirectory
The current directory (Environment.CurrentDirectory) of an application can change during execution. Additionally, the current directory may not be the directory in which the application resides, such as if a user runs it from a command line in an arbitrary directory by specifying an absolute path to the executable.
If you really want the "current directory" of the application, then use Environment.CurrentDirectory, but if you want to know the location of the application, you can use the following approaches:
System.Windows.Forms.Application.ExecutablePath
(if running a WinForm application)
System.Windows.Forms.Application.StartupPath
(if running a WinForm application)
System.Reflection.Assembly.GetEntryAssembly().Location