Von MSDN über Empower zu OPEN
Seit 12 Jahren bin ich nun MSDN-Abonnent, im Laufe der Zeit in den verschiedensten Stufen. Von MSDN-Universal bis MSDN-Library hatte ich alles dabei, die jeweilige Stufe hing immer davon ab, welche Neuerungen von Microsoft im nächsten Jahr zu erwarten waren. Da die Lizenzen auch nach Ende des Abos nicht ablaufen, war es für mich letztlich unsinnig, die MSDN-Universal zu verlängern, wenn in absehbarer Zeit keine neuen Hauptversionen von Entwicklungstools geplant waren.
Vor zwei Jahren hat mich Ramirez auf das Empower-Programm für ISVs verwiesen. Die Programmgebühr beträgt 320 Euro (zzgl. USt), darin enthalten sind u.a. bis zu fünf Lizenzen Windows XP Professional und eine 5er-Lizenz von MSDN Universal (heute MSDN Premium). Das Programm läuft ein Jahr, kann aber um weitere 12 Monate verlängert werden. Der einzige Nachteil besteht darin, dass die Lizenzen im Gegensatz zu einem normalen MSDN-Abo nach den zwei Jahren auch verfallen, das heißt, sie gelten nur während des Programms.
Bei mir ist es nun Ende Mai soweit, daher war ich in letzter Zeit quasi auf der Suche nach einer Anschlussfinanzierung. Leider gibt es beim Abschluss eines MSDN-Abos neuerdings keine Upgrademöglichkeiten mehr von früheren Entwicklungstools, es bleibt nur der Erwerb eines neuen regulären MSDN-Abos übrig. Über die aufgelisteten Bezugsquellen kam ich dann zum Softwarevertrieb Heine. In einem sehr angenehmen Telefongespräch empfahl mir eine Mitarbeiterin, das MSDN-Abo als OPEN-Lizenz zu bestellen. Ein großer Vorteil dabei wäre, dass die Laufzeit einer OPEN-Lizenz zwei Jahre beträgt, die eines normalen MSDN-Abos dagegen (bekannterweise) nur ein Jahr. Preislich gesehen kommt man mit der OPEN-Lizenz sogar noch günstiger weg, so dass ich das Angebot gerne annahm.
Heute kamen nun die Autorisierungs- und Lizenznummer, mit denen sich auf dem Webportal eOPEN die Lizenzen verwalten lassen. Nach der Aktivierung der Lizenz konnte ich mit Hilfe des Verwaltungstools für MSDN-Abonnements auch gleich das MSDN-Abo freischalten. Nervige Produktaktivierungen werden in nächster Zeit wohl nicht mehr nötig sein, da es bei OPEN License Volumen-Lizenzschlüssel gibt. 🙂
Releasezeiten
Ich hatte mir Anfang des Jahres zwar vorgenommen, das Jahr relativ stressfrei zu verbringen, aber in den Wochen vor und nach Veröffentlichung einer neuen Version lässt sich eine gewisse Anspannung nicht vermeiden.
In der letzten Phase des Betatests vor dem Erscheinen eines Updates werden nur noch Fehler korrigiert. Neue Funktionen werden nicht mehr eingebaut, da diese nicht mehr ausreichend getestet werden können. Zwischen Betatest und Veröffentlichung des Updates liegen dann meist noch ca. 14 Tage, in denen nur noch schwerwiegende Probleme (sogenannte Showstopper) behoben werden. Nach der Freigabe beginnt dann das bange Warten, ob meine fleißigen Betatester nicht doch den einen oder anderen Fehler übersehen haben. Aufgrund des hohen Funktionsumfangs ist das auch nicht vermeidbar. In der 11.1 hatte sich z.B. ein Fehler bei der Erkennung von mit dem SC8 verschlüsselten SCB-Archiven eingeschlichen. Dies wurde erst nach der Veröffentlichung von einem Anwender entdeckt, der solche Archive noch entpacken möchte. In dieser ganzen Zeitspanne steht die Entwicklung neuer Funktionen praktisch still. Um diese Zeit über das Jahr gesehen möglichst gering zu halten, versuche ich, Updates für SpeedCommander und Squeez kurz hintereinander zu legen.
Die Anspannung hängt auch davon ab, wieviel Code seit der letzten Version überarbeitet wurde. Anfang des Jahres habe ich mich z.B. in einen großen Teil des von Rainer übernommenen Codes eingearbeitet und diesen auch aufgeklart. Dabei bleibt es leider nicht aus, dass sich auch Fehler einschleichen. Der eine oder andere wird sich jetzt sicher fragen: Warum lässt Du es dann nicht einfach so, wie es ist? Nun, fremder Code ist fast wie eine Blackbox. Man hat keinen Überblick über das Ganze und hangelt sich bei der Fehlersuche von einer Zeile zur anderen. Erweiterungen sind auch nur schwer möglich, da man aufgrund des fehlenden Überblicks nicht abschätzen kann, wo man ansetzen muss und welche Seiteneffekte auftreten könnten. Daher habe ich mir angewöhnt, fremden Code Stück für Stück durchzugehen und in meinen Schreibstil zu übertragen. Das hilft enorm, vorhandene Zusammenhänge aufzudecken und die Funktionsweise des Moduls schrittweise zu erfassen.
Wie es ausschaut, kann es nun mit dem Programmieren weitergehen. Irgendwie kribbelt es auch schon wieder in den Fingern…
Nervige Produktaktivierung
Heute abend bin ich zum ersten Mal mit der telefonischen Produktaktivierung bei Microsoft in Kontakt gekommen. Nach dem Zurückspielen eines Images und der aufgrund eines Motherboard-Wechsels inkl. Prozessor nötigen Reparaturinstallation begrüßte mich Windows beim ersten Start mit dem Hinweis, dass es ohne sofortige Aktivierung keine Anmeldung gibt. Bisher hatte ich jede Software immer über das Internet aktivieren können, aber nach einem fast vollständigen Systemwechsel gab es nach der Reparaturinstallation natürlich noch keine funktionsfähige Netzwerkverbindung. Dazu auch überhaupt keine Möglichkeit, irgendwelche Treiber installieren zu können, selbst im abgesicherten Modus sperrt sich Windows in jeder Hinsicht gegen eine Anmeldung.
Es blieb mir also nichts anderes übrig, als zum ersten Mal die telefonische Aktivierung zu benutzen. Knappe fünf Minuten war ich damit beschäftigt, erst endlose Zahlenkolonnen in das Telefon zu tippen und anschließend die viel zu schnell durchgesagten Aktivierungsziffern auf die Tastatur zu bringen. Erschwerend kommt hinzu, dass man mit einem Festnetztelefon 2m neben dem Rechner auch nicht die besten Karten hat.
Ich habe vollstes Verständnis für den Kampf gegen Produktpiraterie, aber muss man den Kunden wirklich so quälen?
Neues Icon
Seit ein paar Tagen läuft SpeedCommander bei mir mit einem neuen Programmsymbol. Anfangs war es auch recht ungewohnt und ich habe trotz bereits geöffnetem Programm immer wieder eine neue Instanz gestartet, weil das Auge vergeblich den gewohnten Feuerschweif gesucht hat.
Programmfenster:
Taskbar:
32×32-Symbol:
Eigentlich war das neue Symbol schon für die 11.1 geplant, die Zeit am Ende war aber zu kurz für einen ausführlichen Praxistest. Jede Wette, dass es wieder einige gibt, denen es überhaupt nicht gefällt. Aber allen recht getan, ist eine Kunst, die keiner kann. Auch nicht Alexandra.
Spalten für alle Ansichten
Beim Durchstöbern des Vista-SDKs habe ich eine nette Funktion gefunden. Mit dem Flag LVS_EX_HEADERINALLVIEWS zeichnet das ListView-Control die Spaltenheader auch für alle anderen Ansichten, bisher erfolgte dies nur für die Detailansicht. Das ganze sieht dann so aus:
Vista und das ShellTaskScheduler-Objekt
Bis einschließlich zum SpeedCommander 10 habe ich Hintergrundaufgaben immer in einem zusätzlichen Thread abgearbeitet. Neben der Verwaltung für die Threads war nachteilig, dass der Hintergrundthread immer erst gestartet werden konnte, nachdem alle Dateieinträge der Dateiliste hinzugefügt wurden. Weiterhin wurden immer alle Informationen ermittelt, da der Hintergrundthread nicht genau erkennen konnte, ob ein Element nun angezeigt wird oder nicht.
Während der Entwicklung von SpeedCommander 11 habe ich dann das ShellTaskScheduler-Objekt entdeckt. Das ShellTaskScheduler-Objekt wird von der Shell zur Verfügung gestellt und implementiert die Schnittstelle IShellTaskScheduler. Es wird mit kleinen Aufgaben gefüttert, die es der Reihe nach in einem Hintergrundthread abarbeitet. Eine Aufgabe ist ein kleines COM-Objekt, welches die Schnittstelle IRunnableTask implementieren muss. Über diese Schnittstelle kann das ShellTaskScheduler-Objekt die Aufgabe dann starten, anhalten, weiterführen oder beenden. Der Programmierer muss sich mit der Threadsteuerung überhaupt nicht beschäftigen.
Das ShellTaskScheduler-Objekt wird im SpeedCommander 11 für alle Hintergrundaufgaben bei der Anzeige eines Ordners verwendet. Dazu gehört das Ermitteln der Dateisymbole, zusätzlicher Informationen in der Detailansicht und das Berechnen der Ordnergrößen. Speziell bei der Anzeige von dynamischen Icons und Miniaturansichten lässt sich im Vergleich zu früheren Versionen ein großer Geschwindigkeitsschub feststellen.
Unter Vista hat das aber plötzlich nicht mehr funktioniert, alle Icons sahen bis auf die Programmdateien gleich aus. Im Debugger musste ich erkennen, dass die Erstellung des ShellTaskScheduler-Objekts fehlschlug:
IShellTaskScheduler2Ptr pScheduler; HRESULT hResult = CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_IShellTaskScheduler, (void**) &pScheduler);
Die Funktion CoCreateInstance gibt unter Vista den Fehlercode E_NOINTERFACE zurück, während es auf allen anderen Systemen von Windows 98 bis Windows XP nie Probleme gab.
Ändert man nun die gesuchte Schnittstelle von IID_IShellTaskScheduler auf IID_IUnknown, so wird das ShellTaskScheduler-Objekt erstellt und kann dann ganz normal verwendet werden:
IShellTaskScheduler2Ptr pScheduler; HRESULT hResult = CoCreateInstance(CLSID_ShellTaskScheduler, NULL, CLSCTX_INPROC, IID_IUnknown, (void**) &pScheduler);
Unklar bleibt mir aber, warum Microsoft das ganze geändert hat. Die angepasste Version funktioniert übrigens auch auf allen bisherigen Systemen.
Punktlandung
Was wir heute als Legacy-Systeme bezeichnen, ist eigentlich einfach nur das, was inzwischen funktioniert.
Gregory Fitzgerald, Vice President Marketing and Product Management bei Tipping Point, der IT-Security Division von 3Com
Gefunden als Zitat der Woche in Computer Reseller News 9/2006
Werbegeschenke
Die ersten Werbegeschenke sind heute eingetroffen, das kleine Werbeset besteht aus Kugelschreibern, Feuerzeugen und Messern.
Macht alles einen netten Eindruck und stößt auf gute Resonanz. Ich werde wohl noch etwas Nachschub bestellen müssen.
10 Dateimanager im Vergleich
In der Ausgabe 4/2006 der PC-Professionell werden in einem sehr umfangreichen Vergleichstest 10 Dateimanager getestet. SpeedCommander erhält zum wiederholten Mal die Empfehlung der Redaktion.
Den Testsieg erringt SpeedCommander 11 mit leichtem Vorsprung gegenüber Directory Opus 8.2. Unterm Strich setzt sich die Mischung aus überdurchschnittlicher Leistung, sinnvollen Extras und sehr guter Bedienerführung durch. Mit dem akzeptablen Preis von 38 Euro ist SpeedCommander 11 uneingeschränkt empfehlenswert.
Also wenn das kein Grund zur Freude ist. 🙂
Developer Security Training mit Tücken
Bis vor kurzem hat Microsoft kostenlos eine DVD verschickt, in der Frank Fischer einige für den Programmierer wichtige Sicherheitsaspekte bei der Entwicklung beschreibt. Ein Schwerpunkt ist die Beschreibung von Pufferüberläufen und Strategien zu ihrer Vermeidung. In kleinen Codebeispielen wird demonstriert, was bei Pufferüberläufen passiert und was der Entwickler dagegen tun kann.
Pufferüberläufe treten sehr häufig bei Stringfunktionen auf, weil beim Kopieren von Strings oft nicht geprüft wird, ob der Zielpuffer groß genug für die Aufnahme des Strings ist. Abhilfe schaffen hier die sicheren Stringfunktionen, welche die Zielpuffergröße immer beachten und sicherstellen, dass der Zielstring explizit mit einem NULL-Zeichen abgeschlossen wird. Zur Demonstration der sicheren Stringfunktionen wird folgendes Beispiel verwendet:
void DisplayResult(HRESULT hr); int _tmain(int argc, TCHAR *argv[]) { TCHAR pszDest[10]; // String size OK HRESULT hr = StringCchCopy(pszDest, sizeof(pszDest), "Hello"); DisplayResult(hr); // String size TOO big hr = StringCchCopy(pszDest, sizeof(pszDest), "This is a rather long string"); DisplayResult(hr); TCHAR pszFullName[25] = "Oliver"; TCHAR *pszSrc = " Hughes"; // Resultant string less than 25 hr = StringCchCat(pszFullName, sizeof(pszFullName), pszSrc); DisplayResult(hr); // Now we'll add more to the string hr = StringCchCat(pszFullName, sizeof(pszFullName), " James Hughes "); DisplayResult(hr); printf("\nPress a key to continue\n"); getch(); return 1; }
Der jeweils zweite Parameter bei StringCchCopy und StringCchCat gibt die Größe des Puffers an. Die Funktion DisplayResult ermittelt die Beschreibung für die von den Stringfunktionen zurückgegebenen Fehlercodes und gibt diese in einem Konsolenfenster aus:
Der Vorgang wurde erfolgreich beendet.
Der an einen Systemaufruf übergebene Datenbereich ist zu klein.
Der Vorgang wurde erfolgreich beendet.
Der an einen Systemaufruf übergebene Datenbereich ist zu klein.
Bis hier sieht alles ganz vernünftig aus, richtig gefährlich wird es aber, wenn man das vorgestellte Beispiel mit Unicode kompiliert. Hierfür müssen lediglich alle Strings als Unicode gekennzeichnet werden, zusätzlich wird printf durch das Makro _tprintf ersetzt. Durch den konsequenten Einsatz der Wrapper-Makros aus TCHAR.H ist es sehr einfach, Ansi- und Unicode-Version einer Anwendung in einem Quelltext zu verwalten. Anhand der Verwendung von _tmain als Hauptfunktion und TCHAR als universellen Datentyp für Ansi-/Unicode-Zeichen sieht man, dass der Autor des Beispiels eine Verwendung für Unicode bereits angedacht hat.
void DisplayResult(HRESULT hr); int _tmain(int argc, TCHAR *argv[]) { TCHAR pszDest[10]; // String size OK HRESULT hr = StringCchCopy(pszDest, sizeof(pszDest), _T("Hello")); DisplayResult(hr); // String size TOO big hr = StringCchCopy(pszDest, sizeof(pszDest), _T("This is a rather long string")); DisplayResult(hr); TCHAR pszFullName[25] = _T("Oliver"); TCHAR *pszSrc = _T(" Hughes"); // Resultant string less than 25 hr = StringCchCat(pszFullName, sizeof(pszFullName), pszSrc); DisplayResult(hr); // Now we'll add more to the string hr = StringCchCat(pszFullName, sizeof(pszFullName), _T(" James Hughes ")); DisplayResult(hr); _tprintf(_T("\nPress a key to continue\n")); getch(); return 1; }
Führt man das Programm nun aus, dann werden folgende Meldungen ausgegeben:
Der Vorgang wurde erfolgreich beendet.
Der an einen Systemaufruf übergebene Datenbereich ist zu klein.
Der Vorgang wurde erfolgreich beendet.
Der Vorgang wurde erfolgreich beendet.
Anschließend erscheint ein Hinweis von Windows:
—————————
test.exe – Fehler in Anwendung
—————————
Die Anweisung in „0x00680074“ verweist auf Speicher in „0x00000001“. Der Vorgang„written“ konnte nicht auf dem Speicher durchgeführt werden.
Klicken Sie auf „OK“, um das Programm zu beenden.
Klicken Sie auf „Abbrechen“, um das Programm zu debuggen.
—————————
OK Abbrechen
—————————
Nun haben wir das, was eigentlich durch die Verwendung von sicheren Stringfunktionen vermieden werden sollte – einen waschechten Pufferüberlauf. Schaut man sich die Definition von StringCchCopy und StringCchCat nämlich genauer an, dann sieht man, dass diese Funktionen die Größe des Puffers in Zeichen und NICHT in Bytes haben möchten. Umso verwunderlicher ist das ganze, da in einem späteren Kapitel des Vortrags zu möglichen Unicode-Problemen mehrfach explizit darauf hingewiesen wird, dass Puffergrößen bei Unicode-Strings immer mit sizeof(WCHAR) berechnet werden sollen.
Im obigen Beispiel soll den beiden sicheren Stringfunktionen zugesichert werden, dass 10 beziehungsweise 25 Zeichen für den Text zur Verfügung stehen. In der Ansi-Version funktioniert das auch wunderbar, da hier ein Zeichen nur ein Byte groß ist und der sizeof-Operator 10 bzw. 25 zurückgibt. Unicode-Zeichen sind aber immer zwei Bytes groß, so dass der sizeof-Operator im Beispiel 20 bzw. 50 Bytes zurückgibt. Die beiden Stringfunktionen kopieren daher in Anbetracht des großen Puffers munter drauflos. Da aber in Wirklichkeit nur 10 bzw. 25 (und nicht 20 bzw. 50) Zeichen zur Verfügung stehen, kommt es zu einem Pufferüberlauf.
Vermeiden lässt sich das ganze, indem man bei Pufferangaben von Zeichenketten statt sizeof konsequent das Makro countof verwendet. Hierbei wird die von sizeof zurückgegebene Größe durch die Größe des ersten Elements geteilt, welches bei Ansi-Strings ein Byte und bei Unicode-Strings zwei Byte beträgt.
void DisplayResult(HRESULT hr); #define countof(array) (sizeof(array)/sizeof(array[0])) int _tmain(int argc, TCHAR *argv[]) { TCHAR pszDest[10]; // String size OK HRESULT hr = StringCchCopy(pszDest, countof(pszDest), _T("Hello")); DisplayResult(hr); // String size TOO big hr = StringCchCopy(pszDest, countof(pszDest), _T("This is a rather long string")); DisplayResult(hr); TCHAR pszFullName[25] = _T("Oliver"); TCHAR *pszSrc = _T(" Hughes"); // Resultant string less than 25 hr = StringCchCat(pszFullName, countof(pszFullName), pszSrc); DisplayResult(hr); // Now we'll add more to the string hr = StringCchCat(pszFullName, countof(pszFullName), _T(" James Hughes ")); DisplayResult(hr); _tprintf(_T("\nPress a key to continue\n")); getch(); return 1; }
Die sicheren Stringfunktionen sind eine feine Sache und helfen bei richtiger Anwendung enorm, mögliche Pufferüberläufe schon im Ansatz zu bekämpfen. Es ist allerdings sehr schade, dass gerade dieses Beispiel auf der DVD einen solchen Patzer enthält. Entwickler, die beim Anschauen zum ersten Mal mit sicheren Stringfunktionen in Kontakt geraten, werden sich vermutlich am gezeigten Beispiel orientieren und damit unbeachsichtigt wieder potentielle Pufferüberläufe einbauen, die sie eigentlich vermeiden wollten.
Auf der Rückseite der DVD steht übrigens:
Start training to become our Security Champion! Pay close attention to the contents of this DVD and you’ll be ready to tackle almost any security question in the future. Have fun honing your skills!
Hoffentlich verlässt sich der eine oder andere Entwickler nicht zu sehr darauf.