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 = {};

Bug: CSimpleMap und CSimpleArray führen bei Verwendung von SetAtIndex zu einem Leak

Wieder einmal ein Bug, der seit VC-2005 bekannt ist und in meinen Augen unmöglich als by design abgetan werden darf.

Das Problem ist simpel, wenn man die Funktion SetAtIndex in den Klassen CSimpleMap und CSimpleArray angewendet wird, dann wird für das bestehende Element in der Map oder im Array kein Destruktor aufgerufen. D.h. eine CSimpleMap<CString,…> bzw. ein CSimpleArray<CString> führt mit der Verwendung von SetAtIndex sofort zu Leaks.

Tückisch in reinen ATL Projekten, weil hier der CRT Heap nicht benutzt wird und die Speicherleaks durch die CRT nicht entdeckt werden, weil der Win32 Heap zum Einsatz kommt.

Hier ist der Bug zu finden, inkl. der in meinen Augen korrekten Implementierung:
https://connect.microsoft.com/VisualStudio/feedback/details/298324/csimplemap-setatindex-do-not-call-a-ditructor

Für mich ist besonders diese Antwort äußerst fragwürdig:

CSimpleMap wasn’t really designed to work for types that needed destruction. The docs state it is limited and you should use CAtlMap instead.

Dieser Satz und dieser Hinweis ist in keiner Doku zu finden. Die Doku liest sich ganz anders:
http://msdn.microsoft.com/en-us/library/d1xc3983(VS.100).aspx

CSimpleMap provides support for a simple mapping array of any given type T, managing an unordered array of key elements and their associated values.

Man kann nur raten SetAtIndex nicht zu verwenden, sondern nur SetAt oder den operator[] ❗

MFC-Next 9.0 > MFC 10.0 denn CMFCRibbonPanel::EnableLaunchButton gibt es nicht mehr

Sehr erfreut waren viele C++ Entwickler darüber das es mit der MFC in VC-2008 weiter ging und MFC-Next veröffentlicht wurde. Das ganze wurde dann fest in VS-2008 SP1 integriert. Normalerweise sind wir es gewohnt, dass zur MFC nur Dinge hinzukommen und nichts wegfällt.

Für die MFC 10.0 aus VS-2010 gilt das diesmal nicht: MFC 10.0 < MFC-Next 9.0!

Irgendwie hat es CMFCRibbonPanel::EnableLaunchButton nicht in die MFC 10.0 geschafft, obwohl die Funktion vollständig in der MFC-Next 9.0 implementiert war. Das soll mal einer verstehen 😕 ich jedenfalls nicht!

Diese Funktion sorgt für den kleinen netten Schalter in einem Panel:

Erstaunlicherweise gibt es diese Funktion nun nicht mehr! Wer also 100% Office-kompatible Anwendungen schreiben will ist hier schon mal aufgeschmissen, wenn er das mit MFC 10.0 machen will.
Im Header finden wir diese Funktion noch mit einem #ifdef auskommentiert. Allerdings nützt es nichts diesen #define zu setzen, denn es gibt keine Implementierung und entsprechend keinen Code in der DLL/Library. Ja und in der MFC Doku finden wir die Funktion auch noch.

Und auch dieses Problem war noch in der Beta-Phase bekannt und wurde abgebügelt, wie man in den nachfolgenden Links lesen kann.
http://social.msdn.microsoft.com/Forums/en/vcmfcatl/thread/29ad2859-6341-4ffb-85c2-f5f056a6ca48
https://connect.microsoft.com/VisualStudioJapan/feedback/details/533876/cmfcribbonpanel-enablelaunchbutton?wa=wsignin1.0
Wem es möglich ist, sollte hier bitte Abstimmen und diesen Bug als wichtig kennzeichnen!

Langsam frage ich mich ob es nicht gescheiter gewesen wäre bei MFC-Next 9.0 zu bleiben und mit VS-2008 weiter zu arbeiten.
Tja und so hat die BCG-Library in Verbindung mit VS-2010 auch eine Daseinsberechtigung. Die kann diesen LaunchButton natürlich darstellen.

