Dr. Watson starb unter Vista…

… und es war nicht etwa wieder Prof. Dr. Moriarty :mrgreen:

Wenn man unter Vista einen Crashdump benötigt dann sucht man DRWTSN32.EXE unter Vista vergeblich. Für die Qualitätssicherung sind mir Minidumps immer extrem wichtig.

Es stellt sich die nette Frage: Wie kommt man von einem Kunden dann an einen informativen Minidump, wenn man keinen WER-Account hat, oder das Programm nicht signiert war, oder gar der WER Server diese Dumps nicht anfordert?

Unter Vista ist alles noch einfacher und schwieriger geworden. Vista speichert leider nicht grundsätzlich Minidumps, aber es legt für Crashs unter Problemberichte und Lösungen einen eigenen Eintrag an. Zu Crashs von WER registrierten Programme werden hier evtl. direkt Lösungen oder Updates angeboten. Und auch Crashdumps werden hier mit abgelegt, wenn sie erzeugt werden..

So ist es unter Vista aus:

  1. Das WER System in Vista erzeugt normalerweise nur Minidumps für signierte Programme bzw. wenn der WER Server einen Crash abruft.
  2. Um immer einen Minidump zu erhalten muss in der Registry der folgende Wert gesetzt werden:
    HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\ (DWORD)  mit Namen ForceQueue  erzeugen und auf 1 setzen.
  3. Dumps werden im Benutzerverzeichnis unter C:\Users\TheUserName\AppData\Local\Temp und hier C:\ProgramData\Microsoft\Windows\WER\ReportQueue abgelegt und sind meistens gepackt. Sie erhalten die Endung *.mdmp.
  4. Der Zugriff kann ganz einfach erfolgen mit Systemsteuerung -> System und Wartung -> Problemberichte und Lösungen -> Probleme anzeigen und überprüfen
  5. Dort findet man das entsprechende Programm und die dazugehörigen entsprechenden Crashs.
  6. Weitere Infos einfach über Details anzeigen lassen.
  7. Wenn es einen Dump gibt, dann findet man hier wieder einen Eintrag Temporäre Kopie dieser Dateien anzeigen
  8. Damit lässt sich der Explorer öffnen und man erhält Zugriff auf die gespeicherten Daten.
  9. Diese kann man sich nun als Entwickler zusenden lassen.

Siehe auch:

Was tun gegen Fehler in statischen Tabellen bzw. Variablen Deklarationen

Ich habe es immer wieder mit langen Listen von statischen Datenbeschreibungen zu tun. Das können Parserlisten, oder Sprachbeschreibungen, die baumartig vorliegen oder einfach nur simple Arrays sein.

In den meisten Fällen versuche ich solche Strukturen als konstante PODs (Plain Old Data) aufzubauen. D.h. also in einer Form:

  1. sodass kein weiterer Code notwendig ist um diese zu initialisieren (z.B. vermeinden von Konstruktoren/Destruktoren)
  2. dass die Daten sogar möglichst als const deklariert werden und so in einem Code Segment in Modulen geshared werden können.
  3. dass sie sich leicht aus einer „Art Datenbank“ in C/C++ Code erzeugen lassen.

Oft haben diese Datenstrukturen eine komplexe Struktur und auch einen Aufbau nach bestimmten Regeln, wie z.B. dass alle Daten eines Arrays sortiert sein müssen. Dadurch kann der Algorithmus, der diese Daten nutzt natürlich effektiver geschrieben werden, als wenn er auf einem unsortierten Array aufsetzt.

Eine Erfahrung, die ich heute weitergeben will, lautet nun:

Vertraue niemals darauf, dass die Daten in statischen konstanten Strukturen so vorliegen wie Du es glaubst… zumindest nicht in der Debug Version! 😉

Hintergrund für diese Erfahrung ist ein Bug, der sich genau aus einer Annahme einschlich, das statische Daten in einer bestimmten Regel vorliegen. In dem aktuellen Fall war es die bereits erwähnte Regel: „Der Array ist sortiert, nach einer ID“. Das Ganze war sogar am Anfang der besagten Struktur und im Code korrekt und ausführlich dokumentiert. Allerdings ist der Sourcecode dieser Tabelle mehrere 1000 Zeilen lang und ein Entwickler fügte nun einfach ein paar neue Einträge an das Ende der Liste an.
<ironiemode>Außerdem, wer liest schon interne Programmdokumentationen, wo wir alle (insb. der Autor und die geschätzten Leser dieses Artikels) doch fähig sind, den Sinn und Zweck von Code mit einem Blick zu erfassen?</ironiemode>

Die Folge war: „Nun ist der Array nicht mehr sortiert“ und die weitere Folge war, dass ein Algorithmus, der auf einer binären Suche basierte, nicht fand, was er finden sollte.

