.NET memory error on closing ArcMap with open control form

707
3
Jump to solution
03-26-2012 09:11 AM
KeithOlson
New Contributor III
I am developing a custom set of tools for ArcMap implementing BaseToolBar and BaseCommand in VB.NET.  For non-admin users, whenever the ArcMap application is closed with one of the tool's modeless forms still open, the following .NET error message appears:

"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."

Research into this issue has suggested that my COM objects are not being disposed of properly before the application shuts down.  Following the advise here: http://edndoc.esri.com/arcobjects/9.2/NET/fe9f7423-2100-4c70-8bd6-f4f16d5ce8c0.htm#AOShutdown,
I added an AOUninitialize.Shutdown command at the form's Disposed event, but this did not make any difference.

One of my forms is a simple "About" dialog that only shows version info and does nothing else.  This form references no ArcObjects other than the fact that you open it from a BaseCommand button.  So, there are no specific COM objects that need to be released or anything.

One thing that will prevent this error from occurring is to open the form as modal.  But I've seen and used other custom tools with modeless dialogs that do not have this issue.

Any advice/suggestions would be greatly appreciated.
0 Kudos
1 Solution

Accepted Solutions
KeithOlson
New Contributor III
Okay, I think I've solved this.  Originally my forms were all modal and I converted them to modeless using several examples I found on the ArcGIS forums and elsewhere on the Internets.  What I think happened is I ended up with a combination of methods that were somehow incompatible with each other.

What I did since my previous posts was I created a brand new "Hello World" form, defined it by itself (i.e. not inside another class) and simply followed the example given here: http://forums.arcgis.com/threads/53681-Opening-Visual-Studio-in-ArcGIS to set up a modeless form.  My exact code is as follows:

'In a separate module containing project scope variables and constants...  Friend frm1 As Form1  ------------------------------------------------------------------- 'In the BaseCommand class "button"...  Public Overrides Sub OnClick()         If IsNothing(frm1) OrElse frm1.IsDisposed Then             frm1 = New Form1             frm1.Show(New ModelessDialog(m_application.hWnd))         Else             frm1.Show()         End If End Sub  ------------------------------------------------------------------- 'Then the form code itself...  Public Class Form1      Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing         If e.CloseReason = Windows.Forms.CloseReason.UserClosing Then             e.Cancel = True             Me.Hide()         End If     End Sub End Class


This successfully created a singleton modeless form and does not cause those .NET errors after ArcMap closes.  Now I just need to apply this to my actual forms.  Wish me luck......

View solution in original post

0 Kudos
3 Replies
KeithOlson
New Contributor III
A little more background info on this...  All my forms are set to have the ArcMap application as the parent window and are treated as singleton forms so I don't have more than on instance open at a time.  The form classes are all defined in a separate module in a class called clsGlobals.  Here's an example of the OnClick method of one of my tools (the "Apply Template" tool):

'...in the COM class that inherits BaseCommand (i.e., a button on an ArcMap toolbar).

Public Overrides Sub OnClick()
        Try
            'Set pMxDoc and other variables used by multiple tools
            GetMxDocumentFromArcMap(m_application)

            'Make sure there are maps and layers in the document
            If Not CheckFrames() Then Exit Sub

            'create form and open it.
             If IsNothing(clsGlobals.frmTemplate) OrElse clsGlobals.frmTemplate.IsDisposed Then
                clsGlobals.frmTemplate = New TemplateForm(pMxDoc)
                SetWindowLong(clsGlobals.frmTemplate.Handle.ToInt32, GWL_HWNDPARENT, pApp.hWnd)
                clsGlobals.frmTemplate.Show()
            Else
                clsGlobals.frmTemplate.WindowState = FormWindowState.Normal
                clsGlobals.frmTemplate.BringToFront()
            End If

        Catch ex As Exception
            ExHandling(ex)
        End Try
End Sub


I also added this to the code on the actual form itself, which does not seem to make a difference:

Private Sub TemplateForm_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Disposed
    ESRI.ArcGIS.ADF.COMSupport.AOUninitialize.Shutdown()
End Sub


Anyway, if there is a better way to implement modeless forms or if there's any important piece I'm leaving out, I'd be very grateful for your advice.
0 Kudos
KeithOlson
New Contributor III
Okay, I think I've solved this.  Originally my forms were all modal and I converted them to modeless using several examples I found on the ArcGIS forums and elsewhere on the Internets.  What I think happened is I ended up with a combination of methods that were somehow incompatible with each other.

What I did since my previous posts was I created a brand new "Hello World" form, defined it by itself (i.e. not inside another class) and simply followed the example given here: http://forums.arcgis.com/threads/53681-Opening-Visual-Studio-in-ArcGIS to set up a modeless form.  My exact code is as follows:

'In a separate module containing project scope variables and constants...  Friend frm1 As Form1  ------------------------------------------------------------------- 'In the BaseCommand class "button"...  Public Overrides Sub OnClick()         If IsNothing(frm1) OrElse frm1.IsDisposed Then             frm1 = New Form1             frm1.Show(New ModelessDialog(m_application.hWnd))         Else             frm1.Show()         End If End Sub  ------------------------------------------------------------------- 'Then the form code itself...  Public Class Form1      Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing         If e.CloseReason = Windows.Forms.CloseReason.UserClosing Then             e.Cancel = True             Me.Hide()         End If     End Sub End Class


This successfully created a singleton modeless form and does not cause those .NET errors after ArcMap closes.  Now I just need to apply this to my actual forms.  Wish me luck......
0 Kudos
MarkNguyen
New Contributor
Thanks kdolson so much!
0 Kudos