IUfMessung = interface
['{6C258E04-BCC9-4349-912B-57A38F103570}']
function MacheMessung(Ifl,Ufl: double): double;
end;
TUFMessungMitHalten = class(TInterfacedObject,IUfMessung)
private
SWZeitHalten: double;
public
constructor Create(ASWZeitHalten: double); // Time to keep
destructor Destroy; override;
function MacheMessung(Ifl,Ufl: double): double; // do measuring
end; // measuring with holding
TUFMessungMitPause = class(TInterfacedObject,IUfMessung)
private
SWZeitPause: double;
IfMin: double;
public
constructor Create(ASWZeitPause: double; AIfMin: double); // Time to keep + I[A]
destructor Destroy; override;
function MacheMessung(Ifl,Ufl: double): double;
end; // measuring with Pause
TUFMessung = class(TInterfacedObject)
private
//...
Messungsart: IUfMessung;
public
procedure SetMessungsart(art: IUfMessung); // set measuring type
procedure MessungsArtAswahl; // measuring type choice
//...
end; // do measuring
{ TUFMessung }
procedure TUFMessung.MessungsArtAswahl;
begin
if not FMitHalten and not FMitPause then // Uf simple measuring
begin
SetMessungsart(TUFMessungEinfach.Create);
end;
if FMitHalten and not FMitPause then // Uf with holding
begin
SetMessungsart(TUFMessungMitHalten.Create(FSWZeitHalten));
end;
if not FMitHalten and FMitPause then // Uf with pause
begin
SetMessungsart(TUFMessungMitPause.Create(FSWZeitPause, FStartIf));
end;
end;
procedure TUFMessung.Start(StartIf, EndIf, StepIf, Uleer: double);
begin
//...
while not FIstFertig and FUfKannStart do
begin
Uf:= Messungsart.MacheMessung(Ifl, FUleer); // <= CALL the measuring
//...
end;
end;
{ TUFMessungMitHalten }
function TUFMessungMitHalten.MacheMessung(Ifl, Ufl: double): double;
var i_Zeit: integer;
begin // Messvorgang
hole_Uf(true, Ifl, Ufl); // set value
i_Zeit:= Trunc(SWZeitHalten*1000);
Application.ProcessMessages;
Sleep(i_Zeit); // wait Time ms.
result:= hole_Uf(false, Ifl, Ufl); // measuring
end;
{ TUFMessungMitPause }
function TUFMessungMitPause.MacheMessung(Ifl, Ufl: double): double;
var i_Zeit: integer;
begin // Messvorgang
result:= hole_Uf(false, Ifl, Ufl); // measuring
hole_Uf(true, IfMin, Ufl); // set value
i_Zeit:= Trunc(SWZeitPause*1000);
Application.ProcessMessages;
Sleep(i_Zeit); // wait Time ms.
end;
I need to wait between the measuring processes for a time from 0 to 5 seconds. The solution with sleep () works well only till 1 second because I have in the program an RS232 communication and some timers.
Is there an alternative to sleep () function so that the program precisely at this point a certain time is waiting for? Thank you in advance.
I can't tell from your source, but if you're combining RS232 and waiting, Sleep sounds like a bad idea. The best you could do is have the system respond to you as soon as data comes in, not blindly wait for it. Depending on what you use to do RS232 communication, you should look for something like SetCommTimeouts and fine-tune how read operations behave: if the data is not in yet, stall for the receive timeout, and after that respond that zero bytes were received. This is best done from a dedicated thread (which might take a little learning to get a hang of). Another option is using asynchronous calls (which also take a little learning to get a hang of).
As David says, there may be more elegant solutions for an ideal world, or if you are willing to get your hands dirty with low level device I/O and threading. But until you have perhaps identified a more elegant solution, another approach would be to create your own time-out loop (a so called "busy loop") around Application.ProcessMessages to incorporate a "time-out" behaviour to return control to the caller after a specified time, processing messages in the meantime.
This might look something similar to this:
procedure ProcessMessagesFor(aTimeOut: Integer);
var
start: Int64;
elapsed: Integer;
begin
start := Trunc(Now * 24 * 60 * 60 * 1000);
elapsed := 0;
while elapsed < aTimeout do
begin
Application.ProcessMessages;
elapsed := Trunc(Now * 24 * 60 * 60 * 1000) - start;
end;
end;
This is also less than ideal however since Application.ProcessMessages will itself not return until any and all messages have been processed. It would be better to check for the elapsed timeout after each message so that we can get back into the normal message loop as soon as possible.
Application.ProcessMessages simply calls a ProcessMessage function, but this is private to the TApplication class, so we cannot call this directly.
Fortunately, in Delphi 7, the ProcessMessage function is itself relatively simple and can be easily replicated within the timeout loop of a custom message processor.
Note that to do this we need to change a couple of private references (fOnMessage event handler for example) to the public equivalents and a handful of TApplication protected methods are involved which we obtain access to using a local sub-class and type-casting (a primitive pre-cursor to "class helpers" but which works in all versions of Delphi):
type
// Creates a sub-class in scope which we can use in a typecast
// to gain access to protected members of the target superclass
TApplicationHelper = class(TApplication);
procedure ProcessMessagesFor(aTimeOut: Integer);
var
start: Int64;
elapsed: Integer;
wait: Boolean;
function ProcessMessage: Boolean;
var
msg: TMsg;
handled: Boolean;
app: TApplicationHelper;
begin
app := TApplicationHelper(Application);
result := False;
if PeekMessage(msg, 0, 0, 0, PM_REMOVE) then
begin
result := True;
if msg.Message <> WM_QUIT then
begin
handled := False;
if Assigned(Application.OnMessage) then
Application.OnMessage(msg, handled);
if not app.IsHintMsg(msg)
and not handled
and not app.IsMDIMsg(msg)
and not app.IsKeyMsg(msg)
and not app.IsDlgMsg(msg) then
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end
else
PostQuitMessage(msg.wParam);
end;
end;
begin
wait := FALSE; // We will not wait for messages initially
start := Trunc(Now * 24 * 60 * 60 * 1000);
SetTimer(0, 0, aTimeout, NIL); // Makes sure we get a message (WM_TIMER) at the end of the timeout period
repeat
if wait then
WaitMessage;
wait := NOT ProcessMessage; // If there was no message then we will wait for one next time around
elapsed := Trunc(Now * 24 * 60 * 60 * 1000) - start;
until (elapsed >= aTimeout);
end;
I have used a crude multiplier and truncation of a Now date/time to obtain a millisecond precision elapsed time counter without having to deal with the wrap around (potential) issue with GetTickCount. You may want to modify this to use a HPC or simply deal with the GetTickCount wrap-around.
We incorporate a WaitMessage mechanism so that if there are no messages to be processed then the code simply waits (efficiently) for any new messages. To ensure that we are not waiting for messages beyond the timeout period, we initially set a timer event for the specified timeout. This guarantees that a WM_TIMER message will arrive to signal the expiry of the timeout, which will "wake up" our message loop if it is still waiting when the timeout has expired.
Another thing to note is that WM_QUIT messages are re-posted to the message queue. This is to ensure that these will be handled correctly when the ProcessMessagesFor() loop has timed out and messages are once again being handled by the main application message loop.
This function does not (strictly speaking) call Application.ProcessMessages, nor does it involve Sleep(), but it is still not an ideal solution being vulnerable to (potential) re-entrancy problems that having "inline" message loops always creates. These can be managed by controlling user interaction with parts of the UI that might cause such re-entrancy problems (i.e. disable forms or controls while processing is completed).
But even without such refinements it may keep you going with your current problem unless and until a more ideal solution is found.
Create you own sleep function:
procedure MySleep (const uSec: UInt);
var uStart : UInt;
begin
uStart := GetTickCount;
while (GetTickCount < (uStart + (uSec * 1000))) do
begin
Sleep (250);
Application.ProcessMessages;
end
end;
Related
I'm trying to use generics to 'genericize' a var that instantiates network transports of different types. I'm not sure if the "generic=no RTTI" rule would invalidate the approach or not, as I'm not yet up to speed with generics.
I've read this post:
What is the correct way to structure this generic object creation , which states the following in the question:
One other thing I would like to do if possible, is to change two
creations:
LAdapter := TSQLiteNativeConnectionAdapter.Create(LFilename)
LAdapter := TFireDacConnectionAdapter.Create(FDatabaseLink.FConnection as TFDConnection, FDatabaseLink.OwnedComponent)
to use an abstract "GetAdapterClass" type function in the parent
TModelDatabaseConnection and just declare the class of adapter in the
child to do something like:
LAdapter := GetAdapterClass.Create...
This is exactly what I would like to do as well. So if you can picture this:
type
TTransport<T> = class(TComponent)
private
...
function GetTransport: TTransport;
procedure SetTransport(AValue: TTransport);
...
public
...
property Transport: TTransport read GetTransport write SetTransport;
...
end;
TTCPIPTransport = class(TTransport<T>)
private
function GetSocket(Index: Integer): String;
procedure SetSocket(Index: Integer; AValue: String);
public
property Socket[Index: Integer]: String read GetSocket write SetSocket;
end;
TServiceTransport = class(TTransport<T>)
private
function GetServiceName: String;
procedure SetServiceName(AValue: String);
public
property ServiceName: String read GetServiceName write SetServiceName;
end;
TISAPITransport = class(TServiceTransport<T>);
THTTPSysTransport = class(TServiceTransport<T>)
private
function GetURL(Index: Integer): String;
procedure SetURL(Index: Integer; AValue: String);
public
property URL[Index: Integer]: read GetURL write SetURL;
end;
etc.
The idea is to create a base class that has all fields/properties/methods that are common to all transports, then have intermediate classes that contain fields/methods/properties that are common only to a certain subset of transports, then have the final version of each transport be specific to the type.
So when I call:
var
trans: TTransport<T> // or TTransport<TTCPIPTransport> etc.
begin
trans := TTransport<TTCPIPTransport>.Create(AOwner,....);
trans.Transport.Socket[0] := '127.0.0.1:8523';
OR
trans := TTransport<TISAPITransport>.Create(AOwner,...);
trans.Transport.ServiceName = 'Foo';
...
etc.
end;
or perhaps even more generic then that, but have each instance of trans - without typecasting - have properties/fields/methods that are specific to the subclass automagically show up.
This way I can have a config screen that allows an administrator to select the type of transport say in a combo box, the have that variable value set the type inside the <> in code, and one set of code handles creation of the object by it's type.
Is this possible using generics?
Here is my first (feeble) attempt at a class factory, never done this before. It works partially (generates the correct class) but isn't accessible as a distinct subclass of the base class without typecasting, which defeats the purpose. Please see inline comments
TWSTransport = class(TComponent)
...
public
constructor Create(AOwner: TComponent); virtual;
....
end;
TWSTransportClass = Class of TWSTransport;
TWSTCPIPTransportClass = class of TWSTCPIPTransport;
TWSHTTPSysTransport = class(TWSServiceTransport);
TWSServiceTransport = class(TWSTransport);
TWSTransportStringConversion = class(TWSTransport);
TWSTransportStreamFormat = class(TWSTransportStringConversion);
TTransportFactory = class(TClassList)
private
function GetTransport(Index: TWSTransportClass; AOwner: TkbmMWServer): TWSTransportClass;
public
procedure RegisterTransportClass(ATransportClass: TWSTransportClass);
property Transport[Index: TWSTransportClass; AOwner: TkbmMWServer]: TWSTransportClass read GetTransport;
end;
function TTransportFactory.GetTransport(Index: TWSTransportClass; AOwner: TkbmMWServer): TWSTransportClass;
begin
if IndexOf(Index) > -1 then
Result := TWSTransportClass(Items[IndexOf(Index)])
else
Result := TWSTransportClass(Index.Create(AOwner));
end;
procedure TTransportFactory.RegisterTransportClass(ATransportClass: TWSTransportClass);
var
index: Integer;
begin
// is the transport registered?
index := IndexOf(ATransportClass);
if index < 0 then
// the transport is not registered, add it to the list
Add(ATransportClass);
end;
initialization
factory := TTransportFactory.Create;
factory.RegisterTransportClass(TWSHTTPSysTransport);
factory.RegisterTransportClass(TWSISAPIRESTTransport);
factory.RegisterTransportClass(TWSTCPIPTransport);
finalization
FreeAndNil(factory);
end.
Here's how I tested it:
procedure TForm4.FormCreate(Sender: TObject);
var
//trans: TWSTCPIPTransport; // this doesn't work
trans: TWSTransport; // this works
begin
trans := factory.Transport[TWSTCPIPTransport,Self];
showmessage(trans.classname); // this shows the correct classname - TWSTCPIPTransport
trans.AddSocket('127.0.0.1:80'); // the compiler gives an error here because this call is specific to a subclass of TWSTransport, TWSTCPIPTransport.
end;
So I'm still missing something... anyone see the mistake?
I'm struggling with some anonymous methods in Delphi.
When a call the Execute method and the timer created inside that method timeout, it throws a "privileged instruction" exception.
Is that because my anonymous function go out of scope?
unit OneShotTimerReloaded;
interface
uses
System.SysUtils, System.Classes;
type
IOneShotTimerReloaded = interface
['{51DE72F0-4784-4CEB-A065-0B64D6EEA626}']
procedure Execute(Proc: TProc; TimeOut: Cardinal = 1000); overload;
procedure Execute(Proc: TProcedure; TimeOut: Cardinal = 1000); overload;
procedure Execute(Event: TNotifyEvent; TimeOut: Cardinal = 1000; Sender: TObject = nil); overload;
end;
TOneShotTimerReloaded = class(TInterfacedObject, IOneShotTimerReloaded)
public
procedure Execute(Proc: TProc; TimeOut: Cardinal = 1000); overload;
procedure Execute(Proc: TProcedure; TimeOut: Cardinal = 1000); overload;
procedure Execute(Event: TNotifyEvent; TimeOut: Cardinal = 1000; Sender: TObject = nil); overload;
end;
implementation
uses
Winapi.Windows;
{ TOneShotTimerReloaded }
procedure TOneShotTimerReloaded.Execute(Proc: TProc; TimeOut: Cardinal);
var
TimerID: UIntPtr;
begin
TimerID := SetTimer(HWND(0), 0, TimeOut, #procedure
begin
if (Assigned(Proc)) then
Proc;
KillTimer(HWND(0), TimerID);
end
);
end;
procedure TOneShotTimerReloaded.Execute(Proc: TProcedure; TimeOut: Cardinal);
var
TimerID: UIntPtr;
begin
TimerID := SetTimer(HWND(0), 0, TimeOut, #procedure
begin
if (Assigned(Proc)) then
Proc;
KillTimer(HWND(0), TimerID);
end
);
end;
procedure TOneShotTimerReloaded.Execute(Event: TNotifyEvent; TimeOut: Cardinal; Sender: TObject);
var
TimerID: UIntPtr;
begin
TimerID := SetTimer(HWND(0), 0, TimeOut, #procedure
begin
if (Assigned(Event)) then
Event(Sender);
KillTimer(HWND(0), TimerID);
end
);
end;
end.
The way I'm currently using this class is:
procedure TForm1.FormCreate(Sender: TObject);
var
t1: TOneShotTimerReloaded;
t2: TOneShotTimerReloaded;
begin
t1 := TOneShotTimerReloaded.Create;
t2 := TOneShotTimerReloaded.Create;
t1.Execute(btn1Click, 5000, btn1);
t2.Execute(procedure begin ShowMessage('Anonymous'); end, 2000);
// Not worried with t1 and t2 memory leaks yet!!! ;)
end;
Any ideas or suggestions are appreciated. Thanks!
You cannot use an anonymous procedure for a Win32 API callback, any more than you can use a non-static class method (without writing a proxy stub), or a local inner function (not safely, anyway). An anonymous procedure is implemented as a compiler-generated reference-counted interface that has a hidden Invoke() method that is executed whenever the procedure is called. That does not match the signature that SetTimer() (or any other API) is expecting for its callback.
Your code is essentially (but not exactly) doing the following behind the scenes:
type
TOneShotTimerReloaded_Execute_AnonProc = interface(IInterface)
procedure Invoke;
end;
TOneShotTimerReloaded_Execute_AnonProc_Impl = class(TInterfacedObject, TOneShotTimerReloaded_Execute_AnonProc)
public
Captured_Proc: ^TProc;
Captured_TimerID: ^UIntPtr;
procedure Invoke;
end;
procedure TOneShotTimerReloaded_Execute_AnonProc_Impl.Invoke;
begin
if (Assigned(Captured_Proc^)) then
Captured_Proc^();
KillTimer(HWND(0), Captured_TimerID^);
end
procedure TOneShotTimerReloaded.Execute(Proc: TProcedure; TimeOut: Cardinal);
var
TimerID: UIntPtr;
AnonProc: TOneShotTimerReloaded_Execute_AnonProc;
begin
AnonProc := TOneShotTimerReloaded_Execute_AnonProc_Impl.Create;
AnonProc.Captured_Proc := #Proc;
AnonProc.Captured_TimerID := #TimerID;
TimerID := SetTimer(HWND(0), 0, TimeOut, #AnonProc);
end;
See why it cannot possibly ever work?
Even if it were possible, your anonymous procedures are missing the input parameters that SetTimer() passes to its callback, as well as the stdcall calling convention, so you would be mismanaging the call stack anyway.
Your use of the # address operator is hiding compiler errors from you. Get rid of # and let the compiler fail. That should have been your first indication that you are doing something wrong.
To do what you are attempting, you are going to have to create a dynamic proxy stub (similar to what Classes.MakeObjectInstance() does) so SetTimer() can call your Proc handlers (almost) directly. Anonymous procedures will not help you with that.
I' m reading large process output data in Lazarus using the TProcess and the suggestions from this freepascal wiki page.
The wiki page suggests to create a loop to read the process output data like this:
// ... If you want to read output from an external process, this is the code you should adapt for production use.
while True do
begin
MemStream.SetSize(BytesRead + 2024); // make sure we have room
NumBytes := OurProcess.Output.Read((MemStream.Memory + BytesRead)^, READ_BYTES);
if NumBytes > 0
then begin
Inc(BytesRead, NumBytes);
Write('.') //Output progress to screen.
end else
BREAK // Program has finished execution.
end;
// "Then read the MemStream to do your job"
The wiki page also mentions that the calling program should read from the output pipe to prevent it from getting full.
So, how much data makes the output pipe full?
Why we should use a MemStream (TMemoryStream) and not directly read from OurProcess.Output stream (using the bytesAvailable, etc) in the above loop?
I'm reading 80MB of wav data from a process and I have noticed that both MemStream and OurProcess.Output streams have the same amount of data! The memory usage gets doubled. So the suggested method from the wiki cannot be considered as efficient or optimized. Or there is something I'm missing?
Afaik output/input streams are a stream form of a pipe, not memory streams. The values you see are retrieved from the OS handle, not from memory allocated to the FPC app per se.
It is just like you can ask for the .size of a file on disk without reading the whole file.
procedure RunExternalAppInMemo(DosApp:String;AMemo:TMemo);
const READ_BYTES = 2048;
var
aProcess: TProcess; //TProcess is crossplatform is best way
MemStream: TMemoryStream;
NumBytes: LongInt;
BytesRead: LongInt;
Lines: TStringList;
begin
// A temp Memorystream is used to buffer the output
MemStream := TMemoryStream.Create;
Lines :=TStringList.Create;
BytesRead := 0;
aProcess := TProcess.Create(nil);
aProcess.CommandLine := DosApp;
aprocess.ShowWindow := swoHIDE;
AProcess.Options := AProcess.Options + [poUsePipes];
aProcess.Execute;
while aProcess.Running do
begin
// make sure we have room
MemStream.SetSize(BytesRead + READ_BYTES);
// try reading it
NumBytes := aProcess.Output.Read((MemStream.Memory + BytesRead)^, READ_BYTES);
if NumBytes > 0 // All read() calls will block, except the final one.
then Inc(BytesRead, NumBytes)
else
BREAK // Program has finished execution.
end;
MemStream.SetSize(BytesRead);
Lines.LoadFromStream(MemStream);
AMemo.lines.AddStrings(Lines);
aProcess.Free;
Lines.Free;
MemStream.Free;
end;
I was dealing with this problem today, I've modified Georgescu answer, as I wanted Memo to display output stream on the fly
procedure RunExternalAppInMemo(DosApp:String;AMemo:TMemo);
const READ_BYTES = 2048;
var
aProcess: TProcess; //TProcess is crossplatform is best way
NumBytes: LongInt;
Buffer: array of byte;
begin
// set the size of your buffer
SetLength(Buffer,READ_BYTES);
aProcess := TProcess.Create(nil);
aProcess.CommandLine := DosApp;
aprocess.ShowWindow := swoHIDE;
AProcess.Options := AProcess.Options + [poUsePipes];
aProcess.Execute;
while aProcess.Running do
begin
// try reading it
NumBytes := aProcess.Output.Read(Buffer[0], length(buffer)*sizeof(byte)); // I usually do it that way, so I can change Buffer size on if needed
AProcess.Suspend; //I have no experience with pipes, but it seems way I won loose eny output?
if NumBytes > 0 then // All read() calls will block, except the final one.
begin
AMemo.Lines.Add(Pchar(Buffer);
application.ProcessMessages;
AProcess.Resume;
end
else
BREAK; // Program has finished execution.
end;
setlength(Buffer,0);
aProcess.Free;
end;
I'm trying to code a program in vxworks. When a task total delay is 400 ticks, it was suspended at the 100th tick for 20 ticks, then resume to delay.
My main code is like the following:
void DelaySuspend (int level)
{
int tid, suspend_start,suspend_end,i;
suspend_start = vxTicks + 100;
suspend_end = vxTicks + 120;
i = vxTicks;
/* myfunction has taskDelay(400)*/
tid = taskSpawn("tMytask",200,0,2000,(FUNCPTR)myfunction,0,0,0,0,0,0,0,0,0,0);
/* tick between vxTicks+100 and vxTicks+120,suspend tMytask*/
while (i<suspend_start)
{
i=tickGet();
}
while (i <= suspend_end &&i >= suspend_start)
{
i = tickGet();
taskSuspend(tid);
}
}
What I want is to verify total delay time(or tick) doesn't change even I suspend the task for some time. I know the answer but just try to program it to show how vxWorks does it.
I am still not 100% clear on what you are trying to do, but calling taskSuspend in a loop like that isn't going to suspend the task any more. I am guessing you want something like this:
void DelaySuspend (int level)
{
int tid, suspend_start,suspend_end,i;
suspend_start = vxTicks + 100;
suspend_end = vxTicks + 120;
i = vxTicks;
/* myfunction has taskDelay(400)*/
tid = taskSpawn("tMytask",200,0,2000,(FUNCPTR)myfunction,0,0,0,0,0,0,0,0,0,0);
/* tick between vxTicks+100 and vxTicks+120,suspend tMytask*/
while (i<suspend_start)
{
i=tickGet();
}
taskSuspend(tid);
while (i <= suspend_end &&i >= suspend_start)
{
i = tickGet();
}
}
I just pulled the taskSuspend out of the loop, maybe you also want a taskResume in there after the loop or something? I am not sure what you are attempting to accomplish.
Whatever the case, there are probably better ways to do whatever you want, in general using taskSuspend is a bad idea because you have no idea what the task is doing when you suspend it. So for example if the suspended task is doing File I/O when you suspend it, and it has the file system mutex, then you cannot do any file I/O until you resume that task...
In general it is much better to block on a taskDelay/semaphore/mutex/message queue than use taskSuspend. I understand that this is just a test, and as such doing this may be ok, but if this test becomes production code, then you are asking for problems.
I have a straightforward call to a wcf service hosted by iis I'm Delphi 2010
The operation being called on the service could take several minutes
What is the best way of avoiding a timeout error in Delphi?
I deliberately put a Thread.Sleep inside my WCF Service force it to wait for 31 seconds
After 30 seconds I got the error
Project raised exception class ESOAPHTTPException with message 'The handle is in the wrong state for the requested operation - URL:http://10.1.1.4/STC.WcfServices.Host/FlexProcurementService.svc - SOAPAction:http://navsl.stcenergy.com/FlexProcurement/FlexProcurementService/GetPassthroughSummaryGridReportData'.
This turned out to be a bug in Delphi 2010 which I have applied the patch for, so now I get the error operation timed out
function GetFlexProcurementService(const objServiceInfo: TWCFService; UseWSDL: Boolean; Addr: string; HTTPRIO: THTTPRIO): FlexProcurementService;
var
RIO: THTTPRIO;
begin
Result := nil;
if (Addr = '') then
begin
if UseWSDL then
Addr := objServiceInfo.WSDL
else
Addr := objServiceInfo.URL;
end;
if HTTPRIO = nil then
RIO := THTTPRIO.Create(nil)
else
RIO := HTTPRIO;
try
Result := (RIO as FlexProcurementService);
if UseWSDL then
begin
RIO.WSDLLocation := Addr;
RIO.Service := objServiceInfo.Svc;
RIO.Port := objServiceInfo.Prt;
end else
RIO.URL := Addr;
finally
if (Result = nil) and (HTTPRIO = nil) then
RIO.Free;
end;
end;
Paul
uses wininet;
...
function SetTimeout(const HTTPReqResp: THTTPReqResp; Data: Pointer; NumSecs : integer) : boolean;
var
TimeOut: Integer;
begin
// Sets the receive timeout. i.e. how long to wait to 'receive' the response
TimeOut := (NumSecs * 1000);
try
InternetSetOption(Data, INTERNET_OPTION_RECEIVE_TIMEOUT, Pointer(#TimeOut), SizeOf(TimeOut));
InternetSetOption(Data, INTERNET_OPTION_SEND_TIMEOUT, Pointer(#TimeOut), SizeOf(TimeOut));
except on E:Exception do
raise Exception.Create(Format('Unhandled Exception:[%s] while setting timeout to [%d] - ',[E.ClassName, TimeOut, e.Message]));
end;
end;
In the RIO OnBeforePost:
procedure TEETOUpsertWrapper.OnBeforePost(const HTTPReqResp: THTTPReqResp; Data: Pointer); begin
SetTimeout(HTTPReqResp, Data, 5 * 60);
end;