I have file that another process using it.
and I want to force closing the file. so that I will work on the fill.
I tried to use Handle.exe however it didn't find the process
would appreiciate some help here is my code:
Process tool = new Process();
tool.StartInfo.FileName = handlPath;
tool.StartInfo.Arguments = _pathDirectory + " /accepteula";
tool.StartInfo.UseShellExecute = false;
tool.StartInfo.RedirectStandardOutput = true;
tool.Start();
tool.WaitForExit();
string outputTool = tool.StandardOutput.ReadToEnd();
string matchPattern = #"(?<=\s+pid:\s+)\b(\d+)\b(?=\s+)";
foreach (Match match in Regex.Matches(outputTool, matchPattern))
{
Process.GetProcessById(int.Parse(match.Value)).Kill();
}
I'm sure, that if a program really holds an exclusive access to a file, it has a reason to do it. For example, Windows Explorer holds it when the file is in copying process.
Very often, programs open a file for a writing, but do not actively write to it. For example, when you open a document in MS Word, it is copied to the temp file and a source file is just "open for writing". You'll still have an exception if you use standard File.Open method, but you can copy it to a temp file using File.Copy.
Alternatively, you can explicitly specify FileShare.ReadWrite parameter and get an access to a file. In this case, other program will have problems with accessing a file.
If you have mentioned the file name or type it would have been more easier, anyway try using the cmd for this. Get the process name and replace ProcessName.exe of the following code.
First you'll have to add using System.Diagnostics; on top.
Process.Start("cmd.exe", "/c taskkill /F /IM ProcessName.exe");
Related
I'm trying to solve a problem i got. My job is to make little app, that will show text which is inside of .txt file in the app window, but for some reason they told me that i have to use # ShellExecute(use Process.Start).
Is there even a way to do it? Because when i use ShellExecute, that file opens in notepad after button press, which is, I guess, point of using Shell.
There is little code of what i tried to do, but without success.
Thanks in advice!
string filePath = #"C:\Folder\file.txt";
ProcessStartInfo psi = new ProcessStartInfo(filePath);
psi.UseShellExecute = false;
psi.RedirectStandardOutput = true;
psi.CreateNoWindow = true;
var proc = Process.Start(psi);
string s = proc.StandardOutput.ReadToEnd();
textBox1.Text = s;
Instead of using ProcessStartInfo, try StreamReader like this :
string filePath = #"C:\Folder\file.txt";
StreamReader sr = new StreamReader(filePath);
string s = sr.ReadToEndAsync().GetAwaiter().GetResult();
Console.WriteLine(s);
Use Async method to read all text without blocking.
If you absolutely need to do that, you can create a second application TxtToTextBox, which you can run from your first application using Process.Start (initialize ProcessStartInfo with the path to that application instead of the txt file).
Then you can give that process an argument pointing to the file using psi.Arguments = $"\"{filePath}\"; (this also adds quotation marks around your path, so spaces are escaped).
Then in your second application you can do the sane thing, and simply read the file with File.ReadAllLines(args[0]) and print that into your text box.
If possible, I would recommend talking to whoever told you to use Process.Start and asking them for more reasons as to why you should use is, as this is one of the most roundabout ways to do this I could think of.
I have a winforms application in C# where I have to open a certain Folder.
I use
System.Diagnostics.Process.Start(pathToFolder);
This results in the following exception:
System.ComponentModel.Win32Exception (0x80004005): Access is denied
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo
startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at MyApp.openLogFolderToolStripMenuItem_Click(Object sender, EventArgs e)
I have already checked the following things:
The folder exists
The user has rights to the folder (can open it in Explorer)
Another thing is that if I use Process.Start() to open a file inside this folder, it works.
Can anyone give me a hint?Cheers
Edit
My goal is to open the folder in Explorer.
The pathToFolder is something like H:\Something\App.Name\Log
According to Microsoft Doc's the System.Diagnostics.Process.Start(string) runs the file or process (and therefore does not open the folder). For opening a folder, this doc page sugests that you might do this with System.Diagnostics.Process.Start(string, string) where first should be a way to explorer, Total commander or something similar, and second should be a argument telling the used explorer what to do (open the folder pathToFolder).
I suppose that some system variable stores the value for "default folder viewer" but I do not know where. I will try to go for it and return later with the answer.
Hope that it helps.
EDIT: I did some quick digging around and to open the folder the following should do the trick:
System.Diagnostics.Process.Start(Environment.GetEnvironmentVariable("WINDIR") +
#"\explorer.exe", pathToFolder);
Where first argument is a path to classical windows explorer and second is the actual path to the folder itself.
It seem that widows does not by itself hold path to other "folder viewer" (such as Total Commander etc.), so this way is probably off the table.
Try this:
var psi = new System.Diagnostics.ProcessStartInfo() { FileName = pathToFolder, UseShellExecute = true };
System.Diagnostics.Process.Start(psi);
I usually use this to open file/directory:
public static void OpenFile(string path, bool isDirectory = false)
{
if (string.IsNullOrEmpty(path)) return;
if ((isDirectory && Directory.Exists(path)) || (!isDirectory && File.Exists(path)))
{
ProcessStartInfo pi = new ProcessStartInfo(path);
pi.Arguments = Path.GetFileName(path);
pi.UseShellExecute = true;
pi.WindowStyle = ProcessWindowStyle.Normal;
pi.Verb = "OPEN";
Process proc = new Process();
proc.StartInfo = pi;
proc.Start();
}
}
or
Process.Start("explorer.exe",path);
If this doesn't work it may be a permission issue after all.
You can set the working directory like this but you can't run the directory itself only files or exe
var startInfo = new ProcessStartInfo();
startInfo.WorkingDirectory = //working directory
Process proc = Process.Start(startInfo);
This error actually happens when there is a difference between the default behaviour of opening the file and the relative behaviour of opening the file.
For example, if you have selected the default application to open .pdf files as Internet Explorer, and you are trying to open the same file using Process.Start() method. You will receive an exception because as per the default operations it should open that file in Internet Explorer and your application is trying to open it using Adobe reader.
To rectify this set the default application for the .pdf file as Adobe Reader and you won't receive this error any more.
You can do this by, right-clicking on the file and then select, Default program or App. Further, select the default Program or App from the list of available programs and then select the Always use the selected program/App to open files of this type.
I am actualy creating a batch file from my C# application. (path contains accents for example)
using (System.IO.StreamWriter file = new System.IO.StreamWriter("file.bat", false))
{
var path = "C:\directory_été";
var whoot = #"#echo off" + Environment.NewLine + #"pushd %~dp0" + Environment.NewLine + path; // where path contains accents and such
file.Write(whoot);
}
When opening the .bat file with notepad.exe, everything looks written perfectly.
Then my app is running the batch.
var Info = new ProcessStartInfo();
Info.Arguments = "/C choice /C Y /N /D Y /T 3 & start /b \"myBatchTitle\" \"C:\\file.bat\"";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
Process.Start(Info);
The batch returns an error because it is not finding the "path" because it changed the accents into some garbage characters.
So, everything looks ok in the .bat itself, but when running it, it fails reading correctly cause of the encoding.(path echoed as "directory_ÚtÚ" when batch is ran, i cant even copy the Ú from cmd prompt cause its printed correctly here then lol)
How can i fix this please? (and not MANUALLY change characters one by one)
Or isn't there a way to encode the string in C# to OEM something so it will be reading correctly? (example change é to Ú already, for ALL characters)
(For more infos, the created batch file is running 7zip command line version, and the path i submit to it is containing the accents and such)
Otherway, do you know any portable-command-line alternative, accepting real UTF8 encoding so ll languages will be accepted?
I don't know what the appropriate code page is for C:\directory_été (maybe you do, since you are dealing with this file). You can try codepage 863, which is for Canadian French.
In any case, if you know the codepage, you could try changing code page via chchp xxx where xxx is the number identifying the code page you want to switch to. So you could try chcp 863. You can put this in your batch file before you use the path with the accents.
Why "1.bat" can't run successfully? Any help will be appreciate. "1.bat" was created successfully.It can run without error, but can't rename the files.
private void button1_Click(object sender, EventArgs e)
{
string str = System.Environment.CurrentDirectory;
str += "\\1.bat";
string txt = "";
txt = "ren *.mp3 *.wav";
StreamWriter sw = new StreamWriter(str,false, Encoding.UTF8);
sw.Write(txt);
sw.Close();
Process p = new Process();
p.StartInfo.FileName = str;
p.StartInfo.Arguments = "";
p.StartInfo.UseShellExecute = false;
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.Start();
}
One problem is that your file is being written with a UTF-8 BOM. Try passing Encoding.Default to test this out. Or pass new UTF8Encoding(false) as the encoding to pass a UTF-8 encoding that omits the BOM.
Another problem (which you just added in an edit) is that you set UseShellExecute to false. That requires the file you pass to be an executable file. Your file isn't. You need UseShellExecute to be true to allow the shell to work out how to process your .bat file.
And yet another possible problem is that the current directory may not be what you think it is.
When faced with problems like this there is no need at all to be helpless. Do some debugging. Add a pause at the end of your batch file and make sure that you can see the console. You'll find out immediately what the problem is. Learning how to debug is just as important as learning how to program. You won't be able to do the latter until you can do the former.
If I were having to do it this way, with an external process, I would:
Set UseShellExecute to false.
Pass cmd.exe as the executable file.
Pass the command to be executed as the command line.
However, it would be much easier to do this directly using C# and so avoid having to spin up external processes.
I am creating a File copy program which will copy large number of files(~100,000) with size ~50 KB using ROBOCOPY command.
For each file, I am creating a new process and passing the ROBOCOPY command and arguments as follow:
using (Process p = new Process)
{
p.StartInfo.Arguments = string.Format("/C ROBOCOPY {0} {1} {2}",
sourceDir, destinationDir, fileName);
p.StartInfo.FileName = "CMD.EXE";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.WaitForExit();
}
Instead of creating a process for each file, I am looking for a better approach, which will be good in terms of performance and design. Can someone suggest a better method?
This question is a bit old but I thought I would answer to help anyone who still land on it. I wrote a library called RoboSharp (https://github.com/tjscience/RoboSharp) that brings all of the goodness in Robocopy to c#. Take a look if you require the power of Robocopy in c#.
Process p = new Process();
p.StartInfo.Arguments = string.Format("/C Robocopy /S {0} {1}", "C:\\source", "C:\\destination");
p.StartInfo.FileName = "CMD.EXE";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.UseShellExecute = false;
p.Start();
p.WaitForExit();
/C Robocopy -> this is a command to run robocopy
/S -> This will help to copy sub folders as well as Files
I would just use System.IO. Should be plenty fast enough, and your filename could be a wildcard.
using System.IO;
// snip your code... providing fileName, sourceDir, destinationDir
DirectoryInfo dirInfo = new DirectoryInfo(sourceDir);
FileInfo[] fileInfos = dirInfo.GetFiles(fileName);
foreach (FileInfo file in fileInfos)
{
File.Copy(file.FullName, Path.Combine(destinationDir, file.Name), true); // overwrites existing
}
You should call File.Copy in a loop.
Robocopy can use up to 128 thread by itself. It makes a huge difference. By default it uses 8.
See https://pureinfotech.com/robocopy-multithreaded-file-copy-windows-10/
.cmd has following lines
Start ROBOCOY src dest a* b* c* /z /w:1 r:1
Start ROBOCOY src dest d* e* f* g* /z /w:1 r:1
Start ROBOCOY src dest h* K* P* Y* /z /w:1 r:1
Start ROBOCOY src dest xry* srp* /z /w:1 r:1
When I run > Robocopy sample.cmd
I starts with 4 multiple windows copying files simultaneously as per above commands, it waits
for another file, as it has wait time, if file is being used by another process. Is is more
faster as it do job simultaneously.
Now I am developing GUI using C# windows to run the process instead going to command console and
start
main()
{
process.start( "path of sample.cmd" )
process.waitforexit()
label.text=" sucessful copy"
}
However, if it takes control of one process, i.e. cmd.exe and and there are 4 robocopy processes in
taskmanager. when cmd.exe process completes, it returns the cursor to label.text "Sucesssfully
completed". While there are robocopy processes still running. you can see the robocopy windows
doing the copying process.
Here is the question: I want to take control of all the processes (cmd.exe and robocopy.exe)
programatically in C#, so that when the label.text should display "successfully completed" only
when all commands are successfully completed", if one fails, then there is no point in the GUI.
option 2 (similar to Biju has written above): is it better to remove robocopy command scripts from
sample.cmd(batch file) file and write code to run the 4 robocopy lines in C#, but how to run the
robocooy script line written .cmd file, as they have arguments as well. I code runs each robocopy
process then each will return to the next line of code and if it fails, we can catch the error and
display in the message box.
Hope this will help... However, I am looking for more better way, if somebody can improve on the same.