Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I'm trying to run some operations (functions) in seperate threads so that the UI is not blocked. One of this operation is the generation of a feature class copy from an existing feature class into a temporary in memory feature class (used for processing later).

In cases where you must pass ArcObjects components from the main thread into a worker thread, serialize the object into a string, pass the string to the target thread, and deserialize the object back.

I'm using XMLPersistedObject to pass an serialized IName object to the copy function. The FeatureClass is then opened via IName.Open() and copied (structure + rows) into a temporary Workspace (created via the InMemoryWorkspaceFactory). The copied FeatureClass is then serialized back into an IName object again an returned to the main thread.

There IName.Open() fails with a generic COM Error (-2147467259).

The whole thing works when I use a different Workspace (e.g. ScratchWorkspaceFactory), but the copy process (see code below - maybe this can be improved?) and subsequent operations take longer than.

So, is there a possibility to share temporary FeatureClasses between Threads?

public class DataManagement
{
    #region Public Methods and Operators

    public static string CreateAndCopyToTemporaryFeatureWorkspace(string name)
    {
        IFeatureClass featureClass = ArcObjectHelper.CreateNameFromXML(name).Open();

        return ((IDataset)CreateAndCopyToTemporaryFeatureWorkspace(featureClass)).FullName.ToXMLString();
    }

    #endregion

    #region Methods

    private static IFeatureClass CreateAndCopyToTemporaryFeatureWorkspace(IFeatureClass featureClass)
    {
        IFeatureClass localFeatureClass = featureClass;

        // Copy FeatureClass structure
        IFeatureClass featureClassNew = CreateTemporaryFeatureClassCopy(localFeatureClass);

        // Copy rows
        using (ComReleaser comReleaser = new ComReleaser())
        {
            IFeatureCursor featureCursor = localFeatureClass.Search(null, false);
            comReleaser.ManageLifetime(featureCursor);

            IFeature feature;

            IFeatureBuffer featureBuffer = featureClassNew.CreateFeatureBuffer();
            comReleaser.ManageLifetime(featureBuffer);

            IFeatureCursor insertCursor = featureClassNew.Insert(true);
            comReleaser.ManageLifetime(insertCursor);

            while ((feature = featureCursor.NextFeature()) != null)
            {
                featureBuffer.Shape = feature.Shape;

                for (int i = 0; i < localFeatureClass.Fields.FieldCount; i++)
                {
                    if (localFeatureClass.Fields.Field[i].Type == esriFieldType.esriFieldTypeOID)
                    {
                        continue;
                    }

                    featureBuffer.Value[i] = feature.Value[i];
                }

                insertCursor.InsertFeature(featureBuffer);
            }

            featureCursor.Flush();
        }

        return featureClassNew;
    }

    private static IFeatureClass CreateTemporaryFeatureClassCopy(IFeatureClass featureClass)
    {
        IWorkspaceFactory workspaceFactory = new InMemoryWorkspaceFactory();
        IFeatureWorkspace featureWorkspace = ((IName)workspaceFactory.Create("", "InMemoryWorkspace", null, 0)).Open();

        IFields fields = new Fields();
        IFieldsEdit fieldsEdit = (IFieldsEdit)fields;
        fieldsEdit.FieldCount_2 = featureClass.Fields.FieldCount;

        for (int i = 0; i < featureClass.Fields.FieldCount; i++)
        {
            if (featureClass.Fields.Field[i].Type == esriFieldType.esriFieldTypeOID)
            {
                IField field = new Field();
                IFieldEdit fieldEdit = (IFieldEdit)field;
                fieldEdit.Name_2 = "ObjectID";
                fieldEdit.Type_2 = esriFieldType.esriFieldTypeOID;
                fieldsEdit.Field_2[i] = field;
            }
            else
            {
                IClone clone = (IClone)featureClass.Fields.Field[i];
                IField clonedField = (IField)clone.Clone();
                fieldsEdit.Field_2[i] = clonedField;
            }
        }

        IUID uid = featureClass.CLSID;

        Random random = new Random((int)DateTime.Now.Ticks);

        return featureWorkspace.CreateFeatureClass(random.Next(1000000, 10000000).ToString(CultureInfo.InvariantCulture),
            fields, (UID)uid, null, esriFeatureType.esriFTSimple, "shape", "");
    }

    #endregion
}
share|improve this question
    
Not sure but I don't think in-memory feature class names can start with a number. –  blah238 Mar 17 '13 at 19:34
    
Did you try using activator.CreateInstance instead of new ? See discussion here. Also threads in isolation discussion here. –  Kirk Kuykendall Mar 18 '13 at 3:25
    
Using activater.CreateInstance doesn't change anything. "An InMemoryWorkspaceFactory is used to connect to a temporary workspace which is stored in memory. These workspaces are commonly used to hold the results of an analysis operation or to hold objects in memory before persisting them to disk. When the last reference to the workspace is released, the workspace is destroyed and the memory released." - guess the same happens to temporary FeatureClasses. –  Dresel Mar 18 '13 at 16:45
    
All arcobjects (as at 9.3.1) are STA (single thread) objects. You can use them on a separate thread but they must stay on the thread that they are created from and can't be passed between threads. Look up IXMLSerialize to pass objects over threads by converting to and from XML. –  Michael Miles-Stimson Oct 9 '13 at 2:45
    
"I'm using XMLPersistedObject to pass an serialized IName object to the copy function. The FeatureClass is then opened via IName.Open() and copied (structure + rows) into a temporary Workspace (created via the InMemoryWorkspaceFactory). The copied FeatureClass is then serialized back into an IName object again an returned to the main thread." - I am already serializing objects. –  Dresel Oct 9 '13 at 9:08
show 3 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.