ICursor issue in 10.1 SP-1

4818
13
Jump to solution
11-08-2012 12:35 PM
ShawnShepard
New Contributor III
I have used the code below for a few years in an ArcGIS Engine application we have developed.  Essentailly it builds a sorted IEnumerator of unique values from a specific field in a layers attribute table.  It has worked fine for years however after upgrading to SP-1 of 10.1 running it consecutivly three times to build three differant lists of values it causes our application to crash.  The crash seems to happed a few seconds after we step through the last IEnumerator to populate a listbox.

Am I missing somthing here?  The crash is an "nt.dll" error in a standard windows error box.

private IEnumerator getSortedList(string mField, ILayer mLayer, string whereclause)         {             IQueryFilter mQFilter = new QueryFilterClass();             mQFilter.WhereClause = whereclause;             IEnumerator mEnumstreets = null;             if (mLayer != null)             {                 IFeatureLayer mFeatureLayer = (IFeatureLayer)mLayer;                 IFeatureClass pFeatureClass = mFeatureLayer.FeatureClass;                 if (pFeatureClass != null)                 {                         ITable pTable = (ITable)pFeatureClass;                         IFeatureCursor pCursor = pFeatureClass.Search(mQFilter, true);                          ITableSort mTableSort = new TableSortClass();                         mTableSort.Table = pTable;                         mTableSort.Fields = mField;                         mTableSort.set_Ascending(mField, true);                         mTableSort.QueryFilter = mQFilter;                         mTableSort.Sort(null);                          IDataStatistics mDataStats = new DataStatisticsClass();                         mDataStats.Cursor = mTableSort.Rows;                         mDataStats.Field = mField;                         mEnumstreets = mDataStats.UniqueValues;                         pCursor = null;                 }             }             return mEnumstreets;         }
0 Kudos
1 Solution

Accepted Solutions
ArminMueller
New Contributor III
Hi Shawn,

i have the same problem after installing the SP1 for ArcGIS 10.1. I use IDataStatistics.UniqueValues in my code. This works without problems but later in the code ArcMap crashs with error message: .NET Runtime - Fatal Execution Engine Error.
I have removed the IDataStatistics.UniqueValues and create the unique values with .NET functions. After this the code runs without problems

Armin

View solution in original post

0 Kudos
13 Replies
ArminMueller
New Contributor III
Hi Shawn,

i have the same problem after installing the SP1 for ArcGIS 10.1. I use IDataStatistics.UniqueValues in my code. This works without problems but later in the code ArcMap crashs with error message: .NET Runtime - Fatal Execution Engine Error.
I have removed the IDataStatistics.UniqueValues and create the unique values with .NET functions. After this the code runs without problems

Armin
0 Kudos
ShawnShepard
New Contributor III
Thank you Armin, that did the trick. I was begining to think I was going to have to role back to 10.0.  I am using Dynamic Display and there was a big bug in 10.1.  SP-1 fixed it but introduced this issue.

Thanks again

Shawn
0 Kudos
DuncanHornby
MVP Notable Contributor
Armin,

I'm curious, how did you determine it was the IDataStatistics interface that was causing you problems, you say it runs OK then crashes, what made you decide it was that and not something else? I only ask as I am having a 10.1 addin I am creating crashing with a heap corruption error at seemingly random times. It's such a catastrophic error that none of my error-trapping catches it, ArcMap simply bombs out to Windows.

Duncan
0 Kudos
ArminMueller
New Contributor III
Armin,

I'm curious, how did you determine it was the IDataStatistics interface that was causing you problems, you say it runs OK then crashes, what made you decide it was that and not something else? I only ask as I am having a 10.1 addin I am creating crashing with a heap corruption error at seemingly random times. It's such a catastrophic error that none of my error-trapping catches it, ArcMap simply bombs out to Windows.

Duncan


Hi Duncan,

Try and Error 🙂 We have a software which generates interactive SVG maps from ArcMap projects. the error only occured, when using a functionality in our software which use the DataStatistics class from ArcObjects. There was no error when using  IDataStatistics.UniqueValue function but the error comes during saving a xml file. I have then replaced the IDataStatistics.UniqueValue with a function who loops through the cursor and fill a simple .NET HashSet list. After this change the error is gone.

Armin
0 Kudos
DavidWilton
Occasional Contributor
I have just seen this thread and I can confirm that we are experiencing the same issue. We managed to isolate the issue through trial and error too. We created a separate project which confirms that there is an issue with IDataStatistics

