Delphi synapse UDP client/server - delphi

I need to create server and client programs with synapse using UDP protocol.
I have created the server program to listen to any coming messages like this
procedure TForm1.Timer1Timer(Sender: TObject);
var
resive:string;
begin
InitSocket;
resive:=UDPResiveSocket.RecvPacket(1000);
if resive<>'' then Memo1.Lines.Add('>' + resive);
DeInitSocket;
end;
procedure TForm1.InitSocket;
begin
if UDPResiveSocket <> nil then
DeInitSocket;
UDPResiveSocket := TUDPBlockSocket.Create;
UDPResiveSocket.CreateSocket;
UDPResiveSocket.Bind('0.0.0.0','22401');
UDPResiveSocket.AddMulticast('234.5.6.7');
UDPResiveSocket.MulticastTTL := 1;
end;
procedure TForm1.DeInitSocket;
begin
UDPResiveSocket.CloseSocket;
UDPResiveSocket.Free;
UDPResiveSocket := nil;
end;
So i get all incoming messages.
But i want to send a response from the source of this messages.
How can i do that? Does my method is good for server/client?

My UDP Echo client / server code. First the server:
unit UE_Server;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils,
// synapse
blcksock;
type
{ TUEServerThread }
TUEServerThread = class(TThread)
protected
procedure Execute; override;
end;
TUEServer = class
private
FUEServerThread: TUEServerThread;
function GetRunning: Boolean;
public
procedure Stop;
procedure Start;
property Running: Boolean read GetRunning;
end;
implementation
{ TUEServer }
function TUEServer.GetRunning: Boolean;
begin
Result := FUEServerThread <> nil;
end;
procedure TUEServer.Start;
begin
FUEServerThread := TUEServerThread.Create(False);
end;
procedure TUEServer.Stop;
begin
if FUEServerThread <> nil then
begin
FUEServerThread.Terminate;
FUEServerThread.WaitFor;
FreeAndNil(FUEServerThread);
end;
end;
{ TUEServerThread }
procedure TUEServerThread.Execute;
var
Socket: TUDPBlockSocket;
Buffer: string;
Size: Integer;
begin
Socket := TUDPBlockSocket.Create;
try
Socket.Bind('0.0.0.0', '7');
try
if Socket.LastError <> 0 then
begin
raise Exception.CreateFmt('Bind failed with error code %d', [Socket.LastError]);
Exit;
end;
while not Terminated do
begin
// wait one second for new packet
Buffer := Socket.RecvPacket(1000);
if Socket.LastError = 0 then
begin
// just send the same packet back
Socket.SendString(Buffer);
end;
// minimal sleep
if Buffer = '' then
Sleep(10);
end;
finally
Socket.CloseSocket;
end;
finally
Socket.Free;
end;
end;
end.
Then the client:
unit UE_Client;
{$mode objfpc}{$H+}
interface
uses
{$IFDEF WINDOWS}Windows,{$ENDIF}Classes, SysUtils, DateUtils,
// synapse
blcksock;
const
cReceiveTimeout = 2000;
cBatchSize = 100;
type
{ TUEClient }
TUEClient = class
private
FSocket: TUDPBlockSocket;
FResponseTime: Int64;
public
constructor Create;
destructor Destroy; override;
procedure Disconnect;
function Connect(const Address: string): Boolean;
function SendEcho(const Message: string): string;
property ReponseTime: Int64 read FResponseTime;
end;
{ TUEAnalyzer }
{ TUEAnalyzerThread }
TUEAnalyzerThread = class(TThread)
private
FAddress: string;
FBatchDelay: Cardinal;
FDropedPackets: Cardinal;
FAverageResponse: Extended;
FCriticalSection: TRTLCriticalSection;
function GetAverageResponse: Extended;
function GetDropedPackets: Cardinal;
protected
procedure Execute; override;
public
destructor Destroy; override;
constructor Create(const Address: string; const BatchDelay: Cardinal);
property DropedPackets: Cardinal read GetDropedPackets;
property AverageResponse: Extended read GetAverageResponse;
end;
TUEAnalyzer = class
private
FAddress: string;
FBatchDelay: Cardinal;
FAnalyzerThread: TUEAnalyzerThread;
function GetAverageResponse: Extended;
function GetDropedPackets: Cardinal;
function GetRunning: Boolean;
public
procedure StopAnalyzer;
procedure StartAnalyzer;
property Running: Boolean read GetRunning;
property Address: string read FAddress write FAddress;
property DropedPackets: Cardinal read GetDropedPackets;
property AverageResponse: Extended read GetAverageResponse;
property BatchDelay: Cardinal read FBatchDelay write FBatchDelay;
end;
implementation
{ TUEAnalyzerThread }
function TUEAnalyzerThread.GetAverageResponse: Extended;
begin
EnterCriticalsection(FCriticalSection);
try
Result := FAverageResponse;
finally
LeaveCriticalsection(FCriticalSection);
end;
end;
function TUEAnalyzerThread.GetDropedPackets: Cardinal;
begin
EnterCriticalsection(FCriticalSection);
try
Result := FDropedPackets;
finally
LeaveCriticalsection(FCriticalSection);
end;
end;
procedure TUEAnalyzerThread.Execute;
var
UEClient: TUEClient;
Connected: Boolean;
SendString: string;
SendCounter: Int64;
SumResponse: Cardinal;
SumDropedPackets: Cardinal;
begin
UEClient := TUEClient.Create;
try
Connected := UEClient.Connect(FAddress);
try
if not Connected then
begin
raise Exception.CreateFmt('Could not connect UPD client to address %s', [FAddress]);
Exit;
end;
SumDropedPackets := 0;
FAverageResponse := 0;
FDropedPackets := 0;
SumResponse := 0;
SendCounter := 1;
while not Terminated do
begin
SendString := IntToStr(SendCounter);
if not (UEClient.SendEcho(SendString) = SendString) then
Inc(SumDropedPackets);
Inc(SumResponse, UEClient.ReponseTime);
Inc(SendCounter);
if (SendCounter mod cBatchSize) = 0 then
begin
EnterCriticalsection(FCriticalSection);
try
FAverageResponse := SumResponse / cBatchSize;
FDropedPackets := SumDropedPackets;
finally
LeaveCriticalsection(FCriticalSection);
end;
// sleep for specified batch time
Sleep(FBatchDelay * 1000);
SumDropedPackets := 0;
SumResponse := 0;
end;
// minimal sleep
Sleep(10);
end;
finally
UEClient.Disconnect;
end;
finally
UEClient.Free;
end;
end;
destructor TUEAnalyzerThread.Destroy;
begin
{$IFDEF MSWINDOWS}
DeleteCriticalSection(FCriticalSection)
{$ELSE}
DoneCriticalSection(FCriticalSection)
{$ENDIF};
inherited Destroy;
end;
constructor TUEAnalyzerThread.Create(const Address: string; const BatchDelay: Cardinal);
begin
{$IFDEF MSWINDOWS}
InitializeCriticalSection(FCriticalSection)
{$ELSE}
InitCriticalSection(FCriticalSection)
{$ENDIF};
FBatchDelay := BatchDelay;
FreeOnTerminate := True;
FAddress := Address;
inherited Create(False);
end;
{ TUEAnalyzer }
procedure TUEAnalyzer.StartAnalyzer;
begin
FAnalyzerThread := TUEAnalyzerThread.Create(FAddress, FBatchDelay);
end;
function TUEAnalyzer.GetRunning: Boolean;
begin
Result := FAnalyzerThread <> nil;
end;
function TUEAnalyzer.GetAverageResponse: Extended;
begin
Result := FAnalyzerThread.AverageResponse;
end;
function TUEAnalyzer.GetDropedPackets: Cardinal;
begin
Result := FAnalyzerThread.DropedPackets;
end;
procedure TUEAnalyzer.StopAnalyzer;
begin
if Running then
begin
FAnalyzerThread.Terminate;
FAnalyzerThread := nil;
end;
end;
{ TUEClient }
constructor TUEClient.Create;
begin
FSocket := TUDPBlockSocket.Create;
end;
destructor TUEClient.Destroy;
begin
FreeAndNil(FSocket);
inherited Destroy;
end;
procedure TUEClient.Disconnect;
begin
FSocket.CloseSocket;
end;
function TUEClient.Connect(const Address: string): Boolean;
begin
FSocket.Connect(Address, '7');
Result := FSocket.LastError = 0;
end;
function TUEClient.SendEcho(const Message: string): string;
var
StartTime: TDateTime;
begin
Result := '';
StartTime := Now;
FSocket.SendString(Message);
if FSocket.LastError = 0 then
begin
Result := FSocket.RecvPacket(cReceiveTimeout);
FResponseTime := MilliSecondsBetween(Now, StartTime);
if FSocket.LastError <> 0 then
begin
FResponseTime := -1;
Result := '';
end;
end;
end;
end.
The code is written in free pascal, but works equally well in Delphi. The client unit is actually a line analyzer that calculates average response times and dropped packets. It is ideal to check the quality of your internet line to a certain server. You put the echo server to the server part and client on the client side.

Simple client-server in two program
client send two string "Hello world" and "exit"
server wait for client message and stop after client send "exit"
write on free pascal(Lazarus)
client
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
//ADD
blcksock;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
procedure OnStatus(Sender: TObject; Reason: THookSocketReason; const Value: string );
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.OnStatus(Sender: TObject; Reason: THookSocketReason; const Value: string);
var
sReason : String;
begin
case Reason of
HR_ResolvingBegin : sReason := 'HR_ResolvingBegin';
HR_ResolvingEnd : sReason := 'HR_ResolvingEnd';
HR_SocketCreate : sReason := 'HR_SocketCreate';
HR_SocketClose : sReason := 'HR_SocketClose';
HR_Bind : sReason := 'HR_Bind';
HR_Connect : sReason := 'HR_Connect';
HR_CanRead : sReason := 'HR_CanRead';
HR_CanWrite : sReason := 'HR_CanWrite';
HR_Listen : sReason := 'HR_Listen';
HR_Accept : sReason := 'HR_Accept';
HR_ReadCount : sReason := 'HR_ReadCount';
HR_WriteCount : sReason := 'HR_WriteCount';
HR_Wait : sReason := 'HR_Wait';
HR_Error : sReason := 'HR_Error';
end;
Memo1.Lines.Add( sReason + ': ' + Value );
end;
procedure TForm1.Button1Click(Sender: TObject);
var
UDP: TUDPBlockSocket;
s:string;
begin
UDP := TUDPBlockSocket.Create;
try
UDP.OnStatus := #OnStatus;
//send to server
s:='Hello world from client';
UDP.Connect( '127.0.0.1', '12345' );
UDP.SendString('------'+s+'--------');
memo1.Append(s);
//for server stop send string "exit"
s:='exit';
UDP.SendString(s);
memo1.Append('---');
memo1.Append(s);
memo1.Append('---');
UDP.CloseSocket;
finally
UDP.Free;
end;
end;
end.
SERVER
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
//ADD
blcksock;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
procedure OnStatus(Sender: TObject; Reason: THookSocketReason; const Value: string );
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.OnStatus(Sender: TObject; Reason: THookSocketReason; const Value: string);
var
sReason : String;
begin
case Reason of
HR_ResolvingBegin : sReason := 'HR_ResolvingBegin';
HR_ResolvingEnd : sReason := 'HR_ResolvingEnd';
HR_SocketCreate : sReason := 'HR_SocketCreate';
HR_SocketClose : sReason := 'HR_SocketClose';
HR_Bind : sReason := 'HR_Bind';
HR_Connect : sReason := 'HR_Connect';
HR_CanRead : sReason := 'HR_CanRead';
HR_CanWrite : sReason := 'HR_CanWrite';
HR_Listen : sReason := 'HR_Listen';
HR_Accept : sReason := 'HR_Accept';
HR_ReadCount : sReason := 'HR_ReadCount';
HR_WriteCount : sReason := 'HR_WriteCount';
HR_Wait : sReason := 'HR_Wait';
HR_Error : sReason := 'HR_Error';
end;
Memo1.Append( sReason + ': ' + Value );
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Sock:TUDPBlockSocket;
size:integer;
buf:string;
begin
Sock:=TUDPBlockSocket.Create;
try
//On status show error and other
//enable on status if you can more seen
//sock.OnStatus := #OnStatus;
sock.CreateSocket;
//create server
sock.bind('127.0.0.1','12345');
//send string to this server in this program(not client)
sock.Connect( '127.0.0.1', '12345' );
sock.SendString('test send string to sever');
if sock.LastError<>0 then exit;
//shutdown while client send "exit"
while buf<>'exit' do
begin
//get data client
buf := sock.RecvPacket(1000);
Memo1.Append(buf);
sleep(1);
end;
sock.CloseSocket;
finally
sock.free;
end;
end;
end.

