VS-Tipps & Tricks: Gruppieren von Tastaturbefehlen

Als Entwickler hat man schon viele Tastaturkürzel im Kopf. Viele sind jedoch nicht vordefiniert, also denkt man sich was eigenes aus. Dennoch gibt es Befehle, die man nicht so häufig benutzt und gerne auf der Tastatur ausführen möchte. Man vergisst dennoch, das Kürzel oder sogar wo man einfach den Menübefehl findet.

Oft ging es mir so, mit den Befehlen aus Visual Source Safe. Irgendwann habe ich für alle VSS-Befehle dann mal Kürzel angelegt. Aber keine 1 Tastenbefehle, sondern eine Sequenz.
Alle VSS-Befehle fangen bei mir mit Alt+V an. Dann folgt simpel und einfach der Befehl den ich VSS geben möchte:

  • Alt+V, O – Check out
  • Alt+V, I – Check in
  • Alt+V, H – Show history
  • Alt+V, E – Start VSS Explorer
  • Alt+V, U – Undo Checkout
  • Alt+V, G – Get lastest version
  • Alt+V, P – Show properties

So habe ich mit bestimmten Tastatursequenzen mir bestimmte Aufgabengruppen geschaffen, die einfach mit der ersten Sequenz die Gruppe definiert und mit der zweiten Taste, sinnvoll und einfach den Befehl auslöst. Die Lernphase ist extrem niedrig und man behält hunderte von Sequenzen im Kopf, weil man einfach weiß was man machen will.

Gleiches lohnt sich mit vielen netten Features aus Visual Assist (bei mir Alt+A) Gruppe. Oder auch für den Dialogeditor, dem man einfach bestehende Befehle einfachere und zusätzliche Tastaturkürzel gibt. Oder man erzeugt sich eine Gruppe von erweiterten Navigationsbefehlen (nächste Block, nächste Funktion etc.). Die Outlining Befehle sind ja schon unter Strg+M zusammengefasst, allerdings finde ich hier die Assoziationen für den zweiten Buchstaben nicht ganz so gut.
Es gibt noch viele wirklich gute Funktionen im Editor des Visual Studios, leider sind viele unerreichbar, weil die Tastaturbefehle abstrus sind oder gar nicht definiert sind. Es lohnt sich hier selbst auf Erkundungstour zu gehen.

SetFocus versus WM_NEXTDLGCTL

Die meisten Entwickler verwenden SetFocus um in einem Dialog gezielt den Eingabefokus zu versetzen. Aber es gibt ein Problem, dem SetFocus nicht gerecht wird: der Default Button.
Der Default Button wird durch WM_SETDEFID bzw. CDialog::SetDefID gesetzt. SetFocus berücksicht das interne Konzept des Default Buttons nicht.

Wenn man mit der Tab-Taste durch einen Dialog springt und einen Button erwischt, dann wird dieser automatisch zum Default Button. Normalerweise ist das der OK-Schalter, er verliert dann den dicken Rahmen. Drückt man die Eingabe-Taste, dann wird nun der neue Schalter ausgelöst und nicht der OK-Schalter.
Landet der Fokus von einem Button dann bei einem Edit Control, dann wird der OK-Schalter wieder der Default Button und man kann mit der Eingabe-Taste den Dialog beenden.

Wenn nun SetFocus verwendet wird durch eine interne Funktion, dann wird dieser Mechanismus des Dialoges umgangen. Der Default-Button wird evtl. nicht korrekt gesetzt. Es kann sogar soweit kommen, dass es zwei Default-Schalter oder gar keinen mehr gibt. SetFocus führt immer zu Problemen wenn das neue Control oder das bisherige Control, welches den Fokus hatte, ein Button ist. Nur wenn beide Controls keine Button sind kann SetFocus gefahrlos verwendet werden.

Korrekt funktioniert das Ganze nur, wenn statt SetFocus, WM_NEXTDLGCTL verwendet wird, oder die entsprechenden MFC Funktionen, CDialog::NextDlgCtrl bzw. CDialog::GotoDlgCtrl verwendet werden.
Die Nachricht WM_NEXTDLGCTL wird auch intern durch die DefDialogProc behandelt und normalerweise durch IsDialogMessage erzeugt.
Gefahrlos ist auch die Verwendung von SetFocus in WM_INITDIALOG bzw. CDialog::OnInitDialog Handlern, die dann normalerweise mit FALSE, verlassen werden. Nach dieser Funktion sorgt der Dialog Handler, für die korrekte Behandlung der Default Buttons.

