Delphi Unique Dynamic Form Creation - forms

I am using multiple forms on my project. (Client Server Application) I used chat but i have some problems.
1- I have a user list on my listview. And i am open new chat form here.
procedure CreateNewChat(User: String);
var
ChatForm: TChatForm;
begin
ChatForm:= TChatForm.Create(nil);
if assigned (ChatForm) then
ChatForm.User:= User;
Chat.Socket:= MySocket; // TClientSocket new Instance
ChatForm.Show;
end;
///Chatform
procedure ParseData(Cmd:string);
begin
if Cmd <> '' then
begin
/// parsing...
end;
New connections are adding to listview like that
var
Item: TListItem;
NewTempForm: TTempForm;
begin
NewTempForm := tempForm.Create;
Item := Listview.Items.Add;
if User = '' then
Exit;
Item.Caption := User;
Item.SubItems.Add('OK');
Item.GroupId := GroupId;
Item.SubItems.Objects[0] := NewTempForm;
end;
My problems are started on here.
1- How can i detect form according to user? So, if two or higher form is open then how can i show received message on them? Because i was create them dynamically. I need a object for detect.
I tryed like that
var
tempForm: TTempForm; // this is an empty object class
sTempStr: String;
begin
if ListView.Selected <> nil then
begin
tempForm := TTempForm(ListView.Selected.SubItems.Objects[0]); // this is for unique form creation
if tempForm.frmTasks = nil then // if there is not, create!
begin
tempForm.frmTasks := TfrmTasks.Create(nil);
end;
But my received message is appear on all forms. Actually should appear just one form. (Which user sent it)
Thanks.

Related

Delphi REST not updating VCL db components when created runtime

I have a REST client which sends a request and updates some VCL db components with the response using an adapter, that works fine when the REST VCL components are put on a TDatamodule, however if I try to create the same REST components runtime, the VCL db components are not showing the data. I can see that the data are in fact returned (I can read them in the FDMemtable and store the data as a file) so the data is there, but the GUI components doesnt display data. The DBGrid does however show the vertical scroll bare after the update.
I'm using Delphi XE10.2.
I got stuck with this, I got to be missing something.
function TRESTClientModule.UpdateHistory: Boolean;
var
ARESTClient : TRESTClient;
ARESTRequest: TRESTRequest;
ARESTResponse: TRESTResponse;
ARESTResponseDataSetAdapter: TRESTResponseDataSetAdapter;
i : Integer;
s : string;
begin
Result := False;
try
ARESTClient := TRESTClient.Create('http://localhost:8080');
ARESTRequest := TRESTRequest.Create(nil);
ARESTResponse := TRESTResponse.Create(nil);
ARESTResponseDataSetAdapter := TRESTResponseDataSetAdapter.Create(nil);
try
// bind to RESTClient
ARESTRequest.Client := ARESTClient;
//- Prepare to get data from 'alarms' end-point.
ARESTRequest.Resource := 'alarms';
ARESTRequest.Method := TRESTRequestMethod.rmGET;
ARESTRequest.Response := ARESTResponse;
// Link Response to dataset (FDMemtable + TDataSource)
ARESTResponseDataSetAdapter.Dataset := AlarmHistory;
ARESTResponseDataSetAdapter.ResponseJSON := ARESTResponse;
ARESTResponseDataSetAdapter.RootElement := 'alarms';
//- Add the parameter to the request.
ARESTREquest.Params.Clear;
with ARESTRequest.Params.AddItem do
begin
name := 'IncludeOOS';
value := '0';
end;
ARESTRequest.Execute;
s := ARESTResponse.Content; // returned content is present
i := AlarmHistory.RecordCount; // the expected Recordcount is present
Result := True;
finally
ARESTResponse.Free;
ARESTResponseDataSetAdapter.Free;
ARESTRequest.Free;
end;
except on E: Exception do
end;
end;

How to prevent using anything except application in Delphi XE

