Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

MapWinGIS OCX 2

Status
Not open for further replies.

Alec_Gagne

Programmer
Apr 14, 2022
15
US
Are there any VFP folks out there with WinMapGIS OCX experience?

I'm working with the MapWinGIS OCX control (version 5.3) with some degree of success. I've code to create a Shapefile layer, and store the layer handle to a form property, but when the layer already exists I need to identify the object within the map control that corresponds to the LayerHandle. The MapWinGIS documentation suggests that this is easily done by calling the 'get_Shapefile' method to get an object reference to the current Shapefile layer.

[pre]*** Sample MapWinGIS Code ***
sf = axMap1.get_Shapefile(m_layerHandle);
[/pre]


So, I tried calling the 'get_Shapefile' method even though it is not shown in the VFP properties sheet for the ocx but it does not appear to be exposed. The VFP Code below fails with an OLE Error 'Unknown Name'

[pre]loSF = THISFORM.axmap1.get_Shapefile(THISFORM.LayerHandle)[/pre]

It seems more things are exposed in the ocx embedded object so I also tried calling it this way

[pre]loSF = THISFORM.axmap1.object.get_Shapefile(THISFORM.LayerHandle)[/pre]


samplemap1_s9uwne.jpg


* The ultimate goal is to display image icons on the map using VFP. If anyone has VFP sample code that they can share it would greatly speed up my development time...

Any help or examples would be greatly appreciated!

AJ
 
I don't think a Layerhandle exists in the form object, unless you would have defined one.

Chriss
 
Hi Chriss,

Thanks for the reply. You are Correct! 'LayerHandle' is a user defined property I created on my VFP test form so that after I create the new shapefile layer and add it to the map I can store the integer HandleNumber, returned by the AxMap1.AddLayer() method, for later use. I need to subsequently pass that numeric LayerHandle value into the get_Shapefile() method in order to get an instance of the Shapefile object from the map control.

And there in lies my issue, as the requisite get_Shapefile() method does not appear to be exposed by the OCX; or if it is I have not figured out how to call it.

AJ
 
Dear AJ,

Not a direct solution but suggestion to help you!

In your form (or PRG), after the command which creates the object for this ocx, insert a SET STEP ON. When you run it and encounter the STEP ON, you can check the methods and properties of the object from the Watch window or command prompt window. This way you can check if there are any equivalent/corresponding methods for getting the same result.

Rajesh
 
Other than what Rajesh suggested, I can't help you with what is exposed or not exposed from the OCX, that should come from its documentation.

From experience with other Ole COM servers and OCXes I can only tell that it sometimes helps intellisense to offer the list of properties and methods available, if you first set a variable to some object, ie. to you don't see the body object node of a html document node of the Internetexplorer Application OLE automation object, if you do something as simple as:

Code:
oIExplorer = CreateObject("internetexplorer.application")
oIExplorer.Navigate2('google.com')
And then type in [tt]oIExplorer.document.[/tt]
The intellisense list fails to list "body":
intellisensefail_j5bhe1.jpg


If you create a variable [tt]oDoc = oIExplorer.document[/tt] at this point, you can discover the body node by intellisense, too:
intellisensefail2_i2tkpy.jpg


I have to withdraw any hopes this might give you to get at something VFP does not discover directly via this indirection. But this only helps intellisense to overcome a flaw. It's not a general flaw of VFP to acceess the properties or methods the OCX interface makes available. While intellisense doesn't show oIExplorer.document.body, accessing it is not triggering an error. So you don't need to set [tt]oDoc[/tt] to get at [tt]oDoc.body.innerhtml[/tt], you can also get at the innerhtml of the body node via [tt]oIExplorer.document.body.innerhtml[/tt].

So it's merely a flaw of intellisense, not a flaw of accessing what's made available from the OCX via its structure as described by its type library. In short, if the error tells you that get_Shapefile is an unknown name, that's it. The only other thing that I faintly remember right now is that you could get in trouble when the names are case sensitive, for which VFP does not care. Or in other words, VFP will need all lowercase names made available. This can play a role, if you use Javascript objects from VFP, to give one more example in the context of the internet explorer automation server, again. I don't know if it helps you to find the culprit, but that's one article by Rick Strahl, where he mentions this problem, that also leads to the "unknown name" error:

Since you have no control about the method name, there's nothing you can actually do about it directly and from VFP. The only cumbersome solution that I can think of is you need to use any other COM/OLE/OCX capable programming language that can cope with case sensitivity of names and write a wrapper in it, that offers all mixed case property and method names of the OCX as lowercase alternative names VFP can access.

Chriss
 
Rajesh & Chris, Thanks to both of you for the feedback!

So when I examine the OCX object in the debugger at runtime, I see a pretty short list of exposed items.

