Manifeste sind nicht alles, DLLs und COM Objekte benötigen ISOLATION_AWARE_ENABLED oder ein eigenes Activation Context Handling

Ich habe eine DLL die einiges an Datenbank I/O für ein Produkt übernimmt. Diese DLL sollte in einem Service eingesetzt werden.
Eigentlich ist diese DLL immer nur Teil eines vollen UI Projektes und hat auch einige kleine visuelle Komponenten. Entsprechend prüft eine Init Funktion bestimmte Voraussetzungen, die für das korrekte Arbeiten notwendig sind wie: mindestens MS-XML 3.0, IE ab Version 5.1, Common Control 6.0 (also mit Manifest).
Soweit so gut. Die DLL selbst wurde mit einem Manifest (Typ 2) versehen und in den Service mit eingebaut.

Eigentümlicherweise startete der Service nicht. Die Init Funktion meldete immer, dass die Requirements nicht gegeben wären. Was eigentlich nicht sein kann, weil der selbe Code in einem anderen Kontext eines GUI Programms perfekt funktioniert.

Ein wenig debuggen zeigte, dass die Common Control 6.0 nicht gefunden wurden.
Eigentlich kein Wunder. Der Service hat keine UI, es gibt keinen Code der die Common Control 6.0 verwendet, allerdings hatte meine DLL ja ein entsprechendes Manifest für die Common Control 6.0 DLL.
Aber der Versionstest in der DLL lädt immer die 5er Version, also die Version ohne Manifest.

Es dauerte eine Weile bis es bei mir klingelte und ich verstand worin das Problem lag:

  • Wenn man ein Manifest in einer DLL mit dem Code 2 einträgt (ISOLATIONAWARE_MANIFEST_RESOURCE_ID), dann funktioniert dieses Manifest wenn in diesem Moment die ComCtl32.dll implizit geladen werden sollte.
  • In meinem Fall aber klappte das nicht. Die DLL wurde nicht implizit geladen. Die Versionkontrolle später führte LoadLibrary direkt durch und führte dann DllGetVersion aus (mit GetProcAddress ermittelt).
  • In meinem Fall bedeutet das aber, das LoadLibrary im Aktivierungskontext (Activation Context) der EXE ausgeführt wird, und die hat kein ComCtl32 Manifest für die Version 6.0. Es ist ja auch nur ein Service.
  • Damit es funktioniert muss man in jedem Fall auch den folgenden Define setzen.
#define ISOLATION_AWARE_ENABLED 1
  • oder man muss dafür sorgen, dass man seinen eigenen Aktivierungskontext nutzt. Sprich seine Manifeste, die man selber möchte.
  • Durch diesen define, werden bestimmte Funktionen wie CreateWindow, LoadLibrary, CoCreateInstance, SendMessage und andere durch einen inline-Code ersetzt der einen Aktivierungkontext benutzt und die aktuellen Manifeste der DLL bestimmt und benutzt.

In meinem Fall hieß die Lösung nicht LoadLibrary zu benutzen sondern GetModuleHandle und wenn eben ComCtl32 gar nicht im Speicher ist, also auch nicht benutzt wird auch keinen weiteren Test durchzuführen, aber zur Sicherheit habe ich auch ISOLATION_AWARE_ENABLED gesetzt.

Siehe auch:
http://msdn.microsoft.com/en-us/library/aa376607(VS.85).aspx
http://msdn.microsoft.com/en-us/library/aa375197(VS.85).aspx

ComboBox DropDown Höhe wird nicht mehr durch die Ressourcen definiert

Vor Jahren habe ich für die microsoft.public.de.vc FAQ den folgenden Beitrag geschrieben:
Warum klappt meine ComboBox im DropDown-Stil in einem Dialog nicht auf?

Beim Erstellen einer ComboBox in einem Dialog Template muss auch die Größe mit angegeben werden, die die ComboBox haben soll, wenn Sie denn aufgeklappt wird. Dies kann auf zwei Methoden geschehen.

Methode 1: ComboBox aus der Werkzeugleiste einfach durch einen Mausklick einsetzen. Anschließend auf den „DropDown“-Schalter klicken und nun die gewünschte Größe einstellen.

Methode 2: ComboBox durch Ziehen eines Rechteckes auf dem Dialog einsetzen. In diesem Fall wird die Größe gleich korrekt bestimmt. Nachträgliche Änderung der Größe erfolgt dann wieder durch anklicken des „DropDown“-Schalters.

Anmerkung: Die Größe einer ComboBox mit dem Stil CBS_DROPDOWN und CBS_DROPDOWNLIST im NICHT aufgeklappten Zustand kann beim Erzeugen nicht verändert werden. Diese Größe bestimmt Windows automatisch. Die Größe die bei CreateWindow/CreateWindowEx angegeben wird ist immer die Größe des Control im aufgeklappten Zustand. Nachdem ein gültiger Windowshandle auf die ComboBox existiert kann mit CComboBox::SetItemHeight die Höhe der Items bzw. des Editfelds der ComboBox verändert werden.