PS: Auf Nachfrage bei Microsoft bekam ich eine Antwort aber keinerlei Begründung. Jetzt habe ich eine Support-Anfrage dies bzgl. laufen, allerdings mit wenig Hoffnung. 🙁

PPS: (Nachtrag 01.09.2010) Auch der Microsoft Support kann mir dies bzgl. keine Antwort geben aufgrund eines offenen Rechtsstreits. Siehe auch Kommentar von Samsa.

Bug in der MFC von VC-2010 in CImageList::DrawIndirect

Die Funktion CImageList::DrawIndirect der MFC-10

BOOL CImageList::DrawIndirect(CDC* pDC, int nImage, POINT pt, SIZE sz,
    POINT ptOrigin, UINT fStyle = ILD_NORMAL, DWORD dwRop = SRCCOPY,
    COLORREF rgbBack = CLR_DEFAULT, COLORREF rgbFore = CLR_DEFAULT,
    DWORD fState = ILS_NORMAL, DWORD Frame = 0,
    COLORREF crEffect = CLR_DEFAULT);

hat einen massiven Bug: Sie funktioniert einfach nicht.

Der Unsinn, der sich eingeschlichen hat, liegt in der überschriebenen Funktion

BOOL CImageList::DrawIndirect(IMAGELISTDRAWPARAMS* pimldp);

die durch die oben genannte Variante aufgerufen wird. Denn hier cbSize von IMAGELISTDRAWPARAMS nicht mehr in allen Fällen auf einen korrekten Wert gesetzt. Die Folge cbSize enthält Garbage und der Aufruf von ImageList_DrawIndirect geht in die Hose!
Sowohl in VC-2005 als auch VC-2008 wurde in dieser Funktion explizit der cbSize Member überschrieben, je nach dem ob ComCtl 6.0 oder höher von der Anwendung benutzt wird.

