Buffer features
BufferFeatures.cpp
// Copyright 2011 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

  

// BufferFeatures.cpp
//
// This sample shows how to create a buffer polygon for selected
// features, as well as how to draw that buffer as a graphic or write
// it to disk as a shapefile.  It also illustrates using a Motif scale
// widget with ArcEngine.

#include "BufferFeatures.h"

// Global variables
// 
// Motif 
Widget g_topLevel;                // application
Widget g_mainWindow;              // main program window
Widget g_mainForm;                // main prog window's form
Widget g_mapWidget;               // map control
Widget g_tocWidget;               // TOC control
Widget g_toolbarWidget;           // toolbar control
Widget g_addLayerWidget;
Widget g_fileSelectionDialog;
Widget g_scaleWidget;
Widget g_saveToggle;
Widget g_shapefilePathWidget;
Widget g_bufferWidget;
XtAppContext g_appContext;
Atom g_wmDeleteWindow;

// Other 
bool g_bSaveAsShapefile = false;
double g_dblPixelUnits = 0.0;

// main
//
// Initialize ArcEngine and set up widgets
int main(int argc, char* argv[])
{
  // Interfaces for the Controls
  IMapControl3Ptr ipMapControl;
  IToolbarControlPtr ipToolbarControl;
  ITOCControlPtr ipTOCControl;

    // Initialize the engine
  ::AoInitialize(NULL);
  {
    IAoInitializePtr ipAOinit(CLSID_AoInitialize);
    esriLicenseStatus status;
    ipAOinit->Initialize(esriLicenseProductCodeEngine, &status);
    if (status != esriLicenseCheckedOut)
    {
      std::cerr << "License not available for Engine\n";
      std::cerr << "status is " << status << std::endl;
      ipAOinit->Shutdown();
      ipAOinit = 0;
      ::AoUninitialize();
      AoExit(0);
    }      
  }

  XtSetLanguageProc(NULL, NULL, NULL);

  // Initialize the Motif toolkit and create the parent widget
  g_topLevel = XtVaAppInitialize(&g_appContext, "XApplication", 
                                 NULL, 0, &argc, argv, NULL, NULL);
  
  XtVaSetValues(g_topLevel, 
                XmNtitle, "Motif Buffer Features Example",
                NULL);

  XtResizeWidget(g_topLevel, 999, 800, 1);

  // Create g_mainWindow
  g_mainWindow = XtVaCreateWidget("g_mainWindow", 
                                  xmMainWindowWidgetClass, g_topLevel,
                                  NULL);
  // Create g_mainForm - it will fill the g_mainWindow
  g_mainForm = XtVaCreateWidget("g_mainForm",
                                xmFormWidgetClass,        g_mainWindow,
                                XmNtopAttachment,         XmATTACH_WIDGET,
                                XmNtopWidget,             g_mainWindow,
                                XmNbottomAttachment,      XmATTACH_WIDGET,
                                XmNbottomWidget,          g_mainWindow,
                                XmNleftAttachment,        XmATTACH_WIDGET,
                                XmNleftWidget,            g_mainWindow,
                                XmNrightAttachment,       XmATTACH_WIDGET,
                                XmNrightWidget,           g_mainWindow,
                                XmNfractionBase,          100,
                                NULL);

  //Create my button
  XmString label;
  label = XmStringCreateLocalized(const_cast<char*>("Add Layer"));
  g_addLayerWidget = XtVaCreateWidget("g_addLayerWidget",
                                      xmPushButtonWidgetClass,   g_mainForm,
                                      XmNlabelString, label,
                                      XmNtopAttachment,   XmATTACH_FORM,
                                      XmNleftAttachment,  XmATTACH_FORM,
                                      XmNheight,          35,
                                      XmNwidth,           150,
                                      NULL);
  XtAddCallback(g_addLayerWidget, XmNactivateCallback, processClickAdd, NULL);
  XmStringFree(label);


  // Create scale widget
  XmString sTitle;
  sTitle = XmStringCreateLocalized(const_cast<char*>("Buffer Width (pixels)"));
  g_scaleWidget = XtVaCreateWidget("g_scaleWidget",
                                   xmScaleWidgetClass, g_mainForm,
                                   XmNtitleString,   sTitle,
                                   XmNorientation,    XmHORIZONTAL,
                                   XmNminimum,       1,
                                   XmNmaximum,       300,
                                   XmNdecimalPoints, 0,
                                   XmNshowValue,     True,
                                   XmNtopAttachment,   XmATTACH_FORM,
                                   XmNleftAttachment,   XmATTACH_WIDGET,
                                   XmNleftWidget,            g_addLayerWidget,
                                   XmNwidth,         200,
                                   XmNheight,        50,
                                   NULL);
  XtAddCallback(g_scaleWidget, XmNvalueChangedCallback, processScaleChange, NULL);
  XmStringFree(sTitle);

  // Create toggle
  label = XmStringCreateLocalized(const_cast<char*>("Save to shapefile"));
  g_saveToggle = XtVaCreateWidget("g_saveToggle",
                                  xmToggleButtonWidgetClass,   g_mainForm,
                                  XmNlabelString, label,
                                  XmNtopAttachment,   XmATTACH_FORM,
                                  XmNleftAttachment,  XmATTACH_WIDGET,
                                  XmNleftWidget,            g_scaleWidget,
                                  XmNheight,          50,
                                  XmNwidth,           100,
                                  NULL);
  XtAddCallback(g_saveToggle, XmNvalueChangedCallback, processToggle, NULL);
  XmStringFree(label);

  //Create my button
  label = XmStringCreateLocalized(const_cast<char*>("Buffer"));
  g_bufferWidget = XtVaCreateWidget("g_bufferWidget",
                                    xmPushButtonWidgetClass,   g_mainForm,
                                    XmNlabelString, label,
                                    XmNtopAttachment,   XmATTACH_FORM,
                                    XmNrightAttachment,   XmATTACH_FORM,
                                    XmNheight,          35,
                                    XmNwidth,           150,
                                    NULL);
  XmStringFree(label);

  // Create the TextField for the shapefile's path
  g_shapefilePathWidget = XtVaCreateWidget("g_shapefilePathWidget",
                                           xmTextFieldWidgetClass,   g_mainForm,
                                           XmNtopAttachment,   XmATTACH_FORM,
                                           XmNleftAttachment,  XmATTACH_WIDGET,
                                           XmNleftWidget,      g_saveToggle,
                                           XmNrightAttachment,  XmATTACH_WIDGET,
                                           XmNrightWidget,      g_bufferWidget,
                                           XmNheight,          35,
                                           XmNeditable, False,
                                           NULL);

  // Create a FileSelectionDialog with a *.lyr mask
  XmString mask, title;
  Arg args[2];
  mask  = XmStringCreateLocalized(const_cast<char*>("*.lyr"));
  title = XmStringCreateLocalized(const_cast<char*>("Select Layer"));
  XtSetArg(args[0], XmNdirMask, mask);
  XtSetArg(args[1], XmNdialogTitle, title);
  g_fileSelectionDialog = XmCreateFileSelectionDialog(g_mainForm, const_cast<char*>("Select"), args, 2);
  XmStringFree(mask);
  XmStringFree(title);
  
  // Remove the Help button
  Widget remove1 = XmFileSelectionBoxGetChild(g_fileSelectionDialog, XmDIALOG_HELP_BUTTON);
  XtUnmanageChild(remove1);

  // Toolbar Control setup 
  g_toolbarWidget = XtVaCreateWidget("g_toolbarWidget",
                                     mwCtlWidgetClass,   g_mainForm,
                                     XmNtopAttachment,        XmATTACH_WIDGET,
                                     XmNtopWidget,            g_scaleWidget,
                                     XmNrightAttachment, XmATTACH_FORM,
                                     XmNleftAttachment, XmATTACH_FORM,
                                     MwNprogID,        AoPROGID_ToolbarControl,
                                     NULL);
  XtVaSetValues(g_toolbarWidget, XmNheight, 25, NULL);
  MwCtlGetInterface(g_toolbarWidget, (IUnknown**)&ipToolbarControl);
  
  // TOC Control setup
  g_tocWidget = XtVaCreateWidget("g_tocWidget",
                                 mwCtlWidgetClass,        g_mainForm,
                                 XmNtopAttachment,        XmATTACH_WIDGET,
                                 XmNtopWidget,            g_toolbarWidget,
                                 XmNleftAttachment,       XmATTACH_FORM,
                                 XmNbottomAttachment,     XmATTACH_FORM,
                                 MwNprogID,               AoPROGID_TOCControl,
                                 NULL);
  XtVaSetValues(g_tocWidget, XmNwidth, 200, NULL);
  MwCtlGetInterface(g_tocWidget, (IUnknown**)&ipTOCControl);

  // Map Control setup
  g_mapWidget = XtVaCreateWidget("g_mapWidget",
                                 mwCtlWidgetClass,        g_mainForm,
                                 XmNtopAttachment,        XmATTACH_WIDGET,
                                 XmNtopWidget,            g_toolbarWidget,
                                 XmNleftAttachment,       XmATTACH_WIDGET,
                                 XmNleftWidget,           g_tocWidget,
                                 XmNrightAttachment,      XmATTACH_FORM,
                                 XmNbottomAttachment,     XmATTACH_FORM,
                                 MwNprogID,               AoPROGID_MapControl,
                                 NULL);
  MwCtlGetInterface(g_mapWidget, (IUnknown**)&ipMapControl);

  // Set up callbacks that need the map widget
  XtAddCallback(g_bufferWidget, XmNactivateCallback, processClickBuffer, (XtPointer) g_mapWidget);
  XtAddCallback(g_fileSelectionDialog, XmNokCallback, processFileSelect, (XtPointer) g_mapWidget);
  XtAddCallback(g_fileSelectionDialog, XmNcancelCallback, processFileSelect, (XtPointer) g_mapWidget);

  // Manage the non-parent widgets
  XtManageChild(g_mainWindow);
  XtManageChild(g_mainForm);
  XtManageChild(g_addLayerWidget);
  XtManageChild(g_scaleWidget);
  XtManageChild(g_bufferWidget);
  XtManageChild(g_saveToggle);
  XtManageChild(g_shapefilePathWidget);
  XtManageChild(g_toolbarWidget);
  XtManageChild(g_tocWidget);
  XtManageChild(g_mapWidget);

  // Buddy the toolbar and TOC with the map
  ipToolbarControl->SetBuddyControl(ipMapControl);
  ipTOCControl->SetBuddyControl(ipMapControl);

  // Add tools to toolbar
  ::AddStandardToolbarItems(ipToolbarControl);

  // Structure used to pass data to callback routines
  CloseFormClientDataStruct cfcds;
  cfcds.pMapControl = ipMapControl;
  cfcds.pToolbarControl = ipToolbarControl;
  cfcds.pTOCControl = ipTOCControl;

  // Handle the window manager message that the window is about to be closed 
  g_wmDeleteWindow = XmInternAtom(XtDisplay(g_topLevel), "WM_DELETE_WINDOW", FALSE);
  XmAddWMProtocolCallback(g_topLevel, g_wmDeleteWindow, processClickCloseForm, &cfcds);

  // Realize the container widget  
  XtRealizeWidget(g_topLevel);

  XtResizeWidget(g_topLevel, 1000, 800, 1);

  // Turn application control over to the X Toolkit Intrinsics
  MwCtlAppMainLoop(g_appContext);
}

