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.

Shell-Extension für die „alte“ Versionsanzeige in Vista+Windows7

Seit Windows Vista ärgere ich mich über die Anzeige der Datei-Eeigenschaften.
Bei ausführbaren Dateien gibt es nicht mehr den schönen Versionsinfo Dialog aus XP, sondern eine Detailseite, die nicht auf den ersten Blick alle Infos liefert die man als Entwickler möchte. Zudem unterschlägt die Seite noch einiges Wissenswerte.

Jetzt hat „Fish“ David B. Trout auf Codeproject eine Extension bereit gestellt, die die alte Versionsinfo wieder in den Explorer integriert.
Das Addin ist zwar nicht lokalisiert und zeigt die internen VERSIONINFO Tags an, aber das ist eigentlich kein Problem.

http://www.codeproject.com/KB/shell/VersInfoEx2.aspx

My vote: 5!

Mein 12. Award als deutscher MVP für Visual C++

Pünktlich am 01. Oktober 2010 bekam ich eine Email die wie folgt beginnt:

Sehr geehrte(r) Martin Richter,
herzlichen Glückwunsch! Wir freuen uns, Ihnen den Microsoft® MVP Award 2010 verleihen zu können!
Diese Auszeichnung wird an herausragende, führende Mitglieder der technischen Communities verliehen, die ihre wertvollen praktischen Erfahrungen mit anderen Menschen teilen. Wir schätzen Ihren außerordentlich bedeutenden Beitrag in den technischen Communities zum Thema Visual C++ im vergangenen Jahr hoch ein.

Das ist nun mein 12. Award für meine Aktivitäten in den C++ Communities ❗

Mittlerweile gibt es, nach meinem Kenntnisstand, nur noch in Kai Schätzl und Karl Donaubauer MVPs, die mit 13 Awards „dienstälter“ sind (ich beziehe mich hier auf den deutschsprechenden Raum).

Siehe auch http://mvp.support.microsoft.com/

Nette Falle im SQL-Server: Der Kompatibilitätsgrad

Nach einem der letzten Updates unserer Software meldete uns ein Kunde einen SQL Fehler, der bei einer bestimmten Operation auftrat. Er setzt den MS-SQL Server 2008 ein.

OK, meine Testumgebung hat drei Server von SQL 2000, über 2005 bis 2008 R2. Keine der Testumgebungen brachte bei der entsprechenden gleichen Operation einen Fehler 😕 Gut oder besser schlecht… Der Kunde bekommt nun eine Fehlermeldung und auch wenn Kunden meistens ja nicht recht haben wenn sie Fehler melden 😀 schaute ich mir dennoch alle SQL Befehle etwas genauer an, die meine Software da auslöste.
In dem entsprechenden Teil meiner wurde nach Benutzerangaben ein relativ komplexer Query durch einen Abfragegenerator zusammengebaut. Darunter fand sich auch der folgende Subquery, als Teil der gesamten Abfrage:

SELECT a.[Id] FROM [tblXYZ] AS a
  WHERE
    (((a..[IdParent] IS NULL
       AND a..[Id] NOT IN
         (SELECT [IdXYZ]
            FROM [tblSomething]
              WHERE [IdParent] IS NOT NULL))))

Unschwer zu sehen werden hier mit dem Alias a zusammen irgendwie zwei Punkte verwendet. Bleibt die Frage warum in meiner Umgebung nun kein Fehler passiert und beim Kunden ein nun Syntax Fehler ausgelöst wird.

Nach einigem Suchen fand ich die Ursache im Kompatibilitätsgrad, den man im Managementstudio unter Datenbank -> Datenbankname -> Eigenschaften -> Optionen je Datenbank separat einstellen kann. Dort sind folgende Einstellungen möglich.

SQL Server 2000 (80)
SQL Server 2005 (90)
SQL Server 2010 (100)

In meiner Testumgebung verwende ich eine Datenbank, die seit den ersten Anfängen unserer Software immer weiter als Testumgebung mit vielen Testdaten dient. Sie wurde erstmals auf einem SQL Server 2000 angelegt. Dann auf einen 2005er und schließlich auf einen SQL Server 2008 R2 umgezogen. Netterweise – oder besser dummerweise – hat sich der SQL Server bei jeder Umstellung die ehemalige Kompatibilität gemerkt. Und man staunt nicht schlecht: Auf einem SQL Server 2000 ist es kein Fehler zwischen Alias und Spaltennamen zwei Punkte zu schreiben. Bei einem SQL Server 2005 oder später ist das sehr wohl ein Syntaxfehler.
Der Fehler lag also doch bei uns – was ja wirklich selten vorkommt 😀 – und wurde trotz genauer Tests nicht entdeckt.