Auch das ist ein Bug, denn hierdurch wird evtl. ein korrekt gesetzter cbSize Wert mit IMAGELISTDRAWPARAMS_V3_SIZE (pre IE 5.01 d.h. _WIN32_IE < 0x0501) überschrieben und damit vergrößert vergrößert. Dadurch kann es zu Zugriffsfehlern kommen oder zu unerwünschten Seiteneffekten.
(siehe https://connect.microsoft.com/VisualStudio/feedback/details/322713/bug-in-cimagelist-drawindirect)

Also haben die Entwickler scheinbar die Zuweisung von pimldp->cbSize = sizeof(IMAGELISTDRAWPARAMS) entfernt! Allerdings haben Sie dabei vergessen in der anderen Funktion nun cbSize korrekt zu initialisieren!

Wir haben also wieder mal einen Fall von: Let us fix one thing and break others…

Das Gemeine an der Sache ist, dass dieser Bug noch vor RTM bekannt war:
https://connect.microsoft.com/VisualStudio/feedback/details/543108/bug-in-cimagelist-drawindirect
Nur ist er nicht mehr gefixed worden!

PS: Natürlich fährt die eigene Software mit der MFC-10 auch gegen die Wand, wenn man die CImageList::DrawIndirect(IMAGELISTDRAWPARAMS* pimldp) Variante verwendet und selbst cbSize nicht initialisiert, was ein ordentlicher Entwickler aber sicherlich nicht vergisst! 😉

Wem es möglich ist, sollte bei den beiden Connect Einträgen Abstimmen und diesen Bug als wichtig kennzeichnen!

Wie man den Namen einer RegisterWindowMessage bekommt

Manchmal muss man Software verstehen. D.h. auch andere Software, die man selbst nicht geschrieben hat 😉

In meinem Fall war es hier ein Client, den ich geschrieben habe, der eine andere Software startet. Diese Software verwendete interne Nachrichten zur Kommunikation, die mit RegisterWindowMessage registriert wurden. Ich wollte nun hier einen Eingriff machen, der ein Fehlverhalten unter Windows 7 und Vista vermeiden soll.

Hilfreich wäre für mich nun gewesen an den Namen der registrierten Nachrichten zu kommen. Spy++ kann es auch und der importiert auch keine mystischen Funktionen. Also muss es einfach gehen.

Und ein wenig Recherche und ein Verweis eines Community Eintrags brachte mich auf diesen Thread:
http://groups.google.it/group/microsoft.public.vc.mfc/browse_thread/thread/f83f7c12c80e4ada/460bc4c43a844a37

Siehe da GetClipboardFormatName löst das Problem. Der nachfolgende Code lieferte mir nun im Detail, was das so hin und her läuft und der Name der Nachrichten war zum Glück sprechend. Ich konnte das Problem lösen.

if (uiMsg>=0xC000)
{
  TCHAR szName[MAX_PATH];
  ::GetClipboardFormatName(uiMsg,szName,MfxCountOf(szName));
  TCHAR szOut[MAX_PATH*2];
  _stprintf(szOut,_T(__FUNCTION__) _T(" %s, wp=0x%08x, lp=0x%08x\n"),
            szName, wParam, lParam);
  OutputDebugString(szOut);
}

ExitInstance gibt für dialogbasierende MFC Anwendungen Unfug zurück

Wer eine dialogbasierende Anwendung mal mit etwas mehr Aufmerksamkeit debuggt oder analysiert wird feststellen, dass der Returncode der Anwendung irgendwie ziemlich zufällig ist. Beobachtet man dies genauer dann stellt man folgendes fest:

  • Beendet man die Anwendung mit der Maus (Klick auf X) oder OK/Cancel so ist der Returncode 0
  • Hält man die Strg-Taste beim Klick fest ist der Returncode 8
  • Beendet man die Anwendung mit Alt+F4 bekommen wir 2.
  • Und jedermann kann jetzt schon mal raten was passiert, wenn wir die Umschalttaste festhalten. Genau dann bekommen wir 4 als Returncode.

Die Mystik hinter dem Ganzen ist die Behandlung von (Afx)PostQuitMessage. Eigentlich sollte mit dieser Nachricht auch der Exitcode gesetzt werden, der mit WM_QUIT versendet wird. Und wenn eben bei einer MDI/SDI Anwendung alles normal läuft, dann ist diese Nachricht die letzte, die aus der Messsagequeue gezogen wird. Und was passiert in CWinApp::ExitInstance? Genau… aus dem statischen Thread Puffer für die Windowsnachrichten wird mit  AfxGetCurrentMessage die letzte Windowsnachricht (normalerweise WM_QUIT) geholt und der wParam Wert bestimmt. Dieser wird dann zurückgegeben.

Leider ist aber WM_QUIT in manchen Fällen aber nicht die letzte Nachricht, die zum Beenden eines Programms führt. Ganz besonders eben nicht bei einer dialogbasierenden MFC-Anwendung. Da ist die letzte Nachricht ist dann eben ein WM_COMMAND oder ein WM_LBUTTONUP der das Schließen der Anwendung auslöst ❗ Und der wParam Wert ist eben entsprechend dieser Nachricht belegt!

Gleiches passiert natürlich, wenn man nach dem Beenden der Messageloop noch andere interne Fenster zerstört. Auch in diesem Fall kann noch mal die interne AfxWndProc durchlaufen werden und dann wird der Returncode auch wieder verändert.

Wer also wirklich Wert auf den Returncode legt (im wahrsten Sinne des Wortes), der sollte sich nie auf den Wert verlassen, der durch CWinApp::ExitInstance zurückgegeben wird oder den Wert, den man selbst mit AfxPostQuitMessage evtl. versucht zu setzen. Eine Variable in CWinApp tut hier einen besseren Dienst. Ebenfalls sollte man ExitInstance überschreiben und immer 0 zurückgeben, wenn man sowieso keine Verwendung für den Returncode des Prozesses hat oder haben möchte.

BTW:
Die Geschichte, wie ich darauf gekommen bin ist schon eigentümlich genug.
Ich habe komplexere Batch-Dateien, die die gesamte Erstellung einer produktiv-Version regelt. Darin kommen im Problemfall auch ein paar Userinteraktionen vor. Diese werden durch Windows Anwendungen ausgelöst, die evtl. einen Dialog anzeigen. Jedem ist klar, dass ohne Dialog und ohne Fenster keine Nachricht abgearbeitet wird. Der Returncode ist also 0! Der Batch verwendet 4NT Syntax und dort kann man ON ERROR definieren und somit sofort eine Fehlerbehandlung auslösen, wenn der Returncode eines Programms nicht 0 ist.
Nun kann sich jeder schon denken was passiert ist. Die Userinteraktion wurde ausgelöst. Der Benutzer machte eine Angabe und… der Batch terminierte erstaunlicherweise mit einem Fehler… (s.o.)

Tool: Screen-OCR Version 2.0, einfach mal Texte vom Monitor aus Bildschirmausschnitten und Grafiken in die Zwischenablage kopieren

Am 15. Mai hatte ich eine erste Version meines Freeware Screen-OCR Programmes veröffentlicht. Siehe Tool: Screen-OCR, einfach mal Texte vom Monitor aus Bildschirmausschnitten und Grafiken in die Zwischenablage kopieren

Nun habe ich etwas Zeit für Version 2.0 gefunden ❗
Folgende Verbesserungen wurden eingebaut:

  • Etwas schönere UI für das Auschneiden aus dem aktuellen Desktop.
  • Deutsches und englisches Benutzerinterface.
  • Das Programm kann nur noch einmal gestartet werden. Mehrfaches Starten macht hier keinen Sinn.
  • Das Tool kann nun auch das letzte aktive Fenster per OCR erfassen, oder auch eine Bitmap in der Zwischenablage. Es wurde ein entsprechendes Drop-Down Menü eingebaut.
  • Es gab bei mehrfachen Aufrufen ab und zu Crashs, was offensichtlich daran liegt, dass die MODI-DLLs es nicht mögen geladen, entladen und wieder geladen zu werden.

Download hier  MRi-Screen-OCR Version 2.0

Falls man MODI nicht hat, hier kann man es kostenlos bekommen:
http://support.microsoft.com/kb/982760

Tool: Screen-OCR, einfach mal Texte vom Monitor aus Bildschirmausschnitten und Grafiken in die Zwischenablage kopieren

Im Second-Level Support habe ich es oft mit Fehlermeldungen zu tun, die mir von Kunden als Screenshots gesendet werden. Um das ganze in unserem Support-System zu dokumentieren, müssen die oft genug abgeschrieben werden. Oder ich möchte diese Texte haben um sie einfach in Google suchen zu können. Viele Leute wissen nicht, dass man ganz einfach Texte aus Messageboxen in die Zwischenablage kopieren kann. Also bekommt man Megabyte große Screenshots.
Lästig…

Es gibt einige kleine Tools  für Geld (z.B. von Abbyy) und auch einige kostenlose habe ich mal ausprobiert, mit denen man solch einen Screen-OCR durchführen kann. Aber die waren alle nicht das wahre oder unverschämt groß.

Da ich wusste, dass es

  1. im MODI (Microsoft Office Document Imaging) ein einfaches COM Interface gibt,
  2. ein Screenshot einfach zu machen ist und
  3. man mit GDI+ alle möglichen Grafikumwandlungen machen kann benötigt man
  4. nur etwas C++ als Kleber um alles zusammen zu bringen.

Herausgekommen ist Version 1.0 von MRiScreenOCR.exe. Eine simple Freeware EXE, mit der man einen beliebigen Bildschirmausschnitt per OCR in Text umwandeln kann und wahlweise in einem Dialog anzeigen kann oder direkt in die Zwischenablage kopieren kann.
Optional kann man das ganze über ein paar Optionen im Systemmenü steuern.
Eigentlich komplett selbsterklärend.
Wer weiß, vielleicht mache ich mich noch an Version 2.0 und ergänze noch eine Trayicon-Funktion optional.

❗ Einzige Voraussetzung MODI (Microsoft Office Document Imaging) muss installiert sein, damit das kleine Tool arbeiten kann (siehe auch Anmerkung unten). Sonst benötigt man nichts. Die EXE funktioniert stand alone mit XCOPY Installation. Das Tool wurde mit VC-2010 erzeugt, man benötigt also mindestens Windows XP SP2.

Hier kann man MRiScreenOCR.exe kostenlos herunter laden und es steht jedem als Freeware zur freien Nutzung.

PS:
MODI ist übrigens teil von Microsoft Office 2003 und Office 2007. Leider ist es im Office 2010 nicht mehr enthalten. Schade, denn es war für mich das primäre Programm Dokumente zu scannen zu archivieren und auch zu indizieren.

Nachtrag 18.05.2010:
Es ist ohne weiteres möglich nur MODI aus Office 2007 alleine ohne weitere Komponenten zu installieren. Das funktioniert sowohl auf 32bit Systemen wie auch auf 64bit Systemen.

Nachtrag 01.06.2010:
Die Version 2.0 von MRiScreenOCR.exe ist nun verfügbar.

Nachtrag 03.10.2011:
Ich zitiere den Kommentar von Robin hier:

falls man MODI nicht hat, hier kann man es kostenlos bekommen:
http://support.microsoft.com/kb/982760

Achtung: Die festen Mapping Modes des GDI basieren nicht auf LOGPIXELSX und LOGPIXELSY!

Jeder der mit Fontgrößen und Darstellungsgrößen herumspielt, oder wer selber in Fenstern zeichnet kennt LOGPIXELSX und LOGPIXELSY, die durch GetDevCaps geliefert werden. Diese Werte dienen auch CFont::CreatePointFont und anderen Funktionen bei der Umrechnung von „realen“ Maßen auf die Devicepoints, die man dann benötigt. Alles kein Hexenwerk und überall im Netz beschrieben.
Auf diesem Weg kann man mit etwas MulDiv Arithmetik schnell umrechnen wie viele Punkte man benötigt um etwas von 10mm Größe auf einem Device darzustellen.

Der nachfolgende Code wandelt Einheiten von 1mm entsprechend der Auflösung eines Devices in Pixel um.

pDC->SetMapMode(MM_TEXT);
// Convert mm to with LOGPIXELSX
CSize sizeLogPixel(pDC->GetDeviceCaps(LOGPIXELSX),
            pDC->GetDeviceCaps(LOGPIXELSY));
rect.top = ::MulDiv(rect.top,sizeLogPixel.cy*10,254);
rect.bottom = ::MulDiv(rect.bottom,sizeLogPixel.cy*10,254);
rect.left = ::MulDiv(rect.left,sizeLogPixel.cx*10,254);
rect.right = ::MulDiv(rect.right,sizeLogPixel.cx*10,254);

Die Auflösung von 0,1mm je Einheit ist die Metrik des Mappingmodes MM_LOMETRIC. Man sollte also meinen, dass die Verwendung von MM_LOMETRIC mit einem Faktor 10, der obigen Umrechnung gleich kommt.

pDC->SetMapMode(MM_LOMETRIC);
// Convert mm to 0.1mm
rect.top *= -10;
rect.bottom *= -10;
rect.left *= 10;
rect.right *= 10;

Probiert man dies aus, so stellt man überrascht fest, dass die Größen nicht übereinstimmen.
Der Dokumentation nach müsste man es aber denken.

Mit einem bisschen experimentieren bin ich letztlich auf den Grund gekommen.
Keiner der Mappingmodes MM_LOENGLISH, MM_HIENGLICH, MM_LOMETRIC oder MM_HIMETRIC verwendet LOGPIXELSX oder LOGPIXELSY. Diese Mappingmodes verwenden die Werte HORZRES und VERTRES in dem Viewport-Extent und die Werte HORZSIZE und VERTSIZE im Window-Extent.

D.h. der Viewport-Extent bekommt die Größe des Bildschirmes in Pixeln zugewiesen und das Window-Extent bekommt die Größe des Devices in mm zugewiesen. Nun ist diese Größe (HORZSIZE/VERTSIZE) bei Bildschirmen nicht die reale Größe sondern eine Größe, die der Hersteller festlegt. (Anmerkung: Bei Druckern stimmt dieser Wert)

Nun wäre noch alles OK, wenn sich aus den Werten von VERT/HORZSIZE und VERT/HORZRES nun der Quotient LOGPIXELSX/SY ermitteln ließe. Das ist aber nicht der Fall! LOGPIXELSX/SY sind Skalierungswerte die bei Bildschirmen unabhängig von der realen Auflösung angegeben werden und die z.B. dazu Dienen Schriftgrößen grundsätzlich größer oder kleiner anzeigen zu lassen (siehe auch High DPI Mode).

Die Konsequenz daraus ist, dass die Mappingmodes ein relativ exotisches Einzelleben führen, weil die meisten Entwickler eben korrekterweise auf LOGPIXELSX/SY zurückgreifen. Noch mal sei hier bemerkt, dass für Drucker DCs hier in mir bekannten Fällen kein Unterschied existiert und auch das ist gut so.

Die Lösung die sich anbietet, ist nicht weiter schwierig und sie auch der Grund warum ich erst jetzt auf diesen gesamten Umstand gestoßen bin. Ich habe niemals die MM_LO…/MM_HI… Mappingmodes verwendet. Entweder pur MM_TEXT und wenn ich was anderes benötigt habe einfach MM_ANISOTROPIC, und in der entsprechenden Skalierung habe ich dann meistens die Werte aus LOGPIXELSX/SY verwendet. Also musste es passen.

MM_ANISOTROPIC ist sowieso der Mappingmode der Wahl, wenn es um skalierbare Darstellungen und Zoomfaktoren geht, aber dazu vielleicht mehr in einem Artikel demnächst.

Ich habe ein kleines MFC-Programm gebaut (MappingModeTest), dass diese Konflikte aufzeigt. Ich zeichne dort ein Rechteck auf den Koordinaten 20mm,10mm mit der Größe 60mm,40mm. Damit die verschiedenen Rechtecke alle sichtbar werden verwende ich immer einen Versatz von 1mm und zeichne die Rechtecke in unterschiedlichen Farben.
In der Debugausgabe kann man wunderschön sehen wie Extents mit den Werten aus GetDeviceCaps zusammenhängen.

Dieser Artikel basiert auf zwei Anfragen in microsoft.public.de.vc die dieses unterschiedliche Verhalten aufzeigten und diskutieren:
http://groups.google.de/group/microsoft.public.de.vc/browse_thread/thread/23467a5e95051291/7c66c01b8295eaab
http://groups.google.de/group/microsoft.public.de.vc/browse_thread/thread/201719d23a411256/17b41c09844bf105

Mal einen ganz anderen Blick auf seinen Code werfen mit CppDepend

Vor einiger Zeit habe ich versucht mit einem anderen Werkzeug mal den eigenen Code zu analysieren.
Ich habe CppDepend entdeckt.  http://www.cppdepend.com/

Gerade bei großen Projekten kann man schnell den Überblick verlieren und es ist schwierig die abhängigen Klassen und Objekte in Ihren Verbindungen zu sehen oder mögliche Designprobleme nachträglich festzustellen. Oder den richtigen Ansatzpunkt für Reviews zu finden. Man hat manchmal das Gefühl, dass etwas nicht stimmt, aber man weiß oft nicht genau was.

CppDepend kann helfen schlecht konstruierte Klassen zu finden, Fehler in den Namenskonfentionen oder der Dokumentation und gezielter auf notwendige Reviews hinzuweisen.
Durch eine eigene Abfragesprache ist es extrem einfach große unübersichtliche Funktionen zu finden. Klassen mit zyklischen Abhängigkeiten und extreme Vererbungstiefen aufzuspüren. Besonders einfach wird es zum Beispiel auch Namenskonventionen zu überprüfen. Die eigene Codebase wird durch die Abfragesprache analysierbar.

Ich empfand die graphischen Darstellungen der eigenen Codebasis und die Ergebnisse der Abfragen in diesen Grafiken als extrem anschaulich und nützlich. Weitaus mehr als manche tabellarische Analyse meines Codes.

Einen guten Einblick was hier möglich ist liefern die Case-Studies. Wie zum Beispiel die Analyse der MFC 8.0 (VC-2005) http://www.cppdepend.com/MFC.aspx. Man kann die MFC sicherlich nicht als Glanzstück des OOP bezeichnen, umso mehr ist es mal interessant mit diesem Tool einen Blick auf die MFC zu werfen. Wem das nicht anschaulich genug ist kann sollte sich auch die anderen Case-Studies mal ansehen. Oder noch besser die Software 2 Wochen testen.

Ein gutes Tool, aber leider nicht ganz billig, aber in jedem Fall mal einen Blick wert.