Die Unsitte GetCursorPos statt GetMessagePos zu verwenden

Im Endeffekt ist es der gleiche Grund warum man GetKeyState und nicht GetAsynchKeyState verwenden sollte (siehe Die Unsitte GetAsyncKeyState statt GeyKeyState zu verwenden…).

Auch hier liefert GetCursorPos die aktuelle Mauszweiger Position während GetMessagePos die Position liefert in dem Moment in dem die aktuelle Windows Nachricht eingeliefert wurde.
Oft genug wird hier kein Unterschied sein, aber durch aufwendigere Berechnungen oder gar durch eine verzögerte Abarbeitung von Windows Nachrichten (lange Zeit wurde evtl. keine Nachrichtenschleife mehr abgearbeitet), kann es sehr wohl passieren, dass ein Mausklick für eine Position eingeliefert wird, der (Millisekunden) her ist, während die aktuelle Mausposition schon Millimeter weiter ist.

Ist ein User dann richtig schnell und hektisch, kann die folgende Kombination fatale Folgen bei Verwendung von GetCursorPos haben.

  • System ist etwas beschäftigt und die Nachrichtenschleife wird nicht zeitnah abgearbeitet
  • User klickt mit Maus auf Item1
  • Die Maus wird etwas weiter bewegt und steht nun auf Item2
  • Verzögertes Abarbeiten beginnt jetzt und das Programm ermittelt mit GetCursorPos Item2 und selektiert es.
  • User drückt Entf-Taste und wundert sich 😮 dass Item2 weg ist!

Wäre GetMessagePos hier verwendet worden, wäre das korrekte Item1 gelöscht worden.

Das Verwechseln dieser beiden Funktionen hatte mir in einem Stück Software sogar einen richtigen Crash beschert. Wir hatten in einem bestimmten Fenster eigentümliche Abstürze. Er trat immer auf wenn bestimmte Leute (Kategorie Poweruser oder Übernervös) mit der Maus bestimmte Teile in der Auswertung markierten bzw. selektierten.

Ein Programmierer nutze GetMessagePos, der andere GetCursorPos für einige Kalkulationen. Meistens ist kein großer Unterschied zwischen den beiden Werten aber manchmal kam es schon vor. Effekt war aber hier, dass die eine Routine mit einem Objekt eine Funktion einleitete und an anderer Stelle ein anderes Objekt ermittelt wurde. Und gerade einige hektische Leute, die Klicken während Sie noch nicht mal genau gezielt haben, brachten es zustande, dass es einen Unterschied gab zwischen der ursprünglichen Position (bei der ersten auslösenden Nachricht) und der aktuellen Mausposition (wenn die Nachricht dann abgearbeitet wurde).

4 Gedanken zu „Die Unsitte GetCursorPos statt GetMessagePos zu verwenden“

  1. Hallo Martin,

    müsste es statt „… kann die folgende Kombination fatale Folgen bei Verwendung von GetMessagePos haben.“
    nicht
    „… kann die folgende Kombination fatale Folgen bei Verwendung von GetCursorPos haben.“

    So wie ich es verstanden habe und die Überschrift es suggiert, ist doch GetCursorPos die problematische Funktion.

    Gruß
    Thorsten

  2. Das erinnert mich etwas an GetTickCount() und GetMessageTime() .
    Einmal die echte Zeit, in der der Anwender eine Taste gedrueckt hat, und
    einmal die, wo sie in der Fensterprozedur verarbeitet wird.

    Aber GetTickCount() und GetMessageTime() lassen sich in einem meiner
    Programme auch als Paar verwenden.
    Hier habe ich (nur wenn ich per Remote Desktop komme) das Problem,
    dass wenn ich zum Blaettern eine Taste sehr lange gedrueckt halte,
    diese Taste auch noch lange nach dem Loslassen immer weiter an die
    Anwendung gesendet wird und so minutenlang ganz ohne mein weiteres
    Zutun „nachblaettert“.
    Das ist (war) sehr nervig und kann (konnte) nur durch das Killen des
    Prozesses beendet werden.
    Da nur Tasten betroffen sind, habe ich direkt hinter WM_KEYDOWN
    eingefügt:

    if(GetTickCount()-(DWORD)GetMessageTime()>(DWORD)1000) return DefWindowProc(hwnd,uMsg,wParam,lParam);

    Damit wird jede Taste verworfen, die aelter als eine Sekunde ist.
    Waehrend GetTickCount() einen DWORD liefert, tut das GetMessageTime()
    nicht. Wenn man aber alle (nicht DWORD-) Werte nach (DWORD)
    casted, funktionert die Differenzbildung sogar ueber den Ueberlauf bei
    49,7 Tagen hinweg, was jeder mit einem kleinen Programm, in dem er
    die moeglichen DWORD Werte mal subtrahiert, nachpruefen kann (hurra,
    in dem Punkt der Diskussion entgangen;-)

  3. Alt, aber wichtig. Ich möchte noch eine böse Falle erwähnen:

    Bisher habe ich das so (=falsch) gemacht:
    > DWORD pos = GetMessagePos();
    > point = CPoint(LOWORD(pos), HIWORD(pos));

    Das funktioniert eigentlich auch. Solange bis der Klick in einem Monitor links vom Hauptmonitor passiert und die X-Koordinate negativ ist.

    Richtig ist daher:
    > point = CPoint(GetMessagePos());

    Vielleicht hilft es jemandem. 😉

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

This site uses Akismet to reduce spam. Learn how your comment data is processed.