// Function called when WM_DELETE_WINDOW is received (i.e. when the
// user closes the window)
void processClickCloseForm(Widget w, XtPointer client_data, XtPointer call_data)
{
  // To be on the safe side we will make sure the controls are
  // destroyed before uninitializing
  CloseFormClientDataStruct *cfcds = (CloseFormClientDataStruct *) client_data;
  IMapControl3Ptr ipMapControl = cfcds->pMapControl;
  ipMapControl = 0;
  IToolbarControlPtr ipToolbarControl = cfcds->pToolbarControl;
  ipToolbarControl = 0;
  ITOCControlPtr ipTOCControl = cfcds->pTOCControl;
  ipTOCControl = 0;
    
  // Uninitialize the engine
  {
    IAoInitializePtr ipAOinit(CLSID_AoInitialize);
    ipAOinit->Shutdown();
  }    
  ::AoUninitialize();

  AoExit(0);
}

// Calls CreateFeatureBuffer, passing in the buffer size selected in
// the slider control
void processClickBuffer(Widget w, XtPointer client_data, XtPointer call_data)
{
  IMapControl3Ptr ipMapControl;
  MwCtlGetInterface((Widget)client_data, (IUnknown**)&ipMapControl);

  if (g_dblPixelUnits > 0.0)
    CreateBufferedGeometryOfSelectedFeatures(ipMapControl, g_dblPixelUnits);
  else
    ::ShowMessage(g_mainForm, "Error","Please select a buffer size first", true);
}

