Inzwischen war Zeit, sich die hier bemängelte Verarbeitung näher anzusehen. Es ist noch schlimmer als gedacht und es werden Dateien gelöscht, die sicher nicht gelöscht werden dürfen und zwar unabhängig davon, wo die Software installiert wird. Und der Grund ist, dass in Application.StartupPath nicht der Pfad der Applikation steht, denn gestartet wird bei der Deinstallation der Installer (bei Windows 7 in syswow64).
Beheben lässt sich das in dem man den Applicationpfad aus dem Context ausliest:
string strAssemblyPath = Context.Parameters["assemblypath"].ToString();
strAssemblyPath = Path.GetDirectoryName(strAssemblyPath);
Das löst aber noch nicht das Problem, dass möglicherweise Dateien aus einem Ordner gelöscht werden, die gar nicht zur Software gehören. Das umgehen wir, indem wir eine Datei mit allen installierten Dateien schreiben (dir /b /s > deletefiles.txt). Beim Deinstallieren wird diese Datei eingelesen und es werden nur noch die Dateien gelöscht, die dort aufgeführt sind.
Ein Kunde ruft bei uns an und berichtet von einem Nutzer, bei dem nach der Deinstallation einer Software plötzlich Systemdateien fehlten. Er kündigt am nächsten Tag zu diesem Thema eine Telefonkonferenz an. Ein kurzer Blick in den Code offenbart furchtbares. Wenn jemand die Software nicht in den vorgeschlagenen Ortner installiert, sondern beispielsweise in den Systemordner, werden dort mit der Deinstallation alle Dateien gelöscht.
Es ist zwar noch nicht evaluiert, aber das dürfte das Problem sein. Eine mögliche Lösung: Mit dem ersten Start schreiben wir eine Datei mit den vorhandenen Dateien und Ordnern (also quasi dir /b > installed.txt). bei der Deinstallation lesen wir diese Datei aus und löschen nur die darin gelisteten Dateien einschließlich der Datei selbst. Der Ordner wird nur gelöscht, wenn er leer ist.
So geht es auf jeden Fall nicht:
private void Permission_AfterUninstall(object sender, InstallEventArgs e) { string Path_LabelFiles = Path.Combine(Application.StartupPath, @"Labels"); if (Directory.Exists(Path_LabelFiles)) { try { Directory.Delete(Path_LabelFiles, true); } catch (Exception ex) { //nope } } try { Directory.Delete(Application.StartupPath, true); } catch { } }
Heute während eines Versuchs beim Kunden per Communicator eine Neuerung in unserer Software vorzuführen. Entdeckt. Wer findet den Fehler?
if (mo.PanelCountConnected >= mo.PanelCountConnected) { MessageBox.MsgBox.show("MSG_NOMORE_PANELS"); return; }
Lösung nach dem Klick.
Wenn man mit dem Microsoft .net Framework 2.0 in C# mit der folgenden Zeile eine Liste der Named Pipes des Systems ermitteln will, kann es zu einer Fehlermeldung kommen:
string[] strPipes = System.IO.Directory.GetFiles(@"\\.\pipe\");
Ursache dafür ist, dass es eine Named Pipe mit einem Namen gibt, der kein gültiger Dateiname ist. Mit dem folgenden Code (C#) gelingt das Auslesen aller Named Pipes:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct WIN32_FIND_DATA { public uint dwFileAttributes; public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern IntPtr FindFirstFile(string lpFileName, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool FindNextFile(IntPtr hFindFile, out WIN32_FIND_DATA lpFindFileData); [DllImport("kernel32.dll", SetLastError = true)] static extern bool FindClose(IntPtr hFindFile); private List<string> getNamedPipes() { List<string> liNamedPipes = new List<string>(); WIN32_FIND_DATA lpFindFileData; var ptr = FindFirstFile(@"\\.\pipe\*", out lpFindFileData); liNamedPipes.Add(lpFindFileData.cFileName); while (FindNextFile(ptr, out lpFindFileData)) { liNamedPipes.Add(lpFindFileData.cFileName.ToLower()); } FindClose(ptr); liNamedPipes.Sort(); return liNamedPipes; }
Übrigens kann man mit dem Tool PipeList der Microsoft Sysinternals per Kommandozeile eine Liste aller Named Pipes ausgeben lassen.
Vor einiger Zeit habe ich an der Arbeit ein Tool geschrieben, was zur elektronischen Erfassung von Telefonnotizen dient. Heute sind wir nur zu zweit im Büro und ich wollte eine Notiz erstellen. Leider gab es eine Exception und es funktionierte nichts. Also hab ich die Entwicklungsumgebung geöffnet und versucht zu debuggen. Es gab einen diffusen Fehler (xamlparseexception) beim Öffnen einer SQLConnection (SQL-Server 2008) um die Telefonnummer zu einem Kontakt aus der Datenbank auszulesen. Ein Versuch die Exception abzufangen schlägt fehl. Trage ich eine andere Datenbank ein funktioniert es.
Die Lösung: