Buffer features
ArcEngineUtilities.cpp
// Copyright 2010 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.
// 

  
#include "ArcEngineUtilities.h"

// Function to convert pixel units to map units.  This function also
// serves as an example of how to check HRESULTs and return them if a
// failing HRESULT is encountered.
HRESULT ConvertPixelsToMapUnits (IActiveView *pActiveView, double pixelUnits, double *mapUnits)
{
  if (0 == pActiveView)
    return E_INVALIDARG;
  
  double realWorldDisplayExtent, sizeOfOnePixel, pixelExtent;
  long right, left;
  IScreenDisplayPtr ipSD;
  IDisplayTransformationPtr ipDT;
  IEnvelopePtr ipEnv;
  tagRECT bounds;
  
  HRESULT hr = pActiveView->get_ScreenDisplay(&ipSD);
  if (FAILED(hr)) return hr;
  hr = ipSD->get_DisplayTransformation(&ipDT);
  if (FAILED(hr)) return hr;
  hr = ipDT->get_DeviceFrame(&bounds);
  if (FAILED(hr)) return hr;
  right = bounds.right;
  left = bounds.left;
  pixelExtent = (double)(right - left);
  if (pixelExtent <= 0.0) return E_FAIL;
  hr = ipDT->get_VisibleBounds(&ipEnv);
  if (FAILED(hr)) return hr;
  hr = ipEnv->get_Width(&realWorldDisplayExtent);
  if (FAILED(hr)) return hr;
  sizeOfOnePixel = realWorldDisplayExtent / pixelExtent;
  *mapUnits = sizeOfOnePixel * pixelUnits;
  
  return S_OK;
}

// Returns the index in pMapControl's map of the layer w/ name inName,
// or -1 if no layer is found.  Note that if a layer is a sublayer in
// a group layer it won't be found here.
long GetIndexOfLayerName (IMapControl3 *pMapControl, const char *inName)
{
  if (!inName || !pMapControl)
    return -1;

  CComBSTR bsInLayerName (inName);
  CComBSTR bsTmpLayerName;
  ILayerPtr ipLayer;
  long numLayers;
  
  pMapControl->get_LayerCount(&numLayers);
  
  for (long i=0; i<numLayers; i++)
  {
    pMapControl->get_Layer(i, &ipLayer);
    ipLayer->get_Name(&bsTmpLayerName);
    if (bsTmpLayerName == bsInLayerName)
      return i;
  }
  
  return -1;
}

// Adds some commonly used items to a toolbar control using ProgIDs
void AddStandardToolbarItems(IToolbarControl *pToolbarControl)
{
  if (0 == pToolbarControl) return;
  
  long itemIndex;
  CComVariant varTool;
  
  varTool = L"esriControlCommands.ControlsOpenDocCommand";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapPanTool";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomInTool";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomOutTool";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomInFixedCommand";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomOutFixedCommand";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomPanTool";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapFullExtentCommand";
  pToolbarControl->AddItem( varTool, 0, -1, VARIANT_FALSE, 0,
                            esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomToLastExtentBackCommand";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsMapZoomToLastExtentForwardCommand";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsSelectTool";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0,
                           esriCommandStyleIconOnly, &itemIndex);
  varTool = L"esriControlCommands.ControlsSelectFeaturesTool";
  pToolbarControl->AddItem(varTool, 0, -1, VARIANT_FALSE, 0, 
                           esriCommandStyleIconOnly, &itemIndex);
}

// Returns a layer based on its name using RecursiveGetLayerFromName
// to search GroupLayers.  If 2 layers have the same name it will
// return the 1st layer found.
HRESULT GetLayerFromName (IMapControl3* pMapControl, BSTR bsLayerName, ILayer** ppOutLayer)
{
  if (!ppOutLayer)
    return E_POINTER;

  if (!pMapControl || !bsLayerName)
    return E_INVALIDARG;

  // Initialize output
  if (*ppOutLayer)
    (*ppOutLayer)->Release();
  *ppOutLayer = 0;
  
  long layerCount;
  pMapControl->get_LayerCount(&layerCount);
  for (long i=0; i<layerCount; ++i)
  {
    ILayerPtr ipLayer;
    pMapControl->get_Layer(i, &ipLayer);
    if (RecursiveGetLayerFromName(ipLayer, bsLayerName, ppOutLayer) == S_OK)
      return S_OK;
  }

  return S_FALSE;
}

