Frage zu einem Befehl

  • Hallo,
    ich habe da mal eine Frage zum „GUIRegisterMsg“-Befehl.

    Ich habe ein Script, in dem ist die Windows-Message „$WM_NOTIFY“, mit dem Befehl
    “GUIRegisterMsg($WM_NOTIFY, "WM_Notify_Events")”,
    auf die Funktion “WM_Notify_Events” registriert.

    Nun rufe ich in dem Script eine weitere Funktion zur Ordnerauswahl auf und die registriert
    die Windows-Message „$WM_NOTIFY“ mit dem Befehl:
    GUIRegisterMsg($WM_NOTIFY, "__WM_NOTIFY")
    auf eine andere Funktion.


    Wenn diese Funktion zum eigentlichen Script zurückkehrt (mit RETURN und dem ausgewählten Pfad), funktioniert das Script natürlich nicht mehr.

    Es funktioniert erst wieder, nachdem ich die Windows-Message „$WM_NOTIFY“, wieder auf die Funktion „WM_Notify_Events“ registriere.

    Nun die Frage:
    Kann man irgendwie abfragen, auf welche Funktion eine Windows-Message registriert ist ?

    Wenn man die damit, beim Funktionsaufruf (die Ordnerauswahl) die ursprüngliche Registrierung ermitteln und speichern würde, und diese Registrierung am Ende wiederherstellen würde, so müsste das ganze auch funktionieren.

    Ich weiß, mein Post sieht etwas sehr sonderbar aus, aber leider funktioniert bei mir das ganze mit Editieren und Formatieren usw. nicht. (Browser: Opera 12.16)

    Auch den Post zuerst in MS-Word schreiben und dann hier rein kopieren, geht nicht.

    MfG:
    BigRox

    • Offizieller Beitrag

    Mehrere Funktionen für die gleiche Message ist kokolores.
    Man kann die beiden Funktionen zusammenfassen. Wenn du dein Script postest, kann man dir dabei helfen.

  • Hi,
    du musst doch lediglich die einzelnen Events innerhalb der Funktion WM_Notyfy_Events() abarbeiten.


    AutoIt
    Func WM_NOTIFY($hWndGUI, $MsgID, $wParam, $lParam) 
       If event_x_param then  ;
          bla...
        If event_y_param then  ;
          blub...
        If event_z_param then  ;
           bla...
    endfunc

    Schau dir mal in der Hilfe die einzelnen Events an, dazu in der Suche *WM_NOTIFY* eingeben und unten "Ähnliche Wörter suchen" anhaken. Sämtliche dieser Funktionen könnte man in EINE Func WM_NOTIFY($hWndGUI, $MsgID, $wParam, $lParam) packen!

  • Hallo Andy,
    irgendwie verstehe ich das mit den Windows Messages anscheinend nicht so richtig.

    Ich brauche wohl nur die damit verknüpfte Funktion, mit "GUIRegisterMsg" anzugeben und die vier Parameter (hWnd, Msg...)
    kommen von Windows, damit die Funktion "weiß", was in welchem Fenster passiert ist und darauf auch richtig reagieren kann.

    Mit dem von dir geposteten Beispiel, könnte ich also nach dem Funktionsaufruf zuerst mal abfragen, ob z.B. die Nachricht auch in dem richtigen Fenster aufgetreten ist und erst dann die restliche Funktion ausführen.
    Und wenn es das falsche Fenster ist, wird die Funktion einfach nicht ausgeführt.

    Nur das Problem ist dabei, die Message muss erstmal auftreten, damit die Abfrage des Fensters auch stattfindet.
    Und genau dass ist mein Problem.

    Ich möchte den Namen der verknüpften Funktion ermitteln ohne das die Funktion zuerst mal aufgerufen wird.

    So etwas wie: $Name = GetGUIRegisterMsg($WM_NOTIFY) und zurückgegeben wird mir der Name der Funktion.


    @Raupi
    Das ganze Scrip umfasst etwa 3000 Zeilen und massenweise Includes.
    Die Funktion zur Ordnerauswahl wird auch in einigen anderen Scripten verwendet und kann somit nicht so einfach mit einer anderen Funktion zusammengefasst werden, da ich sie eben universell verwendbar halten möchte.
    Das mehrere Funktionen für die gleiche Message nicht so gut funktioniert, kann ich mir schon vorstellen (der PC kann ja auch nicht hellsehen :D ) und deshalb versuch ich genau das irgendwie zu verhindern.
    Mit ein Paar Befehlen im eigentlichen Script, geht es auch (vorm Funktionsaufruf um registrieren und danach wieder zurück), nur dann ist es auch nur eine Frage der Zeit, wann ich wieder genau das Problem haben werde.


    Komisch, heute funktioniert das mit Editieren usw. wieder, vielleicht lag an einem Cookie, die habe ich nämlich vorher mal gelöscht(ich konnte mich sonst nicht mehr anmelden).


    MfG:
    BigRox

    • Offizieller Beitrag

    So etwas wie: $Name = GetGUIRegisterMsg($WM_NOTIFY) und zurückgegeben wird mir der Name der Funktion.

    Verstehe ich nicht! DU legst doch fest, mit welcher Funktion du die Message verknüpfst. Und das kann NUR EINE sein.
    Anders sieht es aus, wenn du z.B. fertige Skripte einbindest, die ihrerseits schon mit GuiRegisterMessage arbeiten. In diesem Fall kannst du GuiRegisterMsg NICHT benutzen (da ja nur eine Funktion mit einer Message verknüpft werden kann). Um dennoch die Messages auswerten zu können musst du diese auswerten BEVOR Windows sie selbst im System verwertet. Das nennt sich Hook.
    Hier ein Bsp. wie das lösbar ist:

  • Hallo BugFix,

    Anders sieht es aus, wenn du z.B. fertige Skripte einbindest, die ihrerseits schon mit GuiRegisterMessage arbeiten. In diesem Fall kannst du GuiRegisterMsg NICHT benutzen (da ja nur eine Funktion mit einer Message verknüpft werden kann).

    Genau, dass ist mein Problem. Ich binde ein fertiges Script ein, das auch mit der Windows-Message $WM_NOTIFY arbeitet.
    Wenn ich das ganze., bis jetzt, richtig verstanden habe, müsste das erste Script doch irgendwie Windows mitteilen, wohin es die angegebene
    Message weiterleiten soll.

    Das erste Script sagt Windows also ungefähr: "Wenn die Nachricht $WM_NOTIFY auftritt, dann her damit, da warte ich nämlich schon drauf".

    Sobald im ersten Script der Befehl "GUIRegisterMsg(...)" erfolgreich ausgeführt wurde, müsste doch irgendwo auch etwas stehen.
    Und genau dies müsste man eigentlich auch abfragen können und zwar, bevor die Windows-Message überhaupt mal aufgetreten ist.


    MfG:
    BigRox

    • Offizieller Beitrag

    Wenn ich das ganze., bis jetzt, richtig verstanden habe, müsste das erste Script doch irgendwie Windows mitteilen, wohin es die angegebene
    Message weiterleiten soll

    Nein, das Skript, welches bereits die Message registriert hat, nutzt diese wie gehabt.
    In deinem anderen Skript greifst du auf die Message ja bereits zu BEVOR die registrierte Funktion des anderen Skripts überhaupt die Msg erhält. Deshalb der Hook:
    - MSG tritt auf
    - eigene Prozedur (_WinProc) wertet die MSG aus und gibt sie dann mittels Standard-Windows-Procedure wieder an das System
    - das System gibt jetzt die Nachricht an die Funktion, die diese MSG mit GuiRegisterMsg gebunden hat
    - diese Funktion verwertet nun ihrerseits die Nachricht

    Unbedingt darauf achten, dass du Nachrichten, die im anderen Skript registriert sind, auch wieder über die Standardprozedur weitergibst und nicht verwirfst. Mein Bsp. zeigt ja genau, wie das zu handhaben ist.

    • Offizieller Beitrag

    Es gibt noch eine einfachere Möglichkeit. In der Funktion, welche per GuiRegisterMsg angegeben ist, im Hauptscript, ruft man die Funktion der UDF auf.
    In der UDF einfach den GUIRegisterMsg Befehl auskommentieren. Aber es ist halt Geschmackssache wie man es regelt.

  • Ich binde ein fertiges Script ein, das auch mit der Windows-Message $WM_NOTIFY arbeitet.

    Naja, so ist das eben mit der Programmiererei, ab und zu braucht man etwas mehr als Copy&Paste dafür!

    Du hast jetzt mehrere Möglichkeiten aufgezeigt bekommen, ich allerdings würde trotzdem sämtliche $WM_NOTIFY-Events in EINER Funktion abwickeln. Damit wird das Debugging einfach und sämtliche Auswertungen beschränken sich auf eine Funktion.
    Weiterhin ist völlig irrelevant, in welcher Reihenfolge die Events in der Queue stehen, die werden von Windows nacheinander an die für $WM_NOTIFY registrierte Funktion weitergegeben, diese wird also auch ggf. mehrmals nacheinander aufgerufen!

  • Hallo,
    ich habe da mal wieder eine Frage zu der Sache.

    Was ist eigentlich der "AutoIt-interne Message-Handler" der im Beispiel mit:


    "Return $GUI_RUNDEFMSG"

    aufgerufen wird ?
    Die Registrierung der Nachricht bleibt doch bestehen und die registrierte Funktion wird wieder aufgerufen, wenn die Nachricht nochmals erscheint.
    Was sind den diese "Autoit3 internal message commands" ?
    Oder setzt man damit alles wieder sauber auf Start, falls die Nachricht doch nicht von der Funktion verarbeitet werden konnte.

    MfG:
    BigRox

  • Normalerweise werden sämtliche Messages jedes Control sowie Window intern von AutoIt verwaltet. Hast du dich nicht mal gefragt wieso wir so schön mit GUICreate() und GUISetState() (2 Zeilen Code) eine GUI erzeugen und anzeigen können? In C++ sind da schon geschätzte 50 Zeilen notwendig. Normalerweise musst du eine Klasse via _WinAPI_RegisterClass() registrieren und dann das Fenster mithilfe von _WinAPI_CreateWindowsEx() erzeugen. Aber damit es nicht noch genug wäre fehlt natürlich noch WndProc Funktion die alle Windows Messages abfängt und behandelt, vom Schließen der GUI bis hin zum minimieren etc.

    Lustigerweise ist das aber auch bei Controls so, für jedes Control musst du eine Klasse registrieren und dann das Control erstellen. Das ist sehr aufwendig, dh. regeln das AutoIt intern was es erst ermöglicht diesen ganzen Mist zu ignorieren bzw. erst gar nicht kennen zu müssen. Wenn man jedoch nun selber anfängt Messages abzufangen pfuscht man da quasi AutoIt dazwischen, nun hat man 2 Optionen: Man führt NUR seine eigene Message aus oder führt im Anschluss (welches das Standardverhalten entspricht) noch ZUSÄTZLICH die interne Funktion aus. Dazu muss lediglich die Konstante $GUI_RUNDEFMSG zurückgegeben werden. Man kann also alles selber implantieren oder nur Teile umschreiben bzw. erweitern was einem für das Standardverhalten fehlt.

    LG. Make :)

  • Hallo Make-Grafik,
    Danke für die Erklärung :thumbup: .

    Damit "räumt" man also alles wieder schön auf, wenn die Message bearbeitet wurde.
    Entweder man macht es selber, oder man lässt es mit "Return $GUI_RUNDEFMSG" machen.

    Und das ist dann einfach auch ein sauberer Programmierstiel, da man damit schon mal eine Fehlerquelle ausschließt.
    (so etwa, wie mit sauberer Variabledeklaration, es geht zwar auch ohne, aber mit geht es viel besser).

    Das mit C++ kenne ich auch, ein Bekannter von mir macht damit rum.
    Schöne, schnelle Programme schreiben, dass ist kein Problem für den, aber wenn es um die GUI'*s dafür geht, dann verzweifelt der daran.
    Ich habe dem schon oft gesagt, er solle sich doch mal eine andere Programmiersprache nur zum erstellen der GUI's suchen und versuchen diese GUI's in C++ einzubinden (mit AutoIt erstellte GUI's müsste man doch auch in C++ einbinden können). Aber dafür hat der anscheinend keine Lust, dann muss er sich halt weiter mit C++ und GUI's rumärgern :D .

    MfG:
    BigRox

  • Ne, so schwer ist das auch nicht, es ist nur aufwendiger. ^^
    AutoIt regelt das glücklicherweise echt so entspannend, durch die GUI Funktionen ist AutoIt dh. Ein mächtiges Werkzeug um Benutzeroberflächen schnell & einfach zu Designen sowie zu verwalten. Aber wenn man den Bogen erst einmal raus hat, ist das auch mithilfe der WinAPI auch selber in jeder Programmiersprache gelöst. Es sind eben nur mehr Zeilen Code und deutlich mehr Verwaltungsaufwand. Vieles worum man sich selbst kümmern muss. Ich habe mal hier ein Beispielcode geschrieben welcher dies (so glaube ich) ganz gut zeigt. Es geht um eine einfache simple GUI welche in fast jeder Hochsprache auf diese Weise umgesetzt werden muss. (Da ist man manchmal echt froh über die GUI Funktionen in AutoIt ^^ )

    Spoiler anzeigen
    [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    #include <ButtonConstants.au3>
    #include <WinAPIEx.au3>
    #include <WindowsConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $g_esClassName = 'MyWindowClass'
    Global $g_hWndProc = DllCallbackRegister('__WndProc__', 'lresult', 'hwnd;uint;wparam;lparam')
    Global $g_hInstance = _WinAPI_GetModuleHandle(Null)
    Global $g_bExit = False
    Global $g_hWindow, $g_hButtonA, $g_hButtonB, $g_hButtonC, $g_hButtonD

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    ; Eine WNDCLASSEX erstellen und füllen
    ; Ref.: https://msdn.microsoft.com/de-de/library/…7(v=vs.85).aspx
    Global $g_tWndClass = DllStructCreate($tagWNDCLASSEX & ';wchar szClassName[' & (StringLen($g_esClassName) + 1) & ']')
    With $g_tWndClass
    .Size = DllStructGetPtr($g_tWndClass, 'szClassName') - DllStructGetPtr($g_tWndClass)
    .Style = 0
    .hWndProc = DllCallbackGetPtr($g_hWndProc)
    .ClsExtra = 0
    .WndExtra = 0
    .hInstance = $g_hInstance
    .hIcon = _WinAPI_LoadIcon(Null, 32512) ; IDC_APPLICATION
    .hCursor = _WinAPI_LoadCursor(Null, 32512) ; IDC_ARROW
    .hBackground = $COLOR_WINDOW
    .MenuName = Null
    .ClassName = DllStructGetPtr($g_tWndClass, 'szClassName')
    .hIconSm = Null
    .szClassName = $g_esClassName
    EndWith

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_RegisterClassEx($g_tWndClass)

    [/autoit] [autoit][/autoit] [autoit]

    ; Fenster und Button erstellen
    $g_hWindow = _WinAPI_CreateWindowEx(0, $g_esClassName, 'My Window Example', BitOR($WS_CAPTION, $WS_POPUPWINDOW), (@DesktopWidth - 240) / 2, (@DesktopHeight - 260) / 2, 240, 260, 0)
    $g_hButtonA = _WinAPI_CreateWindowEx(0, 'BUTTON', 'A', BitOR($WS_TABSTOP, $WS_VISIBLE, $WS_CHILD, $BS_DEFPUSHBUTTON), 10, 10, 100, 100, $g_hWindow)
    $g_hButtonB = _WinAPI_CreateWindowEx(0, 'BUTTON', 'B', BitOR($WS_TABSTOP, $WS_VISIBLE, $WS_CHILD, $BS_DEFPUSHBUTTON), 120, 10, 100, 100, $g_hWindow)
    $g_hButtonC = _WinAPI_CreateWindowEx(0, 'BUTTON', 'C', BitOR($WS_TABSTOP, $WS_VISIBLE, $WS_CHILD, $BS_DEFPUSHBUTTON), 10, 120, 100, 100, $g_hWindow)
    $g_hButtonD = _WinAPI_CreateWindowEx(0, 'BUTTON', 'D', BitOR($WS_TABSTOP, $WS_VISIBLE, $WS_CHILD, $BS_DEFPUSHBUTTON), 120, 120, 100, 100, $g_hWindow)

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_ShowWindow($g_hWindow)

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    While Sleep(10) And Not $g_bExit
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_DestroyCursor($g_tWndClass.hCursor)
    _WinAPI_DestroyIcon($g_tWndClass.hIcon)
    _WinAPI_UnregisterClass($g_esClassName, $g_hInstance)
    DllCallbackFree($g_hWndProc)

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit] [autoit][/autoit] [autoit]

    ; Windows Prozedur
    ; Ref.: https://msdn.microsoft.com/de-de/library/…3(v=vs.85).aspx
    Func __WndProc__($hWnd, $iMsg, $wParam, $lParam)
    Switch $iMsg
    Case $WM_CLOSE
    $g_bExit = True
    Case $WM_COMMAND ; Ref.: https://msdn.microsoft.com/en-us/library/…1(v=vs.85).aspx
    Switch $lParam
    Case $g_hButtonA
    MsgBox(0, 'CLICKED', 'Button A', 0, $g_hWindow)
    Case $g_hButtonB
    MsgBox(0, 'CLICKED', 'Button B', 0, $g_hWindow)
    Case $g_hButtonC
    MsgBox(0, 'CLICKED', 'Button C', 0, $g_hWindow)
    Case $g_hButtonD
    MsgBox(0, 'CLICKED', 'Button D', 0, $g_hWindow)
    EndSwitch
    EndSwitch

    [/autoit] [autoit][/autoit] [autoit]

    ; $GUI_RUNDEFMSG
    Return _WinAPI_DefWindowProcW($hWnd, $iMsg, $wParam, $lParam)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit]

    Einmal editiert, zuletzt von Yjuq (27. April 2015 um 22:20)