MapWindow 4 - ActiveX Control Programming : MapWindow Discussion Forum
Hi guys, I am trying to read and display shapefiles using ASP.NET and MapWinGIS activeX control. Can any one point me to some examples in this area. thanks in advance for all your help, Raj
Re: ASP.NET example?
Posted by: kiner ()
Date: September 27, 2005 11:08AM

Shade,

I got a stupid idea, but it works now!

First, I try to save the value of the boundary of the map.

wrapper
==========================================================================
'Get the boundary of the map.
Public Function extents() As MapWinGIS.Extents
extents = m_form1.AxMap1.Extents
End Function

asp.net
==========================================================================
Dim sf As ClassLibrary1.ASPMap
Dim Gis_Path As String = "C:\Inetpub\wwwroot\WebApplication1\GIS\"
Dim intlayer(4) As Integer
Dim extents As MapWinGIS.Extents
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
sf = New ClassLibrary1.ASPMap
addtown()
ImageButton1.ImageUrl = Server.MapPath("Temp.jpg")
'Read the boundary of the map only "ONCE." :D
If Not IsPostBack Then
extents = sf.extents
TextBox6.Text = extents.xMin
TextBox7.Text = extents.xMax
TextBox8.Text = extents.yMin
TextBox9.Text = extents.yMax
End If
sf.SnapShot(Server.MapPath("Temp.jpg"), TextBox6.Text, TextBox7.Text, TextBox8.Text, TextBox9.Text)
End Sub

Second, I rewrite functions of Snapshot, pandown, and panright. They will need to have additional 4 values of the boundary of the map.

Public Function SnapShot(ByVal SaveFileName As String, ByVal xmin As Double, ByVal xmax As Double, ByVal ymin As Double, ByVal ymax As Double) As MapWinGIS.Extents
Dim image As MapWinGIS.Image
Dim ex As MapWinGIS.Extents = m_form1.AxMap1.Extents
ex.SetBounds(xmin, ymin, 0, xmax, ymax, 0)
m_form1.AxMap1.Extents = ex
image = m_form1.AxMap1.SnapShot(m_form1.AxMap1.Extents)
image.Save(SaveFileName)
SnapShot = m_form1.AxMap1.Extents
End Function

Public Function zoom(ByVal percent As Double) As MapWinGIS.Extents
m_form1.AxMap1.ZoomIn(percent)
zoom = m_form1.AxMap1.Extents
End Function

Public Function PanDown(ByVal Amount As Double, ByVal xmin As Double, ByVal xmax As Double, ByVal ymin As Double, ByVal ymax As Double) As MapWinGIS.Extents
Dim extents As MapWinGIS.Extents = m_form1.AxMap1.Extents
'Amount = 1 would move one full screen to the right.
'A fraction of about 0.15 is a reasonable Amount for pan
'In the case of WGS84 Coordinates in Florida, a negative change moves the extents down
extents.SetBounds(xmin, ymin - (ymax - ymin) * Amount, 0, xmax, ymax - (ymax - ymin) * Amount, 0)
m_form1.AxMap1.Extents = extents
PanDown = extents
End Function

Public Function PanRight(ByVal Amount As Double, ByVal xmin As Double, ByVal xmax As Double, ByVal ymin As Double, ByVal ymax As Double) As MapWinGIS.Extents
Dim extents As MapWinGIS.Extents = m_form1.AxMap1.Extents
'Amount = 1 would move one full screen to the right.
'A fraction of about 0.15 is a reasonable Amount for pan
'In the case of WGS84 Coordinates in Florida, a positive change moves you to the right
extents.SetBounds(xmin + (xmax - xmin) * Amount, ymin, 0, xmax + (xmax - xmin) * Amount, ymax, 0)
m_form1.AxMap1.Extents = extents
PanRight = extents
End Function

Third, keep read and write these 4 values in 4 textboxs.

Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
extents = sf.PanRight(-0.2, TextBox6.Text, TextBox7.Text, TextBox8.Text, TextBox9.Text)
TextBox6.Text = extents.xMin
TextBox7.Text = extents.xMax
TextBox8.Text = extents.yMin
TextBox9.Text = extents.yMax
sf.SnapShot(Server.MapPath("Temp.jpg"), TextBox6.Text, TextBox7.Text, TextBox8.Text, TextBox9.Text)
End Sub

All of codes are used to zoomin, zoomout, pandown, panup, panleft, and panright the amp.
(I don't know what I am talking about, and I hope you can understand them. +_+)

However, I still can find out how to save the status of each layer. I will try to think about the other way to solve this problem.

Anyway, thank you shade!






Re: ASP.NET example?
Posted by: kiner ()
Date: October 05, 2005 11:52AM

Shade,

I found out how to solve my problem totally.

For someone who need to know to how to work in asp.net.

asp.net
==========================================================================
Dim Gis_Path As String = "C:\Inetpub\wwwroot\WebApplication1\GIS\"
Dim extents As MapWinGIS.Extents

Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
If Not IsPostBack Then
Dim sf as New ClassLibrary1.ASPMap
session("KEY") = sf
addtown()
ImageButton1.ImageUrl = Server.MapPath("Temp.jpg")
extents = sf.extents
TextBox6.Text = extents.xMin
TextBox7.Text = extents.xMax
TextBox8.Text = extents.yMin
TextBox9.Text = extents.yMax
sf.SnapShot(Server.MapPath("Temp.jpg"), TextBox6.Text, TextBox7.Text, TextBox8.Text, TextBox9.Text)
End If
End Sub

Private Sub addtown()
Dim col1, col2, col3, col4, col5 As UInt32
' Every time you want to call sf, you have to do this.
Dim sf As ClassLibrary1.ASPMap = CType(Session("key"), ClassLibrary1.ASPMap)
col1 = Convert.ToUInt32(RGB(255, 0, 255))
col2 = Convert.ToUInt32(RGB(0, 0, 255))
col3 = Convert.ToUInt32(RGB(119, 119, 119))
col4 = Convert.ToUInt32(RGB(0, 0, 0))
col5 = Convert.ToUInt32(RGB(0, 0, 0))
Session("taoyuan_town") = sf.Add_Taoyuan(Gis_Path & "Taoyuan_town.shp", col1, "Taoyuan_town")
Session("taoyuan_ri25") = sf.Add_Taoyuan(Gis_Path & "Taoyuan_ri25.shp", col2, "Taoyuan_ri25")
Session("taoyuan_croad") = sf.Add_Taoyuan(Gis_Path & "Taoyuan_croad.shp", col3, "Taoyuan_croad")
Session("taoyuan_xb25") = sf.Add_Taoyuan(Gis_Path & "Taoyuan_xb25.shp", col4, "Taoyuan_xb25")
Session("taoyuan_Taoyuan_NorPoi") = sf.Add_Taoyuan(Gis_Path & "Taoyuan_NorPoi.shp", col5, "Taoyuan_NorPoi")
End Sub

===============================================================================


Re: ASP.NET example?
Posted by: Shade1974 ()
Date: October 05, 2005 12:42PM

That's cool. It looks like ASP has some features I am not familiar with from normal VB Net like the IsPostBack parameter and Session values and stuff. Thanks for posting your solution.

Shade1974 :)

Re: ASP.NET example?
Posted by: boris ()
Date: October 10, 2005 05:04AM

Hi

I have a problem following the instructions, using .DLL causes a server error:

Could not instantiate ActiveX control '54f4c2f7-ed40-43b7-9d6f-e45965df7f95' because the current thread is not in a single-threaded apartment.

I could create a new sta thread but that would cause some other problems.
Any suggestion will be appriciated.

Re: ASP.NET example?
Posted by: danames ()
Date: October 10, 2005 12:23PM

Boris - Are you getting this error when running as an ASP.NET application? I'd be interested to know if you also get it when trying to build a standalone Windows App. At least this would be my suggestion for trying to figure out why the error is occurring. - Dan

Re: ASP.NET example?
Posted by: boris ()
Date: October 10, 2005 01:55PM

Dan Ames Wrote:
-------------------------------------------------------
> Boris - Are you getting this error when running as
> an ASP.NET application? I'd be interested to know
> if you also get it when trying to build a
> standalone Windows App. At least this would be my
> suggestion for trying to figure out why the error
> is occurring. - Dan

thank you for replying.

