show information with Rolling / moving messages delphi xe7 - delphi

Good day sir/ma
i want to create a status bar with a rolling information like
Os version
current User Name
Date and time
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
tmr2: TTimer;
stsbr: TStatusBar;
procedure tmr2Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.tmr2Timer(Sender: TObject);
begin
if tmr2.Interval = 3000 then begin
stsbr.Panels[1].Text:= FormatDateTime('dddd' + ', ' + 'dd/mm/yyyy',date) + ', ' + TimeToStr(Time);
tmr2.Interval := 3001;
end else if tmr2.Interval = 3001 then begin
tmr2.Interval := 3002;
stsbr.Panels[1].Text:= 'PC Owner: '+GetUsersName+ ' - '+ GetLocalPCName;
end else if tmr2.Interval = 3002 then begin
tmr2.Interval := 3003;
stsbr.Panels[1].Text:= GetOSVersion;
end else if tmr2.Interval = 3003 then begin
tmr2.Interval := 3000;
stsbr.Panels[1].Text:= GetCPUName;
end;
procedure Form.FormCreate(Sender: TObject);
begin
tmr2Timer(Sender);
end;
end
.
that my full code
what i wanted to Achieve was a moving Information on a status bar
Please Help if u can
thanks..

You should not use Timer.Interval as lookout value to determine which data you should show in status bar. Use separate variable to do that. It will make your code cleaner.
unit Unit1;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, System.Win.Registry,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.ComCtrls, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
tmr2: TTimer;
stsbr: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure tmr2Timer(Sender: TObject);
private
status: integer;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetUsersName: string;
var
Buf: array [0 .. MAX_PATH] of Char;
BufSize: longword;
begin
Buf[0] := #$00;
BufSize := MAX_PATH;
if Winapi.Windows.GetUserName(Buf, BufSize) then Result := Buf
else Result := '';
end;
function GetLocalPCName: string;
var
Buf: array [0 .. MAX_COMPUTERNAME_LENGTH] of Char;
BufSize: longword;
begin
Buf[0] := #$00;
BufSize := MAX_COMPUTERNAME_LENGTH;
if Winapi.Windows.GetComputerName(Buf, BufSize) then Result := Buf
else Result := '';
end;
function GetOSVersion: string;
begin
Result := TOSVersion.ToString;
end;
function GetCPUName: string;
var
Reg: TRegistry;
begin
Result := '';
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKeyReadOnly('\Hardware\Description\System\CentralProcessor\0') then
begin
Result := Reg.ReadString('ProcessorNameString');
Reg.CloseKey;
end;
finally
Reg.Free;
end;
end;
procedure TForm1.tmr2Timer(Sender: TObject);
begin
case status of
0 : stsbr.Panels[1].Text:= FormatDateTime('dddd' + ', ' + 'dd/mm/yyyy',date) + ', ' + TimeToStr(Time);
1 : stsbr.Panels[1].Text:= 'PC Owner: ' + GetUsersName + ' - ' + GetLocalPCName;
2 : stsbr.Panels[1].Text:= GetOSVersion;
else stsbr.Panels[1].Text:= GetCPUName;
end;
inc(status);
if status > 3 then status := 0;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
status := 0;
// this property can also be set through IDE form designer
tmr2.Enabled := true;
// show initial status data
tmr2Timer(Sender);
end;
end.

Related

Processing Server data

