//requesting departure time zone
TMSFNCTimeZone1.GetTimeZone(CoordRecD, DateD, '1252', mlmDefault,
procedure(const ARequest: TTMSFNCTimeZoneRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
//request departure time zone finished
//work with ARequest.Items to get the requested time zone for the departure time
//request arrival time zone
TMSFNCTimeZone1.GetTimeZone(CoordRecA, DateA, '1252', mlmDefault,
procedure(const ARequest: TTMSFNCTimeZoneRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
//request arrival time zone finished
//work with ARequest.Items to get the requested time zone for the arrival time
end
, '1', nil);
end
, '0', nil);
Your code works fine in a form containing FNCGoogleMap and TMSFNCTimeZone components. However, when I try to use this code in a utilities unit - so that I can get time offsets from various other units in my app - it doesn't work:
...
TMSFNCGoogleMaps1:= TTMSFNCGoogleMaps.Create(nil);
TMSFNCTimeZone1:= TTMSFNCTimeZone.Create(nil);
TMSFNCTimeZone1.Service:= tzsGoogle;
...
TMSFNCTimeZone1.GetTimeZone(CoordRecD, DateD, '1252', mlmDefault,
procedure (const ARequest: TTMSFNCTimeZoneRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
vcl.Dialogs.ShowMessage('Here');
GMTOffset:= StrToFloat(ARequest.Items[0].Offset); vcl.Dialogs.ShowMessage(ARequest.Items[0].Offset);
if (GMTOffset >= 0) then
Times[1]:= 1 //'+'
else
Times[1]:= 0; //'-';
Times[0]:= GMTOffset;
//request departure time zone finished
//request arrival time zone
TMSFNCTimeZone1.GetTimeZone(CoordRecA, DateA, '1252', mlmDefault,
procedure(const ARequest: TTMSFNCTimeZoneRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
GMTOffset:= StrToFloat(ARequest.Items[0].Offset);
if (GMTOffset >= 0) then
Times[3]:= 1 //'+'
else
Times[3]:= 0; //'-';
Times[2]:= GMTOffset;
end
, '1', nil); <--- There is no overloaded version of GetTimeZone that can be called with these args
end
, '0', nil); <--- There is no overloaded version of GetTimeZone that can be called with these args
Now both the FNCMaps form and this code compiles ok with these errors, and works on the form but not in the utility procedure - 'Here' is never seen. All the FNC units have been added to the utilities unit's Uses. Can you see what I'm doing wrong?
Ok, herewith a simplified sample project which illustrates the issue. No doubt I have forgotten something basic!
[Attachment removed because of API keys]
The reason for the code not running is because you are freeing the component before it has a chance to launch the request. Please note that the request that is being executed is asynchronous, which means that the result is retrieved in the callback, but the routine that has called the GetTimeZone will continue to execute. You cannot immediately return the value. You need to await the result:
function GetTimeZone(const Lat,Long: double ): double ;
var
TMSFNCGoogleMaps1: TTMSFNCGoogleMaps; //<???
TMSFNCTimeZone1: TTMSFNCTimeZone;
//TMSFNCTimeZoneRequest1: TTMSFNCTimeZoneRequest; //<???
CoordRec: TTMSFNCMapsCoordinateRec;
Time,GMTOffset: Double;
t: double;
begin
TMSFNCGoogleMaps1:= TTMSFNCGoogleMaps.Create(nil); //<???
TMSFNCTimeZone1:= TTMSFNCTimeZone.Create(nil);
TMSFNCTimeZone1.Service:= tzsGoogle;
TMSFNCGoogleMaps1.APIKey:= 'API KEY';
TMSFNCTimeZone1.APIKey:= 'API KEY';
Try
t:= 0;
CoordRec:= CreateCoordinate(Lat, Long);//vcl.Dialogs.ShowMessage(FloatToStr(CoordRecD.Latitude));
TMSFNCTimeZone1.GetTimeZone(CoordRec, now, '1252', mlmDefault,
procedure (const ARequest: TTMSFNCTimeZoneRequest; const ARequestResult: TTMSFNCCloudBaseRequestResult)
begin
//vcl.Dialogs.ShowMessage('Here');
if ARequest.Items.Count > 0 then
GMTOffset:= StrToFloat(ARequest.Items[0].Offset);
//vcl.Dialogs.ShowMessage(ARequest.Items[0].Offset);
Time:= GMTOffset;
//request departure time zone finished
t := Time;
end
, '0', nil);
Finally
while t = 0 do
begin
Application.ProcessMessages;
sleep(1);
end;
Result := t;
TMSFNCTimeZone1.Free;
TMSFNCGoogleMaps1.Free; //<???
End;
end;
As the book was published in August last year, the feature was not available yet. At least I have a nice visual in there how you can show the different time zones :-)
Indeed, I realised that. Yes, I saw that - very nice. A small comment: when you do include the feature, an example or two showing usage at runtime in the way discussed in this thread would be useful. I am learning a lot from the book though - thank you.
I'm getting a runtime error 216 at 0040AC72 when I close the form which calls function GetTimeZone in the Utilities unit - as discussed previously. The Finally section refers:
Finally
while t = 0 do
begin
Application.ProcessMessages;
sleep(1);
end;
Result := t;
TMSFNCTimeZone1.Free;
end;
If I comment out line: *TMSFNCTimeZone1.Free*;, there is no AV. It looks as though the TTMSFNCTimeZoneGoogleTimeZone.Destroy destructor in Unit VCL.TMSFNCTimeZone.Google is trying to destroy TMSFNCTimeZone1 which has already been freed as shown in the attached screenshot. Perhaps I don't need to free the component?
![TimeZoneAV|658x500](upload://lnexdEIXL5Mw7Jk6kifRqoDZqu2.png)
We have investigated this here and couldn't reproduce the issue, it could be possible that this is related to the maps instead of the timezone, can you verify? We have fixed an issue related to access violation in TTMSFNCMaps.
I don't think so. In one of my usage scenarios (discussed above), I don't display a map - simply the GMT offset times - and I have removed the Google Maps creation code and the AV still occurs. One point I haven't mentioned is that the AV only occurs when I run another unit in the app after running the 'GMT Offsets' function and before closing the app (which closes the form which called the 'GMT Offsets' function). It would appear that freeing TMSFNCTimeZone1 component also frees the TMSFNCTimeZoneGoogleTimeZone component which causes the AV later on?
Well, I've tried, but I can't reproduce the issue in a very basic sample. So it looks like a problem in my very large and complex app. I'll continue investigating and let you know if I find anything. Thanks for looking at this.
Cannot find the problem and the only way to stop the AV on app shutdown is to make the following changes to the previous example :
//TMSFNCTimeZone1:= TTMSFNCTimeZone.Create(nil)
TMSFNCTimeZone1:= TTMSFNCTimeZone.Create(application);
TMSFNCTimeZone1.Service:= tzsGoogle;
Try
.............
Finally
while t = 100000 do begin
Application.ProcessMessages;
sleep(1);
end;
Result := Times;
//TMSFNCTimeZone1.Free;
end;
and get the application to free the TMSFNCTimeZone component. Can you see a problem with this?