Fazit: Man sollte also innerhalb von Dialogen ganz auf SetFocus verzichten sondern nur WM_NEXTDLGCTL  bzw.  CDialog::NextDlgCtrl und CDialog::GotoDlgCtrl verwenden. Konsequenterweise sollte man dann auch in OnInitDialog Handlern auf SetFocus verzichten. ❗

Besonderheiten bei der Ausgabe über Excel via ODBC

Man sollte tunlichst darauf achten, dass bei Excel Export über ODBC alle Spalten mit einem möglichst exakten Datentyp erzeugt werden. D.h. der Faulheit halber sollte man nicht jede Spalte mit dem Typ TEXT erzeugen, sondern eben DOUBLE, NUMERIC, BIT, DATETIME etc. verwenden, die Excel auch unterstützt. In diesem Fall werden nur die TEXT-Daten mit einem Apostroph versehen. (siehe dieser Blogbeitrag)

Lästig ist, dass Excel es nicht schafft DATETIME, DATE und TIME Spalten standardmäßig auch korrekt anzuzeigen. DATETIME-Spalten werden zwar korrekt mit Datum und Uhrzeit befüllt. Das Anzeigeformat wird aber so dämlich gewählt, dass nur das Datum sichtbar ist. Für DATE-Spalten geht das in Ordnung. Bei TIME-Spalten wird sogar noch einfach das Tagesdatum „hinzugedacht“, obwohl nur der Zeitwert übertragen wurde. D.h. man sieht ein Tagesdatum aber nicht die Zeit. Die Zeit wird nur sichtbar beim Ändern des Formtes der Zellen, oder wenn man die Daten einzeln anklickt und in der Bearbeitungsleiste betrachtet.

Trickreich ist auch die Ausgabe in ein DATETIME Feld, wenn man ein Textfeld bindet. In diesem Fall muss zwingend das Format JJJJ-MM-TT für die Ausgabe verwendet werden.

Ein weitere Trick besteht darin, die Spalten zusätzlich mit der Option NULL anzulegen:
CREATE TABLE [Data] ([Field1] TEXT NULL, [Field2] DOUBLE NULL)
andernfalls braucht man sich nicht wundern, wenn es eine Exception gibt beim Speichern eines leeren Strings.

Wann Message Reflection nicht funktioniert!

TN062: Message Reflection for Windows Controls beschreibt die vielen schönen Möglichkeiten der Message Reflection.

Aber es gibt eine wichtige Voraussetzung, dass da ganze funktioniert:
Das Parent Window muss auch ein Fenster sein, das mit der MFC erzeugt wurde, oder durch die MFC gesubclassed sein.

Die Reflektion geschieht immer nur durch das Parent Fenster. Wenn dort also eine WM_CTLCOLOR Nachricht das Parent erreicht, dann wird die Nachricht an das Fenster, dass es gesendet weitergeleitet, wenn es eben über einen entsprechenden Reflektion Eintrag für WM_CTLCOLOR verfügt. Das ganze wird erledigt durch die Funktion CWnd::ReflectLastMessage, die die entsprechenden Funktion  CWnd::SendChildNotifyLastMsg im eigentlichen Control wieder aufruft. Diese Funktion ruft wiederum CWnd::OnChildNotify auf, die dann die Reflection Einträge in der Message Map sucht. Ist das Parent nun kein MFC Fenster kann auch niemand die Nachrichten an das sende Fenster zurückleiten.

Hat man also ein Fenster hat, dass durch pure Win32 API Funktionen erzeugt wurde und auch nicht durch die MFC gesubclassed wurde und in diesem Fenster wird ein MFC Fenster als Child erzeugt, dann erreichen dieses Child keine Nachrichten durch die Reflektion.

Eigentümliche Quotes beim Erzeugen einer Excel Datei mit ODBC