I'm getting this error when running as an ASP.NET application, but when I build a standalone Windowos application everything works fine.

It looks to me like this control has to be used inside a STA thread and the aspnet thread is MTA. I don't know if I am doing something wrong especially since nobody had this problem.

Re: ASP.NET example?
Posted by: danames ()
Date: October 10, 2005 02:05PM

I haven't actually used the control in an ASP app, so hopefully one of these guys who has done it will be able to give you some suggestions. I'm glad to hear that it is not an issue in stand alone apps though. Thanks - Dan

Re: ASP.NET example?
Posted by: cmichaelis ()
Date: October 10, 2005 02:05PM

Boris,

I ran into something similar when I tried to use the OCX in an ASP application -- I did get around it, in a strange way.

The details are on my laptop, which is at home. Once I get back home I'll dig my test application out and see how I got around it, and let you know if it's anything useful.

Thanks!
--Chris

Re: ASP.NET example?
Posted by: ForestChen ()
Date: October 10, 2005 07:07PM

Hi, I have fixed the problem which will cause crash when you drap and drop MapWinGIS ActiveX control to a Microsoft Access form, or when you drap and drop it to a web form in ASP.net.

Now the ActiveX will work ok if you use it as a client contorl in IE or other browsers which support ActiveX. You can do this in Asp.net by 1. Add it to your toolbox, 2. drap it from your tool box and drop it to your webform.

Because MapWinGIS is a !!!ActiveX!!!, it is not supposed to be used in any kind of none-GUI environments, for example, aspnet_wp.exe. Because there is no window handle for the ActiveX contorl to maintain its state, you will end up in either 1, Debug assertion fail in debug mode, or 2, Access violation in Release mode.

For those who really, really, really want to use the ActiveX contorl in ASP.net, here is a work arround:

//Two things must be down:
// 1. Create a new STA thread to host the ActiveX and never let the thread end.
// 2. Create a container for the ActiveX which has a hWnd handle.

// The following code is only created for fun and should never be used in production environment



using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace WebApplication1
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button Button1;
private AxMapWinGIS.AxMap axMap1;
private Form1 form ;

private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
}

#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
System.Threading.ThreadStart start = new System.Threading.ThreadStart(this.InitializeComponent);
System.Threading.Thread th = new System.Threading.Thread(start);
th.ApartmentState = System.Threading.ApartmentState.STA;
th.Start();
base.OnInit(e);
}

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);
if(form == null)
{
form = new Form1();
}
form.Hide();
axMap1 = form.axMap1;
System.Threading.Thread.CurrentThread.Join();
}
#endregion

private void Button1_Click(object sender, System.EventArgs e)
{
MapWinGIS.ShapefileClass sf = new MapWinGIS.ShapefileClass();
sf.Open(@"C:\Dev\Sample Data\Shape Data\eclanduse.shp",null);
axMap1.AddLayer(sf, true);

MapWinGIS.Image img = (MapWinGIS.Image)axMap1.SnapShot(axMap1.Extents);
img.Save(@"C:\temp.jpg",false,MapWinGIS.ImageType.JPEG_FILE,null);
Response.WriteFile(@"C:\temp.jpg");
Response.End();
}
}
}







using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace WebApplication1
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
public AxMapWinGIS.AxMap axMap1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(Form1));
this.axMap1 = new AxMapWinGIS.AxMap();
((System.ComponentModel.ISupportInitialize)(this.axMap1)).BeginInit();
this.SuspendLayout();
//
// axMap1
//
this.axMap1.Enabled = true;
this.axMap1.Location = new System.Drawing.Point(48, 72);
this.axMap1.Name = "axMap1";
this.axMap1.OcxState = ((System.Windows.Forms.AxHost.State)(resources.GetObject("axMap1.OcxState")));
this.axMap1.Size = new System.Drawing.Size(192, 64);
this.axMap1.TabIndex = 0;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.axMap1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.axMap1)).EndInit();
this.ResumeLayout(false);

}
#endregion

}
}



Re: ASP.NET example?
Posted by: ForestChen ()
Date: October 10, 2005 07:13PM

So, in conclusion, ActiveX controls are client side controls, not server side controls. Although the upper code is a work around, it is not a piece of "good" code. In production mode, the code will run into security problems or other performance related problems.

