Die Sache mit den verflixten #defines

By dose | March 29, 2007
Under: technical stuff, Uncategorized
Comments: No Comments »

Oft entstehen Probleme in Programmen aufgrund von ungenügender Kenntnis einer Programmiersprache.
Dieses Problem tritt vermehrt natürlich dann auf, wenn mehrere LEute an einem PRogramm arbeiten.
So ein Problem stellte sich unlängst bei uns in der Firma:

Für unsere Softwareprodukte haben wir ein eigenes Window-Management System entwickelt, welches die Terminal-Ausgabe über verschiedene Messages, die über ein eigenes RPC-System zum Client gesendet werden, auf eine GUI umsetzt, welche die entsprechenden Controls dann anzeigt.
Somit gibt es auch eine Funktion, mit welcher man sich für verschiedene Events registrieren kann, um den Netzwerktraffic-Overhead möglichst gering zu halten. Die jeweiligen Events werden dann zum Client geschickt.
Die Events sind logischerweise als Flags definiert, welche man setzen kann.
Irgendwer hat das Window-Management System dann um ein neues Event, und damit um ein neues Flag, nennen wir es FLAGx, erweitert. Folgende #defines wurden verwendet:


#define FLAG1 00000010
#define FLAG2 00000020
#define FLAG3 00000040
#define FLAG4 00000100
#define FLAGx 00000256

Und jetzt die Rätselfrage: Was hat der Programmierer, der FLAGx deklariert hat hier falsch verstanden?
Bitte als Comment posten 😉

Einfärben von ListBox und ListView controls

By dose | March 15, 2007
Under: technical stuff, Uncategorized
Comments: No Comments »

Die Aufgabenstellung selbst erscheint relativ simpel: Man möchte in einer ListBox bzw. in einem ListView einen Eintrag mit einer Hintergrundfarbe hinterlegen, um diesen z.B. besonders hervorzuheben.
Leider unterscheiden sich die Methoden hierfür bei ListBox und ListView erheblich.
Beim ListView ist das Ganze relativ einfach zu lösen:

Das ListView sendet eine WM_NOTIFY Message an den Parent-Dialog, der das Control beinhaltet. Als lParam erhält man eine LPNMLISTVIEW Struktur, welche im hdr Member wiederum einen Member code enthält, welcher den eigentlichen Notification code angibt. Für das ListView ist hier für uns der Code NM_CUSTOMDRAW interessant. Durch Erhalt der Message ist sichergestellt, dass es sich bei der in lParam an uns übergebene Struktur um eine NMLVCUSTOMDRAW Struktur handelt. In deren Member nmcd befindet sich die zur Message zugehörige Struktur NMCUSTOMDRAW, welche wiederum den Member dwDrawStage beinhaltet, der uns über den aktuellen Zeichnungsstatus informiert. Erhalten wir hier die Nachricht CDDS_PREPAINT, wissen wir, dass das Zeichnen des ListViews gerade beginnt. An dieser Stelle müssen wir nun unser Interesse an den Notifications für die einzelnen Items der Liste anmelden. Das geht ganz einfach mit folgendem Kommando:
SetWindowLong (hWnd, DWL_MSGRESULT, CDRF_NOTIFYITEMDRAW);
Mit besagtem Kommando teilen wir dem Notifier unsere Antwort mit, die da eben lautet CDRF_NOTIFYITEMDRAW.
Nun können wir den Drawstage pro Item mit der Nachricht CDDS_ITEMPREPAINT dispatchen.
An dieser Stelle können wir nun auf den Zeichenprozess einfluss nehmen, indem wir die Members de rStruktur in lParam entsprechend modifizieren und den Notifier diese Änderung zur Kenntnis bringen.
Hier ein Beispiel, welches den Text rot färbt:
lplvcd->clrText = RGB(255,0,0);
SetWindowLong (hWnd, DWL_MSGRESULT, CDRF_NEWFONT);

Den kompletten Source zur besseren Übersicht gibt’s hier