// Open a FileSelectionDialog window to allow the user to select a .lyr file
// to add to the map control and TOC
void processClickAdd(Widget w, XtPointer client_data, XtPointer call_data)
{
  XtManageChild(g_fileSelectionDialog);
}

// Add the .lyr file that the user selected to the map control and TOC
void processFileSelect(Widget w, XtPointer client_data, XtPointer call_data)
{
  IMapControl3Ptr ipMapControl;
  MwCtlGetInterface((Widget)client_data, (IUnknown**)&ipMapControl);

  XmFileSelectionBoxCallbackStruct *cbs = (XmFileSelectionBoxCallbackStruct *)call_data;

  // Kill the dialog if they canceled
  if (cbs->reason == XmCR_CANCEL)
  {
    XtUnmanageChild(g_fileSelectionDialog);
    return;
  }

  // Get the file name and check for errors
  char *fileName = 0;
  if (!XmStringGetLtoR(cbs->value, XmFONTLIST_DEFAULT_TAG, &fileName))
  {
    XtUnmanageChild(g_fileSelectionDialog);
    return;
  }

  if (*fileName)
  {
    // Try to add the layer to the map
    ipMapControl->AddLayerFromFile(CComBSTR(fileName), 0);
      
    // Hide file selection dialog      
    XtUnmanageChild(g_fileSelectionDialog);
  }
  
  XtFree (fileName);
  return;
}

