ToolTips für TreeView-Einträge
Manchmal kann es praktisch sein, dem User zu den einzelnen Einträgen in einem TreeView zusätzliche Informationen anzuzeigen. Wie unter Windows üblich, kann man dies mittes eines ToolTips bewerkstelligen.
Standardmäßig zeigt das TreeView-Control nur dann Tooltips an, wenn der Text des Eintrags abgeschnitten wird, sofern das Quickinfo flag gesetzt ist.
Will man jedoch Tooltips zu einzelnen Einträgen anzeigen, findet man keine entsprechende Funktion dafür. Man ist daher forciert, das Ganze selbst auszuprogrammieren. Sucht man im Internet nach entsprechenden Informationen, findet man leider nur MFC-Codebeispiele. Grundsätzlich ist die Lösung jedoch relativ einfach:
Mittels des Filtern der Windowmessage WM_MOUSEMOVE
des Treeview-Controls kann man die Position des Mauscursors auf dem Control herausfinden und mittels TreeView_HitText
prüfen, ob dieser sich über einem Eintrag befindet. Um dies realisieren zu können, muss das Control gesubclassed werden (dies geschieht in bekannter Weise mittels SetWindowLong GWL_WNDPROC
. Ist nun das entsprechende Item identifiziert, für welches der ToolTip angezeigt werden soll, so legt man einfach ein Tooltip für das TreeView-Control an, sofern noch keines existiert. Existiert bereits ein Tooltip, so ist einfach der Text des Tooltips entsprechend dem zum Eintrag zugehörigen Text geändert. Damit der Tooltip wieder verschwindet, wenn der Cursor außerhalb des Bereichs von einem Eintrag ist, wird der Tooltip in diesem Fall einfach wieder gelöscht.
Um nun den anzuzeigenden Text einem Eintrag zuzuordnen, kann der LPARAM-Parameter verwendet werden. Nachdem man wahrscheinlich noch andere Paramter mitspeichern möchte, wird beim Anlegen eines Eintrags Speicher alloziert, in welchem eine Struktur mit den Parametern, u.a. auch den anzuzeigenden Text, gespeichert wird.
Der allozierte Speicher ist daher bei einer TVN_DELETEITEM
notification wieder freizugeben.
Das komplette Codefragment mit der Realisierung des Ganzen gibt es hier
Fehelrhafte Nachrichtenschleifen und ihre Folgen
In einer meiner Applikationen habe ich einen sehr merkwürdigen Bug beim Verhalten einer Combobox bemerkt:
Die Combobox ließ sich zwar ganz normal öffnen, indem man auf den dropdown-Pfeil klickt, allerdings ließen sich beispielsweise keinerlei Items mittels der Maus darin auswählen (mit der Tastatur funktionierte es allerdings).
Auch zuklappen konnte man das Dropdown-Feld nicht mehr. Einzig, wenn man ESC drückte, wurden die zuvor ausgeführten Ereignisse abgearbeitet (klcikte man z.B. auf den Dropdown-Pfeil und es tat sich nichts und drückte man dann ESC, so klappe das Auswahlfeld kurz ein und dann wieder aus, weil der MAusklick von zuvoir nun verarbeitet wurde).
Nach einigem Rätselraten ob des merkwürdigen Effekts bin ich schließlich auf folgenden News-Beitrag gestoßen, der die Problematik erklärt:
Das Dropdown-Menü ist ein seperates Top-Level Fenster, dessen Nachrichten natürlich auch verarbeitet werden müssen. Das Problem war demnach in meiner Nachrichtenschleife, in welcher ich in meiner GetMessage
-Funktion nur die Nachrichten meines Hauptfensters und dessen Unterfenster verarbeitete und nicht alle Nachrichten, was das merkwürdige Problem verursachte.
Mach sollte der GetMessage
-Funktion in der Haupt-Nachrichtenschleife also wenn möglich immer das NULL-Handle übergeben, damit alle Nachrichten verarbeitet werden können. Konkret also:
while (GetMessage(&msg, NULL, 0, 0))
if (!IsDialogMessage(&msg, hDlg)) TranslateMessage(&msg), DispatchMessage(&msg);
Grid control für Win32
Die Standard WIN32-Forms und Common Controls sind ansich sehr praktisch, um benutzerfreundliche Forms anzulegen. Allerdings besitzen sie von Haus aus keine Funktionalität für Grids, wie diese z.B. von Excel her bekannt sind. Nun gibt es zwar zahlreiche Implementierungen von Grids im Internet (die meisten funktionieren mit Hilfe eines ListView-Controls), diese basieren jedoch leider zumeist auf der MFC, sodass hier wieder unnötiger Overhead entsteht. Was aber macht der normale Win32-API Programmierer in diesem Fall? Erst nach langem Suchen bin ich über den Artikel Win32 Grid Control with Low Overhead (BABYGRID) auf codeguru.com gestoßen, welcher eine Implementierung mittels normaler WIN32-API zeigt. Mit ein paar kleinen Fixes lässt sich der Code auf C portieren (es werden leider standardmäßig einige C++ Features verwendet, das Ganze lässt sich jedoch sehr einfach reparieren. Bei Interesse an dem korrigierten Code einfach einen Kommentar hinterlassen). Praktischerweise wird das Control zur Gänze selbst gezeichnet, sodass man auch leicht auf die Optik des Controls Einfluss nehmen kann. Ich habe beispielsweise erfolgreich ein Sudoku-Lösungsprogramm damit realisiert.
Microsoft Patch KB914784 Für Win64 problematisch
Der Patch KB914784 von Microsoft fügt zusätzliche sicherheitsfunktoinen in den Kernel ein, die eine Modifikation der internen Strukturen verhindern soll. Leider basieren viele Programme auf Techniken dieser art, sodass diese nach der Installation des Updates nicht mehr funktionieren. Beispielsweise ist das populäre Programm Daemon Tools betroffen (siehe Forumbeitrag). Von der Installation dieses Patches wird daher abgeraten.
Generell verursachen neue Sicherheitsfeatures von Windows oft ziemliche Probleme, sodass diese mit vorsicht zu genießen sind (vgl. Beitrag DEP unter Windows XP SP2 und 16bit Applikationen). Auch hier habe ich heute ein weiteres Programm gefunden, welches im Zusammenhang mit der DEP nicht mehr korrekt funktioniert.
Für Microsoft ist es natürlich eine schwierige Entscheidung, einerseits ihr Betriebssystem sicherer zu machen und andererseits die Kompatibilität mit bestehenden Applikationen nicht zu brechen…
Tab controls verwenden
Unter Windows gibt es die Möglichkeit, sogenannte Tab controls zu verwenden. Diese sind zum Beispiel für Eigenschaftsseiten ganz praktisch, um mehrere Optionen übersichtlich darstellen zu können.
Gleich vorweg: Windows bietet hierfür eigene Funktionen für Eigenschaftsseiten an, die verwendet werden können: MSDN – PropertySheets
Allerdings kann es auc hganz interessant sein, so etwas selbst nachzubauen, vor Allem, wenn man eigentlich keine richtigen Eigenschaftsseiten benötigt:
Nachdem das Tab-Control selbst nur Notifications sendet, wenn ein entsprechender Tab angeklickt wird, muss man die Verwaltungs der den Tabs zugehörigen Controls selbst übernehmen. Eine Möglichkeit wäre, alle Controls der jeweiligen Tabs in den Dialog zu geben und von der Nummerierung her so zu wählen, dass immer ein gewisser Bereich an Controls aktiviert, und der Rest beim Wechsel deaktiviert wird. Dies ist jedoch sehr aufwendig zu implementieren und außerdem endet man schnell in einem Kuddelmuddel an Controls.
Einfacher ist es, für jede Tab-Seite einen eigenen Child Dialog zu generieren, der dann entsprechend angezeigt wird.
Ich habe hierzu etwas generischen Code geschrieben, um zu verdeutlichen, wie dies funktioniert:
Zuerst muss das Hauptfenster mit dem Tab Control erstellt werden, welches die anzuzeigenden Subfenster beinhaltet.
Auf diesem wird ein Tab-Control mit der ID IDC_TABS
erstellt. Ihm wird die unten gezeigte Window Procedure zugeordnet.
Danach müssen die entsprechenden Client-Fenster erstellt werden, welche die Styles WS_CHILD | WS_EX_CONTROLPARENT
gesetzt haben, da sie ja childfenster sind. Im Ressource Editor hierfür einfach die Häkchen Stile / Untergeordnet, Rand / Keine und Erweiterte Formate / Übergeordnete steuern wählen.
Hier nun der code der WndProc für das Tab-Fenster. In das Arrray uDialogs
einfach alle Dialoge, die zum Tab gehören eintragen. In pszTitles
die zugehörigen Tital, die auf den Tabs erscheinen sollen und in procDialogs
kann man schließlich die jeweiligen zugehörigen Window procedures setzen.
Alles unklar? Bei Fragen wie immer einfach comment hinterlassen.
Generische Erkennung von gepackten/verschlüsselten Dateien
Im Rahmen meines Rootkit-Detector Projekts benötigte ich eine routine, die erkennen kann, ob eine Datei verschlüsselt oder gepackt ist, um eruieren zu können, ob die Datei auf der Festplatte der im Speicher gleichen kann oder nicht.
Auf alle Signaturen aller auf dem Markt befindlichen EXE-Packer/Crypter zu prüfen ist hier kein optimaler Ansatz.
Stattdessen sollte die Erkennung möglich generisch sein. Was also tun?
Im Prinzip ist die Lösung trivial: Durch was zeichnen sich gepackte Dateien aus? – Durch die Eigenschaft, dass sie sich
schwer weiter komprimieren lassen, sprich: ihre Entropie ist möglichst klein. Dies kann man leicht auch mit einem Hexeditor feststellen:
Sieht man sich eine gepackte, oder auch eine verschlüsselte Datei damit an, so wird man feststellen, dass es sehr viele unterschiedliche Zeichen gibt, die Zeichenauftrittswahrscheinlichkeit ist also ziemlich gleichmäßig verteilt, während bei unkomprimierten Dateien oftmals viele aufeinanderfolgende gleiche Zeichen vorzufinden sind (z.B. lauter 00 – Bytes).
Man kann schon beim Betrachten der Struktur einer Datei mittels eines Viewers mit bloßem Auge sehen,
ob eine Datei komprimiert ist oder nicht. Hier ein Beispiel (nicht gepackt vs. gepackt):
Ich habe daher ein paar kleine Funktionen zum Prüfen der Entropie einer Datei geschrieben, um abschätzen zu können, ob eine Datei wahrscheinlich gepackt ist oder nicht. Ich habe das Ganze für WIN32 geschrieben, es lässt sich aber sehr einfach auf ANSI-C portieren:
Noch etwas zu den Konfigurationsparametern:
ENT_FREQ_MAX
gibt an, wieviele Bytes der Datei maximal analysiert werden sollen. Diese Begrenzung ist durchaus sinnvoll, da eine Prüfung großer Dateien sonts ineffizient wäre.
ENT_EXE_OFFSET
gibt an, wieviele Bytes an Anfang der Datei bei der Prüfung übersprungen werden sollen. dies ist sinnvoll, da der header einer Executable normalerweise nicht komprimiert sein kann und die Prüfung daher erst ab dem Codesegment sinnvoll ist (man köntne natürlich den EXE-header analysieren und erst bei merste ncode-segment zu prüfen beginnen, aber der Einfachheit halber habe ich hier darauf verzichtet).
ENT_BARRIER
gibt den Schwellenwert an, bei dessen Überschreitung eine Datei als nicht gepackt/verschlüsselt gilt. 10 ist hier ein guter Wert.
Der Rest dürfte selbsterklärend sein. Bei Fragen –> Comment hinterlassen.
80Bit IEEE float in 64Bit double in MS VC++ umwandeln
Verwendete man beispielsweise unter Borland Turbo C 3 in DOS einen float
oder double
Wert, so wurde der als IEEE 80Bit float dargestellt, was logisch erscheint, da die FPU der Intel x86 CPU ebenfalls intern mit dieser Au
flösung arbeitet. Ein long double
wird beim gcc C-Compiler ebenfalls in diesr Form repräsentiert. Es ist daher auch üblich, in binären Dateiformaten solche Werte vorzufinden.
Möchte man nun solche Werte im MS VC++ auslesen, steht man vor einem Problem:
Wie der MSDN-Dokumentation zu entnehmen ist, wird dieser Datentyp nicht unterstützt:
In Windows 32-bit programming, the long double data type maps to double. There is, however, assembly language support for computations using the real*10 data type.
Jetzt stellt sich daher die Frage, wie solche Werte ausgelesen und dann auf einen 64Bit breiten double (real*8) konvertiert werden können. Wie ja bereits in der MSDN steht, gibt es auf Assemblerebene Unterstützung für 80Bit breite float
Zahlen.
Es reichen daher auf der x86 CPU 2 kleine FPU-Assemblerkommandos zur Konvertierung. Man kann sich daher folgende kleine Funktion erstellen, welche eine Konvertierung vornimmt:
// float.h required
double _Convert10to8(void *ra)
{
double dbl;
// Floating point register clearen:
_clearfp ();
// 80Bit double lesen und auf 64Bit double schreiben
__asm FLD tbyte ptr [rbuf]
__asm FSTP qword ptr [dbl]
// Bei einem Overflow 0 zurückliefern
if (_statusfp() & _SW_OVERFLOW) return 0;
return dbl;
}
Dynamische arrays in C
Von C++ her kennt man ja die praktischen Klassen zur dynamischen Datenverwaltung wie set
, map
, vector
, etc.
In C sind vor Allem mehrdimensionale Arrays mit variabler Größe aber durchaus eine Herausforderung.
Standardmäßig kann man mehrdimensionale arrays nur fix definieren, z.B.:
char [15][10];
Dies ist für den C-Compiler einfach, da er hier nur entsprechend Speicher im DAtensegment reservieren muss, den man dann nach und nach füllen kann. Die dynamische Verwaltung einer solchen Strutkur am Heap ist der Runtime jedoch nicht zumutbar. Grund genug, ein paar kleine eigene Funktionn zu schreiben, um dynamische Arraybäume zu erstellen und verwalten.
Die Dokumentation der kleinen Funktionen befindet sich in der Header-Datei, die hier gezeigt wird:
Herunterzuladen gibt es die kleine Funktionssammlung hier
Super Mario performance
Witziges Video:
Supermario live
e-Mail und Internet Explorer Seiten – Passwörter auslesen
Bei der Systemmigration hat man oft das Problem, alte e-mails und Bookmarks auf den neuen Windows-Rechner zu transferieren.
Hierfür gibt es einige nützliche Utilities und seit Windows XP gibt es hierfür auch einen eignen Migrationsassistenten.
Zur Not reicht es auch, die entsprechenden Dateien zu kopieren, auch wenn die e-mail Accounteinstellungen bei dieser Methode dann verloren gehen, da diese in der Registry abgelegt sind. Für welche Methode man sich auch immer entscheidet, jede hat den Nachteil, dass man die Passwörter der entsprechenden Accounts nicht mitübernehmen kann.
Oft stellt dies ein Problem dar, wenn die Passwortinformationen nicht mehr verfügbar sind, z.B. weil die entsprechenden Unterlagen verschmissen wurden. Glücklicherweise gibt es eine Möglichkeit, gespeicherte Passwörter auszulesen:
Ich bin heute zufällig beim Suchen nach informationen zum “Protected Storage System Provider” über das nützliche Tool Protected Storage PassView gestolpert.
Achtung: Das Tool wird von einigen Antivirusprogrammen fälschlicherweise als Virus erkannt.