COM Exception - intermittent error

4124
8
02-05-2015 10:51 AM
BBulla
by
Occasional Contributor

Hi,

I've created a tool that updates selected features (ie. a Watermain Valve) with the diameter of the pipe that it is attached to, and updates other attributes too.  Depending on the type of selected feature, things will vary.  Anyways, it seems like with one particular feature I sometimes get this error:

_COMPlusExceptionCode = -532459699

At this line of code:

//Update the feature and move to next feature

                            if (updated == true)

                            {

                                fCursor.UpdateFeature(feature);     **this is where the error occurs!!!!

                                updatedFeatures++;

                            }

                            feature = fCursor.NextFeature();

The weird thing is that it doesn't happen all the time.  For example, the first time I may get the error, but if I close the error window and then run the tool again (with the same feature selected) then it works.

Any ideas??

Thanks,

0 Kudos
8 Replies
GregMcQuat
New Contributor III

Hi there!

Can you post the entire method block where this error occurs? I'd have a few suggestion off the top of my head but seeing just a little more about how you open the workspace & feature class and how you are handling the feature cursor would help narrow things down.

0 Kudos
BBulla
by
Occasional Contributor

Hi Greg,

Here is some code.  Basically, when a 'fitting' is selected and this button is hit, it runs through some logic to determine what kind of fitting it is, and then adjusts a bunch of attributes to match the fitting type.  This is just a small clip of code, as the entire solution does similar work for valves, service connections, etc.  And it all depends on what is selected on screen when the user hits the button.

I've marked where the ERROR occurs, but it usually only happens once.  Once I hit the button again, without changing the selection, it works fine the 2nd time.

