Using Microsoft Location api (locationapi.dll) in Delphi 5

Hi,

First post by a newbie, so please be gentle.

Tablet type notebooks (like the Microsoft Surface Pro) can contain an inbuilt GPSr and I believe access to it is via the Microsoft Location api

I am wanting to get the current location (latitude,longitude) from the GPSr using Delphi (V5) and believe my only option is via a Com object (Remember, I am using Delphi 5). I have very little experience using such objects so I am looking for the complete code to make this work. So I guess I am after the sample code of a small program that would do this.
Clyde24Asked:
Who is Participating?
 
Sinisa VukConnect With a Mentor Commented:
Strange. But if you cannot access to typelib here is created unit: LocationApiLib-TLB.pas

Example:
uses ..., LocationApiLib_TLB, ActiveX, Comobj;
...
function IsLocationAPIAvailable: Boolean;
var
  loc: ILocation;
begin
  Result := False;

  try
    loc := CreateComObject(CLASS_Location) as ILocation;
    Result := True;
  except
  end;

  loc := nil;
end;

function LocReportStatus(status: LOCATION_REPORT_STATUS): String;
begin
  Result := '';
  case status of
    REPORT_RUNNING:
      Result := 'Report received!';
    REPORT_NOT_SUPPORTED:
      Result := 'No devices detected!';
    REPORT_ERROR:
      Result := 'Report error!';
    REPORT_ACCESS_DENIED:
      Result := 'Access denied!';
    REPORT_INITIALIZING:
      Result := 'Report is initializing!';
  end;
end;

procedure TForm1.Button2Click(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
    loc := CreateComObject(CLASS_Location) as ILocation;
    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
        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);
                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;

procedure TForm1.Button3Click(Sender: TObject);
var
  loc: ILocation;
  rep: ILocationReport;
  CivRep: ICivicAddressReport;
  status: LOCATION_REPORT_STATUS;
  hres: HRESULT;
  sCity: WideString;
begin
  if IsLocationAPIAvailable then
  begin
    loc := CreateComObject(CLASS_Location) as ILocation;
    try
      status := REPORT_NOT_SUPPORTED;
      //have permission?
                                                                               // 0 for asynchronous calls
      if loc.RequestPermissions(_RemotableHandle(nil^), IID_ICivicAddressReport, 1, Integer(True))  = S_OK then
      begin
        hres := loc.GetReportStatus(IID_ICivicAddressReport, status);
        if hres = S_OK then
        begin
          if status = REPORT_RUNNING then //report is ok?
          begin
            hres := loc.GetReport(IID_ICivicAddressReport, rep);
            if (hres = S_OK) and (rep<>nil) then
            begin
              hres := rep.QueryInterface(IID_ICivicAddressReport, CivRep);
              if (hres = S_OK) and (CivRep<>nil) then
              begin
                sCity := '';
                CivRep.GetCity(sCity) ;
                Edit1.Text := sCity;
              end;
            end;
          end
          else
            ShowMessage(LocReportStatus(status));
        end
        else
          ShowMessage(IntToStr(Integer(hres)));
      end;
    finally
      CivRep := nil;
      rep := nil;
      loc := nil;
    end;
  end;
end;

initialization
  CoInitializeEx(nil, COINIT_APARTMENTTHREADED or COINIT_DISABLE_OLE1DDE);

finalization
  CoUninitialize;

Open in new window


on separate button I show procedure how to get Latitude and on another button how to get Address, City,...
Device (GPS?) should be available to get Latitude. It is recommended to wait for LatLongReport report until it is available.
0
 
Clyde24Author Commented:
..., Also my understanding is that this DLL is only available on Windows 7 and above. So I need corresponding error checking to make sure the code is only run on systems that have this DLL
0
 
Sinisa VukCommented:
Easiest way is to try load dll (LocationAPI.dll) like:

function IsLocationAPIAvailable: Boolean;
var
  hDllHandle: THandle;
begin
  Result := False;
  
  hDllHandle:=LoadLibrary('LocationAPI.dll');
  if hDllHandle<>0 then
  begin
    Result := True;
    FreeLibrary(hDllHandle);
  end;
end;

Open in new window


Another way is to try create instance of object but using exception handler:
function IsLocationAPIAvailable: Boolean;
var
  loc: ILocation;
begin
  Result := False;
  
  try
    loc := CreateOleObject(LocationApiIntf) as ILocation;
    Result := True;
  exception
  end;

  loc := nil;
end;

Open in new window

0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
Clyde24Author Commented:
The first  example works, but once loaded how do I actually use it to get the Latitude and longitude?

The second example wont compile as several undeclared identifiers - how do I declare them

Error screen shot
0
 
Sinisa VukCommented:
Using Import Type Library in Delphi import Location Api interface. Similar like here:
Installing the Microsoft SAPI speech SDK in Delphi. Add created unit LocationApiLib_TLB and ActiveX too.

Location api description:
http://msdn.microsoft.com/en-us/library/windows/desktop/dd317674%28v=vs.85%29.aspx

I will try to make simple example...

this way is upper function:
function IsLocationAPIAvailable: Boolean;
var
  loc: ILocation;
begin
  Result := False;
  
  try
    loc := CreateComObject(CLASS_Location) as ILocation;
    Result := True;
  except
  end;

  loc := nil;
end;

Open in new window

0
 
Clyde24Author Commented:
Using Import Type Library in Delphi import Location Api interface

But how do I do that. When I take the option "Project=>Import type library" there is no corresponding entry for the Microsoft Location Api

If I click on the "Add" button and select the LocationAPi.dll I get the following errorError dialog
0
 
Clyde24Author Commented:
Unfortunately I get the following compile errors:

compile error
I suspect this is because I am using Delphi5 (as specified in my question title). Probably the same reason why I didn't see the Location api when I tried to import the type library. Does this mean it is impossible to use the location api with Delphi5?. Unfortunately it is a legacy application written in Delphi 5 that I want to add this function to.

However, I do also have Delphi 10 and a quick mock up of your code appears to work - thanks.

So if it is impossible to use the location api in Delphi 5, then I guess the only way to move forward is to create a DLL in Delphi 10 with the required functions, and then use this DLL in Delphi5 to access those functions?
0
 
Sinisa VukCommented:
Yes, dll in D10 will be solution here. Think Delphi is a problem. Upper unit (LocationApiLib) is generated in D6 (so, not a big step in version).

Another thought: try to import some another typelib (maybe ms speech activex control) and see a way how is this unit generated against LocationApiLib. Look in uses too.
0
 
Clyde24Author Commented:
OK, one last question before I accept your answer. You say:

It is recommended to wait for LatLongReport report until it is available.

Does your code above already do this wait or is this something extra I need to add to the code. If so please show an example.

Thanks
0
 
Sinisa VukCommented:
Just simple request for state which must be: REPORT_RUNNING

function 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;
    Sleep(200);
  end;
end;

Open in new window


usage:
...
if loc.RequestPermissions(_RemotableHandle(nil^), IID_ILatLongReport, 1, Integer(True))  = S_OK then
begin
   if not WaitForReport(loc, IID_ILatLongReport) then Exit;
....

Open in new window

0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.