Bug in CPropertyPage und „Certified for Vista“

Der von mir gemeldete Bug Bug in der MFC71.DLL bzgl. CPropertySheet/CPropertyPage führt dazu, dass ein Programm, dass den genannten Voraussetzungen entspricht, bei den Test für „Certified for Vista“ durchfällt!

Der Application Verifier führt bei den Basic Test einen Page Boundary Check durch. Dabei werden alle Allokationen so durchgeführt, dass sie immer am Ende einer Memory Page erfolgen. Jeder Zugriff über die Grenze hinweg führt dann zu einem Crash.

Im realen Leben ist der Crash wirklich selten, aber mit dem Application Verifier kracht es sofort. Das Problem ist, dass dieser Basic Test Bestandteil von „Certified for Vista“ ist.

Die Folge man rasselt mit 100% Sicherheit durch!

Bug Report hier:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=270493

Dämlicherweise wurde auch dieser Bug von Microsoft als „Gelöst (Nicht reproduzierbar)“ markiert. Da kann man wirklich nurmit dem Kopf schütteln.

Und ein kleines Demo findet ihr hier:
Testprogramm für CPropertyPage Bug in MFC 7.1

Geschafft: Mein Software-Baby ist „Certified for Windows Vista“

Obwohl ich im Urlaub bin hat mich diese wirklich nette Nachricht von VeriTest erreicht:

Congratulations! AG-VIP SQL has successfully completed certification testing at VeriTest for the Microsoft “Certified for Windows Vista” logo program.

PS: Baby ist gut. AG-VIP SQL ist mittlerweile ein mittlerer Bolide… 😀

Vista beendet Programme auch wenn WM_QUERYENDSESSION FALSE returniert

Jeder kennt die nette Nachricht WM_QUERYENDSESSION die einem mitteilt, dass das System herunter gefahren wird, oder der Benutzer sich abmeldet.

Und wir alle sind auch einfach gewöhnt FALSE zu returnieren wenn wir das nicht wollen und damit waren wir sicher das WM_ENDSESSION mit FALSE gesendet wird und das System nicht herunterfährt. Ja! Richtig gelesen waren!

Das hat sich mit Vista nun auch geändert. Wird im lParam Bit ENDSESSION_CLOSEAPP (0x1) gesetzt, dann spielt es keine Rolle wie das Programm es gerne hätte. Die Applikation soll und muss beendet werden. D.h. die Applikation muss auch mit dem Zustand zurecht kommen, dass die Daten nicht gesichert sind, bzw. eben mit dem Zustand, der uns veranlasst hat FALSE zu returnieren.
Dies war bisher ausgeschlossen. Deshalb sollte man sich über das Verhalten seines Programmes an dieser Stelle mal Gedanken machen.

Für MFC Anwender noch eine kleine Herausforderung denn OnQueryEndSession wird von der MFC ohne Parameter aufgerufen und ohne das Vista SDK ist natürlich ENDSESSION_CLOSEAPP nicht definiert

#ifndef ENDSESSION_CLOSEAPP
#define ENDSESSION_CLOSEAPP 0x1
#endif

BOOL CMainFrame::OnQueryEndSession()
{
// Need to get the lParam value for this message to
// determine the reason of the shutdown
LPARAM lParam = AfxGetCurrentMessage()->lParam;
if (lParam & ENDSESSION_CLOSEAPP)
{
  // We are forced to exit here, the user want to close the
  // application, even if we loose data
  OnForcedShutdown():
  return TRUE;
}
else
  // do the default
  return __super::OnQueryEndSession();
}

BTW: Eine normale MFC Applikation berücksichtigt dies nicht korrekt. Es wird der Status von allen Dokumenten geprüft und evtl. einen entsprechender Dialog angezeigt, wenn eines der Dokumente nicht gespeichert ist. Wird aber die Anfrage mit ENDSESSION_CLOSEAPP gesendet, dann muss die Antwort in 5 Sekunden erfolgen. Einen Dialog anzuzeigen bzw. Frage zu stellen wie es die Standardimplementierung macht, passt hier nicht!

Man sollte sich unbedingt hier die Vista Änderungen zu Gemüte führen und gegebenenfalls auch ShutdownBlockReasonCreate implementieren.

Weitere Infos zu den Änderungen findet sich in der aktuellen MSDN:

Anmerkung: Jeder der sich mit der Vista-Zertifizierung auseinandergesetzt hat wird erkannt haben, dass es sich bei dem hier beschriebenen Verhalten um den Test Case 30 handelt, bzw. die Requirements, Reliability 3.1!