Eigentümlicher Effekt:
Ich erzeuge eine Excel Tabelle mit ODBC. Dann füge ich einige Zeilen in die Tabelle ein.

Wenn ich diese Tabelle mit Excel öffne sieht alles gut aus.
Betrachte ich die einzelnen Zellen jedoch näher, dann erscheint in der Bearbeitungsleiste für den Wert der Zelle immer ein zusätzliches einzelnes Anführungszeichen ‚ vor jeder Zelle. Die Zellen werden jedoch in der Ansicht korrekt angezeigt und auch in Formeln korrekt verwendet.

Ich binde die Daten ganz normal mit RFX_Text. Und der nColumnType wurde als Default-Wert mit SQL_VARCHAR angegeben.

Nach dem Lesen von einigen Artikeln bin ich letzten Endes darauf gekommen, dass dieses führende Quote ein internes Zeichen für Excel ist, dass es sich um eine Textzelle handelt.
Die Spaltenwerte werden ganz normal und korrekt weiterhin angezeigt.
Es scheint so, dass man das Ganze ignorieren kann. 😕

Siehe auch diesen guten Beitrag, der viele nützliche Excel Links bzgl. Automation und ADO enthält: http://groups.google.de/group/microsoft.public.vb.database.ado/browse_frm/thread/c3504ad88cc713ce

VS-Tipps & Tricks: Schnelles Navigieren im Class View

Wenn man in Dialogen und Klassen über den Class View Variablen oder Funktionen hinzufügen will, dann ist dies oft mit mühsamen Rollen und suchen der Funktionen und Klassen verbunden.
Ganz besonders wenn man auch noch viele Namespaces verwendet.

Es gibt eine Funktion, der normalerweise kein Hotkey zugeordnet ist: View.SynchronizeClassView.

Der Name deutet es ja schon an, der Class View wird mit dem aktuellen Kontext synchronisiert.  Am Besten man weißt dieser Funktionen eine guten Hotkey zu und probiert die Funktion aus. Ich verwende hier Alt+A, S.

Diese Funktion zeigt den Class View an (auch wenn diese Tab-Seite aktuelle nicht aktiv ist), weiterhin wird sofort die aktuelle Klasse oder Funktion im Class View angezeigt, in dessen Kontext man sich aktuell befindet. Längeres Navigieren erübrigt sich.

VS-Tipps & Tricks: Direkte Befehlseingabe über Schnellsuche

Das Command-Window kennt man wahrscheinlich schon (Strg+Alt+A).
Man kann hier direkt über die Tastatur und mit Hilfe von Intellisense, das gesamte Visual Studio steuern. Das ist aber nicht unbedingt unbekannt wird aber selten benutzt.

Interessant ist, dass man sehr schnell ohne ein weiteres Fenster diese Befehlseingabe auch so benutzen kann. Über das Schnellsuch-Fenster.

Drückt man Strg+D, landet man in dem bekannten Eingabefenster im Toolbar in dem man nun nach etwas suchen kann. Aber dieses Fenster kann mehr. Gibt man nun das Größer-als-Zeichen > ein, dann kann man nun auch hier direkt einen Befehl mit der Zusatzhilfe von Intellisense ausführen.

Die Tastenkombination Strg+D > op Eingabetaste öffnet den Datei-Öffnen Dialog.
Mit der Tastenkombination Strg+D > va . opt kommt man an den VA Options Dialog.

VS-Tipps & Tricks: Kontextmenü auf Karteireitern

In der Newsgroup microsoft.public.de.vc kam die Frage auf, ob es eine Seite mit speziellen Tipps und Tricks gibt für Visual Studio. Meines Wissens nach gibt es so etwas leider nicht. Deshalb habe ich mir vorgenommen demnächst einzelne Tipps & Tricks hier zu veröffentlichen.
Eine komplette Sammlung und Übersicht ist dann über diese Seite oder über die Kategorie-Auswahl in meinem Blog möglich.

Wer etwas beizusteuern hat, kann gerne eine Email an mich senden.

Aber nun zum ersten Tipp: Kontextmenü auf Karteireitern

