MapWinGIS Ax with dBase2019: unable to open files

Hello,
I am new to GIS and very interested in embedding MyWinGIS activeX into our applications which include remote equipment management.
Dev environment: dBase2019 v3.2 release 11-2019 - Win10 pro 64 - MapWinGIS activeX v.5.2).
The activex works fine with all events and related methods as well as class libraries called by the dBase New OleAutoClient ("") method.
I carried out loading tests for shapefiles and markers for POIs (GPS coordinates of managed devices), unfortunately without success. The open file function returns an “OLE data type mismatch” message whether it is shp or png. Here is the dBase syntax used:
Image file:
cfile = getfile (".png", “Choose a marker”)*
img = new oleAutoClient (“MapWinGIS.image.1”)
img.Open (cFile, 5, true, null) // 5 = png, true = inRam, no callback
Shape file:
cShp = getFile (". shp", “Choose a shapefile”)*
sf = new oleAutoClient (“MapWinGIS.Shapefile.1”)
sf.Open (cShp, null)
I used the examples provided by the mapwindow.org online documentation and all the properties and methods are accessible (at least the existing ones because visible by inspecting them!)

  • Do I have to predefine more precise parameters before opening?
  • are there any differences between v.5.2 and the online documentation (v.4.9)?
  • must the variable containing the name of the file be completed or delimited with special characters?
  • other reason, forgot something?
    I also noticed that some methods require more arguments than in the online documentation

Sorry for my newbie questions! but it’s frustrating to display and manage a map and be blocked by such a basic function!
And thanks in advance for helping me to get out of this deadlock!
Kind regards
J.

Hello @Joseph, and welcome.

I’m gonna take an initial crack at this, admitting that I may be wrong, having no knowledge of dBase2019.

It looks to me that OleAutoClient is a wrapper around OLE Automation. Here’s what I found in their documentation.

Automation is intended to control objects that live in an Automation Server, such as “Excel.Application”.

The objects exposed from MapWinGIS are simple COM objects, and MapWinGIS is not an automation server. That is likely the reason you cannot successfully create a Shapefile using OleAutoClient.

I tried looking for other COM wrappers in their documentation, but couldn’t find any. You say that you are able to display and manage a map?

  1. So you are able to load the OCX, is this true?
  2. If so, are you able to call any methods from the AxMap control once it is loaded (such as AddLayerFromFilename)?

I hope that if it is possible, we will be able to find the solution.

Regards,
Jerry.

Hello @jerryfaust ,
Sorry for the delay, we have to deal with timezones and I also proceeded to some tests before answering.

  1. Yes the OCX loads fine
  2. Yes I tested the AddLayerFromFilename method and it works !

except that all the get_xxx methods like get_Shapefile AND set_xxx methods are missing when I inspect the axMap object. All the others exist, I used some and they work fine. (maybe it has something to do with the underscore character ?)

I also tested the CreatePointShapefile example which works (except drawing flags in wrong coordinates… I have to check) and here again, I get the same error on saving in a shp file.

I first I deduced a common problem dealing with file access but, oddly, .shp files are opened with ‘AddLayerFromFilename’ !?

Fyi, I’m used to third-party OCX and APIs tools for years, specially Crystal Reports which is a complex one (OCX viewer and powerful OLE API) still working perfectly (print/preview, changing formulas, parameters, databases, saving, etc.) so I know I have to invest some time with mapWinGIS… but not too much!
Embedding GIS in our software is an important enhancement even if the current need is limited to a map display of managed POIs and linked info pop-ups.

I also hope going successfully further with MapWinGIS.
Thanks again
and best regards
Joseph

Hello again. I will comment on a few things you said:

except that all the get_xxx methods like get_Shapefile AND set_xxx methods are missing when I inspect the axMap object. All the others exist, I used some and they work fine. (maybe it has something to do with the underscore character ?)