Dabei hätte Stück simpler Validierungscode, vermeiden können, dass dieser Code in Produktion ging:

class CSomeMightyDataHandler
{
public:
    CSomeMightyDataHandler();

    ...

private:
    // complex static data
    struct S_COMPLEXDATA
    {
        ...
    };
    static const S_COMPLEXDATA *m_pComplexData;

    // Validator for Debug mode
#ifdef _DEBUG
    static const bool m_bValidated;
    static bool ValidateData();
#endif
...
};

#ifdef _DEBUG
// Validation for debug code only!
const bool CSomeMightyDataHandler::m_bValidated = CSomeMightyDataHandler::ValidateData();

bool CSomeMightyDataHandler::ValidateData()
{
    // Do some validation and reset bResult on any failure
    bool bResult = true;

    ...

    ASSERT(bResult);
    return bResult;
}
#endif

Mit solch einem Code wäre sofort ein ASSERT nach der ersten inkorrekten Code Ergänzung geflogen.

PS: Folgende Annahmen stimmen:

  1. Der Programmierer, der den Code falsch hinzugefügt war ich selbst.
  2. Der Programmierer, der beim Design der Klasse keinen Validierungscode geschrieben hat war auch ich selbst.
  3. Ich hatte wirklich vergessen, wie dieser Algorithmus ursprünglich mal von mir geplant war (sprich, dass eine Sortierung beachtet werden muss).
  4. Ich kann mir in den Hintern beißen für soviel selbst gemachte Dummheit.

Resümee bisher: Eine Übernahme aller Daten von VSS nach TFS mit VSSConvert kann man sich sparen

Wir haben Anfang des Jahres produktiv von Visual-Source-Safe (VSS) auf den Team Foundation Server (TFS) umgestellt.
Ich stand vor der Frage ob ich den bisherigen Source-Safe Inhalt komplett in den TFS übernehme und wie die eigentliche Migration auf den TFS möglichst schnell ablaufen kann.

In älteren Blog Artikeln habe ich ja bereits von dem Problem berichtet, dass wir sehr viel auch mit Shares unter VSS gearbeitet haben. Ich hätte hier sowieso tricksen müssen und die eigentliche Umstellung der Projekte in eine Struktur, die keine Shares mehr verwendet wollte ich dich lieber unter Nutzung des TFS durchführen.

Die Entscheidung viel also so aus:

  • Übernahme des aktuellen Programmstandes in das TFS System
  • Keine Übernahme der alten VSS Daten mit dem VSSConverter
  • Überarbeitung der Projektstruktur so dass, keine Datei-Shares mehr benötigt werden. Hierbei werden entsprechende übergeordnete Common Verzeichnisse verwendet.
  • Entzerrung der Gesamten Projektstruktur so, dass auch die Verwendung einer Master-Solution möglich wird.
  • Beibehalten der alten VSS Daten in einem Backup System, für evtl. Hotfixes der letzten Version und einige Legacy Projekte

Ich gebe zu, dass ich misstrauisch war. Auf die Historie des Source Control Systems nicht weiter als zum letzten Release zurückgreifen zu können erschien mir als großer Nachteil. Gerade weil wir hauptsächlich Projekte und Programmteile haben, die zum Teil schon auf 20 Jahre Geschichte zurückblicken und immer noch weiter entwickelt werden.
Letzten Endes haben aber alle Team Mitglieder bisher klar gesagt: „Schade, dass wir diesen Schritt au den TFS nicht eher gemacht haben“.
Im Nachhinein vermisst keiner die gesamte VSS Historie, der Projekte. Wer muss, der kann noch im alten VSS Backup-System stöbern. Aber das war bisher nur in einem einzigen Fall wichtig und hilfreich.

Ich kann aus meiner Sicht also dazu raten, einfach einen Cut mit dem aktuellen System zu machen und mit dem aktuellen Programmstand einfach in das TFS System einzuchecken und einzutauchen. Sich zwei Tage und mehr mit dem VSSConvert herumzuschlagen (wie ich es zum Teil schon gehört habe), ist aus meiner Sicht heute vertane Zeit.

Text aus eine MessageBox einfach in die Zwischenablage kopieren…

Jeder kennt das, der schon mal an Supportfällen gearbeitet hat.

Der Kunde bekommt eine Fehlermeldung und meistens ist es eine simple MessageBox die dort angezeigt wird. Was wird gemacht? Der Kunde drückt Alt+Druck und schickt einen Screenshot.

Oder man will selber nach dem Text in Google suchen und tippt mühselig die Meldung ab.

Dabei geht es so einfach: Strg+C oder einfach Strg+Einfg drücken und schon wird der Text der Messagebox auf wundersameweise in die Zwischenablage kopiert:

---------------------------
Titel der MessageBox
---------------------------
Text der MessageBox
---------------------------
OK   Abbrechen  
---------------------------

Dies geht auf allen Windows Betriebssystemen!

Besonders interessant ist das auch der Windows Vista Task Dialog diese Funktionalität enthält, wie man z.B. mit dem Notepad unter Vista ausprobieren kann.

[Window Title]
Editor
[Main Instruction]
Möchten Sie die Änderungen an Unbenannt speichern?
[Speichern] [Nicht speichern] [Abbrechen]

Tipps & Tricks:Entzerren komplexer Pre- und Post-Build-Steps durch eigene Utility Projekte

Ich habe einige komplexe Projekte in die auch andere Tools eingebunden sind. Diese Tools erzeugen Dateien und Ressourcen erzeugen, die mit in den kompletten Build eines Projektes einfließen. Zum Teil sind es Daten, die auf einen speziellen Weg kompiliert werden oder auch Ressourcen, die durch ein sekundären anderen Compiler erst mit verarbeitet werden müssen.

Teilweise hatte ich diese Prozesse in einen Pre– und Postbuild Step eingebaut. Leider verhält sich Visual Studio oft genug eigentümlich, es merkt nicht das abhängige Dateien während des Build Prozesses verändert werden.

Bei einer Umstellung meiner Projekte stellte ich fest, dass es weitaus einfacher ist für solche speziellen Vorgänge eigene kleine Projekte zu erzeugen vom Typ „Utility„.

In diesen Projekten kann man einfach Ein- und Ausgabedateien definieren und den Befehl, der dazu notwendig ist die Daten eben zu bearbeiten.
Das Ganze wird dann in eine Master Solution kombiniert mit den entsprechenden Abhängigkeiten. Das hat vor allem auch den großen Vorteil, das auch die Projekte parallel im Build durchlaufen werden können.

Utility Projekte sind für manche Aufgaben weitaus besser geeignet als Pre– und Postbuild Steps. Vor allem werden durch die Verwendung von Utility Projekten die einzelnen Vorgänge entzerrt und verständlicher.

Ein nicht geringer Vorteil von Lowridertaschen

Am Dienstag auf dem Maintal Radweg habe ich und meine Frau unsere Ortlieb Sportpacker Taschen, die wir an unseren Lowrider montiert hatte, von einer ganz neuen Seite kennen gelernt.

Ich fahre schon seit Jahren mehrtägige Radtouren. Auch Regen kam hin und wieder vor. Aber 5 Stunden Regenfahrt am Stück hatte ich bisher wirklich noch nicht erlebt – glücklicherweise 😉

Nach etwa 3 Stunden Dauernieselregenfahrt von Wertheim nach Karlstadt bemerkten wir auf einmal, dass uns Radfahrer mit Plastiktüten über den Schuhen entgegen kamen. Zu recht, es regnete ja wirklich nicht wenig. Und erst jetzt registrieten wir, dass wir immer noch trockene Radschuhe hatten.
Besonders das Wasser, dass am Rad wieder nach vorne vom Vorderrad am oberen Schutzblechrand austritt durchnässt einem normalerweise die Schuhe zuverlässig.
Trotz stundenlanger Fahrt im Regen und ohne Überschuhe, waren unsere Schuhe weitgehend trocken geblieben. Spritzwasser wurde von Schutzblech und Lowridertaschen gut abgehalten und auch der Regen von vorne kam nicht an den Lowridertaschen vorbei und so sorgten die Taschen für einen perfekten Schutz der Schuhe.

Für mich noch ein Grund mehr eher den Lowrider zu benutzen als meinen Gepäckträger hinten mit einer zusätzlichen Tasche obendrauf zu belasten.

Acceleratoren in Dialogen für Felder ohne Prompt bzw. Static Control

Mit Alt+Buchstabe ein Feld in einem Dialog anspringen ist der Tastaturliebhaber gewöhnt.
Aber was mach man wenn man keinen Platz für ein Static Control hat vor dem entsprechenden Eingabefeld. Oder wenn solch ein Static gar nicht in das Design passt, oder gar eine Grafik enthalten soll.

Man könnte PreTanslateMessage überschreiben und mit Hooks Klimmzüge veranstalten. Aber es geht weitaus einfacher.

Man kann das Static Control an die korrekte Stelle in der Z-Order platzieren und dann einfach auf „Invisible“ setzen. Der Accelerator funktioniert trotzdem.
Nur Statics, die disabled sind werden als Acceleratoren ignoriert. Das Acceleratoren auch für nicht sichtbare Controls funktionieren habe ich bereits in diesem Artikel Button + Accelerator + ShowWindow(SW_HIDE) – EnableWindow(FALSE) = Falle erwähnt.