Man merke sich: SQL Server Syntax ist trotz gleicher SQL Server Version eben doch lange nicht das selbe.
Wer also Software auf einem SQL Server testet sollte tunlichst darauf achten welchen Kompatibilitätsgrad er benutzt ❗

Warum unter Vista und Windows 7 C:\Programme nicht genau dasselbe ist wie C:\Program Files

Jeder kennt von Windows Vista und Windows 7 die Junctions „C:\Programme“ oder „C:\Dokumente und Einstellungen“.
Diese Verweise erlauben es auch älteren Programmen die evtl. hardcodierte Verzeichnisnamen haben oder auch Programmen, die die alten Verzeichnisstrukturen von Windows 2000 und XP nutzen korrekt zu arbeiten.

Jetzt könnte man meinen, dass es vollkommen egal ist ob man nun „C:\Programme“ oder „C:\Program Files“ benutzt.
Aber das ist es nicht ❗ Es gibt ein paar ganz feine Unterschiede.

Ein simpler DIR auf der Befehlszeile

C:\>dir C:\Programme
 Datenträger in Laufwerk C: ist C-LAPTOP
 Volumeseriennummer: D483-432C

 Verzeichnis von C:\Programme

Datei nicht gefunden

macht das Problem offensichtlich!
Und was geht hier ab?

Die Antwort liefert ICACLS für die Junction:

C:\>icacls C:\Programme
C:\Programme Jeder:(DENY)(S,RD)
             Jeder:(RX)
             NT-AUTORITÄT\SYSTEM:(F)
             ORDEFINIERT\Administratoren:(F)

Dagegen zeigt ICACLS für das Verzeichnis selbst

C:\>icacls "C:\Program Files"
C:\Program Files NT SERVICE\TrustedInstaller:(F)
                 NT SERVICE\TrustedInstaller:(CI)(IO)(F)
                 NT-AUTORITÄT\SYSTEM:(M)
                 NT-AUTORITÄT\SYSTEM:(OI)(CI)(IO)(F)
                 VORDEFINIERT\Administratoren:(M)
                 VORDEFINIERT\Administratoren:(OI)(CI)(IO)(F)
                 VORDEFINIERT\Benutzer:(RX)
                 VORDEFINIERT\Benutzer:(OI)(CI)(IO)(GR,GE)
                 ERSTELLER-BESITZER:(OI)(CI)(IO)(F)

Während man auf „C:\Program Files“ die Rechte sieht, die man auch erwartet, liegt auf der Junction selbst eine Einschränkung:
Die Berechtigung zum „Ordner Auflisten“ wird verweigert für „Jeder“ ❗
Jeder der neu eingeführten Junctions hat diese Einschränkung.

Meines Erachtens wurde dies gemacht um beim Durchsuchen von Verzeichnisstrukturen nicht unendliche Rekursionen zu erzeugen oder Verzeichnisse oder Dateien doppelt aufzuführen.
Eine Verzeichnis Rekursion ergäbe sich zum Beispiel durch die Junction Anwendungsdaten im Verzeichnis C:\Users\Username\AppData\Local, der exakt wieder auf das Verzeichnis C:\Users\Username\AppData\Local verweist.

VS-Tipps & Tricks: MFC/ATL Tracing selektiv ein und ausschalten

In ATL und MFC steckt ein ziemlich ausgeklügelter Trace-Mechanismus. Wenn man sich das MFC – ATL Trace Tool ansieht kann man zu allen möglichen Kategorien Informationen in Debug Fenster ausgeben lassen.
Alleine die MFC hat 14 verschiedene Trace Kategorien. Darunter besonders interessante wie CommandRouting, AppMsg und WinMsg. Die ATL hat weitere 27 Kategorien.
Es lohnt sich mal einen Blick in dieses Tool und die entsprechenden Ausgaben zu machen. Es gehört zu den oft unbekannten netten Helferlein, die leider mangels Bekanntheit selten benutzt werden.

Um Fehler zu finden und einzugrenzen, sind mir jedoch oft eher zu viele Ausgaben vorhanden, als zu wenige. Zudem finde ich es manchmal unhandlich mit dem Trace-Tool die Nachrichten ab einem bestimmten Moment einzuschalten und wieder auszuschalten.
Ich habe eine kleine Hilfsklasse gebaut,mit der man in jedem Szenario, jederzeit zu einem bestimmten Moment das Tracing im Code ein- und automatisch wieder ausschalten kann.

