一、准備
Google Earth提供了個人免費版、Plus版、Pro版,個人開發只安裝個人免費版就可以了,如果需要更多的功能,那么只有每年上交$400購買專業版了
到目前為止,GoogleEarth的二次開發接口還比較少,功能太弱,僅僅提供了1.0的類庫。
GoogleEarth COM API參考文檔可以在這里找到:http://earth.google.com/comapi/index.html
C#調用COM的參考資料多如牛毛,大家可以到網上搜一下
二、例子
這里提供一個利用VS2008 + Google Earth 5.0開發一個“Hello world”程序
首先,確保已經正確安裝GE,打開VS2008 ,新建一個Windows應用程序項目,在“項目”菜單中選擇“添加引用…”,切換到“COM”選項卡,選擇“Google Earth 1.0 Type Library”,其實就是Google Earth的主程序
在項目的引用中你可以看到已經添加了一個EARTHLib的引用,然后我們就可以調用其中的接口進行開發了。
下面就是小例子的代碼,打開GE,然后讓GE保存一張截圖,然后可以打開這個截圖。
1.// 功能:GE實例 2: // 描述:GE COM API 網址:http://earth.google.com/comapi/index.html 3: // 作者:溫偉鵬 4: // 日期:2008-01-20 5: 6: using System; 7: using System.Collections.Generic; 8: using System.ComponentModel; 9: using System.Data; 10: using System.Drawing; 11: using System.Text; 12: using System.Windows.Forms; 13: using EARTHLib; 14: using System.Runtime.InteropServices; 15: using System.IO; 16: using System.Diagnostics; 17: 18: namespace GEDemo 19: { 20: public partial class Form1 : Form 21: { 22: /// <summary> 23: /// 標記GE是否已經啟動 24: /// </summary> 25: private bool isGeStarted = false; 26: /// <summary> 27: /// 定義GE應用程序類 28: /// </summary> 29: private ApplicationGEClass GeApp; 30: 31: public Form1() 32: { 33: InitializeComponent(); 34: } 35: 36: private void button1_Click(object sender, EventArgs e) 37: { 38: StartGE(); 39: } 40: 41: /// <summary> 42: /// 啟動GE 43: /// </summary> 44: private void StartGE() 45: { 46: if (isGeStarted) 47: { 48: return; 49: } 50: 51: try 52: { 53: GeApp = (ApplicationGEClass)Marshal.GetActiveObject("GoogleEarth.Application"); 54: 55: isGeStarted = true; 56: } 57: catch 58: { 59: GeApp = new ApplicationGEClass(); 60: 61: isGeStarted = true; 62: } 63: } 64: 65: private void button2_Click(object sender, EventArgs e) 66: { 67: string ssFile = Path.Combine(Application.StartupPath, "ScreenShot.jpg"); 68: 69: try 70: { 71: //quality的取值范圍在(0,100)之間,質量越高,quality越大 72: GeApp.SaveScreenShot(ssFile, 100); 73: 74: MessageBox.Show("成功保存截屏圖像:" + ssFile); 75: } 76: catch(Exception ex) 77: { 78: MessageBox.Show("保存截屏圖像時發生錯誤:" + ex.Message); 79: } 80: } 81: 82: private void button3_Click(object sender, EventArgs e) 83: { 84: string ssFile = Path.Combine(Application.StartupPath, "ScreenShot.jpg"); 85: 86: if (!File.Exists(ssFile)) 87: { 88: MessageBox.Show("未能找到保存的截屏圖像!"); 89: return; 90: } 91: 92: Process.Start(ssFile); 93: } 94: 95: private void button4_Click(object sender, EventArgs e) 96: { 97: this.Close(); 98: Application.Exit(); 99: } 100: 101: } 102: }
將GoogleEarth的界面隱藏掉,並將GoogleEarth的地圖顯示在自定義的窗體上。
1。主窗口代碼
1: // 功能:GE實例(二) 2: // 描述:GE COM API 網址:http://earth.google.com/comapi/index.html 3: // 作者:溫偉鵬 4: // 日期:2009-02-08 5: 6: using System; 7: using System.Collections.Generic; 8: using System.ComponentModel; 9: using System.Data; 10: using System.Drawing; 11: using System.Text; 12: using System.Windows.Forms; 13: using EARTHLib; 14: 15: namespace GEDemo 16: { 17: public partial class Form2 : Form 18: { 19: /// <summary> 20: /// 用來關閉GoogleEarth的消息定義 21: /// </summary> 22: static readonly Int32 WM_QUIT = 0x0012; 23: 24: private IntPtr GEHWnd = (IntPtr)5; 25: private IntPtr GEHrender = (IntPtr)5; 26: private IntPtr GEParentHrender = (IntPtr)5; 27: /// <summary> 28: /// 定義GE應用程序類 29: /// </summary> 30: private ApplicationGEClass GeApp; 31: 32: public Form2() 33: { 34: InitializeComponent(); 35: } 36: 37: protected override void OnLoad(EventArgs e) 38: { 39: base.OnLoad(e); 40: 41: if (!this.DesignMode) 42: { 43: GeApp = new ApplicationGEClass(); 44: 45: GEHWnd = (IntPtr)GeApp.GetMainHwnd(); 46: 47: NativeMethods.SetWindowPos(GEHWnd, NativeMethods.HWND_BOTTOM, 0, 0, 0, 0, 48: NativeMethods.SWP_NOSIZE + NativeMethods.SWP_HIDEWINDOW); 49: 50: GEHrender = (IntPtr)GeApp.GetRenderHwnd(); 51: GEParentHrender = (IntPtr)NativeMethods.GetParent(GEHrender); 52: 53: NativeMethods.MoveWindow(GEHrender, 0, 0, this.Width, this.Height, true); 54: 55: NativeMethods.SetParent(GEHrender, this.Handle); 56: } 57: } 58: 59: protected override void OnClosing(CancelEventArgs e) 60: { 61: base.OnClosing(e); 62: 63: NativeMethods.PostMessage(GeApp.GetMainHwnd(), WM_QUIT, 0, 0); 64: } 65: } 66: }
2、NativeMethods類定義:
1: // 功能:Windows API調用 2: // 描述:大家可以參照MSDN 3: // 作者:溫偉鵬 4: // 日期:2009-02-08 5: 6: using System; 7: using System.Collections.Generic; 8: using System.Text; 9: using System.Runtime.InteropServices; 10: 11: namespace GEDemo 12: { 13: public class NativeMethods 14: { 15: [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 16: public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, UInt32 uflags); 17: 18: [DllImport("user32.dll", CharSet = CharSet.Auto)] 19: public static extern IntPtr PostMessage(int hWnd, int msg, int wParam, int lParam); 20: 21: #region 預定義 22: 23: public static readonly IntPtr HWND_BOTTOM = new IntPtr(1); 24: public static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2); 25: public static readonly IntPtr HWND_TOP = new IntPtr(0); 26: public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1); 27: public static readonly UInt32 SWP_NOSIZE = 1; 28: public static readonly UInt32 SWP_NOMOVE = 2; 29: public static readonly UInt32 SWP_NOZORDER = 4; 30: public static readonly UInt32 SWP_NOREDRAW = 8; 31: public static readonly UInt32 SWP_NOACTIVATE = 16; 32: public static readonly UInt32 SWP_FRAMECHANGED = 32; 33: public static readonly UInt32 SWP_SHOWWINDOW = 64; 34: public static readonly UInt32 SWP_HIDEWINDOW = 128; 35: public static readonly UInt32 SWP_NOCOPYBITS = 256; 36: public static readonly UInt32 SWP_NOOWNERZORDER = 512; 37: public static readonly UInt32 SWP_NOSENDCHANGING = 1024; 38: 39: #endregion 40: 41: public delegate int EnumWindowsProc(IntPtr hwnd, int lParam); 42: 43: [DllImport("user32", CharSet = CharSet.Auto)] 44: public extern static IntPtr GetParent(IntPtr hWnd); 45: 46: [DllImport("user32", CharSet = CharSet.Auto)] 47: public extern static bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint); 48: 49: [DllImport("user32", CharSet = CharSet.Auto)] 50: public extern static IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); 51: 52: [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)] 53: public static extern IntPtr GetWindow(IntPtr hWnd, int uCmd); 54: 55: public static int GW_CHILD = 5; 56: public static int GW_HWNDNEXT = 2; 57: } 58: }
3、執行效果:
主要改進了三個方面。
1) 實現GoogleEarth顯示畫面隨窗口大小改變而改變
2) 截獲GoogleEarth鼠標消息,實現單擊、雙擊功能;鼠標滾輪縮放現在只能放大!O(∩_∩)O~
3) 實現GoogleEarth彩色截圖(測試環境:Windows 2003 Server ,Vista與Win7中不可用,XP未測)
下面還是繼續看代碼:
1、GoogleEarth動態改變大小
1: /// <summary> 2: /// 重新改變GoogleEarth視圖的大小 3: /// </summary> 4: private void ResizeGoogleControl() 5: { 6: NativeMethods.SendMessage(GEHWnd, (uint)NativeMethods.WM_COMMAND, NativeMethods.WM_PAINT, 0); 7: NativeMethods.PostMessage(GEHWnd, NativeMethods.WM_QT_PAINT, 0, 0); 8: 9: RECT mainRect = new RECT(); 10: NativeMethods.GetWindowRect(GEHWnd, out mainRect); 11: clientRect = new RECT(); 12: NativeMethods.GetClientRect(GEHrender, out clientRect); 13: 14: int offsetW = mainRect.Width - clientRect.Width; 15: int offsetH = mainRect.Height - clientRect.Height; 16: 17: int newWidth = this.Control.Width + (int)offsetW; 18: int newHeight = this.Control.Height + (int)offsetH; 19: 20: NativeMethods.SetWindowPos(GEHWnd, NativeMethods.HWND_TOP, 21: 0, 0, newWidth, newHeight, 22: NativeMethods.SWP_FRAMECHANGED); 23: 24: NativeMethods.SendMessage(GEHWnd, (uint)NativeMethods.WM_COMMAND, NativeMethods.WM_SIZE, 0); 25: }
此例子中對於鼠標消息到處理使用了鈎子,調用HookAPI.dll實現。
1: /// <summary> 2: /// 鼠標鈎子 3: /// </summary> 4: private MouseHook mouseHook; 5: 6: // 設置鼠標鈎子 7: mouseHook = new MouseHook(); 8: mouseHook.MouseClick += new MouseEventHandler(mouseHook_MouseClick); 9: mouseHook.MouseDbClick += new MouseEventHandler(mouseHook_MouseDbClick); 10: mouseHook.MouseWheel += new MouseEventHandler(mouseHook_MouseWheel); 11: // 啟動鼠標鈎子 12: mouseHook.StartHook(HookType.WH_MOUSE_LL, 0);
1: /// <summary> 2: /// 鼠標鈎子。鼠標單擊事件 3: /// </summary> 4: /// <param name="sender"></param> 5: /// <param name="e"></param> 6: void mouseHook_MouseClick(object sender, MouseEventArgs e) 7: { 8: IntPtr hWnd = NativeMethods.WindowFromPoint(e.Location); 9: if (hWnd == this.GeRenderHWnd) 10: { 11: Point point = this.Control.PointToClient(e.Location); 12: // 如果鼠標擊點位置在控件內部,則說明鼠標點擊了GoogleEarth視圖 13: if (this.Control.ClientRectangle.Contains(point)) 14: { 15: Console.WriteLine("點擊了GoogleEarth..."); 16: 17: DoublePoint dp = ((GERenderPanel)Control).DetermineScreenCoordinates(point.X, point.Y); 18: 19: ParameterizedThreadStart pts = new ParameterizedThreadStart(ShowMouseClickPoint); 20: 21: Thread thread = new Thread(pts); 22: thread.Start(dp); 23: 24: } 25: } 26: } 27: 28: protected void ShowMouseClickPoint(object obj) 29: { 30: //Thread.Sleep(20); 31: DoublePoint dp = (DoublePoint)obj; 32: PointOnTerrainGE pGe = GeApp.GetPointOnTerrainFromScreenCoords(dp.X, dp.Y); 33: Console.WriteLine("鼠標點擊了:Lnt=" + pGe.Longitude.ToString() 34: + ";Lat=" + pGe.Latitude.ToString()); 35: }
雙擊事件:
1: /// <summary> 2: /// 鼠標鈎子。鼠標雙擊事件 3: /// </summary> 4: /// <param name="sender"></param> 5: /// <param name="e"></param> 6: void mouseHook_MouseDbClick(object sender, MouseEventArgs e) 7: { 8: IntPtr hWnd = NativeMethods.WindowFromPoint(e.Location); 9: if (hWnd == this.GeRenderHWnd) 10: { 11: Point point = this.Control.PointToClient(e.Location); 12: // 如果鼠標擊點位置在控件內部,則說明鼠標點擊了GoogleEarth視圖 13: if (this.Control.ClientRectangle.Contains(point)) 14: { 15: Console.WriteLine("xx雙擊了GoogleEarth..."); 16: 17: DoublePoint dp = ((GERenderPanel)Control).DetermineScreenCoordinates(point.X, point.Y); 18: 19: ParameterizedThreadStart pts = new ParameterizedThreadStart(ShowMouseDbClickPoint); 20: 21: Thread thread = new Thread(pts); 22: thread.Start(dp); 23: 24: } 25: } 26: } 27: 28: protected void ShowMouseDbClickPoint(object obj) 29: { 30: //Thread.Sleep(20); 31: DoublePoint dp = (DoublePoint)obj; 32: PointOnTerrainGE pGe = GeApp.GetPointOnTerrainFromScreenCoords(dp.X, dp.Y); 33: Console.WriteLine("xx鼠標雙擊了:Lnt=" + pGe.Longitude.ToString() 34: + ";Lat=" + pGe.Latitude.ToString()); 35: 36: MessageBox.Show("我還是出來一下吧!省得你不知道你已經雙擊了鼠標!"); 37: }
3、截圖
程序中有兩種截圖功能,一種是GoogleEarth自帶的截圖功能,只能截取黑白圖片;另一種為彩色截圖,但是Vista以上操作系統不支持,還未找到合適的方法實現Vista與Win7兼容。
1) GoogleEarth自帶截圖功能:
1: GEViewContent view = GetGEView(); 2: 3: if (view != null) 4: { 5: ApplicationGE ge = view.GeApplication; 6: if (ge != null && ge.IsInitialized() > 0) 7: { 8: using (SaveFileDialog sfd = new SaveFileDialog()) 9: { 10: sfd.Filter = "jpg圖片|*.jpg"; 11: sfd.AddExtension = true; 12: sfd.CheckPathExists = true; 13: sfd.Title = "保存Google Earth截圖"; 14: 15: if (sfd.ShowDialog() == DialogResult.OK) 16: { 17: ge.SaveScreenShot(sfd.FileName, 100); 18: } 19: } 20: } 21: }
2) 彩色截圖:
1: GEViewContent view = GetGEView(); 2: if (view != null) 3: { 4: int nWidth = view.Control.Width; 5: int nHeight = view.Control.Height; 6: Point pt = view.Control.PointToScreen(view.Control.Location); 7: int nXSrc = pt.X; 8: int nYSrc = pt.Y; 9: 10: IntPtr hRender = view.GeRenderHWnd; 11: 12: if (hRender != IntPtr.Zero) 13: { 14: // 取得Render DC 15: IntPtr hRenderDC = NativeMethods.GetWindowDC(hRender); 16: // 創建hBitmap 17: IntPtr hBitmap = NativeMethods.CreateCompatibleBitmap(hRenderDC, nWidth, nHeight); 18: // 創建MEM DC 19: IntPtr hMemDC = NativeMethods.CreateCompatibleDC(hRenderDC); 20: // 將Bitmap Select到MemDC 21: NativeMethods.SelectObject(hMemDC, hBitmap); 22: // 直接拷屏 23: NativeMethods.BitBlt(hMemDC, 0, 0, nWidth, nHeight, 24: hRenderDC, 0, 0, 13369376); 25: 26: using(Bitmap bmp = Bitmap.FromHbitmap(hBitmap)) 27: { 28: using(SaveFileDialog sfd = new SaveFileDialog()) 29: { 30: sfd.Filter = "JPG圖片|*.jpg|PNG圖片|*.png"; 31: sfd.AddExtension = true; 32: sfd.CheckPathExists = true; 33: sfd.Title = "保存Google Earth截圖"; 34: 35: if (sfd.ShowDialog() == DialogResult.OK) 36: { 37: ImageFormat imgFormat = null; 38: // 默認選擇JPG 39: if (sfd.FilterIndex == 0) 40: { 41: imgFormat = ImageFormat.Jpeg; 42: } 43: // 選擇PNG 44: else 45: { 46: imgFormat = ImageFormat.Png; 47: } 48: bmp.Save(sfd.FileName, imgFormat); 49: } 50: } 51: 52: //銷毀資源 53: NativeMethods.DeleteDC(hRenderDC); 54: NativeMethods.DeleteDC(hMemDC); 55: } 56: }
http://files.cnblogs.com/wpwen/GEDemo_2009-05-22.rar
1)增加鼠標滾輪支持,可以實現放大、縮小。此功能利用上一篇提供的HookAPI.dll實現
2: // 放大 3: private const long ZoomIn = 0x00780000; 4: // 縮小 5: private const long ZoomOut = 0xFF880000; 6: ... 7: mouseHook.MouseWheel += new MouseEventHandler(mouseHook_MouseWheel); 8: ... 9: /// <summary> 10: /// 鼠標鈎子。鼠標滾動事件 11: /// </summary> 12: /// <param name="sender"></param> 13: /// <param name="e"></param> 14: void mouseHook_MouseWheel(object sender, MouseEventArgs e) 15: { 16: IntPtr hWnd = NativeMethods.WindowFromPoint(e.Location); 17: if (hWnd == this.GeRenderHWnd) 18: { 19: Point point = this.Control.PointToClient(e.Location); 20: // 如果鼠標位置在控件內部,則說明鼠標在GoogleEarth視圖范圍內進行了滾動 21: if (this.Control.ClientRectangle.Contains(point)) 22: { 23: NativeMethods.PostMessage(GeRenderHWnd, (int)WM_MOUSE.WM_MOUSEWHEEL, e.Delta == 120 ? ZoomIn : ZoomOut, 0); 24: } 25: } 26: }
2)讀取PlaceMarks(Google Earth界面中的位置)並顯示、隱藏
3)讀取所有圖層,顯示並隱藏,讀取PlaceMarks
Google Earth COM API中提供了兩個讀取PlaceMarks的函數。一個是GetTemporaryPlaces(),用來讀取臨時位置;另一個是GetMyPlaces(),用來讀取自定義位置,即GoogleEarth中顯示的“我的位置”。呵呵
1: ... 2: /// <summary> 3: /// 顯示位置“PlaceMarks”。位置分為兩種,一種時TemporaryPlaces,另一種為MyPlaces 4: /// </summary> 5: protected void ShowPlaces() 6: { 7: Thread.Sleep(500); 8: // 獲取MyPlaces 9: FeatureGE myPlace = GeApp.GetMyPlaces(); 10: // 獲取臨時位置 11: FeatureGE temporaryPlace = GeApp.GetTemporaryPlaces(); 12: // 13: List<FeatureGE> places = new List<FeatureGE>(); 14: places.Add(myPlace); 15: places.Add(temporaryPlace); 16: 17: // 獲取工具面板 18: GEToolPad toolPad = GetToolPad(); 19: // 顯示所有位置 20: toolPad.ShowPlaces(places); 21: } 22: ... 23: /// <summary> 24: /// 顯示所有PlaceMarks(位置) 25: /// </summary> 26: /// <param name="places"></param> 27: public void ShowPlaces(List<FeatureGE> places) 28: { 29: if (this.InvokeRequired) 30: { 31: Action method = delegate { 32: InternalShowPlaces(places); 33: }; 34: 35: try 36: { 37: this.Invoke(method); 38: } 39: catch { } 40: } 41: else 42: { 43: InternalShowPlaces(places); 44: } 45: } 46: /// <summary> 47: /// 顯示所有PlaceMarks(位置)。被ShowPlaces函數調用 48: /// </summary> 49: /// <param name="places"></param> 50: protected void InternalShowPlaces(List<FeatureGE> places) 51: { 52: this.tvPlaces.Nodes.Clear(); 53: 54: if (places == null || places.Count <= 0) 55: return; 56: 57: foreach (FeatureGE place in places) 58: { 59: TreeNode node = new TreeNode(place.Name); 60: node.Checked = place.Visibility > 0; 61: node.Tag = place; 62: 63: ShowChildrenPlaces(place, node); 64: 65: node.Expand(); 66: 67: this.tvPlaces.Nodes.Add(node); 68: } 69: } 70: /// <summary> 71: /// 顯示指定PlaceMark的子PlaceMark 72: /// </summary> 73: /// <param name="place">父PlaceMark</param> 74: /// <param name="node">父節點</param> 75: protected void ShowChildrenPlaces(FeatureGE place, TreeNode node) 76: { 77: FeatureCollectionGE places = place.GetChildren(); 78: 79: foreach (FeatureGE child in places) 80: { 81: TreeNode tn = new TreeNode(child.Name); 82: tn.Checked = child.Visibility > 0; 83: tn.Tag = child; 84: 85: ShowChildrenPlaces(child, tn); 86: 87: node.Nodes.Add(tn); 88: } 89: }
3、讀取圖層
2: /// <summary> 3: /// 顯示圖層 4: /// </summary> 5: protected void ShowLayers() 6: { 7: Thread.Sleep(500); 8: // 獲取所有圖層信息 9: FeatureCollectionGE layers = GeApp.GetLayersDatabases(); 10: // 獲取工具面板 11: GEToolPad toolPad = GetToolPad(); 12: // 顯示所有圖層 13: toolPad.ShowLayers(layers); 14: } 15: ... 16: /// <summary> 17: /// 將給定的圖層集合顯示在“圖層”選項卡的樹形控件中 18: /// </summary> 19: /// <param name="layers">圖層集合</param> 20: public void ShowLayers(FeatureCollectionGE layers) 21: { 22: if (this.InvokeRequired) 23: { 24: Action method = delegate { 25: InternalShowLayers(layers); 26: }; 27: try 28: { 29: this.Invoke(method); 30: } 31: catch { } 32: } 33: else 34: { 35: InternalShowLayers(layers); 36: } 37: } 38: /// <summary> 39: /// 將給定的圖層集合顯示在“圖層”選項卡的樹形控件中.被公共函數ShowLayers調用 40: /// </summary> 41: /// <param name="layers"></param> 42: protected void InternalShowLayers(FeatureCollectionGE layers) 43: { 44: this.tvLayers.Nodes.Clear(); 45: 46: if (layers == null || layers.Count <= 0) 47: { 48: return; 49: } 50: 51: foreach (FeatureGE layer in layers) 52: { 53: TreeNode node = new TreeNode(layer.Name); 54: node.Checked = layer.Visibility > 0; 55: node.Tag = layer; 56: 57: ShowChidrenLayers(layer, node); 58: 59: node.Expand(); 60: 61: this.tvLayers.Nodes.Add(node); 62: } 63: } 64: /// <summary> 65: /// 顯示指定圖層的子圖層 66: /// </summary> 67: /// <param name="layer">當前圖層</param> 68: /// <param name="node">當前節點</param> 69: protected void ShowChidrenLayers(FeatureGE layer, TreeNode node) 70: { 71: FeatureCollectionGE layers = layer.GetChildren(); 72: 73: foreach (FeatureGE child in layers) 74: { 75: TreeNode tn = new TreeNode(child.Name); 76: tn.Checked = child.Visibility > 0; 77: tn.Tag = child; 78: 79: ShowChidrenLayers(child, tn); 80: 81: node.Nodes.Add(tn); 82: } 83: }