Anmerkung:
Damit ein User weiß das Acceleratoren für dieses Feld funktionieren sollte ein sichtbarer Hinweis im Handbuch existieren. Da aber wenige Menschen überhaupt Handücher verwenden :mrgreen: eignen sich hier Tooltips für den entsprechenden Hinweis.  Etwa so wie das VisualStudio macht mit Show shortcut keys in ScreenTips

VS Tipps & Tricks: Schnellere Lernkurve durch sichtbare Tastatur Shortcuts

Wie kann man eigentlich lernen noch schneller mit Visual Studio umzugehen?
Ein Weg ist sicherlich die Maus zu umgehen und mehr mit der Tastatur zu machen. Dazu ist es aber auch notwendig, die entsprechenden Tastaturbefehle zu kennen.

Ein einfaches Hilfsmittel ist es die Tastatur Shortcuts auch in den Buttons der Toolbars anzeigen zu lassen. Das geht einfach über Tools -> Customize -> Show shortcut keys in ScreenTips.

Die Tooltips der Buttons enthalten, dann auch den Shortcut, der diesen Befehl auch auslösen würde. Auf diese Weise erhält man z.B. schnell die Info, dass Strg+D in das Suchfeld springt.

VisualStudio 2008 SP1 wird ab dem 11.08.2008 auf MSDN zum Download bereitstehen

Die englische Version des Microsoft SQL Server 2008 wurde gestern am 06.08.2008 veröffentlicht.

Auf der Startseite der MSDN Subscriptions findet sich folgende hoch interessante Information:

SQL Server 2008 RTM Available for Download

English downloads are available now and additional languages will be added on a daily basis. Visual Studio 2008 users will need to download and install Service Pack 1 which will be available here after August 11, 2008.

Das heißt, dass wir ab Montagmorgen mit dem finalen SP1 für Visual Studio 2008 rechnen dürfen, zumindest in der englischen Version. Ich befürchte, dass die deutsche Version noch ein paar Tage mehr auf sich warten lässt.
Wie immer ein Grund nur mit den englischen Entwicklungswerkzeugen zu arbeiten :mrgreen:

Tipps & Tricks: #import durch #include ersetzen

Nicht wenige verwenden, wie ich auch COM Komponenten, aus dem eigenen Haus oder von Fremdherstellern. Eingebunden werden diese COM-Komponenten oft genug über das #import Statement, das ja eine wirklich simple Integration erlaubt.

Lästig ist nur, dass diese Komponenten nicht auf allen Rechnern in den selben Verzeichnissen liegen. Das macht es nicht leicht Projekte und Entwicklungmaschinen so auszustatten, dass alle Projekte gleich zu kompilieren sind. Da fängt es schon an, dass ein Entwickler ein englisches OS (C:\Program Files), ein andere ein deutsches (C:\Programme) und der dritte Entwickler benutzt das Installationverzeichnis der zu entwickelnden Komponente (C:\Dev\Project\Bin).

Aus diesem Grund bin ich dazu übergangen das #import Statement nur einmal auszuführen, und die entstehenden .tlh und .tli Dateien direkt in das Projekt aufzunehmen.
Zu schnell? OK, also schrittweise:

  • Ich binde die Komponente also wie gewohnt per #import ein.
  • Die entstehenden .tlh und evtl. auch die .tli Dateien werden in das Projektverzeichnis kopiert und in das Projekt aufgenommen.
  • Das das #import Statement wird nun auskommentiert und statt dessen entsprechende #include Statements eingesetzt.
  • Nachdem man das auch korrekt mit entsprechenden Versionsangaben der Komponente dokumentiert hat und auch dieses Verfahren in die Projektbeschreibung aufgenommen hat ist man fertig!

Vor- und Nachteile:

  • Nicht nur, dass dieses Projekt unabhängig kompiliert werden kann. Das Kompilieren ist auch noch schneller, denn die (an sich) statischen .tlh und .tli Dateien werden nicht immer neu erzeugt.
  • Vorrausetzung ist hier sicherlich, dass es sich hier um Komponenten handelt, deren Interface sich nicht mehr verändert, und man muss bei einem Update der Komponente natürlich auch manuell die neuen .tli und .tlh Dateien einbauen.
  • Ein weiterer Vorteil ist auch, dass das Interface fest eingebunden wird, das auch für die Auslieferung festgelegt wird und keine alte/oder neuere Version zu Überraschungen führt.
  • Was auch zu dem genialen Verhalten führt, dass man aus dem Sourcecontrol System eine Software Version erzeugen kann, die noch mit einer älteren/abweichenden COM Komponente erzeugt wurde ohne diese auch noch mal installieren zu müssen!