Jump to content

Script crashing when using GuiGetMsg() and WM_NOTIFY


idbirch
 Share

Recommended Posts

Hello all, I hope someone can kindly point out what I've done wrong to get my script into this mess. I'm working on a large project which consists of a main GUI which spawns further GUIs for performing various tasks. The main GUI sits in a GuiGetMsg() while loop but I have serious problems when I try and launch a secondary GUI which uses WM_NOTIFY. The notify event works fine but when I try and delete the secondary GUI, the whole thing crashes with a "memory could not be read" error. I'm fairly sure I've broken some cardinal rule of programming but if someone could point it out, I'd be most greatful.

Here's an example script which reproduces the error:

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

Global $ListView_QueryResults, $Form_MuliResults, $SelectedRow

Global $QueryHits = 3
Global $arrQueryResults[3][3]

$arrQueryResults[0][0] = "Computer1"
$arrQueryResults[0][1] = "1111"
$arrQueryResults[0][2] = "07/01/2009  12:24"
$arrQueryResults[1][0] = "Computer1"
$arrQueryResults[1][1] = "2222"
$arrQueryResults[1][2] = "26/02/2009  08:20"
$arrQueryResults[2][0] = "Computer1"
$arrQueryResults[2][1] = "3333"
$arrQueryResults[2][2] = "26/02/2009  08:24"