VS-2005 SP1 für Vista bringt kein Update für die MT.EXE

In meinem Beitrag UAC Trustinfo Manifest in ein VC-2005 SP1 Projekt einfügen habe ich berichtet wie man auf einfache Art und Weise ein UAC-Trustinfo-Manifest in ein VS2005 Projekt einbauen kann.

Dazu musste jedoch die MT.EXE aus dem Vista SDK in das entsprechende VC-Programmverzeichnis kopiert werden.

Ich hatte dies auch als Bug gemeldet und habe gehofft, dass dies auch im VS2005 SP1 für Vista noch behoben wird. Dem ist aber nicht so.
Die MT.EXE bleibt unverändert die Datei aus dem SP1 für VS2005. Und damit verbunden bleibt auch weiterhin das Versions Chaos. Wie schon berichtet haben beide Versionen aus dem Vista SDK und dem VS2005 SP1 die gleiche Versionsnummer. Wobei aber nur die Version aus dem Vista-SDK tut was man von ihr erwartet.

Der Application Verifier, mein neuer Freund

Durch die Vista Zertifizierung habe ich den Application Verifier von Microsoft als neuen guten Freund kennengelernt. Warum? Schauen wir uns mal den nachfolgenden Code an:

{
  CImageList il;
  il.Create(IDB_IMAGELIST,16,0,RGB(255,0,255));
  m_lcList1.SetImageList(&il,LVSIL_SMALL);
  m_lcList2.SetImageList(&il,LVSIL_SMALL);
  il.Detach();
}

Dieser Code ist natürlich fehlerhaft! Allerdings nicht ersichtlich auf den ersten Blick. Er erzeugt korrekt eine Image List. Setzt diese in ein List View 1 und auch in ein List View 2. Sofern LVS_SHAREIMAGELISTS nicht gesetzt wird die Image List beim Zerstören des List Views 1 freigegeben. Aber eben auch noch mal wenn List View 2 zerstört wird! Nicht gut.

Oder noch ein übles Beispiel:

{
  CImageList il;
  il.Create(IDB_IMAGELIST,16,0,RGB(255,0,255));
  m_lcList.SetImageList(&il,LVSIL_SMALL);
  ImageList_Destroy(il.m_hImageList);
}

Er erzeugt auch korrekt eine Image List. Setzt diese in ein List View und zerstört dann einmal die Image List über das Handle und anschließend noch einmal durch den Destruktor von CImageList. Und ein drittes Mal wird die Image List beim zerstören des List Views freigegeben. Übel übel!

Was passiert wenn dieser Code ausgeführt wird? Nichts…
Natürlich würde keiner so etwas programmieren 😉 . Aber man kann sich vorstellen, dass so etwas ablauftechnisch und programmiertechnisch schon mal passieren kann.
Alles ist scheinbar in Ordnung, obwohl hier eine Zeitbombe tickt.

Wie kommt man einem solchen Bug auf die Spur?
Der Titel dieses Beitrages gibt die Antwort: Der Application Verifier.

Man installiert den Verifier und fügt die Anwendung zu den Verifier Einstellungen hinzu. Man belässt es bei den Default Einstellungen und ergänzt am Besten noch unter Miscellaneous die Checkboxen für DangerousAPIs und DirtyStacks.

Sobald man nun den obigen Code im Kontext eines Debuggers ausführt bekommt man eine Exception! Wow… und wenn man einen entsprechenden Symbolserver hat und den Stacktrace betrachtet sieht man

comctl32.dll!CImageListBase::IsValid()+0x2a bytes
comctl32.dll!_HIMAGELIST_QueryInterface@12()+0x29 bytes
comctl32.dll!_ImageList_Destroy@4()+0x19 bytes

Das Ausgabefenster des Debuggers zeigt zusätzlich:

03D8F964 : Invalid address causing the exception.
75C273A8 : Code address executing the invalid access.
0012F08C : Exception record.
0012F0A8 : Context record.

Aus den Informationen kann man sich leicht denken was hier faul ist, oder sein könnte. Es empfiehlz sich die Anwendung auch im Release Mode mit Debug-Infos zu erzeugen. Das sollte sowieso Standard sein!

Es lohnt sich seine Applikation mal mit dem Application Verifier auszuführen, wenn man mal gerade nichts zu tun hat und man wundert sich dann, an welchen Stellen einem sein – so gut programmierter oder gut gemeinter – Code um die Ohren fliegt :mrgreen:

