这里用到一种黑客的手段–hook–来实现,将ge的地图显示部分强行抢夺到我们所指定的一个winform控件上去, 并将ge的主窗体隐藏起来。GE的com api为实现hook提供了方便,通过IApplicationGE.GetMainHwnd()和IApplicationGE.GetRenderHwnd()两个函数我们可以获取到GE主窗体和地图显示部分的句柄,然后利用windows api的几个函数来操作这两个句柄,就能实现我们所期待的效果了。
以VS2005为例(其他windows开发平台都可以),首先新建一个winform窗体,将GE的com组件引用进来,并在winform上添加一个panel控件(命名为pnlEarth),然后引入我们所需要的几个window API函数和常量。(这些API的具体作用和使用方法请自己查资料,这里不再啰嗦)
接下来,我们开始最关键的部分–GE地图控件截获:
这里用到一种黑客的手段–hook–来实现,将ge的地图显示部分强行抢夺到我们所指定的一个winform控件上去, 并将ge的主窗体隐藏起来。GE的com api为实现hook提供了方便,通过IApplicationGE.GetMainHwnd()和IApplicationGE.GetRenderHwnd()两个函数我们可以获取到GE主窗体和地图显示部分的句柄,然后利用windows api的几个函数来操作这两个句柄,就能实现我们所期待的效果了。
以VS2005为例(其他windows开发平台都可以),首先新建一个winform窗体,将GE的com组件引用进来,并在winform上添加一个panel控件(命名为pnlEarth),然后引入我们所需要的几个window API函数和常量。(这些API的具体作用和使用方法请自己查资料,这里不再啰嗦)
接下来,我们开始最关键的部分–GE地图控件截获:
GE地图控件截获
//-----------------------------------
private IntPtr _GEHrender;
private IntPtr _GEParentHrender;
private IntPtr _GEMainHandler;
private IApplicationGE _googleEarth;
private System.Windows.Forms.Control _parentControl;
/// <summary>
/// 将GE的地图控件挂载到指定的控件中去
/// </summary>
/// <param name="parentControl">c#控件</param>
/// <param name="geApplication">ge应用程序</param>
public void SetGEHandlerToControl(System.Windows.Forms.Control parentControl, IApplicationGE geApplication)
{
this._parentControl = parentControl;
this._googleEarth = geApplication;
//获取GE的主窗体句柄
this._GEMainHandler = (IntPtr)this._googleEarth.GetMainHwnd();
//将GE主窗体的高宽设置为0,隐藏掉GE主窗体
SetWindowPos((int)this._GEMainHandler, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE + SWP_HIDEWINDOW);
//获取GE地图控件句柄
this._GEHrender = (IntPtr)_googleEarth.GetRenderHwnd();
//获取GE地图控件的父窗体句柄
this._GEParentHrender = GetParent(this._GEHrender);
//将GE地图控件的父窗体设置为不可见
//(考虑到GE地图控件可能被其他程序截获,加上这一句以应万全)
PostMessage((int)this._GEParentHrender, WM_HIDE, 0, 0);
//设置GE地图控件的父窗体句柄为winform上的控件
SetParent(this._GEHrender, parentControl.Handle);
}
//----------------------------------------------
在winform的load事件中加入SetGEHandlerToControl函数,编译并打开程序 ,这时候你发现你已经成功了。
但是,还不能高兴的太早, 还有两个问题需要解决。你会发现从GE截获的地图控件并不会随着你自定义窗体的大小改变而改变,另外,你自定义窗体关闭之后,GE的进程还没有被杀掉,进而引起下次启动GE的时候地图控件会消失掉。不用急,是问题总会有解决的办法。再定义下面两个函数
代码
//----------------------------------
/// <summary>
/// 使GE控件的大小和父窗体的大小保持一致
/// </summary>
public void ResizeGEControl()
{
if (this._parentControl != null)
{
//设置GE地图控件的大小等于父窗体大小
MoveWindow(this._GEHrender, 0, 0, this._parentControl.Width, this._parentControl.Height, true);
}
}
/// <summary>
/// 释放GE句柄
/// </summary>
public void RealseGEHandler()
{
try
{
if (this._parentControl != null)
{
//将GE地图控件的句柄还原到GE主窗体上去
SetParent(this._GEHrender, this._GEParentHrender);
//关闭GE主程序
PostMessage(this._googleEarth.GetMainHwnd(), WM_QUIT, 0, 0);
}
}
finally
{
//为防本程序的进程不能成功退出而导致GE出现问题,强制杀掉本程序的进程
System.Diagnostics.Process geProcess = System.Diagnostics.Process.GetCurrentProcess();
geProcess.Kill();
}
}
//----------------------------------
ResizeGEControl函数放在pnlEarth控件的SizeChanged事件中,这样每次panel大小改变,GE的地图控件的大小也会随之改变; RealseGEHandler函数放在winform的FormClosing事件中,以释放GE的窗体句柄。
经过上面几个步骤,就实现了GE地图控件的截获。接下来要做一些基于GE的开发,我们就可以摆脱GE那一成不变的摸样了。