I want to create my edition error report form instead default error window.
How I can create my edition form error report?
For example:
So you want to call a custom handler when exception happens? No problem, just define these 3 magic lines in the beginning of your program (as first lines of Sub Main):
AddHandler Application.ThreadException, AddressOf GenericHandler
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)
AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf UnhandledHandler
Then define GenericHandler and UnhandledHandler, which would call your custom form.
Here is a sample implementation of both handlers:
Public Shared Sub GenericHandler(ByVal sender As Object, ByVal args As Threading.ThreadExceptionEventArgs)
ReportException(args.Exception)
End Sub
Public Shared Sub UnhandledHandler(ByVal sender As Object, ByVal args As UnhandledExceptionEventArgs)
If Not Debugger.IsAttached Then
ReportException(args.ExceptionObject)
End
End If
Public Shared Sub ReportException(ByVal ex As System.Exception)
MsgBox(ex.ToString, MsgBoxStyle.OkOnly Or MsgBoxStyle.Exclamation, "Unhandled exception - Please contact support")
'you can further improve this to add custom logging etc.
End Sub
Related
I have a form used to display options about processes.
When options are applyed :
frmOptions
For Each ltvi As ListViewItem In ltvProcesses.CheckedItems
Dim proc As Process = CType(ltvi.Tag, Process)
targeted_processes.Add(proc)
AddHandler proc.Exited, AddressOf frmAET.a_target_process_has_been_exited
proc.EnableRaisingEvents = True
Next
And in a tools module :
Public Sub a_target_process_has_been_exited(sender As Object, e As EventArgs)
frmAET.btnStatus.ForeColor = Color.Red
msgbox("OK")
End Sub
And... the messagebox displays its message but the color doesn't change.
After some tries, the problem is when a_target_process_has_been_exited is actived by the handler.
If I do this (Button1 belongs to frmAET, like btnStatus) :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
a_target_process_has_been_exited()
End Sub
It works ! But not when I really want (when a process is ended).
So, the problem is when the sub is called by the process end event.
And when I try to specify this (maybe a frmAET's sub can modify its controls) :
AddHandler leproc.Exited, AddressOf frmAET.a_target_process_has_been_exited
Error : Reference to a non-shared member requires an objet reference
Could you help me ?
Your AddHandler seems to use AddressOf frmAET.a_target_process_has_been_exited, that means method in frmAET form itself. Not tools module as you stated.
Let's consider your frmOptions is correct and frmAET is containing this (with removed explicit reference to frmAET, since it's local)
Public Sub a_target_process_has_been_exited(sender As Object, e As EventArgs)
btnStatus.ForeColor = Color.Red
MsgBox("OK")
End Sub
As comments already explained, your event handler is called in another thread and you need to sync yourself to main UI thread. For example like this:
Public Sub a_target_process_has_been_exited(sender As Object, e As EventArgs)
Me.BeginInvoke(Sub() HandleProcessExit())
End Sub
Public Sub HandleProcessExit
btnStatus.ForeColor = Color.Red
MsgBox("OK")
End Sub
This version will block main UI thread until you click on the MsgBox button.
You should add some Try/Catch block. Exception in another threads are difficult to detect otherwise.
This code depends on implicit form instances that VB.NET creates for you. I expect your frmAET is actually My.Forms.frmAET instance to make this work.
when ever my program is popping 'UnHandled Exception', can I call for a button click in my program? I have a button in my form which can actually 'fix' or 'go around' the exception. like, something 'On Error Button2.PerformClick() 3 times' ( just an example of my thinking )
Enable the application event and handle it from there, You can use the unhandled exception function to show your form, Take a look at the below code:
Imports System.Text
Imports System.IO
Namespace My
' The following events are available for MyApplication:
'
' Startup: Raised when the application starts, before the startup form is created.
' Shutdown: Raised after all application forms are closed. This event is not raised if the application terminates abnormally.
' UnhandledException: Raised if the application encounters an unhandled exception.
' StartupNextInstance: Raised when launching a single-instance application and the application is already active.
' NetworkAvailabilityChanged: Raised when the network connection is connected or disconnected.
Partial Friend Class MyApplication
'One of the global exceptions we are catching is not thread safe,
'so we need to make it thread safe first.
Private Delegate Sub SafeApplicationThreadException(ByVal sender As Object, ByVal e As Threading.ThreadExceptionEventArgs)
Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
'There are three places to catch all global unhandled exceptions:
'AppDomain.CurrentDomain.UnhandledException event.
'System.Windows.Forms.Application.ThreadException event.
'MyApplication.UnhandledException event.
AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf AppDomain_UnhandledException
AddHandler System.Windows.Forms.Application.ThreadException, AddressOf app_ThreadException
' AddHandler AccessViolationException, AddressOf app_AccessViolationException
End Sub
'Private Sub app_AccessViolationException(ByVal sender As Object, ByVal ex As System.AccessViolationException)
'End Sub
Private Sub app_ThreadException(ByVal sender As Object, ByVal e As Threading.ThreadExceptionEventArgs)
'This is not thread safe, so make it thread safe.
If MainForm.InvokeRequired Then
' Invoke back to the main thread
MainForm.Invoke(New SafeApplicationThreadException(AddressOf app_ThreadException), _
New Object() {sender, e})
Else
frmDebug.Show()
End If
End Sub
Private Sub AppDomain_UnhandledException(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
frmDebug.Show()
End Sub
Private Sub MyApplication_UnhandledException(sender As Object, e As Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs) Handles Me.UnhandledException
frmDebug.Show()
End Sub
End Class
End Namespace
I'm hooking an arcobjects map event to a vb.net form to listen for map selection changes. This all works fine but users are reporting this error occassionally when opening the form. I can't see any pattern to reproduce the error and it seems to be random.
"COM object that has been separated from its underlying RCW cannot be used"
It originates from the form Load() method where I am hooking the event.
Can anyone help me understand what I've done wrong? I'm unhooking the map selection event in the FormClosing() event which I think is the correct approach.
Public Class MyForm
Private _activeViewEvents As IActiveViewEvents_Event
Private Sub FormLoad(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
_activeViewEvents = TryCast(pMxDoc.ActiveView.FocusMap, IActiveViewEvents_Event)
AddHandler _activeViewEvents.SelectionChanged, AddressOf SelectionChanged
End Sub
Private Sub SelectionChanged
'do something when selection is changed
End Sub
Private Sub FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
RemoveHandler _activeViewEvents.SelectionChanged, AddressOf SelectionChanged
End Sub
End Class
The approach you are taking to creating and destroying your handlers are valid. You can receive a RCW COM Exception when the map document is changed while your form is open. Since you are using the FocusMap to create the handles, when the document is changed, so is the FocusMap, which means you need to re-create your handlers for the new map document.
Ok so I think i've resolved this via use of the ActiveViewChanged event. Instead of rehooking the event on each form load or new document event, I tried listening for when the ActiveViewChanged event was fired and rehooking the SelectionChanged event each time. Turns out this is fired more than once each time a new document is opened (not sure why). Anyway, problem seems to have gone. Here's some example code:
Public Class MyForm
Private _activeViewEvents As IActiveViewEvents_Event
Private _docEvents As IDocumentEvents_Event
Private Sub FormLoad(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AddHandler _docEvents.ActiveViewChanged, AddressOf ActiveViewChanged
End Sub
Private Sub ActiveViewChanged()
Dim maps = pMxDoc.Maps
For i = 0 to maps.Count - 1 'remove handlers from all maps
RemoveActiveViewEvents(maps.Item(i))
Next
SetupActiveViewEvent(pMxDoc.ActiveView.FocusMap) 'only add handler to active map
End Sub
Private Sub RemoveActiveViewEvents(map As IMap)
_activeViewEvents = CType(map, IActiveViewEvents_Event)
RemoveHandler _activeViewEvents.SelectionChanged, AddressOf SelectionChanged
End Sub
Private Sub SetupActiveViewEvents(map As IMap)
_activeViewEvents = CType(map, IActiveViewEvents_Event)
AddHandler _activeViewEvents.SelectionChanged, AddressOf SelectionChanged
End Sub
Private Sub SelectionChanged
'do something when selection is changed
End Sub
End Class
I am trying to use the code from the following link:
VB- Helper Create menu items at run time with images, shortcut keys, and event handlers in Visual Basic .NET
The only difference is that I want a local image and not one from my.Recources
What I have is the following:
''Tool 2 displays a string and image.
Dim tool2 As New ToolStripMenuItem("Tool 2", (Image.FromFile("C:\test\icon.jpg")))
tool2.Name = "mnuToolsTool2"
tool2.ShortcutKeys = (Keys.D2 Or Keys.Control) ' Ctrl+2
AddHandler tool2.Click, AddressOf mnuTool2_Click
ToolStripMenuItem1.DropDownItems.Add(tool2)
I could not reproduce this "error". However, from the given text, code and link, my best guess is as follows:
You are using a 64 bit machine.
You run the code inside the Form.Load event.
An error occurs somewhere in this method.
Private Sub _Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Code...
Throw New Exception("ooops..")
'Code...
End Sub
As you might not know is that errors thrown in the Form.Load on a 64 bit machine are "swallowed" by the system.
For more information, read this SO post: Why the form load can't catch exception?
You should move your code inside the constructor:
Public Sub New()
Me.InitializeComponent()
'Code goes here...
End Sub
Or change to the Form.Shown event:
Private Sub _Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
Try
'Code goes here...
Catch ex As Exception
MessageBox.Show(ex.Message, Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
As my title implies i have the following problem, i am receiving data from serial port and i update a richtextbox in a MDI Form with the control.invoke method
(Code in SerialPort.DataReceived Event)
If myTerminal.Visible Then
myTerminal.MyRichTextBox1.Invoke(New MethodInvoker(Sub()
myTerminal.MyRichTextBox1.AppendText(dataLine & vbCrLf)
End Sub))
End If
But as a mdi form it has the ability to close and reopen. So when the serialport is sending data to richtextbox and the user click the close button and the form gets disposed. Then the error "Invoke or BeginInvoke cannot be called on a control until the window handle has been created."... Any Idea????
My regards,
Ribben
That code is not in the SerialPort.DataReceived event it is in the event handler. (Yes, I'm nitpicking, but it points to a solution.) The best thing to do is have the form that owns myTerminal add the handler when it is created and remove the handler when it closes.
Thank you for your answer but unfortunately that's not the solution. First of all my SerialPort Class must inform 2 Forms (Form with richtextbox, Form with Listview) and another class which is responsible for drawing (Unmanaged Directx 9.0c about 4 Forms), so to implement right the serialport class i have made my own events. Again to the problme, it caused because the Serialport.DataReceived everytime it occurs creates a thread in the threadpool and when i dispose the form simply it's too slow to catch up with all the threads and so there is at least one thread which invokes the control which is already disposed!
As a temp solution i came up with (The Below code is in the TerminalForm Class which inherits Form):
Private VisibleBoolean As Boolean = False
Private Index As Integer = 0
Private Sub DataToAppend(ByVal _text As String)
If VisibleBoolean Then
Me.MyRichTextBox1.Invoke(New MethodInvoker(Sub()
Me.MyRichTextBox1.AppendText(_text & vbCrLf)
End Sub))
ElseIf Index = 1 Then
Index = 0
myDispose()
RemoveHandler myserialport.DataToSend2, AddressOf DataToAppend
End If
End Sub
Private Sub Me_Activated(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Activated
VisibleBoolean = True
AddHandler myserialport.DataToSend2, AddressOf DataToAppend
End Sub
Private Sub myDispose()
If Index = 0 And Not Me.IsDisposed Then
Me.Invoke(New MethodInvoker(Sub()
MyBase.Dispose(True)
End Sub))
End If
End Sub
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
End Sub
Protected Overrides Sub OnFormClosing(ByVal e As System.Windows.Forms.FormClosingEventArgs)
Index = 1
VisibleBoolean = False
End Sub
I know i don't like either but at least it's working!
Anyother improvement or suggestion is more