Can't Delete folder as it's in use. - c#

I have an issue with an auto update software that I am trying to make. The application runs as a server application and checks via FTP for updates and downloads them if there is a newer version available. This then unzips a folder called update in the programs root directory. it then launches a file called update.bat that does any file copying etc that I may need to do for that update. Once this is finished the update.bat launches the new server application. Once the program goes to check for updates again it is suppose to delete the update directory that is in the root directory of the server application as well as the update.rar file that was downloaded from the update server. All of this works perfectly except the folder is being used and will not delete. I have read all kinds of things about releasing the handle and changing the current directory etc.. but just can't seem to get it to work. I would appreciate someone helping me out here. Here is the code for this update.
private void Form1_Load(object sender, EventArgs e)
{
foreach (string s in Directory.GetDirectories("C:/my update dir"))
{
if (s.Contains("Instance"))
{
var _instance = Regex.Match(s, #"\d+");
Process p = new Process();
ProcessStartInfo pinfo = new ProcessStartInfo();
pinfo.FileName = "cmd.exe";
pinfo.WorkingDirectory = "C:/mySQL/bin";
pinfo.Arguments = "/C mysql.exe -u** -p** dbnameHere" + _instance.ToString() +
" < \"C:/my update dir/update/update.sql\"";
p.StartInfo = pinfo;
p.Start();
p.WaitForExit();
p.Close();
p.Dispose();
Directory.SetCurrentDirectory("C:/");
}
}
Directory.SetCurrentDirectory("C:/");
this.Dispose();
Application.Exit();
}

I'm going to guess that your problem is here:
Once this is finished the update.bat launches the new server
application.
Windows is going to "lock" the directories all the way down to the .BAT file. So if the .BAT runs a server process from that directory, that process is going to inherit the CWD and file descriptors of the calling process.
It's not clear from your code that this is what's happening, but you may also want to try changing the CWD prior to spawning the process.

Related

Using a .R file as a resource and create a batch directly in C#

I have a number of shiny applications with the file structure global.R, ui.R, server.R and something I call batchTrigger.R. The contents of the latter is simply the following-
.libPath(*Path to my R Package Repository*)
require('shiny')
runApp(*Path to the folder with the aforementioned files*)
I created a batch file called application.cmd with the following code-
cls
#pushd ""
:::::::::::::::::::
#echo off
ECHO Loading...Please, wait. The Application will open automatically.
ECHO ---
ECHO Do not close this console window for the whole duration of your session
ECHO in the application.
ECHO ---
#echo off
"C:\Program Files\R\bin\Rscript.exe" ".../**batchTrigger.R**"
:::::::::::::::::::
#popd
cmd /k
This batch file is working just fine. Then I went one step further, and decided to create a windows form with multiple R Applications. I have two buttons in the form, each of which goes something like this-
private void application1_click(object sender, EventArgs e)
{
System.Diagnostics.Process cmd = new Process();
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.FileName = "...\\**application1.cmd**";
cmd.StartInfo.Arguments = "/K";
cmd.StartInfo.CreateNoWindow = false;
cmd.StartInfo.RedirectStandardInput = true;
cmd.Start();
}
So far, so good. Both the buttons work exactly as they were supposed to. I want to go one more step ahead, but since I am very new at C#, I need help. What I am hoping to get is a dynamic location for the R files and the cmd files within the thus deployed application, within the solution. In other words, I should be able to write the contents of the batch file within the C# code, and the path of the batchTrigger.R should be something which changes with the location of the windows form application (which will be a self contained deployed executable file). The idea is that the R package repository and R installation may remain static and can be pointed at by the batchTrigger.R and application.cmd respectively, but the location of batchTrigger.R itself along with other R files move with the application. I think that resource.resx can do something about this, but how exactly can I go about doing it, I don't seem to get. Any suggestion would be highly appreciated.
Make a general method:
private void StartSilentR(string rScriptFilePath)
{
System.Diagnostics.Process cmd = new Process();
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.FileName = #"C:\Program Files\R\bin\Rscript.exe";
cmd.StartInfo.Arguments = rScriptFilePath;
cmd.StartInfo.CreateNoWindow = false;
//avoid this unless you must control the app via stdin
//cmd.StartInfo.RedirectStandardInput = true;
cmd.Start();
}
Then write something that calls it after working out where the script is. For example if you have your directory structure as:
RLauncherCSharpApp.exe
rscripts\ui.R
rscripts\global.R
rscripts\batchTrigger.R
Then in c# you can:
//take exe Path, remove exe name and add rscripts folder and batchtrigger.R file name
var rbt = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "rscripts", "batchTrigger.R");
StartSilentR(rbt);
Or, say you want to search all the subfolders of the app's folder looking for all files called batchTrigger.R:
var exeFolder = Path.GetDirectoryName(Application.ExecutablePath);
string[] paths = Directory.GetFiles(exeFolder, "batchTrigger.R", SearchOption.AllDirectories);
//maybe add them to a list view and the user can click one to launch ..

Why would reading a certifcate in a server.js started by a process cause the process to terminate?

I have a process which, on start, runs a node.js server. Trying to add HTTPS to the server results in the process which the server is attached to terminating. What could be causing this?
The process is started by a service written in C#. The process is then attached onto by the server.js. I've tried debugging the service to see which path of execution leads to the process being terminated by I couldn't track it down. Removing the lines form server.js that read the certificates results in the process not being terminated. However, I can't work out why that would be the case.
To read the certificates:
var privatekey = fs.readFileSync("xxx.pem", "utf8");
var certificate = fs.readFileSync("xxx.cert", "utf8");
var credentials = { key: privatekey, cert: certificate };
The setup of the Process:
var nodePath = GetNodePath();
// Get the path to the web files
var serverPath = ".\\server\\server.js";
// Create the process arguments
ProcessStartInfo info = new ProcessStartInfo();
info.WorkingDirectory = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
info.CreateNoWindow = true;
info.UseShellExecute = false;
info.FileName = nodePath;
info.EnvironmentVariables.Add( "NODE_ENV", "production" );
info.Arguments = $"{serverPath} --max-old-space=200";
I have an event handler for the exit of the process which is mostly below:
private static void webProcess_Exited( object sender, EventArgs e )
{
// Make sure we haven't restarted more than 10 times
if ( restartCount > 5 )
{
var message = "The xxx web service is being shut down due to the nodejs process expectantly terminating too many times.";
// Log to the event log
ShutdownService();
}
else
{
var message = "The nodejs process was expectantly terminated, restarting the process in 5 seconds.";
// Log to the event log
Thread.Sleep( 5000 );
//Starts the process/node.js server again
Start();
}
}
Starting server.js reading the certificates works fine. Removing the lines reading the certificate and running the service also works fine. But, for some reason, when reading the certificates and starting the node.js server through the service, it terminates/starts before terminating for good, as above.
Would anyone what could be causing this? Or suggest ways to troubleshoot this further?
Investigating the comment by #FrankerZ , I found that moving the certificate file from the directory the server.js is held to where the process assembly is fixed my issue. The reason the process terminated is, I assume, the working directory was set in the c# service to be where the assembly is (one level above the server.js). However, the certificate files were stored in the level below (alongside server.js). Thus, when I read the certificates, it is attempting to read them from the directory above where they actually are, resulting in the process terminating.

Problem with running exe file from c#

