Самостоятельно удаляемое приложение на C # в одном исполняемом файле

Можно ли сделать приложение на C #, которое сможет удалять себя в каком-то состоянии.

Мне нужно написать средство обновления для моего приложения, но я не хочу, чтобы исполняемый файл оставался после процесса обновления.

Существует официальный .Net OneClick, но из-за некоторых несовместимостей с моим HTTP-сервером и некоторых проблем самого OneClick я вынужден сделать его сам.

Джордж.

[РЕДАКТИРОВАТЬ] Подробнее:

У меня есть: Исполняемый файл приложения, который загружает средство обновления («патч», но не совсем), этот «патч» обновляет сам исполняемый файл приложения.

Приложение работает следующим образом:

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);

person George    schedule 20.08.2009    source источник
comment
Вы спрашивали о проблемах с самим OneClick? Может, это решит вопрос.   -  person Christian13467    schedule 20.08.2009
comment
Не сам OneClick. Я обновил вопрос и добавил процедуру приложения для точности.   -  person George    schedule 20.08.2009


Ответы (7)


Если вы используете Process.Start, вы можете передать параметр Del и путь к приложению, которое хотите удалить.

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); 

Фрагмент кода взят из этой статьи

person James    schedule 20.08.2009
comment
Спасибо за статью. Не знаю, почему я не смог его найти: S - person George; 20.08.2009
comment
Что делать, если приложение не закрывается через 3 секунды? - person Alex Zhukovskiy; 03.02.2016
comment
@AlexZhukovskiy тайм-аут в примере не определяет, как долго система должна ждать перед попыткой удалить приложение, тайм-аут просто запускает значение по умолчанию, чтобы принудительно закрыть приложение. Вы просто указываете командной строке, что после того, как процесс существует, запустите del. - person James; 03.02.2016
comment
@ Джеймс, может, я чего-то не понимаю. Вы запускаете сценарий, который ждет 3 секунды, а затем пытается удалить exe. Но если нужно выполнить много кода, del file просто не удастся. Например, если у нас есть множество финализаторов, которые должны выполняться до выхода из приложения. И это могло занять более 3 секунд. - person Alex Zhukovskiy; 03.02.2016
comment
@AlexZhukovskiy думает, что вы сбиваете с толку, беспокоясь о выполнении кода, здесь мы говорим о самом процессе - если код все еще выполняется, значит, процесс еще не завершен. Командная строка выполнит следующую команду только после завершения первой, независимо от того, сколько времени это займет. - person James; 03.02.2016
comment
@James Я имею в виду, что команда самоудаления должна запускаться, когда процесс только что запущен (потому что мы не знаем, когда он будет завершен), потому что единственный способ гарантировать, что этот код будет работать, - это класс с критически безопасным финализатором, который должен быть создан как статический синглетон, поэтому он будет уничтожен при выгрузке домена. Я имею в виду случай, когда Process.Start не последняя команда в программе, и мы не знаем, какая команда будет последней. - person Alex Zhukovskiy; 04.02.2016
comment
@AlexZhukovskiy до сих пор не понимает, почему вы здесь говорите о таких вещах, как финализаторы / классы - del - это системная команда, запускаемая после завершения процесса. мы не знаем, когда он будет завершен - да, знаем, когда процесс возвращает код выхода ... - person James; 10.02.2016
comment
@James добавляет Thread.Sleep(10000) после Process.Start. Исполняемый файл не будет удален. - person Alex Zhukovskiy; 11.02.2016
comment
Я просто попробовал с Thread.Sleep(10000), как предложил Алекс, и удаление не работает. - person Jay Sullivan; 15.01.2017
comment
@JaySullivan, и это вполне ожидаемо, потому что вы больше не закрываете приложение в момент выполнения кода - цель вышеуказанного решения заключалась в том, что OP знал, что в этот момент процесс собирался убить. Я полностью понимаю, что некоторые приложения более сложные, например фоновые потоки могут все еще работать, однако правила все еще применяются - вы должны отслеживать их, и когда они все будут завершены, вы запустите код. Никогда не предполагалось, что вышеупомянутое решение будет охватывать все базы, при использовании по назначению оно выполняет свою работу. - person James; 20.07.2017
comment
Для удаления всей папки: Process.Start (cmd.exe, / C ping 1.1.1.1 -n 1 -w 3000 ›Nul & RD / s / q + Path.GetDirectoryName (Application.ExecutablePath)); Application.Exit (); - person Glebka; 05.09.2018

