Seit langer Zeit einmal wieder eine reine C++ Konferenz am 5.+6. Mai am Chiemsee

Das C++ eine ganze Konferenz bestimmt hat ist auch in der Vergangenheit selten gewesen. Aber es gab zumindest Konferenzen wo es für die vorgestellten Techniken die primäre Sprache war. Lang ist her.
Aber das Nischendasein zu dem Microsoft C++,  in den letzten Jahren die Sprache C++ verdammt hat, wird dieser Technologie auch nicht gerecht.

ppedv als Veranstalter lädt nun zu eine Advanced Developer Conferenz speziell zu C++ ein.
Die Konferenz findet am 5.+6. Mai in Prien am Chiemsee im Yachthotel statt statt.

Eingeladen sind Boris Jabes von Microsoft, den ich zur Veröffentlichung des Feature Packs und TR1 von VS-2008 in Deutschland kennenlernen durfte. Weitere Sprecher sind die allseits bekannte Bernd Marquardt. Christian Binder als TFS-Guru von Microsoft, Michael S. Wong vom C++ Compiler Kernel Development bei IBM, Aaron Coday, der European Visual Computing Manager bei Intel EMEA, sowie Hans Pabst, Matthias Wedemeyer und Michael Klemm.

Was es aktuell zu wissen gibt über die Konferenz findet sich hier: http://cpp.ADC11.de
Bis zum 08. April kann man sich noch zu einem günstigeren Teilnehmerbeitrag anmelden.

Es lohnt auch ein Blick auf C++ Foren wie http://www.c-plusplus.de/, auf denen auch Promotions angeboten werden… 😉

PS:
Ich werde auch bereits ab Mittwoch Abend dort sein. Wer also mit mir auch mal im richtigen Leben ein paar Worte wechseln will, der hat dazu in Prien die Möglichkeit. Ich freue mich darauf andere Entwickler zu treffen und mal zu hören wie die C/C++ Szene eigentlich aktuell wirklich tickt.

Ich würde mich freuen einige meiner Leser dort zu treffen.

Aufstellung aller Änderungen an der MFC durch VS-2010 SP1

Ich habe mir mal die Mühe gemacht alle Änderungenan der MFC, die im VS-2010 SP1 enthalten sind, hier im Detail aufzuführen.

Viele Änderungen sind es nicht, wie man schnell sieht. Ich empfehle als weitere Quelle für Infos über den SP1 die bekannten Blogs des MS-C++ Teams und die KB.
http://blogs.msdn.com/b/vcblog/archive/2011/03/10/10139062.aspx
http://support.microsoft.com/kb/983509

Neue Samples finden sich nach dem SP1 Setup auf der Festplatte im folgenden Ordner:
C:\Program Files\Microsoft Visual Studio 10.0\Samples\1033\VC2010SP1Samples.zip

Für entsprechende bekannte Fixes habe den Text aus den Blogs übernommen. Alle anderen Änderungen habe ich durch einen Vergleich des Sourcecode mit WinMerge ermittelt. Codeänderungendie ich nicht direkt einem Fehler zuordnen konnte habe ich mit dem Prefix Change, markiert und natürlich die neuen Features entsprechend.

In einem späteren Artikel werde ich mich noch die Änderungenan CRT und STL genauer unter die Lupe nehmen.

Neues Feature: Direct2D Unterstützung (dokumentiert)

Direct2D, a hardware-accelerated, immediate-mode, 2-D graphics API that provides high performance and high-quality rendering for 2-D geometry, bitmaps, and text. For more information, visit the following Microsoft website: Direct2D.
http://msdn.microsoft.com/en-us/library/dd370990.aspx
http://msdn.microsoft.com/en-us/library/gg482719.aspx

Geänderte Dateien:

  • afx.h, afxglobals.h, afxrendertarget.h, afxwin.h
  • afxglobals.cpp, afxrendertarget.cpp, appui3.cpp, wincore.cpp

Anmerkung: Die Verwendung von Direct2D führt dazu, dass CoInitialize ausgeführt wird.

Neues Feature: Windows Animation Manager Unterstützung (dokumentiert)

Windows Animation Manager, which enables rich animation of user interface elements. For more information, visit the following Microsoft website: Windows Animation Manager.
http://msdn.microsoft.com/en-us/library/gg482719.aspx

Geänderte Dateien:

  • afxanimationcontroller.h, afxanimationhelper.h, afxwin.h
  • afxanimationcontroller.cpp