class CDebugEnableTraceForCategory
{
public:
  CDebugEnableTraceForCategory(ATL::CTraceCategory &category,
           PCSTR pszPrompt=NULL,
           UINT uiLevel=4,
           ATL::ATLTRACESTATUS eStatus=ATL::ATLTRACESTATUS_ENABLED)
    : m_category(category)
    , m_uiSaveLevel(category.GetLevel())
    , m_eSaveStatus(category.GetStatus())
    , m_strPrompt(pszPrompt)
  {
    if (!m_strPrompt.IsEmpty())
      TRACE("%s - Tracelevel %d\n", m_strPrompt.GetString(),uiLevel);
    m_category.SetLevel(uiLevel);
    m_category.SetStatus(eStatus);
  }
  ~CDebugEnableTraceForCategory()
  {
    m_category.SetLevel(m_uiSaveLevel);
    m_category.SetStatus(m_eSaveStatus);
    if (!m_strPrompt.IsEmpty())
      TRACE("%s - Tracelevel %d\n", m_strPrompt.GetString(), m_uiSaveLevel);
  }
private:
  // Data fields
  ATL::CTraceCategory &m_category;
  ATL::ATLTRACESTATUS m_eSaveStatus;
  UINT m_uiSaveLevel;
  CStringA m_strPrompt;
  // no copy operator
  CDebugEnableTraceForCategory(const CDebugEnableTraceForCategory &);
  CDebugEnableTraceForCategory& operator=(const CDebugEnableTraceForCategory &);
};

Mit dieser Klasse kann ich zum Beispiel alle Windows-Nachrichten an MFC Fenster bei einer bestimmen Aktion ausgeben lassen. Und wenn die Aktion fertig ist stopp auch das Tracing wieder. 

Hier als Beispiel um alle Fensternachrichten in der Aktion LoadFrame zu Tracen: 

void CMyApp::InitInstance()
{
...
    CDebugEnableTraceForCategory trace(traceWinMsg,"messages in LoadFrame");
    pMainFrame->LoadFrame(IDR_MAINFRAME,WS_OVERLAPPEDWINDOW);
...
}

Weitere Infos in der MSDN findet man unter ATL::CTraceCategory und ATLTRACE2 http://msdn.microsoft.com/en-us/library/dhxsse89(VS.100).aspx

Breaking-Change: In VC-2010 in der STL wird 0 bzw. NULL nicht mehr gültiger Zeiger akzeptiert

Die STL Implementierung wurde klar hinsichtlich „perfect forwarding“ überarbeitet (Siehe C++0x). Allerdings sind dabei auch einige Sachen reingerutscht die dazu führen, dass sich mancher Code nicht mehr kompilieren lässt.

So führen die nachfolgenen Zeilen zu einem Compiler Fehler:

std::pair<void*,void*> p(0, NULL);
// fails with error C2440: 'initializing' : cannot convert from 'int' to 'void *'

Gleiches negatives Ergebnis erhält man, wenn man die folgenden Zeile kompiliert:

vector<void*> v; 
v.insert(v.begin(),NULL);

Der Hintergrund wird hier in dieser Connect Meldung beleuchtet:
https://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair?wa=wsignin1.0

Das Problem ist, das 0 (NULL) sich zwar brav in einen Zeiger umwandeln lässt. 0 (NULL) bleibt aber deshalb dennoch vom Typ her ein int ist wird nicht zu einem Zeiger. Die typensichere Implementierung in der STL führt nun dazu, dass 0 (NULL) nicht als void* akzeptiert wird.

Einzige Lösung und auch mein Rat:
Man verwendet nicht mehr 0 oder NULL, wenn ein NULL-Zeiger gemeint ist, sondern nullptr
Wer Code kompatibel zu VC-2008 und früher halten muss, kann ja in seinen Headern den folgende Definition einführen:

#if  _MSC_VER<1600
const int nullptr = 0;
#endif

Mehr zu perfect forwarding liest man hier:
http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
http://thbecker.net/articles/rvalue_references/section_07.html

Wie auch aus dem Connect Artikel zu entnehmen ist kann man damit rechnen, dass sich in VC11 alles wieder etwas zurückentwickeln wird. D.h. std::pair und auch die insert Befehle der Container sollen wirde brav 0 aktzeptieren können, wenn Zeiger gemeint sind. Gleiches bekam ich auch über meine Kontakte zur Produktgruppe zu höhren. Aber was VC11 betrifft ist alles sowieso nur Zukunftsmusik und alles noch im dichten Nebel und was wirklich Realität wird  muss man dann wohl erst mal sehen 😉

Nachtrag vom 09.09.2010:
Dravere hat in einem Kommentar auf eine geniale Implementierung für nullptr hingewiesen:
http://www.c-plusplus.de/forum/viewtopic-var-t-is-220511.html
Die ist weitaus besser als meine Definition als const int.

const class
{
public:
  template<class T> operator T*() const {return 0;}
  template<class C, class T> operator T C::*() const {return 0;}
private:
  void operator&() const;
}
nullptr = {};