Jump to content

DllCallbacks and GUI freeze


Homes32
 Share

Recommended Posts

Hi all,

I am developing a gui app that captures a wim image using a DllCall to wimgapi.dll; the capture process uses a callback to notify my app on the progress of the capture and update the progressbar as appropriate.

my issue arises during the capture if the you try to interact with the GUI (ie. click on the window/a control/etc) the window will freeze and not update any controls, as well as trigger windows to flag the window as "(Not Responding)". and will cease to update the gui until the end of the capture process.

I have tried putting GUIGetMsg() inside my callback to force the window to be polled for events, but it does not help.

does anybody have any suggestions or explanations on how to correct this issue?

my callback fuction looks like this:

Func CallBack($msgId, $param1, $param2, $<img src='http://www.autoitscript.com/forum/public/style_emoticons/<#EMO_DIR#>/cool.png' class='bbc_emoticon' alt='B)' />
    Switch $msgId
        Case $WIM_MSG_PROGRESS ; get progress % and time remaining
            $Percent = $param1

            If $param2 = 0 Then
                $rTime = ""
            Else
                $rTime = StringFormat('Remaining: %i sec.', $param2 / 1000)
            EndIf

        Case $WIM_MSG_PROCESS ; get the file name being processed
            $Str = DllStructCreate('ushort[1024]', $param1)
            $filePath = ''
            $i = 1
            While 1
                $Tmp = DllStructGetData($Str, 1, $i)
                If $Tmp = 0 Then ExitLoop
                $filePath &= ChrW($Tmp)
                $i += 1
            WEnd

        Case $WIM_MSG_STEPIT ; Total files processed so far

            $FilesProcessed += 1

        Case $WIM_MSG_SETRANGE ; Total number of files to process

            If $param2 = 0 Then
                $FilesTotal = ''
            Else
                $FilesTotal = $param2
            EndIf

    EndSwitch

    ;ProgressSet($Percent, StringFormat('%3i%% completed.      %s\n\n   %s', $Percent, $rTime, _StringRightStr($filePath, '\', -1)), 'Capture ' & _StringRightStr($sWimFile, '\', -1))
    ;GUICtrlSetData($LBL_Processing,"Processing: " & _StringRightStr($filePath, '\', -1))
    ControlSetText($FRM_Progress, "", $LBL_Processing,"Processing: " & _StringRightStr($filePath, '\', -1))
    WinSetTitle($FRM_Progress, "", $ProgramName & " - " & $Percent & "% complete")

    GUICtrlSetData($PB_Progress, $Percent)
    ControlSetText($FRM_Progress, "", $LBL_TRemain, $rTime)
    ControlSetText($FRM_Progress, "", $LBL_Files, "Files: " & $FilesProcessed & "/" & $FilesTotal)

    Return $WIM_MSG_SUCCESS

EndFunc   ;==>CallBack

thanks,

Homes32

Edited by Homes32
Link to comment
Share on other sites

You can't correct it. It's the limitation of the current callback implementation.

You can minimize the negative effect by smarter coding. Unfortunately, the code you posted is unreadable to help you further.

edit:

ok, you corrected the code tags in the mean time. Will see now.

... except for that WIM_MSG_PROCESS that loops unnecessary, all looks fine. Maybe it wold be better to call lstrlenW and make wchar buffer then and do just one reading. Also should you process lparam ($B ) for this message?

Edited by trancexx

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

You can't correct it. It's the limitation of the current callback implementation.

I was afraid it was something like that.

quite annoying as it pretty much make the GUI useless when even switching to another window to do something while the capture is running will freeze the progress GUI. people tend to develop an annoying habit of immediately trying to kill off any process they think is hung more than 30 sec. much less 2-4 minutes to capture a .wim :)

... except for that WIM_MSG_PROCESS that loops unnecessary, all looks fine. Maybe it wold be better to call lstrlenW and make wchar buffer then and do just one reading. Also should you process lparam ($B ) for this message?

I'll play around with this idea and see if I can't make it work. I'm pretty new to the whole struct business...

thanks for the reply.

regards,

Homes32

Link to comment
Share on other sites

Maybe you should try this: remove all ControlSetText from the loop, set the data to global variables and then use AdlibRegsiter with an interval of 500ms to update the labels or so. Make only the absolutely necessary things in the callback.

Global $giWIM_PERCENT, $giWIM_TIME, $gsWIM_FILE, $giWIM_FILES_PROCESSED, $giWIM_FILES_TOTAL

Func CallBack($msgId, $param1, $param2, $B)
    Switch $msgId
        Case $WIM_MSG_PROGRESS ; get progress % and time remaining
            $giWIM_PERCENT = $param1
            $giWIM_TIME = $param2

        Case $WIM_MSG_PROCESS ; get the file name being processed
            Local $aLen = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $param1)
            If Not @error Then
                Local $tData = DllStructCreate("wchar[" & $aLen[0] & "]")
                $gsWIM_FILE = DllStructGetData($tData, 1)
            EndIf

        Case $WIM_MSG_STEPIT ; Total files processed so far

            $giWIM_FILES_PROGRESSED += 1

        Case $WIM_MSG_SETRANGE ; Total number of files to process
            $giWIM_FILES_TOTAL = $param2
    EndSwitch
    Return $WIM_MSG_SUCCESS

EndFunc   ;==>CallBack

Func _UpdateLabels() ; Function for adlib
    ; Update labels here
EndFunc

Or write a DLL that implements the callback.

PS: How does that DLLCall to wimimg.dll work? If it blocks the script until it is finished you can ignore the content of this post. Then you will have to live with the current behaviour or create a DLL which starts a thread and then in this thread starts the capture.

Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

Maybe you should try this: remove all ControlSetText from the loop, set the data to global variables and then use AdlibRegsiter with an interval of 500ms to update the labels or so. Make only the absolutely necessary things in the callback.

Global $giWIM_PERCENT, $giWIM_TIME, $gsWIM_FILE, $giWIM_FILES_PROCESSED, $giWIM_FILES_TOTAL

Func CallBack($msgId, $param1, $param2, $B)
    Switch $msgId
        Case $WIM_MSG_PROGRESS ; get progress % and time remaining
            $giWIM_PERCENT = $param1
            $giWIM_TIME = $param2

        Case $WIM_MSG_PROCESS ; get the file name being processed
            Local $aLen = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $param1)
            If Not @error Then
                Local $tData = DllStructCreate("wchar[" & $aLen[0] & "]")
                $gsWIM_FILE = DllStructGetData($tData, 1)
            EndIf

        Case $WIM_MSG_STEPIT ; Total files processed so far

            $giWIM_FILES_PROGRESSED += 1

        Case $WIM_MSG_SETRANGE ; Total number of files to process
            $giWIM_FILES_TOTAL = $param2
    EndSwitch
    Return $WIM_MSG_SUCCESS

EndFunc   ;==>CallBack

Func _UpdateLabels() ; Function for adlib
    ; Update labels here
EndFunc

Or write a DLL that implements the callback.

PS: How does that DLLCall to wimimg.dll work? If it blocks the script until it is finished you can ignore the content of this post. Then you will have to live with the current behaviour or create a DLL which starts a thread and then in this thread starts the capture.

yeah. WIMCaptureImge is a blocking function and uses the callback to relay information.

I tried using

Case $WIM_MSG_PROCESS ; get the file name being processed
            Local $aLen = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $param1)
            If Not @error Then
                Local $tData = DllStructCreate("wchar[" & $aLen[0] & "]")
                $gsWIM_FILE = DllStructGetData($tData, 1)
            EndIf
but $aLen returns NULL so I can't get the filename. :)

m$ sample implantation is:

//
//Callback function:
//
DWORD
WINAPI
SampleCaptureCallback(
    IN      DWORD msgId,    //message ID
    IN      WPARAM param1,   //usually file name
    INOUT   LPARAM param2,   //usually error code
    IN      void  *unused
    )
{
    //First parameter: full file path for if WIM_MSG_PROCESS, message string for others
    TCHAR *message  = (TCHAR *) param1;
    TCHAR *filePath = (TCHAR *) param1;
    DWORD percent   = (DWORD)   param1;

    //Second parameter: message back to caller if WIM_MSG_PROCESS, error code for others
    DWORD errorCode = param2;
    DWORD *msg_back = (DWORD *) param2;


    switch ( msgId )
    {
        case WIM_MSG_PROCESS:

            //This message is sent for each file, capturing to see if callee intends to
            //capture the file or not.
            //
            //If you do not intend to capture this file, then assign FALSE in msg_back
            //and still return WIM_MSG_SUCCESS.
            //Default is TRUE.
            //

            //In this example, print out the file name being applied
            //
            _tprintf(TEXT("FilePath: %s\n"), filePath);

            break;

...
Link to comment
Share on other sites

Couldn't you have another script which calls the dll and run that script when you want the capture. It can have a small window which is never shown. In the callback of the extra script it can send a message to the main script with the update information. Then the main script won't freeze and it can still show the progress.

Edited by martin
Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

Couldn't you have another script which calls the dll and run that script when you want the capture. It can have a small window which is never shown. In the callback of the extra script it can send a message to the main script with the update information. Then the main script won't freeze and it can still show the progress.

thats an interesting thought...I'll have to play around with the idea.
Link to comment
Share on other sites

When you do, you'll see that it's not. ProgAndy's is.

I don't doubt you're right trancexx but I expected that if there is a call back then the callback function could send a message to another script before it returned. Why couldn't that be done?

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

And the purpose of the dll in that case would be?

The same as before. I imagined that the script calls a function in the dll and that dll function calls the callback function and passes back information on the progress but the gui freezes. So, assuming the callback works and information is passed back on the progress (I understood from the first post that it did) then if another script calls the dll function instead then the gui won't be frozen and the update information could be passed. Hopefully in that you will understand my faulty logic and explain it to me.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
Link to comment
Share on other sites

The same as before. I imagined that the script calls a function in the dll and that dll function calls the callback function and passes back information on the progress but the gui freezes. So, assuming the callback works and information is passed back on the progress (I understood from the first post that it did) then if another script calls the dll function instead then the gui won't be frozen and the update information could be passed. Hopefully in that you will understand my faulty logic and explain it to me.

No, that's fine. I misunderstood you previously.

♡♡♡

.

eMyvnE

Link to comment
Share on other sites

No, that's fine. I misunderstood you previously.

ok.

Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.
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...