Image4_z8e4ms.jpg


When I focused in on the 'OBJECT' object within the debugger and see many more things...

Image6_qekxgf.jpg


but I still do not see any reference to the hundreds of methods that the documentation suggests are in the OCX control.

If I programmatically create an instance of the WinMapGIS OCX via the command window the 'OBJECT' object does not exist. Presumably because the OBJECT is a representation of the visual map display and there is no display when created via command window.

Image9_ecehji.jpg


Attempts to reference it in code via the command window, even though it is not displayed via intellisense fail

oTest = Thisform.AXmap.OBJECT

This variable reference does not fail at runtime via my form, but an examination of the oTest object variable via the debugger does not net anything new.

Chris, Thanks for the link to Rick Strahl's post about calling JavaScript functions. His mention that VFP forces all COM interop to be lower case is both enlightening and troubling! So at this point I am sort of suspecting that the documented functions exist within the OCX but perhaps are not visible via intellisense or the debugger and that's okay as there really is no need for them to be visible. That said, if those OCX methods/functions are case sensitive and VFP is forcing all COM interop to lowercase, that could explain why the OCX is responding with an Unknown Name error.

So if this presumption is true, this is a bit of a show stopper... Unless the developers of the OCX make accommodations for this, which might be a BIG ASK !!

AJ
 
If there is a way to use this OCX within a webbrowser control you may be able to wrap the functionality with a wrapper in Javascript. As said that's cumbersome, but Javascript can likely give you a list of members (property/method names) quite like VFPs AMEMBERS does, with Object.getOwnPropertyNames().

So the cumbersome task to get all the names and turn them to lowercase twin properties and methods you can use from VFP can be automated. The issue with that can be, that the web browser control in itself becomes less and less usable for modern HTML content. It's a chance since you can determine the whole HTML layer in this scenario, but it makes it an indirect and less simple use of the OCX, that still may fail on the incapabilities of the web browser control, if the OCX is even able to be used within a browser anyway.

Chriss
 
Thanks again Chris,

While it is an interesting suggestion, I don't believe the OCX was designed for implementation within a web browser and I've not heard of anyone who has done that. Even if it were possible, I suspect doing so would add significant overhead and I'm not sure it would be usable or practical.

I've reached out to one of the folks who serves as a contributor to the MapWinGIS open source project that produces this OCX control to try to get clarification on both access to the methods and whether case sensitivity may be the issue that is resulting in the 'Unknown Name' error.

Also, since I use VFPA, I've reached out to inquire if this "Unfortunate Behavior" (as Rick Strahl calls it) in VFP of forcing all COM interop to be lower case is something that can be optionally changed in a future release of VFPA.

I'll update this post when I get more information.

AJ
 
UPDATE: This issue seems to be resolved and the issue is not case sensitivity but rather one of using the proper syntax.

One of the developers for the Open Source MapWinGIS OCX control was kind enough to point out that in some legacy products like VB6 and VFP the ‘get_’ prefix to the method is not used. When I changed my VFP code to simply call

loSF = THISFORM.axmap1.Shapefile(THISFORM.LayerHandle)

rather than

loSF = THISFORM.axmap1.get_Shapefile(THISFORM.LayerHandle)

as the documentation shows, I was able to get a reference to the shapefile object as desired.

So now we know! [smile]

Alec
 
In the meantime, I found this OCX project online and tried it myself.

I see, this is a property defined with a getter. A concept VFP does, too, just turned upside down: When you define a property and define an access method for it. Similarly for setter and assign method.
In this OCX that GET-method leads to the confusing intellisense display of it as a property "Shapefile", which has the property icon next to it and not the method icon. But okay, thanks for pointing that out.

This OCX might be handy at some point in the future. For others, you find it at


Chriss
 
Hi Chris,

Okay, as long as you've ventured into this OCX a bit here is another issue I've stumbled across that you may be able to shed light upon if you care to venture further... (If not that's okay)

The MapWinGIS web site has Examples and I've been going thru some of them to try to reproduce them in VFP. Here is a sample that simply creates a series of random points in a Shapefile and displays it. Here is a link to the C++ example:


The output display is not relative to a map it just plotted points. Seems like it should be easy, Right? Nothing is ever easy.

I keep hitting an error when I get to the InsertPoint() method. The OLE Exception error C0000005 OLE Object may be corrupt. VFP does not crash (as is often the case when the dreaded C0000005 appears) and I presume the object that it is referring to would be the point object. Not sure why it would be corrupt as it was just created.

Here is my code:

[pre]
********************************************
* Creates a point shapefile by placing 1000 points randomly

thisform.AXmap.projection = 0 && PROJECTION_NONE

sf = CreateObjectEx("MapWinGIS.Shapefile","","")

* MWShapeId field will be added to attribute table
llResult = sf.CreateNewWithShapeID("", 5) && ShpfileType.SHP_POINT)