// Sets the value of g_dblPixelUnits based on the slider widget's value
void processScaleChange(Widget w, XtPointer client_data, XtPointer call_data)
{
  XmScaleCallbackStruct *cbs = (XmScaleCallbackStruct *) call_data;
  g_dblPixelUnits = (double) cbs->value;
}

// Toggles a boolean which controls whether or not a shapefile with
// the buffered features is created and sets whether or not the
// textfieldwidget which will contain the path to the new shapefile is
// editable.
void processToggle(Widget w, XtPointer client_data, XtPointer call_data)
{
  XmToggleButtonCallbackStruct *cbs = (XmToggleButtonCallbackStruct *) call_data;
  if (cbs->set)
  {
    g_bSaveAsShapefile = true;
    XtVaSetValues(g_shapefilePathWidget, XmNeditable, True, NULL);
  }
  else
  {
    g_bSaveAsShapefile = false;
    XtVaSetValues(g_shapefilePathWidget, XmNeditable, False, NULL);
  }
}

// Create a polygon containing the union of the buffer of the selected
// features
//
// scaleValue - size of buffer in pixels
void CreateBufferedGeometryOfSelectedFeatures(IMapControl3 *pMapControl, double scaleValue)
{
  // Make sure that a layer has been added
  long layerCount = 0;
  pMapControl->get_LayerCount(&layerCount);
  if (layerCount < 1)
  {
    ::ShowMessage(g_mainForm, "Error","Please add a feature layer first", true);
    return;
  }
  
  // Just use 1st layer, but make sure it's a featurelayer
  ILayerPtr ipLayer;
  pMapControl->get_Layer(0, &ipLayer);
  IFeatureSelectionPtr ipFeatSel (ipLayer); // Implicit QI
  if (ipFeatSel == 0)
  {
    ::ShowMessage(g_mainForm, "Error","Please add a feature layer first", true);
    return;
  }

  // Get the SelectionSet and make sure there's at least 1 feature selected
  long numSelected = 0;
  ISelectionSetPtr ipSelSet;
  ipFeatSel->get_SelectionSet(&ipSelSet);
  ipSelSet->get_Count(&numSelected);
  if (numSelected < 1)
  {
    ::ShowMessage(g_mainForm, "Error","Please select features first", true);
    return;
  }

  // Convert the scale value to a real world value
  IActiveViewPtr ipActiveView;
  pMapControl->get_ActiveView(&ipActiveView);
  double rwUnits = 0.0;
  ::ConvertPixelsToMapUnits(ipActiveView, scaleValue, &rwUnits);
  double generalOffset = rwUnits / 20.0;

  // Get all features
  ICursorPtr ipCursor;
  ipSelSet->Search(0, VARIANT_FALSE, &ipCursor);
  IFeatureCursorPtr ipFeatureCursor (ipCursor); // Implicit QI
  
  // Just get the spatial reference once.  It is used when creating a
  // new feature class.
  IFeaturePtr ipFeature;
  ipFeatureCursor->NextFeature(&ipFeature);
  ISpatialReferencePtr ipSpaRef;
  if (ipFeature != 0)
  {
    IGeometryPtr ipG;
    ipFeature->get_Shape(&ipG);
    ipG->get_SpatialReference(&ipSpaRef);
  }

  IPolygonPtr ipAllPolygons (CLSID_Polygon);
  ITopologicalOperatorPtr ipTopoOp (ipAllPolygons); // Implicit QI
  ipTopoOp->Simplify();
  
  // Loop through the selected features and union their buffered geometry  
  bool needToGeneralize;
  esriGeometryType geomType;
  IPolycurvePtr ipPolycurve;
  IPolygonPtr ipSinglePolygon;
  IGeometryPtr ipGeometry;
  while (ipFeature != 0)
  {
    ipFeature->get_ShapeCopy(&ipGeometry);
    ipGeometry->get_GeometryType(&geomType);
    if (geomType == esriGeometryPoint)
    {
      ipTopoOp = ipGeometry;
      needToGeneralize = false;
    }
    else
    {
      ipPolycurve = ipGeometry;
      ipPolycurve->Generalize(generalOffset);
      ipTopoOp = ipPolycurve;
      needToGeneralize = true;
    }
    ipTopoOp->Simplify();
    ipTopoOp->Buffer(rwUnits,&ipGeometry);
    ipSinglePolygon = ipGeometry;

    if (needToGeneralize)
      ipSinglePolygon->Generalize(generalOffset);

    ipTopoOp = ipSinglePolygon;
    ipTopoOp->Simplify(); 

    ipGeometry = ipAllPolygons;
    ipTopoOp->Union(ipAllPolygons, &ipGeometry); 
    ipAllPolygons = ipGeometry;

    ipFeatureCursor->NextFeature(&ipFeature); 
  }

  // Draw buffer to screen and persist as shapefile if specified
  DrawPolygonToActiveView(pMapControl, ipAllPolygons);
  
  if (g_bSaveAsShapefile)
  {
    char *text  = XmTextFieldGetString(g_shapefilePathWidget);
    if (strcmp(text, "") != 0)
    {
      CComBSTR bsPathToWorkspace;
      CComBSTR bsName;
      HRESULT hr1 = GetParentDirFromFullPath(text, &bsPathToWorkspace, false);  
      HRESULT hr2 = GetFileFromFullPath(text, &bsName);
      if (FAILED(hr1) || FAILED(hr2) || bsPathToWorkspace.Length() == 0 || bsName.Length() == 0) 
      {
        ::ShowMessage(g_mainForm, "Error","Please specify the full path for the new shapefile", true);      
        return;
      }
      HRESULT hr = CreateShapefile(rwUnits, bsPathToWorkspace, bsName, ipSpaRef, ipAllPolygons);
      if (FAILED(hr))
        ::ShowMessage(g_mainForm, "Error","Couldn't create shapefile", true);      
    }
    else
      ::ShowMessage(g_mainForm, "Error","Please specify the full path for the new shapefile", true);      
  }
}