Bugfix: Korrektur eines Fehlers in den RDX Kompontenten (dokumentiert)

In the CDatabase/Crecordset MFC, the „DoFieldExchange“ variable does not work correctly in Visual Studio 2010.
http://connect.microsoft.com/VisualStudio/feedback/details/574974

Geänderte Dateien:

  • dbrfx.cpp

Bugfix:  Umgang mit SPI_GETNONCLIENTMETRICS in unterschiedlichen Windows Versionen (nicht dokumentiert)

Der interne Umgang mit unterschiedlichen Windows Versionen und SPI_GETNONCLIENTMETRICS wurde gefixed.

Geänderte Dateien:

  • afxglobals.cpp, afxribbonbar.cpp, afxvisualmanageroffice2007.cpp, afxvisualmanagerwindows7.cpp

Change: Cleanup der MFCNext Klassen (nicht dokumentiert)

Das Cleanup für die neuen MFC-Next Klassen wurde geändert.

Geänderte Dateien:

  • afxcontrolbarutil.h
  • afxglobals.cpp, afxwinappex.cpp, ctlmodul.cpp

Bugfix: Fehler bei Anzeige in CFormView Klassen (nicht dokumentiert)

VC-2010 MFC CFormViewzeichnet Buttons beim Rollenfalsch, es erscheinen schwarze Blöcke
http://blog.m-ri.de/index.php/2010/08/28/bug-vc-2010-cformview-zeichnet-buttons-beim-rollen-falsch-es-erscheinen-schwarze-bloecke/

Geänderte Dateien:

  • afxext.h
  • viewform.cpp

Bugfix: CImageList::DrawIndirect wurde korrigiert (nicht dokumentiert)

CImageList::DrawIndirect funktioniert nicht korrekt weil cbSize nicht initialisiert wurde
http://blog.m-ri.de/index.php/2010/07/21/bug-in-der-mfc-von-vc-2010-in-cimagelistdrawindirect/

Geänderte Dateien:

  • winctrl7.cpp

Change: Änderung des Suchalgorithmus für MFC Satellite DLLs (nicht dokumentiert)

Das Handling des Suchalgorithmus für die MFC Resource DLLs wurde geändert

Geänderte Dateien:

  • appcore.cpp, dllinit.cpp

 

PS:
Erstaunlich, dass zwei der Bugs, die ich zur MFC gemeldet habe auch direkt in diesem SP1 gefixed wurden. Das ist eine Quote, die ich in den letzten 12 Jahren bei einem SP noch nie hatte 🙂

Nachtrag und Ergänzungen am 18.03.2011
durch Sven von http://www.speedproject.de

Infos zum Laden der dwmapi.dll

Die Datei dwmapi.dll wird nun explizit aus dem Systemverzeichnis geladen.

Geänderte Dateien:

  • afxglobals.cpp

Infos zum Suchalgorithmus der MFC DLLs

Die Änderung des Suchalgorithmus für die zusätzlichen Sprachressourcen ist ebenfalls eine Schutzmaßname gegen das ‘Binary Planting’. Die Dlls werden jetzt nur noch aus dem Verzeichnis geladen, in dem sich die MFC-Dll befindet.

Infos zu dem geänderten Clennup der MFCNext Klassen

Der Grund für die Änderung beim Aufräumen ist wohl ein mögliches Speicherleck beim Beenden:
http://connect.microsoft.com/VisualStudio/feedback/details/577870/cmfcbutton-causes-memory-leak

Danke Sven!

BUG: Breaking Change durch VS-2010 SP1 für manche C++/CLI Projekte

Am 09.03. wurde im US-VCGeneral Forum ein Bug öffentlich, der durch SP1 verursacht wurde.
http://social.msdn.microsoft.com/Forums/en-US/vcgeneral/thread/4b8f353d-8153-45d6-b286-10403cdf159a

Nachdem die Produktgruppe auf diesen Fehler aufmerksam gemacht wurde, hat sie einen entsprechenden Workarround veröffentlicht:
http://blogs.msdn.com/b/vcblog/archive/2011/03/11/10140139.aspx

Wichtig ❗
Betroffen sind nur Projekte bei denen C++/CLI Assemblies im Linker Prozess signiert werden.
Normale native C++ Projekte sind von diesem Fehler nicht betroffen.

BUG: VC-2010 regex liefert falsche Ergebnisse bei Verwendung von Repetitions/Wiederholungen

In der regex Implementierung von VS-2010 ist ein relativ fataler Bug drin, der auftritt, wenn man Repetitions (Wiederholungen, {n}) verwendet.
Wie zum Beispiel hier in diesem Beispiel.

#include <stdio.h>
#include <ios>
#include <iostream>
#include <ostream>
#include <regex>
#include <string>
using namespace std;

void test(const string& s, const string& reg)
{
  cout << "---------------" << endl;
  cout << "s: " << s << endl;
  cout << "r: " << reg << endl;

  const regex r(reg);
  cout << boolalpha << regex_match(s, r) << endl;
}

int main()
{
 printf("%02d.%02d.%05d.%02d\n",
          _MSC_VER / 100,
          _MSC_VER % 100,
          _MSC_FULL_VER % 100000,
          _MSC_BUILD);

  test("56." , "(([0-9]{1,2})\\.){1}");
  test("1." ,  "(([0-9]{1,2})\\.){1}");
  test("56.1.", "(([0-9]{1,2})\\.){2}");

}

Der erste und zweite Ausdruck führt zu einem Match. Der dritte Ausdruck ist eigentlich nur der kombinierte Test, der beide Ausdrücke in einem testet.
Der Fehler wird auch in SP1 nicht gefixed sein.

Meine Tests ergaben, dass in VS-2008 SP1 bei der das ganze tr1-Zeugs in VisualStudio Einzug genommen hat, noch alles korrekt funktioniert hat.

Nachtrag (07.03.2010): Es gibt auch einen entsprechenden Bug auf Connect:
https://connect.microsoft.com/VisualStudio/feedback/details/648543/tr1-regex-doesnt-match-a-valid-pattern-with-repetition#tabs

virtuelle Funktionen und const sind immer wieder eine Freude… oder wie C++0x einen Fehler verhindert hätte…

Wieder mal hat sich in unserer Software ein kleiner und ganz mieser Fehler eingeschlichen, obwohl der Entwickler „eigentlich“ an alles gedacht hatte.

class A
{
...
    virtual void Doit() const;
...
};

class DerivedA : public A
{
...
    virtual void Doit(); 
...
};

void Foo()
{
...
    A *pA = Something();
...
    pA->Doit();
...
}

Sieht alles gut aus. Leider fehlt das kleine nette Wort const beim Überscheiben der Funktion Doit und daraus folgt, dass DerivedA::Doit niemals aufgerufen wird.

Obwohl wir VC-2010 verwenden, hat der neue C++0x Standard noch keinen Einzug in unseren Köpfen gefunden.
Das kleine Wort override in DerivedA hätte diesen Fehler verhindert.

class DerivedA : public A
{
...
    virtual void Doit() override;
// This line results in:

// error C3668: 'DerivedA::Doit' :
// method with override specifier 'override' did
// not override any base class methods
...
};

Es wird wirklich Zeit, dass C++0x auch wirklich genutzt wird, aber wie alles Neue muss man es sich besonders am Anfang immer wieder bewusst machen, damit es einem direkt zur Angewohnheit wird.
override ist sogar schon in VC-2008 und dem nativen Compiler implementiert. Allerdings wundert es mich, dass hier nicht dann auch gleich das Schlüsselwort new eingeführt wurde.
Aber das man unter dem gleichen Namen wirklich einen neuen Slot in der vtable aufmacht ist wirklich eher selten. Ich persönlich hatte dafür bisher noch keine Verwendung. 

Leider ist C++0x  nicht komplett in der C++ Doku in der MSDN hervorgehoben. Man kann nicht mal erkennen, dass sealed und abstract MS-Extensions sind, und override im Standard verankert ist. Schade…

Damit man sich etwas besser einen halbwegs kompletten Überblick verschaffen kann habe ich hier ein paar Links zusammengestellt.

Siehe auch:

BUG: VC-2010 ftell liefert negative Werte wenn eine UTF-8 Datei mit ccs=UNICODE geöffnet wird, die nicht mit fseek funktionieren

In VS-2005 hielt die Unicode und UTF-8 Unterstützung Einzug in die CRT und damit auch in die MFC. Jochen und ich haben dazu gebloggt.

