Delete a file which is used by another process in c# - c#

I am trying to delete one file which was used by certain another process of my Application.
So its giving an Error that file is used by certain another process.
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
DirectoryInfo NewDir = new DirectoryInfo(imagefolderpath1);
FileInfo[] files = NewDir.GetFiles("*.jpg");
foreach (var item in files)
{
string strFile = imagefolderpath1 + "\\" + item.ToString();
if (File.Exists(strFile))
{
File.Delete(strFile);
}
}
}
How should i solve this problem can you please help me????

You need to kill the process which is causing this issue by the following code, something like :
string fileName = #"D:\pathname.jpg";//Path to locked file
Process Handletool = new Process();
Handletool.StartInfo.FileName = "handle.exe";
Handletool.StartInfo.Arguments = fileName+" /accepteula";
Handletool.StartInfo.UseShellExecute = false;
Handletool.StartInfo.RedirectStandardOutput = true;
Handletool.Start();
Handletool.WaitForExit();
string outputTool = Handletool.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();
}
u can get Handle.exe from http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx

The file needs to be released by the other program before it can be deleted. You can use Process Explorer to find out what is locking it if you don't know.

you can't access the file used by another process. But if it's not critical for you app to do this later, you can do this in the System.AppDomain.ProcessExit event handler.
just add the file to a centrally managed list and register your cleanup routine like here:
AppDomain.CurrentDomain.ProcessExit += new EventHandler(deleteFilesIfPossibleNow);
in the handler you must still handle exceptions if files are still accessed from another processes.

instead of using _FormClosed you might want to try launching the form from your other code like this:
DirectoryInfo NewDir;
FileInfo[] files;
using (var form = new Form1())
{
var result = form.ShowDialog();
if (result == DialogResult.Close)
{
NewDir = new DirectoryInfo(imagefolderpath1);
files = NewDir.GetFiles("*.jpg");
}
}
foreach(var item in files) {
string strFile = imagefolderpath1 + "\\" + item.toString();
File.Delete(strFile);
}
i wasn't a hundred % sure how your program is meant to work but you can grab information from the forms before they close then close the files they were using after with this kind of method

Related

C# How to add new processes to a list of processes using a checkedlistbox