Es lohnt sich einen Blick auf das Kontext-Menü zu öffnen, das sich öffnet, wenn man mit der rechten Maus auf den Karteireiter einer offenen Datei im Visual Studio klickt. Dort gibt es drei äußerst nette Helferlein, die man leicht übersieht:

  1. Close All But This
    Schließt alle Fenster bis auf das aktive. Besonders gut noch einer Debugging Session um wieder etwas Übersicht zu bekommen.
  2. Copy Full Path
    Kopiert den kompletten Pfad der Datei auf die Zwischenablage.
  3. Open Containing Folder (Mein Favorit) ❗
    Netter und schneller kann man den entsprechenden Projekt Ordner im Explorer nicht öffnen. Besonders, wenn man seine Projektdateien in Unterverzeichnisse gegliedert hat kommt man hier ganz schnell an das entsprechende Explorer-Fenster.

Command Routing der MFC bei Kontext Menüs mit TrackPopupMenu

Kontext Menüs  gehören zum State of  the Art.

Es ist auch nicht weiter schwer ein Menü zu laden ünd per TrackPopupMenu auf den Bildschirm zu zaubern. Entsprechender Code sieht dann meistens so aus:

void CMyView::OnContextMenu(CWnd* pWnd, CPoint pt)
{
    // Get the menu
    CMenu popups;
    if (!popups.LoadMenu(_T("AGV-IDR_MACRO_EDITOR_CONTEXT")))
        AfxThrowResourceException();
    CMenu* pSubMenu= popups.GetSubMenu(0);
    ASSERT(pSubMenu);
    if (!pSubMenu)
        AfxThrowResourceException();
    pSubMenu->TrackPopupMenu(0,pt.x,pt.y,this);
}

Oft sind in dem Menü einfache IDs von Commands verwendet worden, die irgendwo im View, Dokument, Frame oder der Applikation implementiert sind. Der Programmierer wundert sich nun warum seine Menüpunkte nicht ausgegraut werden. Alle Menüpunkte für alle IDs sind aktiv. Und man wundert sich noch mehr. Manche Commands (außerhalb des Views) werden nicht ausgeführt.

Was läuft hier falsch?

❗ Die Antwort liegt einzig und alleine im Aufruf von TrackPopupMenu! Der letzte Parameter gibt an, an wen die entsprechenden Nachrichten (WM_COMMAND, WM_INITPOPUPMENU und andere) gesendet werden. Naheliegender Weise gibt der Entwickler hier das Fenster an, in dem er das Popup Menü anzeigen will. Hier liegt der Hase im Pfeffer.
Ein normales Fenster und ein View hat keine Verwendung (Handler) für WM_INITPOPUPMENU. Solch ein Handler wäre aber für das Command Routing der MFC notwendig um die Menu-Items ein- und auszuschalten.

Das CMainFrame hat solch einen Handler, und kann damit umgehen. Also einfach das CMainFrame als Zeiger übergeben und … es funktioniert wie erwartet. Warum auch nicht. Die IDs aus dem normalen Menü werden ja auch über genau den selben Weg des Command Routings behandelt.
Die entscheidende Codezeile sieht dann so aus:

pSubMenu->TrackPopupMenu(0,pt.x,pt.y,AfxGetMainWnd());

RTM für VS-2008 Orcas doch zum Ende des Jahres

Sorry für meinen etwas schnellen Blog-Eintrag:
http://blog.m-ri.de/index.php/2007/07/16/vs-2008orcas-kommt-jetzt-doch-erst-im-februar-2008/

Ich habe Launch und RTM (Release to Market) durcheinandergebracht. Sorry!

Wie es aussieht ist es doch schon Ende des Jahres soweit: 

http://blogs.msdn.com/dseven/archive/2007/07/10/windows-server-2008-visual-studio-2008-and-microsoft-sql-server-2008-joint-launch-announced.aspx

„While the launch events are scheduled to kick off on February 27, 2008, Visual Studio 2008 will be released before the end of the year.“

http://blogs.msdn.com/somasegar/archive/2007/07/13/it-all-begins-february-27th.aspx

„While we will be launching our products together in February, we are still aiming to release Visual Studio 2008 and .NET FX 3.5 by the end of this year based on your feedbackso far.“