Not sure if this applies, but the API looks a little different depending upon the language. From c++ and c#, the various properties are exposed with the get_ and set_ prefix; while through VB.net, you just refer to the property name itself, without the get_ or set_ prefix. Have you tried getting a Shapefile reference without the get_ prefix?

I first I deduced a common problem dealing with file access but, oddly, .shp files are opened with ‘AddLayerFromFilename’ !?

I still think this may have to do with the OleAutoClient wrapper. Just for clarification, is it true that all of the methods (including opening a Shapefile) work when called from the AxMap (OCX), but anything called from a standalone component, such as opening a Shapefile from the Shapefile object, don’t work? My thinking is that it doesn’t have to do with file access, but from which component you attempt file access.

Regards.

Addendum:

The reason I bring up these things is because MapWinGIS really consists of 2 separate libraries (so to speak). You have the OCX, which includes the Map Control and all associated properties/methods; then you have a separate set of standalone components (MapWinGIS). This is why (at least in the .NET world), when you reference MapWinGIS, you will get two distinct Interop DLLs, one for the OCX (Interop.AxMapWinGIS.dll) and one for the library (Interop.MapWinGIS.dll). My suspicion (and I may be wrong) is that dBase can ‘see’ the OCX and associated functions, but is not seeing the separate library.

Hello Jerry,

I must first thank you a lot for spending time helping me !
I confirm that dBase ‘sees’ the OCX with its properties, events & methods as an object in a form just like in VB. Classes are also available through their Windows registration, as mentioned in the ‘overview’ documentation. Object reference for each class is done with dBase oleAutoClient function.

I performed different tests to geolocate installed equipment which is the first aspect that interests our software.
Since I couldn’t get the png files as markers, I tried placing points and circles, but both functions result in placing them on coordinates of 0, 0.
Tests were made with Paris coordinate ( 48.85718 , 2.3514992)
For point drawing I defined ‘sf’ and ‘sh’ objects and tested in two ways (with and without using a point reference object).
For circle drawing I first clear all drawing layers, assigned a new one ( AxMap.NewDrawing(1) ) then used DrawCircle(x, y, 6, 255, true).
(is there a difference between a layer and a ‘drawing layer’)
Why the symbol is placed on the coordinates 0, 0?
I used debug mode to watch each step and value but nothing changes until projection of the symbol on the map
I strictly followed the examples provided but perhaps I have to define specific properties / information before ?

if I pass this step, the next will be a pop-up information display for each point and this will be our first phase of evaluation. So you can see we have a very basic need… for the moment !
I must say that after having embedded several OCX in our softwares, it’s the first time we experience file reading / writing errors and its very amazing.
Is there a way to find out what is the source of the error code returned with the open file function ? with the ocx object we only have an interpreted result mentioning a data type mismatch? this must be generated by detecting a specific event.

Thanks again in advance Jerry and have a nice safe day !

Regards

J.

Addendum
After testing point drawing I get ’ LayerProjectionIsEmpty’ event.
I think I missed settings informations before drawing points. Is there a tutorial, white paper or example of main settings to activate before placing objects on a map ?

Addendum 2
In the inst. folder there is no ‘mapwinGIS.dll’, just the MapWinGIS.ocx file and some others dlls. However, in the registry (AppID & CLSID), all classes are present and well registered since they are visible with dBase OleAutoClient. Each generates an object reference, even a ‘map’ class with the same properties, methods, and events as the activex control.

Hello Joseph.

I will try to get to your questions soon. It is true that there is no MapWinGIS.dll; just the OCX. The OCX is registered by the installer, which results in all of the classes being present in the registry.

And although not exactly a tutorial, you can go through the topics on the Main page to get some introductory information.

Just a info about drawing a point to which seems to work. I first set the axMap.Lat/Long coordinates and a zoom value then add the point using axMap.Extents.center.x /y values, and I end with axMap.AddLayer(shapeFile, true).
I’m not sure it’s the academic method! … but it’s better than seeing the point at 0,0 !

Hello Joseph.

Would you mind posting more of your actual code that was resulting in shapes near [0, 0]? It might be helpful to see the full sequence to help resolve the problem (map settings, projection, etc.).

There is a significant difference between the drawing layers and the true Shapefile layers. You have much more control over the actual Shapefile layers in terms of persistence, rendering, spatial queries, etc.

Regards,
Jerry.

Hello Jerry,
I finally succeeded in placing multiple coloured round shapes in the right coordinates but it’s a workaround as reading png files does not work (I hope… for the moment!).
Here is a sample code in dBase syntax, the main reference to axMap is: form.axMap
// ===== Initial settings step:
form.axMap = form.mapw.nativeObject
form.axmap.projection = 2
form.axMap.cursorMode = 2
form.axMap.mapUnits = 8
form.axMap.tileProvider = 0
form.axMap.scaleBarUnits = 0
gs = new oleAutoClient(“MapWinGIS.GlobalSettings.1”)
gs.AllowLayersWithoutProjections = true
gs.AllowProjectionMismatch = True
gs.ReprojectLayersOnAdding = True

// ==== Function drawSHcircle(… params…)
form.axMap.RemoveAllLayers()
shFile = new oleAutoClient(“MapWinGIS.Shapefile.1”)
shFile.CreateNewWithShapeID("", 5) // SHP_POLYGON

// ===== Have to deal with AxMap.extents.center after assigning Lat/Lng to AxMap
form.AxMap.Latitude = nLat // (ie. 48.85718)
form.AxMap.Longitude = nLng // (ie. 2.3514992)
nx = form.AxMap.extents.center.x
ny = form.AxMap.extents.center.y

// ===== Then create a circular shape based on “CreatePolygonShapefile” example
shp = class::SHP_Create(nx, ny, 600) // Radius 600 px.

// ===== Insert in shapeFile
shFile.EditInsertShape(shp, 0)
shFile.DefaultDrawingOptions.FillColor = nClr // Provided as a param.
shFile.DefaultDrawingOptions.SetDefaultPointSymbol(1) // dpsCircle

// ===== Add a layer from the created shapeFile
nLayerHnd = form.axMap.AddLayer(shFile, true)

Placing several colored circles is done by calling this function with appropriate parameters (color, radius,…) from a loop based on an array of coordinates.

All intermediate return values are correct, and we do have different colored circular shapes in the correct locations on the map. Still have few more issues to resolve, the 3 most important are:
1- RemoveAllLayers: previous shapes remain when doing more than one test in a session
2- If I directly assign x,y to create the shape nothing happens (result coord=0,0). I noticed that when assigning AxMap.lat/long and use the AxMap.extents.center.x/y values the circle shape is well located.
3- Resulting shapes are resized when zooming while markers (png files) keep their original size

There is some progress… for a newbie in GIS like me!
Hope this will help…
Thank you again
Kind regards
Joseph

Hello Joseph.

What it looks like, is that you’re setting the projection to 2, which is Google Mercator (or Web Mercator), but then you were setting your shape coordinate in DMS. Since Google Mercator is in meters, you’re effectively setting your position of Paris to roughly 2 meters east and 48 meters north, which is effectively (0, 0) in the big picture. The reason it works in your modified implementation is that you set the Lat/Long, which is always in DMS (no matter what the map projection is), and then you ask for the map extents, which is always in the current map projection - so the map did the coordinate conversion for you. If you look at the values of nx and ny, you should see values in the thousands.

What you probably want to do, if you want your map projection in Google Mercator, is either

  1. transform each coordinate (in DMS) to Google Mercator using GeoProjection.Transform, OR
  2. build a shapefile in DMS, add the shapes in DMS, then add the layer to the map. And since you have set gs.ReprojectLayersOnAdding, the map will transform the shapefile into Google Mercator on-the-fly.