_ArrayDisplay ( $arrQueryResults, "Dummy return values from an SQL query" )

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("GUI 1", 237, 175, 192, 124)
$Button1 = GUICtrlCreateButton("Button1", 72, 72, 75, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
    $nMsgMainGUI = GUIGetMsg(1)
                                    ;This is the main loop for the master GUI, lots of child windows are created for various other functions
                                    ;but most just create their own GUIGetMsg() loop and break out of that once finished, returning control to
                                    ;this loop.  The problem function is one that requires use of WM_NOTIFY, this crashes the whole script :(
    Select

            Case $nMsgMainGUI[0] = $GUI_EVENT_CLOSE and $nMsgMainGUI[1] = $Form1
                Exit
            Case  $nMsgMainGUI[0] = $Button1 and $nMsgMainGUI[1] = $Form1
                _Function1()

    EndSelect
WEnd

Func _Function1()
    
    If $QueryHits > 1 Then
        
        #Region ### START Koda GUI section ### Form=
        $Form_MuliResults = GUICreate("Multiple results", 419, 289, 288, 270)
        $ListView_QueryResults = _GUICtrlListView_Create($Form_MuliResults, "Asset No|Machine ID|Last Scan Time", 16, 64, 386, 174 )
        _GUICtrlListView_SetExtendedListViewStyle($ListView_QueryResults, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES))
        _GUICtrlListView_SetColumnWidth($ListView_QueryResults, 0, 100)
        _GUICtrlListView_SetColumnWidth($ListView_QueryResults, 1, 100)
        _GUICtrlListView_SetColumnWidth($ListView_QueryResults, 2, 186)
        GUICtrlCreateLabel("There is more than 1 result for your query, double click to choose one", 16, 16, 360, 17)
        _GUICtrlListView_AddArray($ListView_QueryResults, $arrQueryResults )
        GUISwitch ($Form_MuliResults)
        GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
        GUISetState(@SW_SHOW)
        #EndRegion ### END Koda GUI section ###
        
    EndIf
    
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) 
    Local $tNMHDR, $hWndFrom, $iCode

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = DllStructGetData($tNMHDR, "hWndFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
 
    Switch $hWndFrom
        Case $ListView_QueryResults
            Switch $iCode
                Case $NM_DBLCLK
                    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
                    $x = DllStructGetData($tInfo, "Index")
                    $SelectedRow = $x
                    ConsoleWrite ("User double clicked item " & $x & @CRLF)
                    _Function2()                    
            EndSwitch
            
    EndSwitch
     
    Return $GUI_RUNDEFMSG
EndFunc

Func _Function2()
    
    GUIRegisterMsg($WM_NOTIFY, '')  ;Unregister the WMNOTIFY function
    GUIDelete ( $Form_MuliResults ) ;Delete the multi results window as it is no longer needed
    GuiSwitch ( $Form1 )            ;Switch control back to main window

    $MachineIDtoUse = $arrQueryResults[$SelectedRow][1];Grab ID number of machine that was double clicked by user
    $StrScanTime = $arrQueryResults[$SelectedRow][2]    ;Grab scan time of machine that was double clicked by user
    
;Run another SQL query using the machine ID and scan time of the machine that was double clicked by user
    
    GUISetState ( @SW_ENABLE, $Form1 )

EndFunc
Link to comment
Share on other sites

  • Moderators

idbirch,

I am not sure about "cardinal rules", but I can see a problem in your script.

From the ever helpful (because that it why it is there!) Help file on GUIRegisterMessage: "Warning: ... the return to the system should be as fast as possible !!!".

You are running another function inside the WM_Notify function, which I do not think counts as "as fast as possible"! Try using a boolean flag to indicate the click within the WM_Notify function, then look for that flag in your While...WEnd loop and run your other function. I have done that successfully in many scripts.

Here is a modified version of your script which does not crash when I run it (changed lines are marked by : <<<<<<<<<):

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

Global $ListView_QueryResults, $Form_MuliResults, $SelectedRow, $fClicked = False; <<<<<<<<<<<<<<<<<<<<<<<<<<

Global $QueryHits = 3
Global $arrQueryResults[3][3]

$arrQueryResults[0][0] = "Computer1"
$arrQueryResults[0][1] = "1111"
$arrQueryResults[0][2] = "07/01/2009  12:24"
$arrQueryResults[1][0] = "Computer1"
$arrQueryResults[1][1] = "2222"
$arrQueryResults[1][2] = "26/02/2009  08:20"
$arrQueryResults[2][0] = "Computer1"
$arrQueryResults[2][1] = "3333"
$arrQueryResults[2][2] = "26/02/2009  08:24"

_ArrayDisplay ( $arrQueryResults, "Dummy return values from an SQL query" )

#Region ### START Koda GUI section ### Form=
$Form1 = GUICreate("GUI 1", 237, 175, 192, 124)
$Button1 = GUICtrlCreateButton("Button1", 72, 72, 75, 25, 0)
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
    $nMsgMainGUI = GUIGetMsg(1)
                                   ;This is the main loop for the master GUI, lots of child windows are created for various other functions
                                   ;but most just create their own GUIGetMsg() loop and break out of that once finished, returning control to
                                   ;this loop.  The problem function is one that requires use of WM_NOTIFY, this crashes the whole script :(
    Select

            Case $nMsgMainGUI[0] = $GUI_EVENT_CLOSE and $nMsgMainGUI[1] = $Form1
                Exit
            Case  $nMsgMainGUI[0] = $Button1 and $nMsgMainGUI[1] = $Form1
                _Function1()

    EndSelect

    If $fClicked = True Then _Function2() ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

WEnd

Func _Function1()
    
    If $QueryHits > 1 Then
        
        #Region ### START Koda GUI section ### Form=
        $Form_MuliResults = GUICreate("Multiple results", 419, 289, 288, 270)
        $ListView_QueryResults = _GUICtrlListView_Create($Form_MuliResults, "Asset No|Machine ID|Last Scan Time", 16, 64, 386, 174 )
        _GUICtrlListView_SetExtendedListViewStyle($ListView_QueryResults, BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT, $LVS_EX_SUBITEMIMAGES))
        _GUICtrlListView_SetColumnWidth($ListView_QueryResults, 0, 100)
        _GUICtrlListView_SetColumnWidth($ListView_QueryResults, 1, 100)
        _GUICtrlListView_SetColumnWidth($ListView_QueryResults, 2, 186)
        GUICtrlCreateLabel("There is more than 1 result for your query, double click to choose one", 16, 16, 360, 17)
        _GUICtrlListView_AddArray($ListView_QueryResults, $arrQueryResults )
        GUISwitch ($Form_MuliResults)
        $fClicked = False ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
        GUISetState(@SW_SHOW)
        #EndRegion ### END Koda GUI section ###
        
    EndIf
    
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam) 
    Local $tNMHDR, $hWndFrom, $iCode

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

    Switch $hWndFrom
        Case $ListView_QueryResults
            Switch $iCode
                Case $NM_DBLCLK
                    $tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
                    $x = DllStructGetData($tInfo, "Index")
                    $SelectedRow = $x
                    ConsoleWrite ("User double clicked item " & $x & @CRLF)
                   ;_Function2() ; <<<<<<<<<<<<<<<<<<<<<<<<               
                    $fClicked = True ; <<<<<<<<<<<<<<<<<<<<<<<
            EndSwitch
            
    EndSwitch
     
    Return $GUI_RUNDEFMSG
EndFunc

Func _Function2()
    
    $fClicked = False ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    GUIRegisterMsg($WM_NOTIFY, '')   ;Unregister the WMNOTIFY function
    GUIDelete ( $Form_MuliResults )   ;Delete the multi results window as it is no longer needed
    GuiSwitch ( $Form1 )           ;Switch control back to main window

    $MachineIDtoUse = $arrQueryResults[$SelectedRow][1];Grab ID number of machine that was double clicked by user
    $StrScanTime = $arrQueryResults[$SelectedRow][2]   ;Grab scan time of machine that was double clicked by user
    
;Run another SQL query using the machine ID and scan time of the machine that was double clicked by user
    
    GUISetState ( @SW_ENABLE, $Form1 )

EndFunc

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

M23, you are a prince among men :P I thank you. I did read the GUIRegisterMsg portion of the help file but didn't appreciate that then length of time Function2 took to run was contravening the undefined time limit so thanks very much for pointing it out and for getting me to use boolean for the first time in over 10,000 lines of code!

I incorporated the method you demonstrated in my project and it works brilliantly, thanks again for your help.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...