Hope this will help somehow.

Regards,
Forest.

Re: ASP.NET example?
Posted by: cmichaelis ()
Date: October 10, 2005 07:56PM

Boris et al,

I'm at home now and have my project open on my laptop. Now that I can see what I did (this was months ago), what happened was exactly what Forest said above - I got all sorts of ugly crashes. So, what I did is this:

I created a standalone EXE that has the map control in it. This is acting as a TCP/IP server handling specially-formulated requests over a specific port. This way, the ActiveX control has a window handle and an MTA environment to work in. The server EXE can do whatever it needs to do on the map object. One of the specially-formatted requests is to provide a snapshot of given extents; you see where I'm going with this...

Now, the ASP side is then all proper ASP, rather than coercing an ActiveX control to place nicely. The ASP side just has a TCP/IP client module that interacts with the standalone EXE server. Works nice and quickly, gets the job done (at least in my case).

This may be a viable alternative to using the ActiveX control directly, but still use the ActiveX conrol in a roundabout way.

Cheers, and good luck to all.
--Chris

Re: ASP.NET example?
Posted by: boris ()
Date: October 11, 2005 01:27AM

Thanks all for your suggestions!

Re: ASP.NET example?
Posted by: Oxcarz ()
Date: October 11, 2005 10:00AM

I have had similar permissions/security/sharing problems when trying to hook up MapPoint 2004 .ocx controls to an ASP.net server. In the end, I finaly just kept the .ocx in a Windows form and used fileWatcher events to pass map images and requests between the Windows app and the ASP.net app.

I like CHris's idea of using a servlet to pass data via TCP. the fileWatcher events is quick-and-dirty.

Ox

Re: ASP.NET example?
Posted by: kiner ()
Date: October 11, 2005 12:07PM

ForestChen,

//Two things must be down:
// 1. Create a new STA thread to host the ActiveX and never let the thread end.
// 2. Create a container for the ActiveX which has a hWnd handle.

Would you please explian how to do these two things more clearly?

I'm really interested in knowing how to run MapWinGIS.ocx in client side because my website will crash after about 10 people browse it. (the capacity of aspnet_wp.exe will increase quickly(200mb), and I have to close it by myself.)

Thx in advance:)

Re: ASP.NET example?
Posted by: Shade1974 ()
Date: October 11, 2005 01:41PM

I think cmichaelis has hit on the best solution here because you would only load your map into memory once. Instead of loading the activeX each time a person makes a request, you just have one server side executable that is sitting around waiting for requests for snapshots. While I've worked with TCP/IP, it has been a while. In the old school days, you had to add a reference to WinSock32. Now these are under the namespace System.Net.Sockets or something. In any case, the Sockets class will handle the geek speak between your ASP and your server side EXE, just look it up in the help under "Windows Sockets".


I don't know if you can do this with ASP, but with normal programs, if the ActiveX application has a caption you can find it with FindWindowA. You can search for the classname or caption. If the handle isn't 0 then the program is running.

Private Declare Function FindWindowA Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr

in code somewhere: Dim myHandle As Intptr = findWindowA(vbNullString, "MyCaption")

If it isn't there, then normal programs can use a shell to start the application. I'm not at all sure that this will work in ASP. You might just have to ensure that there is a copy always running on the server machine.

dim myHandle As Intptr = myHandle.op_Explicit(Shell(strFileName, 1))

you may have to play around with the windows state (1 in the code above) to figure out what works. While you want to wait long enough for the application to come online and start up, you don't want to wait forever. You could always send out a message over the socket port from the server to the client telling it that the server is now ready to take an order.

Anyway, the EXE should have your ActiveX showing on a form or something. (That is what is meant by having a container for the ActiveX). Basically, now that your exe is running, make sure that it has a Socket object initiated and waiting for messages on a particular port. You will have to figure out how to encode the stream and decode it, but basically you have to pass the four doubles of an extents object. Envision creating a string of characters from those four doubles and then reconstructing the extents from the character string.