In answer to your issues to resolve:

  1. RemoveAllLayers is not working because you are adding a drawing layer, not a true layer. You can either call ClearDrawing (or ClearDrawings), OR use true layers rather than drawing layers, which in the long run, I recommend.
  2. I think this is due to what I explained above. The question is, are the shapes truly at 0,0 or are they just really close to 0,0?
  3. This is true. Shapes are geometries that maintain their true size, scaling with the map, while images by default render in their native size. If you use a Shapefile, you can use custom rendering, such as ShapeDrawingOptions.ScaleX and ScaleY if you want to resize the image dynamically; but this is not trivial.

I realize that I’m not giving you a lot of details, but hopefully this helps point you in the right direction.

Regards,
Jerry.

Hello Jerry,
Concerning the 1st issue: in the code I dropped I use AddLayer which I think generates a true layer, isn’t that correct? I’ll do more tests today and try to remove layers individually.
2nd. Issue: I have to learn more and go deeper in the different methods to optimize coordinates management…
3rd. issue comes from the error on opening (and saving) files with dll libraries. That’s why I asked about the source error code or method of the ‘open()’ statement:

  • what is expected for a file name, does the string must meet more rules / information than providing a standard file path with it’s drive or network location?
  • why it is interpreted as a “data type mismatch”. This is really important as it’s the first time I meet this kind of issue in an activex… all others I use comply to the basic method of opening / saving files, whatever is the type. This is quite strange…

Solving this problem will be for us the main entry point for a deeper use of this powerful activex!
Best regards
Joseph

Hello Joseph.

I’m sorry I didn’t pay enough attention; I was looking at your code drop and also scrolling up to your earlier post which used DrawCircle. You’re correct, you are adding a true layer, and it should be removed using RemoveAllLayers. So I don’t know what’s wrong there.

Based on that, presuming that you want to add shapes using DMS, you can do the equivalent of:

Dim gp as New GeoProjection()
gp.SetWGS84();

shFile.GeoProjection = gp

This tells the Shapefile that it’s projection is WGS84 (DMS). You can then add your shapes using known DMS coordinates. Then, when you call AddLayer, the map will reproject the layer into Google Mercator.

However, from that point on, you need to realize that the Shapefile and the Shapes are no longer in DMS, so that if you query a shape for it’s points, it will be in Google Mercator meters. And if you want to add a Shape to the layer after adding the layer, you can no longer use DMS because the layer is now in meters.

Regarding the 3rd issue:

  1. It should be a standard path in the string format of DBase, and it requires the .shp file extension.

  2. The data type mismatch sounds like an error being raised by the lower-level c++ code rather than a standard COM error. Are you able to use the callback function ICallback to get errors from the library? If not, you can check the last error using something like:

      Shapefile.get_ErrorMsg(Shapefile.LastErrorCode)
    

See LastErrorCode. Hopefully, you’ll get a better clue of what’s going wrong.

Regards,
Jerry.

Addendum:
Looking at your post from Aug 26/27, I’m guessing that the getfile method returns the full file path, including extension, that the user selected. So that should work.

Are you already using the ErrorMsg call to get the data type mismatch error? If so, give me the exact syntax and I should be able to track it down in the source code.

Thank you.
Jerry.

Quick answer for error codes when attempting to open a shapefile or an image:

  • No Callback / ICallback function (not in lib. list / registry)
  • LastErrorCode = 6 after SF.open(cShpFile)
  • LastErrorCode = 606 after IM.open(cPngFile)
    Same string structure for both variables cShpFile & cPngFile (D:\path\filename.ext)
    No message available: Empty errorMsg(n) for both object references SF & IM

Joseph.

Error 6 can occur many places, and generally indicates that the file is open, but is failing to perform a subsequent operation. It’s hard to guess what it might be.

Would you mind zipping and attaching the shapefile set, and I’ll try opening here to see what happens?

Thank you.

Here is a zip file containing the shapefile set and I also joined the png file which generates 606 err code with img.open(cFpng). Good luck! shp&png.zip (1.6 MB)