English

How To: Create custom objects in C++

Summary

MapObjects 2.x allows custom symbol rendering code in an integrated manner. To do so, write an OLE (COM) class that implements a well defined API. MapObjects 2.x now supports five custom interfaces:

ICustomFill
ICustomLine
ICustomMarker
ICustomProjection
ICustomRenderer

Since MapObjects2 uses OLE interface to interact with custom symbols, source code nor libraries are needed to build the custom symbols. All the definitions are distributed in a type library (AfCust20.tlb). This file can be found in the "..\Common Files\ESRI\" directory.

When using Visual C++ the easiest way to build COM objects that implement these interfaces is to use the ATL. ATL is the Active Template Library, a set of template-based C++ classes, which allows for the easy creation of small, fast (COM) objects.

The following steps demonstrate how to create a custom point symbol; they can be modified with ease to provide support for custom fill and line symbols, custom renderers and projections. A similar description for creating custom projections exists in the online Help.

When distributing the application, ensure all necessary DLL's are distributed - the ATL COM application will have dependancies on Visual Studio 6.0 DLL's.

Create the ATL COM DLL, using the ATL COM AppWizard, as described below.

Procedure

The following is an example procedure to create a custom point symbol server in Visual Studio 6.0:

  1. Click File > New. Continue with:

    A. Select Projects tab.
    B. Enter project name, for example, customSymbol.
    C. Press OK.
  2. ATL COM AppWizard - Step 1 of 1

    A. Select Dynamic Link Library radio button.
    B. Check MFC support.
    C. Press Finish.
  3. At the New Project Information, click OK.
  4. Click Insert > New ATL Object. Continue with:

    A. Select Objects in the list of Categories.
    B. Select Simple Object in the list of Objects.
    C. Click Next.
  5. ATL Object Wizard Properties:

    A. Select Names.
    B. Enter the name of the point symbol class in Short Name; for example: MyPointSymbol.
    C. On the Attributes tab, no change is necessary.
    D. Click OK.
  6. Click Workspace window > ClassView tab. Continue with:

    A. Expand the list of classes in your project.

    B. Find a class name starting with a 'C', such as CMyPointSymbol. Right-click on this class, and select Implement Interface.
    C. The warning dialog box warns that an ‘idl’ file is needed; click OK.
  7. Browse Type Libraries:

    A. Click Browse.
    B. Find and select AFCust20.tlb. This is usually in ‘..\Common Files\ESRI\’
    C. Click Open.
  8. Implement Interface:

    A. At the list of the interfaces supported by AFCustom20, check the box next to ICustomMarker to implement the point symbol interface
    B. Click OK.
  9. At Workspace window > ClassView tab:

    Double-click on the CMyPointSymbol class; it opens the file 'MyPointSymbol.h' in a window.
  10. In 'MyPointSymbol.h':

    A. Locate the implementations of SetupDC, ResetDC, and Draw.

    These will look like this:

    Code:

    STDMETHOD(SetupDC)(LONG hDC, DOUBLE dpi, IDispatch * pBaseSym)
    {
    return E_NOTIMPL;
    }
    STDMETHOD(ResetDC)(LONG hDC)
    {
    return E_NOTIMPL;
    }
    STDMETHOD(Draw)(LONG hDC, LONG x, LONG y)
    {
    return E_NOTIMPL;
    }


    B. Add a private member variable. In the workspace window > ClassView Tab, highlight the CMyPointSymbol class. Right-click and select ‘Add member variable’. Enter type as CPen* and name as m_oldPen. This will be used to hold the old pen object that is returned from CDC::SelectStockObject

    C. Add the code to implement a custom point symbol. The following example is very basic – it simply draws each point symbol as three concentric squares.
    Code:
    STDMETHOD(SetupDC)(LONG hDC, DOUBLE dpi, IDispatch * pBaseSym)

    {
    CDC* pcdc = CDC::FromHandle((HDC)hDC);
    m_oldPen =
    CPen*)pcdc->SelectStockObject(BLACK_PEN);
    return S_OK;
    }
    STDMETHOD(ResetDC)(LONG hDC)
    {
    CDC* pcdc = CDC::FromHandle((HDC)hDC);
    CPen* temp = pcdc->SelectObject(m_oldPen);
    temp->DeleteObject();
    return S_OK;
    }
    STDMETHOD(Draw)(LONG hDC, LONG x, LONG y)
    {
    CDC* pcdc;
    pcdc =
    ::CDC::FromHandle((HDC)hDC);
    CPoint pt;
    for (int i= 0; i<10; i+=2)
    {
    pt.x = x-i;
    pt.y = y-i;
    pcdc->MoveTo(pt);
    pcdc->LineTo(pt.x+(2*i),pt.y);
    pcdc->LineTo(pt.x+(2*i),pt.y+(2*i));
    pcdc->LineTo(pt.x,pt.y+(2*i));
    pcdc->LineTo(pt);
    }
    return S_OK;
    }

  11. At Build > Set Active Configuration, select Win32 Release MinDependency.
  12. At Build > Rebuild All, build your dll.

    The new COM object can now be used in the application.
  13. The following example uses Visual Basic to demonstrate the use of the new COM point symbol object:

    A. Create a new project with the MapObjects2 control loaded.
    B. Add a map control to the form and add a points shape file layer ("..\data\world\cities.shp").
    C. To load the CustomlSymbol into your Visual Basic project, select the Project > References option and check the appropriate checkbox.
    D. Look for 'Custom Symbol 1.0 Type Library'. If VB cannot find the type library, you may need to browse for it.
    E. Locate 'CustomSymbol.tlb'.

    Code:

    Private Sub Command1_Click()

    Dim oLayer As MapObjects2.MapLayer
    Set oLayer = Map1.Layers(0)

    Dim myMarker As New CUSTOMSYMBOLLib.MyPointSymbol
    Dim oSymbol As New MapObjects2.Symbol

    oLayer.Symbol.Custom = myMarker
    Map1.Refresh

    End Sub