Leider ist die Implementierung nicht fehlerfrei. Wenn man eine UTF-8 Datei mit ccs=UNICODE öffnet dann liefert ftell zum Teil auch negative Werte. Das ftell nicht die exakte Position in der Datei liefert ist dokumentiert, nur sollte es mit dem Wert zumindest möglich sein wieder fseek aufzurufen um an eine alte Dateiposition zurück zu gelangen.
Das ist mit der jetzigen Implementierung nicht möglich.

Ein Sample dazu ist schnell gebaut:

int _tmain()
{
  FILE *file = NULL;
  if (_tfopen_s(&file,_T("Test.txt"),_T("rt") _T(", ccs=UNICODE")))
    return -1;

  TCHAR szBuffer[_MAX_PATH];
  while (_fgetts(szBuffer,_countof(szBuffer),file))
  {
    int iPos = static_cast(ftell(file));
    _tprintf(_T("%d\n"),iPos);
    _ASSERTE(fseek(file,iPos,SEEK_SET)==0);
  }

  fclose(file);
  return 0;
}

Ein entsprechendes Sample kann man hier herunterladen.

Der Fehler betrifft natürlich auch die MFC mit CStdioFile und GetPosition!

Hintergrund:
Ich kam auf den Fehler, weil wir ein Programm benutzen, dass sich bestimmte Dateipositionen merkte um einen Datenimport bei einer bestimmten Bedingung, ab einer definierten Stelle, neu aufnehmen zu können. Bisher hatten wir hier nur pure ASCII Dateien erlaubt, jetzt wollten wir auch UTF-8 Dateien unterstützen.
Sicher man kann auch alles im Speicher zwischenhalten, aber wenn es eine simple Dateiposition ist das Ganze so weitaus Ressourcen schonender.

Soweit ich das übersehen kann, betrifft der Fehler alle VS-Versionen ab VS-2005. Ein entsprechende Bug wurde von mir schon vor längerer Zeit auf Connect geöffnet. Getan hat sich bisher noch nichts:
https://connect.microsoft.com/VisualStudio/feedback/details/591030/ftell-returns-negative-value-for-utf-8-files-opened-with-textmode-and-ccs

Warum es manchmal nicht genügt die Basisklasse aufzurufen und die miesen Konsequenzen…

Wenn man eine Windowsnachricht bearbeitet dann ruft man in den meisten Fällen die Funktion der Elternklasse auf. Was aber, wenn man die Nachricht nicht nur entgegennehmen will, sondern sie „verändert“ an die Basisfunktion weitergeben will. Was dann?
Kein Problem denkt man. Man ändert die Parameter eben und gibt diese neuen Werte an die Basisklasse weiter.

Nehmen wir mal als Beispiel ein Eingabe Control, das sich möglichst intelligent verhalten soll. D.h. in diesem Fall, wenn ein Datum eingegeben wird, dann sollte auch bei der Eingabe auf numerischen Ziffernbock, das Komma in einen Punkt gewandelt werden, oder bei englischem Datumsformat in einen Slash…

Na OK. Man überschreibt als CMyWnd::OnChar. Man prüft ob ein bestimmtes Zeichen ankommt und wenn es mir passt, dann ändere ich den Parameter und gebe diesen dann an die Basis Funktion weiter.

:Eeek: aber was ist das? Der Code hat keine Wirkung? Egal was wir an die Basisfunktion übergeben, es ändert sich nichts. Warum?

Die Antwort liegt in dem für mich etwas eigentümlichen Design der MFC. Alle CWnd Nachrichten Routinen rufen letzten Endes immer genau ein und die selbe Funktion auf: CWnd::Default(); Aber was macht CWnd::Default? Es nimmt die ursprünglichen Parameter, die Windows mal gesendet hat und übergibt die an die Window-Proc des Fensters. D.h. alle tollen Manipulationen an der WM_CHAR Nachricht sind weg in dem Moment in dem CWnd::OnChar aufgerufen wird.

Was also tun, wenn man nun aber wirklich die WM_CHAR Nachricht manipulieren will?
Eigentlich nicht schwer. Man macht das Gleiche, dass eben auch CWnd::Default macht. Man ruft DefWindowProc mit den passenden wParam und lParam Werten auf.

Aber jetzt wird es dumm ❗ Damit umgehen wir alle anderen geerbten Funktionalitäten des Controls. Ich habe keine Ahnung was die Entwickler der MFC in der Anfangszeit dazu getrieben hat immer CWnd::Default aufzurufen? War es Ihnen zu kompliziert wieder aus den Parametern wParam und lParam zusammen zu bauen?

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.

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!

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