Unfortunately I didn't see your post:
http://forums.arcgis.com/threads/71895-Issues-with-ArcObjects-and-ArcGIS-10.1-SP1-IDataStatistics?hi...
0 Kudos
DavidWilton
Occasional Contributor
So we can continue to test I have recreated the data statistics object. I'm sure that this code could be optimised, any suggestions welcome. But the idea isn't to use this in production, it is just to get around what looks like a common bug so we can test the rest of the code. I haven't implemented the statistics function, this just returns unique values. If you are releasing the statitics com object you will have to remove that line as it is no longer a com object (Marshal.ReleaseComObject(pData))

Imports ESRI.ArcGIS.Geodatabase

Public Interface IDataStatiticsECL

    WriteOnly Property Cursor() As ESRI.ArcGIS.Geodatabase.ICursor

    Property Field() As String

    ReadOnly Property UniqueValues() As System.Collections.IEnumerator

End Interface

Public Class DataStatisticsClassECL
    Implements IDataStatiticsECL

    Private m_Cur As ESRI.ArcGIS.Geodatabase.ICursor
    Public WriteOnly Property Cursor As ESRI.ArcGIS.Geodatabase.ICursor Implements IDataStatiticsECL.Cursor
        Set(value As ESRI.ArcGIS.Geodatabase.ICursor)
            m_Cur = value
        End Set
    End Property

    Private m_Field As String
    Public Property Field As String Implements IDataStatiticsECL.Field
        Get
            Return m_Field
        End Get
        Set(value As String)
            m_Field = value
        End Set
    End Property

    Public ReadOnly Property UniqueValues As System.Collections.IEnumerator Implements IDataStatiticsECL.UniqueValues
        Get
            Dim row As Row = CType(m_Cur.NextRow(), Row)
            Dim dic As New SortedList(Of Object, String)
            Dim iFeild = row.Fields.FindField(m_Field)

            'loop through the data and get the unique values
            Do Until row Is Nothing
                If dic.ContainsKey(row.Value(iFeild)) = False Then
                    dic.Add(row.Value(iFeild), "")
                End If
                row = CType(m_Cur.NextRow(), Row)
            Loop

            Dim arr(dic.Count - 1) As Object
            Dim arrInd As Integer
            dic.Keys.CopyTo(arr, arrInd)
            Dim n As New ValuesEnum(arr)
            Return n
        End Get
    End Property

    Private Class ValuesEnum
        Implements IEnumerator

        Private ReadOnly m_Values() As Object
        Private m_Cur As Integer

        Public Sub New(ByVal lst() As Object)
            m_Values = lst
            m_Cur = -1
        End Sub

        Public ReadOnly Property Current() Implements IEnumerator.Current
            Get
                If m_Cur >= m_Values.Length Then
                    Return Nothing
                End If
                Return m_Values(m_Cur)
            End Get
        End Property

        Public Sub Reset() Implements IEnumerator.Reset
            m_Cur = -1
        End Sub

        Public Function Movenext() As Boolean Implements IEnumerator.MoveNext
            m_Cur = m_Cur + 1

            If m_Cur < m_Values.Length Then
                Return True
            Else
                Return False
            End If
        End Function
    End Class

End Class
0 Kudos
DavidWilton
Occasional Contributor
Esri inc have confirmed that there is a bug in 10.1 SP1:

Bug is NIM087476  �??Memory leakage ESRI.ArcGIS.Geodatabase.IDataStatistics using UniqueValues property  with ArcGIS 10.1 with SP1�?�
0 Kudos
RichardFairhurst
MVP Honored Contributor
David:

I have modified your replacement DataStatistics code slightly. I have added a new property that returns an UniqueValueCount so that the class supports the use of a For loop in the same way as IDataStatistics.

Your Interface declarations were misspelled. It read IDataStatiticsECL and not IDataStatisticsECL. That error made it harder to incorporate into my code that used the IDataStatistics interface. The spelling correction below makes it easy to just append "ECL" to the appropriate places in code that uses the broken IDataStatistics interface.

This fixed the crashes and memory errors I was having with the IDataStatistics interface, so I appreciate the code you posted. It saved me a lot of time. Overall the performance of the new code seem fairly good, but if any one has performance enhancement suggestions, I am also intersested.

Here is the revised code:

Imports ESRI.ArcGIS.Geodatabase

Public Interface IDataStatisticsECL

    WriteOnly Property Cursor() As ESRI.ArcGIS.Geodatabase.ICursor

    Property Field() As String

    ReadOnly Property UniqueValues() As System.Collections.IEnumerator

    ReadOnly Property UniqueValueCount() As Integer

