Follow

How to automate MapViewer using C++

This article contains a sample script for automating MapViewer from C++. This example was compiled with Microsoft Visual C++ 6.0.

 

To run this script, you can copy and paste from below or download it here: Client.cpp.

 

*********

// 
// Client.cpp    Copyright (C) Golden Software, LLC 1999-2014
//
// You have a royalty-free right to use, modify, reproduce and distribute
// the Sample Application Files in any way you find useful, provided that 
// you agree that Golden Software has no warranty, obligations or liability
// for any Sample Application Files.
//
// This example demonstrates how to automate MapViewer from C++.  A new instance
// of MapViewer is started, and a map is created.  
//
// This example uses the Microsoft-specific extension "#import" to create
// header files from the type library information contained within map.exe.
// The generated header files contain several smart-pointer classes that
// greatly simplify this entire process.  Make sure the #import directive
// below points to the correct location of map.exe.
//
// This example was compiled with Microsoft Visual C++ 6.0 using the
// following command line:
//
// cl -GX Client.cpp
//-----------------------------------------------------------------------------
#include <iostream>
#include <windows.h>
#import "C:\Program Files\Golden Software\MapViewer 8\map.exe" no_namespace   // Make sure to change path appropriately

using namespace std;

void TestBaseMap(IDocumentsPtr& pDocs, wchar_t* BoundaryPath, wchar_t* DataPath);
void TestHatchMap(IDocumentsPtr& pDocs,wchar_t* BoundaryPath, wchar_t* DataPath);
void TestPieMap(IDocumentsPtr& pDocs,wchar_t* BoundaryPath, wchar_t* DataPath);
SAFEARRAY *AutoCreateSafeArray(int Type,int nElem,void *pData);

//-----------------------------------------------------------------------------
void main()
{
   // Initialize the system DLL's
   HRESULT hr = CoInitialize(NULL);
   if(FAILED(hr))
   {
      cout << "CoInitialize Failed: " << hr << "\n\n";
      exit(1);
   }

   try
   {
      // Create an instance of the Application object
      IApplicationPtr pApp(__uuidof(Application));

      // Make the Application object visible
      pApp->Visible = VARIANT_TRUE;

      auto InPath = pApp->ApplicationFolder + L"Samples\\";

      auto BoundaryPath = InPath + L"us50alb.gsb";

      auto DataPath = InPath + L"us502010.dat";

      // Get the Documents collection
      IDocumentsPtr pDocs = pApp->Documents;

      // Creates base map
      TestBaseMap(pDocs, BoundaryPath, DataPath);

      // Creates hatch map
      TestHatchMap(pDocs, BoundaryPath, DataPath);

      // Creates pie map
      TestPieMap(pDocs, BoundaryPath, DataPath);

   }
   catch(_com_error& e)
   {
      MessageBeep(0);

      // Display a generic COM error message
      cout << e.ErrorMessage() << "\n";

      // Display any application supplied information
      if(e.Description().length())
      {
         cout << e.Description() << "\n";
         OutputDebugString(e.Description());
         OutputDebugString(L"\n");
      }
   }

   CoUninitialize();
}

