Self deletable application in C# in one executable
Asked Answered
M

7

31

Is it possible to make an application in C# that will be able to delete itself in some condition.

I need to write an updater for my application but I don't want the executable to be left after the update process.

There is an official .Net OneClick but due to some incompatibilities with my HTTP server and some problems of OneClick itself I'm forced to make one myself.

George.

[EDIT] In more details:

I have: Application Executable which downloads the updater ("patch", but not exactly) this "patch" updates the application executable itself.

Application executes as folowed:

Application: Start -> Check Version -> Download new Updater -> Start Updater -> exit;
Updater: Start -> do it's work -> start Application Executable -> self delete (this is where I get stuck);
Malady answered 20/8, 2009 at 11:6 Comment(2)
Did you ask about the problems with OneClick itself? May be it would solve the question.Framing
Not the OneClick itself. I updated the question and added application routine for precision.Malady
E
35

If you use Process.Start you can pass in the Del parameter and the path to the application you wish to delete.

ProcessStartInfo Info=new ProcessStartInfo();
Info.Arguments="/C choice /C Y /N /D Y /T 3 & Del "+
               Application.ExecutablePath;
Info.WindowStyle=ProcessWindowStyle.Hidden;
Info.CreateNoWindow=true;
Info.FileName="cmd.exe";
Process.Start(Info); 

Code snippet taken from this article

Eatable answered 20/8, 2009 at 11:17 Comment(12)
Thanks for the article. Dunno why I couldn't find it :SMalady
What if application won't close in 3 seconds?Mechanism
@AlexZhukovskiy the timeout in the example does not dictate how long the system should wait before attempting to delete the application, the timeout just triggers a default value to force the application to close. You are simply indicating to the command line that after the process exists, run the del command.Eatable
@Eatable maybe I don't uderstand something. You run a script, that waits for 3 seconds and then trying to delete an exe. But if there are a lot of code that should be executed del file will just fail. For example, if we have tons of finalizers that should be executed before application exits. And it could take more than 3 seconds.Mechanism
@AlexZhukovskiy think your confusing matters by worrying about executing code here, we are talking about the process itself - if code is still executing then the process hasn't finished. The command line will only run the next command after the first has finished, regardless of how long it takes.Eatable
@Eatable I mean self-delete command should be runned when process is just started (because we don't know when it will be finished), because the only way to guarantee that this code will run is class with critical-safe finalizer, that should be created as static singletone so it will be destroyed when domain is unloaded. I mean the case when Process.Start isn't the last command in the programm, and we don't know what command will be the last.Mechanism
@AlexZhukovskiy still don't understand why you are talking about things like finalizers / classes here - the del command is a system command initiated after the process finishes. "we don't know when it will be finished" - yes we do, when the process returns an exit code...Eatable
@Eatable add Thread.Sleep(10000) after Process.Start. Executable won't be deleted.Mechanism
I just tried it, with Thread.Sleep(10000), as Alex suggested, and the delete doesn't work.Predator
@JaySullivan and that's completely expected because your no longer closing the application at the point of executing the code - the intention of the above solution was the OP knew at that point the process was about to be killed. I completely understand that some applications are more complex e.g. background threads might still be running, however the rules still apply - you'd keep track of these and once they had all finished, then you'd run the code. It was never suggested that the above solution would cover all the bases, when used as intended it does the job.Eatable
For deleting full folder: Process.Start("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 3000 > Nul & RD /s /q " + Path.GetDirectoryName(Application.ExecutablePath)); Application.Exit();Boffin
On application exit event I've collected all running threads then Dispose them all. After that run this code and it will work.Radcliff
U
9

I suggest you use a batch file as a bootstrap and have it delete itself and the exe afterwards

public static class Updater
{
    public static void Main() 
    {   
        string path = @"updater.bat";

        if (!File.Exists(path)) 
        {
            // Create a file to write to.
            using (StreamWriter sw = File.CreateText(path)) 
            {
                sw.WriteLine("updater.exe");
                sw.WriteLine("delete updater.exe /y");
                sw.WriteLine("delete updater.bat /y");
            } 

            System.Process.Start(path);   
        }
        else
        {
            RunUpdateProcess();
        }
    }

    private void RunUpdateProcess()
    {
        .....
    }
}
Unstriped answered 20/8, 2009 at 11:6 Comment(1)
Just not "delete... /y", but "del ... /Q"Octavus
N
5

It's tricky without introducing yet another process (that you'd then want to delete as well, no doubt). In your case, you already have 2 processes - updater.exe and application.exe. I'd probably just have the Application delete updater.exe when it's spawned from there - you could use a simple command line arg, or an IPC call from updater.exe to application.exe to trigger it. That's not exactly a self deleting EXE, but fulfills the requirements I think.

