Transmission delay in delphi [closed] - delphi

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I developed application that transfer bytes via virtual serial port using Delphi 6 and asyncfree
I need to delay transfer after 10 bytes to synchronize transmission. I use windows.sleep(1).
The application works very well when I run it from Delphi IDE. When I close Delphi and run application from exe ... the application becomes slow.
What is the reason?

The Delphi IDE obviously sets the system timer tick to a higher resolution. You can do the same in your application by using timeBeginPeriod/timeEndPeriod functions. See msdn document and also this one regarding sleep function
uses MMSystem;
if TimeBeginPeriod(1) = TIMERR_NOERROR then // 1 ms resolution
try
// The action or process needing higher resolution
finally
TimeEndPeriod(1);
end;
Just to demonstrate the effect I made following simple application, so anybody interested can check for themselves:
uses System.DateUtils, MMSystem;
var
s, e: TTime;
procedure SomeDelay;
var
i: integer;
begin
s := Now;
for i := 1 to 1000 do
Sleep(1);
e := Now;
end;
procedure TForm19.btnWithClick(Sender: TObject);
begin
if TimeBeginPeriod(1) = TIMERR_NOERROR then // 1 ms resolution
try
SomeDelay; // The action or process needing higher resolution
finally
TimeEndPeriod(1);
end;
Memo1.Lines.Add('with ' + IntToStr(SecondsBetween(s, e)));
end;
procedure TForm19.btnWithoutClick(Sender: TObject);
begin
SomeDelay; // The action or process needing higher resolution
Memo1.Lines.Add('without ' + IntToStr(SecondsBetween(s, e)));
end;
Output:
with 1
without 15
NOTE Because the TimeBeginPeriod affects the system tick, be sure to shut down any program that may us the same method to modify the timer tick, like multimedia and similar programs (and also the Delphi IDE).

Related

EnumerateWindows works in Delphi 7 but not in Delphi 10.3

