Solved

Using Microsoft Location api (locationapi.dll)

Posted on 2013-11-02
9
695 Views
Last Modified: 2013-11-06
I have written a routine to fetch the Latitude and Longitude from the inbuilt GPSr using the Microsoft LocationApi.dll

For more information see This question

I Personally don't have a computer with an inbuilt GPSr, but I have a user that has a Microsoft Surface Pro and he is testing for me.

He reports that the fetching of the lat/lon works OK the first time the program is run. If he clicks on the button a second time, the program does not do the fetch and it just loops in the WaitForReport function (the status value is always "REPORT_INITIALIZING") . It is like the code needs to release or cancel something before it can be successfully run again.

What needs to be added to the code so it can be run a second time without having to exit the program and start again.

FYI here is the tweaked WaitForReport function. It shows a message after every second of waiting. It is this message (status=3) that the user sees continually when trying to fetch the Lat/Lon a second time.

function Tform2.WaitForReport(loc: ILocation; reportType: TGUID): Boolean;
var
  status: LOCATION_REPORT_STATUS;
 begin
  Result := False;

  while (loc.GetReportStatus(reportType, status) = S_OK) do
  begin
    if status = REPORT_RUNNING then //report ready!
    begin
      Result := True;
      Exit;
    end;

    if status <> REPORT_INITIALIZING then //wait for report!
    begin
      //error occured
      Exit;
    end;
    application.ProcessMessages;
    Sleep(1000);
    showmessage('Waiting for locatin report to finish - Status = ' + inttostr(status));

  end;
end;

Open in new window


And here is the actual code for the get lat/lon button (originally had in the debug messages so the user could tell me how far the routine was getting)

procedure TForm2.Button1Click(Sender: TObject);
//type
 // PILocationReport = ^ILocationReport;
var
  loc: ILocation;
  rep: ILocationReport;
  LatLongRep: ILatLongReport;
  status: LOCATION_REPORT_STATUS;
  hres: HRESULT;
  fLat, fLon: double;
begin
  if IsLocationAPIAvailable then
  begin
//    showmessage('debug1');
    loc := CreateComObject(CLASS_Location) as ILocation;
    application.ProcessMessages;
//    showmessage('debug2');
    try
      status := REPORT_NOT_SUPPORTED;
      //have permission?
                                                                            // 0 for asynchronous calls
      if loc.RequestPermissions(_RemotableHandle(nil^), IID_ILatLongReport, 1, Integer(True))  = S_OK then
      begin
        application.ProcessMessages;
//        showmessage('debug3');
        if not WaitForReport(loc, IID_ILatLongReport) then
        begin
          showMessage(LocReportStatus(status));
          Exit;
        end;
//        showmessage('debug4');
        hres := loc.GetReportStatus(IID_ILatLongReport, status);
//        showmessage('debug5');
        if hres = S_OK then
        begin
//          showmessage('debug6');
          if status = REPORT_RUNNING then //report is ok?
          begin
//            showmessage('debug7');
            hres := loc.GetReport(IID_ILatLongReport, rep);
//            showmessage('debug8');
            if (hres = S_OK) and (rep<>nil) then
            begin
//              showmessage('debug9');
              hres := rep.QueryInterface(IID_ILatLongReport, LatLongRep);
//              showmessage('debug10');
              if (hres = S_OK) and (LatLongRep<>nil) then
              begin
                fLat := 0;
                fLon := 0;
                LatLongRep.GetLatitude(fLat);
                LatLongRep.GetLongitude(fLon);
                showmessage('Latitude: ' + FloatToStr(fLat) + chr(13) + chr(10) + 'Longitude: ' +  FloatToStr(fLon));
              //  Edit1.Text := FloatToStr(fLat);
              //  Edit2.Text := FloatToStr(fLon);
              end;
            end;
          end
          else
            ShowMessage(LocReportStatus(status));
        end
        else
          ShowMessage(IntToStr(Integer(hres)));
      end;
    finally
      LatLongRep := nil;
      rep := nil;
      loc := nil;
    end;
  end;
end;

Open in new window

0
Comment
Question by:Clyde24
  • 5
  • 4
9 Comments
 
LVL 25

Expert Comment