If the extents were:
Dim ext as MapWinGIS.Extents
ext.Setbounds(1, 2, 0, 3, 4, 0)
You could encode this as
Dim stream as string = ext.XMin & "," & ext.YMin & "," & ext.XMax & "," & ext.YMax
Then in the server you would decode your stream
Dim Vals() as String = String.Split(stream, ",")
ext.Setbounds(Val(Vals(0)), Val(Vals(1)), 0, Val(Vals(2)), Val(Vals(3)))
Then you just take your snapshot and save it.

Best of luck, I know this is nowhere near enough help, but I just haven't worked enough with ASP or dot Net based TCP/IP to be much assistance.

Shade1974

Re: ASP.NET example?
Posted by: ForestChen ()
Date: October 11, 2005 04:02PM

Hi kiner,

// 1. Create a new STA thread to host the ActiveX and never let the thread end.

Because the aspnet_wp.exe is initialized as a MTA apartment, you can not host MapWinGIS.ocx, which is in a STA apartment model, in aspnet_wp.exe. However, you can create a new thread and initialize it to be a STA apartment. The trick is that you shouldn't let the thread die. Otherwise the component will die away with the thread.

// 2. Create a container for the ActiveX which has a hWnd handle.
Because a ActiveX is has it's UI state, it should be held by a container with a window handle(you can use spy++, a tool shipped with visual studio.net to check all the window handles in your system). That is the reason why you should created a Form to host it.

This code sample is just for fun, if you realy want to use it at server side, just like Shade has recommended, you may need to consider Chis' approach.


If you want to use MapWinGIS.ocx at client side. drap it to your WebForm, you will get code similar to the following:


<OBJECT id="MapWin" style="Z-INDEX: 101; LEFT: 72px; WIDTH: 192px; POSITION: absolute; TOP: 48px; HEIGHT: 88px"
classid="clsid:54F4C2F7-ED40-43B7-9D6F-E45965DF7F95" VIEWASTEXT>
<PARAM NAME="_Version" VALUE="196608">
<PARAM NAME="_ExtentX" VALUE="5080">
<PARAM NAME="_ExtentY" VALUE="2328">
<PARAM NAME="_StockProps" VALUE="0">
<PARAM NAME="BackColor" VALUE="16777215">
<PARAM NAME="ExtentPad" VALUE="0.02">
<PARAM NAME="CursorMode" VALUE="0">
<PARAM NAME="ZoomPercent" VALUE="0.3">
<PARAM NAME="SendMouseMove" VALUE="0">
<PARAM NAME="SendMouseDown" VALUE="0">
<PARAM NAME="SendMouseUp" VALUE="0">
<PARAM NAME="SendSelectBoxDrag" VALUE="0">
<PARAM NAME="SendSelectBoxFinal" VALUE="0">
<PARAM NAME="ExtentHistory" VALUE="20">
<PARAM NAME="DoubleBuffer" VALUE="-1">
</OBJECT>


and then you can control the object using vbscript or javascript at client browser. I am sorry that I am not good at vbscript or javascript, but you can get plentry of examples from google about how to use ActiveX controls in vbscript or javascript.

That's all I can tell you, hope it will help. Good luck!

Forest.

Re: ASP.NET example?
Posted by: kiner ()
Date: October 16, 2005 10:48AM

ForestChen,

The new version of MapWinGis.ocx(10/15) solved the problem that I used to have.

But I don't know how to put GIS files into this object in Asp.net. :(

(For example, Taoyuan_town = Map1.AddLayer(sf, True))

Shade's suggestion seems to be the best solution, but it's really hard for me to understand how to work with winSock32 or something else.

Anyway, thanks your both...:)





Re: ASP.NET example?
Posted by: ForestChen ()
Date: October 17, 2005 04:39PM

kiner,

Here is a good sample for using winsock32 in c#
[www.codeproject.com]

Wish it can help you somehow.

>>But I don't know how to put GIS files into this object in Asp.net

It should be some kind of javascript or vbscript. But I am sorry to to say I am not good at those clientside scripts.

Thank you for your information and wish you good luck!
Forest.

Re: ASP.NET example?
Posted by: tamajayus ()
Date: June 16, 2008 09:56PM

where can i get a source of asp.net application? thks

Sorry, only registered users may post in this forum.





Banner Exchange




GISCP.com




Send us your banner logo (160x120) for the space above, and add this MapWindow banner ad to your site:

Just paste this text in your page: