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

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

Related

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.

Application.Current.DispatcherUnhandledException

I would like to catch an unhandled exception that causes my application to silently close.
I have read that there is
Application.Current.DispatcherUnhandledException
My application however uses a form to run and the application framework, not a sub main.
The example on MSDN (http://msdn.microsoft.com/en-us/library/system.windows.application.dispatcherunhandledexception.aspx) seems to rely on a sub main, as it seems to me.
Could somebody tell me how to install the exception handler for a project that uses the application framework?
I have tried the following:
I have changed my application to use a Sub Main instead and used the following code:
Public Sub Main()
' Set the unhandled exception mode to force all Windows Forms errors to go through'
' our handler. '
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)
' Add the event handler for handling UI thread exceptions to the event. '
AddHandler Application.ThreadException, AddressOf frmMain.UIThreadException
' Add the event handler for handling non-UI thread exceptions to the event. '
AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf frmMain.CurrentDomain_UnhandledException
' Runs the application. '
Application.Run(New frmMain())
End Sub
However, the error I am getting is:
"The thread exception mode can no longer be changed as soon as controls were created in this thread".
You could use a Try Catch to avoid an application from closing by exception. You could try something like
Try
Console.WriteLine("Hello, world!")
Dim A As Integer = 0
Dim I As Integer
For I = 1 to 500000000000
A*=I
Next
Catch ex As Exception
Console.WriteLine("Error occurred")
End Try
This is a little example in a Console Application program, but you will be able to use something like in your project.
The generic Exception catches every kind of exception you could have, so also Application.Current.DispatcherUnhandledException.
Your program shouldn't crash anymore with a try statement.
Hope it helps.
It is good practice to also register an event handler for the case that some exception does not get caught at runtime.
It allows you to log the exception cause and to exit application in a controlled manner.
But as already said, you should primarily use Try Catch statements to catch exceptions in first instance.

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.

.NET Security Exception only in external code

I am using VS2012 with VB.NET for a winfowms app, using Active Directory roles.
Running the program as a user without permissions, I am getting an (expected) security exception when trying to launch this form.
I have a form that looks like this:
<PrincipalPermission(SecurityAction.Demand, Role:=Security.Roles.ADMINISTRATORS)> _
<PrincipalPermission(SecurityAction.Demand, Role:=Security.Roles.CORRECTIVE_ACTION_EDITORS)> _
<PrincipalPermission(SecurityAction.Demand, Role:=Security.Roles.GRIEVANCE_EDITORS)> _
<PrincipalPermission(SecurityAction.Demand, Role:=Security.Roles.ABOLISHMENT_EDITORS)> _
Public Class EmployeeInformationForm
...
End Class
The call to the code looks like this:
Private Sub SendEmployeeIDToEmployeeInformationForm(ByVal ID_in As String, ByVal employeeRecord_in As String)
...
If Not formFound Then
' Create a new instance of the child form.
Dim ChildForm As New EmployeeInformationForm(ID_in, employeeRecord_in) ' ** throws expected security exception here**
Try
' Make it a child of this MDI form before showing it.
ChildForm.MdiParent = Me.MdiParent
...
ChildForm.Show()
Catch ex As Exception
ChildForm.Close()
Throw
End Try
End If
After 15 or 16 attempts (or maybe the variable is "after about 1 minute"?) the program crashes.
UPDATE: after more input of any kind the program crashes. I have debugged the code as the user without permissions, and was able to capture the exception being thrown - apparently from nowhere. It is very weird saying "The call stack contains only external code", and displays the following:
This thread is stopped with only external code frames on the call stack. External code frames are typically from framework code but can also include other optimized modules which are loaded in the target process.
Call stack with external code
mscorlib.dll!System.Security.Permissions.PrincipalPermission.ThrowSecurityException()
mscorlib.dll!System.Security.Permissions.PrincipalPermission.Demand()
mscorlib.dll!System.Security.PermissionSet.DemandNonCAS()
[Native to Managed Transition]
[Managed to Native Transition]
OHRC Database.exe!OHRC_Database.EmployeeInformationForm.Dispose(Boolean disposing)
System.dll!System.ComponentModel.Component.Finalize()
It seems to imply it is having a hard time closing the form? Can anyone tell me why it is throwing this exception?
The exception is being thrown from the finalization thread (the Finalize() call in your exception stack trace is the hint for this), and the user identity on that thread doesn't have the right permissions either. See http://msmvps.com/blogs/calinoiu/archive/2006/01/07/why-is-my-application-coughing-up-a-securityexception-after-my-code-stops-running.aspx for further details and a fix.
HTH,
Nicole

Global Exception Handling for winforms control

When working on ASP.NET 1.1 projects I always used the Global.asax to catch all errors. I'm looking for a similar way to catch all exceptions in a Windows Forms user control, which ends up being a hosted IE control. What is the proper way to go about doing something like this?
You need to handle the System.Windows.Forms.Application.ThreadException event for Windows Forms. This article really helped me: http://bytes.com/forum/thread236199.html.
Currently in my winforms app I have handlers for Application.ThreadException, as above, but also AppDomain.CurrentDomain.UnhandledException
Most exceptions arrive via the ThreadException handler, but the AppDomain has also caught a few in my experience
If you're using VB.NET, you can tap into the very convenient ApplicationEvents.vb. This file comes for free with a VB.NET WinForms project and contains a method for handling unhandled exceptions.
To get to this nifty file, it's "Project Properties >> Application >> Application Events"
If you're not using VB.NET, then yeah, it's handling Application.ThreadException.
To Handle Exceptions Globally...
Windows Application
System.Windows.Forms.Application.ThreadException event
Generally Used in Main Method. Refer MSDN Thread Exception
Asp.Net
System.Web.HttpApplication.Error event
Normally Used in Global.asax file. Refer MSDN Global.asax Global Handlers
Console Application
System.AppDomain.UnhandledException event
Generally used in Main Method. Refer MSDN UnhandledException
Code from MSDN: http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-2
Sub Main()
Dim currentDomain As AppDomain = AppDomain.CurrentDomain
AddHandler currentDomain.UnhandledException, AddressOf MyHandler
Try
Throw New Exception("1")
Catch e As Exception
Console.WriteLine("Catch clause caught : " + e.Message)
Console.WriteLine()
End Try
Throw New Exception("2")
End Sub
Sub MyHandler(sender As Object, args As UnhandledExceptionEventArgs)
Dim e As Exception = DirectCast(args.ExceptionObject, Exception)
Console.WriteLine("MyHandler caught : " + e.Message)
Console.WriteLine("Runtime terminating: {0}", args.IsTerminating)
End Sub

Resources