Bonjour,
Je fais un programme en C# et j'aimerai que à la fin du script il se supprime tout seul.
J'ai fais ceci mais ça lève un exception:
Merci d'avance pour vos réponsesCode:System.IO.File.Delete(Application.ExecutablePath);
Version imprimable
Bonjour,
Je fais un programme en C# et j'aimerai que à la fin du script il se supprime tout seul.
J'ai fais ceci mais ça lève un exception:
Merci d'avance pour vos réponsesCode:System.IO.File.Delete(Application.ExecutablePath);
Un executable ne peut pas se supprimer lui-même étant donné qu'il est en cours d'execution...
En lançant ton application à partir d'un fichier cmd ou bat tu peux supprimer à la fin de l'execution via une command dos...
Comme dit précédemment un exécutable ne peut pas s'autosupprimer, simplement parce que pour exécuter son code Windows verrouille l'exe et ça se comprend ...
Mais il existe des subterfuges pour donner l'illusion :
- Lancer ton application à partir d'un fichier bat, mais ça c'est pas élégant
- Créer un fichier bat à la volée à la fin de l'exécution de ton application avec un code genre :
mais il faudrait vérifier, ça fait longtemps que j'ai pas touché aux fichiers bat (si tu veux je peut te passer une classe que j'ai crée à cet effet ... là j'y ai pas accès, mais ça se fait).Code:
1
2
3
4
5 Beg: erase PATH_DE_TON_EXE if exists PATH_DE_TON_EXE goto Beg erase LE_FICHIER_BAT
L'avantage avec les bats c'est que eux, il peuvent s'autosupprimer
- Créer ton exe et y mettre un autre exe qui sera extrait dans le dossier temp de Windows et qui aura en charge de supprimer ton application. Ensuite, pour supprimer le "supprimeur" tu peut utiliser l'api MoveFileEx avec comme chemin source le supprimeur, chemin de destination vide, et attributs "MOVE_FILE_ON_REBOOT" et dans ce cas ton "supprimeur" sera supprimé par Windows au prochain redémarrage
Voilà en gros les options ...
Excellent, le .Bat généré en fin d'éxécution.
Je mettrai quand même une petite ligne "Sleep 1" après Beg:
Merci beaucoup pour toutes ces méthodes.
Je vais essayer la méthode du MoveFileEx et je vous tien au courant du résultat.
Mon autodeleter, éprouvé par DreamShield depuis 2 ans sans bugs (a priori :aie:)
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Reflection; using System.Diagnostics; using System.Windows.Forms; using System.Runtime.InteropServices; namespace IoDeleterApp { class AutoDeleter { public static bool WindowsIsClosing { get; protected set; } static AutoDeleter() { WindowsIsClosing = false; Microsoft.Win32.SystemEvents.SessionEnding += delegate { WindowsIsClosing = true; }; Microsoft.Win32.SystemEvents.SessionEnded += delegate { WindowsIsClosing = true; }; } static string GetTmpBatName() { const string model = "{0}\\DS_Unist{1}.bat"; string WinTmpDir = Path.GetTempPath(); int nm = 0; while (File.Exists(String.Format(model,WinTmpDir,nm.ToString()))) { nm++; } return String.Format(model, WinTmpDir, nm.ToString()); } [Flags] public enum MoveFileFlags { MOVEFILE_REPLACE_EXISTING = 0x00000001, MOVEFILE_COPY_ALLOWED = 0x00000002, MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004, MOVEFILE_WRITE_THROUGH = 0x00000008, MOVEFILE_CREATE_HARDLINK = 0x00000010, MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020 } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); public static void AutoDeleterStart() { string file_name = Assembly.GetEntryAssembly().Location; if (WindowsIsClosing) { /* Si Windows est en train de se fermer, on va se supprimer au prochain redémarrage */ MoveFileEx(file_name, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); } else { Environment.CurrentDirectory = Path.GetDirectoryName(Application.ExecutablePath); FileStream fi = null; int try_count = 20; do { try { fi = new FileStream(GetTmpBatName(), FileMode.Create); } catch { } try_count--; System.Threading.Thread.Sleep(1000); } while (try_count >= 0 && fi == null); if (try_count < 0) { MessageBox.Show("Impossible de supprimer certains fichiers temporraires car la création du fichier d'auto-suppression a échouée", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (fi == null) fi = new FileStream(GetTmpBatName(), FileMode.Create); /* erreur possible, si le do a échoué ... */ string name = fi.Name; StreamWriter wr = new StreamWriter(fi, Encoding.Default); wr.WriteLine("@echo off"); wr.WriteLine("REM DreamShield.IO.Utils AutoDeleter Bat"); wr.WriteLine("REM BatGenerator v 1.0"); wr.WriteLine(); wr.WriteLine(":del_process"); wr.WriteLine(String.Format("@if exist \"{0}\" del \"{0}\"", file_name)); wr.WriteLine(String.Format("@if exist \"{0}\" goto del_process", file_name)); wr.WriteLine(); wr.WriteLine(String.Format("del \"{0}\"", name)); wr.Flush(); fi.Flush(); fi.Close(); ProcessStartInfo info = new ProcessStartInfo(); info.WindowStyle = ProcessWindowStyle.Hidden; info.FileName = name; Process.Start(info); } } } }
Pour l'utiliser :
à la fin de l'exécution du programme pour que celui ci soit autosupprimé dès l'arrêt du process.Code:AutoDeleter.AutoDeleterStart();
Merci beaucoup à vous tous (particulièrement à smyley ;)) pour votre aide.
J'ai utiliser la class de smyley et ça marche nickel. :)
Visual Studio 2005 m'a quand même relevé une erreur à la compilation à cette ligne:je l'ai donc remplacée parCode:public static bool WindowsIsClosing {get; protected set; }
et maintenant tout marche bien 8-)Code:public static bool WindowsIsClosing = false;
C'est parce que moi je code en C# 3.0 avec VS 2008 alors que toi tu utilises le C# 2.0 avec VS 2005. Le C# 3.0 peut générer automatiquement les champs qui correspondent aux propriétés :
deviens en grosCode:
1
2 public virtual bool Test{get;set;}
Sinon, il aura fallu que je dise que ça marche pour trouver un hic :aie: :Code:
1
2
3
4
5
6 bool _test = false; public virtual bool Test { get {return _test;} set {_test = value;} }
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126 class AutoDeleter { public static bool WindowsIsClosing { get; protected set; } static AutoDeleter() { WindowsIsClosing = false; Microsoft.Win32.SystemEvents.SessionEnding += delegate { WindowsIsClosing = true; }; Microsoft.Win32.SystemEvents.SessionEnded += delegate { WindowsIsClosing = true; }; } static string GetTmpBatName() { const string model = "{0}\\DS_Unist{1}.bat"; string WinTmpDir = Path.GetTempPath(); int nm = 0; while (File.Exists(String.Format(model,WinTmpDir,nm.ToString()))) { nm++; } return String.Format(model, WinTmpDir, nm.ToString()); } [Flags] public enum MoveFileFlags { MOVEFILE_REPLACE_EXISTING = 0x00000001, MOVEFILE_COPY_ALLOWED = 0x00000002, MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004, MOVEFILE_WRITE_THROUGH = 0x00000008, MOVEFILE_CREATE_HARDLINK = 0x00000010, MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x00000020 } [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); public static bool IsFullASCIIString(string str) { /* * Windows pour l'instant (même jusqu'à Vista) ne supporte * pas l'exécution (via cmd) de fichiers bat qui contient * des caractères accentués. * * Dans le cas où on en a, on va donc repasser * vers le MoveFileEx ... * */ byte[] b = Encoding.ASCII.GetBytes(str); string ascii_equivalent = Encoding.ASCII.GetString(b); return str.Equals(ascii_equivalent); } public static void AutoDeleterStart() { string file_name = Assembly.GetEntryAssembly().Location; if (!IsFullASCIIString(file_name) || WindowsIsClosing) { /* Si Windows est en train de se fermer, on va se supprimer au prochain redémarrage */ MoveFileEx(file_name, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); } else { Environment.CurrentDirectory = Path.GetDirectoryName(Application.ExecutablePath); FileStream fi = null; int try_count = 20; do { try { fi = new FileStream(GetTmpBatName(), FileMode.Create); } catch { } try_count--; System.Threading.Thread.Sleep(1000); } while (try_count >= 0 && fi == null); if (try_count < 0) { MessageBox.Show("Impossible de supprimer certains fichiers temporraires car la création du fichier d'auto-suppression a échouée", "Erreur", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (fi == null) fi = new FileStream(GetTmpBatName(), FileMode.Create); /* erreur possible, si le do a échoué ... */ string name = fi.Name; StreamWriter wr = new StreamWriter(fi, Encoding.Default); wr.WriteLine("@echo off"); wr.WriteLine("REM DreamShield.IO.Utils AutoDeleter Bat"); wr.WriteLine("REM BatGenerator v 1.0"); wr.WriteLine(); wr.WriteLine(":del_process"); wr.WriteLine(String.Format("@if exist \"{0}\" del \"{0}\"", file_name)); wr.WriteLine(String.Format("@if exist \"{0}\" goto del_process", file_name)); wr.WriteLine(); wr.WriteLine(String.Format("del \"{0}\"", name)); wr.Flush(); fi.Flush(); fi.Close(); ProcessStartInfo info = new ProcessStartInfo(); info.WindowStyle = ProcessWindowStyle.Hidden; info.FileName = name; Process.Start(info); } } }
En gros ce qui change c'est :
Parce que si le nom de l'utilisateur (par exemple) contient un accent, cmd ne sais pas gérer donc il faut repasser à la suppression au redémarrage.Code:!IsFullASCIIString(file_name) || WindowsIsClosing
Sinon si vous trouvez un moyen de faire à cmd exécuter un fichier batch unicode ...