Automation with C++ (Compile OK but Errors in Linking)

rules
09-01-2005, 08:58 AM
I was trying to compile the example code of the article about Automation of Mappoint with C/C++ http://www.mp2kmag.com/a122--c-c++.automation.ole.mappoint.html
and i manage to compile it, but when i do the "Build MapPointApp.exe" Microsoft Visual C++ gives me lots of errors like this:
Linking...
MapPointApp.obj : error LNK2001: unresolved external symbol "public: long __thiscall MapPoint::_Application::Quit(void)" (?Quit@_Application@MapPoint@@QAEJXZ)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::_Map::PutSaved(short)" (?PutSaved@_Map@MapPoint@@QAEXF@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: long __thiscall MapPoint::Pushpin::Delete(void)" (?Delete@Pushpin@MapPoint@@QAEJXZ)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: long __thiscall MapPoint::_Map::SaveAs(class _bstr_t,enum MapPoint::GeoSaveFormat,short)" (?SaveAs@_Map@MapPoint@@QAEJV_bstr_t@@W4GeoSaveFor mat@2@F@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: long __thiscall MapPoint::_Map::ZoomIn(void)" (?ZoomIn@_Map@MapPoint@@QAEJXZ)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: long __thiscall MapPoint::Location::GoTo(void)" (?GoTo@Location@MapPoint@@QAEJXZ)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::Pushpin::PutHighlight(short)" (?PutHighlight@Pushpin@MapPoint@@QAEXF@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::Pushpin::PutBalloonState(enum MapPoint::GeoBalloonState)" (?PutBalloonState@Pushpin@MapPoint@@QAEXW4GeoBallo onState@2@@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::Pushpin::PutSymbol(short)" (?PutSymbol@Pushpin@MapPoint@@QAEXF@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: class _com_ptr_t<class _com_IIID<struct MapPoint::Pushpin,&struct __s_GUID _GUID_34b0f619_37e1_4c76_a6da_69bf75a5d3de> > __thiscall MapPoint::_Map::AddPushpin(struct MapPoint::Loca
tion *,class _bstr_t)" (?AddPushpin@_Map@MapPoint@@QAE?AV?$_com_ptr_t@V?$ _com_IIID@UPushpin@MapPoint@@$1?_GUID_34b0f619_37e 1_4c76_a6da_69bf75a5d3de@@3U__s_GUID@@A@@@@PAULoca tion@2@V_bstr_t@@@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: class _com_ptr_t<class _com_IIID<struct IDispatch,&struct __s_GUID _GUID_00020400_0000_0000_c000_000000000046> > __thiscall MapPoint::FindResults::GetItem(struct tagVARIANT *)" (?G
etItem@FindResults@MapPoint@@QAE?AV?$_com_ptr_t@V? $_com_IIID@UIDispatch@@$1?_GUID_00020400_0000_0000 _c000_000000000046@@3U__s_GUID@@A@@@@PAUtagVARIANT @@@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: class _com_ptr_t<class _com_IIID<struct MapPoint::FindResults,&struct __s_GUID _GUID_188084cf_db96_482b_97a6_2571df9bef81> > __thiscall MapPoint::_Map::FindAddressResults(class _bs
tr_t,class _bstr_t,class _bstr_t,class _bstr_t,class _bstr_t,class _variant_t const &)" (?FindAddressResults@_Map@MapPoint@@QAE?AV?$_com_p tr_t@V?$_com_IIID@UFindResults@MapPoint@@$1?_GUID_ 188084cf_db96_482b_97a6_2571df9bef81@@3U__s_GUID@@ A@@@@V_bstr
_t@@0000ABV_variant_t@@@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: class _com_ptr_t<class _com_IIID<struct MapPoint::_Map,&struct __s_GUID _GUID_90b167c0_923d_4b65_aee2_66938491c916> > __thiscall MapPoint::_Application::GetActiveMap(void)" (?GetAc
tiveMap@_Application@MapPoint@@QAE?AV?$_com_ptr_t@ V?$_com_IIID@U_Map@MapPoint@@$1?_GUID_90b167c0_923 d_4b65_aee2_66938491c916@@3U__s_GUID@@A@@@@XZ)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::_Application::PutUnits(enum MapPoint::GeoUnits)" (?PutUnits@_Application@MapPoint@@QAEXW4GeoUnits@2 @@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::_Application::PutCaption(class _bstr_t)" (?PutCaption@_Application@MapPoint@@QAEXV_bstr_t@@ @Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::_Application::PutWindowState(enum MapPoint::GeoWindowState)" (?PutWindowState@_Application@MapPoint@@QAEXW4GeoW indowState@2@@Z)
MapPointApp.obj : error LNK2001: unresolved external symbol "public: void __thiscall MapPoint::_Application::PutVisible(short)" (?PutVisible@_Application@MapPoint@@QAEXF@Z)
Debug/MapPointApp.exe : fatal error LNK1120: 17 unresolved externals
Error executing link.exe.

MapPointApp.exe - 18 error(s), 0 warning(s)
Please, can anyone help me? I know if i get this code to work i could do my own but damn Murphy's Law, DAMN IT!!

Wilfried
09-02-2005, 06:25 AM
Hi,

As it is unresolved externals given by the linker, it is some obj file that is not linked in. Maybe the typelibrary file ? It should be generated by the IDE and it has to be in the linker options.

Note that I dont know nor have Microsoft visual C++, so I'm just gueassing.

hieronymus1
09-02-2005, 10:11 AM
Hi,

A few years ago I got an working C++ MFC program which embedded the mappoint control. Was not easy I remember. Perhaps I will find it once I search on my harddisk.

rules
09-03-2005, 07:03 AM
I will thank you hieronymus1 if you find that code. I need it for something important.

About what Wilfried said:

The type library is called mpna82.tlb and it's in the folder where you install MapPoint. I import it in my code. And the compiler generates two files mpna82.tlh and mpna82.tli that contain definitions of all structs, enums, and so on, and functions to call MapPoint functions, for example:

LocationPtr Location::GetLocation ( ) {
struct Location * _result;
HRESULT _hr = get_Location(&_result);
if (FAILED(_hr)) _com_issue_errorex(_hr, this, __uuidof(this));
return LocationPtr(_result, false);
}

is defined in mpna82.tli.

I don't know how to solve this unresolved external symbol the linker gives me.

I have another question about the COM programing. Is it possible to compile the C++ app under linux, tu execute it under linux, if you have your mappoint installation mounted on a linux folder? or do this COM interface need to execute on windows necesarylly?

Wilfried
09-04-2005, 01:08 PM
Hi,

I'm pretty sure the COM interface has to be on Windows. I dont know about the unresolved externals since I dont know the IDE. Hope you find it.

ma2005pp
09-07-2005, 03:37 PM
I tried this example. After some modification, it works. Following is what I did step by step:

1. Create a console project in VC6.0
2. Copy code to files
ComInterfaces.h
ComInterfaces.cpp
MapPointApp.cpp
3. Build -- lots of errors
So I add
using namespace MapPoint;
4. Build again -- 1 error
I erase ", geoCountryDefault" from the FindAddressResults parameter list
Build -- No error
5. Run -- 0x00000005 Access Violation
I add 5 release() calls at the end of the code, something like

...
myMapPtr->Saved = true;

pinAddressPtr.Release();
locAddressPtr.Release();
resultsPtr.Release();
myMapPtr.Release();

g_pMapPoint->Quit();
g_pMapPoint.Release();

CoUninitialize();
}

6. Run -- OK

rules
09-08-2005, 09:54 AM
I did follow steps 1 to 4. But the erros it gives me building are not when compiling but when linking. I think is a problem of missconfiguration of my IDE, that is, Microsoft VC++6.0. I asked one of my university teachers about it and told me it could be some problem with the PATH system variable but i selected the option "Register environmental variables" when installing. It has to be something very simple and stupid but i don't find it,, damn it.

But ma2005pp, thanks a lot for you mini-guide, cause i'm sure when i solve these unresolved symbols, i would have found a problem with the access violation. Now i know how to solve that other problem.

ma2005pp
09-08-2005, 04:50 PM
I think you should

(1) double check the file mpna82.tlb

On my machine, the file is

C:\WINDOWS\system32>dir "C:\Program Files\Microsoft MapPoint\mpna82.tlb"
Volume in drive C has no label.
Volume Serial Number is B058-A879

Directory of C:\Program Files\Microsoft MapPoint

06/20/2003 02:11 AM 134,832 MPNA82.tlb
1 File(s) 134,832 bytes

(2) if there are files mpna82.tlh and mpna82.tli
in your debug or release folder

(3) Build the code with map file, and try to find if the missing symbols are in the map file. For example, I could find method "Quit" in my map file

0001:000001d0 ?Quit@_Application@MapPoint@@QAEJXZ 004011d0 f ComInterfaces.obj

rules
09-09-2005, 10:09 AM
Thanks.

I have solved the problem. It was some kind of missconfiguration of VC++.
If any of you are interested in what i'm doing here is my code (working).
It makes reverse geocoding by an spiral algorithm and also saves the map.
MapPointApp.cpp
/******************************************
* *
* CGI de conversion de coordenadas GPS *
* *
******************************************/


#include "ComInterfaces.h"
#include <stdio.h>
using namespace MapPoint;

MapPoint::_ApplicationPtr g_pMapPoint = NULL;

void main( int argc, const char*argv[] )
{
char *endptr;
//first and second arguments are latitude and longitude
double lat = strtod(argv[1], &endptr);
double lon = strtod(argv[2], &endptr);

CoInitialize( NULL );

/********************
* Initialization *
********************/

g_pMapPoint.CreateInstance( "MapPoint.Application" );
g_pMapPoint->Visible = false;
g_pMapPoint->PutWindowState( geoWindowStateMinimize );
g_pMapPoint->PutCaption( "MapPoint 2004 is in Automation Mode!" );
g_pMapPoint->PutUnits( geoKm );

_MapPtr myMapPtr = g_pMapPoint->ActiveMap;


/**********************************
* Find street name by lat/long *
**********************************/

int step = -1;
int step_m = -1;
int mult = 0;
StreetAddressPtr sap;
LocationPtr latlongPos;

LocationPtr latlongPosInicial = myMapPtr->GetLocation(lat,lon,1);
printf("Position(lat/long): %s\n", (char*)latlongPosInicial->Name);

VARIANT idx;
VariantInit( &idx );
V_VT(&idx) = VT_I4;
V_I4(&idx) = 1;

for(int j=0;j<1000;j++){

latlongPos = myMapPtr->GetLocation(lat,lon,1);
latlongPos->GoTo();

FindResultsPtr resultsPtr =
myMapPtr->ObjectsFromPoint( myMapPtr->LocationToX(latlongPos),
myMapPtr->LocationToY(latlongPos));
if(resultsPtr->GetCount()>0){

LocationPtr res = resultsPtr->GetItem( &idx );
sap = res->StreetAddress;
if(sap!=NULL){
printf("Street: %s\n", (char*)sap->GetValue());
//latlongPosInicial = res;
printf("Error margin: %.3f Km\n",
llatlongPosInicial->DistanceTo(latlongPos));
goto found;
}
}
//Increases espiral by 0.00002 degrees
step = (step+1)%4;
step_m = (step_m+1)%3;
if(step_m == 0) mult+=1;
switch(step){
case 0:
lat+=0.00002*mult;
break;
case 1:
lon+=0.00002*mult;
break;
case 2:
lat-=0.00002*mult;
break;
case 3:
lon-=0.00002*mult;
break;
}
}

printf("Street not found\n");

found:

/******************
* Map creation *
******************/

PushpinPtr pinAddressPtr = myMapPtr->AddPushpin( latlongPosInicial,
"You are here"/*nombre_calle*/ );

if(sap!=NULL) pinAddressPtr->PutNote(sap->GetValue());

pinAddressPtr->PutSymbol( 82 );

pinAddressPtr->BalloonState = geoDisplayBalloon;
pinAddressPtr->Highlight = true;

myMapPtr->SaveAs( "C:\\MapIsHere", geoFormatHTMLMapAndDirections, false );

pinAddressPtr->Highlight = false;
pinAddressPtr->BalloonState = geoDisplayBalloon;
pinAddressPtr->Delete();

myMapPtr->Saved = true;

g_pMapPoint->Quit();

CoUninitialize();
//end
}


It is a console application. You pass the latitude and longitude values and then it prints the nearest street, the real distance to the point specified (error margin) and saves the map as an html document.

Thanks a lot for all your help and for the article about c++ automation.
Now this works perfect :D

Eric Frost
09-09-2005, 10:30 AM
Thanks for sharing and following up!!

Eric

rules
09-09-2005, 11:46 AM
I have just realized my spiral algorithm is not very good if you pick a position very far from any street cause the spiral is like this:
*-------*
| |
| *---* |
| | | |
| | *-* |
| | |
| *-----*
|
*-------...
The points represent where the program searches for a Location containig a street. So, if the spiral grows very much, the points would finish being very far one from another. I will try to correct this with more searching points between points from corners.

Wilfried
09-09-2005, 12:01 PM
Hi,

The way I do this is following:

- first check if we are on a street of course
- then make a circle with radius of 5 meter, and start scanning the cirucmfence of the circle with a resolution of 5 meter.
- if no address found at >= 360 degree then increase radius of circle with 5 meter, and start scanning again on circumfence with 5 meter resolution
- this repeat until address is found or until a certain maximum

I try to post some code this eve if I dont forget it :)

 
Web mp2kmag.com
mapforums.com