Я предлагаю вам использовать командный файл в качестве начальной загрузки и затем удалить себя и exe.

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()
    {
        .....
    }
}
person Community    schedule 20.08.2009
comment
Только не удалять ... / y, а del ... / Q - person Boogier; 13.07.2013

Это сложно, не вводя еще один процесс (который, без сомнения, вы также захотите удалить). В вашем случае у вас уже есть 2 процесса - updater.exe и application.exe. Я бы, вероятно, просто попросил приложение удалить updater.exe, когда он появится оттуда - вы можете использовать простой аргумент командной строки или вызов IPC от updater.exe к application.exe для его запуска. Это не совсем самоудаление EXE, но я думаю, что он удовлетворяет требованиям.

Для полного лечения и других вариантов вы должны прочитать окончательное лечение самоудаления EXE-файлов. Примеры кода написаны на C (или ASM), но должны быть вызываемыми.

Я бы, наверное, попробовал CreateFile с FILE_FLAG_DELETE_ON_CLOSE для updater.exe с чем-то вроде ( псевдокод):

 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");

После выхода из application.exe у updater.exe дескриптор файла 1. При выходе из программы updater.exe он становится равным 0, и его следует удалить.

person Mark Brackett    schedule 20.08.2009
comment
К сожалению, это не работает, потому что процесс должен быть запущен с FILE_SHARE_DELETE, чего Process.Start не делает. Затем ему не удается запустить процесс, потому что файл все еще открыт (и его нельзя закрыть, потому что это приведет к его удалению). - person urbanhusky; 01.04.2014

Не могли бы вы просто удалить программу обновления из приложения? то есть:

Приложение: Пуск -> [Удалить старое средство обновления, если оно есть] -> Проверить версию -> Загрузить новое средство обновления -> Запустить средство обновления -> выйти;

Программа обновления: Пуск -> Выполнить обновление -> Запустить приложение -> выйти;

Приложение: Пуск -> [Удалить старую программу обновления, если она есть] -> ...

person Eamon Nerbonne    schedule 20.08.2009

Ммм, позволь мне уточнить это. У вас есть application.exe и ваше приложение для обновления updater.exe?

Поэтому, когда вы запускаете свой application.exe, он проверяет какой-либо веб-сервер на наличие более новой версии, а затем запускает updater.exe. И вы хотите, чтобы updater.exe удалил себя после завершения обновления? Или вы хотите удалить скачанный патч (или аналогичный)? Пожалуйста, будьте точнее.

Учтите, что при удалении updater.exe необходимо воссоздать его для следующего процесса обновления.

person chrischu    schedule 20.08.2009
comment
Я добавил процедуру приложения для точности. - person George; 20.08.2009

ваша вторая строка может быть

Updater: Star -> do it's work -> start Application Executable -> Updater Exits -> Application deletes your Updater.exe
person Community    schedule 20.08.2009
comment
Интересный. Вы пытаетесь найти решение, которое, похоже, не работает. В чем проблема? ПОЧЕМУ вы хотите, чтобы программа обновления удаляла себя и почему не приложение? - person ; 20.08.2009

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();
}

Самостоятельное удаление с помощью внешнего исполняемого файла ".bat" для приложений Windows Forms.

person reza63    schedule 17.03.2017
comment
Кажется очень похожим на более ранний подход к пакетному файлу, но может бесконечно зацикливаться в условиях ошибки, что не кажется разумным. - person Nathan Tuggy; 17.03.2017