GoogleEarth二次开发(资料二)

GoogleEarth二次开发(资料二)

 

在163博客上发布了《GoogleEarth二次开发难点和技巧》一文之后,很多朋友发邮件询问怎样将googleearth的地图控件引用到自定义的窗体中去,因为某些原因一直没有给予详细解答。其实一些公司早已经实现了这种技术,上帝之眼很早就发布了这样一个ge控件,不过控件上有个很大的logo,看着很不爽。后来因为公司业务的需要,也钻研了一下,发现其实实现那样一种效果并不难,下面请听我细细道来。

 

这里用到一种黑客的手段–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地图控件截获:

 

复制代码
   
   
1 // --------------------------------- 2   3 [DllImport( " user32.dll " , CharSet = CharSet.Auto)] 4   public extern static bool SetWindowPos( int hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); 5 6 [DllImport( " user32.dll " , CharSet = CharSet.Auto)] 7   public static extern IntPtr PostMessage( int hWnd, int msg, int wParam, int lParam); 8 9 [DllImport( " user32 " , CharSet = CharSet.Auto)] 10   public extern static IntPtr GetParent(IntPtr hWnd); 11 12 [DllImport( " user32 " , CharSet = CharSet.Auto)] 13   public extern static bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); 14 15 [DllImport( " user32 " , CharSet = CharSet.Auto)] 16   public extern static IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 17 18   private static readonly IntPtr HWND_BOTTOM = new IntPtr( 1 ); 19   private static readonly IntPtr HWND_NOTOPMOST = new IntPtr( - 2 ); 20   private static readonly IntPtr HWND_TOP = new IntPtr( 0 ); 21 private static readonly IntPtr HWND_TOPMOST = new IntPtr( - 1 ); 22 private static readonly UInt32 SWP_NOSIZE = 1 ; 23 private static readonly UInt32 SWP_HIDEWINDOW = 128 ; 24 private static readonly Int32 WM_QUIT = 0x0012 ; 25 private static readonly Int32 WM_HIDE = 0x0 ; 26 // -------------------------------------------
复制代码

 

 

复制代码
   
   
1 // ----------------------------------- 2 private IntPtr _GEHrender; 3 private IntPtr _GEParentHrender; 4 private IntPtr _GEMainHandler; 5 private IApplicationGE _googleEarth; 6 private System.Windows.Forms.Control _parentControl; 7 8 /// <summary> 9 /// 将GE的地图控件挂载到指定的控件中去 10 /// </summary> 11 /// <param name="parentControl">c#控件</param> 12 /// <param name="geApplication">ge应用程序</param> 13 public void SetGEHandlerToControl(System.Windows.Forms.Control parentControl, IApplicationGE geApplication) 14 { 15 this ._parentControl = parentControl; 16 this ._googleEarth = geApplication; 17 18 // 获取GE的主窗体句柄 19 this ._GEMainHandler = (IntPtr) this ._googleEarth.GetMainHwnd(); 20 // 将GE主窗体的高宽设置为0,隐藏掉GE主窗体 21 SetWindowPos(( int ) this ._GEMainHandler, HWND_BOTTOM, 0 , 0 , 0 , 0 , SWP_NOSIZE + SWP_HIDEWINDOW); 22 23 // 获取GE地图控件句柄 24 this ._GEHrender = (IntPtr)_googleEarth.GetRenderHwnd(); 25 // 获取GE地图控件的父窗体句柄 26 this ._GEParentHrender = GetParent( this ._GEHrender); 27 // 将GE地图控件的父窗体设置为不可见 28 // (考虑到GE地图控件可能被其他程序截获,加上这一句以应万全) 29 PostMessage(( int ) this ._GEParentHrender, WM_HIDE, 0 , 0 ); 30 31 // 设置GE地图控件的父窗体句柄为winform上的控件 32 SetParent( this ._GEHrender, parentControl.Handle); 33 } 34 // ----------------------------------------------
复制代码

 

 

 

在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那一成不变的摸样了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值