Good luck....let me know if you see anything I can enhance.

                #region Check for Water Fittings

                if (waterFittingsLayer != null)

                {

                    //Check for selected features in the Water Fittings               

                    fSel = (IFeatureSelection)waterFittingsLayer;

                    selSet = (ISelectionSet2)fSel.SelectionSet;

                    if (selSet.Count > 0)   //if there are any selected, then process them

                    {

                        IFeatureCursor selectedWaterService, selectedWaterMain;

                        IFeature waterService, waterMain;

                        //create a cursor for the fittings

                        ICursor cursor;

                        selSet.Update(null, false, out cursor);

                        IFeatureCursor fCursor = (IFeatureCursor)cursor;  //create an updatedable FeatureCursor of the

                        //selected features

                        feature = fCursor.NextFeature();  //go to the first feature in the cursor

                        while (feature != null) //loop through all the features in the cursor

                        {

                            //A fitting can be on a WaterMain or a WaterService.

                            //Update the attributes of the Valve from the WaterMain first.

                            //Get the correct WaterMain based on the location of the Valve (feature).

                            //More than one WaterMain could be returned!!!

                            selectedWaterMain = SelectByLocation(waterMainLayer, (IPoint)feature.Shape);

                            waterMain = selectedWaterMain.NextFeature();

                            int waterMainCounter = 0;

                            bool waterMainExists = false;

                            bool updated = false;

                            //remove any existing Diameters from the feature

                            for (int i = 1; i < 5; i++)

                                feature.set_Value(feature.Fields.FindField("Diameter" + i.ToString()), 1);

                            //This will update Fittings on WaterMains

                            while (waterMain != null)

                            {

                                IPoint thePoint = (IPoint)feature.Shape;

                                IPolyline5 theLine = (IPolyline5)waterMain.Shape;

                                switch (waterMainCounter)

                                {

                                    case 0:

                                        feature.set_Value(feature.Fields.FindField("Diameter1"), waterMain.get_Value(waterMain.Fields.FindField("Diameter")));

                                        //if it's not a service connection, res_service connection or generic node

                                        //then make it a plug

                                        if (((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 9) && ((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 6) && ((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 10))

                                        {

                                            //determine if at the end or the edge of the line

                                            if ((thePoint.X == theLine.FromPoint.X && thePoint.Y == theLine.FromPoint.Y) || (thePoint.X == theLine.ToPoint.X && thePoint.Y == theLine.ToPoint.Y))

                                            {

                                                feature.set_Value(feature.Fields.FindField("SubTypeCD"), 4);

                                                //also rotate the plug so it looks nice

                                                if (theLine.FromPoint.X == thePoint.X && theLine.FromPoint.Y == thePoint.Y)

                                                    feature.set_Value(feature.Fields.FindField("Rotation"), CalculateAngle(theLine.ToPoint, theLine.FromPoint) * -1);

                                                else

                                                    feature.set_Value(feature.Fields.FindField("Rotation"), CalculateAngle(theLine.FromPoint, theLine.ToPoint) * -1);

                                            }

                                            else  //if located on the edge, then also set diameter2 for the generic node

                                            {

                                                feature.set_Value(feature.Fields.FindField("SubTypeCD"), 9);

                                                feature.set_Value(feature.Fields.FindField("Diameter2"), waterMain.get_Value(waterMain.Fields.FindField("Diameter")));

                                            }

                                        }

                                        waterMainExists = true;

                                        updated = true;

                                        //update the feature so it can calculate the case 1 properly in the next step

                                        fCursor.UpdateFeature(feature);

                                        break;

                                    case 1:

                                        feature.set_Value(feature.Fields.FindField("Diameter2"), waterMain.get_Value(waterMain.Fields.FindField("Diameter")));

                                        //if Diam1 = current WM Diam, and it's not a service connection or generic node

                                        //then make it a sleeve

                                        if ((feature.get_Value(feature.Fields.FindField("Diameter1")).ToString() == waterMain.get_Value(waterMain.Fields.FindField("Diameter")).ToString()) && ((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 6) && ((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 9))

                                            feature.set_Value(feature.Fields.FindField("SubTypeCD"), 7);

                                        //if Diam1 is not = to WM Diam, and it's not a service connection or generic node

                                        //then make it a reducer

                                        if ((feature.get_Value(feature.Fields.FindField("Diameter1")).ToString() != waterMain.get_Value(waterMain.Fields.FindField("Diameter")).ToString()) && ((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 6) && ((int)feature.get_Value(feature.Fields.FindField("SubTypeCD")) != 9))

                                            feature.set_Value(feature.Fields.FindField("SubTypeCD"), 5);

                                        break;

                                    case 2:

                                        //if it gets this far, then it has to be a Tee

                                        feature.set_Value(feature.Fields.FindField("Diameter3"), waterMain.get_Value(waterMain.Fields.FindField("Diameter")));

                                        feature.set_Value(feature.Fields.FindField("SubTypeCD"), 8);

                                        break;

                                    case 3:

                                        //if it gets this far, then it has to be a Cross

                                        feature.set_Value(feature.Fields.FindField("Diameter4"), waterMain.get_Value(waterMain.Fields.FindField("Diameter")));

                                        feature.set_Value(feature.Fields.FindField("SubTypeCD"), 3);

                                        break;

                                }

                                if (contractNumber == true)

                                    feature.set_Value(feature.Fields.FindField("CONTRACTNO"), waterMain.get_Value(waterMain.Fields.FindField("CONTRACTNO")));

                                if (installDate == true)

                                    feature.set_Value(feature.Fields.FindField("INSTALLDATE"), waterMain.get_Value(waterMain.Fields.FindField("INSTALLDATE")));

                                if (dataSource == true)

                                    feature.set_Value(feature.Fields.FindField("DATASOURCE"), waterMain.get_Value(waterMain.Fields.FindField("DATASOURCE")));

                                if (lifecycleStatus == true)

                                    feature.set_Value(feature.Fields.FindField("LifecycleStatus"), waterMain.get_Value(waterMain.Fields.FindField("LifecycleStatus")));

                                waterMainCounter++;

                                waterMain = selectedWaterMain.NextFeature();

                            }

                            selectedWaterService = SelectByLocation(waterServiceLayer, (IPoint)feature.Shape);

                            waterService = selectedWaterService.NextFeature();

                            //This will update Fittings on WaterService

                            while (waterService != null)

                            {

                                IPoint thePoint = (IPoint)feature.Shape;

                                IPolyline5 theLine = (IPolyline5)waterService.Shape;

                                if (waterMainExists == false)   //if no Water Main was intersected, then it must be a plug or service connection

                                {

                                    feature.set_Value(feature.Fields.FindField("Diameter1"), waterService.get_Value(waterService.Fields.FindField("Diameter")));

                                    if ((thePoint.X == theLine.FromPoint.X && thePoint.Y == theLine.FromPoint.Y) || (thePoint.X == theLine.ToPoint.X && thePoint.Y == theLine.ToPoint.Y))

                                    {

                                        feature.set_Value(feature.Fields.FindField("SubTypeCD"), 4);

                                        if (theLine.FromPoint.X == thePoint.X && theLine.FromPoint.Y == thePoint.Y)

                                            feature.set_Value(feature.Fields.FindField("Rotation"), CalculateAngle(theLine.ToPoint, theLine.FromPoint) * -1);

                                        else

                                            feature.set_Value(feature.Fields.FindField("Rotation"), CalculateAngle(theLine.FromPoint, theLine.ToPoint) * -1);

                                    }

                                    else

                                        feature.set_Value(feature.Fields.FindField("SubTypeCD"), 6);

                                }

                                else    //if there is a WaterMain, then it must be a Service Connection

                                {

                                    feature.set_Value(feature.Fields.FindField("Diameter2"), feature.get_Value(feature.Fields.FindField("Diameter1")));

                                    feature.set_Value(feature.Fields.FindField("Diameter3"), waterService.get_Value(waterService.Fields.FindField("Diameter")));

                                    //if the water service is a res_service then create a res_serviceConnection

                                    //else make a regular service connection

                                    if ((int)waterService.get_Value(waterService.Fields.FindField("SubTypeCD")) == 3)

                                        feature.set_Value(feature.Fields.FindField("SubTypeCD"), 10);

                                    else

                                        feature.set_Value(feature.Fields.FindField("SubTypeCD"), 6);

                                }

                                if (contractNumber == true)

                                    feature.set_Value(feature.Fields.FindField("CONTRACTNO"), waterService.get_Value(waterService.Fields.FindField("CONTRACTNO")));

                                if (installDate == true)

                                    feature.set_Value(feature.Fields.FindField("INSTALLDATE"), waterService.get_Value(waterService.Fields.FindField("INSTALLDATE")));

                                if (dataSource == true)

                                    feature.set_Value(feature.Fields.FindField("DATASOURCE"), waterService.get_Value(waterService.Fields.FindField("DATASOURCE")));

                                if (dataSource == true)

                                    feature.set_Value(feature.Fields.FindField("LifecycleStatus"), waterService.get_Value(waterService.Fields.FindField("LifecycleStatus")));

                                waterService = selectedWaterService.NextFeature();

                                updated = true;

                            }

                            //Update the feature and move to next feature

                            if (updated == true)

                            {

                                fCursor.UpdateFeature(feature);     *****THIS IS WHERE THE ERROR OCCURS

                                updatedFeatures++;

                            }

                            feature = fCursor.NextFeature();

                            //set these to null before moving to the next Fitting

                            selectedWaterService = null;

                            waterService = null;

                            selectedWaterMain = null;

                            waterMain = null;

                        }

                    }

                }

                #endregion

0 Kudos
GregMcQuat
New Contributor III

Try using the ComReleaser class to manage the lifetime of the update FeatureCursor. The ComReleaser will release the cursor objects when it goes out of scope and decrement the number of Runtime Callable Wrappers (RCWs). You can read more on COM Interop and RCWS in the documentation; I'm sure that my use of terms is not quite right.

What happens is that as you open up new cursors, the number of RCWs starts to add up and that's when things go awry. So it makes sense that it would run a few times and then fail and that when you restart it works fine again.

//create a cursor for the fittings

                        ICursor cursor;

                        selSet.Update(null, false, out cursor);

                        using (ComReleaser comReleaser = new ComReleaser())

                        {

                             IFeatureCursor fCursor = (IFeatureCursor)cursor;

                              comReleaser.ManageLifetime(fCursor);

                              // ... everything until you are done with the cursor;

                         }

0 Kudos
BBulla
by
Occasional Contributor

Hi Greg,

Thanks for the idea.  I've adjusted my code as you stated, but it's not making any difference.  I still get the same error at the same line of code.

I run this same bit of code for other features too;  hydrants, valves, etc, but I never get this same error in those blocks of code.  Only when doing the fittings features.  Even if I only select a single fitting, the same error happens the first time 'round.

I'm certain the error is happening with that Fittings code block, but I have no idea what is causing it.

Any other ideas??

0 Kudos
GregMcQuat
New Contributor III

I couldn't find a match for the error code you had posted, what other information is there about the error? If we can match it to an ESRI error code we might be able to narrow it down further.

Are you managing / releasing all the other cursors here as well (e.g. selectedWaterMain, selectedWaterService)?

You say that this is with one particular feature... is there anything strange about the geometry? If you make a new feature class with only that feature, do you still get the error?

0 Kudos
BBulla
by
Occasional Contributor

Hi Greg,

Other than doing this (see below) at the end of each code block, I am not doing anything else to 'manage' the cursors:

//set these to null before moving to the next Fitting

                                selectedWaterService = null;

                                waterService = null;

                                selectedWaterMain = null;

                                waterMain = null;

Our production environment is SDE (SQL Server), and I'm use a File GDB for testing.  The same problem appears in either.

Here is the exact error:

ERROR.JPG

0 Kudos
GregMcQuat
New Contributor III

No match for that error code - I still think that this is an RCW thing but hard to tell without seeing it run through in debug mode.

Note that setting cursor references to null doesn't always release the references right away. Either use the ComReleaser class by adding each cursor to the comReleaser.ManageLifetime(any_cursor):

//More than one WaterMain could be returned!!!

selectedWaterMain = SelectByLocation(waterMainLayer, (IPoint)feature.Shape);

comReleaser.ManageLifetime(selectedWaterMain);

and

selectedWaterService = SelectByLocation(waterServiceLayer, (IPoint)feature.Shape);

comReleaser.ManageLifetime(selectedWaterService);

or explicitly call Marshal.ReleaseComObject(cursor) where you are setting them to null, e.g.:

int wsCount = Marshal.ReleaseComObject(selectedWaterService);

System.Diagnostics.Debug.WriteLine(wsCount.ToString() + " water service references remaining."); //  Just to see how many are remaining.

One more thing I noticed is that in case 0, UpdateFeature is called as well. I'm not sure if that would have anything to do with it...

This looks so much like a case of a reference to a feature cursor not being released before you open another one up. If explicitly releasing them doesn't work, I would start looking at how you are opening the workspaces ..( ArcObjects 10 .NET SDK Help )

0 Kudos
BBulla
by
Occasional Contributor

I will step through the code a bit more and see if something else is happening that I'm not quite catching.

I'll keep you posted.

0 Kudos