I have an Indy TCPServer that connects a device with several clients.
When device-data arrives, the server sends it to every client.
When client-data arrives, it is sent to the device. (And the device will send it to the server again (echo)).
I only process 2 bytes per cycle.
The above works perfect.
Now i want to process/save that data.
Only when data arrives via the device port, i want to 'Translate' the data.
I need to save the data to a clientdatset.
Then i want to take the bytes apart and compare them with som other info
...
The translated data is also saved in another clientdataset.
unit BusServer;
interface
uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Classes, System.Variants,
Vcl.Graphics, Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs,
IdContext, IdAntiFreezeBase, IdAntiFreeze, IdBaseComponent, IdComponent,
IdCustomTCPServer, IdTCPServer,
Data.DB, Datasnap.DBClient;
type
TBus_Server = class(TService)
tcpBusDataServer: TIdTCPServer;
IdAntiFreeze1: TIdAntiFreeze;
cdsBusMonitor: TClientDataSet;
cdsBusMonitorNr: TIntegerField;
cdsBusMonitorDate: TStringField;
cdsBusMonitorTime: TStringField;
cdsBusMonitorAad: TIntegerField;
cdsBusMonitorAgr: TIntegerField;
cdsBusMonitorAName: TStringField;
cdsBusMonitorAFct: TStringField;
cdsBusMonitorOrigin: TStringField;
cdsIncoming: TClientDataSet;
cdsMemberState: TClientDataSet;
cdsMemberStateMemberID: TStringField;
cdsMemberStateState: TStringField;
cdsMemberStateDateTime: TDateTimeField;
cdsMemberStateTotaal: TFloatField;
procedure tcpBusDataServerExecute(AContext: TIdContext);
procedure ServiceCreate(Sender: TObject);
private
{ Private declarations }
functionmon: String;
DevicePort: Integer;
ClientPort: Integer;
ClientLSB, ClientMSB: Byte;
DeviceLSB, DeviceMSB: Byte;
FunctionList: TStringList;
procedure TranslateData;
function CodeValue: String;
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;
var
Bus_Server: TBus_Server;
implementation
uses
CodesiteLogging;
{$R *.dfm}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
Bus_Server.Controller(CtrlCode);
end;
function TBus_Server.CodeValue: String;
begin
if (cdsIncoming.FieldbyName('MemberType').AsInteger = 11) or
(cdsIncoming.FieldbyName('MemberType').AsInteger = 22)or
(cdsIncoming.FieldbyName('MemberType').AsInteger = 33) then
begin
Result := FunctionMon
end
else
begin
// TODO:
end
end;
function TBus_Server.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
procedure TBus_Server.ServiceCreate(Sender: TObject);
var
DataSetName: String;
begin
DevicePort := 10001;
ClientPort := 10012;
tcpBusDataServer.Bindings.Clear;
tcpBusDataServer.Bindings.Add.Port := DevicePort;
tcpBusDataServer.Bindings.Add.Port := ClientPort;
tcpBusDataServer.Active := True;
FunctionList := TStringList.Create;
FunctionList.Add('Null');
FunctionList.Add('Reset');
FunctionList.Add('Toggle');
FunctionList.Add('Set');
FunctionList.Add('Misc');
FunctionList.Add('Status');
FunctionList.Add('Timer/Direct');
FunctionList.Add('Value');
FunctionList.Add('Dimmer');
FunctionList.Add('Readout');
FunctionList.Add('Teller');
FunctionList.Add('System');
FunctionList.Add('Settings');
FunctionList.Add('Select');
FunctionList.Add('Data');
FunctionList.Add('Program');
ForceDirectories('c:\Test\');
DataSetName := 'c:\Test\BusMonitor' + FormatDateTime('YYYY-MM-DD', Now) + '.xml';
if cdsBusMonitor.Active then
cdsBusMonitor.Close;
cdsBusMonitor.Filename := DataSetName;
if not System.SysUtils.FileExists(DataSetName) then
begin
cdsBusMonitor.CreateDataSet;
cdsBusMonitor.SaveToFile
end;
DataSetName := 'c:\Test\MemberState' + FormatDateTime('YYYY-MM-DD', Now) + '.xml';
if cdsMemberState.Active then
cdsMemberState.Close;
cdsMemberState.Filename := DataSetName;
if not System.SysUtils.FileExists(DataSetName) then
begin
cdsMemberState.CreateDataSet;
cdsMemberState.SaveToFile
end;
end;
procedure TBus_Server.tcpBusDataServerExecute(AContext: TIdContext);
var
Ctx: TIdContext;
List: TList;
begin
if AContext.Binding.Port = ClientPort then // Client
begin
DeviceLSB := AContext.Connection.IOHandler.ReadByte;
DeviceMSB := AContext.Connection.IOHandler.ReadByte;
List := tcpBusDataServer.Contexts.LockList;
try
for var i := 0 to List.count - 1 do
begin
Ctx := TIdContext(List[I]);
if (Ctx <> AContext) and (Ctx.Binding.Port = DevicePort) then
begin
Ctx.Connection.IOHandler.Write(DeviceLSB);
Ctx.Connection.IOHandler.Write(DeviceMSB);
// Since only 1 has to be written to
Break
end
end
finally
tcpBusDataServer.Contexts.UnlockList
end
end
else
begin
if AContext.Binding.Port = DevicePort then // Device
begin
ClientLSB := AContext.Connection.IOHandler.ReadByte;
ClientMSB := AContext.Connection.IOHandler.ReadByte;
List := tcpBusDataServer.Contexts.LockList;
try
for var i := 0 to List.count - 1 do
begin
Ctx := TIdContext(List[I]);
if (Ctx <> AContext) and (Ctx.Binding.Port = ClientPort) then
begin
Ctx.Connection.IOHandler.Write(ClientLSB);
Ctx.Connection.IOHandler.Write(ClientMSB)
end
end
finally
TIdNotify.NotifyMethod(TranslateData);
tcpBusDataServer.Contexts.UnlockList
end
end
end
end;
procedure TBus_Server.TranslateData;
const {$J+}
LastSave: TDateTime = 0;
type
TProgramState = (psNone,psProgram,psIgnore1,psIgnore2);
const
ProgramState: TProgramState = psNone;
const
ValueMode: Boolean = False;
var
i: Integer;
fct: Integer;
GroupMon: Integer;
AddressMon: Integer;
CorrecteSettings: Boolean;
TmpStr: String;
begin
fct := 0;
// Functie uit MSB halen
if ClientMSB >= 128 then
begin
ClientMSB := ClientMSB - 128;
fct := 8
end;
if ClientMSB >= 64 then
begin
ClientMSB := ClientMSB - 64;
fct := fct + 4
end;
if ClientMSB >= 32 then
begin
ClientMSB := ClientMSB - 32;
fct := fct + 2
end;
if ClientMSB >= 16 then
begin
ClientMSB := ClientMSB - 16;
fct := fct + 1
end;
// Variabelen voor monitor bepalen
functionMon := FunctionList[fct];
if cdsBusMonitor.Active then
begin
cdsBusMonitor.Filtered := False;
cdsBusMonitor.Append;
cdsBusMonitor.FieldByName('Nr').AsInteger := cdsBusMonitor.RecordCount + 1;
cdsBusMonitor.FieldByName('AFct').Asstring := functionMon;
cdsBusMonitor.FieldByName('Aad').AsInteger := ClientLSB;
cdsBusMonitor.FieldByName('Agr').AsInteger := ClientMSB;
cdsBusMonitor.FieldByName('Time').Asstring := TimeToStr(Now);
cdsBusMonitor.FieldByName('Origin').AsString := 'Van de Bus: '{ + UserPeerIP};
cdsBusMonitor.Post;
end;
if ProgramState = psNone then
begin
CodeSite.Send('New situation...');
try
if cdsIncoming.Locate('Group;Address', VarArrayOf([IntToStr(DeviceMsb),IntToStr(DeviceLsb)]), []) then
begin
CodeSite.Send('After locate...');
if cdsMemberState.Locate('MemberID', cdsIncoming.FieldByName('MemberID').AsString, []) then
cdsMemberState.Edit
else
cdsMemberState.Append;
if cdsMemberStateState.AsString = Codevalue then
begin
CodeSite.Send('New state ' + Codevalue + ' already known');
cdsMemberState.Cancel
end
else
begin
CodeSite.Send('New state ' + Codevalue);
cdsMemberStateState.AsString := Codevalue;
if Codevalue.ToLower = 'reset' then
cdsMemberStateTotaal.AsFloat := cdsMemberStateTotaal.AsFloat + (Now - cdsMemberStateDateTime.AsDateTime);
cdsMemberStateDateTime.AsDateTime := Now;
cdsMemberState.Post
end
end
else
CodeSite.SendError('ServerMethodsBServer.cdsIncoming Locate Fail');
except
on E: Exception do
CodeSite.SendException(E);
end
end;
if ((cdsBusMonitor.RecordCount mod 100) = 0) or ((Now - LastSave) > (1/24/60)) then
begin
LastSave := Now;
cdsBusMonitor.MergeChangeLog;
cdsBusMonitor.SaveToFile;
cdsMemberState.MergeChangeLog;
cdsMemberState.SaveToFile
end
end;
In the clientdataset, i occasionally see "wrong data", meaning:
First i have a correct record, followed by a record with the same lsb and a wrong msb.
I split up the msb in the procedure(Translatedata) in a 'high nibble' and a 'low nibble'.
So now i'm trying to find out where this comes from.
As you can see in my code i call the procedure via TIdNotify.NotifyMethod(TranslateData);
Is this te correct way?
Could appending/posting data in a clientdataset (whilst in the serverthread) be a problem?
Is this a timing issue?
Has anyone an idea of what could be wrong?
Your code is not very thread-safe. You are not protecting your data values from concurrent access across thread boundaries, if multiple clients send data to the server at the same time.
Also, you should not be doing all of your service initializations in the OnCreate event, use the OnStart event instead. The OnCreate event is triggered whenever your TService object is created for any reason, which includes not only running the service, but also (un)installing the service.
Try something more like this:
unit BusServer;
interface
uses
Winapi.Windows, Winapi.Messages,
System.SysUtils, System.Classes, System.Variants,
Vcl.Graphics, Vcl.Controls, Vcl.SvcMgr, Vcl.Dialogs,
IdContext, IdBaseComponent, IdComponent,
IdCustomTCPServer, IdTCPServer, IdThreadSafe,
Data.DB, Datasnap.DBClient, System.SyncObjs;
type
TBus_Server = class(TService)
tcpBusDataServer: TIdTCPServer;
cdsBusMonitor: TClientDataSet;
cdsBusMonitorNr: TIntegerField;
cdsBusMonitorDate: TStringField;
cdsBusMonitorTime: TStringField;
cdsBusMonitorAad: TIntegerField;
cdsBusMonitorAgr: TIntegerField;
cdsBusMonitorAName: TStringField;
cdsBusMonitorAFct: TStringField;
cdsBusMonitorOrigin: TStringField;
cdsIncoming: TClientDataSet;
cdsMemberState: TClientDataSet;
cdsMemberStateMemberID: TStringField;
cdsMemberStateState: TStringField;
cdsMemberStateDateTime: TDateTimeField;
cdsMemberStateTotaal: TFloatField;
procedure tcpBusDataServerExecute(AContext: TIdContext);
procedure ServiceStart(Sender: TObject; var Started: Boolean);
procedure ServiceStop(Sender: TObject; var Stopped: Boolean);
procedure ServiceShutdown(Sender: TObject);
private
{ Private declarations }
FunctionMon: TIdThreadSafeString;
DevicePort: Integer;
ClientPort: Integer;
DeviceLSB, DeviceMSB: Byte;
DeviceDataLock: TCriticalSection;
FunctionList: TStringList;
procedure TranslateData(ClientLSB, ClientMSB: Byte);
function CodeValue: String;
public
function GetServiceController: TServiceController; override;
{ Public declarations }
end;
var
Bus_Server: TBus_Server;
implementation
uses
CodesiteLogging;
{$R *.dfm}
procedure ServiceController(CtrlCode: DWord); stdcall;
begin
Bus_Server.Controller(CtrlCode);
end;
function TBus_Server.CodeValue: String;
begin
case cdsIncoming.FieldByName('MemberType').AsInteger of
11, 22, 33: begin
Result := FunctionMon.Value;
end;
else
// TODO
Result := '';
end;
end;
function TBus_Server.GetServiceController: TServiceController;
begin
Result := ServiceController;
end;
procedure TBus_Server.ServiceStart(Sender: TObject; var Started: Boolean);
var
DataSetName: String;
begin
DevicePort := 10001;
ClientPort := 10012;
DeviceDataLock := TCriticalSection.Create;
FunctionMon := TIdThreadSafeString.Create;
FunctionList := TStringList.Create;
FunctionList.Add('Null');
FunctionList.Add('Reset');
FunctionList.Add('Toggle');
FunctionList.Add('Set');
FunctionList.Add('Misc');
FunctionList.Add('Status');
FunctionList.Add('Timer/Direct');
FunctionList.Add('Value');
FunctionList.Add('Dimmer');
FunctionList.Add('Readout');
FunctionList.Add('Teller');
FunctionList.Add('System');
FunctionList.Add('Settings');
FunctionList.Add('Select');
FunctionList.Add('Data');
FunctionList.Add('Program');
ForceDirectories('c:\Test\');
DataSetName := 'c:\Test\BusMonitor' + FormatDateTime('YYYY-MM-DD', Now) + '.xml';
if cdsBusMonitor.Active then
cdsBusMonitor.Close;
cdsBusMonitor.Filename := DataSetName;
if not System.SysUtils.FileExists(DataSetName) then
begin
cdsBusMonitor.CreateDataSet;
cdsBusMonitor.SaveToFile;
end;
DataSetName := 'c:\Test\MemberState' + FormatDateTime('YYYY-MM-DD', Now) + '.xml';
if cdsMemberState.Active then
cdsMemberState.Close;
cdsMemberState.Filename := DataSetName;
if not System.SysUtils.FileExists(DataSetName) then
begin
cdsMemberState.CreateDataSet;
cdsMemberState.SaveToFile;
end;
tcpBusDataServer.Bindings.Clear;
tcpBusDataServer.Bindings.Add.Port := DevicePort;
tcpBusDataServer.Bindings.Add.Port := ClientPort;
tcpBusDataServer.Active := True;
Started := True;
end;
procedure TBus_Server.ServiceStop(Sender: TObject; var Stopped: Boolean);
begin
ServiceShutdown(Sender);
Stopped := True;
end;
procedure TBus_Server.ServiceShutdown(Sender: TObject);
begin
tcpBusDataServer.Active := False;
cdsBusMonitor.Close;
cdsMemberState.Close;
DeviceDataLock.Free;
FunctionMon.Free;
FunctionList.Free;
end;
procedure TBus_Server.tcpBusDataServerExecute(AContext: TIdContext);
var
LSB, MSB: Byte;
List: TList;
Ctx: TIdContext;
begin
LSB := AContext.Connection.IOHandler.ReadByte;
MSB := AContext.Connection.IOHandler.ReadByte;
if AContext.Binding.Port = ClientPort then // Client
begin
DeviceDataLock.Enter;
try
DeviceLSB := LSB;
DeviceMSB := MSB;
finally
DeviceDataLock.Leave;
end;
List := tcpBusDataServer.Contexts.LockList;
try
for var i := 0 to List.count - 1 do
begin
Ctx := TIdContext(List[I]);
if (Ctx <> AContext) and (Ctx.Binding.Port = DevicePort) then
begin
Ctx.Connection.IOHandler.Write(LSB);
Ctx.Connection.IOHandler.Write(MSB);
// Since only 1 has to be written to
Break;
end;
end;
finally
tcpBusDataServer.Contexts.UnlockList;
end;
end
else if AContext.Binding.Port = DevicePort then // Device
begin
List := tcpBusDataServer.Contexts.LockList;
try
for var i := 0 to List.count - 1 do
begin
Ctx := TIdContext(List[I]);
if (Ctx <> AContext) and (Ctx.Binding.Port = ClientPort) then
begin
Ctx.Connection.IOHandler.Write(LSB);
Ctx.Connection.IOHandler.Write(MSB)
end;
end
finally
tcpBusDataServer.Contexts.UnlockList;
TThread.Queue(nil,
procedure
begin
TranslateData(LSB, MSB);
end
);
end;
end;
end;
procedure TBus_Server.TranslateData(ClientLSB, ClientMSB: Byte);
const {$J+}
LastSave: TDateTime = 0;
type
TProgramState = (psNone,psProgram,psIgnore1,psIgnore2);
const
ProgramState: TProgramState = psNone;
const
ValueMode: Boolean = False;
var
i: Integer;
fct: Integer;
GroupMon: Integer;
AddressMon: Integer;
CorrecteSettings: Boolean;
TmpFunc, TmpCodeValue: string;
TmpDeviceLSB, TmpDeviceMSB: Byte;
begin
fct := 0;
// Functie uit MSB halen
if ClientMSB >= 128 then
begin
Dec(ClientMSB, 128);
fct := 8;
end;
if ClientMSB >= 64 then
begin
Dec(ClientMSB, 64);
Inc(fct, 4);
end;
if ClientMSB >= 32 then
begin
Dec(ClientMSB, 32);
Inc(fct, 2);
end;
if ClientMSB >= 16 then
begin
Dec(ClientMSB, 16);
Inc(fct, 1);
end;
// Variabelen voor monitor bepalen
TmpFunc := FunctionList[fct];
FunctionMon.Value := TmpFunc;
if cdsBusMonitor.Active then
begin
cdsBusMonitor.Filtered := False;
cdsBusMonitor.Append;
try
cdsBusMonitor.FieldByName('Nr').AsInteger := cdsBusMonitor.RecordCount + 1;
cdsBusMonitor.FieldByName('AFct').Asstring := TmpFunc;
cdsBusMonitor.FieldByName('Aad').AsInteger := ClientLSB;
cdsBusMonitor.FieldByName('Agr').AsInteger := ClientMSB;
cdsBusMonitor.FieldByName('Time').AsString := TimeToStr(Now);
cdsBusMonitor.FieldByName('Origin').AsString := 'Van de Bus: '{ + UserPeerIP};
cdsBusMonitor.Post;
except
cdsBusMonitor.Cancel;
raise;
end;
end;
if ProgramState = psNone then
begin
CodeSite.Send('New situation...');
try
DeviceDataLock.Enter;
try
TmpDeviceLSB := DeviceLSB;
TmpDeviceMSB := DeviceMSB;
finally
DeviceDataLock.Leave;
end;
if cdsIncoming.Locate('Group;Address', VarArrayOf([IntToStr(TmpDeviceMSB),IntToStr(TmpDeviceLSB)]), []) then
begin
CodeSite.Send('After locate...');
if cdsMemberState.Locate('MemberID', cdsIncoming.FieldByName('MemberID').AsString, []) then
cdsMemberState.Edit
else
cdsMemberState.Append;
try
TmpCodeValue := CodeValue;
if cdsMemberStateState.AsString = TmpCodeValue then
begin
CodeSite.Send('New state ' + TmpCodeValue + ' already known');
cdsMemberState.Cancel;
end
else
begin
CodeSite.Send('New state ' + TmpCodeValue);
cdsMemberStateState.AsString := TmpCodeValue;
if TmpCodeValue = 'Reset' then
cdsMemberStateTotaal.AsFloat := cdsMemberStateTotaal.AsFloat + (Now - cdsMemberStateDateTime.AsDateTime);
cdsMemberStateDateTime.AsDateTime := Now;
cdsMemberState.Post;
end;
except
cdsMemberState.Cancel;
raise;
end;
end
else
CodeSite.SendError('ServerMethodsBServer.cdsIncoming Locate Fail');
except
on E: Exception do
CodeSite.SendException(E);
end
end;
if ((cdsBusMonitor.RecordCount mod 100) = 0) or ((Now - LastSave) > (1/24/60)) then
begin
LastSave := Now;
cdsBusMonitor.MergeChangeLog;
cdsBusMonitor.SaveToFile;
cdsMemberState.MergeChangeLog;
cdsMemberState.SaveToFile;
end;
end;

Delphi Open two files and re size whatever application they open in so they fit in the screen 50% 50%

If you have two random files e.g. .txt, .csv, .jpg, and you wanted to open two of them and make them take up the screen 50% 50%.
How would you find the window handle that was opened so that you can re size the right one?
I have edited below to be closer to the answer thanks to suggestions from David Heffernan and Rob Kennedy
The code below kind of works if everything goes right but i'm sure there are ways to improve the code.
Using ShellExecuteEx can return a process ID, you can get a window handle off the process ID by using EnumWindows checking against the process id. Then if everything works you can re size the form using MoveWindow
i have an example in the unit uFileStuff below
There are a few issues that i'm not sure can be resolved
Files can be opened in the same application e.g. notepad++.
ShellExecuteEx may not return a process id
EnumWindows may not find the window
Unit uFileStuff
unit uFileStuff;
interface
uses Winapi.Windows, System.SysUtils, Generics.Collections, shellapi, Winapi.Messages, Vcl.Dialogs, Vcl.Forms;
type
PWindowSearch = ^TWindowSearch;
TWindowSearch = record
TargetProcessID: DWord;
ResultList: TList<HWnd>;
end;
TMyFile = class
private
sFileNameAndPath : String;
MyProcessID : DWord;
MyParentProcessID : Dword;
Procedure OpenFile(sFile: String);
procedure UpdateWindowListByProcessID;
public
WindowsLinkedToProcessID : TList<HWnd>;
function GetWindowInformation(Wnd: HWnd) : String;
function GetAllWindowInformation : String;
property ProcessID : Dword read MyProcessID;
property ParentProcessID : Dword read MyParentProcessID;
constructor Create(sFile : String);
destructor Destroy; override;
end;
implementation
constructor TMyFile.Create(sFile: String);
begin
MyProcessID := 0;
MyParentProcessID := 0;
sFileNameAndPath := sFile;
WindowsLinkedToProcessID := TList<HWnd>.Create;
if (sFile <> '') and FileExists(sFile) then
OpenFile(sFileNameAndPath);
end;
destructor TMyFile.Destroy;
begin
WindowsLinkedToProcessID.Free;
Inherited;
end;
function TMyFile.GetAllWindowInformation: String;
var i : Integer;
sMessage : String;
begin
result := '';
for I := 0 to WindowsLinkedToProcessID.Count -1 do begin
sMessage := sMessage + #13#10 + GetWindowInformation(WindowsLinkedToProcessID[i]);
end;
result := result + sMessage;
end;
function TMyFile.GetWindowInformation(Wnd: HWnd): String;
var Buffer: array[0..255] of char;
begin
result := inttostr(Wnd);
SendMessage(Wnd, WM_GETTEXT, 255, LongInt(#Buffer[0]));
if Buffer <> '' then begin
result := result + ', ' + Buffer;
end;
end;
procedure TMyFile.OpenFile(sFile: String);
var i : Integer;
SEInfo: TShellExecuteInfo;
ExitCode: DWORD;
ExecuteFile, ParamString, StartInString, sMessage: string;
begin
ExecuteFile:=sFile;
FillChar(SEInfo, SizeOf(SEInfo), 0);
SEInfo.cbSize := SizeOf(TShellExecuteInfo);
with SEInfo do
begin
fMask := SEE_MASK_NOCLOSEPROCESS;
Wnd := Application.Handle;
lpFile := PChar(sFile);
nShow := SW_SHOWNORMAL;
end;
if ShellExecuteEx(#SEInfo) then
begin
if SEInfo.hProcess > 0 then begin
Sleep(100);
WaitForInputIdle(SEInfo.hProcess, 10000 );
MyProcessID := GetProcessId( SEInfo.hProcess );
UpdateWindowListByProcessID;
end else begin
ShowMessage('No Process ' + SysErrorMessage(GetLastError) );
end;
end else
ShowMessage('Error starting "'+ sFile +'"' + #13#10 + SysErrorMessage(GetLastError));
end;
procedure TMyFile.UpdateWindowListByProcessID;
function SelectWindowByProcessID(Wnd: HWnd; Param: LParam): Bool; stdcall;
var
pSearchRec: PWindowSearch;
WindowPid: DWord;
begin
pSearchRec := PWindowSearch(Param);
Assert(Assigned(pSearchRec));
GetWindowThreadProcessID(Wnd, WindowPid);
if (WindowPid = pSearchRec.TargetProcessID) and IsWindowVisible(Wnd) then
pSearchRec.ResultList.Add(Wnd);
Result := True;
end;
var
SearchRec: TWindowSearch;
begin
if MyProcessID > 0 then begin
SearchRec.TargetProcessID := MyProcessID;
SearchRec.ResultList := WindowsLinkedToProcessID;
EnumWindows(#SelectWindowByProcessID, LParam(#SearchRec));
end;
end;
end.
Form Creating Files on create - has button to open them
unit fFileOpen;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TfrmFileOpen = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
sApplicationPath : String;
sFile1, sFile2 : String;
public
{ Public declarations }
end;
var
frmFileOpen: TfrmFileOpen;
implementation
uses uFileStuff;
{$R *.dfm}
procedure TfrmFileOpen.btn1Click(Sender: TObject);
var File1 : TMyFile;
File2 : TMyFile;
begin
File1 := TMyFile.Create( sFile1 );
try
if sFile2 <> sFile1 then
File2 := TMyFile.Create( sFile2 )
else
File2 := TMyFile.Create( '' );
try
if (File1.ProcessID > 0) and (File2.ProcessID > 0) then begin
if (File1.ParentProcessID > 0) and (File2.ParentProcessID > 0) and (File1.ParentProcessID = File2.ParentProcessID) then begin
showmessage('Both Files opened in same process');
end else if (File1.WindowsLinkedToProcessID.Count > 0) and (File2.WindowsLinkedToProcessID.Count > 0) then begin
if File1.WindowsLinkedToProcessID.Count > 1 then
ShowMessage('Warning returned more than 1 window Moving the first window' + #13#10 + File1.GetAllWindowInformation);
MoveWindow(File1.WindowsLinkedToProcessID[0], 0, 0, Trunc(Screen.WorkAreaWidth / 2), Screen.WorkAreaHeight, True);
if File2.WindowsLinkedToProcessID.Count > 1 then
ShowMessage('Warning returned more than 1 window Moving the first window' + #13#10 + File2.GetAllWindowInformation);
MoveWindow(File2.WindowsLinkedToProcessID[0], Round(Screen.WorkAreaWidth / 2)+1, 0, Trunc(Screen.WorkAreaWidth / 2), Screen.WorkAreaHeight, True);
end;
end;
finally
File2.Free;
end;
finally
File1.Free;
end;
end;
procedure TfrmFileOpen.FormCreate(Sender: TObject);
var slTemp : TStringList;
img : TBitmap;
begin
ReportMemoryLeaksOnShutdown := true;
sApplicationPath := ExtractFileDir(application.ExeName);
sFile1 := IncludeTrailingPathDelimiter( sApplicationPath ) + 'File1.txt';
sFile2 := IncludeTrailingPathDelimiter( sApplicationPath ) + 'File2.csv';
{
if not FileExists( sFile1 ) then begin
img := TBitmap.Create;
img.SetSize(300,300);
img.SaveToFile( sFile1 );
img.Free;
end; }
if not FileExists(sFile1) then begin
slTemp := TStringList.Create;
slTemp.Add('File1');
slTemp.SaveToFile(sFile1);
slTemp.Free;
end;
if not FileExists(sFile2) then begin
slTemp := TStringList.Create;
slTemp.Add('File2');
slTemp.SaveToFile(sFile2);
slTemp.Free;
end;
end;
end.

Displaying value by value in a threaded binary tree using a "Next" button with a recursive inorder traversal

As the title states, having a bit of trouble mostly with the algorithm. I have the algorithm down to parse through and print ALL the values, but I need to be able to stop on each value and display it in a label. I tried using a global variable 'count', thinking I may be able to stop it. Any ideas? This is what I have so far:
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm4 = class(TForm)
Createtree: TButton;
Current: TLabel;
RecursiveNext: TButton;
Close: TButton;
IterativeNext: TButton;
Iterative: TLabel;
procedure CloseClick(Sender: TObject);
procedure CreatetreeClick(Sender: TObject);
procedure RecursiveNextClick(Sender: TObject);
procedure IterativeNextClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
nodeptr = ^nodetype;
nodetype = record
id : integer ;
left,right : nodeptr ;
threaded : Boolean;
end;
var
Form4: TForm4;
inf : textfile;
root,c : nodeptr;
count : integer;
implementation
{$R *.dfm}
function Emptytree(var root : nodeptr) : Boolean;
begin
Result := False;
if root^.id <> NULL then Result := True;
end;
procedure TForm4.CloseClick(Sender: TObject);
begin
application.Terminate;
end;
function recursiveinorder(c : nodeptr) : integer;
begin
if c^.left <> nil then recursiveinorder(c^.left);
Result := c^.id;
if (c^.right <> nil) and (count > 0) then recursiveinorder(c^.right);
count := count - 1;
end;
function iterativeinorder(c : nodeptr) : integer;
var done : boolean;
begin
c := root;
while c <> nil do c := c^.left;
begin
done := false;
while done = False do
begin
Result := c^.id;
if (c^.threaded = false) and (count > 0) then
begin
c := c^.right;
done := true;
end
else
begin
c := c^.right;
if c = nil then done := true;
end;
end;
end;
count := count - 1;
end;
procedure TForm4.CreatetreeClick(Sender: TObject);
var
parent, knew, c : nodeptr;
begin
count := 0;
new(parent);
new(c);
new(root);
assignfile(inf, 'treedata.txt');
reset(inf);
readln(inf,root^.id);
while not eof(inf) do
begin
new(knew);
readln(inf,knew^.id);
if not Emptytree(root) then
begin
c:= root;
while c <> nil do
begin
parent := c;
if knew^.id < c^.id then
c:=c^.left
else c:= c^.right;
end;
if knew^.id < parent^.id then
begin
parent^.left := knew;
knew^.threaded := True;
knew^.right := parent;
end
else begin
knew^.right := parent^.right;
knew^.threaded := parent^.threaded;
parent^.right := knew;
parent^.threaded := false;
end;
end;
if Emptytree(root) then root := knew;
end;
end;
procedure TForm4.IterativeNextClick(Sender: TObject);
begin
count := count + 1;
Iterative.Caption := inttostr(iterativeinorder(root));
end;
procedure TForm4.RecursiveNextClick(Sender: TObject);
begin
count := count + 1;
Current.Caption := inttostr(recursiveinorder(root));
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?

delphi idhttp post related question

im new to delphi. and also almost new to programming world.
i was made some simple post software which using idhttp module.
but when execute it , it not correctly working.
this simple program is check for my account status.
if account login successfully it return some source code which include 'top.location ='
in source, and if login failed it return not included 'top.location ='
inside account.txt is follow first and third account was alived account
but only first account can check, after first account other account can't check
i have no idea what wrong with it
ph896011 pk1089
fsadfasdf dddddss
ph896011 pk1089
following is source of delphi
if any one help me much apprecated!
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, IdHTTP, IdCookieManager, ExtCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
IdHTTP1: TIdHTTP;
Memo1: TMemo;
IdCookieManager1: TIdCookieManager;
lstAcct: TListBox;
result: TLabel;
Edit1: TEdit;
Timer1: TTimer;
procedure Button1Click(Sender: TObject);
//procedure FormCreate(Sender: TObject);
//procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
AccList: TStringList;
IdCookie: TIdCookieManager;
CookieList: TList;
StartCnt: Integer;
InputCnt: Integer;
WordList: TStringList;
WordNoList: TStringList;
WordCntList: TStringList;
StartTime: TDateTime;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
//temp: String;
lsttemp: TStringList;
sl : tstringlist;
//userId,userPass: string;
begin
InputCnt:= 0;
WordList := TStringList.Create;
CookieList := TList.create;
IdCookie := TIdCookieManager.Create(self);
if FileExists(ExtractFilePath(Application.ExeName) + 'account.txt') then
WordList.LoadFromFile(ExtractFilePath(Application.ExeName) + 'account.txt');
WordNoList:= TStringList.Create;
WordCntList := TStringList.Create;
lsttemp := TStringList.create;
sl :=Tstringlist.Create;
try
try
for i := 0 to WordList.Count -1 do
begin
ExtractStrings([' '], [' '], pchar(WordList[i]), lsttemp);
WordNoList.add(lsttemp[0]);
//ShowMessage(lsttemp[0]);
WordCntList.add(lsttemp[1]);
//ShowMessage(lsttemp[1]);
sl.Add('ID='+ lsttemp[0]);
sl.add('PWD=' + lsttemp[1]);
sl.add('SECCHK=0');
IdHTTP1.HandleRedirects := True;
IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded';
memo1.Text:=idhttp1.Post('http://user.buddybuddy.co.kr/Login/Login.asp',sl);
if pos('top.location =',Memo1.Text)> 0 then
begin
application.ProcessMessages;
ShowMessage('Alive Acc!');
//result.Caption := 'alive acc' ;
sleep(1000);
Edit1.Text := 'alive acc';
lsttemp.Clear;
Memo1.Text := '';
//memo1.Text := IdHTTP1.Get('https://user.buddybuddy.co.kr/Login/Logout.asp');
Sleep(1000);
end;
if pos('top.location =', memo1.Text) <> 1 then
begin
application.ProcessMessages;
ShowMessage('bad');
Edit1.Text := 'bad';
//edit1.Text := 'bad';
lsttemp.Clear;
memo1.Text := '';
sleep(1000) ;
end;
Edit1.Text := '';
end;
finally
lsttemp.free;
end;
StartCnt := lstAcct.items.Count;
StartTime := Now;
finally
sl.Free;
end;
end;
end.
Right before:
sl.Add('ID='+ lsttemp[0]);
Do:
sl.Clear;
On the first run your "SL" holds the two POST parameters, but unless you clear it on the second run, you just keep adding parameters, confusing the HTTP server you're trying to connect to!
That might not be your only problem, but that's surely one of the problems.

Resources