Hints

A. COM objects.
MapWinGIS is COM-based, therefore it counts the references of particular objects to determine when they are no longer needed and can be released.

  1. Environments like .NET or VB6 add and release these references automatically. Calling the operations explicitly (Marshal.AddRef, Marshal.Release for example) in most cases will cause problems and sometimes even crashes.
  2. In the languages like unmanaged C++ the client is responsible for maintaining the number of reference, so AddRef(), Release() must be called explicitly.

Try to avoid the usage of the same COM object as a child to several objects. For example it's a good practice not to insert the same shape in several shapefiles, unless there is a good reason to do it and you understand the possible effects. In any other case call
Clone (Shape.Clone for example) before the operation.

// let's copy a shape from one shapefile to another
Shapefile sf = some_shapefile;
Shapefile sfNew = sf.Clone();
// 1. without Clone()
Shape shp = sf.get_Shape(shapeIndex);
sfNew.EditAddShape(shp); // risky, the same instance of shape will be used by two shapefiles
// 2. with Clone()
Shape shp = sf.get_Shape(shapeIndex);
sfNew.EditAddShape(shp.Clone()); // safe, there are 2 different instances of shape
A shape object represents a geometric shape which can be added to a shapefile which is displayed in t...
Definition: Shape.cs:41
Shape Clone()
Creates a deep copy of this object with the same type, parts and points.
Definition: Shape.cs:123
Provides a functionality for accessing and editing ESRI shapefiles.
Definition: Shapefile.cs:72
Shape get_Shape(int shapeIndex)
Gets the reference to the specified shape.
Definition: Shapefile.cs:379
int EditAddShape(Shape shape)
Adds a new shape to the shapefile.
Definition: Shapefile.cs:863
Shapefile Clone()
Creates a copy of the shapefile.
Definition: Shapefile.cs:1376

MapWinGIS objects are not thread-safe. Therefore accessing the same object from several threads should be made with caution especially when the editing takes place.