I'm developing a VCL Form Application
When the application started
I need to prevent the user of the computer to do anything
He can't close the application by ALT+F4 or CTRL+ALT+DEL
He can't change to another window by ALT+Tab
He can't Go to the desktop by clicking Windows + D
This will used in Cyber Cafe and it is a Server/Client application
so before the Admin in the Server giving access to the Client, He can't do anything in the computer .. just a full screen for my form
Because it is the login system of Windows that traps the CTRL-ALT-DEL combination (and so it is not accessible to user applications), you will need to change the system's keyboard scancode map to ignore at least one of those keys.
First you have to ensure Autologon on your computer, else you can login. This could also be done in the registry.
Then the tricky part editing the scancode map. In MSDN you'll find an article about how to do: https://msdn.microsoft.com/en-us/library/windows/hardware/jj128267%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
I've found this reg file that is suppose to disable CTRL + ALT + DELETE but I havent tested it
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,00,00,38,00,00,00,38,e0,\
00,00,00,00
Be aware that this is extremely hirisk. Both using the REG file and changing the scancode map. I suggest you test your stuff in a virtual Machine.
You also need to prevent the user from shuttingdown the computer. Which is also done in registry:
User Key: [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\
Explorer]
System Key: [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\
Explorer]
Value Name: NoClose
Data Type: REG_DWORD (DWORD Value)
Value Data: (0 = shutdown enabled, 1 = shutdown disabled)
So inorder for shuttingdown the computer your probram must make a call to ShutdownwindowsEx
function ExitWindows(iFlags: Integer): Boolean;
var
osVerInfo: TOSVersionInfo;
function SetPrivilege(sPrivilegeName: string; bEnabled: Boolean): Boolean;
var
TPPrev, TP: TTokenPrivileges;
Token: THandle;
dwRetLen: DWord;
begin
Result := False;
OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token);
TP.PrivilegeCount := 1;
if (LookupPrivilegeValue(nil, PChar(sPrivilegeName), TP.Privileges[0].LUID)) then
begin
if (bEnabled) then
TP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
else
TP.Privileges[0].Attributes := 0;
dwRetLen := 0;
Result := AdjustTokenPrivileges(Token, False, TP, sizeof(TPPrev), TPPrev, dwRetLen);
end;
CloseHandle(Token);
end;
begin
Result := True;
osVerInfo.dwOSVersionInfoSize := sizeof(TOSVersionInfo);
if GetVersionEx(osVerInfo) then
case osVerInfo.dwPlatformId of
VER_PLATFORM_WIN32_WINDOWS:
if not ExitWindowsEx(iFlags, 0) then
Result := False; // handle errors...
VER_PLATFORM_WIN32_NT:
if SetPrivilege('SeShutdownPrivilege', True) then
begin
if not ExitWindowsEx(iFlags, 0) then
Result := False; // handle errors...
SetPrivilege('SeShutdownPrivilege', False)
end
else
Result := False; // handle errors...
else
Result := False;
end;
end;

Wrong Form is focused after closing form in firemonkey

When showing and closing Forms in firemonkey, the application cannot remember wich form was the last activated form, and activates the wrong form.
How can I activate the last active form instead of an arbitrary form chosen by the application?
To replicate : Create 3 forms and open each one in succession from previous form.
I a mainform and 2 ChildForms, the second form is parent to the third form.
I open the first childForm from my MainForm.
var
tmpForm2:TForm2;
begin
tmpForm2:=TForm2.Create(self);
tmpForm2.Show;
end;
In this Form there is a button that shows second childform
var
form3:Tform3;
begin
form3:=TForm3.Create(nil);
form3.Show;
end;
When I open the second ChildForm and close it, the Mainform is activated. Instead of the first ChildForm
Now I repeat the process but when closing the second ChildForm, the first one is actived, as one would expect.
Next time the Mainform is again activated, so the order keeps chainging, instead of the real last active form.
Looks like it was bug in Delphi XE7/XE7 Update 1 in function
function TScreen.NextActiveForm(const OldActiveForm:
TCommonCustomForm): TCommonCustomForm;
On Delphi XE8 this function works correctly and you return to previous window.
In XE8 they rewrite function function TScreen.NextActiveForm(const OldActiveForm: TCommonCustomForm): TCommonCustomForm;
Dog-nail for XE7. I copy function from XE8 and using it before close form.
I tested it only under Windows platform.
unit ufmForm3;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls;
type
TfmForm3 = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
function NextActiveForm(const OldActiveForm: TCommonCustomForm): TCommonCustomForm;
end;
var
fmForm3: TfmForm3;
implementation
{$R *.fmx}
procedure TfmForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
NextActiveForm(Self);
end;
function TfmForm3.NextActiveForm(const OldActiveForm: TCommonCustomForm): TCommonCustomForm;
var
I, CurrIndex: integer;
begin
Result := nil;
CurrIndex := Screen.IndexFormOfObject(OldActiveForm);
if CurrIndex >= 0 then
begin
I := CurrIndex - 1;
while (I >= 0) and (Screen.Forms[I].Released or not Screen.Forms[I].Visible) do
Dec(I);
if I < 0 then
begin
I := Screen.FormCount - 1;
while (I >= 0) and (I <> CurrIndex) and (Screen.Forms[I].Released or not Screen.Forms[I].Visible) do
Dec(I);
end;
if (I >= 0) and (I <> CurrIndex) then
begin
Result := Screen.Forms[I];
Screen.ActiveForm := Result;
end;
end;
end;
end.
I had a related problem in Delphi FMX Berlin. My SDI application has a hidden "real" main form and one or more instances of the working form. When one of the working forms called a modal dialog, I was finding that on closure of the dialog, the focus was going to a form different to the calling form. The solution turned out to be simple.
(1) Create the dialog with owner Self:
MyDlg := TMyDlg.Create(Self);
MyDlg.ShowModal;
(2) Use the following in the modal dialog OnClose:
procedure TMyDlg.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
Screen.ActiveForm:=TMySDIAppForm(Self.Owner);
end;

