В случае, если кто-то хочет знать, решение было довольно простым для реализации.Теперь у нас есть истекшие рабочие часы [0:00], которые увеличиваются каждый раз, когда клиентское приложение ожидает, пока сервер DataSnap обработает запрос.По сути, это то, что мы сделали.( Особая благодарность тем, кто делится своими решениями, - которые помогли мне мыслить. )
Сгенерированные сервером классы (ProxyMethods) должны быть созданы в потоке VCL, но выполнены вотдельная тема.Для этого мы создали класс-оболочку ProxyMethods и класс потока ProxyMehtods (все это придумано для этого примера, но все же он иллюстрирует поток):
ProxyMethods.pas
...
type
TServerMethodsClient = class(TDSAdminClient)
private
FGetDataCommand: TDBXCommand;
public
...
function GetData(Param1: string; Param2: string): string;
...
end;
ProxyWrapper.pas
...
type
TServerMethodsWrapper = class(TServerMethodsClient)
private
FParam1: string;
FParam2: string;
FResult: string;
public
constructor Create; reintroduce;
procedure GetData(Param1: string; Param2: string);
procedure _Execute;
function GetResult: string;
end;
TServerMethodsThread = class(TThread)
private
FServerMethodsWrapper: TServerMethodsWrapper;
protected
procedure Execute; override;
public
constructor Create(ServerMethodsWrapper: TServerMethodsWrapper);
end;
implementation
constructor TServerMethodsWrapper.Create;
begin
inherited Create(ASQLServerConnection.DBXConnection, True);
end;
procedure TServerMethodsWrapper.GetData(Param1: string; Param2: string);
begin
FParam1 := Param1;
FParam2 := Param2;
end;
procedure TServerMethodsWrapper._Execute;
begin
FResult := inherited GetData(FParam1, FParam2);
end;
function TServerMethodsWrapper.GetResult: string;
begin
Result := FResult;
end;
constructor TServerMethodsThread.Create(ServerMethodsWrapper: TServerMethodsWrapper);
begin
FServerMethodsWrapper := ServerMethodsWrapper;
FreeOnTerminate := False;
inherited Create(False);
end;
procedure TServerMethodsThread.Execute;
begin
FServerMethodsWrapper._Execute;
end;
Вы можете видеть, что мы разбили выполнение ProxyMethod на двашаги.Первым шагом является сохранение значений параметров в приватных переменных.Это позволяет методу _Execute()
иметь все, что ему нужно знать, когда он выполняет фактический метод ProxyMethods, результат которого сохраняется в FResult
для последующего извлечения.
Если класс ProxyMethods имеет несколько функций, вы легкооберните каждый метод и установите внутреннюю переменную (например, FProcID
) при вызове метода для установки приватных переменных.Таким образом, метод _Execute()
может использовать FProcID
, чтобы узнать, какой ProxyMethod должен выполняться ...
Вы можете удивиться, почему Thread не освобождает себя.Причина в том, что я не смог устранить ошибку « Ошибка потока: недопустимый дескриптор (6) », когда поток выполнил свою собственную очистку.
Код, который вызывает класс-оболочкувыглядит следующим образом:
var
smw: TServerMethodsWrapper;
val: string;
begin
...
smw := TServerMethodsWrapper.Create;
try
smw.GetData('value1', 'value2');
// start timer here
with TServerMethodsThread.Create(smw) do
begin
WaitFor;
Free;
end;
// stop / reset timer here
val := smw.GetResult;
finally
FreeAndNil(smw);
end;
...
end;
WaitFor
приостанавливает выполнение кода до завершения потока ProxyMethods.Это необходимо, потому что smw.GetResult
не вернет нужное значение, пока поток не завершит выполнение.Ключом к увеличению времени истекших часов [0:00], когда поток выполнения прокси занят, является использование TJvThreadTimer
для обновления пользовательского интерфейса.TTimer
не работает даже при выполнении ProxyMethod в отдельном потоке, поскольку поток VCL ожидает WaitFor
, поэтому TTimer.OnTimer()
не выполняется до тех пор, пока не будет выполнен WaitFor
.
Информационно код TJvTheadTimer.OnTimer()
выглядит следующим образом, что обновляет строку состояния приложения:
var
sec: Integer;
begin
sec := DateUtils.SecondsBetween(Now, FBusyStart);
StatusBar1.Panels[0].Text := Format('%d:%.2d', [sec div 60, sec mod 60]);
StatusBar1.Repaint;
end;