B. Error handling and progress information.
By design MapWinGIS doesn't throw exceptions to return the information about errors. If an unhandled exception is still thrown, in the most cases it should be treated as a bug and reported to the Issue tracker.
To notify a client about success or failure of certain method the following approaches are used:

  1. A boolean return value (for C++ it's VARIANT_BOOL* [out, retval] parameter);
  2. Null reference in case the method must return some object reference;
  3. For C++ it's also possible to check HRESULT return values, but it's not recommended as MapWinGIS relies on first 2 approaches.
    string filename = "somefile.shp";
    Shapefile sf = new Shapefile();
    // function returns false on failure
    bool success = sf.Open(filename, null);
    if (!success)
    {
    Debug.Print(sf.get_ErrorMsg(sf.LastErrorCode));
    }
    else
    {
    // function returns null pointer on failure
    Shapefile sfCopy = sf.Clone();
    if (sfCopy == null)
    {
    Debug.Print(sf.get_ErrorMsg(sf.LastErrorCode));
    }
    }
    string get_ErrorMsg(int errorCode)
    Gets the description of the specific error code.
    Definition: Shapefile.cs:295
    int LastErrorCode
    Gets the code of last error which took place inside this object.
    Definition: Shapefile.cs:249
    bool Open(string shapefileName, ICallback cBack)
    Opens shapefile from the disk.
    Definition: Shapefile.cs:1430

If the execution failed, there are generally 2 ways to get information about the reason of failure.

// 1. Class.LastErrorCode and Class.get_ErrorMessage properties, which are defined for all major classes. If no error took place within this instance of class "No error" string will be return. Every call of LastErrorCode property will clear the error, i.e. reset it to the "No error" state.

Shapefile sf = some_shapefile;
Shape shp = sf.get_Shape(sf.NumShapes); // deliberately faulty line; the last index is NumShapes - 1
Debug.Print(sf.get_ErrorMessage(sf.LastErrorCode)); // "Index Out of Bounds" error will be reported
Debug.Print(sf.get_ErrorMessage(sf.LastErrorCode)); // "No error" will be reported as the error was cleared by previous call
int NumShapes
Gets the number of shapes in the shapefile.
Definition: Shapefile.cs:254


// 2. Class.GlobalCallback property. If the object which implements ICallback interface was set to this property the error description will be passed to the ICallback.Error method.

ICallback interface can also be used to report the information about the progress of some lasting task.

public void Test()
{
Shapefile sf = new Shapefile();
sf.GlobalCallback = new Callback();
}
class Callback : ICallback
{
public void Error(string KeyOfSender, string ErrorMsg)
{
Debug.Print("Error reported: " + ErrorMsg);
}
public void Progress(string KeyOfSender, int Percent, string Message)
{
Debug.Print(Message + ": " + Percent + "%");
}
}
ICallback GlobalCallback
Gets or sets a Callback object which handles progress and error messages of the Shapefile class.
Definition: Shapefile.cs:219
An interface for callback objects which can be used to return information about progress and errors.
Definition: GlobalCallback.cs:34
void Error(string keyOfSender, string errorMsg)
A function to report the information about an error.
void Progress(string keyOfSender, int percent, string message)
A function to report the information about progress of the task.


C. Map redraw.
Map control tracks some of the changes of its properties and data layers and trigger redraws to display them. It's usually applicable to all the AxMap members. But changes to the data layers made through API of other classes (like Shapefile or Image) will not be tracked. Therefore an explicit AxMap.Redraw() call will be needed to display the changes. In general it's a good practice to call redraw explicitly and not to rely on built-in tracking of state change.

AxMap axMap = map_instance;
Shapefile sf = some_shapefile;
axMap.AddLayer(sf, true); // the map will be updated automatically
sf.DefaultDrawingOptions.LineWidth = 3; // the map wasn't be updated
axMap.Redraw(); // the thick lines will be shown only here
Map component for visualization of vector, raster or grid data.
Definition: AxMap.cs:56
void Redraw()
Redraws all layers in the map if the map is not locked.
Definition: AxMap.cs:183
float LineWidth
Gets or sets the width of the lines to draw shapes.
Definition: ShapeDrawingOptions.cs:624
ShapeDrawingOptions DefaultDrawingOptions
Gets or sets an instance of ShapeDrawingOptions class which holds default drawing options.
Definition: Shapefile.cs:111
int AddLayer(object Object, bool visible)
Adds a layer to the map.
Definition: AxMap.cs:1342

AxMap.Redraw2 rather AxMap.Redraw should be called when there is need to update only temporary objects on map (so-called "drawing layers") rather then to redraw the whole map. The former operation is fast and can be used for display of objects being dragged atop the map for example.

AxMap axMap = map_instance;
int handle = axMap.NewDrawing(tkDrawReferenceList.dlScreenReferencedList);
axMap.DrawPolygon(arguments);
axMap.Redraw2(); // redraw of drawing layer only to see the polygon (fast)
axMap.Redraw(); // complete redraw of the map (slow)
tkDrawReferenceList
The type of spatial reference for the drawing layer.
Definition: Enumerations.cs:484
void Redraw2(tkRedrawType redrawType)
Performs specific type of map redraw.
Definition: AxMap.cs:370
void DrawPolygon(ref object xPoints, ref object yPoints, int numPoints, uint color, bool fill, byte alpha=255)
Draws a polygon on the last drawing layer created using AxMap.NewDrawing.
Definition: AxMap.cs:1780
int NewDrawing(tkDrawReferenceList projection)
Creates a new drawing layer on the map returning its handle.
Definition: AxMap.cs:1868


D. Some aspects of interaction with .NET.

  1. Interop libraries. In order to use MapWinGIS in .NET environment 2 interop assemblies (wrappers) must be generated: AxInteriop.MapWinGIS.dll and Interop.MapWinGIS dll. Visual Studio generates these assemblies automatically in the process of adding AxMap control on the form. Tlbimp.exe and Aximp.exe command line utilities can be used to do the same tasks manually.

  2. Passing colors. The OLE_COLOR data type used by MapWinGIS is mapped to UInt32 in .NET, which doesn't provide immediate means for specification of colors using System.Drawing.Color class. The following 2 approaches can be used.
    Shapefile sf = new Shapefile();
    //1. ColorTranslator class can be used to do the job
    sf.DefaultDrawingOptions.FillColor = Convert.ToUInt32(ColorTranslator.ToOle(Color.Red));
    //2. there is ColorByName method of the Utils class
    Utils utils = new Utils();
    tkMapColor
    A list of named constants for some of the well-known colors.
    Definition: Enumerations.cs:951
    uint FillColor
    Gets or sets the fill color of the shape.
    Definition: ShapeDrawingOptions.cs:471
    A utils object provides access to a set of utility functions to perform a variety of tasks on other o...
    Definition: Utils.cs:20
    uint ColorByName(tkMapColor Name)
    Returns the numeric representation for the specified color.
    Definition: Utils.cs:40

  3. Consuming the variant data type. .NET doesn't have data type equivalent to COM VARIANT. Therefore arguments of of variant type are converted to the object data type. Variant parameters can be used in the following scenarios:
    • to return any COM class with IDispath interface (see AxMap.get_GetObject);
    • to return the array of objects (see Shapefile.SelectShapes);
    • to get or set the values in the attribute table, which can be of either double, integer or string type (see Table.get_CellValue). Use the documentation to find out the data type the output values should be cast to on the .NET side.

  4. Create registrationless COM manifest file. Registrationless COM lets you use MapWinGIS without it being registered in the registry. This means it's possible to deploy MapWinGIS along with your own application using plain xcopy semantics.
    How to generate this manifest?

    • In Visual Studio right click on the MapWinGIS reference and select Properties
    • Click on the Isolated DropDown and select True
    • Compile and that's all there's to it. Visual Studio will create a yourApp.exe.manifest file right alongside your application's EXE.

    When you copy the MapWinGIS files to your client, don't forget to include all files including the GDAL files and folders.