Für wen Qulitätssicherung kein Fremdwort ist, der kommt an diesem sehr nützlichen Tool nicht vorbei. Der Application Verifier und weitere brauchbare Infos findet sich hier auf der entsprechenden Produktseite von Microsoft:
http://www.microsoft.com/technet/prodtechnol/windows/appcompatibility/appverifier.mspx

Antivirus Software für Vista… NOD32

Mit Antivirus Software unter Vista ist das so eine Sache. Irgendwie haben es alle Hersteller nicht ganz so eilig gehabt.

Ich setze mittlerweile NOD32 ein und bin begeistert. Schnell unkompliziert simpel. Und mit der neuen Firewall von Vista frage ich mich ernsthaft was brauche ich mehr. (Ich sitze ja sowieso hinter einem Router mit Firewall wir die meisten).

Vormals habe ich Avira Personal Premium Antivirus Software verwendet aber die schlafen ja und haben frühestens für April Antivirus Software angekündigt. Schlapp…

Und nach meinen ersten Tests ist NOD32 schneller und belastet das System weniger.
Jetzt bin ich NOD32 Fan!

Infos hier: http://www.nod32.de/  oder http://www.eset.com

Vista auf Virtual PC und Multi-Session CDs

Ich habe auf meinen Entwicklungsrechner (XP SP2 DualCore 2GB Raid1 Controller etc.) für einige Tests von Installationsroutinen einen Satz von verschiedenen Virtual PC Images. Darunter auch ein Image für Vista.

Nun hatte ich eine Multi Session CD erstellt und nachträglich noch einige neuere Dateien in einer zweiten Session darauf gebrannt. CD in Virtual PC freigegeben, Dateien kopiert und… 😯 was sehen meine müden Entwickleraugen: Alle Dateien sind alt, oder genauer, alle Dateien sind von der ersten CD-Session. Die Dateien der zweiten Sessin werden nicht angezeigt.

CD auf dem XP-Host kontrolliert, alle Dateien OK. Nun scheinbar kommt Virtual PC nicht mit Multi-Session CDs klar. Ärgerlich und dazu habe ich selbst bei längerem googeln nicht einen einzigen Hinweis auf dieses Problem gefunden.
Wahrscheinlich habe ich die offensichtliche Readme.txt und KnownBug-List wieder mal übersehen.

UAC und CreateNamedPipe mit lpSecurityAttributes==NULL

Das Leben steckt einfach voller Überraschungen. Da hat man einen Service der im LocalSystem Account läuft. Mit diesem Service wird über Named Pipes kommuniziert.

Das Programm, das diesen Service steuert soll nur für Administratoren verfügbar sein und greift lesend und schreibend auf diese Pipe zu. Der Admin nutzt dieses Programm oft, muss man dazu sagen.

In der Vergangenheit war da nicht viel zu tun. Einfach lpSecurityAttributes auf NULL setzen und OK. Der Admin hat dann einfach das Steuerungsprogramm gestartet und war glücklich.
Nun unter Vista läuft aber das Steuerungsprogramm nicht mehr mit administrativen Privilegien.

  • Ist das Programm nicht Vista aware (also hat kein Trustinfo Manifest), dann hat man keinen Zugriff auf die Pipe. Den in diesem Fall wird der Admin Token ausgefiltert!
  • Ist es Vista aware und man setzt asInvoker als Trustinfo, dann hat man auch keinen Zugriff. Logo.
  • Nur requireAdministrator führt zum gewünschten Ziel. Natürlich wieder mit der (manchmal) lästigen Meldung für ein Programm das häufig benutzt wird.


❗ Also liebe Programmierer Gemeinde! Bitte die SECURITY_ATTRIBUTES richtig ausfüllen mit einer DACL die eben nicht mehr nur den lokalen Admin enthält.  Diese bei CreateNamedPipe verwenden und dann kann das Programm auch normal mit asInvoker gestartet werden.

Ach ja! Und ehe ich es vergessen ein NULL DACL ist hier nicht im Sinne des Erfinders… 🙂

😐 Insgesamt ärgerlich:
Man möchte es dem Benutzer möglichst einfach machen Programme zu nutzen. Der Vista-Admin-Privileg Dialog stört da manchmal (nicht immer). Also was macht man? Man setzt die Rechte für die Names Pipes und andere Objekte dieser Welt herunter, weil der Admin Token eben nicht mehr Bestandteil der Rechte ist für Programme die mit asInvoker gestartet werden.
Die Folge: Die Programme werden mit weniger Sicherheitsschranken gebaut, als zuvor.
War das im Sinne des Erfinders?