How To logout and close any active forms in Delphi

Sorry for my bad English, first this is the logout syntax.
When I click logout, all active forms keep showing up and not closing.
procedure Tf_utama.KELUAR1Click(Sender: TObject);
begin
if MessageDlg('Logout ??',mtConfirmation,mbOKCancel,0)=mrOK
then
DATAINPUTAN1.Visible:=False;
INFODATA1.Enabled:=False;
TRANSAKSI.Enabled:=False;
LAPORAN1.Enabled:=False;
PENGATURAN1.Enabled:=False;
f_databuku:=nil;
f_rakbuku:=nil;
f_permintaan_pembeli:=nil;
f_rakbuku:=nil;
f_pengguna:=nil;
f_transaksi_penjualan:=nil;
f_transaksi_pembelian:=nil;
f_supplier:=nil;
StatusBar1.Panels[0].Text:='Nama Pengguna :';
StatusBar1.Panels[1].Text:='Hak Akses :';
end;
On each form to close I am using:
procedure Tf_caribuku.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
f_caribuku:=nil;
end;
That's not how you close and free the form. You are just assigning nil to form pointers, which doesn't close them. What you have to call is TForm.Close(). Also, you have to open your if MessageDlg(... statement with begin..end; blocks if you want to execute multiple commands if statement is satisfied. So your code would look something like this:
procedure Tf_utama.KELUAR1Click(Sender: TObject);
begin
if MessageDlg('Logout ??',mtConfirmation,mbOKCancel,0) = mrOK then
begin
DATAINPUTAN1.Visible:=False;
INFODATA1.Enabled:=False;
TRANSAKSI.Enabled:=False;
LAPORAN1.Enabled:=False;
PENGATURAN1.Enabled:=False;
f_databuku.Close;
f_rakbuku.Close;
f_permintaan_pembeli.Close;
f_rakbuku.Close;
f_pengguna.Close;
f_transaksi_penjualan.Close;
f_transaksi_pembelian.Close;
f_supplier.Close;
StatusBar1.Panels[0].Text:='Nama Pengguna :';
StatusBar1.Panels[1].Text:='Hak Akses :';
end;
end;
Also, if any of forms you're trying to close is not created, I believe it will fail with AV exception. Better way to do this is to make another class which will serve as form container, e.g. TFormContainer, where you can Add and Remove forms on need. That way, upon logout, opened forms will be in TFormContainer class, and you can close them.

InnoSetup Dynamic ComboBox, check which item is selected and execute program

In InnoSetup I want to disply a ComboBox on the Finished Page which shows the Components that were installed.
You can choose "None" or any of the installed Components and start the associated program when clicking on finish.
This is my code so far:
procedure CurPageChanged(CurPageID: Integer);
var
NewComboBox1: TNewComboBox;
begin
if (CurPageID = wpFinished) then begin
NewComboBox1 := TNewComboBox.Create(WizardForm);
with NewComboBox1 do begin
Parent := WizardForm.FinishedPage;
Left := ScaleX(256);
Top := ScaleY(208);
Width := ScaleX(145);
Height := ScaleY(21);
ItemIndex := 0;
Style := csDropDownList;
Items.Add('None');
if IsComponentSelected('1') then
Items.Add('Component 1');
if IsComponentSelected('2') then
Items.Add('Component 2');
if IsComponentSelected('3') then
Items.Add('Component 3');
end;
end;
end;
First I want to set "None" as automatically selected. when the page is shown. I have looked up many Pascal forums but none of the solutions worked, like NewComboBox1.ItemSelected=0 (or similar, don't remember correctly...). So how do I achieve this?
Then I don't know how to make a program start when clicking on Finish. I thought
function NextButtonClick
might help but then no Next button worked in the setup.
Maybe there is also a problem because the list is created depending on which Components were selected, so item 1 is not Component 1, if Component 1 was not selected but Component 2 for instance.
I thought one might solve this by making the items invisible instead of not creating them at all.
I looked in the Support Classes Reference in the IS help file but didn't find anything that would help me.
I am looking forward to your answers!
There's no simple way to do this due to a lack of missing access to the file name and destination directory which the component is binded to. Even TSetupComponentEntry internal record doesn't contain this information, but even if would, you won't be able to access it. So, the following script uses its own separate array which contains the component/file linkage needed for this task:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Components]
Name: "program_32"; Description: "Program 32-bit"
Name: "program_x64"; Description: "Program 64-bit"
Name: "program_ia64"; Description: "Program IA 64-bit"
[Files]
Source: "MyProg.exe"; DestDir: "{app}"; Components: program_32
Source: "MyProg-x64.exe"; DestDir: "{app}"; Components: program_x64
Source: "MyProg-IA64.exe"; DestDir: "{app}"; Components: program_ia64
[Code]
type
TFileData = record
Component: string;
Description: string;
FileName: string;
Parameters: string;
end;
var
ComponentCombo: TNewComboBox;
ComponentArray: array of TFileData;
SelectionArray: array of TFileData;
procedure InitializeWizard;
begin
// this is a weakness of this solution - you need to fill the array
// of components that can be added to the final combo box when they
// are selected on component selection page. This is needed because
// you can't get neither file name nor destination directory of the
// file for the component from script. As first, set how many items
// you want to add to your component array storage
SetArrayLength(ComponentArray, 2);
// the Component member must match to the "Name" parameter from the
// [Components] section item since it's used in IsComponentSelected
// function call
ComponentArray[0].Component := 'program_32';
// the Description member is the text displayed in the combo item
ComponentArray[0].Description := 'Program 32-bit';
// the FileName member is the name of the file including path. This
// member may contain InnoSetup constants
ComponentArray[0].FileName := '{app}/MyProg.exe';
// the Parameters member contains execution parameters
ComponentArray[0].Parameters := '-a';
// this is the second item that can be added to the combo box, note
// that the program_ia64 component is not added to this array, what
// means, that it cannot be added to the "run" combo box. It's such
// kind of a filter for components like help files etc.
ComponentArray[1].Component := 'program_x64';
ComponentArray[1].Description := 'Program 64-bit';
ComponentArray[1].FileName := '{app}/MyProg-x64.exe';
ComponentArray[1].Parameters := '-b';
end;
procedure CurPageChanged(CurPageID: Integer);
var
I: Integer;
begin
if (CurPageID = wpFinished) then
begin
ComponentCombo := TNewComboBox.Create(WizardForm);
ComponentCombo.Parent := WizardForm.FinishedPage;
ComponentCombo.Left := ScaleX(256);
ComponentCombo.Top := ScaleY(208);
ComponentCombo.Width := ScaleX(145);
ComponentCombo.Height := ScaleY(21);
ComponentCombo.Style := csDropDownList;
ComponentCombo.Items.Add('None');
for I := 0 to GetArrayLength(ComponentArray) - 1 do
if IsComponentSelected(ComponentArray[I].Component) then
begin
ComponentCombo.Items.Add(ComponentArray[I].Description);
SetArrayLength(SelectionArray, GetArrayLength(SelectionArray) + 1);
SelectionArray[High(SelectionArray)] := ComponentArray[I];
end;
ComponentCombo.ItemIndex := 0;
end;
end;
function NextButtonClick(CurPageID: Integer): Boolean;
var
FileData: TFileData;
ResultCode: Integer;
begin
Result := True;
if (CurPageID = wpFinished) and (ComponentCombo.ItemIndex > 0) then
begin
FileData := SelectionArray[ComponentCombo.ItemIndex - 1];
Exec(ExpandConstant(FileData.FileName), FileData.Parameters, '', SW_SHOW,
ewNoWait, ResultCode);
end;
end;