Problem with Progressbar and Runspace

This topic contains 4 replies, has 2 voices, and was last updated by Profile photo of Talcom Talcom 2 years, 4 months ago.

  • Author
    Posts
  • #17378
    Profile photo of Talcom
    Talcom
    Participant

    Hello,

    I have tried the following code to start a extern batch-exe in the main thread. Then I have created a Runspace to refresh my progress bar while the batch-exe is still running. But it don't work because the script don't jump into my refresh script block. It continues the script with the next commands, without waiting until the batch-exe is closed.

    Here are some parts from my coding (PowerShellV2 Newbie):

    #Create synchronized Hashtable-Object for communication between sub-thread and form
    $syncHash = [hashtable]::Synchronized(@{})

    #set the controls in the hashtable we wish to manipulate
    $syncHash.Status = "Running"
    $syncHash.CVS_EXE = $Null
    $syncHash.ProgessBar = $Null

    # start batch exe – this works
    $arguments = ' -q update'
    $UpdateProcess = start-process -FilePath $CVS_EXE -ArgumentList $arguments -RedirectStandardOutput $CVS_LOG2

    # transfer intern variables to hash variables
    $syncHash.CVS_EXE = $CVS_EXE
    $syncHash.ProgressForm = $ProgressForm

    # define runspace
    $newRunspace =[runspacefactory]::CreateRunspace()
    $newRunspace.ApartmentState = "STA"
    $newRunspace.ThreadOptions = "ReuseThread"
    $newRunspace.Open()

    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash.Status)
    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash.CVS_EXE)
    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash.ProgressForm)

    # script block with coding for loop
    $ScriptBlock =
    {
    $syncHash.Status = Get-Process $syncHash.CVS_EXE
    while ($syncHash.Status -eq "Running")
    {
    [System.Windows.Forms.Application]::DoEvents()
    $syncHash.ProgressForm.Refresh()
    }
    }

    # start runspace with scriptblock
    $newPowerShell = [PowerShell]::Create()
    $newPowerShell.Runspace = $newRunspace
    $newPowerShell.AddScript($ScriptBlock).AddArgument($syncHash)

    $AsyncResult = $newPowerShell.BeginInvoke()

    $newPowerShell.Endinvoke($AsyncResult)
    $newPowerShell.dispose()
    $newRunspace.close()

    Who could help me? I would be happy to get some hints! Or are there other possibilities to reach my goal?
    By the way... I need PowerShell V2 Coding – Thanks

    Thanks!

  • #17384
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    There are a few problems with your code:

    [ul][li]You're setting up a background runspace, but I'm not sure why you're bothering to do this. You call EndInvoke immediately after BeginInvoke; this is the same as just calling Invoke(), a synchronous operation, and that is just like running the code directly without bothering with a runspace at all. If your intention is to have something asynchronous happening here, the code isn't structured properly for that.
    [/li][li]This bit of code is wrong:

    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash.Status)
    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash.CVS_EXE)
    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash.ProgressForm)
    

    It should just be this:

    $newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)
    

    [/li][li]You're trying to compare the result of Get-Process to the string "Running", which will never be true. If you add the -Passthru switch to Start-Process, you can monitor the HasExited property of the $UpdateProcess object instead. For example:

    $UpdateProcess = start-process -FilePath $CVS_EXE -ArgumentList $arguments -RedirectStandardOutput $CVS_LOG2 -Passthru
    while (-not $UpdateProcess.HasExited)
    {
        # Process is still running; update progress bar
    }
    

    [/li][/ul]

    Without knowing more about exactly what you're trying to accomplish (why the background runspace, etc), this is all I'll suggest for now.

  • #17387
    Profile photo of Talcom
    Talcom
    Participant

    Thanks for your reply. I'll try it out tomorrow at work. Especially the last hint seems to be very interesting.

    The reason for using the background runspace is, that my processbar gui get an "not response" after a while, when it's waiting for the end of my called batch-exe.
    So I was looking for hints to fix it. And I found very much about using runspaces. At the end it was a try to fix my problem.

  • #17388
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    I see. You're still going to run into the same problem, as the code is currently written. As soon as you call EndInvoke() on your powershell object, the main thread is blocking again, which will probably result in the same problem of an unresponsive GUI. Concurrent code can be very tricky to get right.

  • #17399
    Profile photo of Talcom
    Talcom
    Participant

    Hello Dave,

    today I tried the start-process commando with -passthru option. The batch call works perfectly, but I get a "not responding" from my gui also, when it's waiting until my batch exe ends. This time period would take nearly up to 10 seconds, because my batch exe communicates with a server.

    Everything in my script works. The only problem is the gui. When the user see "no responding" in the head of the gui frame, he would be confused about it. So I tried to update my progress bar, set the focus again or show it again. But every time "no responding" after a while. 🙁

You must be logged in to reply to this topic.