Using ArcObjects as tool input


As discussed in the topic The role of geoprocessing in developing applications, one common misconception is that geoprocessing tools can only deal with pathname strings for feature data.  That is, tools are ‘pathname to pathname’ only.  This topic shows you how you can use interface pointers such as IFeatureClass, IName, workspace, spatial reference and other ArcObjects.
Using ArcObjects reference as tool input
What ArcObject can be passed to a parameter depends on the parameter of the tool. More specific information of a parameter can be found in the tool’s reference page – see Using a tool reference page for details.

IFeatureClass, ILayer, IName, IDataset objects can be used to define the input to any tool that accepts a feature class or feature layer.  Additionally, an IRasterDataset (see DecodeRasterLayer UnitTest in gptest8) object can be used as input to any tool that accepts a raster dataset or raster layer.  An IFeatureWorkspace can be passed if the parameter accepts a catalog path. An ITable or and IStandAloneTable can be used instead of a dbf or geodatabase table. An ISpatialReference object can be passed if the data type of the parameter is Coordinate System.
However, if a tool creates new output data then a path must be used. Refer to Using Catalog path in Desktop help for more information.

A tool that updates an existing dataset, such as the Append tool, can have the output dataset defined using an ArcObjects component, such as IFeatureClass because Append doesn’t have an output dataset – the dataset it is updating is an input to the tool.
In this example, the Buffer tool takes an IFeatureClass as input features. As the tool creates a new feature class, a catalog path must be used for output.
[C#]
public void IFeatureClassAsInput(IFeatureClass pFC, string buff_dist)
{
    IGeoProcessor2 gp = new GeoProcessorClass();
    gp.OverwriteOutput = true;
    IVariantArray parameters = new VarArrayClass();
    parameters.Add(pFC);
    parameters.Add(@"C:\temp\poitns_buff.shp");
    parameters.Add(buff_dist);
    gp.Execute("Buffer_analysis", parameters, null);
}
[VB.NET]
Public Sub IFeatureClassAsInput(ByVal pFC As IFeatureClass, ByVal dist As IGPLinearUnit)
    
    ' Create the geoprocessor
    Dim gp As IGeoProcessor2 = New GeoProcessor
    gp.OverwriteOutput = True
    
    ' Create variant array and populate with parameter values
    Dim parameters As IVariantArray = New VarArray
    parameters.Add(pFC)
    parameters.Add("C:\temp\Lakes_buff.shp")
    parameters.Add(dist)
    
    ' Execute the tool
    gp.Execute("Buffer_analysis", parameters, Nothing)
    
End Sub
In the next example, we have map document from which we get an ILayer and then join it to a ITable. For the field parameters you could pass IField objects instead of string field names.
[C#]
public void AddJoinWithILayerITable(string sMap, ITable pTable)
{
    IGeoProcessor2 gp = new GeoProcessorClass();
    IMapDocument pMapDoc = new MapDocumentClass();
    pMapDoc.Open(sMap, "");
    IMap pMap = pMapDoc.get_Map(0);
    ILayer pLayer = pMap.get_Layers(null, true).Next();
    IVariantArray parameters = new VarArrayClass();
    parameters.Add(pLayer);
    parameters.Add("BEAT"); // in_field
    parameters.Add(pTable);
    parameters.Add("BEAT"); // join_field
    gp.Execute("AddJoin_management", parameters, null);
}
[VB.NET]
Public Sub AddJoinWithILayerITable(ByVal sMap As String, ByVal pTable As ITable)
    
    Dim gp As IGeoProcessor2 = New ESRI.ArcGIS.Geoprocessing.GeoProcessor()
    
    Dim pMapDoc As IMapDocument = New MapDocument
    pMapDoc.Open(sMap, "")
    
    Dim pMap As IMap = pMapDoc.Map(0)
    
    Dim pLayer As ILayer = pMap.Layers(Nothing, True).Next()
    
    Dim parameters As IVariantArray = New VarArray
    parameters.Add(pLayer)
    parameters.Add("BEAT")
    parameters.Add(pTable)
    parameters.Add("BEAT")
    
    gp.Execute("AddJoin_management", parameters, Nothing)
    
    ' the resulting join persists only for the current session
    ' use CopyFeatures_management tool to save it on disk
    
End Sub
Although a newly created output must be passed as a catalog path, a parameter expecting a workspace can be populated with an IWorkspace object. In The following code, Create Feature Dataset tool  also accepts an ISpatialReference  object as input.
[C#]
public void createFeatureDataset(IWorkspace workspace, ISpatialReference spatialRef)
{
    try
    {
        IVariantArray parameters = new VarArrayClass();
        parameters.Add(workspace);
        parameters.Add("Rivers");
        parameters.Add(spatialRef);
        gp.Execute("CreateFeatureDataset_management", parameters, null);
    }
    catch (Exception ex)
    {
        object sev = null;
        string msgs = gp.GetMessages(ref sev);
    }
}
[VB.NET]
Public Sub createFeatureDataset(ByVal workspace As IWorkspace, ByVal spatialRef As ISpatialReference)
    
    Try
    
    Dim parameters As IVariantArray = New VarArray
    parameters.Add(workspace)
    parameters.Add("Rivers")
    parameters.Add(spatialRef)
    
    gp.Execute("CreateFeatureDataset_management", parameters, Nothing)
    
    Catch ex As Exception
    
    Dim sev As Object = Nothing
    Dim msgs As String = gp.GetMessages(sev)
    
    End Try
    
End Sub

in_memory workspace

You can use in_memory workspace for intermediate tool outputs. Avoid using in_memory workspace for large datasets as memory is always a limitation. See Using in_memory workspace for more information. Note that not every tool, for example Project tool, accepts in_memory as output workspace. Refer to tool’s reference page to make sure the tool allows in_memory workspace.
[C#]
public void InMemoryWorkspaceTest(IArray points)
{
    IGeoProcessor2 gp = new GeoProcessorClass();
    IGPUtilities3 util = new GPUtilitiesClass();
    gp.OverwriteOutput = true;
    IVariantArray parameters = new VarArrayClass();
    parameters.Add("in_memory");
    parameters.Add("Parks");
    parameters.Add("POINT");
    parameters.Add(@"C:\gpqa\mytools\append\wells.gdb\well_1a");
    IGeoProcessorResult result = (IGeoProcessorResult)gp.Execute(
        "CreateFeatureclass_management", parameters, null);
    IGPValue gpVal = result.GetOutput(0);
    string inmemfc = gpVal.GetAsText();
    IFeatureClass pFC = util.OpenFeatureClassFromString(inmemfc);
    IFeatureBuffer buff = pFC.CreateFeatureBuffer();
    IFeatureCursor cur = pFC.Insert(true);
    object featureOID;
    ESRI.ArcGIS.Geometry.IPoint pt;
    for (int i = 0; i < points.Count; i++)
    {
        pt = new ESRI.ArcGIS.Geometry.PointClass();
        pt = (Point)points.get_Element(i);
        buff.Shape = pt;
        featureOID = cur.InsertFeature(buff);
    }
    cur.Flush();
    parameters.RemoveAll();
    parameters.Add(result.GetOutput(0).GetAsText());
    parameters.Add(@"C:\sdk\data\testdata.gdb\in_mem_out");
    gp.Execute("CopyFeatures_management", parameters, null);
}
[VB.NET]
Public Sub InMemoryWorkspaceFeatures(ByVal points As IArray)
    Dim gp As IGeoProcessor2 = New ESRI.ArcGIS.Geoprocessing.GeoProcessor()
    Dim util As IGPUtilities3 = New GPUtilitiesClass()
    gp.OverwriteOutput = True
    Dim parameters As IVariantArray = New VarArray
    parameters.Add("in_memory")
    parameters.Add("Parks")
    parameters.Add("POINT")
    parameters.Add("C:\data\wells.gdb\wells")
    Dim result As IGeoProcessorResult2
    result = CType(gp.Execute("CreateFeatureClass_management", parameters, Nothing), IGeoProcessorResult2)
    'Dim gpVal As IGPValue = result.GetOutput(0)
    Dim inmemfc As String = gpVal.GetAsText()
    Dim pFC As IFeatureClass = util.OpenFeatureClassFromString(inmemfc)
    Dim buff As IFeatureBuffer = pFC.CreateFeatureBuffer()
    Dim cur As IFeatureCursor = pFC.Insert(True)
    Dim featureOID As Object
    Dim pt As ESRI.ArcGIS.Geometry.IPoint
    For i As Integer = 0 To points.Count - 1
        pt = New ESRI.ArcGIS.Geometry.Point()
        pt = CType(points.Element(i), ESRI.ArcGIS.Geometry.IPoint)
        buff.Shape = pt
        featureOID = cur.InsertFeature(buff)
    Next
    cur.Flush()
    parameters.RemoveAll()
    parameters.Add(result.GetOutput(0).GetAsText())
    parameters.Add("C:\data\output.gdb\in_mem_out")
    gp.Execute("CopyFeatures_management", parameters, Nothing)
End Sub

Using Feature Set and Record Set

Geoprocessing also provides Feature Set and Record Set data types to hold features and records in memory. The only use of Feature Set is to send features to a geoprocessing server. Using these types programmatically is complicated. A better option is to create an in_memory feature class using geoprocessing tools (such as Create Feature Class).
The following code example executes the BestPath service, on bdhost ArcGIS Server in the gp/Routing . The service has one parameter of Feature Set type. It loads the incoming IFeatureClass to a Feature Set and then pass it to the server tool. For more information, see An overview of geoprocessing with ArcGIS Server.
[C#]
public void FeatureSetUsingServer(IFeatureClass pFC)
{
    IGeoProcessor2 gp = new GeoProcessorClass();

    gp.AddToolbox(@"http://bdhost/arcgis/services;gp/Routing");
    ITable table = (ITable)pFC;
    IRecordSetInit rsInit = new RecordSetClass();
    IQueryFilter2 qf = new QueryFilterClass();
    rsInit.SetSourceTable(table, qf); // Load fc
    IRecordSet rs = rsInit as IRecordSet;
    IGPRecordSet gprs = new GPFeatureRecordSetLayerClass();
    gprs.RecordSet = rs;
    IVariantArray params = new VarArrayClass();
    parameters.Add(gprs);
    IGeoProcessorResult result;
    try
    {
        result = (IGeoProcessorResult)gp.Execute("BestPath", params, null);
        while (result.Status != esriJobStatus.esriJobSucceeded)
            System.Threading.Thread.Sleep(250);
        // Do next task with result.GetOutput(0)
    }
    catch (Exception ex)
    {
        object sev = null;
        string messages = gp.GetMessages(ref sev);
    }
}
[VB.NET]
Public Sub FeatureSetUsingServer(ByVal pFC As IFeatureClass)
    Dim gp As IGeoProcessor2 = New ESRI.ArcGIS.Geoprocessing.GeoProcessor()
    gp.AddToolbox("http://bdhost/arcgis/services;gp/Routing")
    Dim table As ITable = CType(pFC, ITable)
    Dim rsInit As IRecordSetInit = New RecordSet()
    Dim qf As IQueryFilter2 = New QueryFilter()
    rsInit.SetSourceTable(table, qf) ' Load fc into recordset
    Dim rs As IRecordSet = CType(rsInit, IRecordSet)
    Dim gprs As IGPRecordSet = New GPFeatureRecordSetLayerClass()
    gprs.RecordSet = rs
    Dim parameters As IVariantArray = New VarArray()
    parameters.Add(gprs)
    Dim result As IGeoProcessorResult2
    Try
    result = CType(gp.Execute("BestPath", parameters, Nothing), IGeoProcessorResult2)
    While result.Status = esriJobStatus.esriJobExecuting
        Threading.Thread.Sleep(250)
    End While
    ' other statements ...
    Catch ex As Exception
    Dim sev As Object = Nothing
    Dim messages As String = gp.GetMessages(sev)
    End Try
End Sub


See Also:

Using geoprocessing to develop applications
How to run a geoprocessing tool
Using in_memory workspace
How to work with geoprocessing services




To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):