When I execute an exe file (PVFProject15.exe), it reads the data from an input file (inputFile.txt) and print the results in another file (outputFile.txt). The exe file works well when I double click it; It opens the console window which stays opened until the output file is created. However, when I run (PVFProject15.exe) from c#, the console window opens and closes very quickly and the output file is never created.
I would really appreciate your help since I have been working to fix this for a whole day and never found the answer. Here is my code below.
private void button1_Click(object sender, EventArgs e)
{
Process runFortran = new Process();
try
{
runFortran.StartInfo.FileName = "C:\\temp\\trial\\PVFProject15.exe";
runFortran.Start();
runFortran.WaitForExit();
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Thank you in advance.
Safaa
Probably PVFProject15.exe needs current directory to be set to C:\temp\trial
If PVFProject15.exe writes to file using relative path, look for outputFile.txt in directory from which you start your main program-bootstrapper.
I also meet with same problem, when I try start some .exe and .hta from my C# based software.
I start to looking for solution and answer of Mike Mozhaev get to me right direction.
In your code you need to use:
StartInfo.WorkingDirectory = Convert.ToString( System.IO.Directory.GetParent(appPath));
So code have to be like this:
if (File.Exists(appPath))
{
Process runProcess = new Process();
runProcess.StartInfo.WorkingDirectory = Convert.ToString( System.IO.Directory.GetParent(appPath));
runProcess.StartInfo.UseShellExecute= true;
runProcess.StartInfo.FileName = appPath;
runProcess.Start();
}

How can I make my .NET application erase itself?

How can I make my C# app erase itself (self-destruct)? Here's two ways that I think might work:
Supply another program that deletes the main program. How is this deleter program deleted then, though?
Create a process to CMD that waits a few seconds then deletes your file. During those few seconds, you close your application.
Both of those methods seem inefficient. I have a feeling that there's some built-in flag or something in Windows that allows for such stuff. How should I do it? Also, can you provide some sample code?
UPDATE: Thanks for all your answers! I'm going to try them, and see where that gets me.
First of all, some people have asked why I'd want my app to do this. Here's the answer: a few days ago, I read the Project Aardvark spec that Joel Spolsky posted on his blog, and it mentioned that the client app would delete itself after the remote session. I'm wondering how this works, and how, if I ever need to do this, I can accomplish such a feat.
Here's a little overview of what's been suggested:
Create a registry entry that tells Windows to delete the file on reboot
Launch CMD with a ping command to wait a few seconds and then delete the file
Both of those, of course, have their disadvantages, as outlined in the comments.
However, would such a method as outlined below work?
There are two executables: Program.exe and Cleaner.exe. The former is the program itself, the latter is the app that deletes Program.exe and itself (if it's loaded into memory, as I'm about to explain). Is it possible for Program.exe (which has dependencies) to load all of Cleaner.exe, which doesn't have any dependencies, into memory and run it?
If this is possible, could Cleaner.exe be packaged inside Program.exe, loaded into memory, and run?
There's a MoveFileEx API, which, when given a MOVEFILE_DELAY_UNTIL_REBOOT flag, will delete specified file on next system startup.
There's a great CodeProject Article about this topic.
Edit: Basically it's a simple cmd-call which will delete the specified files after some seconds.
Process.Start("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 3000 > Nul & Del " + Application.ExecutablePath);
Application.Exit();
You will never be able to guarantee that this will work, as long as you require a physical presence on the machine. For example:
What if the app fails to release a resource in a timely fashion while you're trying to delete it? An error occurs, and the app remains.
The behavior of one app starting another which then deletes the first app is very suspicious from an AV perspective. You are likely to trigger defenses on a user's machine which may kill the process that's trying to kill your original app.
If you do something like delete a file at reboot, what if the user moves your file in between or makes a copy? It's not in the original spot anymore, and the app remains.
If your application requires this level of security, consider hosting it on a machine you control (e.g., by providing a web service and letting a stub client access it that way).
On a somewhat related note, one is also tempted to speculate about the motives of someone who (1) requires a physical presence on someone's machine and (2) wants to delete the evidence that the app existed.
A correction to #Bobby answer, in case people will find it useful - executable path needs to be quoted. Additionally, below is setting cmd.exe window to be hidden (otherwise it flashes as a black console window) and converted to run without relying on System.Windows.Forms assembly (the Application class).
var exepath = Assembly.GetEntryAssembly().Location;
var info = new ProcessStartInfo("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 3000 > Nul & Del \"" + exepath + "\"");
info.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(info).Dispose();
Environment.Exit(0);
There is also FileOptions.DeleteOnClose, but that requires the file to be open for writing. You might be able to do it with a sequence like this (untested):
Program launches as Original.exe, and detects (from its own name) that it needs to trigger the self-destruct function.
Original.exe creates a new file Temp.exe with FileOptions.DeleteOnClose and copies its own content into it, but does not close it yet
Original.exe opens a second, read-only handle to Temp.exe and closes the first write handle. The read-only handle can co-exist with an execute handle, whilst keeping the file open to delay auto-deletion.
Original.exe launches Temp.exe. Temp.exe detects that it has been launched from the temp directory and bypasses the self-destruct sequence and continues normal operation.
Original.exe exits (taking its read-only handle to Temp.exe with it.)
Temp.exe continues running. When it exits, the file Temp.exe will no longer be in use so it will be deleted automatically.
Edit #2: Actually I don't think this is possible, because it relies on the kernel opening the file with the FILE_SHARE_DELETE flag, which is unlikely.
sorted by NJ
c#
the other codes does not work so its simple
if u create bath file that loops to del application and
the batch file itself
u can use takkill command to kill the process if u dont want to use
application.close method
`string delname = "test.cmd";
string fileurl = Application.ExecutablePath;
System.IO.StreamWriter file = new System.IO.StreamWriter(delname);
file.WriteLine(":Repeat");
file.WriteLine("del \"" + fileurl + "\"");
file.WriteLine("if exist \"" + fileurl + "\" goto Repeat");
file.WriteLine("del \"" + delname + "\"");
file.Close();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.FileName = delname;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);`
`
Th3 3e3 one is not 3d parts ov one
I5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Think CMD
int sectosleep = 5000;
string exename = "yourexe.exe";
string location = #"c:\yourexe.exe"
Process.Start("cmd.exe", "/C taskkill /f /im " + exename + " & ping 1.1.1.1 -n 1 -w " + sectosleep + " > Nul & Del /F /Q \"" + location + "\"");
;>
I know reflector deletes itself if you use an old version and choose not to update. You might try to figure out what it does. I would start with FileMon and see if it spawns any processes to achieve this.
Since my application (a Windows Service) is installed via the Windows Installer, I self-delete using this:
Dim uninstall_params As String = "/x {MY-PRODUCTS-GUID} /qn /norestart REBOOT=ReallySuppress"
proc.StartInfo = New ProcessStartInfo("msiexec.exe", uninstall_params)
proc.Start()
Environment.Exit(-1)
Sorry--it's in VB, but it should be easily convertible to C#.
Works in Windows 7 & 8, **ENSURE you run your application with admin privileges or you will get an error.
This code exists elsewhere so I can't take full credit I found I made it work for me by adding "Application.Exit();"
static void autodelete()
{
string batchCommands = string.Empty;
string exeFileName = Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", string.Empty).Replace("/", "\\");
batchCommands += "#ECHO OFF\n"; // Do not show any output
batchCommands += "ping 127.0.0.1 > nul\n"; // Wait approximately 4 seconds (so that the process is already terminated)
batchCommands += "echo j | del /F "; // Delete the executeable
batchCommands += exeFileName + "\n";
batchCommands += "echo j | del deleteMyProgram.bat"; // Delete this bat file
File.WriteAllText("deleteMyProgram.bat", batchCommands);
Process.Start("deleteMyProgram.bat");
Application.Exit();
}
This is the Uninstall.exe:
Shutdown.
Wait for 3 sec.
Try to kill that task if it is still running.
Wait for 3 sec.
Delete the app directory with the Uninstall.exe in it.
public void Uninstall()
{
var delPath = AppDomain.CurrentDomain.BaseDirectory;
var procId = Process.GetCurrentProcess().Id;
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/C timeout 3 & Taskkill /F /PID {procId} & timeout 3 & rd /s /q \"{delPath}\"",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(psi);
Application.Current.Shutdown();
}

Running console application from C# but application can't create file

I have windows forms application wich runs another console application
here is the part of code
prog = new Process();
prog.StartInfo.FileName = exefile;
The console application should create file but when running that application from C# it doesn't creates any file
when im running console application with double click it works fine
here is the part of code from "exefile" (its on c++)
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
printf("somedata\n");
"file.in" surely exists
The most likely thing is that you need to set the working path:
prog.StartInfo.WorkingDirectory = ...
i.e. I'm thinking it can't find file.in in the current app folder.
You need to add this line whenever you want to start the process:
prog.Start();
Here is the link to the MSDN page for Process.Start. There are several overloads that you may want to consider.
I would suggest,
handle exceptions to see what's going wrong
like mentioned before make sure you
call the start() method
Here's a snippet of code from msdn, that you might want to refer
Process myProcess = new Process();
try
{
// Get the path that stores user documents.
string myDocumentsPath =
Environment.GetFolderPath(Environment.SpecialFolder.Personal);
myProcess.StartInfo.FileName = myDocumentsPath + "\\MyFile.doc";
myProcess.StartInfo.Verb = "Print";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
}
catch (Win32Exception e)
{
if(e.NativeErrorCode == ERROR_FILE_NOT_FOUND)
{
Console.WriteLine(e.Message + ". Check the path.");
}
else if (e.NativeErrorCode == ERROR_ACCESS_DENIED)
{
// Note that if your word processor might generate exceptions
// such as this, which are handled first.
Console.WriteLine(e.Message +
". You do not have permission to print this file.");
}
}

Categories