// Display a polygon in the ActiveView.  This only draws graphics to
// the screen- they will be gone when the activeview is refreshed.
void DrawPolygonToActiveView(IMapControl3 *pMapControl, IPolygon *pPoly)
{
  IFillSymbolPtr  ipFillSymbol(CLSID_SimpleFillSymbol);
  ILineSymbolPtr ipLineSymbol;
  ISymbolPtr ipSymbol;
  IRgbColorPtr ipRGBColor(CLSID_RgbColor);
  IActiveViewPtr ipActiveView;
  IScreenDisplayPtr ipScreenDisplay;
  long color = 45;

  // Set up FillSymbol
  ipSymbol = ipFillSymbol;
  ipSymbol->put_ROP2(esriROPXOrPen);
  ipRGBColor->put_UseWindowsDithering(VARIANT_FALSE);
  ipRGBColor->put_Red(color);
  ipRGBColor->put_Green(color);
  ipRGBColor->put_Blue(color);
  ipFillSymbol->put_Color(ipRGBColor); 

  // Set up FillSymbol's outline
  ipFillSymbol->get_Outline(&ipLineSymbol);
  ((ISymbolPtr)ipLineSymbol)->put_ROP2(esriROPXOrPen);  
  color = 145;
  ipRGBColor->put_Red(color);
  ipRGBColor->put_Green(color);
  ipRGBColor->put_Blue(color);
  ipLineSymbol->put_Color(ipRGBColor);
  ipLineSymbol->put_Width(0.1);
  ipFillSymbol->put_Outline(ipLineSymbol);

  // Draw the polygon to the screen
  pMapControl->get_ActiveView(&ipActiveView);
  ipActiveView->get_ScreenDisplay(&ipScreenDisplay);
  ipScreenDisplay->StartDrawing(0, esriNoScreenCache);
  ipScreenDisplay->SetSymbol(ipSymbol);
  ipScreenDisplay->DrawPolygon(pPoly);
  ipScreenDisplay->FinishDrawing();  
}

// Creates a new shapefile containing 1 feature which is the buffer of
// the selected features in the map control
//
// rwUnits             -  the width of the buffer in real world units (will be saved to feature in shapefile)
// outPath             -  where shapefile will be saved
// outName             -  name for new shapefile
// ipSpatialReference  -  spatial reference of selected features
// ipPolygon           -  polygon representing the union of the selected features
// 
HRESULT CreateShapefile(double rwUnits, BSTR bstrOutPath, BSTR bstrOutName, ISpatialReference *ipSpatialReference, IPolygon *ipPolygon)
{
  // Get a feature workspace for output shapefile
  IWorkspaceFactoryPtr ipWorkFact(CLSID_ShapefileWorkspaceFactory);
  IWorkspacePtr ipWork;
  ipWorkFact->OpenFromFile(bstrOutPath, 0, &ipWork);
  IFeatureWorkspacePtr ipFeatWork;
  ipFeatWork = ipWork; //QI

  // Set up fields
  IFieldsPtr ipFields(CLSID_Fields);
  IFieldsEditPtr ipFieldsEdit;
  ipFieldsEdit = ipFields; //QI
  IFieldPtr ipField(CLSID_Field);
  IFieldEditPtr ipFieldEdit;
  ipFieldEdit = ipField; //QI
  // Set up geometry field
  ipFieldEdit->put_Name(CComBSTR(L"Shape"));
  ipFieldEdit->put_Type(esriFieldTypeGeometry);
  IGeometryDefPtr ipGeoDef(CLSID_GeometryDef);
  IGeometryDefEditPtr ipGeoDefEdit;
  ipGeoDefEdit = ipGeoDef; //QI
  ipGeoDefEdit->put_GeometryType(esriGeometryPolygon);

  // Use spatial reference of the feature class you buffered
  ipGeoDefEdit->putref_SpatialReference(ipSpatialReference);
  ipFieldEdit->putref_GeometryDef(ipGeoDef);
  ipFieldsEdit->AddField(ipField);

  // Add field for scale value
  IFieldPtr ipScale(CLSID_Field);
  long len = 30;
  ipFieldEdit = ipScale;
  ipFieldEdit->put_Length(len);
  ipFieldEdit->put_Name(CComBSTR(L"Scale"));
  ipFieldEdit->put_Type(esriFieldTypeDouble);
  ipFieldsEdit->AddField(ipScale);

  // Create the shapefile
  IFeatureClassPtr ipShape;
  HRESULT hr = ipFeatWork->CreateFeatureClass(bstrOutName, ipFields, 0, 0, esriFTSimple, CComBSTR(L"Shape"), 0, &ipShape);
  if (FAILED(hr)) return hr;

  // Now insert the feature
  IFeatureCursorPtr ipFC;
  IFeatureBufferPtr ipFB;
  IFieldsPtr ipFieldsNew;

  // Get an insert cursor and a feature buffer
  ipShape->Insert(VARIANT_TRUE, &ipFC);
  ipShape->CreateFeatureBuffer(&ipFB);
  ipFB->get_Fields(&ipFieldsNew);

  // Get the column index in table for Scale field
  long indScale;
  ipFieldsNew->FindField(CComBSTR(L"Scale"), &indScale);

  // Update the feature buffer
  IGeometryPtr ipGeom = ipPolygon;
  ipFB->putref_Shape(ipGeom);
  ipFB->put_Value(indScale, CComVariant(rwUnits));

  // Insert the feature, its OID is returned
  CComVariant ret;
  ipFC->InsertFeature(ipFB, &ret);

  // Flush the insert cursor
  ipFC->Flush();

  return S_OK;
}