基于Wms协议的Map开发(六:通讯模块)
2010-05-06 15:11
357 查看
声明:此系列文章,不是说教,不是告诉任何人如何利用
C++
开发电子地图的教程,而且本人水平有限,也达不到教程的地步。只是利用此系列的文章,来记录开发基于
C++
应用在
Windows
下
开发电子地图的过程。愿对
C++
开发感兴趣的朋友,熟知
Gis
开发的朋友,了解
Wms
、
WFS
协议的朋友,亦或是对
GoogleMap
之类感兴趣的朋友,共同讨论。(废话到此结束)。
通讯模块
此通讯模块目的在于根据输入,下载指定
URL
的内容。由于本人很少从事网络方面的编码,这部分很不擅长,当初,设计时,欲寻找一套简单易用的库,所以选择了
WinInet
实现此部分逻辑,但是随着知识的增长,了解到
WinINet
是极不稳定的,所以对网络编程熟悉的朋友可自行实现此部分功能。例如:可以使用
Socket
来完成此功能。
重中之重
GetCapability
bool
BStarWmsPostMan
::SaveCapFile
(char
* strAddr
,char
buf
[], int
& buflen
)
{
char
* temp
= "SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities"
;
char
url
[512];
memcpy_s
(url
,512, strAddr
,256);
strcat_s
(url
,512,temp
);
if
(!ReciveBuffer
(url
,buf
, buflen
))
{
delete
[] buf
;
buf
= NULL
;
return
false
;
}
}
解释:
strAddr
:是你服务器的地址字符串
char
buf
[]
:接收到的字符串。
int
& buflen
:接收到的字符串的长度。
GetMap
我给出一个如何拼接
GetMap
命令的函数,主要目的是让大家了解
GetMap
字符串如何拼接的,这样有利于大家自己实现下载功能。
bool
BStarWmsPostMan
::GetMap
(LATLONBB
maparea
, char
buf
[], int
& buflen
)
{
char
strTemp
[1280];;
char
url
[2560];
memcpy_s
(url
,2560,m_strAddr
,256);
sprintf_s
(strTemp
,1280,"BBOX=%f,%f,%f,%f&SRS=EPSG:%s&WIDTH=%d&HEIGHT=%d&LAYERS=%s&STYLES=&FORMAT=%s&DPI=96"
,maparea
.minx
,maparea
.miny
,maparea
.maxx
,maparea
.maxy
,m_layerProperty
.Srs
,m_layerProperty
.Width
,m_layerProperty
.Height
,m_layerProperty
.Name
,m_layerProperty
.ImageType
);
strcat_s
(url
,2560, "SERVICE=WMS&version=1.0.0&request=getmap&"
);
strcat_s
(url
, 2560, strTemp
);
if
(!ReciveBuffer
(url
,buf
,buflen
))
{
return
false
;
}
return
true
;
}
解释:
LATLONBB
maparea
:这个数据结构大家看过前文的,应该记得,由四个double
组成,代表左右上下四个边界的经纬度值。
char
buf
[]
:接收到的字符串。
int
& buflen
:接收到的字符串的长度。
如果你看明白了,而且想做个稳定的通讯模块,好的,就别再往下看了,自己实现吧。主要工作就是用你自己的方法实现ReciveBuffer()
这个函数。
模块功能
先让我们来看看此功能模块是做什么用的,有哪些事情是要处理的。
流程图如下:
![](http://student.csdn.net/attachment/201005/**72207_1273129458Pzav.jpg)
再让我们用文字描述一下这个流程:
明确任务
首先明确,通讯模块需要得到什么样的数据呢?
(1)
还记得
Wms
协议中的
GetCapability
吗?对了,得到服务器属性的功能,我们需要通过
GetCapability
来得到一个关于当前地图服务器描述的
XML
表。从而得到很多我们需要的信息,例如当前服务器上存在的地图图层有哪一些,每个图层的经纬度范围是什么,每个图层的名称是什么,投影系是什么等等。
(2)
重点当然是我们要通过
GetMap
来获取我们指定图层、指定坐标范围内的图片了。此模块当然还要能下载这些指定的图片。
其次,我们通过
GetCapability
得到的关于服务器属性的
XML
描述,要经过分析得到我们关心的数据集合了。我这里采用了一个轻量级的
XML
库来做到这一点。选择了
TinyXML
(上网看一下关于此的简介吧)。由于我希望透视
XML
分析过程,所以这里没有采用他的库文件,而是直接使用了他的源代码(
TinyXML
是开源的)。经过分析、确认的数据会被我存到我定义好的数据结构中。
再回首
明确了功能后,回过头来,再来看一下流程图
。
(
1
)
其中“设置服务器”是一个拼接命令给
GetCapability
作为输入的过程。简单的说来,比如你的服务器地址是
http://wms.lizardtech.com/lizardtech/iserv/ows
如果你使用的是一个
1.1.1
版本的
WMS
服务器
,
那么如果加上“
?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities
”这个字符串之后,就相当于设置完成
GetCapability
命令的拼接。只需要打开“
http://wms.lizardtech.com/lizardtech/iserv/ows
?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities
”这个
URL
,那么你就会得到一个
XML
文件。
(
2
)接下来,“获取服务器属性”以及“得到服务器相关属性”的两个步骤,就是我要通过
TinyXML
分析这个
XML
文件,并将我们关心的数据存入我们自定义的数据结构中。
(
3
)
随后,“工作对象的相关属性”,应为我们是要针对对象开发的,意思就是我可以建立多个独立的地图对象,所以,每个独立的地图对象要拥有各自独立的通讯模
块,所以,通讯模块的实现要通过建立类,用类的实例来实现,所以工作对象的属性,就是指每个类实例中的一些私有化成员变量将得到赋值。
(
4
)最后,每个通讯对象的实例,要根据自己的输入去下载数据到本地保存,我的是现实是用
WinINet
,强烈建议大家用
socket
实现,这里要说的是,
XML
下载每个通讯实例只需要完成一次,而图片的下载要完成多次。(这里是根据上层模块的多线程安排下载的,之后会在文件模块的说明中介绍)。
(
5
)
补充说明,这里有个问题,不知道大家注意到没有,下载文件的过程相对于其他操作是耗时的工作,如果用户没耐心看完当前的地图,或者不关心当前地图,从而又
开始了新的操作,我们需要一种中断机制,让正在下载的工作停止。这是很重要的,个人在工作中感觉到,好的功能代码要做到全代码调用的可控。相当于开线程,
不能让线程成为脱缰野马的道理一样。
模块接口及数据结构
数据结构
//
经纬度范围
typedef
struct
tagLATLONBB
{
double
minx
;
//
最小x
double
miny
;
//
最小y
double
maxx
;
//
最大x
double
maxy
;
//
最大y
}LATLONBB
, *PLATLONBB
;
#endif
//wms
标准协议中包含数据
typedef
struct
tagCAPABILITYDATAS
{
int
Width
;
//
图片像素宽度
int
Height
;
//
图片像素高度
char
ImageType
[BUFFER_SIZE_COMMON
];
//
图片类型
char
Srs
[BUFFER_SIZE_COMMON
];
//
投影类型
char
Name
[BUFFER_SIZE_SPECIAL
];
//
层名(用于拼接)
char
Title
[BUFFER_SIZE_SPECIAL
];
//
层名(用于显示)
LATLONBB
BoundBox
;
//
层范围(该层最大范围)
}CAPABILITYDATAS
,*PCAPABILITYDATAS
;
对外接口
//
登录服务器
DLL_API
int
LogIn
(const
char
* strAddr
);
// 2
次调用
,1
次确定buflen
,2
次真正的操作
DLL_API
bool
GetCapability
(int
index
, CAPABILITYDATAS
itemsName
[], int
& count
);
//
设置
用户关心的层
DLL_API
LATLONBB
SetCapability
(int
index
, CAPABILITYDATAS
itemsName
[],const
int
count
);
//
获取图层2
次获取
,1
次确定buflen
,2
次真正的操作
DLL_API
bool
GetMap
(int
index
, LATLONBB
maparea
, char
buf
[], int
& buflen
);
//
中断操作
,舍弃当前下载的工作
DLL_API
void
AbortMap
(int
index
, BOOL
IsAbort
);
//
登出服务器
DLL_API
void
LogOut
(int
index
);
//
复制服务器信息
DLL_API
void
CopyServerData
(int
indexSrs
, int
indexDes
);
TinyXML
我们看一下针对我们的应用,TinyXML
的使用。(这只是个建议,可以使用其他XML
操作的库),其实使用起来还是很简单的,至少是读取很简单吧。
bool
BStarWmsPostMan
::GetCapItems
(CAPABILITYDATAS
items
[], int
& count
)
{
LATLONBB
tempLatlon
;
TiXmlDocument
* myDocument
= new
TiXmlDocument
();
BOOL
bHaveLatlon
= FALSE
;
char
filename
[64];
sprintf_s
(filename
,"%s-%d"
,"GetCapability"
,m_Index
);
if
(!myDocument
->LoadFile
(filename
,TIXML_ENCODING_UNKNOWN
))
{
return
FALSE
;
}
TiXmlElement
* rootElement
= myDocument
->RootElement
();//class
TiXmlElement
* CapabilityElement
= rootElement
->FirstChildElement
("Capability"
);
TiXmlElement
* LayersElement
= CapabilityElement
->FirstChildElement
("Layer"
);
TiXmlElement
* allName
= LayersElement
->FirstChildElement
("Name"
);
TiXmlElement
* LayersTitleElement
= LayersElement
->FirstChildElement
("Title"
);
TiXmlElement
* LayerElement
= LayersElement
->FirstChildElement
("Layer"
);
TiXmlElement
* LayerTitleElement
=
LayerElement
->FirstChildElement
("Title"
);
while
(LayerElement
)
{
indextemp
++;
TiXmlElement
* LayerSrsElement
= LayerElement
->FirstChildElement
("SRS"
);
TiXmlElement
* LayerTitleElement
=
LayerElement
->FirstChildElement
("Title"
);
TiXmlElement
* LayerNameElement
=
LayerElement
->FirstChildElement
("Name"
);
TiXmlElement
* LayerLatLonBoundingBox
= LayerElement
->FirstChildElement
("LatLonBoundingBox"
);
TiXmlElement
* LayerBoundingBox
= LayerElement
->FirstChildElement
("BoundingBox"
);
TiXmlElement
* LayerSrs
= LayerElement
->FirstChildElement
("SRS"
);
TiXmlAttribute
* RectofLayerLatLonBoundingBox
= LayerLatLonBoundingBox
->FirstAttribute
();
Datas
[indextemp
].BoundBox
.minx
= atof
(RectofLayerLatLonBoundingBox
->Value
());
RectofLayerLatLonBoundingBox
=RectofLayerLatLonBoundingBox
->Next
();
Datas
[indextemp
].BoundBox
.miny
= atof
(RectofLayerLatLonBoundingBox
->Value
());
RectofLayerLatLonBoundingBox
=RectofLayerLatLonBoundingBox
->Next
();
Datas
[indextemp
].BoundBox
.maxx
= atof
(RectofLayerLatLonBoundingBox
->Value
());
RectofLayerLatLonBoundingBox
=RectofLayerLatLonBoundingBox
->Next
();
Datas
[indextemp
].BoundBox
.maxy
= atof
(RectofLayerLatLonBoundingBox
->Value
());
LATLONBB
tempsort
;
tempsort
= Datas
[indextemp
].BoundBox
;
if
(tempsort
.minx
> tempsort
.maxx
)
{
Datas
[indextemp
].BoundBox
.minx
= tempsort
.maxx
;
Datas
[indextemp
].BoundBox
.maxx
= tempsort
.minx
;
}
if
(tempsort
.miny
> tempsort
.maxy
)
{
Datas
[indextemp
].BoundBox
.miny
= tempsort
.maxy
;
Datas
[indextemp
].BoundBox
.maxy
= tempsort
.miny
;
}
memcpy
(Datas
[indextemp
].Name
,(char
*)LayerNameElement
->GetText
(),128);
memcpy
(Datas
[indextemp
].Srs
, "4326"
,sizeof
( "4326"
));
memcpy_s
(Datas
[indextemp
].Title
, BUFFER_SIZE_SPECIAL
,(char
*) LayerTitleElement
->GetText
(),128);
memcpy_s
(Datas
[indextemp
].ImageType
, BUFFER_SIZE_COMMON
, "image/jpeg"
,sizeof
("image/jpeg"
));
Datas
[indextemp
].Width
= 256;
Datas
[indextemp
].Height
= 256;
if
(items
!= NULL
)
{
memcpy_s
(items
[indextemp
].Name
,BUFFER_SIZE_SPECIAL
,Datas
[indextemp
].Name
,BUFFER_SIZE_SPECIAL
);
items
[indextemp
].BoundBox
=
Datas
[indextemp
].BoundBox
;
memcpy_s
(items
[indextemp
].Title
,BUFFER_SIZE_SPECIAL
, Datas
[indextemp
].Title
,BUFFER_SIZE_SPECIAL
);
memcpy_s
(items
[indextemp
].ImageType
,BUFFER_SIZE_COMMON
,Datas
[indextemp
].ImageType
,BUFFER_SIZE_COMMON
);
items
[indextemp
].Width
= Datas
[indextemp
].Width
;
items
[indextemp
].Height
= Datas
[indextemp
].Height
;
memcpy_s
(items
[indextemp
].Srs
,BUFFER_SIZE_COMMON
, Datas
[indextemp
].Srs
,BUFFER_SIZE_COMMON
);
}
LayerElement
= LayerElement
->NextSiblingElement
("Layer"
);
}
count
= indextemp
+ 1;
delete
myDocument
;
myDocument
= NULL
;
return
true
;
}
GetMap
虽然强烈建议大家用
socket
开发图片下载这部分,不过还是给出
WinInet
的实现吧。
我定义了一个类
头文件
#ifndef
_CVodStreamCache_H
#define
_CVodStreamCache_H
#include
<iostream>
#include
<Windows.h>
#include
<WinInet.h>
#include
<tchar.h>
#include
<string>
using
namespace
std
;
#pragma
comment
(lib
, "wininet.lib"
)
class
CVodStreamCache
{
public
:
CVodStreamCache
();
~CVodStreamCache
();
bool
Create
(char
token
[], char
url
[]);
int
ReadBlock
(long
offset
, int
len
, char
*buffer
);
bool
Recive
(char
buf
[], int
& buflen
);
void
Destory
();
void
CacheInfo
();
void
Abort
(BOOL
IsAbort
);
private
:
HINTERNET
internetOpen
;
HINTERNET
internetOpenUrl
;
DWORD
dwStatusCode
;
DWORD
dwContentLength
;
HANDLE
createFile
;
static
const
int
BUFFERSIZE
= 9216;
BOOL
m_IsAbort
;
};
#endif
//_CVodStreamCache_H
CPP
#include
"stdafx.h"
#include
<stdio.h>
#include
"CVodStreamCache.h"
CVodStreamCache
::CVodStreamCache
()
{
internetOpen
= NULL
;
internetOpenUrl
= NULL
;
m_IsAbort
= false
;
}
CVodStreamCache
::~CVodStreamCache
()
{
}
bool
CVodStreamCache
::Create
(char
token
[], char
url
[])
{
internetOpen
= InternetOpen
(NULL
, INTERNET_OPEN_TYPE_PRECONFIG
, NULL
, NULL
, 0);
if
(internetOpen
== NULL
)
{
cout
<< "Internet open failed!"
<< endl
;
return
false
;
}
if
(m_IsAbort
)
{
InternetCloseHandle
(internetOpen
);
return
false
;
}
if
(internetOpen
== NULL
)
{
cout
<< "Internet open failed!"
<< endl
;
return
false
;
}
internetOpenUrl
= InternetOpenUrlA
(internetOpen
, url
,
NULL
, 0, INTERNET_FLAG_TRANSFER_BINARY
| INTERNET_FLAG_PRAGMA_NOCACHE
, 0);
if
(internetOpenUrl
== NULL
)
{
cout
<< "Internet open url failed! Error code = "
<< GetLastError
() << endl
;
InternetCloseHandle
(internetOpen
);
return
false
;
}
return
true
;
}
int
CVodStreamCache
::ReadBlock
(long
offset
, int
len
, char
*buffer
)
{
return
0;
}
bool
CVodStreamCache
::Recive
(char
* buf
, int
& buflen
)
{
BOOL
internetReadFile
;
char
buffer
[BUFFERSIZE
];
memset
(buffer
, 0, sizeof
(buffer
));
DWORD
byteRead
= 0;
DWORD
byteDown
= 0;
while
(1)
{
if
(m_IsAbort
)
{
InternetCloseHandle
(internetOpenUrl
);
InternetCloseHandle
(internetOpen
);
return
false
;
}
if
(!internetOpenUrl
)
{
InternetCloseHandle
(internetOpenUrl
);
InternetCloseHandle
(internetOpen
);
return
false
;
}
internetReadFile
= InternetReadFile
(internetOpenUrl
, buffer
, sizeof
(buffer
), &byteRead
);
if
(byteRead
== 0)
{
break
;
}
if
(m_IsAbort
)
{
InternetCloseHandle
(internetOpenUrl
);
InternetCloseHandle
(internetOpen
);
return
false
;
}
if
(NULL
!= buf
)
{
memcpy_s
(buf
+byteDown
, buflen
- byteDown
, buffer
, byteRead
);
}
byteDown
+= byteRead
;
}
InternetCloseHandle
(internetOpenUrl
);
internetOpenUrl
= NULL
;
InternetCloseHandle
(internetOpen
);
internetOpen
= NULL
;
buflen
= byteDown
;
return
1;
}
void
CVodStreamCache
::Abort
(BOOL
IsAbort
)
{
m_IsAbort
= IsAbort
;
}
................................................
未完待续
................................................
C++
开发电子地图的教程,而且本人水平有限,也达不到教程的地步。只是利用此系列的文章,来记录开发基于
C++
应用在
Windows
下
开发电子地图的过程。愿对
C++
开发感兴趣的朋友,熟知
Gis
开发的朋友,了解
Wms
、
WFS
协议的朋友,亦或是对
GoogleMap
之类感兴趣的朋友,共同讨论。(废话到此结束)。
通讯模块
此通讯模块目的在于根据输入,下载指定URL
的内容。由于本人很少从事网络方面的编码,这部分很不擅长,当初,设计时,欲寻找一套简单易用的库,所以选择了
WinInet
实现此部分逻辑,但是随着知识的增长,了解到
WinINet
是极不稳定的,所以对网络编程熟悉的朋友可自行实现此部分功能。例如:可以使用
Socket
来完成此功能。
重中之重
GetCapability
boolBStarWmsPostMan
::SaveCapFile
(char
* strAddr
,char
buf
[], int
& buflen
)
{
char
* temp
= "SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities"
;
char
url
[512];
memcpy_s
(url
,512, strAddr
,256);
strcat_s
(url
,512,temp
);
if
(!ReciveBuffer
(url
,buf
, buflen
))
{
delete
[] buf
;
buf
= NULL
;
return
false
;
}
}
解释:
strAddr
:是你服务器的地址字符串
char
buf
[]
:接收到的字符串。
int
& buflen
:接收到的字符串的长度。
GetMap
我给出一个如何拼接GetMap
命令的函数,主要目的是让大家了解
GetMap
字符串如何拼接的,这样有利于大家自己实现下载功能。
bool
BStarWmsPostMan
::GetMap
(LATLONBB
maparea
, char
buf
[], int
& buflen
)
{
char
strTemp
[1280];;
char
url
[2560];
memcpy_s
(url
,2560,m_strAddr
,256);
sprintf_s
(strTemp
,1280,"BBOX=%f,%f,%f,%f&SRS=EPSG:%s&WIDTH=%d&HEIGHT=%d&LAYERS=%s&STYLES=&FORMAT=%s&DPI=96"
,maparea
.minx
,maparea
.miny
,maparea
.maxx
,maparea
.maxy
,m_layerProperty
.Srs
,m_layerProperty
.Width
,m_layerProperty
.Height
,m_layerProperty
.Name
,m_layerProperty
.ImageType
);
strcat_s
(url
,2560, "SERVICE=WMS&version=1.0.0&request=getmap&"
);
strcat_s
(url
, 2560, strTemp
);
if
(!ReciveBuffer
(url
,buf
,buflen
))
{
return
false
;
}
return
true
;
}
解释:
LATLONBB
maparea
:这个数据结构大家看过前文的,应该记得,由四个double
组成,代表左右上下四个边界的经纬度值。
char
buf
[]
:接收到的字符串。
int
& buflen
:接收到的字符串的长度。
如果你看明白了,而且想做个稳定的通讯模块,好的,就别再往下看了,自己实现吧。主要工作就是用你自己的方法实现ReciveBuffer()
这个函数。
模块功能
先让我们来看看此功能模块是做什么用的,有哪些事情是要处理的。流程图如下:
![](http://student.csdn.net/attachment/201005/**72207_1273129458Pzav.jpg)
再让我们用文字描述一下这个流程:
明确任务
首先明确,通讯模块需要得到什么样的数据呢?(1)
还记得
Wms
协议中的
GetCapability
吗?对了,得到服务器属性的功能,我们需要通过
GetCapability
来得到一个关于当前地图服务器描述的
XML
表。从而得到很多我们需要的信息,例如当前服务器上存在的地图图层有哪一些,每个图层的经纬度范围是什么,每个图层的名称是什么,投影系是什么等等。
(2)
重点当然是我们要通过
GetMap
来获取我们指定图层、指定坐标范围内的图片了。此模块当然还要能下载这些指定的图片。
其次,我们通过
GetCapability
得到的关于服务器属性的
XML
描述,要经过分析得到我们关心的数据集合了。我这里采用了一个轻量级的
XML
库来做到这一点。选择了
TinyXML
(上网看一下关于此的简介吧)。由于我希望透视
XML
分析过程,所以这里没有采用他的库文件,而是直接使用了他的源代码(
TinyXML
是开源的)。经过分析、确认的数据会被我存到我定义好的数据结构中。
再回首
明确了功能后,回过头来,再来看一下流程图。
(
1
)
其中“设置服务器”是一个拼接命令给
GetCapability
作为输入的过程。简单的说来,比如你的服务器地址是
http://wms.lizardtech.com/lizardtech/iserv/ows
如果你使用的是一个
1.1.1
版本的
WMS
服务器
,
那么如果加上“
?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities
”这个字符串之后,就相当于设置完成
GetCapability
命令的拼接。只需要打开“
http://wms.lizardtech.com/lizardtech/iserv/ows
?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities
”这个
URL
,那么你就会得到一个
XML
文件。
(
2
)接下来,“获取服务器属性”以及“得到服务器相关属性”的两个步骤,就是我要通过
TinyXML
分析这个
XML
文件,并将我们关心的数据存入我们自定义的数据结构中。
(
3
)
随后,“工作对象的相关属性”,应为我们是要针对对象开发的,意思就是我可以建立多个独立的地图对象,所以,每个独立的地图对象要拥有各自独立的通讯模
块,所以,通讯模块的实现要通过建立类,用类的实例来实现,所以工作对象的属性,就是指每个类实例中的一些私有化成员变量将得到赋值。
(
4
)最后,每个通讯对象的实例,要根据自己的输入去下载数据到本地保存,我的是现实是用
WinINet
,强烈建议大家用
socket
实现,这里要说的是,
XML
下载每个通讯实例只需要完成一次,而图片的下载要完成多次。(这里是根据上层模块的多线程安排下载的,之后会在文件模块的说明中介绍)。
(
5
)
补充说明,这里有个问题,不知道大家注意到没有,下载文件的过程相对于其他操作是耗时的工作,如果用户没耐心看完当前的地图,或者不关心当前地图,从而又
开始了新的操作,我们需要一种中断机制,让正在下载的工作停止。这是很重要的,个人在工作中感觉到,好的功能代码要做到全代码调用的可控。相当于开线程,
不能让线程成为脱缰野马的道理一样。
模块接口及数据结构
数据结构
//经纬度范围
typedef
struct
tagLATLONBB
{
double
minx
;
//
最小x
double
miny
;
//
最小y
double
maxx
;
//
最大x
double
maxy
;
//
最大y
}LATLONBB
, *PLATLONBB
;
#endif
//wms
标准协议中包含数据
typedef
struct
tagCAPABILITYDATAS
{
int
Width
;
//
图片像素宽度
int
Height
;
//
图片像素高度
char
ImageType
[BUFFER_SIZE_COMMON
];
//
图片类型
char
Srs
[BUFFER_SIZE_COMMON
];
//
投影类型
char
Name
[BUFFER_SIZE_SPECIAL
];
//
层名(用于拼接)
char
Title
[BUFFER_SIZE_SPECIAL
];
//
层名(用于显示)
LATLONBB
BoundBox
;
//
层范围(该层最大范围)
}CAPABILITYDATAS
,*PCAPABILITYDATAS
;
对外接口
//登录服务器
DLL_API
int
LogIn
(const
char
* strAddr
);
// 2
次调用
,1
次确定buflen
,2
次真正的操作
DLL_API
bool
GetCapability
(int
index
, CAPABILITYDATAS
itemsName
[], int
& count
);
//
设置
用户关心的层
DLL_API
LATLONBB
SetCapability
(int
index
, CAPABILITYDATAS
itemsName
[],const
int
count
);
//
获取图层2
次获取
,1
次确定buflen
,2
次真正的操作
DLL_API
bool
GetMap
(int
index
, LATLONBB
maparea
, char
buf
[], int
& buflen
);
//
中断操作
,舍弃当前下载的工作
DLL_API
void
AbortMap
(int
index
, BOOL
IsAbort
);
//
登出服务器
DLL_API
void
LogOut
(int
index
);
//
复制服务器信息
DLL_API
void
CopyServerData
(int
indexSrs
, int
indexDes
);
TinyXML
我们看一下针对我们的应用,TinyXML的使用。(这只是个建议,可以使用其他XML
操作的库),其实使用起来还是很简单的,至少是读取很简单吧。
bool
BStarWmsPostMan
::GetCapItems
(CAPABILITYDATAS
items
[], int
& count
)
{
LATLONBB
tempLatlon
;
TiXmlDocument
* myDocument
= new
TiXmlDocument
();
BOOL
bHaveLatlon
= FALSE
;
char
filename
[64];
sprintf_s
(filename
,"%s-%d"
,"GetCapability"
,m_Index
);
if
(!myDocument
->LoadFile
(filename
,TIXML_ENCODING_UNKNOWN
))
{
return
FALSE
;
}
TiXmlElement
* rootElement
= myDocument
->RootElement
();//class
TiXmlElement
* CapabilityElement
= rootElement
->FirstChildElement
("Capability"
);
TiXmlElement
* LayersElement
= CapabilityElement
->FirstChildElement
("Layer"
);
TiXmlElement
* allName
= LayersElement
->FirstChildElement
("Name"
);
TiXmlElement
* LayersTitleElement
= LayersElement
->FirstChildElement
("Title"
);
TiXmlElement
* LayerElement
= LayersElement
->FirstChildElement
("Layer"
);
TiXmlElement
* LayerTitleElement
=
LayerElement
->FirstChildElement
("Title"
);
while
(LayerElement
)
{
indextemp
++;
TiXmlElement
* LayerSrsElement
= LayerElement
->FirstChildElement
("SRS"
);
TiXmlElement
* LayerTitleElement
=
LayerElement
->FirstChildElement
("Title"
);
TiXmlElement
* LayerNameElement
=
LayerElement
->FirstChildElement
("Name"
);
TiXmlElement
* LayerLatLonBoundingBox
= LayerElement
->FirstChildElement
("LatLonBoundingBox"
);
TiXmlElement
* LayerBoundingBox
= LayerElement
->FirstChildElement
("BoundingBox"
);
TiXmlElement
* LayerSrs
= LayerElement
->FirstChildElement
("SRS"
);
TiXmlAttribute
* RectofLayerLatLonBoundingBox
= LayerLatLonBoundingBox
->FirstAttribute
();
Datas
[indextemp
].BoundBox
.minx
= atof
(RectofLayerLatLonBoundingBox
->Value
());
RectofLayerLatLonBoundingBox
=RectofLayerLatLonBoundingBox
->Next
();
Datas
[indextemp
].BoundBox
.miny
= atof
(RectofLayerLatLonBoundingBox
->Value
());
RectofLayerLatLonBoundingBox
=RectofLayerLatLonBoundingBox
->Next
();
Datas
[indextemp
].BoundBox
.maxx
= atof
(RectofLayerLatLonBoundingBox
->Value
());
RectofLayerLatLonBoundingBox
=RectofLayerLatLonBoundingBox
->Next
();
Datas
[indextemp
].BoundBox
.maxy
= atof
(RectofLayerLatLonBoundingBox
->Value
());
LATLONBB
tempsort
;
tempsort
= Datas
[indextemp
].BoundBox
;
if
(tempsort
.minx
> tempsort
.maxx
)
{
Datas
[indextemp
].BoundBox
.minx
= tempsort
.maxx
;
Datas
[indextemp
].BoundBox
.maxx
= tempsort
.minx
;
}
if
(tempsort
.miny
> tempsort
.maxy
)
{
Datas
[indextemp
].BoundBox
.miny
= tempsort
.maxy
;
Datas
[indextemp
].BoundBox
.maxy
= tempsort
.miny
;
}
memcpy
(Datas
[indextemp
].Name
,(char
*)LayerNameElement
->GetText
(),128);
memcpy
(Datas
[indextemp
].Srs
, "4326"
,sizeof
( "4326"
));
memcpy_s
(Datas
[indextemp
].Title
, BUFFER_SIZE_SPECIAL
,(char
*) LayerTitleElement
->GetText
(),128);
memcpy_s
(Datas
[indextemp
].ImageType
, BUFFER_SIZE_COMMON
, "image/jpeg"
,sizeof
("image/jpeg"
));
Datas
[indextemp
].Width
= 256;
Datas
[indextemp
].Height
= 256;
if
(items
!= NULL
)
{
memcpy_s
(items
[indextemp
].Name
,BUFFER_SIZE_SPECIAL
,Datas
[indextemp
].Name
,BUFFER_SIZE_SPECIAL
);
items
[indextemp
].BoundBox
=
Datas
[indextemp
].BoundBox
;
memcpy_s
(items
[indextemp
].Title
,BUFFER_SIZE_SPECIAL
, Datas
[indextemp
].Title
,BUFFER_SIZE_SPECIAL
);
memcpy_s
(items
[indextemp
].ImageType
,BUFFER_SIZE_COMMON
,Datas
[indextemp
].ImageType
,BUFFER_SIZE_COMMON
);
items
[indextemp
].Width
= Datas
[indextemp
].Width
;
items
[indextemp
].Height
= Datas
[indextemp
].Height
;
memcpy_s
(items
[indextemp
].Srs
,BUFFER_SIZE_COMMON
, Datas
[indextemp
].Srs
,BUFFER_SIZE_COMMON
);
}
LayerElement
= LayerElement
->NextSiblingElement
("Layer"
);
}
count
= indextemp
+ 1;
delete
myDocument
;
myDocument
= NULL
;
return
true
;
}
GetMap
下载过程
虽然强烈建议大家用socket
开发图片下载这部分,不过还是给出
WinInet
的实现吧。
我定义了一个类
头文件
#ifndef_CVodStreamCache_H
#define
_CVodStreamCache_H
#include
<iostream>
#include
<Windows.h>
#include
<WinInet.h>
#include
<tchar.h>
#include
<string>
using
namespace
std
;
#pragma
comment
(lib
, "wininet.lib"
)
class
CVodStreamCache
{
public
:
CVodStreamCache
();
~CVodStreamCache
();
bool
Create
(char
token
[], char
url
[]);
int
ReadBlock
(long
offset
, int
len
, char
*buffer
);
bool
Recive
(char
buf
[], int
& buflen
);
void
Destory
();
void
CacheInfo
();
void
Abort
(BOOL
IsAbort
);
private
:
HINTERNET
internetOpen
;
HINTERNET
internetOpenUrl
;
DWORD
dwStatusCode
;
DWORD
dwContentLength
;
HANDLE
createFile
;
static
const
int
BUFFERSIZE
= 9216;
BOOL
m_IsAbort
;
};
#endif
//_CVodStreamCache_H
CPP
文件
#include"stdafx.h"
#include
<stdio.h>
#include
"CVodStreamCache.h"
CVodStreamCache
::CVodStreamCache
()
{
internetOpen
= NULL
;
internetOpenUrl
= NULL
;
m_IsAbort
= false
;
}
CVodStreamCache
::~CVodStreamCache
()
{
}
bool
CVodStreamCache
::Create
(char
token
[], char
url
[])
{
internetOpen
= InternetOpen
(NULL
, INTERNET_OPEN_TYPE_PRECONFIG
, NULL
, NULL
, 0);
if
(internetOpen
== NULL
)
{
cout
<< "Internet open failed!"
<< endl
;
return
false
;
}
if
(m_IsAbort
)
{
InternetCloseHandle
(internetOpen
);
return
false
;
}
if
(internetOpen
== NULL
)
{
cout
<< "Internet open failed!"
<< endl
;
return
false
;
}
internetOpenUrl
= InternetOpenUrlA
(internetOpen
, url
,
NULL
, 0, INTERNET_FLAG_TRANSFER_BINARY
| INTERNET_FLAG_PRAGMA_NOCACHE
, 0);
if
(internetOpenUrl
== NULL
)
{
cout
<< "Internet open url failed! Error code = "
<< GetLastError
() << endl
;
InternetCloseHandle
(internetOpen
);
return
false
;
}
return
true
;
}
int
CVodStreamCache
::ReadBlock
(long
offset
, int
len
, char
*buffer
)
{
return
0;
}
bool
CVodStreamCache
::Recive
(char
* buf
, int
& buflen
)
{
BOOL
internetReadFile
;
char
buffer
[BUFFERSIZE
];
memset
(buffer
, 0, sizeof
(buffer
));
DWORD
byteRead
= 0;
DWORD
byteDown
= 0;
while
(1)
{
if
(m_IsAbort
)
{
InternetCloseHandle
(internetOpenUrl
);
InternetCloseHandle
(internetOpen
);
return
false
;
}
if
(!internetOpenUrl
)
{
InternetCloseHandle
(internetOpenUrl
);
InternetCloseHandle
(internetOpen
);
return
false
;
}
internetReadFile
= InternetReadFile
(internetOpenUrl
, buffer
, sizeof
(buffer
), &byteRead
);
if
(byteRead
== 0)
{
break
;
}
if
(m_IsAbort
)
{
InternetCloseHandle
(internetOpenUrl
);
InternetCloseHandle
(internetOpen
);
return
false
;
}
if
(NULL
!= buf
)
{
memcpy_s
(buf
+byteDown
, buflen
- byteDown
, buffer
, byteRead
);
}
byteDown
+= byteRead
;
}
InternetCloseHandle
(internetOpenUrl
);
internetOpenUrl
= NULL
;
InternetCloseHandle
(internetOpen
);
internetOpen
= NULL
;
buflen
= byteDown
;
return
1;
}
void
CVodStreamCache
::Abort
(BOOL
IsAbort
)
{
m_IsAbort
= IsAbort
;
}
................................................
未完待续
................................................
相关文章推荐
- 基于Wms协议的Map开发(五:模块组成)
- 基于Wms协议的Map开发(七:计算模块)
- 基于Wms协议的Map开发(二:相关概念)
- 基于Wms协议的Map开发(三:写在前面)
- 基于Wms协议的Map开发(四:系统设计)
- 基于Wms协议的Map开发(一:概要)
- Android蓝牙开发与蓝牙模块进行通讯(基于eclipse)
- Websocket全讲解。跨平台的通讯协议 !!基于websocket的高并发即时通讯服务器开发。
- 基于xmpp的协议即时通讯软件开发--理论(一)
- Websocket全讲解。跨平台的通讯协议 !!基于websocket的高并发即时通讯服务器开发
- 手机通讯模块开发协议文档索引
- Android实现基于TCP和UDP协议的即时通讯,含android端和服务器端
- iOS开发笔记--基于面向协议MVP模式下的软件设计
- 基于Metronic的Bootstrap开发框架经验总结(1)-框架总览及菜单模块的处理
- 基于Metronic的Bootstrap开发框架经验总结(1)-框架总览及菜单模块的处理
- 基于UDP的通讯协议(zz)
- 基于Video4Linux的视频采集模块开发
- 基于融云的即时通讯开发(一)
- 基于ngx_lua模块的waf开发实践
- 基于88E6095的链路冗余协议开发(三)