* bounding box for the new shapefile
xMin = 0.0
yMin = 0.0
xMax = 1000.0
yMax = 1000.0

* the location of points will be random
lnRnd = RAND()

* creating points and inserting them in the shape
FOR i = 0 TO 1000

loPnt = CreateObjectEx("MapWinGIS.Point","","")
loPnt.x = xMin + (xMax - xMin) * lnRnd
loPnt.y = yMin + (yMax - yMin) * lnRnd

loshp = CreateObjectEx("MapWinGIS.Shape","","")
loshp.Create( 1 ) && ShpfileType.SHP_POINT

lnIndex = 0
loshp.InsertPoint(loPnt, @lnIndex)
sf.EditInsertShape(loshp, @i)

ENDFOR

sf.DefaultDrawingOptions.SetDefaultPointSymbol(9) && tkDefaultPointSymbol.dpsStar

* adds shapefile to the map
THISFORM.AXmap.AddLayer(sf, .T.)

********* save if needed
********* sf.SaveAs(@"c:\points.shp", null)

********************************************

[/pre]

Do you see anything obvious with my reproduction of their example?

Thanks

Alec
 
1. rnd.NextDouble() in the C# code is generating the next random number, the c# rnd variable is not just a rando number, it's a generator, used by this method.

In your code use RAND() instead of lnRnd.

2. The loop should be from 0 to 999, but that's just creating 1001 instead of 1000 points.

3. You might need to use 0 and 1 or -1 instead of .T. and .F., so instead of THISFORM.AXmap.AddLayer(sf, .T.) try THISFORM.AXmap.AddLayer(sf, 1) or THISFORM.AXmap.AddLayer(sf, -1)

I'm not sure if CreateObjectEx is a better option than using CreateObject. The only reason to use CreateObjectEx are using a COM class remotely and using a COM class that does not support the IDispatch interface. The third parameter cIID specifies an interface to use and passing in "" as you do means CreateObjectEx makes use of the default interface.

The IDispatch interface has to do with memory management and not using it but another interface might cause you the trouble with C5 errors. So while CreateObjectEx extends VFPs capabilities to create objects of COM classes without the Idispatch interface, it might not help with stable usage of other interfaces regarding memory management and garbage collection.

I see that all of the MapWinGIS can be created with CreateObject, so I don't see the need for using CreateObjectEx, using CreateObject could mitigate the C5 problems you have.

Chriss
 
I only get this error free when chagnging from CreateObjectEx to CreateObject.
But then sf.EditInsertShape(loshp, @i) always returns .f., though loShp.create(1) and loShp.InsertPoint do return .t., so the step to insert a point into the shapefile fails for some reason.



Chriss
 
Hi Chris,

Thanks for the feedback. I finally got this simple example working too.
Image2_vlulky.jpg


For the benefit of anyone else who may visit this thread here is the updated VFP Code
____________________________

[pre]* Creates a point shapefile by placing 1000 points randomly
thisform.AXmap.projection = 0 && PROJECTION_NONE

sf = CreateObject("MapWinGIS.Shapefile")

* MWShapeId field will be added to attribute table
llResult = sf.CreateNewWithShapeID("", 1) && ShpfileType.SHP_POINT)

* bounding box for the new shapefile
xMin = 0.0
yMin = 0.0
xMax = 1000.0
yMax = 1000.0

* creating points and inserting them in the shape
FOR i = 0 TO 999
* the location of points will be random
loPnt = CREATEOBJECT("MapWinGIS.Point")
loPnt.x = xMin + (xMax - xMin) * RAND()
loPnt.y = yMin + (yMax - yMin) * RAND()

loshp = CreateObject("MapWinGIS.Shape")
loshp.Create( 1 ) && ShpfileType.SHP_POINT

lnIndex = 0
loshp.InsertPoint(loPnt, @lnIndex)
sf.EditInsertShape(loshp, @i)
ENDFOR

sf.DefaultDrawingOptions.SetDefaultPointSymbol(9) && tkDefaultPointSymbol.dpsStar

* adds shapefile to the map
Thisform.axMap.AddLayer(sf, .T.)

[/pre]
____________________________

Changing the CreateObjectEx to CreateObject resolved the issue of the Point object being flagged as corrupt. FYI, it seems that the VFP syntax .T. works the same as a value of 1 so that was not an issue.

That got the code running without error but there still was no display. Then I discovered that I had the wrong Enumeration Value for the call to CreateNewWithShapeID(). I mistakenly had a value of 5 for a poly and it should have been a 1 for a point shapefile. Once that change was made the image shown above was created.

Thanks for all the feedback... now on the next challenge.

Alec (Santa Barbara, California)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top