dcsimg
Results 1 to 25 of 25

Thread: Stop a complex long running process reliably

  1. #1

    Thread Starter
    New Member
    Join Date
    May 2019
    Posts
    13

    Stop a complex long running process reliably

    I have an extremely complex and long running process (a complex algorithm) with hundreds of loops, nested loops, recursions, data structures, file processing, multiple threads using user controls, etc. The algorithm is decided into many multiple steps with separate functions and sub procedures for better maintenance, all work towards generating the final output at the end. The algorithm contains thousands of lines of code, where I am extremely happy about overall performance of it.

    The user is provided an interface with multiple configuration and a process button. When the user clicks on process button once the initial configuration is done, algorithm starts running.

    What I need to have is a reliable way to instantly stop this complex process at any stage, when the user clicks on a Stop button resetting all its memory utilization, CPU consumption and come back to the idle stage. I know I might try to set a flag and check for it, but do not know whether it will be really success. Any idea Please.

  2. #2
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    5,661

    Re: Stop a complex long running process reliably

    There are a few places where I do this as well. In my case, I do them on the single VB6 thread available to me.

    When I do this, I make sure I "lock down" all user interface except for a Cancel button. And then, in critical places in the long running process, I place DoEvents statements. I also have a global cancel variable, possibly named something like gbCancel. I set gbCancel=False when the long process starts, and check it immediately after each DoEvents execution.

    The Cancel button does one single thing ... it sets gbCancel=True. If my long running process detects that gbCancel goes True, it then somehow jumps to whatever cleanup code needs to be executed, and returns to the caller. The caller might also need to check the gbCancel variable to see if the long running process was successfully completed (or, there may be some other variable to indicate this).

    ----------------

    Another thing that comes to mind is the possibility of an out-of-process ActiveX EXE. This is an easy way to get access to a second thread for the purposes of running your long process. If it's appropriate, this would allow your primary application to keep running while the long process is taking place. There are other multi-threading alternatives found in the CodeBank, but I've never been entirely happy with any of them, and an out-of-process ActiveX EXE works just fine.

    Also, if you used this out-of-process ActiveX EXE approach, you'd still need to work out communications between your primary application and the ActiveX EXE, and they may also handle the cancelling in a similar way.

    ---------------

    Maybe those thoughts will help you.

    Good Luck,
    Elroy
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  3. #3
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    I've been feeling a bit guilty about using DoEvents, so it's nice to see someone well thought of, using it.

  4. #4
    PowerPoster techgnome's Avatar
    Join Date
    May 2002
    Posts
    32,401

    Re: Stop a complex long running process reliably

    Quote Originally Posted by vbrad View Post
    I've been feeling a bit guilty about using DoEvents, so it's nice to see someone well thought of, using it.
    It has its uses, problem is that a lot of the time it's mis-used incorrectly.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  5. #5
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,491

    Re: Stop a complex long running process reliably

    Quote Originally Posted by techgnome View Post
    It has its uses, problem is that a lot of the time it's mis-used incorrectly.
    It should be banned because anyone that knows when to use it knows how to impl their own message pump too :-)) With custom message pump impl one can filter on hWnd and message ranges too.

    Elroy's use case is half legit -- he has to pump the button and its parent form only (for repaint) or risk re-entrance from timers, sockets and whatever other notification can be received by VB events.

    cheers,
    </wqw>

  6. #6
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    I don't understand the message pump.
    Where is it, what is it, guess I should google!
    Is it something windows is doing for my program
    or has my program a second inaccessible thread?

    On a form i put button1 with a long running loop in its click event
    I put button2 that just increments a variable whose initial value is 0
    I have no DoEvents.

    I hit button1 and while that running I hit button2 several times and it looks unresponsive each time
    When the loop finishes I see that the variable has been incremented several times
    I guess all these button2 clicks happen only when the loop is finished and in the meantime are they
    being stored in the pump?

    If during the loop i hit button2 more often the form window freezes, and displays the unresponsive
    message at the top until the loop is done and it becomes responsive again.
    Is this because the pump is full?

  7. #7
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably


  8. #8
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,491

    Re: Stop a complex long running process reliably

    Quote Originally Posted by vbrad View Post
    . . . in the meantime are they being stored in the pump?
    These get stored in the message queue. The message pump fetches messages from current thread message queue when these are available. Otherwise GetMessage API blocks i.e. it does not return until a new message is posted/sent to the queue.

    Quote Originally Posted by vbrad View Post
    If during the loop i hit button2 more often the form window freezes, and displays the unresponsive
    message at the top until the loop is done and it becomes responsive again.
    Is this because the pump is full?
    No, this is a feature of Windows XP (and later) to provide "end process" dialog when messages are not pumped for more the 5 seconds by "paling" the window (a.k.a "window ghosting") and enabling close button.

    You can use DisableProcessWindowsGhosting API function to disable it if you want your mouse and keyboard messages to not get lost when UI gets ghosted on long synchronous operations your application is performing (a.k.a For/Do ... Loops or some h/w device communication).

    cheers,
    </wqw>

  9. #9
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    735

    Re: Stop a complex long running process reliably

    This remindme, how I handled large asymchronic tasks in the server EXE, I have a server side done in VB6, it can accept the tasks about so many ppl loged in, run large tasks in parallel and on-demand, and be 100% responsive without a single "DoEvents" written (DoEvents are evil). It also can do concurrent tasks, is to say, one task creating another task. This all on the single main thread which gives VB6, no tricks..., just pure legacy VB6 code, no more is required to do the job.

    How to do?

    1) Create a class..., this class must have all its internal private variables and code, enough to do the job. Include it can call external if the external functions can handle sinmultaneous concurrently, like any function that can peek information somewhere and return quick without DoEvents.

    Plus some I/O Variables:

    * what task I am running or will run?
    * Which stage or substage of the task I am about to run next? Which record or id or whatever (cursor)?.
    * When I started to execute this sub-task? (to check if it needs to escape NOW or can do other internal subtask cycle). (use tickcount() engine)
    * Which user to respond or send data when the task is done? (in case of multi-user engine). (normally a session slot index plus an account username (so check in each send_message if the slot is logged by the same user consistently, and wasn't dropped and taken in the middle for security reason must be check that or you can start sending critical information to other user that just did log in)).
    * I am an InUse task?
    * I am Done?



    2) Set a fast timer in a form (30ms or so), and in it, run a cyclic LOOP (NOT A FOR/NEXT) , cyclic, I mean round-robin type code. So each tick of the timer it runs a different task.

    Tasks are divided in so many part, that can do just a slice of it, and escape.


    Tasks are created like.

    Code:
    Module holding the tasks pool.
    
    private const TotalTasks = 512
    Private TasksPool(0 to 511) as ClassTasksEngine
    Private TasksPoolAlreadyCreated(0 to 511) as boolean
    
    public function CreateTask(....) as boolean
    
    for x=0 to totaltasks-1
        if TasksPoolAlreadyCreated(x) = false then
              set TasksPool(x) as new ClassTasksEngine
                   TasksPool(x).TaskClassID =  
                   TasksPool(x).SessionID =
                   TasksPool(x).SessionUserName =
                   TasksPoolAlreadyCreated(x) = True
                   CreateTask=true
                   exit function
        end if
    next x
    
    CreateTask=false
    
    end function
    
    
    despues en un timer
    
    
    _TIMER
    
    while executedsomething=false 
      if TasksPoolAlreadyCreated(currenttask)  then
            ' Ok, is existing task.
            if TasksPool(currenttask).isdone then
                  ' Task, already finished.
                  set TasksPool(currenttask) = nothing
                  TasksPoolAlreadyCreated(currenttask)=false
           else
                ' It have job to do.
                 call TasksPool(currenttask).Execute
                 ExecutedSomething = true
           end if
       endif
    
        currenttask=currenttask+1:if currenttask>totaltasks-1 then currenttask=0:exit sub
    wend
    SUPER AIR CODING,.... well, hope everybody get the idea. I have it in practice, up to 200 users..... CERO PROBLEM!. And it does a year of accounting balance in it!.
    Last edited by flyguille; Jul 31st, 2019 at 07:37 PM.

  10. #10
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    Quote Originally Posted by wqweto View Post
    These get stored in the message queue. The message pump fetches messages from current thread message queue when these are available. Otherwise GetMessage API blocks i.e. it does not return until a new message is posted/sent to the queue.

    No, this is a feature of Windows XP (and later) to provide "end process" dialog when messages are not pumped for more the 5 seconds by "paling" the window (a.k.a "window ghosting") and enabling close button.

    You can use DisableProcessWindowsGhosting API function to disable it if you want your mouse and keyboard messages to not get lost when UI gets ghosted on long synchronous operations your application is performing (a.k.a For/Do ... Loops or some h/w device communication).

    cheers,
    </wqw>
    That makes sense all right now, thanks for info.

  11. #11
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    Quote Originally Posted by flyguille View Post
    This remindme, how I handled large asymchronic tasks in the server EXE, I have a server side done in VB6, it can accept the tasks about so many ppl loged in, run large tasks in parallel and on-demand, and be 100% responsive without a single "DoEvents" written (DoEvents are evil). It also can do concurrent tasks, is to say, one task creating another task. This all on the single main thread which gives VB6, no tricks..., just pure legacy VB6 code, no more is required to do the job.

    How to do?

    1) Create a class..., this class must have all its internal private variables and code, enough to do the job. Include it can call external if the external functions can handle sinmultaneous concurrently, like any function that can peek information somewhere and return quick without DoEvents.

    Plus some I/O Variables:

    * what task I am running or will run?
    * Which stage or substage of the task I am about to run next? Which record or id or whatever (cursor)?.
    * When I started to execute this sub-task? (to check if it needs to escape NOW or can do other internal subtask cycle). (use tickcount() engine)
    * Which user to respond or send data when the task is done? (in case of multi-user engine). (normally a session slot index plus an account username (so check in each send_message if the slot is logged by the same user consistently, and wasn't dropped and taken in the middle for security reason must be check that or you can start sending critical information to other user that just did log in)).
    * I am an InUse task?
    * I am Done?



    2) Set a fast timer in a form (30ms or so), and in it, run a cyclic LOOP (NOT A FOR/NEXT) , cyclic, I mean round-robin type code. So each tick of the timer it runs a different task.

    Tasks are divided in so many part, that can do just a slice of it, and escape.


    Tasks are created like.

    Code:
    Module holding the tasks pool.
    
    private const TotalTasks = 512
    Private TasksPool(0 to 511) as ClassTasksEngine
    Private TasksPoolAlreadyCreated(0 to 511) as boolean
    
    public function CreateTask(....) as boolean
    
    for x=0 to totaltasks-1
        if TasksPoolAlreadyCreated(x) = false then
              set TasksPool(x) as new ClassTasksEngine
                   TasksPool(x).TaskClassID =  
                   TasksPool(x).SessionID =
                   TasksPool(x).SessionUserName =
                   TasksPoolAlreadyCreated(x) = True
                   CreateTask=true
                   exit function
        end if
    next x
    
    CreateTask=false
    
    end function
    
    
    despues en un timer
    
    
    _TIMER
    
    while executedsomething=false 
      if TasksPoolAlreadyCreated(currenttask)  then
            ' Ok, is existing task.
            if TasksPool(currenttask).isdone then
                  ' Task, already finished.
                  set TasksPool(currenttask) = nothing
                  TasksPoolAlreadyCreated(currenttask)=false
           else
                ' It have job to do.
                 call TasksPool(currenttask).Execute
                 ExecutedSomething = true
           end if
       endif
    
        currenttask=currenttask+1:if currenttask>totaltasks-1 then currenttask=0:exit sub
    wend
    SUPER AIR CODING,.... well, hope everybody get the idea. I have it in practice, up to 200 users..... CERO PROBLEM!. And it does a year of accounting balance in it!.

    That's really very impressive.
    For me I think that type of coding requires a great amount of concentration and the breaking up of tasks in ways that aren't the easiest to debug and change.
    I say that because I had one foray into something like this for a mobile app that was interacting with a file server and I confused the hell out of myself so often.
    I suppose I'd have gotten better with it with practice.

  12. #12
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    . double post

  13. #13
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    735

    Re: Stop a complex long running process reliably

    Quote Originally Posted by vbrad View Post
    That's really very impressive.
    For me I think that type of coding requires a great amount of concentration and the breaking up of tasks in ways that aren't the easiest to debug and change.
    I say that because I had one foray into something like this for a mobile app that was interacting with a file server and I confused the hell out of myself so often.
    I suppose I'd have gotten better with it with practice.
    It is basic tasks timing slicing, multi user, multi sesión per user, and so on.

    Just more hints.... if a given task must fetch some table.... divide it in different stages, by example, in accounting doing full balances.... it is like:



    STAGE=0
    current date = initial date
    and others initial parameters, plus define de output recipient.
    set stage=1
    ESCAPE


    Stage=1
    fetch the whole result for the current date (so read all the table of a given date at once IF IT IS LOCAL, it is quick).
    record cursor =0 and goto set STAGE = 2
    ESCAPE

    stage=2
    process , filter, sum, send maintain a cursor of the current record, after a give mili-seconds ESCAPE
    if no more record, set stage=3

    stage = 3
    loop next date AND stage = 1
    if complete present final balance sum
    ESCAPE WITH IsDone.


    you get the basic idea about how slicing a task.

  14. #14
    Fanatic Member
    Join Date
    Jan 2013
    Posts
    735

    Re: Stop a complex long running process reliably

    Quote Originally Posted by vbrad View Post
    That's really very impressive.
    For me I think that type of coding requires a great amount of concentration and the breaking up of tasks in ways that aren't the easiest to debug and change.
    I say that because I had one foray into something like this for a mobile app that was interacting with a file server and I confused the hell out of myself so often.
    I suppose I'd have gotten better with it with practice.
    It is basic tasks timing slicing, multi user, multi sesión per user, and so on.

    Just more hints.... if a given task must fetch some table.... divide it in different stages, by example, in accounting doing full balances.... it is like:



    STAGE=0
    current date = initial date
    and others initial parameters, plus define de output recipient.
    set stage=1
    ESCAPE


    Stage=1
    fetch the whole result for the current date (so read all the table of a given date at once IF IT IS LOCAL, it is quick).
    record cursor =0 and goto set STAGE = 2
    ESCAPE

    stage=2
    process , filter, sum, send maintain a cursor of the current record, after a give mili-seconds ESCAPE
    if no more record, set stage=3

    stage = 3
    loop next date AND stage = 1
    if complete present final balance sum & miscs
    ESCAPE WITH IsDone.


    you get the basic idea about how slicing a task.



    Now, if it will be remote SQL, better slice in between fetching. And do the task to initialice a communication channel and destroy when is all done, so it won't interfere with others tasks. Single channel to send all the tasks, can be only if can be guarantee that a single tasks can execute a command, and fetch everything before escaping, so the next task doing whatever will do has the channel clean and ready to get another command.
    Last edited by flyguille; Aug 2nd, 2019 at 09:15 AM.

  15. #15
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    5,661

    Re: Stop a complex long running process reliably

    Hmmm, ok, fine fine fine.

    Here's what I sometimes use when I want to do this:

    Code:
    
    Option Explicit
    '
    Public Type POINTAPI
        x As Long
        Y As Long
    End Type
    '
    Private Type Msg
        hWnd        As Long
        message     As Long
        wParam      As Long
        lParam      As Long
        Time        As Long
        pt          As POINTAPI
    End Type
    '
    Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" (lpMsg As Msg, ByVal hWnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    Private Declare Function TranslateMessage Lib "user32" (ByRef lpMsg As Any) As Long
    Private Declare Function DispatchMessage Lib "user32" Alias "DispatchMessageW" (ByRef lpMsg As Any) As Long
    '
    
    Public Sub FastDoEvents()
        Dim uMsg As Msg
        '
        Do While PeekMessage(uMsg, 0&, 0&, 0&, 1&)
            TranslateMessage uMsg
            DispatchMessage uMsg
        Loop
    End Sub
    
    

    Now, if you really wanted to, you could smarten that up so that it only dispatched messages that were related to your "Cancel" button. It'd be a bit complex as you'd have to re-post the messages you didn't handle.

    Personally, when I'm doing these types of things and I'm in a loop, I make sure there are no other timers and other things running that will foul things up.

    Also, I'll second techgnome's comment that it's easy to misuse DoEvents. Canceling a long-running process is pretty much the singular place I use it.

    Good Luck,
    Elroy

    EDIT1: Also, I'm sure there's a way to peek through (without popping) all the messages in the queue. It's just not something I've ever done.

    EDIT2: Sorry, I didn't originally place the UDTs in the first post. Also, I'm noticing that I'm using the ...A version of PeekMessage and the ...W version of DispatchMessage. It probably doesn't matter as I have all the variables in the UDTs declared as Long, but these should probably be changed to match.
    Last edited by Elroy; Aug 3rd, 2019 at 11:34 AM.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  16. #16
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,491

    Re: Stop a complex long running process reliably

    Quote Originally Posted by Elroy View Post
    Now, if you really wanted to, you could smarten that up so that it only dispatched messages that were related to your "Cancel" button. It'd be a bit complex as you'd have to re-post the messages you didn't handle.
    Check out the zeros in PeekMessage(uMsg, 0&, 0&, 0&, 1&) -- the first one is an hWnd to *filter* on. Second and third filter the range of msgs to retrieve too.

    The last 1 is PM_REMOVE and here are the named consts (esp. PM_NOREMOVE)

    Code:
    Private Const PM_NOREMOVE                   As Long = 0
    Private Const PM_REMOVE                     As Long = 1
    cheers,
    </wqw>

  17. #17
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    5,661

    Re: Stop a complex long running process reliably

    So basically, we could just pass in a hWnd to that FastDoEvents function, and have it process only those events. So, we could pass in the hWnd of our "Cancel" button, and that'd be it.

    So, there you go, shannarad. I don't have time to play with it this second, but it sounds easy enough. With that approach, you don't even need to make sure that nothing else is clickable ... as it just won't be (until your loop finishes). Although they may get stored in Windows event cache.

    Good Luck,
    Elroy

    p.s. I'll play with it when I've got more time.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  18. #18
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    5,661

    Re: Stop a complex long running process reliably

    Ok, it seems to work as we'd want. Here's my BAS module code:

    Code:
    
    Option Explicit
    '
    Public Type POINTAPI
        x As Long
        Y As Long
    End Type
    '
    Private Type Msg
        hWnd        As Long
        message     As Long
        wParam      As Long
        lParam      As Long
        Time        As Long
        pt          As POINTAPI
    End Type
    '
    Private Declare Function PeekMessageW Lib "user32" (lpMsg As Msg, ByVal hWnd As Long, ByVal wMsgFilterMin As Long, ByVal wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
    Private Declare Function TranslateMessage Lib "user32" (ByRef lpMsg As Any) As Long
    Private Declare Function DispatchMessageW Lib "user32" (ByRef lpMsg As Any) As Long
    '
    
    Public Sub DoHwndEvents(hWndToPump As Long)
        Dim uMsg As Msg
        '
        Do While PeekMessageW(uMsg, hWndToPump, 0&, 0&, 1&)
            TranslateMessage uMsg
            DispatchMessageW uMsg
        Loop
    End Sub
    
    

    And here's code I threw into a test project's Form1:

    Code:
    
    Option Explicit
    '
    Dim mbCanceled  As Boolean
    Dim mbRunning   As Boolean
    '
    
    Private Sub cmdCancel_Click()
        mbCanceled = True
    End Sub
    
    Private Sub cmdStart_Click()
    
        If mbRunning Then MsgBox "Bad things because we're already running."
    
    
        Dim t1 As Single
    
        mbCanceled = False
        t1 = timer
    
        MsgBox "Our long process will start once you click ""OK"""
    
        mbRunning = True
        Do
            DoHwndEvents cmdCancel.hWnd
            If timer > t1 + 3600 Then Exit Do   ' An hour.
            If mbCanceled Then Exit Do          ' We canceled.
        Loop
        mbRunning = False
    
    
        If mbCanceled Then MsgBox "We canceled"
    
    
    
    End Sub
    
    Private Sub Command3_Click()
        If mbRunning Then
            MsgBox "We fouled things up by clicking another button #1."
        Else
            MsgBox "Not doing anything, but another button #1 clicked."
        End If
    End Sub
    
    Private Sub Command4_Click()
        If mbRunning Then
            MsgBox "We fouled things up by clicking another button #2."
        Else
            MsgBox "Not doing anything, but another button #2 clicked."
        End If
    End Sub
    
    

    I've also attached it as a complete project.

    The "Cancel" button isn't always as responsive as we might like (particularly if we've clicked around on other things). Also, we might want to improve it to respond to non-client events of the form so it could be moved around and/or minimized, but I'll leave that for others.

    Take Care,
    Elroy
    Attached Files Attached Files
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  19. #19
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,491

    Re: Stop a complex long running process reliably

    Quote Originally Posted by Elroy View Post
    . . . but I'll leave that for others.
    That should be fairly easy. Just replace DoHwndEvents cmdCancel.hWnd w/ DoHwndEvents cmdCancel.hWnd : DoHwndEvents Me.hWnd i.e. pump both command button *and* the parent form.

    cheers,
    </wqw>

  20. #20
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,416

    Re: Stop a complex long running process reliably

    Here is an approach that uses a background worker process with a GUI client. For IPC it uses a memory-mapped file which is polled to accomplish synchronization. The worker just progressively pokes random pixels into an image, returning intermediate results. That's just a dummy long-running workload to test the concept with.

    Hard to debug? Sure. But most approaches have this sort of issue.

    It would be possible to combine both the Client and Worker as a single EXE, examining the command line to decide which mode to run in. It might then also be possible to detect runs in the IDE and instead of starting a Worker process make calls into the Worker logic from the Client Form... but that would take some rework. We don't have coroutine calls in VB6 so we'd have to get a bit tricky.

    Name:  sshot.png
Views: 91
Size:  2.9 KB

    Picking any non-black color enables the Start button. Clicking Start begins the Worker process and enables the Cancel button. Upon cancel or completion the UI is reset. Pick another color to play again.

    Worker.vbp must be compiled to EXE before you can run Client.vbp from the IDE or a compiled EXE.
    Attached Files Attached Files
    Last edited by dilettante; Aug 4th, 2019 at 01:51 PM. Reason: tweaked attachment, a little more robust startup

  21. #21
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    @ Elroy
    I tried out your DoHwndEvents project and it works great. The only problem though is if someone clicks on another button before the Cancel one, then the loop keeps running presumably for the full hour.
    I assume that this is because there is a message in the queue ahead of the cancel message that's going prevent it from being acted on. Is there a way to deal with this?


    Adding in the DoHwndEvents Me.hWnd as wqweto suggested overcomes that problem but now all the buttons respond to clicking so it's kind of like plain DoEvents again.

  22. #22
    PowerPoster Elroy's Avatar
    Join Date
    Jun 2014
    Location
    Near Nashville TN
    Posts
    5,661

    Re: Stop a complex long running process reliably

    Quote Originally Posted by vbrad View Post
    The only problem though is if someone clicks on another button before the Cancel one, then the loop keeps running presumably for the full hour.
    That's not my experience. However, I will agree that, if you try and click something else, the "Cancel" button becomes less responsive, but it does still respond.
    Any software I post in these forums written by me is provided “AS IS” without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. Please understand that I’ve been programming since the mid-1970s and still have some of that code. My contemporary VB6 project is approaching 1,000 modules. In addition, I have a “VB6 random code folder” that is overflowing. I’ve been at this long enough to truly not know with absolute certainty from whence every single line of my code has come, with much of it coming from programmers under my employ who signed intellectual property transfers. I have not deliberately attempted to remove any licenses and/or attributions from any software. If someone finds that I have inadvertently done so, I sincerely apologize, and, upon notice and reasonable proof, will re-attach those licenses and/or attributions. To all, peace and happiness.

  23. #23
    Member
    Join Date
    Aug 2013
    Posts
    52

    Re: Stop a complex long running process reliably

    I don't know what is wrong on mine. I just tried it again and now if I don't click on the cancel button in the first few seconds I get the "(Not Responding)" message and it stays that way. This happens even if I position the mousepointer over the Cancel button right after clicking the message box just before the loop starts and then only move it a smidge over the button after a few seconds. Immediately the form greys out etc.

  24. #24
    PowerPoster
    Join Date
    Feb 2006
    Posts
    20,416

    Re: Stop a complex long running process reliably

    Here's a rewritten version that can be tested in the IDE. There is just one Project.


    Whew, that was a lot of gymnastics. Works though.
    Attached Files Attached Files

  25. #25
    Frenzied Member wqweto's Avatar
    Join Date
    May 2011
    Posts
    1,491

    Re: Stop a complex long running process reliably

    Quote Originally Posted by vbrad View Post
    I just tried it again and now if I don't click on the cancel button in the first few seconds I get the "(Not Responding)" message and it stays that way.
    Try pumping WM_PAINT for all windows too. "(Not Responding)" appears when windows are prevented from redrawing for some reason.

    cheers,
    </wqw>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width