Can a Timer event experience reentrancy? - timer

I'm examining some dreadful legacy code that has a Timer event with some lengthy code that contains DoEvents calls. A simplified version looks something like this:
Private Sub tmrProcess_Timer()
'Run some slow processing code here
DoEvents
'More slow code here
DoEvents
'Lots more slow code and the occasional DoEvents here
If booComplete Then
tmrProcess.Enabled = False
End If
End Sub
The timer has it's Interval set to 250 and the slow code could take up to thirty or so seconds to complete. Note that there is a button on the form that sets booComplete = True when it is clicked.
Given that VB6 is single threaded and that timer messages are low priority is it at all possible for the Timer event to be re-entered during a DoEvents call or will the VB6 runtime block execution of a Timer event if the Timer event is currently executing?
This reference has some relevant information. In particular it states that WM_PAINT messages are combined into a single message but there is no mention of whether or not WM_TIMER messages are combined.

i expected it would reenter, but it seems not to
have a look at the following test project:
'1 form with:
' 1 timer control : Name=Timer1
Option Explicit
Private Sub Form_Load()
WindowState = vbMaximized
Timer1.Interval = 2000
End Sub
Private Sub Timer1_Timer()
Static intCount As Integer
Dim sngTime As Single
intCount = intCount + 1
Print CStr(Now) & " Timer event fired " & CStr(intCount)
sngTime = Timer + 3
Do While sngTime > Timer
DoEvents
Loop
Print CStr(Now) & " End of timer event " & CStr(intCount)
End Sub
you will see a "start" 2 seconds after the form loads
you will see an "end" 3 seconds after that
you will see a "start" 2 seconds after the previous "end" showed
you will see an "end" 3 seconds after the "start"
...
if the timer would be reentered i would expect 2 seconds between each "start", but there appears to be 3+2=5 seconds between each "start"
removing the DoEvents doesn't change the behaviour, it just changes the time at which the texts are printed

To avoid reentry, disable the timer till the time taking logic is executed and then enable again.
Private Sub tmrProcess_Timer()
tmrProcess.Enabled = False
'your time taking logic goes here ......
tmrProcess.Enabled = True
End Sub

First, most code containing DoEvents doesn't require it, it's a magical word that people feel compelled to incant (but without without knowing why).
DoEvents allows reentrancy of anything, not just timers.
Your's is a TimerProc. If you had chosen a message then the wm_timer message only comes if the message queue is empty and you ask "are their any messages?". If their is a paint, timer, or mouse move type message pending then if the queue is empty only then are they available.
Despite the obviousnous this is the link it came from:
> mk:#MSITStore:C:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\kbvb.chm::/Source/vbapps/q118468.htm
(of course you have to have same libraries as me installed for this to work.)
Why do you assume the source is the internet?
Definition of DoEvents in Visual Basic for Applications
Q118468
The information in this article applies to:
Microsoft Visual Basic for Applications version 1.0 Microsoft Excel
for Windows, versions 5.0, 5.0c Microsoft Excel for the Macintosh,
versions 5.0, 5.0a Microsoft Excel for Windows 95, versions 7.0, 7.0a
Microsoft Excel 97 for Windows Microsoft Excel 98 Macintosh Edition
SUMMARY The DoEvents function surrenders execution of the macro so
that the operating system can process other events. The DoEvents
function passes control from the application to the operating system.
Some instances in which DoEvents may be useful include the following:
Hardware I/O
Delay Loops
Operating System Calls
DDE Deadlocking
This article also discusses potential problems associated with the
DoEvents function.
MORE INFORMATION
Hardware I/O If your code waits for an input from any I/O device, the
DoEvents function speeds up the application by multitasking. As a
result, the computer does not seems to pause or stop responding (hang)
while the code is executing.
Example:
Open "com1" For Input As #1 Input #1, x Do Until x = Chr(13) DoEvents
'... '... Input #1, x Loop Delay Loops In a delay loop, the DoEvents
function can allow the CPU operating system to continue with any
pending jobs.
Example:
X = Timer() Do While X + 10 > Timer()
DoEventsLoop Operating System Calls When Visual Basic calls the
operating system, the operating system may return the control even
before processing the command completely. Doing so may prevent any
macro code that depends on an object generated by the call from
running. In the example below, the Shell function starts the Microsoft
Word application. If Word is not yet open, any effort to establish a
DDE link to it will halt the code. By using DoEvents, your procedure
makes sure that an operation, such as Shell, is completely executed
before the next macro statement is processed.
Example:
z% = Shell("WinWord Source.Doc",1) DoEvents ... ... DDE Deadlocking
Consider a situation in which a Visual Basic macro calls an
application that is waiting for a second application to get some data.
If the macro does not give control to the second application, the
result is a deadlock. In DDE conversations between multiple
applications, using DoEvents removes the possibility of this type of
deadlocking. Problems Associated with DoEvents Using too many nested
DoEvents statements may deplete the stack space and therefore generate
an "Out of Stack Space" error message. This error is referring to the
application stack space allocated to the Microsoft Excel application.
Make sure the procedure that has given up control with DoEvents is not
executed again from a different part of your code before the first
DoEvents call returns; this can cause unpredictable results.
Once DoEvents relinquishes control to the operating system, it is not
possible to determine when Microsoft Excel will resume the control.
After the operating system obtains control of the processor, it will
process all pending events that are currently in the message queue
(such as mouse clicks and keystrokes). This may be unsuitable for some
real- time data acquisition applications.
REFERENCES For more information about DoEvents, click the Search
button in Help and type:
doevents
Additional query words: Sendkeys keystroke Wait XL98 XL97 XL7 XL5
Keywords : Issue type : Technology : kbHWMAC kbOSMAC kbExcelSearch
kbZNotKeyword6 kbExcel95 kbExcel500 kbExcel98 kbExcel95Search
kbExcel97Search kbExcel98Search kbExcelMacsearch kbVBASearch
kbZNotKeyword3 kbExcel500Mac kbExcel500aMac kbExcel500c kbExcel95a
kbVBA100
Last Reviewed: January 17, 2001 © 2001 Microsoft Corporation. All
rights reserved. Terms of Use.
Send feedback to MSDN.Look here for MSDN Online resources

Related

C# .NET system timer hiccup

private System.Timers.Timer timerSys = new System.Timers.Timer();
ticks are set to start at the beginning of each multiple of 5 seconds
entry exit
10:5:00.146 10:5:00.205
10:5:05.129 10:5:05.177
10:5:10.136 10:5:10.192
10:5:15.140 10:5:15.189
10:5:20.144 10:5:20.204
amd then a delay of 28 second
note that Windows 10 compensates for missing ticks
by firing them at close intervals
10:5:48.612 10:5:48.692
10:5:48.695 10:5:48.745
10:5:48.748 10:5:48.789
10:5:48.792 10:5:49.90
10:5:43.93 10:5:49.131
and another delay of 27 seconds
again Windows 10 crams ticks to compensate
but this time there is an even inside the second tick
that lasts about 28 seconds that makes the tick very long
10:6:16.639 10:6:16.878
this one is very long
10:6:16.883 10:6:42.980
10:6:42.984 10:6:43.236
10:6:43.241 10:6:43.321
10:6:43.326 10:6:43.479
The PC is running just two applications that I wrote.
They communicate via files and also via SQL tables.
This event happens maybe once every two months.
Questions:
What could be happening?
Is there a way to create a log file of all processes over time
My applications keep tabs of the time down to milliseconds.
So if there were a way of logging processes, I could match.
Alternately is there a way for my app to know what the OS is doing.

CANOPEN SYNC timeout after enable Operation

I am a newbie in CANOPEN. I wrote a program that read actual position via PDO1 (default is statusword + actual position).
void canopen_init() {
// code1 setup PDO mapping
nmtPreOperation();
disablePDO(PDO_TX1_CONFIG_COMM);
setTransmissionTypePDO(PDO_TX1_CONFIG_COMM, 1);
setInhibitTimePDO(PDO_TX1_CONFIG_COMM, 0);
setEventTimePDO(PDO_TX1_CONFIG_COMM, 0);
enablePDO(PDO_TX1_CONFIG_COMM);
setCyclePeriod(1000);
setSyncWindow(100);
//code 2: enable OPeration
readyToSwitchOn();
switchOn();
enableOperation();
motionStart();
// code 3
nmtActiveNode();
}
int main (void) {
canopen_init();
while {
delay_ms(1);
send_sync();
}
}
If I remove "code 2" (the servo is in Switch_on_disable status), i can read position each time sync send. But if i use "code 2", the driver has error "sync frame timeout". I dont know driver has problem or my code has problem. Does my code has problem? thank you!
I don't know what protocol stack this is or how it works, but these:
setCyclePeriod(1000);
setSyncWindow(100);
likely correspond to these OD entries :
Object 1006h: Communication cycle period (CiA 301 7.5.2.6)
Object 1007h: Synchronous window length (CiA 301 7.5.2.7)
They set the SYNC interval and time window for synchronous PDOs respectively. The latter is described by the standard as:
If the synchronous window length expires all synchronous TPDOs may be discarded and an EMCY message may be transmitted; all synchronous RPDOs may be discarded until the next SYNC message is received. Synchronous RPDO processing is resumed with the next SYNC message.
Now if you set this sync time window to 100us but have a sloppy busy-wait delay delay_ms(1), then that doesn't add up. If you write zero to Object 1007h, you disable the sync window feature. I suppose setSyncWindow(0); might do that. You can try to do that to see if that's the issue. If so, you have to drop your busy-wait in favour for proper hardware timers, one for the SYNC period and one for PDO timeout (if you must use that feature).
Problem fixed. Due to much EMI from servo, that make my controller didn't work properly. After isolating, it worked very well :)!

Adding a DocumentWindow to a DocumentTabStrip causes the application to hang indefinitely