BTW: Da man sich mittlerweile schon blind angewöhnt hat, diesen Dialog zu bestätigen kann man sich fragen ob da noch ein Sicherheitsaspekt verbleibt, weil keiner mehr liest, welches Programm eigentlich administrative Rechte haben will.

Beim Entpacken von ZIP-Dateien setzt Vista manchmal das aktuelle Datum

Ich hatte gestern den neuesten High Definition Treiber von Realtek für meinen Laptop herunter geladen. Ich entpacke die ZIP-Datei und arbeite noch etwas weiter. Irgendwann schaue ich mir die entpackten Daten an und staune nicht schlecht. 😯

Boah, ich war wohl der erste der diesen Treiber herunter geladen hat, den die Uhrzeit aller Dateien ist gerade mal 5 Minuten her.

😕 Hmmm… Alle Dateien gelöscht. Das ganze nochmal. Wieder aktuelle Uhrzeit. Wie das?

Nun des Rätsels Lösung scheint ein kleiner Bug zu sein.
Die ZIP-Datei die man aus dem Internet heruntergeladen hat bekommt in einem Stream eine Info, die dafür sorgt das Dateien später beim Ausführen warnen. Diese Info kann man sich auch in den Datei Eigenschaften ansehen.
Da steht dann unten im Eigenschaftsdialog: „Diese Datei stammt von einem anderen Computer. Der Zugriff wurde aus Sicherheitsgründen evtl. geblockt.“ (Dämliche Übersetzung! Wieso wurde?)

Daneben finden wir einen netten Schalter Zulassen. Klickt man ihn, dann wird diese Zusatzinfo aus der Datei entfernt. Entpackt man nun die Datei, dann haben die Dateien auch das Datum, das auch beim Packvorgang gesetzt war und auch beim Anzeigen der Daten im ZIP-Verzeichnis zu sehen ist.

Scheinbar wird beim setzen dieser Zusatz-Sicherheits-Infos auch das ursprüngliche Datum vernichtet… ❗

UAC Trustinfo Manifest in ein VC-2005 SP1 Projekt einfügen

An sich ist die Sache ganz einfach. Man erzeugt eine Manifest-Datei z.B. mit dem Namen Trustinfo.manifest, die nur den entsprechenden <trustinfo> Block enthält (und nicht mehr). Um die anderen Manifest Daten für CRT und COMCTL32 v6.0 kümmert man sich erstmal nicht, das soll ja MT.EXE und der Linker machen. Diese Datei fügt man in das Projekt ein. VS erkennt die Endung und der Manifest-Compiler soll diese Datei nun mit den anderen Manifest Daten mischen und das finale Manifest erzeugen.
Man wirft den Compiler an und… 🙄 … erhält die Fehlermeldung:
.\TrustInfo.manifest : manifest authoring warning 81010002: Unrecognized Element „requestedPrivileges“ in namespace „urn:schemas-microsoft-com:asm.v3“.

Entsprechende Recherche ergab, dass nur die MT.EXE aus dem Vista SDK dieses Manifest korrekt einmischt. Die funktionierende MT.EXE hat es nicht in das 2005 SP1 gepackt 🙁 .

OK also Vista SDK herunterladen installieren. MT.EXE ansehen und… 🙄
Die MT.EXE aus 2005 SP1 ist vom 2006-12-02 07:17,
die MT.EXE aus dem Vista SDK ist vom 2006-10-19 14:52,
beide haben eine Größe von 727.552 Bytes und haben die gleiche Versionsnummer 5.2.3790.2075. Es ist nicht zu fassen.

OK packen wir also trotzdem die MT.EXE aus dem Vista SDK in das Verzeichnis C:\Program Files\Microsoft Visual Studio 8\VC\bin

Nun kompilieren wir das Projekt noch einmal und nun… :mrgreen:
wunderbar, das Projekt kompiliert wie erwartet. Das Manifest wird eingefügt. Die erzeugte EXE hat alle entsprechenden Manifeste eingebettet.

Wen es interessiert, die Bug-Meldung bzgl. der Versionsnummer ist hier zu finden:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=258108

Es sei noch angemerkt: Mein Testrechner ist ein Vista-Ultimate Laptop. Installiert war auch das VS-2005 SP1 Beta für Vista. Auch diese Version enthält keine kompatible MT.EXE!
Danke Jochen für den Hinweis!