void TestBaseMap(IDocumentsPtr& pDocs, wchar_t* BoundaryPath, wchar_t* DataPath)
{
   // Add a new document to the Documents collection.
   IPlotDocumentPtr pPlotDoc1 = pDocs->Add(mvDocPlot);

   // Import us50alb.gsb file to the document's active layer, and return
   // the active layer.
   ILayerPtr pImportLayer = pPlotDoc1->Import(BoundaryPath, "", VARIANT_TRUE);

   // Get the Layers collection from the document
   ILayersPtr pLayers = pPlotDoc1->Layers;
      
   // Add a new layer.  This action automatically make the new layer 
   // the active layer.
   ILayerPtr pNewLayer = pLayers->AddLayer("New Layer");

   // Get the active layer from the layers collection, which is the new layer.
   ILayerPtr  pActiveLayer = pLayers->ActiveLayer;
      
   // The following is another way to get the active layer of the document
   ILayerPtr  pOtherWayToGetActiveLayer = pPlotDoc1->ActiveLayer;

   // Get the Shapes collection from the active layer
   IShapesPtr pShapes = pActiveLayer->Shapes;

   // The following is another way to get the Shapes collection on the active 
   // layer of the document
   IShapesPtr pOtherWayToGetActiveShapesCollection = pPlotDoc1->ActiveShapes;

   // Create a rectangle in the Shapes collection
   IRectanglePtr pRectangle = pShapes->AddRectangle(0.5, 0.5, 10.5, 8.0, VARIANT_FALSE, mvCoordDisplayUnitPageUnits);

   // Set up an array of long specifying columns to be used in CreatePostMap
   long ArrayOfVarCols[3] = { 2, 3, 4 };

   SAFEARRAY* pVarCols = AutoCreateSafeArray(VT_I4, 3, ArrayOfVarCols);

   // Create data labels on the the first layer in the map, where the boundary file has already been imported.
   pImportLayer->Activate();
   IPostDataPtr pPostMapLayer = pPlotDoc1->CreatePostMap(pVarCols, "", DataPath, "", "", 0);

   // Position the next labels so they don't overlap
   pPostMapLayer->PostPosOffsetType[2] = mvPosOffsetUser;
   pPostMapLayer->PostPosYOffset[2] = -.15;

   pPostMapLayer->PostPosOffsetType[3] = mvPosOffsetUser;
   pPostMapLayer->PostPosYOffset[3] = .15;

}

void TestHatchMap(IDocumentsPtr& pDocs,wchar_t* BoundaryPath, wchar_t* DataPath)
{
   // Add a new document to the Documents collection.
   IPlotDocumentPtr pPlotDoc = pDocs->Add(mvDocPlot);

   // Create a hatch map using column 3 for the variable and 6 classes
   IHatchMapPtr pMapObj = pPlotDoc->CreateHatchMap(BoundaryPath, DataPath, "", "", 1, 3, 6, VARIANT_FALSE, VARIANT_FALSE);
}


void TestPieMap(IDocumentsPtr& pDocs,wchar_t* BoundaryPath, wchar_t* DataPath)
{
   // Add a new document to the Documents collection.
   IPlotDocumentPtr pPlotDoc = pDocs->Add(mvDocPlot);
   
   // Set up an array of long specifying columns to be used in CreatePieMap
   long ArrayOfVarCols[3] = { 4, 5, 6 };

   SAFEARRAY* pVarCols = AutoCreateSafeArray(VT_I4, 3, ArrayOfVarCols);

   // Create a pie map
   IPieMapPtr pMapObj = pPlotDoc->CreatePieMap(pVarCols, BoundaryPath, DataPath, "", "", 1);
}

/******************************************************************************
*
* Creates a SAFEARRAY from a C array.
*
* Type   the type of element in the SAFEARRAY (as in VT_I4)
* nElem  the number of elements in the array
* pData  pointer to the C style array to copy
*
******************************************************************************/
SAFEARRAY *AutoCreateSafeArray(int Type, int nElem, void *pData)
{
   int BytesPerElem;
   if(Type == VT_I4)
      BytesPerElem = 4;
   else if(Type == VT_R8)
      BytesPerElem = 8;
   else
      return NULL;   // Error

   SAFEARRAYBOUND Bound = {nElem, 0};
   SAFEARRAY *pSA = SafeArrayCreate(Type, 1, &Bound);
   if(!pSA) _com_issue_error(E_OUTOFMEMORY);

   void *p;
   SafeArrayAccessData(pSA, &p);
   memcpy(p, pData, nElem*BytesPerElem);
   SafeArrayUnaccessData(pSA);

   return pSA;
}

 

 

Updated: September 17, 2016

Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.