End Interface

Public Class DataStatisticsClassECL
    Implements IDataStatisticsECL

    Private m_Cur As ESRI.ArcGIS.Geodatabase.ICursor
    Public WriteOnly Property Cursor As ESRI.ArcGIS.Geodatabase.ICursor Implements IDataStatisticsECL.Cursor
        Set(ByVal value As ESRI.ArcGIS.Geodatabase.ICursor)
            m_Cur = value
        End Set
    End Property

    Private m_Field As String = ""
    Public Property Field As String Implements IDataStatisticsECL.Field
        Get
            Return m_Field
        End Get
        Set(ByVal value As String)
            m_Field = value
        End Set
    End Property

    Public ReadOnly Property UniqueValues As System.Collections.IEnumerator Implements IDataStatisticsECL.UniqueValues
        Get
            Dim row As Row = CType(m_Cur.NextRow(), Row)
            Dim dic As New SortedList(Of Object, String)
            Dim iFeild = row.Fields.FindField(m_Field)

            'loop through the data and get the unique values
            Do Until row Is Nothing
                If dic.ContainsKey(row.Value(iFeild)) = False Then
                    dic.Add(row.Value(iFeild), "")
                End If
                row = CType(m_Cur.NextRow(), Row)
            Loop

            Dim arr(dic.Count - 1) As Object
            Dim arrInd As Integer
            dic.Keys.CopyTo(arr, arrInd)
            m_UniqueValueCount = arr.Length
            Dim n As New ValuesEnum(arr)
            Return n
        End Get
    End Property

    Private m_UniqueValueCount As Integer = 0
    Public ReadOnly Property UniqueValueCount As Integer Implements IDataStatisticsECL.UniqueValueCount
        Get
            Return m_UniqueValueCount
        End Get
    End Property

    Private Class ValuesEnum
        Implements IEnumerator

        Private ReadOnly m_Values() As Object
        Private m_Cur As Integer

        Public Sub New(ByVal lst() As Object)
            m_Values = lst
            m_Cur = -1
        End Sub

        Public ReadOnly Property Current() Implements IEnumerator.Current
            Get
                If m_Cur >= m_Values.Length Then
                    Return Nothing
                End If
                Return m_Values(m_Cur)
            End Get
        End Property

        Public Sub Reset() Implements IEnumerator.Reset
            m_Cur = -1
        End Sub

        Public Function Movenext() As Boolean Implements IEnumerator.MoveNext
            m_Cur = m_Cur + 1

            If m_Cur < m_Values.Length Then
                Return True
            Else
                Return False
            End If
        End Function
    End Class

End Class
0 Kudos
RichardFairhurst
MVP Honored Contributor
David:

I have made another correction to the code in the UniqueValues property.  The code below handles two cases where code results in unhandled exceptions.  The first occurs when the cursor for the class is Nothing (unassigned).  The second occurs when the cursor returns Nothing for the row value (the cursor had no records).  In both of these cases I set the UniqueValueCount of the class to 0 and return an empty Enumeration, which I believe matches the behavior of the original IDataStatistics property.

    Public ReadOnly Property UniqueValues As System.Collections.IEnumerator Implements IDataStatisticsECL.UniqueValues
        Get
            If m_Cur Is Nothing Then
                m_UniqueValueCount = 0
                Dim arra(-1) As Object
                Dim noCursor1 As New ValuesEnum(arra)
                Return noCursor1
            End If
            Dim row As Row = CType(m_Cur.NextRow(), Row)
            If row Is Nothing Then
                m_UniqueValueCount = 0
                Dim arra(-1) As Object
                Dim noRow2 As New ValuesEnum(arra)
                Return noRow2
            End If
            Dim dic As New SortedList(Of Object, String)
            Dim iFeild = row.Fields.FindField(m_Field)

            'loop through the data and get the unique values
            Do Until row Is Nothing
                If dic.ContainsKey(row.Value(iFeild)) = False Then
                    dic.Add(row.Value(iFeild), "")
                End If
                row = CType(m_Cur.NextRow(), Row)
            Loop

            Dim arr(dic.Count - 1) As Object
            Dim arrInd As Integer
            dic.Keys.CopyTo(arr, arrInd)
            m_UniqueValueCount = arr.Length
            Dim n As New ValuesEnum(arr)
            Return n
        End Get
    End Property
0 Kudos