+ Reply to Thread
Results 1 to 20 of 20

Thread: What's Up with ComReleaser? Is it really working?

  1. #1
    David Plume
    Join Date
    Apr 2010
    Posts
    25
    Points
    1
    Answers Provided
    0


    0

    Default What's Up with ComReleaser? Is it really working?

    Hi Everyone,

    We're using the ComReleaser object in .NET to free up cursors, feature cursors and a few other COM objects in various functions through out our project.

    The following code shows a typical implementation. We're finding that a number errors are being thrown in our code when it is running suggesting that the releaser is not working the way we think that i might be.

    I am under the impression that the ComReleaser object "knows" to clean up as it gets to the "End Using" statement. Apparently not?

    Errors that we're seeing are:

    COM object that has been separated from its underlying RCW cannot be used.
    Too many tables open.
    Attempted to read or write to protected memory.

    Bottom line, what is the best way to ensure that COM objects are cleaned up appropriately?

    Thanks
    D


    Here is a typical implementation:

    Using pComReleaser As ComReleaser = New ComReleaser

    Try

    Dim pBreakptFC As ESRI.ArcGIS.Geodatabase.IFeatureClass
    Dim pQF As ESRI.ArcGIS.Geodatabase.IQueryFilter

    Dim pTable As ESRI.ArcGIS.Geodatabase.ITable = Nothing
    pComReleaser.ManageLifetime(pTable)

    Dim pFeatCursor As ESRI.ArcGIS.Geodatabase.IFeatureCursor = Nothing
    pComReleaser.ManageLifetime(pFeatCursor)

    Dim pFeat As ESRI.ArcGIS.Geodatabase.IFeature

    pBreakptFC = GetBreakptClass(MXApp)
    pFeatCursor = Nothing

    If Not pBreakptFC Is Nothing Then

    pTable = pBreakptFC
    pQF = New ESRI.ArcGIS.Geodatabase.QueryFilter

    pQF.WhereClause = FIELD_PERIMETERID & " = " & CStr(PerimFeat.OID)

    If pTable.RowCount(pQF) > 0 Then

    pFeatCursor = pBreakptFC.Search(pQF, False)
    pFeat = pFeatCursor.NextFeature
    Do While Not pFeat Is Nothing
    pFeat.Delete()
    pFeat = pFeatCursor.NextFeature
    Loop

    End If

    End If

    pBreakptFC = Nothing
    pQF = Nothing
    pTable = Nothing
    pFeat = Nothing
    pFeatCursor = Nothing

    Catch ex As Exception
    LogError(LIBRARY_NAME, ex.ToString())
    End Try

    End Using

  2. #2
    Neil Clemmons

    Join Date
    Apr 2010
    Posts
    894
    Points
    570
    Answers Provided
    94


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    I don't think you should be setting the variables to Nothing before you exit the Using block. From what I understand, the ComReleaser class is handling the calls to ReleaseComObject that are necessary to release any resources being used by the object instances. You can't call ReleaseComObject on an object that has been set to Nothing so I imagine you are preventing the ComReleaser class from doing what it needs to do. I personally haven't used the ComReleaser class myself so I'm not sure how well it works. I prefer to release the objects myself by calling FinalReleaseComObject on them as needed.
    Neil Clemmons
    Geographic Information Services, Inc.
    http://www.gisinc.com

    Check out our blog:
    http://blog.gisinc.com

  3. #3
    James MacKay
    Join Date
    Dec 2009
    Posts
    45
    Points
    0
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Dim pFeatCursor As ESRI.ArcGIS.Geodatabase.IFeatureCursor = Nothing
    pComReleaser.ManageLifetime(pFeatCursor)
    You have to provide the ComReleaser with references to the objects you want to manage. The approach above is basically "managing" a null reference. You need to move your ManageLifetime calls to a place like this:

    Dim featCursor as IFeatureCursor =featureClass.Search(...)
    comReleaser.ManageLifetime(featCursor)

    Likewise, since you're using a non-recycling cursor, every row retrieved from the cursor is a new object, which means every row should be managed as well.

    One thing to avoid is managing a RCW that you plan on using outside the scope of the using block. This error - "COM object that has been separated from its underlying RCW cannot be used." - indicates that's happening. Keep in mind that when you perform an explicit cast, for example from IFeatureClass to ITable, you're still referencing the same RCW.

    Cheers,
    James

  4. #4
    Kirk Kuykendall

    Join Date
    Oct 2009
    Posts
    295
    Points
    3
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Likewise, since you're using a non-recycling cursor, every row retrieved from the cursor is a new object, which means every row should be managed as well.
    I've never noticed any ill side effects in apps (or extensions) that do not call ReleaseCOMObject on IFeature/IRow references - has anyone else?

    For example if I have methods that return generic lists of IFeatures (List<IFeature>) and releases the cursor when its done, do I really need to call ReleaseCOMObject on each feature when they are no longer in use?

    Can anyone show me code where failing to call ReleaseCOMObject on an IFeature/IRow causes an exception?

    Thanks!
    Kirk Kuykendall
    AmberGIS Programming Services
    Now answering questions at http://gis.stackexchange.com

  5. #5
    James MacKay
    Join Date
    Dec 2009
    Posts
    45
    Points
    0
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Kirk,

    It definitely isn't as big of a deal as managing cursors; I've never seen a case where it throws an exception. It can help performance though, and ensures that things behave as expected in some workflows. One that comes to mind is trying to delete local geodatabase after having used a non-recycling cursor. Granted, that's not a common workflow, but it's one that does happen on occasion.

    If a cursor is recycling, typically I use this kind of pattern:

    Code:
    using (ComReleaser comReleaser = new ComReleaser())
    {
      ICursor cursor = table.Search(null, true);
      comReleaser.ManageLifetime(cursor);
      IRow row = null;
      Boolean isManaged = false;
      while ((row = cursor.NextRow()) != null)
      {
        if (!isManaged)
        {
          comReleaser.ManageLifetime(row);
          isManaged = true;
        }
    
        // Use the row...
      }
    }
    Whereas for non-recycling cursors I generally do something like this:

    Code:
    using (ComReleaser comReleaser = new ComReleaser())
    {
      ICursor cursor = table.Search(null, false);
      comReleaser.ManageLifetime(cursor);
      IRow row = null;
      while ((row = cursor.NextRow()) != null)
      {
        try
        {
          // Use the row...
        }
        catch (Exception exc)
        {
          // Handle the exception...
        }
        finally
        {
          Marshal.ReleaseComObject(row);
        }
      }
    }
    ... with the exception being the odd case where I have to use references to rows other than the last one fetched (like the List<IFeature> scenario you mentioned). In those cases I manage the rows using the ComReleaser.

    (In the non-recycling case I've also used a nested ComReleaser at times...)

    Cheers,
    James
    Last edited by mackayj80; 05-12-2010 at 07:35 AM.

  6. #6
    Kirk Kuykendall

    Join Date
    Oct 2009
    Posts
    295
    Points
    3
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Hey James, thanks for the quick response.

    Would you see any problems in having an architecture where a Data Access Layer (DAL) that returns a BindingList of Business Objects (BO's) such that:
    • the BO maintains a strong reference to a IObject (passed as constructor arg)
    • each field in IObject.Fields maps to a BO getter/setter that calls IObject.get_Value/set_Value.
    • BO implements IDisposable, and calls ReleaseCOMObject on the contained IRow in Dispose()
    • DAL calls ReleaseCOMObject on ICursor after returning BindingList<BO>.

    Thanks again,
    Kirk Kuykendall
    AmberGIS Programming Services
    Now answering questions at http://gis.stackexchange.com

  7. #7
    James MacKay
    Join Date
    Dec 2009
    Posts
    45
    Points
    0
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Kirk,

    I've done similar things in the past to allow attribute editing through the .NET PropertyGrid and it generally worked okay as long as all the IDisposable-ish plumbing's there, which it sounds like you've got. You might run into trouble for strange cases like the one I mentioned above - deleting a local geodatabase while rows remain unreleased - but I haven't seen too many other problems. One thing that comes to mind is if you allow the creation of rows through your BOs and you use a feature buffer under a hood you'll want to dispose of that feature buffer as well.

    Cheers,
    James

  8. #8
    David Plume
    Join Date
    Apr 2010
    Posts
    25
    Points
    1
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Neil, James and Kirk,

    Your replies have been very helpful, thank you -- A tip of my hat to the masters!

    For the sake of my own understanding and the thread then, regarding RCWs I am left wondering:

    see:
    http://edndoc.esri.com/arcobjects/9....f16d5ce8c0.htm,
    and
    http://msdn.microsoft.com/en-us/libr...comobject.aspx

    Reading at MSDN, I see that "Every time a COM interface pointer enters the common language runtime (CLR), it is wrapped in an RCW." I take this to mean, essentially, that all our our ArcObjects in .NET have a corresponding RCW.

    Furthermore MSDN says: Therefore, use the ReleaseComObject only if it is absolutely required. If you want to call this method to ensure that a COM component is released at a determined time, consider using the FinalReleaseComObject method instead. FinalReleaseComObject will release the underlying COM component regardless of how many times it has re-entered the CLR. The internal reference count of the RCW is incremented by one every time the COM component re-enters the CLR. Therefore, you could call the ReleaseComObject method in a loop until the value returned is zero. This achieves the same result as the FinalReleaseComObject method.

    So: it seems that a good rule of thumb would be -- if you explicitly know that you should release the object, such as a cursor, then do it otherwise leave things to the garbage collector.

    So consequently I'm wondering, is there a rule of thumb to help one detect which objects we should consider for explicit release, either by ReleaseComObject, FinalReleaseComObject or alternatively, ComReleaser?

    Best Regards
    David

  9. #9
    James MacKay
    Join Date
    Dec 2009
    Posts
    45
    Points
    0
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    David,

    Unfortunately it isn't a great rule of thumb since you have to be familiar with the implementation of the COM classes you're using (or go through trial and error), but if an object ties up resources or locks, I manage/release it. Also, when I'm in doubt about an object I release it... I'm not really sure why MSDN recommends leaving objects to the garbage collector, other than it keeps your code from getting cluttered up with potentially unnecessary release lines, or that prematurely releasing an object could leave you with a trashed RCW.

    Within the ArcObjects Geodatabase library, the types I would suggest managing/releasing are:
    • Cursors
    • Datasets, i.e. tables, feature classes, feature datasets, rel. classes (but excluding name objects)
    • Workspaces (inc. versions, if you're connecting to multiple versions of an enterprise GDB at once)
    • Rows, features and attributed relationships
    • Row buffers and feature buffers
    It's important to be aware of cases where "unique instancing" occurs, however. For example, if you connect to an ArcSDE workspace twice - once with a set of connection properties and once with an SDE connection file - assuming the username/password and version are the same, you'll be handed a single COM object and your .NET references will share a single RCW. In these kinds of situations you'll want to use ReleaseComObject rather than FinalReleaseComObject or the ComReleaser (although in a lot of the code I write I use a ComReleaser with workspaces, since I'm often only working with one workspace and don't have to worry about this). Other cases you have to look out for are:
    • Rows/features in an edit session - Being in an active geodatabase edit session guarantees that any time you retrieve a feature, whether through GetFeature or a cursor, only one instance of that feature will be created. If you call IFeature.GetFeature(1) and pull a feature from a cursor that had a where clause of "OBJECTID = 1", you'll get the same feature COM object and the same RCW.
    • Datasets - Dataset references are pooled in their workspace. If you try to open a feature class that was previously opened, you'll be handed a reference to the existing instance. Note that this is not true across different versions of an enterprise GDB.
    Cheers,
    James
    Last edited by mackayj80; 05-12-2010 at 09:47 AM.

  10. #10
    Neil Clemmons

    Join Date
    Apr 2010
    Posts
    894
    Points
    570
    Answers Provided
    94


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Quote Originally Posted by kirkktx View Post
    I've never noticed any ill side effects in apps (or extensions) that do not call ReleaseCOMObject on IFeature/IRow references - has anyone else?

    For example if I have methods that return generic lists of IFeatures (List<IFeature>) and releases the cursor when its done, do I really need to call ReleaseCOMObject on each feature when they are no longer in use?

    Can anyone show me code where failing to call ReleaseCOMObject on an IFeature/IRow causes an exception?

    Thanks!
    Hi Kirk,
    I've never seen any exceptions thrown but in one of our applications a temporary geodatabase was being created, used, then deleted. The code that deleted the geodatabase failed any time the user tried to repeat the same workflow without first closing the dialog and re-opening it (which we didn't want them to have to do). I went over all of the code with a fine toothed comb several times releasing every object I could find to no avail. I didn't bother with feature and row objects inside of loops because I was releasing the objects outside of the loops. The last thing I tried was releasing the feature and row objects inside the loop because I had seen an ESRI example where it was being done and all of a sudden the geodatabase could be deleted without any problems. Under normal circumstances I don't think you'll run into any problems if you don't release the objects but in specific cases like mine it's necessary. Hope this helps.
    Neil Clemmons
    Geographic Information Services, Inc.
    http://www.gisinc.com

    Check out our blog:
    http://blog.gisinc.com

  11. #11
    Kirk Kuykendall

    Join Date
    Oct 2009
    Posts
    295
    Points
    3
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Hey Neil -

    Thanks for responding. This is helpful.

    I'm starting to see how this would be a hard thing to track down. I guess instead of keeping a reference to the IFeature, I could hang onto its' OID, then have a method in the DAL that:
    • puts the BO's into a Dictionary<int,BO>
    • Gets a cursor by passing the array of Dictionary keys to IGeoDatabaseBridge2.GetFeatures
    • loops through the cursor, synching each feature with Dictionary[IFeature.oid]
    • Release feature
    • Release Cursor
    Kirk Kuykendall
    AmberGIS Programming Services
    Now answering questions at http://gis.stackexchange.com

  12. #12
    David Plume
    Join Date
    Apr 2010
    Posts
    25
    Points
    1
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Thanks again everyone, I'm finding the whole conversation very instructive and hope that others will also find it so in the future.

    Here, in our current project, It seems to me that our best strategy now will be to change our coding to the patterns as James suggested, still using ComReleaser. Furthermore we'll review our code to confine the use of the releaser to the basics that James also cited.

    Best Regards.
    Last edited by david.plume; 05-13-2010 at 11:04 AM.

  13. #13
    David Plume
    Join Date
    Apr 2010
    Posts
    25
    Points
    1
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    For the sake of the thread, the following links provide a bit more insight into what is happening relative to releasing COM objects and the role of the Using block.

    Bottom line, my take is this: unlike VB6, setting COM objects = nothing doesn't really buy very much. When your functions and subs go out of scope your objects and their respective wrappers lurk around in object purgatory waiting for the garbage collector to clean them up. Generally speaking, this isn't a problem but for some resources it is best to explicitly force the release so one doesn't tie up limited resources such as tables.

    Hence, Marshal.ReleaseComObject(pMyCOMObject) --> I think of this sort of like pMyCOMObject = nothing in VB6

    See also:
    http://www.getdotnetcode.com/gdncsto...sWithVbNet.htm

    For those interested in the ComReleaser and the role of the Using statement see:

    http://msdn.microsoft.com/en-us/library/htd05whh.aspx

    In part from that article:

    Sometimes your code requires an unmanaged resource, such as a file handle, a COM wrapper, or a SQL connection. A Using block guarantees the disposal of one or more such resources when your code is finished with them. This makes them available for other code to use.
    Managed resources are disposed of by the .NET Framework garbage collector (GC) without any extra coding on your part. You do not need a Using block for managed resources. However, you can still use a Using block to force the disposal of a managed resource instead of waiting for the garbage collector.
    A Using block has three parts: acquisition, usage, and disposal.
    • Acquisition means creating a variable and initializing it to refer to the system resource. The Using statement can acquire one or more resources, or you can acquire exactly one resource before entering the block and supply it to the Using statement. If you supply resourceexpression, you must acquire the resource before passing control to the Using statement.
    • Usage means accessing the resources and performing actions with them. The statements between Using and End Using represent the usage of the resources.
    • Disposal means calling the Dispose method on the object in resourcename. This allows the object to cleanly terminate its resources. The End Using statement disposes of the resources under the Using block's control.
    Please feel free to comment with suggestions or corrections if I've missed something. Otherwise, I hope this helps others sort out this important topic and is helpful to others.

    D

  14. #14
    Kirk Kuykendall

    Join Date
    Oct 2009
    Posts
    295
    Points
    3
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Careful with FinalReleaseCOMObject though. What might not be apparent is that if the same featureclass is opened in two different places, calling FinalReleaseComObject on one variable can cause an "object disconnected from its underlying com object" exception when the other variable is used.
    ReleaseComObject just decrements by one, so no exception is thrown.
    Code below prints "same object".

    Code:
    try
    {
        IFeatureWorkspace fws = (IFeatureWorkspace)OpenWS(@"D:\Projects\SAWS\data\March02Test1.gdb");
        IFeatureClass fc1 = fws.OpenFeatureClass("SAWS_ADDRESSES");
        IFeatureClass fc2 = fws.OpenFeatureClass("SAWS_ADDRESSES");
        if (fc1 == fc2)
            Debug.Print("same object");
        else
            Debug.Print("different object");
    
        //Marshal.FinalReleaseComObject(fc1); 
        Marshal.ReleaseComObject(fc1);
        Debug.Print("{0} records", fc2.FeatureCount(null));
    }
    catch (Exception ex)
    {
        Debug.Print(ex.Message);
    }
    Apparently ComReleaser calls FinalReleaseComObject when it disposes:
    Code:
    try
    {
        IFeatureWorkspace fws = (IFeatureWorkspace)OpenWS(@"D:\Projects\SAWS\data\March02Test1.gdb");
        IFeatureClass fc1 = fws.OpenFeatureClass("SAWS_ADDRESSES");
    
        using (ComReleaser comReleaser = new ComReleaser())
        {
            IFeatureClass fc2 = fws.OpenFeatureClass("SAWS_ADDRESSES");
            if (fc1 == fc2)
                Debug.Print("same object");
            else
                Debug.Print("different object");
            comReleaser.ManageLifetime(fc2);
            Debug.Print("{0} records", fc2.FeatureCount(null));
        }
        // next line throws exception ...
        Debug.Print("{0} records", fc1.FeatureCount(null));
    }
    catch (Exception ex)
    {
        Debug.Print(ex.Message);
    }
    This might be a hard bug to track down. I've never seen a case where failure to releasecomobject on a featureclass causes problems, so maybe releasing is not worth the risk.
    Last edited by kirkktx; 05-19-2010 at 07:15 PM.
    Kirk Kuykendall
    AmberGIS Programming Services
    Now answering questions at http://gis.stackexchange.com

  15. #15
    David Plume
    Join Date
    Apr 2010
    Posts
    25
    Points
    1
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Thanks again Kirk,

    Yes, it seems like, unlike the old days working in MFC C++, the best policy is to leave your objects alone; trying to explicitly clean them up can cause more harm than good. This confirms the adage: no good deed goes unpunished!

    I found the following link that seems to confirm this and offers a bit of insight into how to think about COM objects and an approach to managing them:

    Please see:

    http://social.msdn.microsoft.com/For...7-37e671a37279

    From that link:

    Hi Gary,

    Yes, managing Runtime Callable Wrappers (RCWs) can be tricky. However, depending on what you are doing, you may not need to manage them at all. As you know RCW's will hold a reference to their underlying COM object. When the RCW's finalizer is run, they will release their reference.

    So when do RCW's get finalized? At a minimum, they get finalized when the AppDomain is torn down. During teardown, all objects are collected regardless of whether they are rooted. Before AppDomain teardown, there are two other ways that RCWs could be finalized. The first would be when the objects are no longer rooted and therefore become eligable for collection. If the GC0 heap fills up, a garbage collection will occur, and those RCWs that are eligible will be finalized. The second way finalization can happen is if you explicitly force a garbage collection by calling GC.Collect. If you do that, any RCWs eligible for collection will be finalized. By calling WaitForPendingFinalizers, you ensure that the finalizer thread has finalized all of the objects in the queue before your thread continues.

    In addition, as you are aware, you can deterministically force the RCWs to release their reference by calling either Marshal.ReleaseComObject or Marshal.FinalReleaseComObject. The difference between the two calls is this. RCW's have a reference count of their own which gets bumped when the IUnknown is marshalled across AppDomain boundaries. Calling Marshal.ReleaseComObject will only actually release when the RCW reference count goes to zero--otherwise it has the effect of decrementing this internal count. Marshal.FinalReleaseComObject, however, will call the release regardless of what the RCW reference count is.

    So the real question is when do you need to be explicit about enforcing RCW finalization or calling Marshal.Final/ReleaseComObject? The answer is whenever you can't afford to wait for GC to happen (knowing that it might not occur until shutdown). The two most likely reasons would be if the object is holding onto a resource (such as a file handle) or if memory pressure caused by keeping the object(s) alive was hurting performance.

    If you know you are going to need to deterministically control the RCW cleanup, the best thing to do is to keep them isloated (and not pass them around) so that you can just call Marshal.FinalReleaseComObject when you are done with them. As long as you can guarantee that you won't try to call into the RCW again after you make that call, then this is a safe approach. This is better than trying to force a GC yourself since doing that will promote any existing objects in the heap to later generations which will mean they will potentially hang around in memory longer than they would have otherwise.

    That said, the ideal is to do nothing and just let the system take care of everything. Managing this stuff on your own is harder, so be sure you understand your reasons for doing so before you take that on.

    Sincerely,

    Geoff Darst
    Microsoft VSTO Team
    Regards
    David

  16. #16
    Domenico Ciavarella

    Join Date
    Mar 2010
    Posts
    2,678
    Points
    458
    Answers Provided
    71


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    here there is a wrapper class for finalization com library

    http://msdn.microsoft.com/en-us/magazine/cc163316.aspx
    Studio A&T srl

    Domenico Ciavarella

    ESRI Certified
    Enterprise Geodatabase Management Associate 10.1
    Web Application Developer Associate 10.1

    My ArcGIS.com

    Blog: NicoGis

  17. #17
    Fridjof Schmidt
    Join Date
    May 2010
    Posts
    29
    Points
    7
    Answers Provided
    1


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Quote Originally Posted by kirkktx View Post
    Apparently ComReleaser calls FinalReleaseComObject when it disposes [...]
    This might be a hard bug to track down. I've never seen a case where failure to releasecomobject on a featureclass causes problems, so maybe releasing is not worth the risk.
    Kirk,

    Apparently this is not a bug, although I thought so too. According to the documentation (http://resources.esri.com/help/9.3/A...eLifetime.html) this is the expected behavior:
    "Marshal.ReleaseComObject will be called during the disposal process on this Interface pointer until its RCW reference count becomes 0"

    I wonder why ESRI implemented it that way, because, as you said, when using the same feature class in two different places, and its lifetime is being managed in one place, it may fail in the other.
    Fridjof Schmidt
    GIS Software Developer
    www.frischgis.de

  18. #18
    Paul Bartschi
    Join Date
    Apr 2010
    Posts
    54
    Points
    0
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    I am trying to use comReleaser. What library do I have to reference to get it to show up? When I use the following line:
    using (ComReleaser comReleaser = new ComReleaser())
    comReleaser is not recognized. Searching help does not reveal the library to reference. Can anyone help? Thanks!

  19. #19
    Ken Buja

    Join Date
    Jan 2010
    Posts
    1,212
    Points
    874
    Answers Provided
    151


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    It's in ESRI.ArcGIS.ADF.ComReleaser. In ArcGIS 10, you have to add the reference ESRI.ArcGIS.ADF.Connection.Local
    Ken Buja
    Silver Spring, MD

  20. #20
    Paul Bartschi
    Join Date
    Apr 2010
    Posts
    54
    Points
    0
    Answers Provided
    0


    0

    Default Re: What's Up with ComReleaser? Is it really working?

    Thanks Ken

+ Reply to Thread

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts