 |
|
 |
 |
Using MapPoint 2001 from C++ - the 'FindAddress' Problem
The MFC ClassWizard makes using MapPoint from
C++ almost as easy as it is from VB. This article explains the basics,
and provides a plug-in replacement for the MapPoint 2001 "FindAddress" not supported by ClassWizard
The simplest way talk to MapPoint via automation from C++/MFC
is using ClassWizard generated wrappers - here's a brief recap how
this is done:
- create or open an MFC-based application
- open ClassWizard e.g. by pressing Ctrl-W
- press the "Add Class ..." button and select "from a type library"
- locate the type library for your version of MapPoint - look for a
file with a .tlb extension in the MapPoint installation directory. For
the North American version of MapPoint 2001, it is called MPNA80.TLB.
Select this file and press Open.
[NOTE: If you have MapPoint 2002, the corresponding type library is
called MPNA81.TLB or MPEU81.TLB in the European version.]
- For each class of the MapPoint object model you want to use in your
project (e.g. _Application, _Map, Location, Pushpin), do the
following:
- select the class
[NOTE: If you have MapPoint 2002 installed but would like to stay
compatible with MapPoint 2001 on your users machines, select the
classes that have an "80" in their name]
- rename it under "class name" - use a consistent prefix, e.g.
prefix all your MapPoint objects with "Mp"
- If you want, you can also rename the .CPP and header file that will
be generated.
- Make sure all classes you want included are selected.
- Press OK, then OK again.
- Make sure you initialize the COM library by adding a call to
AfxOleInit() in the InitInstance method of your app.
- don't forget to #include the generated header file for the MapPoint
wrapper objects in your source code - the default name e.g. for
MapPoint 2001 North America is MPNA80.H
After you have completed these steps, you can check whether MapPoint
obeys your commands by adding e.g. the following code to the event
procedure of a button or menu item:
MpApplication mpApp;
mpApp.CreateDispatch("MapPoint.Application");
mpApp.SetVisible(true);
MessageBox("MapPoint should be visible now ...");
mpApp.Quit();
mpApp.ReleaseDispatch();
One problem with the wrapper classes generated for MapPoint 2001 by the class
wizard is that due to an MFC limitation, the FindAddress method of the Map class
cannot be generated - instead, you will find the following comment in the generated
code:
// method 'FindAddress' not emitted because of invalid
// return type or parameter type
The problem is that "FindAddress" uses a variable-length list of arguments, and
the COleDispatchDriver MFC class used by the wizard as base class for your
wrapper classes and responsible for packaging and invoking automation calls,
does not understand how to package the SAFEARRAY type.
A detailed description of the problem can be found in
Microsoft knowledgebase article Q158451.
The good news is that a replacement "FindAddress" can be added relatively easily -
the corresponding code is shown below.
This routine sets up the arguments and calls the Invoke method of the
COleDispatchDriver class itself. On input, it accepts a (mandatory) street
address, additional (optional) address strings, and finally, a country code
that indicates which country the address should be searched in.
(The country codes can be determined e.g. by opening the MapPoint type library in the
OLE/COM object viewer available on the VC++ Tools menu)
To provide the map wrapper object the wizard generated for you with a
FindAddress method, add the code above to the corresponding
implementation file (e.g. MPNA80.CPP). Make sure you adapt the object
name to what you selected at creation time - if your map object
wrapper is called "MaptMap" instead of "MpMap" as in my case, change
the MpMap::FindAddress above accordingly. Also, add the following
declaration:
LPDISPATCH MpMap::FindAddress(LPCTSTR szStreet,
const CStringArray& sarAddressStrings,
short nCountryCode);
to the wrapper header file (e.g. MPNA80.H), e.g. after below the "FindAddress
not emitted" comment inserted by the wizard.
Here's a short snippet that shows how you would use the routine.
MpApplication mpApp;
MpMap mpMap;
mpApp.CreateDispatch("MapPoint.Application");
mpApp.SetVisible(-1);
mpMap = mpApp.GetActiveMap();
CStringArray sarAddress;
sarAddress.Add("Redmond");
sarAddress.Add("WA");
sarAddress.Add("98052");
MpLocation mpLoc = mpMap.FindAddress(
"1 Microsoft Way",
sarAddress,
244);
mpLoc.GoTo();
MessageBox("Press OK to close MapPoint");
mpLoc.ReleaseDispatch();
mpMap.SetSaved(-1);
mpMap.ReleaseDispatch();
mpApp.Quit();
mpApp.ReleaseDispatch();
The snippet creates a MapPoint application object, makes it visible,
and retrieves the active map. It then adds the address components
(except for the street which is always passed as the first parameter)
to a CStringArray. The location returned by the FindAddress method of
the map object is stored in a corresponding object variable which is
used to center the map around the address.
Conclusion: With ClassWizards help, remote-controlling MapPoint and
other automation servers is a breeze. Methods with variable argument
lists need some extra attention, but the problem is solvable.
In MapPoint 2002, "FindAddress" is still available for compatibility
reasons, but it has been replaced by the more powerful
"FindAddressResults" method which can return several addresses at
once, and is supported by ClassWizard.
Discuss this story in the forum.
Author: Gilles Kohl Email: gilles(AT)_deletethisincludingunderlines_compuserve.com URL: http://www.procad.de Gilles Kohl, a native of Luxembourg living in Germany, is a software development lead with PROCAD GmbH of Karlsruhe, Germany. Mapping and especially GPS-related topics are a hobby - Gilles enjoys developing solutions for Microsoft MapPoint and his favorite outdoor occupation is confluence hunting. As always, please direct questions to the newsgroup.
|
 |
 |
 |
Recent Discussion
|
 |
|
 |
 |
|
 |
Resources
|
 |
|
 |
|
 |