Solved

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

Posted on 2013-10-28
10
1,140 Views
Last Modified: 2013-10-31
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.
0
Comment
Question by:Clyde24
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
10 Comments
 

Author Comment

by:Clyde24
ID: 39607597
..., 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
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39608501
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
 

Author Comment

by:Clyde24
ID: 39610183
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39610405
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
 

Author Comment

by:Clyde24
ID: 39610476
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
 
LVL 27

Accepted Solution

by:
Sinisa Vuk earned 500 total points
ID: 39611233
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
 

Author Comment

by:Clyde24
ID: 39613233
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
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39613451
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
 

Author Comment

by:Clyde24
ID: 39613498
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
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 39614309
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

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Are you ready to implement Active Directory best practices without reading 300+ pages? You're in luck. In this webinar hosted by Skyport Systems, you gain insight into Microsoft's latest comprehensive guide, with tips on the best and easiest way…
This video shows how to use Hyena, from SystemTools Software, to update 100 user accounts from an external text file. View in 1080p for best video quality.

734 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