4

I want to create a WinForms app that can detect location just like a web browser would using the javascript function navigator.geolocation.getCurrentPosition(showPosition);

Is there some way to do this in WinForms directly?

I thought that I might be able to use the WebBrowser control to do this but I don't believe this supports Geolocation (unless someone knows otherwise?)

Apparently the Gecko browser does support gelocation but this is not an option for me because client may have a different firefox version installed.

Matt Wilko
  • 26,994
  • 10
  • 93
  • 143
  • Possible duplicate: http://stackoverflow.com/questions/5591457/get-ip-address-location-from-windows-application – Anthony May 23 '13 at 15:25
  • 1
    @Anthony - not exactly a duplicate because that question is geolocation lookup from IP only. A web browser can use other sensors to detect location e.g Wi-Fi signal and A-GPS if connected via a dongle – Matt Wilko May 23 '13 at 15:28
  • 1
    good point, leaving the link for other people's reference either way – Anthony May 23 '13 at 15:30

3 Answers3

2

Credit goes to the answer by Alex Filipovici given on this question: C# desktop application doesn't share my physical location

below is the code converted to VB:

WebServer Class:

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Net
Imports System.Text
Imports System.Threading

Public Class WebServer
    Private ReadOnly _listener As New HttpListener()
    Private Shared _staticContent As String

    Public Sub New(ByVal prefixes() As String, ByVal content As String)
        _staticContent = content
        For Each s As String In prefixes
            _listener.Prefixes.Add(s)
        Next s
        _listener.Start()
    End Sub

    Public Sub New(ByVal content As String, ByVal ParamArray prefixes() As String)
        Me.New(prefixes, content)
    End Sub

    Public Sub Run()
        ThreadPool.QueueUserWorkItem(Sub(o)
                                         Try
                                             Do While _listener.IsListening
                                                 ThreadPool.QueueUserWorkItem(Sub(c)
                                                                                  Dim ctx = TryCast(c, HttpListenerContext)
                                                                                  Try
                                                                                      Dim buf() As Byte = Encoding.UTF8.GetBytes(_staticContent)
                                                                                      ctx.Response.ContentLength64 = buf.Length
                                                                                      ctx.Response.OutputStream.Write(buf, 0, buf.Length)
                                                                                  Catch
                                                                                  Finally
                                                                                      ctx.Response.OutputStream.Close()
                                                                                  End Try
                                                                              End Sub, _listener.GetContext())
                                             Loop
                                         Catch
                                         End Try
                                     End Sub)
    End Sub

    Public Sub [Stop]()
        _listener.Stop()
        _listener.Close()
    End Sub

End Class

Form Code:

Imports System.Reflection
Imports System.Net
Imports System.Threading
Imports System.Text

Public Class Form1
    Dim _ws As WebServer
    Dim _webbrowser1 As WebBrowser

    Public Sub New()
        InitializeComponent()
        _webBrowser1 = New WebBrowser()
        _webBrowser1.Visible = False
        _webBrowser1.ScriptErrorsSuppressed = True
        Dim location = System.Reflection.Assembly.GetExecutingAssembly().Location
        _webBrowser1.Navigate(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) & "\test1.html")
        AddHandler _webBrowser1.DocumentCompleted, AddressOf webBrowser1_DocumentCompleted
    End Sub

    Async Sub webBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs)
        If _ws Is Nothing Then
            Dim html = _webBrowser1.Document.GetElementsByTagName("html")
            Dim response = html(0).OuterHtml
            _ws = New WebServer(response, "http://localhost:9999/")
            _ws.Run()
            _webBrowser1.Navigate("http://localhost:9999/")
        Else
            Dim latitude As String = ""
            Dim longitude As String = ""

            Await Task.Factory.StartNew(Sub()
                                            While String.IsNullOrEmpty(latitude)
                                                System.Threading.Thread.Sleep(1000)

                                                If Me.InvokeRequired Then
                                                    Me.Invoke(DirectCast(Sub()
                                                                             Dim latitudeEl = _webbrowser1.Document.GetElementById("latitude")
                                                                             Dim longitudeEl = _webbrowser1.Document.GetElementById("longitude")

                                                                             latitude = latitudeEl.GetAttribute("value")
                                                                             longitude = longitudeEl.GetAttribute("value")

                                                                         End Sub, MethodInvoker))
                                                End If
                                            End While

                                        End Sub)
            txtLocation.Text = String.Format("{0},{1}", latitude, longitude)
        End If
    End Sub
End Class

test1.html file

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <meta http-equiv="X-UA-Compatible" content="IE=10" />
    <script type="text/javascript">
        window.onload = function () {
            var latitude = document.getElementById("latitude");
            var longitude = document.getElementById("longitude");

            function getLocation() {
                if (navigator.geolocation) {
                    navigator.geolocation.getCurrentPosition(showPosition);
                }
                else { }
            }
            function showPosition(position) {
                latitude.value = position.coords.latitude;
                longitude.value = position.coords.longitude;
            }
            getLocation();
        }
    </script>
</head>
<body>
    <input type="hidden" id="latitude" />
    <input type="hidden" id="longitude" />
</body>
</html>
Community
  • 1
  • 1
Matt Wilko
  • 26,994
  • 10
  • 93
  • 143
1

You should use Geckofx

Also you need to ensure you exactly match the geckofx version with the correct xulrunner/firefox version.

GeoLocation doesn't yet have nice C# wrapper classes around it in geckofx, but you can access it using the xpcom C# interops.

    var instance = Xpcom.CreateInstance<nsIGeolocationProvider>("@mozilla.org/geolocation/provider;1");
hizbul25
  • 3,829
  • 4
  • 26
  • 39
  • thanks but I mentioned in my post that I cannot use this component as this is for a commercial product so I cannot dictate what version of xulrunner/firefox will be on any target machine. – Matt Wilko Jun 12 '13 at 16:46
  • You could bundle the needed version of xulrunner/firefox with your application. I do this with an application I work on, The needed files total around 20MB in size which can be compressed for the installer. – Tom Jun 23 '13 at 03:19
1

I haven't used it, but Microsoft has a Windows.Devices.Geolocation API, although it is for Windows 8.

For Windows 7, they seem to have a Sensor API, with some sample code here.

Jer
  • 391
  • 1
  • 5
  • Unfortunately the windows 7 sensor API only works when a sensor is installed and the only Sensor driver I can find is Geosense for Windows. This however seems to have been retired and I can't find a download that works. – Matt Wilko Jun 17 '13 at 10:32