zoukankan      html  css  js  c++  java
  • 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 //-------------------------------------------

     

     

    GE地图控件截获
    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那一成不变的摸样了。

  • 相关阅读:
    20175330第九周学习总结
    20172326 《程序设计与数据结构》第十周学习总结
    20172326 《程序设计与数据结构》第九周学习总结
    20172326『Java程序设计』课程结对编程练习_四则运算第二周阶段总结
    《程序设计与数据结构》第八周学习总结
    结对编程-四则运算 第一周总结
    《程序设计与数据结构》实验2报告
    《程序设计与数据结构》第七周学习总结
    20172326 2017-2018-2 《程序设计与数据结构》第7周课堂测试修改报告
    《程序设计与数据结构》第六周学习总结
  • 原文地址:https://www.cnblogs.com/DivClose/p/1759904.html
Copyright © 2011-2022 走看看