Wie speichere ich lParam von WM_Notif?

    • Offizieller Beitrag

    Servus.

    Hab eine kleines(großes) Problem mit lparam.

    Ich habe vor lParam das bei WM_NOTIFY zurückgegeben wird in einer Variable abzuspeichen.

    Zitat aus MSDN zu lparam

    Zitat

    A pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this parameter points to a larger structure that has the NMHDR structure as its first member.

    Also soweit ich das jetzt verstanden habe wird ein Pointer auf eine Struct $tagNMHDR zurückgegeben plus zusätzlichen informationen.

    [autoit]

    Global Const $tagNMHDR = "hwnd hWndFrom;int IDFrom;int Code"

    [/autoit]


    $tagNMHDR zu speichern ist kein Problem, diese Daten werden immer zurückgegeben. Wie bekomme ich heraus welche Daten noch zurückgegenen werden?
    Bzw. wie bekomme ich die Datenstructur heraus? Und noch wichtiger wie speichere ich lParam z.b. in einem Array.
    Hab es schon ausprobier, aber ohne Erfolg ein einfaches $Array[$i] = $lParam reicht nicht aus, das Arrayelement hat nicht den gleichen Inhalt wie $lParam.
    Schein daran zu liegen das der Pointer auf $lParam nicht mehr beim abfragen existiert.

    Kann mir jemand helfen?


    Edit: Ich glaub es gibt keine Lösung, die den Verwaltungsaufwand rechtfertigt, deshalb setze ich das ganze mal auf gelöst.

    Danke an alle, die sich den Kopf deshalb zerbrochen haben.

  • Das funktioniert bei WM_Notify über eine Structur (jetzt frag mich aber nicht wieso und weshalb :D)

    [autoit]


    Func _SHLV_WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    ; Prog@ndy
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $tInfo

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

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
    Case $hListView1
    Switch $iCode
    Case $NM_DBLCLK ; Sent by a list-view control when the user double-clicks an item with the left mouse button
    ;Local $ItemText = _GUICtrlListView_GetItemText($hListView1, _GUICtrlListView_GetSelectedIndices($hListView1), 0)
    ;_Browse($ItemText)

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

    Case $LVN_KEYDOWN
    ;Nuts-mod ohne Garantie ;)
    Local $tagLVKEYDOWN = $tagNMHDR & "; USHORT wVKey; UINT flags;"
    $tNMHDR = DllStructCreate($tagLVKEYDOWN, $ilParam)
    Switch DllStructGetData($tNMHDR, "wVKey")
    Case 0x27; rechte Pfeiltaste
    ;Local $ItemText = _GUICtrlListView_GetItemText($hListView1, _GUICtrlListView_GetSelectedIndices($hListView1), 0)
    ;_Browse($ItemText)
    Case 0x25 ;linke Pfeiltaste
    ;_Browseback()
    EndSwitch
    EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
    EndFunc ;==>_SHLV_WM_NOTIFY

    [/autoit]


    Hilft dir das?

    • Offizieller Beitrag

    Das Problem ist das lparam auch weitere Daten, außer die von $tagNMHDR enthalten kann.

    [autoit]

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")

    [/autoit]


    $hwndFrom,$iDFrom und $iCode kann man ja ohne Probleme in einem Array abspeichern.
    $lParam einfach in einem Array speichern funktioniert aber nicht.
    z.B. bei einem Listview kann $lparam auch auf diese Struct angewendet werden:

    [autoit]

    Global Const $tagNMLISTVIEW = $tagNMHDR & ";int Item;int SubItem;int NewState;int OldState;int Changed;" & _
    "int ActionX;int ActionY;int Param"

    [/autoit]
  • Na klar. Siehe mein Zusatz zur Funktion von Progandy.
    Dort werden weitere Infos aus $ilParam geholt (Zeile 17-27).

    Ansonsten hast du ein konkretes Problem dazu? So gut erklären kann ich die halbverstandenen Sachen auch nicht :wacko:

    • Offizieller Beitrag

    Ich will den kompletten Inhalt von $lParam abspeichern. Wenn ich $lParam innerhalb der Funktion abfrage funzt es ja. Aber eben nur dort.
    Im grundegenommen will ich einen Buffer für NM_NOTIFY realisieren. Um den Buffer abzuarbeiten brauche ich aber $lparam (den kompletten Inhalt).

    Der Grundgedanke daran ist es, die auswertende Funktion so schnell wie möglich wieder zu verlassen.
    Die empfangenen Daten werden per Timer abgearbeitet.

    Die Frage ist ob es überhaupt möglich ist den Inhalt von $lParam zu duplizieren. Sobald eine neue Notify ausgelöst wurde ist der Pointer auf $lParam nicht mehr existend.

  • Hm als Variable gehts ja:

    Spoiler anzeigen
    [autoit]


    #include <GUIConstants.au3>
    #include <WindowsConstants.au3>
    ;Globals für die Funktion:

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

    $MainGui = GUICreate("DBClick test", 616, 395, 192, 120)
    ;GUISetBkColor(0x0)

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

    $ListView = GUICtrlCreateListView("Produkt Name", 8, 8, 498, 214);Das ListView mit $LVS_LIST...
    $TestItem = GUICtrlCreateListViewItem("TEST1", $ListView);Test 1
    $TestItem = GUICtrlCreateListViewItem("TEST2", $ListView);Test 2
    $hEdit = GUICtrlCreateInput("edit", 1,300 , 177, 21)
    $hbutton = GUICtrlCreateButton("edit", 150,300 , 177, 21)
    Global $test
    GUISetState(@SW_SHOW)
    GUIRegisterMsg($WM_notify, "_DoubleClickOnListView");Die Funktion wird bei einem Klick auf die GUI aufgerufen!

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    WEnd

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

    Func _DoubleClickOnListView($hWndGUI, $MsgID, $wParam, $lParam);Die Eigentliche Funktion
    Local $tagNMHDR, $event, $hwndFrom, $code
    ;ConsoleWrite( $hWndGUI& @CRLF& $MsgID& @CRLF& $wParam& @CRLF& $lParam& @CRLF)
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3); Checkt wie das EVENT aussieht
    If $wParam = $ListView Then;Wenn der Klick auf das ListView ging..
    If $event = $NM_DBLCLK Then;.. Wenn es ein DoppelKlick war
    ; Hier kommt hin was er machen soll:
    ConsoleWrite("Doppelklick ins Listview " & @CRLF)
    EndIf
    EndIf
    $tagNMHDR = 0
    $event = 0
    $test = $lParam
    _test()
    $lParam = 0
    EndFunc ;==>_DoubleClickOnListView

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

    Func _test()
    local $tagNMHDR = DllStructCreate("int;int;int", $test)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3); Checkt wie das EVENT aussieht
    If $event = $NM_DBLCLK Then;.. Wenn es ein DoppelKlick war
    ; Hier kommt hin was er machen soll:
    ConsoleWrite("Testfunktion" & @CRLF)
    EndIf
    EndFunc

    [/autoit]
    • Offizieller Beitrag

    Das hat aber nichts mit speichern zu tun. Du ruftst die Func Test innerhalb von _DoubleClickOnListView auf. Da existiert der Pointer auf $lParam auch noch. Nach verlassen von _DoubleClickOnListView eben nicht mehr.

  • Du musst auf jeden Fall die Größe der Notify-Struktur wissen (ändert sich ja je nach Event). Dann könntest du sie entweder Binär auslesen und speichern oder alles, was du brauchst, auslesen und speichern.

  • Das hat aber nichts mit speichern zu tun. Du ruftst die Func Test innerhalb von _DoubleClickOnListView auf. Da existiert der Pointer auf $lParam auch noch. Nach verlassen von _DoubleClickOnListView eben nicht mehr.


    Hö? ich speichere $lParam in einer globalen Variable und rufe diese in meiner Testfunktion auf.

    • Offizieller Beitrag

    Wie bekomme ich die Größe der Notify-Struktur heraus? Und wie könnte man das dann auslesen.

  • Ich glaube ich weiss was er vorhat^^
    Der INHALT der aktuellen struct $tagNMHDR soll gespeichert werden, d.h. alle darin enthaltenen Parameter.
    Im Prinzip müßtest du nur eine neue struct erstellen und $tagNMHDR dort hineinkopieren, und den Pointer auf diese (neue) struct in einem Array speichern.
    Die Frage ist nun, wie findest du die für dich relevanten Daten. Nach irgendwas willst/musst du ja suchen. Ggf alle Pointer durchlaufen und die Daten in den gespeicherten structs durchsuchen....

    • Offizieller Beitrag
    Zitat

    Hö? ich speichere $lParam in einer globalen Variable und rufe diese in meiner Testfunktion auf.

    Ich hab dein Script mal umgeschrieben. Beim Doppelklick wird $lparm gespeichert und Test wid in der Hauptschleife abgearbeitet. Ergebnis funzt nicht.

    Spoiler anzeigen
    [autoit]

    #include <GUIConstants.au3>
    #include <WindowsConstants.au3>
    ;Globals für die Funktion:

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

    $MainGui = GUICreate("DBClick test", 616, 395, 192, 120)
    ;GUISetBkColor(0x0)

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

    $ListView = GUICtrlCreateListView("Produkt Name", 8, 8, 498, 214);Das ListView mit $LVS_LIST...
    $TestItem = GUICtrlCreateListViewItem("TEST1", $ListView);Test 1
    $TestItem = GUICtrlCreateListViewItem("TEST2", $ListView);Test 2
    $hEdit = GUICtrlCreateInput("edit", 1,300 , 177, 21)
    $hbutton = GUICtrlCreateButton("edit", 150,300 , 177, 21)
    Global $test ,$set =0
    GUISetState(@SW_SHOW)
    GUIRegisterMsg($WM_notify, "_DoubleClickOnListView");Die Funktion wird bei einem Klick auf die GUI aufgerufen!

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

    While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
    Case $GUI_EVENT_CLOSE
    Exit
    EndSwitch
    If $set = 1 then _Test()
    WEnd

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

    Func _DoubleClickOnListView($hWndGUI, $MsgID, $wParam, $lParam);Die Eigentliche Funktion
    Local $tagNMHDR, $event, $hwndFrom, $code
    ;ConsoleWrite( $hWndGUI& @CRLF& $MsgID& @CRLF& $wParam& @CRLF& $lParam& @CRLF)
    $tagNMHDR = DllStructCreate("int;int;int", $lParam)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3); Checkt wie das EVENT aussieht
    If $wParam = $ListView Then;Wenn der Klick auf das ListView ging..
    If $event = $NM_DBLCLK Then;.. Wenn es ein DoppelKlick war
    $test = $lParam
    $set = 1
    ; Hier kommt hin was er machen soll:
    ConsoleWrite("Doppelklick ins Listview " & @CRLF)
    EndIf
    EndIf
    $tagNMHDR = 0
    $event = 0
    EndFunc ;==>_DoubleClickOnListView

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

    Func _test()
    local $tagNMHDR = DllStructCreate("int;int;int", $test)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3); Checkt wie das EVENT aussieht
    If $event = $NM_DBLCLK Then;.. Wenn es ein DoppelKlick war
    ; Hier kommt hin was er machen soll:
    ConsoleWrite("Testfunktion" & @CRLF)
    EndIf
    EndFunc

    [/autoit]
  • Wie bekomme ich die Größe der Notify-Struktur heraus? Und wie könnte man das dann auslesen.


    Du musst dazu erst mal ein tagNMHDR auf den lParam erstellen. Dann kannst du mit Hilfe des Classnames und des notification Codes die nötige DLLStruct herausfinden (Da musst du aber über Switch bzw Switch das für alle Controls prüfen, die du später abfragen willst. So in etwa stelle ich mir das vor:

    Spoiler anzeigen
    [autoit]

    Func WM_NOTIFY($hWnd, $uMSg, $wParam, $lParam)
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $Class = _WinAPI_GetClassName(DllStructGetData($tNMHDR, "hwndFrom"))
    $Code = DllStructGetData($tNMHDR, "code")

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

    $Struct = $tagNMHDR
    Switch $Class
    Case ...
    Switch $Code ; eventuell, manche Controls haben auch eine Struktur für alle Codes
    Case ...
    $Struct = $tagEBEN_DIE_STRUCT
    EndSwitch
    Case ...
    Switch $Code ; eventuell
    Case ...
    EndSwitch
    ...
    EndSwitch

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

    $Size = DllStructGetSize(DllStructCreate($Struct, $lParam))
    $Size = DllStructGetSize($tNMHDR)

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

    $bInhaltderStruct = DllStructCreate("byte[" & $Size & "]", $lParam)
    _ArrayAdd($_GLOBAL_NOTIFY, $bInhaltderStruct)
    _ArrayAdd($_GLOBAL_NOTIFYSTRUCT, $Struct)
    Return $GUI_RUNDEFMSG
    EndFunc

    [/autoit]

    //Edit: Ich frage mich aber, ob das wirklich schneller ist. Wenn man bei ein paar Events aufwendigeren Code hat, ist es doch genug, dafür eine spezielle Variable einzuführen und nicht die komplette Behandlung auszulagern

    • Offizieller Beitrag

    Ich bin dabei eine UDF für WM_Notify zu erstellen. Darauf hat mich BugFix gebraucht. Per Funktion einzelne Notifys einer Funktion
    zuzuordnen.Ich wollte halt die Notifys buffern um die Hauptfunktion so schnell wie möglich zu verlassen. Das ein Speichern von
    Lparam so ein Problem aufwirft hätte ich jetzt nicht gedacht. Notfalls muß es halt über den direkten Weg eines Funktionsaufruf
    gehen ohne einen Buffer.

    Zitat


    Zitat von »Greenhorn«
    Aber wofür nur ?


    Weil er diese Warteschleife erst dann abarbeiten will, "wenn das Script Zeit dafür hat"

    Du hats es erfaßt :)

  • Weil er diese Warteschleife erst dann abarbeiten will, "wenn das Script Zeit dafür hat"


    Hmm, wie auch immer, es reicht nicht nur die Speicheradresse aus lParam in eine glbale Variable abzulegen, weil die Struktur nicht mehr existiert, wenn Du Test () aufrufst !
    Du musst, wie Progandy bereits anmerkte, die Werte aus der Struktur abspeichern/kopieren.
    Entweder in ein globales Array oder eine globale Struktur !


    Gruß
    Greenhorn


  • Das geht aber auch nur mit WM_NOTIFY-events, da die meistens keinen Rückgabewert brauchen. Es kann jedoch auch Ausnahmen geben, bei denen der Rückgabewert nicht egal ist. Diese lassen sich dann nicht mehr problemlos verarbeiten.