For the full treatment, and other options you should read the definitive treatment of self deleting EXEs. Code samples are in C (or ASM), but should be p/invokable.

I'd probably try CreateFile with FILE_FLAG_DELETE_ON_CLOSE for updater.exe with something like (psuedo code):

 var h = CreateFile(
            "updater.exe", 
            GENERIC_READ | GENERIC_WRITE, 
            FILE_SHARE_DELETE, 
            NULL, 
            CREATE_NEW, 
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE
         );

 byte[] updaterBytes = GetUpdaterBytesFromWeb();
 File.WriteAllBytes("updater.exe", updaterBytes);

 Process.Start("updater.exe");

Once application.exe exits, updater.exe has a file handle of 1. When updater.exe exits, it drops to 0 and should be deleted.

Nunn answered 20/8, 2009 at 11:56 Comment(1)
Unfortunately that doesn't seem to work because the process would have to be started with FILE_SHARE_DELETE - which Process.Start doesn't do. It then fails to start the process because the file is still open (and it can't be closed because that would delete it).Caniff
M
3

Couldn't you simply delete the updater from within the application? i.e.:

Application: Start -> [Delete old updater if present] -> Check version -> Download new updater -> Start updater -> exit;

Updater: Start -> Perform update -> Start application -> exit;

Application: Start -> [Delete old updater if present] -> ...

Mean answered 20/8, 2009 at 11:32 Comment(0)
I
0

Mhh so let me get this straight. You got some application.exe and your updater application updater.exe?

So when you start your application.exe it checks some webserver for a newer version and then starts updater.exe. And you want updater.exe to delete itself after it has finished updating? Or do you want to delete the downloaded patch (or similar)? Please be a bit more precise.

Consider that when you are deleting updater.exe you must recreate it for the next update process.

Insouciance answered 20/8, 2009 at 11:11 Comment(1)
I've added the application routine for precision.Malady
A
0

your second line can be

Updater: Star -> do it's work -> start Application Executable -> Updater Exits -> Application deletes your Updater.exe
Amatory answered 20/8, 2009 at 11:29 Comment(1)
Interesting. You are struggling with the solution that doesn't seem to work. What is the problem? WHY do you want updater to delete itself and why not the application?Amatory
S
0
public void uninstall() {
    string app_name = Application.StartupPath + "\\" + Application.ProductName + ".exe";
    string bat_name = app_name + ".bat";

    string bat = "@echo off\n"
        + ":loop\n"
        + "del \"" + app_name + "\"\n"
        + "if Exist \"" + app_name + "\" GOTO loop\n"
        + "del %0";

    StreamWriter file = new StreamWriter(bat_name);
    file.Write(bat);
    file.Close();

    Process bat_call = new Process();
    bat_call.StartInfo.FileName = bat_name;
    bat_call.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
    bat_call.StartInfo.UseShellExecute = true;
    bat_call.Start();

    Application.Exit();
}

self delete by an external executable file ".bat" for windows form applications.

Shostakovich answered 17/3, 2017 at 0:37 Comment(1)
Seems pretty similar to an earlier batch file approach, but can loop infinitely in error conditions, which doesn't seem wise.Jocular

© 2022 - 2024 — McMap. All rights reserved.