Sign in to follow this  
Followers 0
Logman

Strange problem with events (WM_NOTIFY handling)

7 posts in this topic

#1 ·  Posted (edited)

Hi, I have problem with $NM_DBLCLK handling for ListView. I need three forms:

Form 1 = base form of app

Form 2 = any listview with ListView event handling

Form 3 = viewing details of selected item from Form 2

After double-click on a item in the listview AutoIt crashes! :)

What's wrong with my script? Can somebody help me with this problem?

AutoIt: 3.2.10.0

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>

Global $Form1, $Form2, $Form3
Global $List_View
Global $Result

; MAIN GUI 
    $Form1=GUICreate("FORM 1", 600, 400)
    $Button1=GUICtrlCreateButton("Show form 2", 240, 352, 121, 33, 0)
    $Label1=GUICtrlCreateLabel("Text.....", 16, 16, 332, 17)
    GUISetState(@SW_SHOW,$Form1)
    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; <<<< SET EVENTS
    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop 
            Case $Button1
                _ShowForm2()
        EndSwitch
    WEnd
Exit  

;== SHOW FORM 2 ==============================
Func _ShowForm2()
$Form2=GUICreate("FORM 2", 410, 250)
$Button2=GUICtrlCreateButton("Show form 3", 152, 200, 121, 33, 0)
$List_View=GUICtrlCreateListView("Name", 8, 16, 393, 150)
$item1=GuiCtrlCreateListViewItem("Paul",$List_View)
$item2=GuiCtrlCreateListViewItem("Robert",$List_View)
$item3=GuiCtrlCreateListViewItem("Chris",$List_View)
Local $Label1=GUICtrlCreateLabel("Please, double click on a item...", 16, 170, 200, 17)
GUISetState (@SW_DISABLE, $Form1)
GUISetState(@SW_SHOW,$Form2)
While 1
    $nMsg = GUIGetMsg()
    Select 
        Case $nMsg = $GUI_EVENT_CLOSE
            GUISetState (@SW_ENABLE, $Form1)
            GUIDelete($Form2)
            Return
        Case $nMsg = $Button2
            _ShowForm3() ; test only
    EndSelect
WEnd
EndFunc ;==> SHOW FORM 2 ======================= 

;== SHOW FORM 3 ==============================
Func _ShowForm3()
$Form3=GUICreate("FORM 3", 200, 100)
$Button3=GUICtrlCreateButton("Close", 48, 64, 97, 33, 0)
$Result=GUICtrlCreateLabel("Result:", 16, 16, 100, 17)
GUISetState(@SW_DISABLE,$Form2)
GUISetState(@SW_SHOW,$Form3)
While 1
    $nMsg = GUIGetMsg()
    Select 
        Case $nMsg=$GUI_EVENT_CLOSE Or $nMsg=$Button3
            GUISetState (@SW_ENABLE, $Form2)
            GUIDelete($Form3)
            Return
        Case Else 
    EndSelect
WEnd
EndFunc ;==> SHOW FORM 3 =======================

Func WM_NOTIFY($hWndGUI, $MsgID, $wParam, $lParam)
    #forceref $hWndGUI, $MsgID, $wParam
    Local $tagNMHDR, $event, $hwndFrom, $code
    $tagNMHDR = DllStructCreate("int;int;int", $lParam) ;NMHDR (hwndFrom, idFrom, code)
    If @error Then Return
    $event = DllStructGetData($tagNMHDR, 3)
    Select
    Case $wParam = $List_View
        Select
            Case $event = $NM_DBLCLK ; Crash?
                _ShowForm3() ; + result (in the future)
            EndSelect
    EndSelect
    $tagNMHDR = 0
    $event = 0
    $lParam = 0
EndFunc ;==> WM_Notify_Events
Edited by Logman

Share this post


Link to post
Share on other sites



#2 ·  Posted (edited)

You have all 3 gui's using $nMsg, what happens when you change each function to their own Var like $nMsg1 for $Form2 and $nMsg2 for $Form3?

When using functions, you should really declare variables within the function local if they are only to be used in a local scope.

Edit:

Nah, I even changed that and it crashed still, even after changing up the wm_events... guess I'm too tired to debug:

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>

Global $Form1, $Form2, $Form3
Global $List_View
Global $Result
Global $hForm2

; MAIN GUI
    $Form1=GUICreate("FORM 1", 600, 400)
    $Button1=GUICtrlCreateButton("Show form 2", 240, 352, 121, 33, 0)
    $Label1=GUICtrlCreateLabel("Text.....", 16, 16, 332, 17)
    GUISetState(@SW_SHOW,$Form1)
    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $Button1
                _ShowForm2($Form1)
        EndSwitch
    WEnd
Exit 