I have a Winforms application with a primary form that contains (among other things) a Telerik DocumentTabStrip. These tabs are used to hold user controls or web pages (via a web browser control). It has worked fine for quite a while, but I'm running into an issue now.
I recently switched the web browser control from the built-in .NET web browser based on IE to CefSharp. Since doing so, I've noticed that occasionally when trying to add the DocumentWindow to the DocumentTabStrip, the call will hang indefinitely (in debug) or crash outright (running the app normally). This only appears to happen when opening a DocumentWindow that contains the browser control, not any other user controls. The actual call itself is below.
I'm at a bit of a loss as to how to even begin to debug this, since there's no error that gets received - it just hangs inside the Controls.Add() method indefinitely. Any advice would be appreciated.
Private dts As New Telerik.WinControls.UI.Docking.DocumentTabStrip
Try
dts.InvokeIfRequired(Sub()
Dim docWindow As Telerik.WinControls.UI.Docking.DocumentWindow = Nothing
Dim ctrl As ucBaseControl = Nothing
Dim browser As ucBrowser = Nothing
Dim isBrowser As Boolean = False
docWindow = New Telerik.WinControls.UI.Docking.DocumentWindow
docWindow.BackColor = Color.FromArgb(89, 89, 89)
'Do various stuff to determine the type of control to load (ctrl or browser), then setup the applicable control
If isBrowser Then
'Place the browser into the Document Window.
If Not IsNothing(browser) Then
browser.Dock = DockStyle.Fill
docWindow.Controls.Add(browser)
End If
Else
'Place the ctrl into the Document Window.
ctrl.Dock = DockStyle.Fill
docWindow.Controls.Add(ctrl)
End If
'Add the DocumentWindow to the DocumentTabStrip
' Ensure DockWindow not disposed due to lag in bringing up
If IsNothing(docWindow) OrElse docWindow.IsDisposed Then
Exit Sub
End If
Try
docWindow.Padding = New Padding(0)
dts.TabStripElement.Children(0).Children(1).Padding = New Padding(0)
dts.Controls.Add(docWindow) 'This is where the issue is. It only happens sporadically here.
Catch ex As Exception
'Code to log any exceptions here. In the problem described here, no exception is ever generated, though.
End Try
'Bring the control to the front and focus it, here...
End Sub)
Catch ex As Exception
'Error handling code here'
End Try
I'm assuming InvokeIfRequired is an extension method you've created for Controls. Note that if it relies on Invoke, that is a synchronous call, instead use BeginInvoke (see: What's the difference between Invoke() and BeginInvoke())
No exception was ever thrown because you were suffering from deadlock

Slow Excel Shutdown When WPF Called from Add-In

I have an Excel add-in with a button on it that calls a WPF application on a new thread. When I close Excel not having opened my WPF application or after opening it and then closing it again, Excel closes immediately, however, whenever I open the application and then close Excel, Excel takes 5-10 seconds to close. I've only come across these solutions, neither of which has helped:
VSTO Runtime Update to Address Slow Shutdown...
This one sort of asks the question, but the asker's issue ends up being different.
I'm running VS 2010 and Excel 2010, so there shouldn't be an interoperability problem.
Does anyone have a suggestion?
Thread Code:
Private qbdThread As Thread = Nothing
Private frmQBD As QBDApplication.MainWindow
qbdThread = New Thread(New ParameterizedThreadStart(AddressOf RunQBD))
qbdThread.SetApartmentState(Threading.ApartmentState.STA)
qbdThread.Start(TabletType)
AddHandler QBDApplication.MainWindow.QBDClose, AddressOf QBDThreadClose
Private Sub RunQBD(Optional tabletQBDSelected As String = Nothing)
...
frmQBD = New QBDApplication.MainWindow(contacts, saveLocation, tabletQBDLocal)
frmQBD.Show()
frmQBD.Activate()
System.Windows.Threading.Dispatcher.Run()
End Sub
This code runs when the app is closed by the user on the new thread:
Me.Close()
System.Windows.Threading.Dispatcher.CurrentDispatcher.InvokeShutdown()
An event is then raised on the main thread (ThisAddin.vb) with this code:
Private Sub QBDThreadClose()
qbdThread = Nothing
frmQBD = Nothing
End Sub
One other thing to note is that when frmQBD is not created as a class variable, and instead dimensioned in the "RunQBD" sub, this issue does not occur. This would solve my problem, but then I wouldn't be able to access something like frmQBD.Activate() on the main thread, which I need to be able to do.
EDIT: Code has been updated
We found a solution for this problem.
You have to set an AppSwith in the framework
Public Sub EnablePointerSupport()
AppContext.SetSwitch("Switch.System.Windows.Input.Stylus.EnablePointerSupport",True)
End Sub
You can find more information about it here and here.
This Microsoft bug is described at https://connect.microsoft.com/VisualStudio/feedback/details/783019/word-slow-shutdown-on-windows-8-when-using-wpf-in-application-addin. It was initially reported in 2013 and supposedly fixed in 2014, but appears to be back now.
We can reproduce this exact problem with Excel and Word 2016 running on Windows 10, but mysteriously not in PowerPoint. Latest version of VSTO Runtime is installed. We could not reproduce the problem in Office 2013 running on Windows 8.1.
The workaround is as described at the link above--go to Device Manager > Human Interface Devices and disable "HID-compliant touch screen" (in our testing) or perhaps another one of the "HID-compliant" items.

WPF: Wait animation window blocks

I have seen several similar questions on SO and elsewhere, but none seems to work for me.
I have a small Window in my project containing a LoadingAnimation that I show up at application startup and want to keep actual processing running. Here's my startup code:
Dim WaitWindow As New WaitWindow("Loading application...")
WaitWindow.Show()
LongRunningLoading()
WaitWindow.Close()
Here's LongRunningLoading() function that I try to run on a separate thread to avoid blocking my animation:
Private Function LongRunningLoading() As Boolean
Dim resetEvent As New System.Threading.ManualResetEvent(False)
Dim RetVal As Boolean = False
ThreadPool.QueueUserWorkItem(Sub(state)
'DO SOMETHING AND RETURN RESULTS
resetEvent.Set()
End Sub,
RetVal)
resetEvent.WaitOne()
Return RetVal
End Function
Everything works as expected except that the loading animation doesn't play. What am I doing wrong?
What am I doing wrong?
You're doing this:
resetEvent.WaitOne()
That blocks the UI thread. Don't do that. Instead, remember that the UI is basically event based - unless you're using the async features in VB 11, you'll have to write your code in an event-based way. So basically when your long-running task completes, you need to post back to the UI thread to execute the WaitWindow.Close() part.
If you can use .NET 4.5 and VB 11, you can use Task.Run to start a new task for your long-running work, and then Await that task from an asynchronous method.
They are both running on UI Thread, this is why loading animation is waiting. Try to use BackgroundWorker for your LongRunningLoading process and then return to UI thread if needed for your results.
This approach worked for me:
Dim waitwindow As New WaitWindow("Loading application...")
ThreadPool.QueueUserWorkItem( _
Sub()
LongRunningLoading()
Dispatcher.Invoke(New Action(AddressOf waitwindow.Close))
End Sub)
waitwindow.ShowDialog()
May help someone else.

Resources