I am writing a windows forms application for a cleanup utility in which the windows forms application will execute multiple batch files with the same process attributes to cleanup various sections of the computer, this is what I have so far,
ProcessStartInfo[] infos = new ProcessStartInfo[]
{
new ProcessStartInfo(Environment.CurrentDirectory + #"example batch file 1"),
new ProcessStartInfo(Environment.CurrentDirectory + #"example batch file 2"),
};
I then execute them with,
Process[] startedProcesses = StartProcesses(infos, true);
The attributes for every process are contained within,
public Process[] StartProcesses(ProcessStartInfo[] infos, bool waitForExit)
{
ArrayList processesBuffer = new ArrayList();
foreach (ProcessStartInfo info in infos)
{
Process process = Process.Start(info);
if (waitForExit)
{
process.StartInfo.UseShellExecute = true;
process.StartInfo.Verb = "runas";
process.WaitForExit();
}
}
}
The issue is, I want to add new batch files to the list with if statements as I want the user to control what batch files are executed using a checkedlistbox eg,
ProcessStartInfo[] infos = new ProcessStartInfo[]
{
if (checkedListBox1.GetItemCheckState(0) == CheckState.Checked)
{
new ProcessStartInfo(Environment.CurrentDirectory + #"example batch file 1"),
}
if (checkedListBox1.GetItemCheckState(1) == CheckState.Checked)
{
new ProcessStartInfo(Environment.CurrentDirectory + #"example batch file 2"),
}
};
But this does not work... Is there anyway around this?
Kind regards, Jacob
In your last code fragment, you had syntax errors, because it's not a proper way to fill the array. I modified it, so it is a simple example and uses a List. It starts apps based on checked items. And you should show exactly what errors did you have.
private void button1_Click(object sender, EventArgs e)
{
List<ProcessStartInfo> startInfos = new List<ProcessStartInfo>();
if (checkedListBox1.GetItemChecked(0))
{
startInfos.Add(new ProcessStartInfo("notepad.exe"));
}
if (checkedListBox1.GetItemChecked(1))
{
startInfos.Add(new ProcessStartInfo("calc.exe"));
}
if (checkedListBox1.GetItemChecked(2))
{
startInfos.Add(new ProcessStartInfo("explorer.exe"));
}
foreach (var startInfo in startInfos)
{
Process.Start(startInfo);
}
}

Getting "File already in Use by other process" when using File.Move, why/how can I fix this?

I want to move several files that names are saved in an ObservableCollection<String> _collection with this method:
string firstFolderThatContainsEveryFile = "...\Folder\Files";
string secondFolderArchiv = "...\Folder\Files\Archiv";
foreach (var item in _collection)
{
string firstFolder = System.IO.Path.Combine(firstFolderThatContainsEveryFile, item);
string secondFolder = System.IO.Path.Combine(secondFolderArchiv, item);
File.Move(firstFolder, secondFolder);
}
This works at the first time, but if i load new files into firstFolderThatContainsEveryFile and try to use my move method i get an exception:
File already in Use by other process
This are the steps:
I open the programm -> use the move method -> success -> close the programm -> fill the folder with new files -> open the programm -> use the move method -> exception!
How can i get the processname or processID to close the process before i use my move method, or is there even a better way to get around this?
To figure out which process are using your file, with the solution proposed by this, you can use a tool Handle of Microsoft and this code C# to invoke the tool.
public void ViewProcess(string filePath)
{
Process tool = new Process();
tool.StartInfo.FileName = "handle.exe";
tool.StartInfo.Arguments = filePath + " /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))
{
try{
Console.WriteLine(match.Value); // this is the process ID using the file
}
catch(Exception ex)
{
}
}
}
If the file is using by the others program, you should figure why they use it, if by your program, so recheck your code to understand why.

Having problems deleting all files in a directory, then the directory itself

I am trying to delete a directory & all it's contents when I tap on a ContextMenu's MenuItem. However I seem to be running into to issues, as the files/directory aren't being deleted.
However I am not running into any errors, it just doesn't seem to work.
Here's my code so far:
private void gridSessionDelete_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
var item = (((sender as MenuItem).Parent as ContextMenu).Owner as Grid);
var title = (TextBlock)item.FindName("Title");
string directory = title.Text;
var appStorage = IsolatedStorageFile.GetUserStoreForApplication();
string[] fileList = appStorage.GetFileNames(directory + "\\*");
foreach (string file in fileList)
{
appStorage.DeleteFile(directory + "\\" + file);
}
appStorage.DeleteDirectory(directory);
bindList();
}
does anyone have any help on what I am doing wrong?
Thanks all help is appreciated!
Well, I can see a couple of places, where the error could be.
First, this line:
var item = (((sender as MenuItem).Parent as ContextMenu).Owner as Grid);
As you know, when you cast types with as keyword, the result might be null and no exception is thrown.
Second, and IMO most important:
This line:
string[] fileList = appStorage.GetFileNames(directory + "\\*");
That won't find anything. You should use "." (star-point-star) instead of "*"(star) in search request.
Also, when you work with IsolatedStorage, use using keyword, like:
using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
{
// your code
}
Does the code actually execute? Do breakpoints get hit? If so here is code that I use to delete all files in a directory. It does work for me. The main difference I see is in the DeleteFile method.
var storage = IsolatedStorageFile.GetUserStoreForApplication();
if (storage.DirectoryExists(directoryName))
{
foreach (var oldFile in storage.GetFileNames(string.Concat(directoryName, "\\*")))
{
storage.DeleteFile(Path.Combine(directoryName, oldFile));
}
}

Changing a programs process name in task manager?

Okay so I've been looking around and I can't find an answer anywhere.
What I want my program to do is every time I run it, the name that shows up in the task manager is randomized.
There is a program called 'Liberation' that when you run it, it will change the process name to some random characters like AeB4B3wf52.tmp or something. I'm not sure what it is coded in though, so that might be the issue.
Is this possible in C#?
Edit:
I made a sloppy work around, I created a separate program that will check if there is a file named 'pb.dat', it will copy it to the temp folder, rename it to a 'randomchars.tmp' and run it.
Code if anyone was interested:
private void Form1_Load(object sender, EventArgs e)
{
try
{
if (!Directory.Exists(Environment.CurrentDirectory + #"\temp")) // Create a temp directory.
Directory.CreateDirectory(Environment.CurrentDirectory + #"\temp");
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + #"\temp");
foreach (FileInfo f in di.GetFiles()) // Cleaning old .tmp files
{
if (f.Name.EndsWith(".tmp"))
f.Delete();
}
string charList = "abcdefghijklmnopqrstuvwxyz1234567890";
char[] trueList = charList.ToCharArray();
string newProcName = "";
for (int i = 0; i < 8; i++) // Build the random name
newProcName += trueList[r.Next(0, charList.Length)];
newProcName += ".tmp";
if (File.Exists(Environment.CurrentDirectory + #"\pb.dat")) // Just renaming and running.
{
File.Copy(Environment.CurrentDirectory + #"\pb.dat", Environment.CurrentDirectory + #"\temp\" + newProcName);
ProcessStartInfo p = new ProcessStartInfo();
p.FileName = Environment.CurrentDirectory + #"\temp\" + newProcName;
p.UseShellExecute = false;
Process.Start(p);
}
}
catch (Exception ex)
{
MessageBox.Show("I caught an exception! This is a bad thing...\n\n" + ex.ToString(), "Exception caught!");
}
Environment.Exit(-1); // Close this program anyway.
}
The process name in the task manager bases on the executable name without the extension, which you can not change while it is running.
Read the documentation:
The ProcessName property holds an executable file name, such as
Outlook, that does not include the .exe extension or the path. It is
helpful for getting and manipulating all the processes that are
associated with the same executable file.
in visual studio go to Project - Properties - Application - Assembly information and change Title
I would implement a host application to do this that simply runs and monitors a sub process (other executable). You may rename a file as such:
System.IO.File.Move("oldfilename", "newfilename");
and start the process like this:
Process.Start("newfilename");
This would mean that instead of one process you would have two, but the owner process only needs to be alive under startup - in order to change the name.

Refreshing FileVersionInfo in Program Files directory

I have a program with a FileSystemWatcher which watches for itself to be updated to a new version by an external program (which involves renaming the current executable and copying a new one in its place).
The problem is, when the file it's watching is in the Program Files directory, the FileVersionInfo.GetVersionInfo() doesn't get the new version information, it returns the same thing it got the first time. So if it updated from 1.1 to 1.2, it would say "Upgraded from 1.1 to 1.1" instead of "Upgraded from 1.1 to 1.2". It works correctly in the debug directory, but under Program Files, it won't get the correct value.
Here's the essence of what it's doing, without all the exception handling and disposing and logging and thread invoking and such:
string oldVersion;
long oldSize;
DateTime oldLastModified;
FileSystemWatcher fs;
string fullpath;
public void Watch()
{
fullpath = Assembly.GetEntryAssembly().Location;
oldVersion = FileVersionInfo.GetVersionInfo(fullpath).ProductVersion;
var fi = new FileInfo(fullpath);
oldSize = fi.Length;
oldLastModified = fi.LastWriteTime;
fs = new FileSystemWatcher(
Path.GetDirectoryName(fullpath), Path.GetFileName(file));
fs.Changed += FileSystemEventHandler;
fs.Created += FileSystemEventHandler;
fs.EnableRaisingEvents = true;
}
void FileSystemEventHandler(object sender, FileSystemEventArgs e)
{
if (string.Equals(e.FullPath, fullpath, StringComparison.OrdinalIgnoreCase))
{
var fi = new FileInfo(fullpath);
if (fi.Length != oldSize
|| fi.LastWriteTime != oldLastModified)
{
var newversion = FileVersionInfo.GetVersionInfo(fullpath).ProductVersion;
NotifyUser(oldVersion, newversion);
}
}
}
How do I make GetVersionInfo() refresh to see the new version? Is there something else I should be calling instead?
I'm answering my own question because there doesn't seem to be much interest. If anyone has a better answer, I'll accept that instead...
As far as I can tell, there is no way to make it refresh. Instead I worked around the issue:
return AssemblyName.GetAssemblyName(fullpath).Version.ToString();
Combined with code that makes sure it only gets called once, it seems to work just fine.

Categories

Resources