Related

How to allow a Windows Service (written in Delphi) to access an Amazon Bucket?

I would like to create a Windows Service (with Delphi) that will attempt, every hour, to retrieve a specific file from a specific Amazon S3 Bucket.
I have no problem accessing the Amazon S3 Bucket with my VCL application. However, if I try to run the same function through my Windows Service, it returns absolutely nothing. I believe that it is a permission issue: my Service does not permission to access the outside world.
What should I do to remedy my problem?
I am using Delphi Tokyo Update 3, my Service is built upon a DataSnap Server.
Here is the code for my 'server container' unit:
unit UnitOurDataSnapServerContainer;
interface
uses
System.SysUtils, System.Classes, System.Win.Registry, Vcl.SvcMgr,
Datasnap.DSTCPServerTransport,
Datasnap.DSServer, Datasnap.DSCommonServer,
IPPeerServer, IPPeerAPI, Datasnap.DSAuth;
type
TServerContainer_OurCompany = class(TService)
DSServer_OurCompany: TDSServer;
DSServerClass_OurCompany: TDSServerClass;
DSTCPServerTransport_OurCompany: TDSTCPServerTransport;
procedure DSServerClass_OurCompanyGetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
procedure ServiceStart(Sender: TService; var Started: Boolean);
private
{ Private declarations }
protected
function DoStop: Boolean; override;
function DoPause: Boolean; override;
function DoContinue: Boolean; override;
procedure DoInterrogate; override;
public
function GetServiceController: TServiceController; override;
end;
var
ServerContainer_OurCompany: TServerContainer_OurCompany;
implementation
{$R *.dfm}
uses
Winapi.Windows,
UnitOurDataSnapServerMethods;
procedure TServerContainer_OurCompany.DSServerClass_OurCompanyGetClass(DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
begin
PersistentClass := UnitOurDataSnapServerMethods.TOurDataSnapServerMethods;
end;
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
ServerContainer_OurCompany.Controller(CtrlCode);
end;
function TServerContainer_OurCompany.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
function TServerContainer_OurCompany.DoContinue: Boolean;
begin
Result := inherited;
DSServer_OurCompany.Start;
end;
procedure TServerContainer_OurCompany.DoInterrogate;
begin
inherited;
end;
function TServerContainer_OurCompany.DoPause: Boolean;
begin
DSServer_OurCompany.Stop;
Result := inherited;
end;
function TServerContainer_OurCompany.DoStop: Boolean;
begin
DSServer_OurCompany.Stop;
Result := inherited;
end;
procedure TServerContainer_OurCompany.ServiceStart(Sender: TService; var Started: Boolean);
begin
{$IFDEF RELEASE}
DSServer_OurCompany.HideDSAdmin := True;
{$ENDIF}
DSServer_OurCompany.Start;
end;
end.
Here is the code for my 'servermethods' unit:
unit UnitOurDataSnapServerMethods;
interface
uses
System.SysUtils, System.Classes, Datasnap.DSServer, Datasnap.DSAuth;
type
{$METHODINFO ON}
TOurDataSnapServerMethods = class(TComponent)
private
{ Private declarations }
public
{ Public declarations }
function Get_ListOfFilesInS3Bucket(aS3Path: String; aFileExtension: String) : Integer;
end;
{$METHODINFO OFF}
implementation
uses
Data.Cloud.CloudAPI, Data.Cloud.AmazonAPI;
function TOurDataSnapServerMethods.Get_ListOfFilesInS3Bucket(aS3Path: String; aFileExtension: String) : Integer;
var
iFileList: TStrings;
iFileExtension: String;
iOptionalParams: TStrings;
iResponseInfo: TCloudResponseInfo;
iStorageService: TAmazonStorageService;
iAmazonBucketResult: TAmazonBucketResult;
iAmazonObjectResult: TAmazonObjectResult;
iAmazonConnectionInfo: TAmazonConnectionInfo;
begin
Result := 0;
iFileExtension := aFileExtension;
if Pos('.', iFileExtension) = 0 then
iFileExtension := '.' + iFileExtension;
try
iAmazonConnectionInfo := TAmazonConnectionInfo.Create(nil);
iAmazonConnectionInfo.AccountName := 'AKIA****************';
iAmazonConnectionInfo.AccountKey := 'BzNn************************************';
iOptionalParams := TStringList.Create;
iOptionalParams.Values['prefix'] := aS3Path;
iStorageService := TAmazonStorageService.Create(iAmazonConnectionInfo);
iResponseInfo := TCloudResponseInfo.Create;
iAmazonBucketResult := nil;
iFileList := TStringList.Create;
try
iAmazonBucketResult := iStorageService.GetBucket('our-s3-bucket', iOptionalParams, iResponseInfo);
for iAmazonObjectResult in iAmazonBucketResult.Objects do
begin
if Pos(iFileExtension, iAmazonObjectResult.Name) <> 0 then
iFileList.Add(iAmazonObjectResult.Name);
end;
Result := iFileList.Count;
except
on e: Exception do
;
end;
FreeAndNil(iAmazonBucketResult);
finally
iFileList.Free;
iResponseInfo.Free;
iStorageService.Free;
iOptionalParams.Free;
iAmazonConnectionInfo.Free;
end;
end;
end.
It is the call to 'iStorageService.GetBucket' that returns nothing.

Problems getting the JSON data from DLL using SuperObject and OmniThreadLibrary

I'm using Delphi XE, I have the following code for my program and DLL:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, superobject,
OtlCommon, OtlCollections, OtlParallel;
type
TForm1 = class(TForm)
btnStart: TButton;
btnStop: TButton;
procedure btnStartClick(Sender: TObject);
procedure btnStopClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure FormCreate(Sender: TObject);
private
FLogger : IOmniBackgroundWorker;
FPipeline: IOmniPipeline;
FLogFile: TextFile;
strict protected
procedure Async_Log(const workItem: IOmniWorkItem);
procedure Async_Files(const input, output: IOmniBlockingCollection);
procedure Async_Parse(const input: TOmniValue; var output: TOmniValue);
procedure Async_JSON(const input, output: IOmniBlockingCollection);
end;
var
Form1: TForm1;
function GetJSON(AData: PChar): ISuperObject; stdcall; external 'my.dll';
implementation
uses OtlTask, IOUtils;
{$R *.dfm}
function GetJSON_local(AData: PChar): ISuperObject;
var
a: ISuperObject;
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Text := StrPas(AData);
Result := SO();
Result.O['array'] := SA([]);
a := SO;
a.S['item1'] := sl[14];
Result.A['array'].Add(a);
a := nil;
a := SO;
a.S['item2'] := sl[15];
Result.A['array'].Add(a);
finally
sl.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
s: string;
begin
// log
s := ExtractFilePath(Application.ExeName) + 'Logs';
if not TDirectory.Exists(s) then TDirectory.CreateDirectory(s);
s := Format(s+'\%s.txt', [FormatDateTime('yyyy-mm-dd_hh-nn-ss', Now)]);
AssignFile(FLogFile, s);
Rewrite(FLogFile);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
CloseFile(FLogFile);
end;
procedure TForm1.Async_Log(const workItem: IOmniWorkItem);
begin
WriteLn(FLogFile, workItem.Data.AsString);
end;
procedure TForm1.Async_Files(const input, output: IOmniBlockingCollection);
var
f: string;
begin
while not input.IsCompleted do begin
for f in TDirectory.GetFiles(ExtractFilePath(Application.ExeName), '*.txt') do
output.TryAdd(f); // output as FileName
Sleep(1000);
end;
end;
procedure TForm1.Async_Parse(const input: TOmniValue; var output: TOmniValue);
var
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.LoadFromFile(input.AsString);
// output := GetJSON_local(PChar(sl.Text)); // output as ISuperObject --- local function
output := GetJSON(PChar(sl.Text)); // output as ISuperObject --- DLL function
finally
sl.Free;
end;
FLogger.Schedule(FLogger.CreateWorkItem(Format('%s - File processed: %s', [DateTimeToStr(Now), input.AsString])));
end;
procedure TForm1.Async_JSON(const input, output: IOmniBlockingCollection);
var
value: TOmniValue;
JSON: ISuperObject;
begin
for value in input do begin
if value.IsException then begin
FLogger.Schedule(FLogger.CreateWorkItem(value.AsException.Message));
value.AsException.Free;
end
else begin
JSON := value.AsInterface as ISuperObject;
FLogger.Schedule(FLogger.CreateWorkItem(JSON.AsString));
end;
end;
end;
//
procedure TForm1.btnStartClick(Sender: TObject);
begin
btnStart.Enabled := False;
FLogger := Parallel.BackgroundWorker.NumTasks(1).Execute(Async_Log);
FPipeline := Parallel.Pipeline
.Stage(Async_Files)
.Stage(Async_Parse)
.Stage(Async_JSON)
.Run;
end;
procedure TForm1.btnStopClick(Sender: TObject);
begin
if Assigned(FPipeline) and Assigned(FLogger) then begin
FPipeline.Input.CompleteAdding;
FPipeline := nil;
FLogger.Terminate(INFINITE);
FLogger := nil;
end;
btnStart.Enabled := True;
end;
end.
// DLL code
library my;
uses
SysUtils,
Classes, superobject;
function GetJSON(AData: PChar): ISuperObject; stdcall;
var
a: ISuperObject;
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Text := StrPas(AData);
Result := SO();
Result.O['array'] := SA([]);
a := SO;
a.S['item1'] := sl[14];
Result.A['array'].Add(a);
a := nil;
a := SO;
a.S['item2'] := sl[15];
Result.A['array'].Add(a);
finally
sl.Free;
end;
end;
exports
GetJSON;
begin
end.
When I try to run with debugging my code, after a few calls of the dll GetJSON function i get the following error:
"Project test_OTL_SO.exe raised exception class EAccessViolation with message 'Access violation at address 005A2F8A in module 'my.dll'. Write of address 00610754'."
However, this issue does not occur when I use the same local function GetJSON_local.
Could anyone suggest what am I doing wrong here?
EDIT: (solution)
I write this code for my DLL:
procedure GetJSON_(const AData: PChar; out Output: WideString); stdcall;
var
json, a: ISuperObject;
sl: TStringList;
begin
sl := TStringList.Create;
try
sl.Text := AData;
json := SO();
json.O['array'] := SA([]);
a := SO;
a.S['item1'] := sl[14];
json.A['array'].Add(a);
a := nil;
a := SO;
a.S['item2'] := sl[15];
json.A['array'].Add(a);
Output := json.AsString;
finally
sl.Free;
end;
end;
and changed the code of Async_Parse procedure:
procedure TForm1.Async_Parse(const input: TOmniValue; var output: TOmniValue);
var
sl: TStringList;
ws: WideString;
begin
sl := TStringList.Create;
try
sl.LoadFromFile(input.AsString);
GetJSON_(PChar(sl.Text), ws); // DLL procedure
output := SO(ws); // output as ISuperObject
finally
sl.Free;
end;
FLogger.Schedule(FLogger.CreateWorkItem(Format('%s - File processed: %s', [DateTimeToStr(Now), input.AsString])));
end;
The problem is your passing of ISuperObject interfaces across a module boundary. Although interfaces can be safely used that way, the methods of the interface are not safe. Some of the methods of the interface accept, or return, strings, objects, etc. That is, types that are not safe for interop.
Some examples of methods that are not safe:
function GetEnumerator: TSuperEnumerator; // TSuperEnumerator is a class
function GetS(const path: SOString): SOString; // returns a Delphi string
function SaveTo(stream: TStream; indent: boolean = false;
escape: boolean = true): integer; overload; // TStream is a class
function AsArray: TSuperArray; // TSuperArray is a class
// etc.
You should serialize the JSON to text, and pass that text between your modules.

How to detect addition of new serial port?

To communicate with micro controllers I use the serial port. I use TCommPortDriver 2.1 which works fine. However, it lacks the ability to detect the addition or removal of new comports. This happens regularly during a session.
Is there an event that tells when a comport has been added or removed?
Update 1
I tried the first suggestion of RRUZ and turned it into a standalone program. It reacts on a WM_DEVICECHANGE when the cable is plugged in or out, but WParam does not show arrival or removal of the device. Results are:
msg = 537, wparam = 7, lparam = 0
msg = 537, wparam = 7, lparam = 0
msg = 537, wparam = 7, lparam = 0
The first message is sent when the USB cable is plugged out and the next two when it is plugged in.
The message part shows the WM_DEVICECHANGE message (537) but WParam is 7, which is not WM_DEVICECHANGE or DBT_DEVICEARRIVAL. I modified the code somewhat in order the message to be processed but as LParam is zero this is no use. Results are identical to VCL and FMX. As a check see code below.
Update 2
I now got the WMI code running. It only fires when a COM port is added, no reaction when one is removed. Results:
TargetInstance.ClassGuid : {4d36e978-e325-11ce-bfc1-08002be10318}
TargetInstance.Description : Arduino Mega ADK R3
TargetInstance.Name : Arduino Mega ADK R3 (COM4)
TargetInstance.PNPDeviceID : USB\VID_2341&PID_0044\64935343733351E0E1D1
TargetInstance.Status : OK
Might this explain the fact that in the other code this is not seen as the addition of a COM port? It appears to see the new connection as a USB port (what it actually is). The Arduino driver translates this into a COM port but that is not recognized by WMI. Windows messaging 'sees' a COM port change but cannot detect whether it is added or removed.
Anyhow: the device change works. I only need to enumerate the COM ports to see which one are actually present and that was something I already did manually. Now I can do that automatically with WM_DEVICECHANGE. I just add an event to the CPDrv component.
Thanks RRUZ for your code and help!
unit dev_change;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TProc = procedure (text: string) of object;
BroadcastHdr = ^DEV_BROADCAST_HDR;
DEV_BROADCAST_HDR = packed record
dbch_size: DWORD;
dbch_devicetype: DWORD;
dbch_reserved: DWORD;
end;
TDevBroadcastHdr = DEV_BROADCAST_HDR;
type
PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE;
DEV_BROADCAST_DEVICEINTERFACE = record
dbcc_size: DWORD;
dbcc_devicetype: DWORD;
dbcc_reserved: DWORD;
dbcc_classguid: TGUID;
dbcc_name: Char;
end;
TDevBroadcastDeviceInterface = DEV_BROADCAST_DEVICEINTERFACE;
const
DBT_DEVICESOMETHING = $0007;
DBT_DEVICEARRIVAL = $8000;
DBT_DEVICEREMOVECOMPLETE = $8004;
DBT_DEVTYP_DEVICEINTERFACE = $00000005;
type
TDeviceNotifyProc = procedure(Sender: TObject; const DeviceName: String) of Object;
TDeviceNotifier = class
private
hRecipient: HWND;
FNotificationHandle: Pointer;
FDeviceArrival: TDeviceNotifyProc;
FDeviceRemoval: TDeviceNotifyProc;
FOnWin: TProc;
procedure WndProc(var Msg: TMessage);
public
constructor Create(GUID_DEVINTERFACE : TGUID);
property OnDeviceArrival: TDeviceNotifyProc read FDeviceArrival write FDeviceArrival;
property OnDeviceRemoval: TDeviceNotifyProc read FDeviceRemoval write FDeviceRemoval;
destructor Destroy; override;
property OnWin: TProc read FOnWin write FOnWin;
end;
TForm1 = class(TForm)
Memo: TMemo;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
DeviceNotifier : TDeviceNotifier;
public
{ Public declarations }
procedure arrival(Sender: TObject; const DeviceName: String);
procedure report (text: string);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TDeviceNotifier.Create(GUID_DEVINTERFACE : TGUID);
var
NotificationFilter: TDevBroadcastDeviceInterface;
begin
inherited Create;
hRecipient := AllocateHWnd(WndProc);
ZeroMemory (#NotificationFilter, SizeOf(NotificationFilter));
NotificationFilter.dbcc_size := SizeOf(NotificationFilter);
NotificationFilter.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid := GUID_DEVINTERFACE;
//register the device class to monitor
FNotificationHandle := RegisterDeviceNotification(hRecipient, #NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
end;
procedure TDeviceNotifier.WndProc(var Msg: TMessage);
var
Dbi: PDevBroadcastDeviceInterface;
begin
OnWin (Format ('msg = %d, wparam = %d, lparam = %d', [msg.Msg, msg.WParam, msg.LParam]));
with Msg do
if (Msg = WM_DEVICECHANGE) and ((WParam = DBT_DEVICEARRIVAL) or (WParam = DBT_DEVICEREMOVECOMPLETE) or
(WParam = DBT_DEVICESOMETHING)) then
try
Dbi := PDevBroadcastDeviceInterface (LParam);
if Dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE then
begin
if WParam = DBT_DEVICEARRIVAL then
begin
if Assigned(FDeviceArrival) then
FDeviceArrival(Self, PChar(#Dbi.dbcc_name));
end
else
if WParam = DBT_DEVICEREMOVECOMPLETE then
begin
if Assigned(FDeviceRemoval) then
FDeviceRemoval(Self, PChar(#Dbi.dbcc_name));
end;
end;
except
Result := DefWindowProc(hRecipient, Msg, WParam, LParam);
end
else
Result := DefWindowProc(hRecipient, Msg, WParam, LParam);
end;
destructor TDeviceNotifier.Destroy;
begin
UnregisterDeviceNotification(FNotificationHandle);
DeallocateHWnd(hRecipient);
inherited;
end;
procedure TForm1.arrival(Sender: TObject; const DeviceName: String);
begin
report (DeviceName);
ShowMessage(DeviceName);
end;
procedure TForm1.FormCreate(Sender: TObject);
const
GUID_DEVINTERFACE_COMPORT : TGUID = '{86E0D1E0-8089-11D0-9CE4-08003E301F73}';
begin
DeviceNotifier:=TDeviceNotifier.Create(GUID_DEVINTERFACE_COMPORT);
DeviceNotifier.FDeviceArrival:=arrival;
DeviceNotifier.OnWin := report;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
DeviceNotifier.Free;
end;
procedure TForm1.report (text: string);
begin
Memo.Lines.Add (text);
end;
end.
You can use the RegisterDeviceNotification WinAPI function passing the DEV_BROADCAST_DEVICEINTERFACE structure with the GUID_DEVINTERFACE_COMPORT device interface class.
Try this sample.
type
PDevBroadcastHdr = ^DEV_BROADCAST_HDR;
DEV_BROADCAST_HDR = packed record
dbch_size: DWORD;
dbch_devicetype: DWORD;
dbch_reserved: DWORD;
end;
TDevBroadcastHdr = DEV_BROADCAST_HDR;
type
PDevBroadcastDeviceInterface = ^DEV_BROADCAST_DEVICEINTERFACE;
DEV_BROADCAST_DEVICEINTERFACE = record
dbcc_size: DWORD;
dbcc_devicetype: DWORD;
dbcc_reserved: DWORD;
dbcc_classguid: TGUID;
dbcc_name: Char;
end;
TDevBroadcastDeviceInterface = DEV_BROADCAST_DEVICEINTERFACE;
const
DBT_DEVICEARRIVAL = $8000;
DBT_DEVICEREMOVECOMPLETE = $8004;
DBT_DEVTYP_DEVICEINTERFACE = $00000005;
type
TDeviceNotifyProc = procedure(Sender: TObject; const DeviceName: String) of Object;
TDeviceNotifier = class
private
hRecipient: HWND;
FNotificationHandle: Pointer;
FDeviceArrival: TDeviceNotifyProc;
FDeviceRemoval: TDeviceNotifyProc;
procedure WndProc(var Msg: TMessage);
public
constructor Create(GUID_DEVINTERFACE : TGUID);
property OnDeviceArrival: TDeviceNotifyProc read FDeviceArrival write FDeviceArrival;
property OnDeviceRemoval: TDeviceNotifyProc read FDeviceRemoval write FDeviceRemoval;
destructor Destroy; override;
end;
type
TForm17 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
DeviceNotifier : TDeviceNotifier;
public
{ Public declarations }
procedure arrival(Sender: TObject; const DeviceName: String);
end;
var
Form17: TForm17;
implementation
{$R *.dfm}
constructor TDeviceNotifier.Create(GUID_DEVINTERFACE : TGUID);
var
NotificationFilter: TDevBroadcastDeviceInterface;
begin
inherited Create;
hRecipient := AllocateHWnd(WndProc);
ZeroMemory(#NotificationFilter, SizeOf(NotificationFilter));
NotificationFilter.dbcc_size := SizeOf(NotificationFilter);
NotificationFilter.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
NotificationFilter.dbcc_classguid := GUID_DEVINTERFACE;
//register the device class to monitor
FNotificationHandle := RegisterDeviceNotification(hRecipient, #NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE);
end;
procedure TDeviceNotifier.WndProc(var Msg: TMessage);
var
Dbi: PDevBroadcastDeviceInterface;
begin
with Msg do
if (Msg = WM_DEVICECHANGE) and ((WParam = DBT_DEVICEARRIVAL) or (WParam = DBT_DEVICEREMOVECOMPLETE)) then
try
Dbi := PDevBroadcastDeviceInterface(LParam);
if Dbi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE then
begin
if WParam = DBT_DEVICEARRIVAL then
begin
if Assigned(FDeviceArrival) then
FDeviceArrival(Self, PChar(#Dbi.dbcc_name));
end
else
if WParam = DBT_DEVICEREMOVECOMPLETE then
begin
if Assigned(FDeviceRemoval) then
FDeviceRemoval(Self, PChar(#Dbi.dbcc_name));
end;
end;
except
Result := DefWindowProc(hRecipient, Msg, WParam, LParam);
end
else
Result := DefWindowProc(hRecipient, Msg, WParam, LParam);
end;
destructor TDeviceNotifier.Destroy;
begin
UnregisterDeviceNotification(FNotificationHandle);
DeallocateHWnd(hRecipient);
inherited;
end;
procedure TForm17.arrival(Sender: TObject; const DeviceName: String);
begin
ShowMessage(DeviceName);
end;
procedure TForm17.FormCreate(Sender: TObject);
const
GUID_DEVINTERFACE_COMPORT : TGUID = '{86E0D1E0-8089-11D0-9CE4-08003E301F73}';
begin
DeviceNotifier:=TDeviceNotifier.Create(GUID_DEVINTERFACE_COMPORT);
DeviceNotifier.FDeviceArrival:=arrival;
end;
procedure TForm17.FormDestroy(Sender: TObject);
begin
DeviceNotifier.Free;
end;
end.
Another option is use the WMI Events, on this case using the __InstanceCreationEvent Event and the Win32_PnPEntity WMI class you can filter the serial ports added using the {4d36e978-e325-11ce-bfc1-08002be10318} class GUID, writting a WQL sentence like so
Select * From __InstanceCreationEvent Within 1 Where TargetInstance ISA "Win32_PnPEntity" AND TargetInstance.ClassGuid="{4d36e978-e325-11ce-bfc1-08002be10318}"
Try this sample
{$APPTYPE CONSOLE}
{$R *.res}
uses
Windows,
{$IF CompilerVersion > 18.5}
Forms,
{$IFEND}
SysUtils,
ActiveX,
ComObj,
WbemScripting_TLB;
type
TWmiAsyncEvent = class
private
FWQL : string;
FSink : TSWbemSink;
FLocator : ISWbemLocator;
FServices : ISWbemServices;
procedure EventReceived(ASender: TObject; const objWbemObject: ISWbemObject; const objWbemAsyncContext: ISWbemNamedValueSet);
public
procedure Start;
constructor Create;
Destructor Destroy;override;
end;
//Detect when a key was pressed in the console window
function KeyPressed:Boolean;
var
lpNumberOfEvents : DWORD;
lpBuffer : TInputRecord;
lpNumberOfEventsRead : DWORD;
nStdHandle : THandle;
begin
Result:=false;
nStdHandle := GetStdHandle(STD_INPUT_HANDLE);
lpNumberOfEvents:=0;
GetNumberOfConsoleInputEvents(nStdHandle,lpNumberOfEvents);
if lpNumberOfEvents<> 0 then
begin
PeekConsoleInput(nStdHandle,lpBuffer,1,lpNumberOfEventsRead);
if lpNumberOfEventsRead <> 0 then
begin
if lpBuffer.EventType = KEY_EVENT then
begin
if lpBuffer.Event.KeyEvent.bKeyDown then
Result:=true
else
FlushConsoleInputBuffer(nStdHandle);
end
else
FlushConsoleInputBuffer(nStdHandle);
end;
end;
end;
{ TWmiAsyncEvent }
constructor TWmiAsyncEvent.Create;
const
strServer ='.';
strNamespace ='root\CIMV2';
strUser ='';
strPassword ='';
begin
inherited Create;
CoInitializeEx(nil, COINIT_MULTITHREADED);
FLocator := CoSWbemLocator.Create;
FServices := FLocator.ConnectServer(strServer, strNamespace, strUser, strPassword, '', '', wbemConnectFlagUseMaxWait, nil);
FSink := TSWbemSink.Create(nil);
FSink.OnObjectReady := EventReceived;
FWQL:='Select * From __InstanceCreationEvent Within 1 '+
'Where TargetInstance ISA "Win32_PnPEntity" AND TargetInstance.ClassGuid="{4d36e978-e325-11ce-bfc1-08002be10318}" ';
end;
destructor TWmiAsyncEvent.Destroy;
begin
if FSink<>nil then
FSink.Cancel;
FLocator :=nil;
FServices :=nil;
FSink :=nil;
CoUninitialize;
inherited;
end;
procedure TWmiAsyncEvent.EventReceived(ASender: TObject;
const objWbemObject: ISWbemObject;
const objWbemAsyncContext: ISWbemNamedValueSet);
var
PropVal: OLEVariant;
begin
PropVal := objWbemObject;
Writeln(Format('TargetInstance.ClassGuid : %s ',[String(PropVal.TargetInstance.ClassGuid)]));
Writeln(Format('TargetInstance.Description : %s ',[String(PropVal.TargetInstance.Description)]));
Writeln(Format('TargetInstance.Name : %s ',[String(PropVal.TargetInstance.Name)]));
Writeln(Format('TargetInstance.PNPDeviceID : %s ',[String(PropVal.TargetInstance.PNPDeviceID)]));
Writeln(Format('TargetInstance.Status : %s ',[String(PropVal.TargetInstance.Status)]));
end;
procedure TWmiAsyncEvent.Start;
begin
Writeln('Listening events...Press Any key to exit');
FServices.ExecNotificationQueryAsync(FSink.DefaultInterface,FWQL,'WQL', 0, nil, nil);
end;
var
AsyncEvent : TWmiAsyncEvent;
begin
try
AsyncEvent:=TWmiAsyncEvent.Create;
try
AsyncEvent.Start;
//The next loop is only necessary in this sample console sample app
//In VCL forms Apps you don't need use a loop
while not KeyPressed do
begin
{$IF CompilerVersion > 18.5}
Sleep(100);
Application.ProcessMessages;
{$IFEND}
end;
finally
AsyncEvent.Free;
end;
except
on E:EOleException do
Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode]));
on E:Exception do
Writeln(E.Classname, ':', E.Message);
end;
end.

Delphi 7: Handling events in console application (TidIRC)

I'm trying to make a console application based on Indy's IRC Component (TIdIRC) but I'm having trouble with events. Here's my code:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
Classes,
Math,
IdBaseComponent,
IdComponent,
IdTCPConnection,
IdTCPClient,
IdIRC;
type
TEvents = class
public
procedure Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
end;
const
IrcServ = 'gr.irc.gr';
IrcPort = 6667;
IrcChan = '#lalala';
var
Irc: TidIRC;
Event: TEvents;
uName, rName: string;
function Log(s: string): string;
var now: TDateTime;
begin
now := Time;
result := FormatDateTime('[hh:nn:ss] ', now) + s;
end;
procedure TEvents.Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
begin
Log(AUser.Nick+' '+ACommand+' '+AContent);
end;
begin
Event := TEvents.Create;
Irc := TidIRC.Create(nil);
Irc.OnRaw := Event.Raw;
Randomize;
Write('Nickname: ');
ReadLn(uName);
rName := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
with Irc do begin
AltNick := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
Nick := rName;
Username := rName;
RealName := 'I.D.M.';
Host := IrcHost;
Port := IrcPort;
//MaxLineAction := maException; <-- [ERROR] Undeclared identifier: 'maException'
ReadTimeout := 0;
UserMode := [];
Connect();
Join(IrcChan);
end;
ReadLn;
end.
I've tried so far everything i could think of, but, although the app is connected successfully, it won't return any raw message... What am i missing?
TdIRC uses an internal worker thread to receive data. The OnRaw event is triggered when that thread is parsing data. The thread uses TThread.Synchronize() to do that parsing. Since your main thread does not have an active VCL message loop, you can pump the Synchronize() queue manually. After you connect, call the CheckSynchronize() function from the Classes unit in a loop while you are connected to IRC, eg:
begin
...
Connect;
try
Join(IrcChan);
do
CheckSynchronize;
Sleep(10);
until SomeCondition;
finally
Disconnect;
end;
...
end.
For good measure, you can assign a handler to the WakeMainThread event in the Classes unit to help control when CheckSynchronize() should be called, so the main thread can go to sleep while the IRC connection is idle, eg:
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils,
Classes,
Math,
IdBaseComponent,
IdComponent,
IdTCPConnection,
IdTCPClient,
IdIRC;
type
TEvents = class
private
FSyncEvent: TEvent;
public
constructor Create;
destructor Destroy; override;
procedure Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
procedure Wake(Sender: TObject);
procedure CheckSync;
end;
function Log(s: string): string;
begin
result := FormatDateTime('[hh:nn:ss] ', Time) + s;
end;
constructor TEvents.Create;
begin
inherited;
FSyncEvent := TEvent.Create(nil, False, False, '');
end;
destructor TEvents.Destroy;
begin
FSyncEvent.Free;
inherited;
end;
procedure TEvents.Raw(Sender: TObject; AUser: TIdIRCUser; ACommand, AContent: String; var Suppress: Boolean);
begin
Log(AUser.Nick+' '+ACommand+' '+AContent);
end;
procedure TEvents.Wake(Sender: TObject);
begin
FSyncEvent.SetEvent;
end;
procedure TEvents.CheckSync;
begin
FSyncEvent.WaitFor(Infinite);
CheckSynchronize;
end;
const
IrcServ = 'gr.irc.gr';
IrcPort = 6667;
IrcChan = '#lalala';
var
Irc: TidIRC;
Event: TEvents;
uName, rName: string;
begin
Event := TEvents.Create;
try
WakeMainThread := Event.Wake;
Irc := TIdIRC.Create(nil);
try
Irc.OnRaw := Event.Raw;
Randomize;
Write('Nickname: ');
ReadLn(uName);
rName := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
with Irc do begin
AltNick := 'IDM' + IntToStr(RandomRange(1000, 9999)) + uName;
Nick := rName;
Username := rName;
RealName := 'I.D.M.';
Host := IrcHost;
Port := IrcPort;
//MaxLineAction := maException; <-- [ERROR] Undeclared identifier: 'maException'
ReadTimeout := 0;
UserMode := [];
Connect;
try
Join(IrcChan);
do
Event.CheckSync;
until SomeCondition;
finally
Disconnect;
end;
end;
finally
Irc.Free;
end;
finally
Event.Free;
end;
end.

Progressbar in splash while copying a file on program load

OK, here is the complete code for the Splashbar.pas, still have three progressbars, as I want to see what they look like before I choose one. It also includes some stuff that's disabled, as I can't get them to work.
unit Splashbar;
interface
uses ExtActns, Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls,
Buttons, ExtCtrls, AdvProgr, ComCtrls, NetAPI32, SHFolder, WinInet, ActnList,
AdvSmoothSplashScreen, AdvSmoothProgressBar, AdvSmoothProgressBarReg,
UTCT1b, GIFImg;
type
TSplashBar1 = class(TForm)
Bevel1: TBevel;
ProgressBar1: TProgressBar;
AdvProgress1: TAdvProgress;
Timer1: TTimer;
Label1: TLabel;
AdvSmoothProgressBar1: TAdvSmoothProgressBar;
ActionList1: TActionList;
DatabaseCopy: TAction;
procedure FormCreate(Sender: TObject);
procedure DatabaseCopyExecute(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private { Private declarations }
{ procedure URLOnDownloadProgress (Sender: TDownLoadURL;
Progress, ProgressMax: Cardinal;
StatusCode: TURLDownloadStatus;
StatusText: String; var Cancel: Boolean) ; }
public { Public declarations }
procedure OpenSplash;
procedure ShowProgress;
procedure CloseSplash;
end;
var
SplashBar1 : TSplashBar1;
dirpath: string;
Total: Integer;
Percent: Integer;
implementation
{$R *.dfm}
function GetSpecialFolderPath(folder : integer) : string;
const
SHGFP_TYPE_CURRENT = 0;
var
path: array [0..MAX_PATH] of char;
begin
if SUCCEEDED(SHGetFolderPath(0,folder,0,SHGFP_TYPE_CURRENT,#path[0])) then
Result := path
else
Result := '';
end;
function GetInetFile(const fileURL, FileName: String): boolean;
const BufferSize = 1024;
var
hSession, hURL: HInternet;
Buffer: array[1..BufferSize] of Byte;
BufferLen: DWORD;
f: File;
sAppName: string;
begin
Result:=False;
sAppName := ExtractFileName(Application.ExeName);
hSession := InternetOpen(PChar(sAppName),
INTERNET_OPEN_TYPE_PRECONFIG,
nil, nil, 0);
try
hURL := InternetOpenURL(hSession,
PChar(fileURL),
nil,0,0,0);
try
AssignFile(f, FileName);
Rewrite(f,1);
repeat
InternetReadFile(hURL, #Buffer,
SizeOf(Buffer), BufferLen);
BlockWrite(f, Buffer, BufferLen)
until BufferLen = 0;
CloseFile(f);
Result:=True;
finally
InternetCloseHandle(hURL)
end
finally
InternetCloseHandle(hSession)
end
end;
procedure TSplashBar1.FormCreate(Sender: TObject);
begin
Timer1.Enabled := True;
DatabaseCopy.Execute;
dirpath:=GetSpecialFolderPath($0023)+'\UTCT\';
end;
procedure TSplashBar1.DatabaseCopyExecute(Sender: TObject);
var
InternetFile,LocalFile: string;
begin
InternetFile:='http://160.14.20.20/log/Docs/test.xls';
LocalFile:=(dirpath + 'test.xls');
if GetInetFile(InternetFile,LocalFile)=True then
Label1.Caption := 'Working...';
//OnDownloadProgress := URLOnDownloadProgress;
//else
// StatusBar1.Panels[2].Text := 'MTable Offline!' ;
CopyFile(PChar(internetFile), PChar(LocalFile), False);
end;
procedure TSplashBar1.Timer1Timer(Sender: TObject);
const cnt: integer = 1;
begin
ProgressBar1.Position := cnt;
if cnt = 1 then Label1.Caption := 'Waiting...'
else
if cnt = 100 then begin
Label1.Caption := 'Done!';
Timer1.Enabled := False;
end
else begin
Label1.Caption := 'Working...';
end;
end;
procedure TSplashBar1.OpenSplash;
begin
Label1.Caption := '';
Show;
Update;
end;
procedure TSplashBar1.CloseSplash;
begin
Close;
end;
procedure TSplashBar1.ShowProgress;
var
xs: integer;
begin
Label1.caption:='';
Total := 1000;
for xs := 1 to Total do
begin
Sleep(5);
Percent := (xs * 100) div Total;
Label1.caption := StringOfChar('|', Percent) + IntToStr(Percent) + '%';
Label1.Repaint;
end;
end;
end.
// {procedure TSplashBar1.URLOnDownloadProgress;
// begin
// ProgressBar1.Max:= ProgressMax;
// ProgressBar1.Position:= Progress;
// AdvProgress1.Max:= ProgressMax;
// AdvProgress1.Position:= Progress;
// AdvSmoothProgressBar1.Position:= Progress;
//
// end; }
First error (W1056):
Make sure that
{$R *.RES}
is not entered twice in your dpr (Project|View Source)
Second error (H2077):
Somewhere else in your code, can't help with it
Third error (W1019):
You have to put
var
X: integer
right after
procedure TSplashBar1.ShowProgress;
You seem to have defined X somewhere other than the procedure, which the loop control variable error is indicating.
Did you include TSplashBar's unit in your .dpr file's 'uses' clause, and does it define a global SplashBar variable?

Resources