I have a problem after upgrading Delphi.
I have this code:
function EnumerateWindows(hWnd: HWND; lparam:LPARAM):Bool;
var
ClassName, TheText : Array [0..255] of char;
sName : string;
begin
Application.ProcessMessages;
GetClassNAme(hWnd,Classname, 255);
if GetWindowText(hWnd, TheText, 255) > 0 then
begin
sName := StrPas(TheText);
if pos('NOTEPAD',UpperCase(sName)) > 0 then
postMessage(FindWindow(ClassName, TheText), WM_CLOSE, 0, 0);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
EnumWindows(#EnumerateWindows,0);
end;
In Delphi 7 the code above is working perfectly anytime there is NOTEPAD title and the program will kill its process but when I tried to use Selphi 10.3 the code above is not working. When i open Notepad it does not kill the process (there is no error in compiler).
Is there any way to make the code work in Delphi 10.3?
i finally managed to fix it...
when i added this
Result := True;
after if condition the code is working.
You have to either use
the types AnsiChar and AnsiString or
the functions GetClassNameW(), GetWindowTextW(), StrPasW() and FindWindowW()
...because Delphi 7 uses by default ANSI and Delphi 10 by default WIDE. You could also use Unicode in Delphi 7 right away by using all the WIDE functions and the types WideChar and WideString. Edit: the previous text is wrong as per Remy's comment.
Furthermore no process is killed: WM_CLOSE merely requests a window to be closed - there is neither a guarantee that the process really closes that window (i.e. for Notepad it can still result in a question dialog if you want to save your edits or not), nor that the process would end after closing that window - processes can run without windows. To kill a process you have to use TerminateProcess().

refresh google map every x minutes in webbrowser in xe5 [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i am develop a small mobile application in XE5 using delphi, i will show the current location in google map in webbrowser. the problem is how to refresh the google map every x minutes in webbrowser. the default refresh time is 20 second. thanks.
Use TTimer to refresh.
You can change the X minutes in the property Interval.
procedure TForm1.FormCreate(Sender: TObject);
begin
self.WebBrowser1.Navigate('www.embarcadero.com');
self.Timer1.Interval:= 10000;
self.Timer1.Enabled:= True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
self.WebBrowser1.Refresh;
end;
# Tom Brunberg
I use the Locationsensor LocationChange to display the google map in WebBrowser,below is the code:
procedure TTabbedForm.LocationSensor1LocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
begin
ListBoxItem3.Text := 'Latitude: ' + NewLocation.Latitude.ToString;
ListBoxItem2.Text := 'Longitude: ' + NewLocation.Longitude.ToString;
Locationsensor1.Distance:=200;
{ and track the location via Google Maps }
WebBrowser1.Navigate(Format(LGoogleMapsURL, [NewLocation.Latitude.ToString, NewLocation.Longitude.ToString]));
// Timer1.Interval:=50000;
// Timer1.Enabled:=true;
ClientModule1.ServerMethods19Client.insertParcelLocation(EDIT4.Text,now,NewLocation.Longitude,NewLocation.Latitude);
i want to refresh the google map in webBrowser every 5 minutes.Thus, i use the TTimer. but i do not know where to raise Timer event? the code below is i try to raise the timer event in webBrowser, but it did not work!
procedure TTabbedForm.Timer1Timer(Sender: TObject);
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
begin
WebBrowser1.Navigate(Format(LGoogleMapsURL,[Locationsensor1.Sensor.Latitude.ToString,LocationSensor1.Sensor.Longitude.ToString ]));
Timer1.Interval:=50000;
Timer1.Enabled:=true;
end;
Presumably you are navigating with something like
WebBrowser1.Navigate('https://www.google.com/maps/#<latitude>,<longitude>,<zoom>z');
and you want to update the map because the location has changed.
In this case there's no point in calling something like refresh (on TWebBrowser for Windows, or similar on TWebBrowser for mobile), since that would just use the same coordinates as before.
Instead, at the timer event, get your updated location and then simply navigate as above with the new coordinates.
Edit after new info
Right now I can not verify with a real LocationSensor so I assume that the LocationSensor and the request for the initial map works in the OnLocationChanged event. Note also that depending on installed technology in your device, the location sensor may need quite some time to be ready to report location changes.
You attempt to initialize (set interval and enable) the timer in the OnLocationChanged event, (except that now those lines are outcommented). Thus starting the timer depends of course on this event to fire. If you have verified that the OnLocationChanged event fires then this is OK, just take away the comment markers.
However, if initially, the OnLocationChanged event doesn't fire, then you need to start the timer somewhere else. When you drop a TTimer on a form, it is by default enabled and has an interval of 1000 ms. So you could just change the interval to 5 minutes (300 000 ms) at design time and the timer will start at program startup.
On the other hand, you may want to show the (or a) google map immediately in which case you could use the OnShow event of the form, using a previously saved (or default) location until the LocationSensor starts to report location changes.
// Instead of having this constant in several procedures,
// place it for example in the private section of your form
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
var
SavedLocation: TLocationCoord2D;
....
procedure TTabbedForm.FormShow(Sender: TObject);
begin
// using a previously saved location
WebBrowser1.Navigate(Format(LGoogleMapsURL,
[SavedLocation.Latitude.ToString, SavedLocation.Longitude.ToString]));
// remove these lines if timer is enabled at design time
Timer1.Interval := 300000;
Timer1.Enabled := true;
end;
You don't need to repeatedly set the timer interval and enabled properties in the OnTimer event
procedure TTabbedForm.Timer1Timer(Sender: TObject);
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
begin
WebBrowser1.Navigate(Format(LGoogleMapsURL,[Locationsensor1.Sensor.Latitude.ToString,LocationSensor1.Sensor.Longitude.ToString ]));
// you can remove these two lines
// Timer1.Interval:=50000;
// Timer1.Enabled:=true;
end;
If this doesn't answer your question, you need to be more specific in how you want it to work and what precisly is not as you want.
Edit 2
Next time you really need to describe all aspects of your problem.
The OnLocationChanged event is an event of LocationSensor1. The easiest way to get rid of it is to remove from LocationSesnor1LocationChanged any const and var declaration as well as the code between begin and end. Then just do a build and the IDE will remove all traces of it.

Delphi XE3 - performance issue with TDataSet

Data processing with XE3 programs take up to 10 times more than with same programs compiled with XE2. This is known issue (probably refers mainly to TStringField), reported to QC 111942, but it is not fixed yet. Does anybody have a fix / workaround for this issue?
TIA Branko
Same in XE5. Plus extra traffic and all this client-server thing require >5 Mbit per second (!) to work normally. I am using only TFDConnection and TFDQuery. Specially for MySQL the speed is the same with Delphi components and with third-party driver (libmysql.dll). If you have no FireDAC you can replace TFDQuery with TSQLQuery. Here is a procedure how to fill a string grid:
procedure SelGrid(sql:ansiString;Q:TFDQuery;grid:TStringGrid);
var i: integer;
begin
Q.Close;
Q.SQL.Text:='';
Q.Open(sql);
grid.ColCount:=Q.FieldCount;
grid.RowCount:=1;
while not Q.Eof do begin
for i := 0 to grid.ColCount-1 do grid.Cells[i,grid.RowCount-1]:=Q.Fields.Fields[i].AsString;
grid.RowCount:=grid.RowCount+1;
Q.Next;
end;
Q.Close;
if grid.RowCount>1 then grid.RowCount:=grid.RowCount-1;
grid.Row:=0;
//AutoSizeGridColumns(grid,30,200);
end;
This is VCL string grid. Of course you muse deal with updates and so on, but you'll have no more performance problems.

Get web page in Delphi [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicates:
Downloading a file in Delphi
Delphi File Downloader Component
Hello everyone,
I'm trying to develop a Delphi 7 app which would serve as a currency database or something close to it (don't ask me why, I'm doing it just for money:) ). So current task is to download a web page containing currency list from a server and extract this list to the database.
Is it possible and what tools should one need to accimplish it? I know php, but writing php gui seems something crazy)
To add to Andreas comments, you can also check out Delphi.About.com, there is an example there to download a file and show a progressbar: http://delphi.about.com/cs/adptips2003/a/bltip0903_2.htm
"If you need to save the contents of a specified URL to a file - and be able to track the download progress, use the TDownLoadURL Delphi action
While TDownLoadURL is writing to the specified file, it periodically generates an OnDownloadProgress event, so that you can provide users with feedback about the process.
Here's an example - note that you must include the unit ExtActns in the uses clause."
uses ExtActns, ...
type
TfrMain = class(TForm)
...
private
procedure URL_OnDownloadProgress
(Sender: TDownLoadURL;
Progress, ProgressMax: Cardinal;
StatusCode: TURLDownloadStatus;
StatusText: String; var Cancel: Boolean) ;
...
implementation
...
procedure TfrMain.URL_OnDownloadProgress;
begin
ProgressBar1.Max:= ProgressMax;
ProgressBar1.Position:= Progress;
end;
function DoDownload;
begin
with TDownloadURL.Create(self) do
try
URL:='http://0.tqn.com/6/g/delphi/b/index.xml';
FileName := 'c:\ADPHealines.xml';
OnDownloadProgress := URL_OnDownloadProgress;
ExecuteTarget(nil) ;
finally
Free;
end;
end;

Delphi SAPI Text-To-Speech

First of all: this is not a duplicate of Delphi and SAPI. I have a specific problem with the "SAPI in Delphi" subject.
I have used the excellent Import Type-Library guide in Delphi 2009 to get a TSpVoice component in the component palette. This works great. With
var
SpVoice: TSpVoice;
I can write
SpVoice.Speak('This is an example.', 1);
to get asynchronous audio output.
First question
According to the documentation, I would be able to write
SpVoice.Speak('This is an example.', 0);
to get synchronous audio output, but instead I get an EZeroDivide exception. Why's that?
Second question
But more importantly, I would like to be able to create the SpVoice object dynamically (I think this is called to "late-bind" the SpVoice object), partly because only a very small fraction of all sessions of my app will use it, and partly because I do not want to assume the existance of the SAPI server on the end-user's system.
To this end, I tried
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: Variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('this is a test', 0);
end;
which apparently does nothing at all! (Replacing the 0 with 1 gives me the EZeroDivide exception.)
Disclaimer
I am rather new to COM/OLE automation. I am sorry for any ignorance or stupidity shown by me in this post...
Update
For the benefit of everyone encountering the same problem as I did, the video by François explained there is a bug in SAPI/Windows (some incompatibility somewhere), which makes the following code raise the EZeroDivide exception:
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: variant;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SpVoice.Speak('This is a text.');
end;
The solution, as presented by the video, is to alter the FPU control word:
procedure TForm1.FormClick(Sender: TObject);
var
SpVoice: variant;
SavedCW: Word;
begin
SpVoice := CreateOleObject('SAPI.SpVoice');
SavedCW := Get8087CW;
Set8087CW(SavedCW or $4);
SpVoice.Speak('This is a text.');
Set8087CW(SavedCW);
end;
And, in addition, if you want to play a sound asynchronously, then you have to make sure that the player doesn't go out of scope!
You may find interesting to see this CodeRage 4 session on "Speech Enabling Delphi Applications (zip)"
You'll get the "how-to" you're looking for...
(and I guess you are on Vista or + as the the zero divide did not happend on XP)
I was having the same problem in Delphi XE2. The Set8087CW(SavedCW or $4) solution presented in the question did not work for me. It merely replaced the division by zero exception with another floating point exception.
What did work for me is this:
SavedCW := Get8087CW;
SetFPUExceptionMask([exInvalidOp, exDenormalized, exZeroDivide, exOverflow, exUnderflow, exPrecision]);
SpVoice.Speak('All floating point exceptions disabled!', 0);
Set8087CW(SavedCW);

Resources