Jetzt habe ich entdeckt, dass dieser Beitrag eigentlich überflüssig geworden ist, seit dem es COMCTL32 in der Version 6.0 gibt.
Wenn ein Manifest für die 6.0 Version der Common Controls vorhanden ist, dann bestimmt die COMCTL32 DLL automatisch selbst anhand der Höhe des Monitors und der Position der ComboBox wie groß der DropDown-Bereich sein kann.

Aufgefallen ist mir das, als ich in einer RC-Datei sah, dass eine ComboBox mit der Höhe gerade einmal 20 DLUs angegeben wurde. Da in der RC Datei normalerweise immer nur die DropDown-Höhe eingetragen ist, fragte ich mich warum bisher niemandem aufgefallen war, dass diese ComboBox, nicht aufklappt. Ein kurzer Test, zeigte allerdings, dass alles normal war und die Box, den halben Monitor in der Höhe einnahm.
Ein weiter Test mit und ohne Manifest zeigte mir dann schnell, dass sich das Standardverhalten von Comboboxen offensichtlich verändert hat.

Nachtrag (07.01.2011):
Nur die neuen Common Controls ab Vista und Windows 7 verhalten sich wie oben beschrieben. Windows XP (einschließlich SP3) verhält sich noch gemäß der MSDN WinAPI Doku. D.h. die Höhe wird nicht automatisch angepasst. Man kann sich eben auf nichts verlassen.

BUG: VS-2010 vergisst regelmäßig die Tastaturkürzel für Extensions und Addins

 Toll ist, das es für VS-2010 wirklich viele nützliche Extensions gibt. Das heißt aber auch, dass man des öfteren mal ein Update einer solchen Extension installiert. Und jetzt wird es ärgerlich. Jedesmal wenn man ein Update einer Extension installiert dann sind alle Tastaturzuordnungen auf ALLE Extensions und Addins futsch.

Mich hat das so genervt, dass ich einen entsprechenden Bugreport eingereicht habe:
https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=621929

Wie man lesen kann: „A known issue!“. Na dann hoffen wir mal auf einen Hotfix… 😉 (also bitte gebt Eure Votes ab), wie immer stirbt die Hoffnung zuletzt..

Ich kann jedem nur raten, die eigenen Einstellungen des Visual-Studios über die Import/Export Funktionen regelmäßig zu sichern. Dann kann man bei Bedarf auch die Tastaturmappings alleine wieder zurückspielen…

TFS-2010 zeigt nicht alle Historien Einträge für Dateien

Ein Kunde meldete ein Problem und ich entdeckte einen Fehler. Ich wollte wissen wann dieser Fehler in die Software kam oder ob er evtl. schon immer vorhanden war. Also bemühte ich die Historie des Team Foundation Servers. Allerdings erschien mir diese nicht komplett.

Vor ca. 2 Jahren habe ich einige Projekte umstrukturiert und dabei auch Verzeichnisse verschoben. Und genau bis zu diesem Punkt konnte ich die Historie einsehen.

Nach ein bisschen Recherche im Netz fand ich diesen Report auf Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/538032/tfs-2010-does-not-display-history-for-a-renamed-folder
Und in dieser Meldung fand ich dann auch den entsprechenden Workarround.

Erst der Befehl:
tf.exe history  „C:\Dev\Root\Projects\the file name I am looking for.cpp“   /itemmode
zeigt die komplette Historie:

Frag mich bitte keiner warum das so sein muss 😉 Slotmode / Itemmode? Brauchen wir das wirklich?

In VS-2010 SP1 wird sich einiges bzgl. des Help-Viewers tun…

Das sich doch relativ viele Entwickler (wie auch ich hier in meinem Blog) negativ über die MSDN-Hilfe Integration in VS-2010 geäußert haben hat scheinbar Spuren hinterlassen, wie in Jeff Brattens Blog zu lesen ist:

http://thirdblogfromthesun.com/2010/10/the-story-of-help-in-visual-studio-2010/
http://thirdblogfromthesun.com/2010/10/the-story-of-help-in-visual-studio-2010-part-2/
http://thirdblogfromthesun.com/2010/10/the-story-of-help-in-visual-studio-2010-part-3/

Besonders Teil 3 mit dem Ausblick auf SP1 ist interssant. Ich zitiere direkt aus Part 3:

New Features in Visual Studio SP1

We’ve made three major changes to the Help Viewer in SP1. First, we’ve abandoned the browser-as-local-help-viewer and implemented a simple client application for offline help. The help window is no longer lost in the set of browser tabs you have open and the help application icon can be easily located in the taskbar. F1 Help re-uses the currently active tab instead of creating a parade of open tabs that must be manually managed. The help application can be sized and placed anywhere on your desktop and retains its size and placement across sessions. The navigation panel width is resizable and it can be placed to the right or the left of the content.

