diff --git a/GMap.NET.WindowsMobile/GMap.NET.GPS/GPS.cs b/GMap.NET.WindowsMobile/GMap.NET.GPS/GPS.cs
new file mode 100644
--- /dev/null
+++ b/GMap.NET.WindowsMobile/GMap.NET.GPS/GPS.cs
@@ -0,0 +1,390 @@
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+//
+// Use of this sample source code is subject to the terms of the Microsoft
+// license agreement under which you licensed this sample source code. If
+// you did not accept the terms of the license agreement, you are not
+// authorized to use this sample source code. For the terms of the license,
+// please see the license agreement between you and Microsoft or, if applicable,
+// see the LICENSE.RTF on your install media or the root of your tools installation.
+// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
+//
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+#if PocketPC
+using OpenNETCF.ComponentModel;
+using OpenNETCF.Threading;
+using Thread=OpenNETCF.Threading.Thread2;
+using System.Diagnostics;
+#endif
+
+namespace GMap.NET.GPS
+{
+ public delegate void LocationChangedEventHandler(object sender, GpsPosition args);
+ public delegate void DeviceStateChangedEventHandler(object sender, GpsDeviceState args);
+
+ ///
+ /// Summary description for GPS.
+ ///
+ public class Gps
+ {
+ // handle to the gps device
+ IntPtr gpsHandle = IntPtr.Zero;
+
+ // handle to the native event that is signalled when the GPS
+ // devices gets a new location
+ IntPtr newLocationHandle = IntPtr.Zero;
+
+ // handle to the native event that is signalled when the GPS
+ // device state changes
+ IntPtr deviceStateChangedHandle = IntPtr.Zero;
+
+ // handle to the native event that we use to stop our event
+ // thread
+ IntPtr stopHandle = IntPtr.Zero;
+
+ // holds our event thread instance
+ Thread gpsEventThread = null;
+
+
+ event LocationChangedEventHandler locationChanged;
+
+ ///
+ /// Event that is raised when the GPS locaction data changes
+ ///
+ public event LocationChangedEventHandler LocationChanged
+ {
+ add
+ {
+ locationChanged += value;
+
+ // create our event thread only if the user decides to listen
+ CreateGpsEventThread();
+ }
+ remove
+ {
+ locationChanged -= value;
+ }
+ }
+
+
+ event DeviceStateChangedEventHandler deviceStateChanged;
+
+ ///
+ /// Event that is raised when the GPS device state changes
+ ///
+ public event DeviceStateChangedEventHandler DeviceStateChanged
+ {
+ add
+ {
+ deviceStateChanged += value;
+
+ // create our event thread only if the user decides to listen
+ CreateGpsEventThread();
+ }
+ remove
+ {
+ deviceStateChanged -= value;
+ }
+ }
+
+ ///
+ /// True: The GPS device has been opened. False: It has not been opened
+ ///
+ public bool Opened
+ {
+ get
+ {
+ return gpsHandle != IntPtr.Zero;
+ }
+ }
+
+ ~Gps()
+ {
+ // make sure that the GPS was closed.
+ Close();
+ }
+
+ ///
+ /// Opens the GPS device and prepares to receive data from it.
+ ///
+ public void Open()
+ {
+ if(!Opened)
+ {
+ // create handles for GPS events
+ newLocationHandle = CreateEvent(IntPtr.Zero, 0, 0, null);
+ deviceStateChangedHandle = CreateEvent(IntPtr.Zero, 0, 0, null);
+ stopHandle = CreateEvent(IntPtr.Zero, 0, 0, null);
+
+ gpsHandle = GPSOpenDevice(newLocationHandle, deviceStateChangedHandle, null, 0);
+
+ // if events were hooked up before the device was opened, we'll need
+ // to create the gps event thread.
+ if(locationChanged != null || deviceStateChanged != null)
+ {
+ CreateGpsEventThread();
+ }
+ }
+ }
+
+ ///
+ /// Closes the gps device.
+ ///
+ public void Close()
+ {
+ if(gpsHandle != IntPtr.Zero)
+ {
+ GPSCloseDevice(gpsHandle);
+ gpsHandle = IntPtr.Zero;
+ }
+
+ // Set our native stop event so we can exit our event thread.
+ if(stopHandle != IntPtr.Zero)
+ {
+ EventModify(stopHandle, eventSet);
+ }
+
+ // wait exit
+ if(gpsEventThread != null && gpsEventThread.IsAlive)
+ {
+ //gpsEventThread.Join(4444);
+ }
+ }
+
+ ///
+ /// Get the position reported by the GPS receiver
+ ///
+ /// GpsPosition class with all the position details
+ public GpsPosition GetPosition()
+ {
+ return GetPosition(TimeSpan.Zero);
+ }
+
+ ///
+ /// Get the position reported by the GPS receiver that is no older than
+ /// the maxAge passed in
+ ///
+ /// Max age of the gps position data that you want back.
+ /// If there is no data within the required age, null is returned.
+ /// if maxAge == TimeSpan.Zero, then the age of the data is ignored
+ /// GpsPosition class with all the position details
+ public GpsPosition GetPosition(TimeSpan maxAge)
+ {
+ GpsPosition gpsPosition = null;
+ if(Opened)
+ {
+ // allocate the necessary memory on the native side. We have a class (GpsPosition) that
+ // has the same memory layout as its native counterpart
+ IntPtr ptr = Utils.LocalAlloc(Marshal.SizeOf(typeof(GpsPosition)));
+
+ // fill in the required fields
+ gpsPosition = new GpsPosition();
+ gpsPosition.dwVersion = 1;
+ gpsPosition.dwSize = Marshal.SizeOf(typeof(GpsPosition));
+
+ // Marshal our data to the native pointer we allocated.
+ Marshal.StructureToPtr(gpsPosition, ptr, false);
+
+ // call native method passing in our native buffer
+ int result = GPSGetPosition(gpsHandle, ptr, 500000, 0);
+ if(result == 0)
+ {
+ // native call succeeded, marshal native data to our managed data
+ gpsPosition = (GpsPosition) Marshal.PtrToStructure(ptr, typeof(GpsPosition));
+
+ if(maxAge != TimeSpan.Zero)
+ {
+ // check to see if the data is recent enough.
+ if(!gpsPosition.Time.HasValue || DateTime.UtcNow - maxAge > gpsPosition.Time)
+ {
+ gpsPosition = null;
+ }
+ }
+ }
+
+ // free our native memory
+ Utils.LocalFree(ptr);
+ }
+
+ return gpsPosition;
+ }
+
+ ///
+ /// Queries the device state.
+ ///
+ /// Device state information
+ public GpsDeviceState GetDeviceState()
+ {
+ GpsDeviceState device = null;
+
+ // allocate a buffer on the native side. Since the
+ IntPtr pGpsDevice = Utils.LocalAlloc(GpsDeviceState.GpsDeviceStructureSize);
+
+ // GPS_DEVICE structure has arrays of characters, it's easier to just
+ // write directly into memory rather than create a managed structure with
+ // the same layout.
+ Marshal.WriteInt32(pGpsDevice, 1); // write out GPS version of 1
+ Marshal.WriteInt32(pGpsDevice, 4, GpsDeviceState.GpsDeviceStructureSize); // write out dwSize of structure
+
+ int result = GPSGetDeviceState(pGpsDevice);
+
+ if(result == 0)
+ {
+ // instantiate the GpsDeviceState class passing in the native pointer
+ device = new GpsDeviceState(pGpsDevice);
+ }
+
+ // free our native memory
+ Utils.LocalFree(pGpsDevice);
+
+ return device;
+ }
+
+ ///
+ /// Creates our event thread that will receive native events
+ ///
+ private void CreateGpsEventThread()
+ {
+ // we only want to create the thread if we don't have one created already
+ // and we have opened the gps device
+ if(gpsEventThread == null && gpsHandle != IntPtr.Zero)
+ {
+ // Create and start thread to listen for GPS events
+ gpsEventThread = new Thread(new System.Threading.ThreadStart(WaitForGpsEvents));
+ gpsEventThread.IsBackground = false;
+ gpsEventThread.Name = "GMap.NET GpsEvents";
+ gpsEventThread.Start();
+ }
+ }
+
+ ///
+ /// Method used to listen for native events from the GPS.
+ ///
+ private void WaitForGpsEvents()
+ {
+ //lock (this)
+ {
+ bool listening = true;
+ // allocate 3 handles worth of memory to pass to WaitForMultipleObjects
+ IntPtr handles = Utils.LocalAlloc(12);
+
+ // write the three handles we are listening for.
+ Marshal.WriteInt32(handles, 0, stopHandle.ToInt32());
+ Marshal.WriteInt32(handles, 4, deviceStateChangedHandle.ToInt32());
+ Marshal.WriteInt32(handles, 8, newLocationHandle.ToInt32());
+
+ while(listening)
+ {
+ int obj = WaitForMultipleObjects(3, handles, 0, -1);
+ if(obj != waitFailed)
+ {
+ switch(obj)
+ {
+ case 0:
+ // we've been signalled to stop
+ listening = false;
+ break;
+
+ case 1:
+ // device state has changed
+ if(deviceStateChanged != null)
+ {
+ deviceStateChanged(this, GetDeviceState());
+ }
+ break;
+
+ case 2:
+ // location has changed
+ if(locationChanged != null)
+ {
+ locationChanged(this, GetPosition());
+ }
+ break;
+ }
+ }
+ }
+
+ // free the memory we allocated for the native handles
+ Utils.LocalFree(handles);
+
+ if(newLocationHandle != IntPtr.Zero)
+ {
+ CloseHandle(newLocationHandle);
+ newLocationHandle = IntPtr.Zero;
+ }
+
+ if(deviceStateChangedHandle != IntPtr.Zero)
+ {
+ CloseHandle(deviceStateChangedHandle);
+ deviceStateChangedHandle = IntPtr.Zero;
+ }
+
+ if(stopHandle != IntPtr.Zero)
+ {
+ CloseHandle(stopHandle);
+ stopHandle = IntPtr.Zero;
+ }
+
+ // clear our gpsEventThread so that we can recreate this thread again
+ // if the events are hooked up again.
+ gpsEventThread = null;
+
+ Debug.WriteLine("gps device stopped...");
+ }
+ }
+
+ public double GetDistance(double p1Lat, double p1Lng, double p2Lat, double p2Lng)
+ {
+ double dLat1InRad = p1Lat * (Math.PI / 180);
+ double dLong1InRad = p1Lng * (Math.PI / 180);
+ double dLat2InRad = p2Lat * (Math.PI / 180);
+ double dLong2InRad = p2Lng * (Math.PI / 180);
+ double dLongitude = dLong2InRad - dLong1InRad;
+ double dLatitude = dLat2InRad - dLat1InRad;
+ double a = Math.Pow(Math.Sin(dLatitude / 2), 2) + Math.Cos(dLat1InRad) * Math.Cos(dLat2InRad) * Math.Pow(Math.Sin(dLongitude / 2), 2);
+ double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
+ double dDistance = EarthRadiusKm * c;
+ return dDistance;
+ }
+
+ ///
+ /// Radius of the Earth
+ ///
+ public double EarthRadiusKm = 6378.137; // WGS-84
+
+ #region PInvokes to gpsapi.dll
+ [DllImport("gpsapi.dll")]
+ static extern IntPtr GPSOpenDevice(IntPtr hNewLocationData, IntPtr hDeviceStateChange, string szDeviceName, int dwFlags);
+
+ [DllImport("gpsapi.dll")]
+ static extern int GPSCloseDevice(IntPtr hGPSDevice);
+
+ [DllImport("gpsapi.dll")]
+ static extern int GPSGetPosition(IntPtr hGPSDevice, IntPtr pGPSPosition, int dwMaximumAge, int dwFlags);
+
+ [DllImport("gpsapi.dll")]
+ static extern int GPSGetDeviceState(IntPtr pGPSDevice);
+ #endregion
+
+ #region PInvokes to coredll.dll
+ [DllImport("coredll.dll")]
+ static extern IntPtr CreateEvent(IntPtr lpEventAttributes, int bManualReset, int bInitialState, StringBuilder lpName);
+
+ [DllImport("coredll.dll")]
+ static extern int CloseHandle(IntPtr hObject);
+
+ const int waitFailed = -1;
+ [DllImport("coredll.dll")]
+ static extern int WaitForMultipleObjects(int nCount, IntPtr lpHandles, int fWaitAll, int dwMilliseconds);
+
+ const int eventSet = 3;
+ [DllImport("coredll.dll")]
+ static extern int EventModify(IntPtr hHandle, int dwFunc);
+
+ #endregion
+ }
+}