// Recursive function to return a layer based on its name.  If 2
// layers have the same name it will return the 1st layer found.  If
// the layer is a grouplayer the function first checks whether the
// group layer's name is a match and if not it then proceeds to check
// sublayers.
HRESULT RecursiveGetLayerFromName (ILayer* pLayer, BSTR bsSearchName, ILayer** ppOutLayer)
{
  if (!ppOutLayer)
    return E_POINTER;

  if (!pLayer || !bsSearchName)
    return E_INVALIDARG;

  // Initialize output
  if (*ppOutLayer)
    (*ppOutLayer)->Release();
  *ppOutLayer = 0;

  CComBSTR bsName;
  pLayer->get_Name(&bsName);
  if (bsName == bsSearchName)
  {
    *ppOutLayer = pLayer;
    if (*ppOutLayer)
    {
      (*ppOutLayer)->AddRef();
      return S_OK;
    }
  }

  ICompositeLayerPtr ipCompLayer(pLayer);
  if (ipCompLayer)
  {
    long layerCount;
    ipCompLayer->get_Count(&layerCount);
    for (long i=0; i<layerCount; ++i)
    {
      ILayerPtr ipSubLayer;
      ipCompLayer->get_Layer(i, &ipSubLayer);
      if (RecursiveGetLayerFromName(ipSubLayer, bsSearchName, ppOutLayer) == S_OK)
        return S_OK;
    }
  }

  return S_FALSE;
}

// // Returns a set with all layers that implement IFeatureLayer using
// // RecursiveGetFeatureLayerSet to search GroupLayers.
// HRESULT GetFeatureLayerSet (IMapControl3* pMapControl, ISet* pSet)
// {
//   if (!pMapControl || !pSet)
//     return E_INVALIDARG;

//   long layerCount;
//   pMapControl->get_LayerCount(&layerCount);
//   for (long i=0; i<layerCount; ++i)
//   {
//     ILayerPtr ipLayer;
//     pMapControl->get_Layer(i, &ipLayer);
//     RecursiveGetFeatureLayerSet(ipLayer, pSet);
//   }

//   return S_OK;
// }

// // Recursive function which adds to a set all layers that implement
// // IFeatureLayer.
// HRESULT RecursiveGetFeatureLayerSet (ILayer* pLayer, ISet* pSet)
// {
//   if (!pLayer || !pSet)
//     return E_INVALIDARG;

//   ICompositeLayerPtr ipCompLayer(pLayer);
//   if (ipCompLayer)
//   {
//     long layerCount;
//     ipCompLayer->get_Count(&layerCount);
//     for (long i=0; i<layerCount; ++i)
//     {
//       ILayerPtr ipSubLayer;
//       ipCompLayer->get_Layer(i, &ipSubLayer);
//       RecursiveGetFeatureLayerSet(ipSubLayer, pSet);
//     }
//   }
//   else
//   {
//     IFeatureLayerPtr ipFeatLayer(pLayer);
//     if (ipFeatLayer)
//       pSet->Add(ipFeatLayer);
//   }

//   return S_OK;
// }

// Calls RecursiveCheckLayerNames to check the layers in the map for
// duplicate names. Returns S_OK if the layer names are OK, S_FALSE if
// there are duplicates.
HRESULT CheckLayerNames (IMapControl3* pMapControl)
{
  if (!pMapControl)
    return E_INVALIDARG;

  WStringSet wss;
  long layerCount;
  pMapControl->get_LayerCount(&layerCount);
  for (long i=0; i<layerCount; ++i)
  {
    ILayerPtr ipLayer;
    pMapControl->get_Layer(i, &ipLayer);
    HRESULT hr = RecursiveCheckLayerNames(ipLayer, wss);
    if (hr == S_FALSE || FAILED(hr))
      return hr;
  }

  return S_OK;
}

// Recursively checks the layers in the map for duplicate
// names. Returns S_OK if the layer names are OK, S_FALSE if there are
// duplicates.
HRESULT RecursiveCheckLayerNames (ILayer* pLayer, WStringSet& wss)
{
  if (!pLayer)
    return E_INVALIDARG;

  CComBSTR bsName;
  pLayer->get_Name(&bsName);
  wstring wsName(bsName);
  WStringSet::iterator it = wss.find(wsName);
  if (it != wss.end())
    return S_FALSE;

  // Insert the name into the set
  wss.insert(wsName);
  
  ICompositeLayerPtr ipCompLayer(pLayer);
  if (ipCompLayer)
  {
    long layerCount;
    ipCompLayer->get_Count(&layerCount);
    for (long i=0; i<layerCount; ++i)
    {
      ILayerPtr ipSubLayer;
      ipCompLayer->get_Layer(i, &ipSubLayer);
      HRESULT hr = RecursiveCheckLayerNames(ipSubLayer, wss);
      if (hr == S_FALSE || FAILED(hr))
        return hr;
    }
  }

  return S_OK;
}