Second, with the flexibility we gain from building a client application, we’ve re-introduced many of the productivity/efficiency features found in Document Explorer. The viewer features four navigation tabs: a fully-expandable table of contents that can be explored without reloading the current topic, a keyword index, a Favorites and History tab, and a search results pane. The search results pane allows you to refine your search queries without losing your current topic context. In addition, context menus and shortcut keys allow you to access features quickly without excessive need for a mouse.

Mein neuer Entwicklungsrechner…

Unsere Abteilung durfte für dieses Jahr (vor Weihnachten) noch Wünsche äußern. Und unser neuer Azubi brauchteinen besseren Rechner.
Jetzt bekommt er meinen Fujitsu Siemens Q8200 (Quad Core mit 2, 33 Ghz) mit 3GB RAM, 500GB Platte und Nvidia 9300 GE, das OS bisher war Window 7 Ultimate 32bit.

Ich habe schon meinen neuen ausgepackt ein Dell i7-870 (2,93GHz, 4 Cores, 8 Threads) mit 2x1TB Raid1 und 8GB Hauptspeicher dazu eine Nvidia GTX460 auch mit 1GB. Das Ganze wird dann mit Windows 7 Ultimate 64bit laufen.

Gegenüber meinem Intel Q8200 ist der neue rein gefühlsmässig im ersten Moment nicht schneller. Und von der schnellen Graka habe ich aktuell nichts, denn ich arbeite ziemlich oft nur Remote auf den Maschinen. Aber auf die 8GB Hauptspeicher und auf die 64bit Installation und virtuellen Maschinen, die meinen Rechner nicht mehr in die Knie zwingen, da freue ich mich schon echt drauf.

TFS Unshelve mit Merge

Ich und meine Kollegen benutzen gerne Shelvesets um uns Code gegenseitig zuschieben zu können, oder Testcode auszuprobieren.

Problematisch ist allerdings, dass die Dateien alle nicht ausgechecked sein dürfen, die man mit dem Shelveset laden möchte. Doof! Ein Merge ist mit VS-2010 nicht möglich, wenn man ein Shelveset lädt.

Glücklicherweise gibt es aber die Team Foundation Server Powertools. Und in diesem genialen Tool-Paket ist auch netterweise der Befehl: tfpt unshelve verfügbar! Und damit kann man in gewohnterweise, ein Shelveset in die eigenen bereits bearbeiteten Source hinein-mergen.

Erstaunen: CMemDC ist Bestandteil der MFC!

Wer Double Buffering benötigt und die MFC nutzt, der kennt auch CMemDC. Vermutlich eine der meist genutzten und kopierten Klassen, die auf CodeProject und CodeGuru vorgestellt wurden.
http://www.codeproject.com/KB/GDI/flickerfree.aspx
http://www.codeguru.com/cpp/misc/misc/flickerfreedrawing/article.php/c389/Flicker-free-drawing-using-memory-DC.htm

Ich habe meine Erweiterung hier im Blog vorgestellt und die liegt normalerweise in einem separaten Namespace, wie alle meine Tool-Klassen.

Nicht schlecht staunte ich, als ich keinen Compilerfehler bekam obwohl ich CMemDC nutzte aber keinen Namespace angab. Siehe da: CMemDC hat in einer eigenen Implementierung den Weg in die MFC gefunden. Man findet sie in:
C:\Program Files\Microsoft Visual Studio 10.0\VC\atlmfc\include\afxcontrolbarutil.h

Im Großen und Ganzen ist es die bekannte Standard-Implementierung, allerdings verfügt diese CMemDC Version auch Code, der auf Windows Vista und Windows 7, die fest im Betriebssystem verankerten Funktionen nutzt: BeginBufferedPaint, EndBufferedPaint
Siehe http://msdn.microsoft.com/en-us/library/bb773178(VS.85).aspx
Diese Funktionen werden innerhalb des Themeings von Windows Vista und Windows 7 verwendet und in dieser Funktionsgruppe ist auch Alphablending direkt verankert. (BufferedPaintSetAlpha). Ich vermute sogar, dass diese integrierten Klassen effektiver arbeiten, als die eigenen Klassen (ein Test steht noch aus), denn Windows weiß intern natürlich viel besser was wie zu puffern und zu zeichnen ist, als wir, wenn WM_PAINT aufgerufen wird.

Vielleicht ein guter Grund, die eigene CMemDC Klasse auch auf Vista/Windows 7 Funktionen zu erweitern oder die integrierte Klasse in der MFC zu verwenden.

Tipp: Übrigens hat die MFC CMemDC Klasse einen statischen Member, der es auf einfache Weise erlaubt das Double-Buffering abzuschalten (CMemDC:: m_bUseMemoryDC), dass ist besonders interessant beim Debuggen von grafischen Operationen, deren Ergebnisse man auch gleich sehen will, allerdings wird dieser Member nicht benutzt wenn das interne Windows Double-Buffering genutzt werden kann, schade eigentlich.

PS: Aber eigentlich muss man sich auch die Frage stellen, warum die Entwickler genau diesen Klassennamen verwendet haben, denn er provoziert ja auch direkt den Konflikt mit existierendem Code.