Bei der ListBox ist das Ganze leider nicht ganz so einfach. Diese bietet nämlich leider keinen so bequemen WM_NOTIFY-Mechanismus. Stattdessen muss man sich hier mit einem owner-Drawn control aushelfen, was natürlich einiges an Arbeit mit sich bringt. Daher sollte man als Style für das Control LBS_OWNERDRAWFIXED verwenden. Ein LBS_HASSTRINGS könnte sich auch als nützlich erweisen.
Bei einem Owner-Drawn control erhält der Parent eine WM_DRAWITEM Notification, welche entpsrechend behandelt werden muss.
Als lParam erhält man ein LPDRAWITEMSTRUCT, welches den Member itemAction hat. Interessant sind hierbei die Actions ODA_SELECT und ODA_DRAWENTIRE.
Ein Zeichnen des ListBox-Eintrags im entsprehcenden Style erreicht man hier mittels Modifikation des device contexts, welcher sich im hDC Member des DRAWITEMSTRUCTs befinder.
Je nach itemState Member sollte man die Vordergrund- und Hintergrundfarbe des Eintrags entsprechend setzen. Um die Systemfarben zu ermitteln, empfiehlt sich der Einsatz der Funktion GetSysColor.Mit FillRect die Auswahlmarkierung erzeugen und mit TextOut schließlich den Text zeichnen. Also ein relativ hoher Aufwand, um nur die Farbe des Textes zu ändern.
Ein Codebeispiel gibt’s wie immer hier.

MessageBox mit Mauscursor auf default button

By dose | January 16, 2007
Under: technical stuff, Uncategorized
Comments: No Comments »

Ich bin unlängst vor dem Problem gestanden, dass ich eine Software, welche sich über ein Diktiergerät
steuern lässt (im Prinzip ein USB HID mit Zusatzknöpfen), entsprechend erweitern sollte, sodass der
Mauscursor auch in Dialogen entsprechend immer auf dem Default-Knopf platziert wird.
Das bietet den Vorteil, dass man beim schnellen Arbeiten z.B. bei der Frage, ob man ein Diktat speichern will,
nur noch die linke Maustaste drücken muss, um zu bestätigen, und nicht jedesmal mit der Trackpad-Kugel
hinfahren muss.
In selbst definierten Dialogen geht das ja relativ einfach mit SetCursorPos. Was aber macht man bei Standard Windows-Dialoge, welche man mit MessageBox generiert? Hier hat man ja normalerweise keinen Einfluss auf die Gestaltung des Dialogs. Aufmerksame Leser meines Blogs werden sich an meinen Artikel zur Anpassung von Standarddialogen erinnern, wo diese Problematik ja schon einmal besprochen wurde. Windows bietet ja glücklicherweise die Möglichkeit, mittels SetWindowsHookEx und einer CBTProc-Funktion die Erstellung von Messageboxes zu hooken und damit auch zu beeinflussen.
Konstruiert man also nun so einen Hook, kann man die HCBT_ACTIVATE Notification abfangen. Zu diesem Zeitpunkt sind bereits alle Controls positioniert und gesetzt. Daher kann man dann mittels GetWindowLong mit dem GWL_STYLE Parameter abfragen, welcher Button default ist. Um das Ganze für alle möglichen Buttons in einer Schleife realisieren zu können, muss man die IDs der einzelnen Buttons wissen:

#define IDOK 1
#define IDCANCEL 2
#define IDABORT 3
#define IDRETRY 4
#define IDIGNORE 5
#define IDYES 6
#define IDNO 7

Es reicht also, zwischen IDOK und IDNO zu loopen.
Interessanterweise kann sich die Position des MessageBox-Fensters auch nach HCBT_ACTIVATE noch ändern, sodass man mittels SetWindowPos die Fensterposition auf eine marginal andere Position als die aktuelle ändern muss, damit das Fenster dort bleibt, wo es ist.
Dann einfach mit SetCursorPos den Mauscursor auf das Default-Button platzieren und fertig.

Das Sourcecode dafür gibt es hier

Win32 API Tutorial

By dose | December 9, 2006
Under: technical stuff, Uncategorized
Comments: No Comments »

Beim Herumstöbern im Netz bin ich auf eine gute Seite mit nützlichen Win32-Codesnippets gestoßen, die ich dem geneigten Leser dieses Blogs nicht vorenthalten möchte: Win32 tutorial

COM Interface von C aus ansprechen

By dose | November 14, 2006
Under: technical stuff, Uncategorized
Comments: No Comments »

Ich habe ja schon bereits vor einiger Zeit erklärt, wie man COM-Interfaces von reinem C aus über die VTable eines COM-Objekts richtig anspricht. Allerdings gibt es natürlich manchmal das Problem, dass keine C-Style Deklaration des Interfaces vorliegt. Beim Surfen durch das Netz bin ich hier auf einen interessantes Artikel gestoßen, der gut erklärt, wie man nun COM-Interfaces von C aus anspricht: COM-Interfaces von C aus ansprechen

Bluetooth Crack

By newq | November 4, 2006
Under: Uncategorized
Comments: No Comments »

Thierry Zoller und Kevin Finistere haben auf der Hack.lu-Konferenz beeindruckend bewiesen, dass es mit der Sicherheit in Bluetooth-Geräten nicht weit her ist. Sie zeigten eine Demonstration mit dem Windows-Tool BTCrack. Bluetooth-PIN und Linkkey wurden nach dem „Handshake“ in fast Echtzeit gecrackt.

Größe eines struct members ohne Instanzierung ermitteln

By dose | October 20, 2006
Under: technical stuff, Uncategorized
Comments: No Comments »

Manchmal steht man vor dem Problem, die Größe eines einzelnen Eintrags einer Struktur wissen möchte, ohne die Struktur vorher instanzieren zu müssen, beispielsweise, um die Größe einer anderen Struktur entsprechend anzupassen.
Folgendes Beispiel soll dies verdeutlichen:

typedef struct {
char szText[10];
int iInt;
} Struct1;

typedef struct {
char szBuf[sizeof(Struct1.szText)];
long lLong;
} Struct2;

Natürlich funktioniert dieses Beispiel nicht, weil der sizeof() Operator nur auf “instanzierte” Strukturen angewandt werden kann, nicht auf die Typendefinition an sich. Was kann man in diesem Fall also tun?
Eine Funktion zur Auflösung zu schreiben fällt aus, da die Größe ja schon zur Compilezeit feststehen muss.

Nach einiger Überlegung kommt man dann zur eigentlich trivialen Lösung des Problems:
Wenn der Compiler unbedingt eine “Instanz” haben will, dann soll er sie doch mittels eines Typecasts haben.
Also erstellt man einfach einen Pointer auf die Struktur an Adresse 0, und verwendet dann wie gewohnt den sizeof()-
Operator. Folgendes Makro bewerkstelligt die Aufgabe:

#define SIZEOFMEMBER(struct_type, member) sizeof((((struct_type *)0)->member))

Die Definition von Struct2 auf dem obrigen Beispiel würde dann also folgendermaßen funktionieren:

typedef struct {
char szBuf[SIZEOFMEMBER(Struct1, szText)];
long lLong;
} Struct2;

Cursed GTK package

By dose | October 18, 2006
Under: technical stuff, Uncategorized
Comments: No Comments »

Bei meinen Recherchen zu einem GUI-Toolkit, welcher Win32 und Linux unterstützt und wenn möglichst auch noch eine rudimentäre Terminal-Darstellung zur einfacheren Wartung bietet, bin ich auf das folgende geniale Projekt gestoßen:
Cursed GTK.
Lädt man diese Bibliothek beim Laden einer GTK-Anwendung auf der Shell, so bekommt man eine ncurses-Oberfläche mit den wichtigsten Widgets. Somit ist es zumindest möglich, einfache Wartungsprogramme ohne viel Aufwand mit dem GLADE Userinterface builder zu basteln, welche gleichzeitig auch von der Shell aus noch bedienbar sind, sofern man sich auf einfache Widgets beschränkt.
Das Projekt hat nur leider den Nachteil, dass es seit Ende 2003 nicht mehr weitergewartet wird. Dementsprechend basiert es auch auf etwas älteren Libraries und funktioniert u.A. mit aktuellen Versionen der libpango (Teil von GTK) nicht mehr. Eine ältere libPango lässt sich wiederum nicht mehr ohne herumpatchen mit einer neueren Freetype-Version kompilieren usw. Kurzum: Das Ganze ist leider recht mühselig einzurichten.
Um einem diesen Aufwand zu ersparen, habe ich mir die Mühe gemacht, di ebenötigten Bibliotheken zu kompilieren und das Installationsscript der RPM-PAkete entsprechend zu fixen, sodass man eine Lösung hat, welche nur noch mit einem Shellscript installiert werden muss und dann automatisch mit den richtigen Bibliotheken out-of-the-box läuft.
Das Paket kann man sich hier herunterladen.
Sofern man rpm benutzen kann, muss man nur install.sh ausführen und im Besten Fall installiert sich das Paket von selbst. Es ist allerdings darauf zu achten, dass sich das Verzeichnis des PAkets nach der Installation nicht mehr ändern darf, da man die in dne Unterverzeichnissen enthaltenen Bibliotheken zum Laden der jeweiligen Applikation benutzen muss.
Starten kann man eine GTK-Applikation im Textmodus mittels des enthaltenen Shellscripts runcursed.sh.
Möchte man das Ganze wieder deinstallieren, so muss man nur uninstall.sh ausführen.
Hat man Debian und damit kein RPM zur Verfügung, kann man sich mit ein wenig Bastelei mit alien behelfen.
Auf jeden Fall ist das Ganze nach wie vor eine interessante Bibliothek. Bleibt nur zu hoffen, dass sich irgendwann wieder um dieses verwaiste Projekt annimmt.

Hohe CPU-Auslastung durch DOS-Programme in ntvdm vermeiden

By dose | October 10, 2006
Under: technical stuff, Uncategorized
Comments: No Comments »

Heute bin ich zufällig beim Surfen über folgenden interessanten Forumpost gestolpert:
http://www.softgames.de/forum/frage117849.html
Der Autor vermindert damit das Problem, dass DOS-Programme, die sehr oft die Tastatur pollen, die CPU den Rechners, auf welchem sie in der NTVDM rennen, auf Vollast bringen.
Eine einfache und dennoch sehr praktische Lösung in Form eines TSRs hat der Autor in seinem Beitrag vorgestellt.

TreeView-Items ohne bzw. fixen Checkboxen

By dose | September 28, 2006
Under: technical stuff, Uncategorized
Comments: No Comments »

Das TreeView-Control der Windows Common Controls bietet unter Anderem die Möglichkeit, vor jedem Eintrag Kontrollkästchen (Checkboxen) zu platzieren, die mit Tastatur und Maus beliebig ein- und ausgeschaltet werden können.
Hierzu muss einfach der Style TVS_CHECKBOXES gesetzt werden.
Als Checkboxen-Bildchen werden sogenannte StateImages verwendet.
Leider bietet Windows keinen Einfluss auf die Automatik, die hinter dem Toggeln der Checkbox liegt.
Eine Funktion wie TVN_SELCHANGING nur für das Ändern des Kontrollkästchen-Status wurde also scheinbar vergessen. Das ist insbesondere dann ärgerlich, wenn man einen User daran hintern möchte, den Status einer Checkbox zu ändern oder wenn man einfach nur eine Notification erhalten möchte, wenn der User den Status einer Checkbox ändert.
Es bleibt einem daher nichts anderes übrig, als die selben Nachrichten, die von der Window-Routine zum Ändern des Checkbox-Status herangezogen werden, in einer Subclassing-Procedure entsprechend zu filtern.
Bevor wir uns nun näher ansehen, wie das Ganze funktioniert, sei noch der Geheimnis gelüftet, wie man für einen einzelnen Eintrag kein Kontrollkästchen anzeigt: Hierzu nimmt man den Index 3 mittels des Makros INDEXTOSTATEIMAGEMASK für den state-Parameter des Treeview-Items. Benutzt man diesen Parameter, hat man aber das Problem, dass Windows den Status der Checkbox beim nächsten Klick auf die Stelle, wo sich das Kontrollkästchen befinden sollte, oder beim Drücken der Leertaste, munter weiter toggelt und das Kontrollkästchen so wieder von selbst erscheint. Mit dem hier gezeigten Lösungsansatz kann dieses Problem gelöst werden:

Grundsätzlich wird einfach eine Subclassing-Procedure für das TreeView installiert, welche Tastendrücke (WM_KEYDOWN) auf die Leertaste (VK_SPACE) und Mausklicks mit der linken Maustaste (WM_LBUTTONDOWN) filtert. Eben jene Nachrichten also, die zum Toggeln der Checkboxen verwendet werden. Beim Mausklick muss natürlich noch zusätzlich überprüft werden, ob die Koordinaten des Mauscursors auf ein StateItem zeigen (TVHT_ONITEMSTATEICON) und ob das Item zum aktuell gewählten Item gehört.
Sind diese Bedingungen erfüllt, so wird geprüft, ob es sich um ein leeres Item handelt (der Index in die Stateimagemask also 3 ist). Ist dies der Fall, so erfolgt keien weitere Behandlung der Nachricht durch die originale Windowprocedure und damit kein Toggeln des Status.
Prinzipiell ist das Ganze also relativ einfach. Das Beispiel sollte auch leicht modifizierbar sein, sodass eine entsprechende Notification gesendet wird, wenn sich der Status einer Checkbox ändert o.ä.
Für Fragen und Anregungen gilt natürlich wie immer: Einfach einen Kommentar hinterlassen.

Das komplette Codefragment mit der Realisierung des Ganzen gibt es hier