Issue with Task and Windows 10

I’m having an issue with the Task class from UIThreadingWithTask example.

I’m calling UpdateUI in the Run event many times, for sample in a file download, I have noticed that in Windows this will raise a RuntimeException with message: “Current process has used maximum number of manipulators allowed by the object system in Windows administrator” (translated).

It can be reproduced using the mentioned UIThreadingWithTask example by changing Run code to:

[code]Dim progressValue As Integer

While progressValue < 100
progressValue = progressValue + 1

// Do some long-running process
LongRunningMethod

// Call UpdateUI with any parameters you need. This calls the UpdateUI event handler
// where you can directly access any UI controls on the Window.

// This specifies simple parameters using a Pair
// You can also pass values using a Dictionary
Dim n as integer = 0
while n < 1000 //in a real runtime this may happen while downloading a file if only bytes received are used to update
Me.UpdateUI(“UIProgress”:progressValue)
n = n + 1
wend
Wend
[/code]

In Mac it works fine and it has worked until now in Windows, seems last OS updates are different.
While debugging I have found that InternalDispatchEvents is never called in Windows once Run has started.

I know I can check the progress value and minimize use of UpdateUI but, is there another solution? Or do I have to use the Timer update option?

Thanks.

You cannot update the UI from within a thread

Dave, I’m using the Task class from Xojo’s example Desktop/UpdatingUIFromThread/UIThreadingWithTask which is exactly for this purpose.

In Task.InternalPushEvent, there is code to make sure the timer is running when a new UpdateUI request comes through. It looks like this code is starting a new timer each time through and reaching a limit on Windows. I’m not sure if this is a bug with the Windows timer, but it looks like you can avoid it.

Try changing this code in Task.InternalPushEvent:

mLock.Enter mEvents.Append(evt) mTimer.Period = 0 mTimer.Mode = Timer.ModeSingle mLock.Leave

To this:

mLock.Enter mEvents.Append(evt) If mTimer.Mode = Timer.ModeOff Then mTimer.Period = 0 mTimer.Mode = Timer.ModeSingle End If mLock.Leave

Paul,
thanks so much, this solved the issue.

I didn’t worried about timer, being local and unique to the Task I thought that changing mode or period wouldn’t start a new Timer but it seems in last Windows versions it does.

This fix seems to make it not work under MacOS, so a #IfTarget conditional is probably in order.

It works fine for me in Mac OS X, I have introduced the change in several controls and not found an issue.

In my app under MacOS, if I include the conditional timer period and mode setting the UI is refreshed only once or not at all, event though I can see that I’m calling UpdateUI repeatedly. If I execute those lines, it works all the time.

I don’t remember exactly in which macOS version – 10.10? 10.11? – Apple changed something in their NSView redraw handling so that an invalidated or updated control simply does not get enough time to redraw and the app returns to tight loops without visual feedback. Infamous are folderitem dialogues closing with a delay of several seconds if you don’t give the system time to update its UI.

I often find myself refactoring methods into several smaller ones, calling each other with a very short Xojo.core.Timer.CallLater delay to work around these framework changes. It is interesting anyway that the absence of the condition above allows the system to redraw while the If clause does not. What happens if you yield to other threads before the End If on macOS?

And did someone create a feedback entry to investigate why Windows creates new timers when it should not?

I’m running 10.12 right now. The UI update is a canvas redraw. Sorry, no time to experiment with yield times, I just need it to work, and it does (for the moment) if I do the timer period and mode updates. The ultimate target is Windows, I just do my coding on Mac.