by:Sinisa Vuk
ID: 39620194
This is what I do (because I don't hw too):
- go to http://www.turboirc.com/gps7/ and get driver for gps on win7 and install it in simulation mode

- all is running first time as you said - then I change sync to async fetch request for report:

from:
if loc.RequestPermissions(_RemotableHandle(nil^), IID_ILatLongReport, 1, Integer(True))  = S_OK then

Open in new window


to:
if loc.RequestPermissions(_RemotableHandle(nil^), IID_ILatLongReport, 1, Integer(False))  = S_OK then

Open in new window


..this way goes all time
0
 

Author Comment

by:Clyde24
ID: 39620560
I don't really understand your answer. What exactly do you mean by this? Are you saying that the very first call should use sync, then after the first call we should use async. Or are you saying if you do have a sensor you should always use async, if you don't have a sensor you should always use sync.

One thing I will note that I found very strange. The user reported that the original code worked every time when the debug messages were shown. When I removed the debug messages, the code only worked the first time. Even after cancelling the program (via task manager and then restart) it would not work again. The user had to reboot the computer before the code would work again.  When the debug messages were shown it worked every time - why would this be?
0
 

Author Comment

by:Clyde24
ID: 39620591
OK, I installed the simulation driver and I now think I understand your answer, because I can now get it to work all the time using async.

What you are saying is that the code should *always* use async (your second block of code)

Basically the original code was using sync (which was wrong), where as it should have been using async all along?
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
ID: 39620859
Try to use async all time ... First time all worked fine because location engine load and took time - so next line - checking status will catch good value. Original work is based on "as is" couse I don't have hw as you do - later I decide do use simulator.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:Clyde24
ID: 39620936
The async call seems to work OK for me in the simulator. However, when I sent my test program to the user who has the Microsoft surface pro, he says it made no difference - it works the first time and then just hangs on the second attempt. He needs to reboot the computer to get it to work again.

The user reports that it always works when the debug messages are displayed (using both sync and async calls). This I just don't understand. Perhaps it is a timing issue and the display of the status messages stop the issue from happening.

How can we fix this. Is there some initialization step that can be run to reset the api?
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
ID: 39621170
Try this code (without waiting for status):

function GetLocationAPI: ILocation;
begin
  Result := nil;
  
  try
    Result := CreateComObject(CLASS_Location) as ILocation;
  except
  end;
end;

....
var
  loc: ILocation;
  rep: ILocationReport;
  LatLongRep: ILatLongReport;
  status: LOCATION_REPORT_STATUS;
  hres: HRESULT;
  fLat, fLon: double;
begin
  loc := GetLocationAPI; //GetLocationAPIClass;
  if loc<>nil then
  begin
    application.ProcessMessages;
    try
      status := REPORT_NOT_SUPPORTED;
      //have permission?
      hres := loc.RequestPermissions(_RemotableHandle(nil^), IID_ILatLongReport, 1, Integer(False));
      if hres = S_OK then
      begin
        application.ProcessMessages;

        hres := loc.GetReportStatus(IID_ILatLongReport, status);
        if hres = S_OK then
        begin
          if status = REPORT_RUNNING then //report is ok?
          begin
            hres := loc.GetReport(IID_ILatLongReport, rep);
            if (hres = S_OK) and (rep<>nil) then
            begin
              hres := rep.QueryInterface(IID_ILatLongReport, LatLongRep);
              if (hres = S_OK) and (LatLongRep<>nil) then
              begin
                fLat := 0;
                fLon := 0;
                LatLongRep.GetLatitude(fLat);
                LatLongRep.GetLongitude(fLon);
                showmessage('Latitude: ' + FloatToStr(fLat) + chr(13) + chr(10) + 'Longitude: ' +  FloatToStr(fLon));
              end;
            end;
          end
          else
            ShowMessage(LocReportStatus(status));
        end
        else
          ShowMessage(IntToStr(Integer(hres)));
      end
      else
        ShowMessage(IntToStr(Integer(hres)));
    finally
      LatLongRep := nil;
      rep := nil;
      loc := nil;
    end;
  end;

Open in new window


There is some issue with waiting and request for permission ... Without real hw it is hard to detect real problem. These example is compatible with MS Location Api example.
0
 

Author Comment

by:Clyde24
ID: 39623724
... Update

The code given still only works the first time. After the first time the user always gets the message "Report is initializing!"

In desperation I tried a modification to the finally block - basically I removed (commented out)  the := nil statements. so from
    finally
      LatLongRep := nil;
      rep := nil;
      loc := nil;
    end;

Open in new window

To
    finally
      //LatLongRep := nil;
      //rep := nil;
      //loc := nil;
    end;

Open in new window

This worked every time!

So it looks like it has something to do with the objects being set to nil. I don't like this code as I believe it would create a memory leak.  However, as "loc" is really the only object being created, I have made another test for the user with:

finally
      //LatLongRep := nil;
      //rep := nil;
      loc := nil;
end;

Open in new window


I will report back my findings after the user has tested.
0
 
LVL 25

Accepted Solution

by:
Sinisa Vuk earned 500 total points
ID: 39623819
instead of loc: ILocation try to define loc: TLocation.
Then you go with....
...
loc := TLocation.Create(nil);
....

Open in new window


replace all ILocation with TLocation and replace loc:=nil with loc.Free.
0
 

Author Comment

by:Clyde24
ID: 39629228
Thanks. My test user reports that this seems to be working.
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now