;== SHOW FORM 2 ==============================
Func _ShowForm2($hParent)
$Form2=GUICreate("FORM 2", 410, 250, Default, Default, -1, -1, $hParent)
$Button2=GUICtrlCreateButton("Show form 3", 152, 200, 121, 33, 0)
$List_View=GUICtrlCreateListView("Name", 8, 16, 393, 150)
$item1=GuiCtrlCreateListViewItem("Paul",$List_View)
$item2=GuiCtrlCreateListViewItem("Robert",$List_View)
$item3=GuiCtrlCreateListViewItem("Chris",$List_View)
Local $Label1=GUICtrlCreateLabel("Please, double click on a item...", 16, 170, 200, 17)
GUISetState (@SW_DISABLE, $Form1)
GUISetState(@SW_SHOW,$Form2)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; <<<< SET EVENTS
While 1
    $nMsg2 = GUIGetMsg()
    Select
        Case $nMsg2 = $GUI_EVENT_CLOSE
            GUISetState (@SW_ENABLE, $Form1)
            GUIDelete($Form2)
            Return
        Case $nMsg2 = $Button2
            _ShowForm3($Form2) ; test only
    EndSelect
WEnd
EndFunc ;==> SHOW FORM 2 =======================

;== SHOW FORM 3 ==============================
Func _ShowForm3($hParent)
$Form3=GUICreate("FORM 3", 200, 100, Default, Default, -1, -1, $hParent)
$Button3=GUICtrlCreateButton("Close", 48, 64, 97, 33, 0)
$Result=GUICtrlCreateLabel("Result:", 16, 16, 100, 17)
GUISetState(@SW_DISABLE,$Form2)
GUISetState(@SW_SHOW,$Form3)
While 1
    $nMsg3 = GUIGetMsg()
    Select
        Case $nMsg3 = $GUI_EVENT_CLOSE Or $nMsg3 = $Button3
            GUISetState (@SW_ENABLE, $Form2)
            GUIDelete($Form3)
            Return
    EndSelect
WEnd
EndFunc ;==> SHOW FORM 3 =======================
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $iCode, $tNMHDR
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $iCode
        Case $NM_DBLCLK
            _ShowForm3($Form2)
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc
Edited by SmOke_N

Common sense plays a role in the basics of understanding AutoIt... If you're lacking in that, do us all a favor, and step away from the computer.

Share this post


Link to post
Share on other sites

Smoke_N, thanks for your reply. I've tried several times to change the wm_events, but still AutoIt crashes. I find it strange. :)

This code is not working too:

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>

Global $Form1, $Form2, $Form3
Global $List_View
Global $Result
Global $hForm2

; MAIN GUI
    $Form1=GUICreate("FORM 1", 600, 400)
    $Button1=GUICtrlCreateButton("Show form 2", 240, 352, 121, 33, 0)
    $Label1=GUICtrlCreateLabel("Text.....", 16, 16, 332, 17)
    GUISetState(@SW_SHOW,$Form1)
    While 1
        $nMsg = GUIGetMsg()
        Switch $nMsg
            Case $GUI_EVENT_CLOSE
                ExitLoop
            Case $Button1
                _ShowForm2($Form1)
        EndSwitch
    WEnd
Exit

;== SHOW FORM 2 ==============================
Func _ShowForm2($hParent)
$Form2=GUICreate("FORM 2", 410, 250, Default, Default, -1, -1, $hParent)
$Button2=GUICtrlCreateButton("Show form 3", 152, 200, 121, 33, 0)
$List_View=GUICtrlCreateListView("Name", 8, 16, 393, 150)
$item1=GuiCtrlCreateListViewItem("Paul",$List_View)
$item2=GuiCtrlCreateListViewItem("Robert",$List_View)
$item3=GuiCtrlCreateListViewItem("Chris",$List_View)
Local $Label1=GUICtrlCreateLabel("Please, double click on a item...", 16, 170, 200, 17)
GUISetState (@SW_DISABLE, $Form1)
GUISetState(@SW_SHOW,$Form2)
GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; <<<< SET EVENTS
While 1
    $nMsg2 = GUIGetMsg()
    Select
        Case $nMsg2 = $GUI_EVENT_CLOSE
            GUISetState (@SW_ENABLE, $Form1)
            GUIDelete($Form2)
            Return
        Case $nMsg2 = $Button2
            _ShowForm3($Form2) ; test only
    EndSelect
WEnd
EndFunc ;==> SHOW FORM 2 =======================

;== SHOW FORM 3 ================================
Func _ShowForm3($hParent)
$Form3=GUICreate("FORM 3", 200, 100, Default, Default, -1, -1, $hParent)
$Button3=GUICtrlCreateButton("Close", 48, 64, 97, 33, 0)
$Result=GUICtrlCreateLabel("Result:", 16, 16, 100, 17)
GUISetState(@SW_DISABLE,$Form2)
GUISetState(@SW_SHOW,$Form3)
While 1
    $nMsg3 = GUIGetMsg()
    Select
        Case $nMsg3 = $GUI_EVENT_CLOSE Or $nMsg3 = $Button3
            GUISetState (@SW_ENABLE, $Form2)
            GUIDelete($Form3)
            Return
    EndSelect
WEnd
EndFunc ;==> SHOW FORM 3 =======================

;== WM_NOTIFY ==================================
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo
    $hWndListView = $List_View
    If Not IsHWnd($List_View) Then $hWndListView = GUICtrlGetHandle($List_View)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
      Case $hWndListView
            Switch $iCode
                 Case $NM_DBLCLK 
                _ShowForm3($Form2)
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc ;==>WM_NOTIFY ===========================

Share this post


Link to post
Share on other sites

#4 ·  Posted (edited)

Don't run the function from the WM_NOTIFY, just set a flag from there.

You need to return from the WM_NOTIFY as quickly as possible.

#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <ListBoxConstants.au3>
#include <WindowsConstants.au3>

Global $Form1, $Form2, $Form3
Global $List_View, $fLoadForm = False, $hForm2

; MAIN GUI
$Form1 = GUICreate("FORM 1", 600, 400)
$Button1 = GUICtrlCreateButton("Show form 2", 240, 352, 121, 33, 0)
GUICtrlCreateLabel("Text.....", 16, 16, 332, 17)
GUISetState(@SW_SHOW, $Form1)
While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $Button1
            _ShowForm2($Form1)
    EndSwitch
WEnd
Exit

;== SHOW FORM 2 ==============================
Func _ShowForm2($hParent)
    $Form2 = GUICreate("FORM 2", 410, 250, Default, Default, -1, -1, $hParent)
    $Button2 = GUICtrlCreateButton("Show form 3", 152, 200, 121, 33, 0)
    $List_View = GUICtrlCreateListView("Name", 8, 16, 393, 150)
    $item1 = GUICtrlCreateListViewItem("Paul", $List_View)
    $item2 = GUICtrlCreateListViewItem("Robert", $List_View)
    $item3 = GUICtrlCreateListViewItem("Chris", $List_View)
    GUICtrlCreateLabel("Please, double click on a item...", 16, 170, 200, 17)
    GUISetState(@SW_DISABLE, $Form1)
    GUISetState(@SW_SHOW, $Form2)
    GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY") ; <<<< SET EVENTS
    While 1
        $nMsg2 = GUIGetMsg()
        Select
            Case $nMsg2 = $GUI_EVENT_CLOSE
                GUISetState(@SW_ENABLE, $Form1)
                GUIDelete($Form2)
                Return
            Case $nMsg2 = $Button2
                _ShowForm3($Form2) ; test only
            Case Else
                If $fLoadForm Then
                    $fLoadForm = False
                    _ShowForm3($Form2)
                EndIf
        EndSelect
    WEnd
EndFunc   ;==>_ShowForm2

;== SHOW FORM 3 ================================
Func _ShowForm3($hParent)
    $Form3 = GUICreate("FORM 3", 200, 100, Default, Default, -1, -1, $hParent)
    $Button3 = GUICtrlCreateButton("Close", 48, 64, 97, 33, 0)
    GUICtrlCreateLabel("Result:", 16, 16, 100, 17)
    GUISetState(@SW_DISABLE, $Form2)
    GUISetState(@SW_SHOW, $Form3)
    While 1
        $nMsg3 = GUIGetMsg()
        Select
            Case $nMsg3 = $GUI_EVENT_CLOSE Or $nMsg3 = $Button3
                GUISetState(@SW_ENABLE, $Form2)
                GUIDelete($Form3)
                Return
        EndSelect
    WEnd
EndFunc   ;==>_ShowForm3

;== WM_NOTIFY ==================================
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo
    $hWndListView = $List_View
    If Not IsHWnd($List_View) Then $hWndListView = GUICtrlGetHandle($List_View)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $NM_DBLCLK
                    $fLoadForm = True
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
Edited by GaryFrost

SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Share this post


Link to post
Share on other sites

Don't run the function from the WM_NOTIFY, just set a flag from there.

You need to return from the WM_NOTIFY as quickly as possible.

Huh, I think your solution is very simple and this is extremely useful information. You solved my problem, it's works!

Thank you GaryFrost!

Share this post


Link to post
Share on other sites

GaryFrost

Don't run the function from the WM_NOTIFY, just set a flag from there.

You need to return from the WM_NOTIFY as quickly as possible.

Well, but if i need run function from the WM_NOTIFY, possible run function and then exit from function with return?

e.g.:

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo
    $hWndListView = $List_View
    If Not IsHWnd($List_View) Then $hWndListView = GUICtrlGetHandle($List_View)
    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView
            Switch $iCode
                Case $NM_DBLCLK
                    _ShowForm3()
            Return
            EndSwitch
    EndSwitch
    Return $GUI_RUNDEFMSG

Share this post


Link to post
Share on other sites

Think about what this is doing.....

WM_NOTIFY is fired

Function is called from WM_NOTIFY that loads a new form

New form is expecting WM_NOTIFY events but the function hasn't returned to WM_NOTIFY yet and WM_NOTIFY hasn't returned yet.


SciTE for AutoItDirections for Submitting Standard UDFs

 

Don't argue with an idiot; people watching may not be able to tell the difference.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0