CEF4Delphi unit test not - delphi

I am testing a TFrame with CEF4Delphi component in it but I have issues when it comes to freeing up the TForm containing the TFrame and the relevant CEF4Delphi components.
The following is a Minimal Example
program MyTFrameExample;
{
Delphi DUnit Test Project
-------------------------
This project contains the DUnit test framework and the GUI/Console test runners.
Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options
to use the console test runner. Otherwise the GUI test runner will be used by
default.
}
{$IFDEF CONSOLE_TESTRUNNER}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
madExcept,
madLinkDisAsm,
madListHardware,
madListProcesses,
madListModules,
DUnitTestRunner,
Vcl.Forms,
WinApi.Windows,
uCEFApplication,
SSFrame in '..\..\SS\SSFrame.pas' {SSFrm: TFrame},
TestSSFrame in '..\..\Test\TestSSFrame.pas';
{*.RES}
{$I cef.inc}
{$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE}
begin
GlobalCEFApp := TCefApplication.Create;
GlobalCEFApp.SingleProcess := True;
if GlobalCEFApp.StartMainProcess then
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
DUnitTestRunner.RunRegisteredTests;
Application.Run;
end;
GlobalCEFApp.Free;
end.
unit TestSSFrame;
{
Delphi DUnit Test Case
----------------------
This unit contains a skeleton test case class generated by the Test Case Wizard.
Modify the generated code to correctly setup and call the methods from the unit
being tested.
}
interface
uses
TestFramework,
System.SysUtils,
Vcl.Graphics,
uCEFChromium,
Winapi.Windows,
System.Variants,
uCEFInterfaces,
uCEFChromiumWindow,
Vcl.Dialogs,
Vcl.Controls,
uCEFWindowParent,
Vcl.Forms,
Winapi.Messages,
SSFrame,
System.Classes;
type
// Test methods for class TSSFrm
TestTSSFrm = class(TTestCase)
strict private
FSSFrm: TSSFrm;
FMainForm: TForm;
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure TestChromium1AfterCreated;
end;
implementation
procedure TestTSSFrm.SetUp;
begin
Application.CreateForm(TForm, FMainForm);
FSSFrm := TSSFrm.Create(FMainForm);
FSSFrm.Parent := FMainForm;
FSSFrm.Visible := True;
FSSFrm.Align := alClient;
FSSFrm.Chromium1.CreateBrowser(FSSFrm.ChromiumWindow1);
if not (FSSFrm.ChromiumWindow1.CreateBrowser) then
FSSFrm.Timer1.Enabled := True;
while FSSFrm.Chromium1.Initialized = False do
begin
Application.ProcessMessages;
end;
FMainForm.Show;
end;
procedure TestTSSFrm.TearDown;
begin
FMainForm.Free;
[enter link description here][1] FMainForm := nil;
end;
procedure TestTSSFrm.TestChromium1AfterCreated;
var
a: Boolean;
begin
if (FMainForm.Components[0] is TSSFrm) then
begin
a := (FMainForm.Components[0] as TSSFrm).IsGoogleSearchPageCreated;
CheckTrue(a);
end;
end;
initialization
// Register any test cases with the test runner
RegisterTest(TestTSSFrm.Suite);
end.
unit SSFrame;
interface
uses
Winapi.Windows,
Winapi.Messages,
System.SysUtils,
System.Variants,
System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
uCEFWindowParent,
uCEFChromiumWindow,
uCEFInterfaces,
uCEFChromium,
Vcl.StdCtrls,
Vcl.ExtCtrls;
type
TSSFrm = class(TFrame)
Chromium1: TChromium;
ChromiumWindow1: TChromiumWindow;
Timer1: TTimer;
procedure Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
procedure Timer1Timer(Sender: TObject);
private
{ Private declarations }
FIsGoogleSearchPageLoaded: Boolean;
FIsGoogleSearchPageCreated: Boolean;
public
{ Public declarations }
function IsGoogleSearchPageCreated: Boolean;
end;
implementation
{$R *.dfm}
procedure TSSFrm.Chromium1AfterCreated(Sender: TObject; const browser: ICefBrowser);
begin
FIsGoogleSearchPageLoaded := False;
FIsGoogleSearchPageCreated := True;
end;
function TSSFrm.IsGoogleSearchPageCreated: Boolean;
begin
Result := FIsGoogleSearchPageCreated;
end;
procedure TSSFrm.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
if not (ChromiumWindow1.CreateBrowser) and not (ChromiumWindow1.Initialized) then
Timer1.Enabled := True;
end;
end.
When I run TestTSSFrm.TestChromium1AfterCreated; the test pass but when it comes to close the test application then the application itself does not close completely and I have to reset it from the IDE manually. If I comment out the lines
FMainForm.Free;
FMainForm := nil;
then I have no issues with closing the test application but I have to close the form manually.
Where am I doing wrong?

Related

Delphi IdTCPClient.connect Hanging while threaded

I am trying to run 8 threads making IdTCPClient repeatedly scanning a range of IP. When these threads are running, the main form is hanging, lagging. The "IdTCClient.connect" is the issue. Is there a way to fix that ?
unit Unit3;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TTcpThread = class(TThread)
Idx: word;
procedure Execute; override;
end;
TForm3 = class(TForm)
procedure FormShow(Sender: TObject);
private
public
end;
var
Form3: TForm3;
implementation
uses IdTCPClient;
{$R *.dfm}
procedure TTcpThread.Execute;
begin
for var i := Idx*8 to (Idx*8) + (8-1) do // 8 IP per Thread
begin
var TCP := TidTCPClient.Create(nil);
TCP.Host := '192.168.1.' + i.ToString;;
TCP.Port := 9999;
TCP.ConnectTimeout := 500;
TCP.ReadTimeout := 1000;
try
TCP.Connect;
TCP.Disconnect;
except end;
TCP.Free;
end;
end;
procedure TForm3.FormShow(Sender: TObject);
begin
for var i := 0 to 32-1 do // 32 Threads
begin
var Thread := TTcpThread.Create(True);
Thread.Idx := i;
Thread.FreeOnTerminate := True;
Thread.Start;
end;
end;
end.
The mainform will freeze/lag while the threads are running

How to get FileName and Directory of Windows Control Panels?

In Delphi, create a VCL Forms Application. Use the 64-bit Windows platform if you are on a 64-bit Windows.
Use the following code:
unit Unit1;
interface
uses
CodeSiteLogging,
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure GetControlPanelItems;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Winapi.ShlObj, Winapi.ShellAPI, System.Win.ComObj;
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
GetControlPanelItems;
end;
procedure TForm1.GetControlPanelItems;
var
psfDeskTop: IShellFolder;
psfControl: IShellFolder;
pidControl: PITEMIDLIST;
pidChild: PITEMIDLIST;
pidAbsolute: PItemIdList;
pEnumList: IEnumIDList;
celtFetched: ULONG;
FileInfo: SHFILEINFOW;
ShExeInfo: SHELLEXECUTEINFO;
begin
OleCheck(SHGetDesktopFolder(psfDeskTop));
OleCheck(SHGetSpecialFolderLocation(0, CSIDL_CONTROLS, pidControl));
OleCheck(psfDeskTop.BindToObject(pidControl, nil, IID_IShellFolder, psfControl));
OleCheck(psfControl.EnumObjects(0, SHCONTF_NONFOLDERS or SHCONTF_INCLUDEHIDDEN or SHCONTF_FOLDERS, pEnumList));
while pEnumList.Next(1, pidChild, celtFetched) = 0 do
begin
pidAbsolute := ILCombine(pidControl, pidChild);
SHGetFileInfo(LPCTSTR(pidAbsolute), 0, FileInfo, SizeOf(FileInfo), SHGFI_PIDL or SHGFI_DISPLAYNAME or SHGFI_TYPENAME);
CodeSite.Send('TForm1.GetControlPanelItems: szDisplayName', FileInfo.szDisplayName);
// Exe-Info:
ZeroMemory(#ShExeInfo, SizeOf(ShExeInfo));
ShExeInfo.cbSize := SizeOf(ShExeInfo);
ShExeInfo.lpVerb := 'Open';
// control panel item's PIDL:
ShExeInfo.lpIDList := pidAbsolute;
ShExeInfo.nShow := SW_SHOWNORMAL;
ShExeInfo.fMask := SEE_MASK_IDLIST;
//ShExeInfo.lpFile := ???
//ShExeInfo.lpDirectory := ???
CodeSite.Send('TForm1.GetControlPanelItems: ShExeInfo.lpFile', ShExeInfo.lpFile);
CodeSite.Send('TForm1.GetControlPanelItems: ShExeInfo.lpDirectory', ShExeInfo.lpDirectory);
end;
end;
end.
This gets me the Display names of the control panels.
But how can I get the file-paths? (ShExeInfo.lpDirectory, ShExeInfo.lpFile)
As others mentioned here, it might be worthless to try getting file name of a certain applet binary as there can be more than one applet implemented in a single binary. For your overall task, dropped in your comment, creating shell shortcut links, simply use absolute ITEMIDLIST that you know in your loop, and set it to the created IShellLink object by the SetIDList method.

Delphi Form in DLL works, but Delphi Frame - not

I am trying to create a Form and a Frame in Delphi-made DLL using handles only. The form appears in host application normally, but the frame doesn't appear at all.
What could be wrong?
Below I provide a piece of code that creates both Frame and Window:
library DLL1;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
uses
System.SysUtils,
System.Classes,
DllMain in 'DllMain.pas',
Winapi.Windows,
Vcl.Forms,
Vcl.Controls {DLLFrame1: TFrame},
DllForm in 'DllForm.pas' {Form1};
{$R *.res}
type
TSingleton = class
private
fra: TDLLFrame1;
frm: TForm1;
class var __instance: TSingleton;
class function __getInstance(): TSingleton; static;
public
class property Instance: TSingleton read __getInstance;
procedure CreateDLLFrame(AppHandle, ParentWindow: HWND);
procedure CreateDLLForm(AppHandle, ParentWindow: HWND);
procedure DestroyDLLFrame();
procedure DestroyDLLForm();
end;
procedure CreateDLLFrame(AppHandle, ParentWindow: HWND); stdcall;
begin
TSingleton.Instance.CreateDLLFrame(AppHandle, ParentWindow);
end;
procedure CreateDLLForm(AppHandle, ParentWindow: HWND); stdcall;
begin
TSingleton.Instance.CreateDLLForm(AppHandle, ParentWindow);
end;
procedure DestroyDLLFrame(); stdcall;
begin
TSingleton.Instance.DestroyDLLFrame();
end;
procedure DestroyDLLForm(); stdcall;
begin
TSingleton.Instance.DestroyDLLForm();
end;
exports
CreateDLLFrame,
CreateDLLForm,
DestroyDLLFrame,
DestroyDLLForm;
procedure TSingleton.CreateDLLFrame(AppHandle, ParentWindow: HWND);
begin
Application.Handle := AppHandle;
fra := TDLLFrame1.CreateParented(ParentWindow);
fra.Show();
end;
procedure TSingleton.DestroyDLLForm();
begin
frm.Free();
end;
procedure TSingleton.DestroyDLLFrame();
begin
fra.Free();
end;
procedure TSingleton.CreateDLLForm(AppHandle, ParentWindow: HWND);
begin
Application.Handle := AppHandle;
frm := TForm1.CreateParented(ParentWindow);
frm.Show();
end;
class function TSingleton.__getInstance(): TSingleton;
begin
if __instance = nil then
__instance := TSingleton.Create();
Result := __instance;
end;
end.
The DLLFrame:
unit DllMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
type
TDLLFrame1 = class(TFrame)
mmoText: TMemo;
pnlSend: TPanel;
edtSend: TEdit;
btnSend: TButton;
private
public
constructor Create(AOwner: TComponent); override;
end;
implementation
{$R *.dfm}
{ TDLLFrame1 }
constructor TDLLFrame1.Create(AOwner: TComponent);
begin
inherited;
if AOwner = nil then
MessageBox(0, 'Frame owner is NIL', 'Debug', 0)
else
MessageBox(0, PWideChar(AOwner.Name), 'Debug', 0);
end;
end.
Delphi TFrame descend from TWinControl (and thus, TControl), they have an Owner and they have a Parent (often these are the same). The Owner controls the Frame's lifetime while the Parent controls where it's displayed (i.e. which Window handle is to be used). For example, in a VCL app with 2 form units and a frame unit, you could instantiate a Frame having it's owner be the Application object or the the first Form while having it's parent be the second form; the Frame would be displayed on the second form even though it's owner was the first frame.
What is the difference between Owner and Parent of a control?
This little example doesn't use DLLs, but it shows how the frame won't be displayed without a Parent being assigned:
unit CreateFrameAtRunTimeForm;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm2 = class(TForm)
Label1: TLabel;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses CreateFrameAtRunTimeFrame;
{$R *.dfm}
procedure TForm2.Button1Click(Sender: TObject);
var
F : TFrame3;
begin
F := TFrame3.Create(self);
F.Name := 'Frame'+Random(1000000).ToString;
F.Panel1.Caption := 'Frame '+F.Name;
F.Left := 200;
F.Top := 100;
end;
procedure TForm2.Button2Click(Sender: TObject);
var
F : TFrame3;
begin
F := TFrame3.Create(self);
F.Name := 'Frame'+Random(1000000).ToString;
F.Panel1.Caption := 'Frame '+F.Name;
F.Left := 200;
F.Top := 100;
F.Parent := self;
end;
end.
I'm sure your problem is that the Frame doesn't have a Parent control and I don't think it's possible to set one if you are only passing window handles around.

Solution to Printing Crystal Reports XI Forms in Delphi XE3

After suffering through the same problems as others did, I came up with this solution to previewing/printing Crystal Reports XI reports. This borrows a few lines for the login sequence. I still can't find anything in the *TLB.pas files that allows me to login to the server directly rather than running down through the list of tables. Anyway, here's what I have at this point. Hope it helps someone !
Unit CrystalReports;
uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.OleCtrls, ActiveX, ComObj, Data.DB, Data.Win.ADODB,
CrystalActiveXReportViewerLib11_TLB, Vcl.OleServer, CrystalReportsControllersLib_TLB;
type
TCrystalReportForm = class(TForm)
CRV: TCrystalActiveXReportViewer;
procedure DisplayReport;
private
{ Private declarations }
public
{Public declarations }
ReportName : WideString;
ReportCaption : String;
ReportSelectionFormula : WideString;
end;
var
CRXIRuntime : Variant;
implementation
{$R *.dfm}
procedure TCrystalReportForm.DisplayReport;
var
CrystalReport : variant;
i : integer;
begin
CrystalReport := CRXIRuntime.OpenReport(ReportName);
for i := 1 to CrystalReport.Database.Tables.Count do begin
CrystalReport.Database.Tables[1].ConnectionProperties.Item['User ID'] := 'user';
CrystalReport.Database.Tables[1].ConnectionProperties.Item['Password'] := 'password';
end;
CrystalReport.FormulaSyntax := 0;
Caption := ReportCaption;
CrystalReport.RecordSelectionFormula := ReportSelectionFormula;
CRV.Align := alClient;
CRV.ReportSource := CrystalReport;
WindowState := wsMaximized;
CRV.ViewReport;
ShowModal;
end;
begin
CRXIRuntime := CreateOleObject('CrystalRuntime.Application');
end.

FMX form in a DLL (firemonkey/delphi)

Im trying to make a FMX form in a dll, after about 17 hours (of trying diffrent approches) i got it working, except i get a exception trying to unload the dll. I have no idea how to make it work, maybe someone could help me and point out what im doing wrong?
side note:
i cant have a FMX form in my VCL application becouse of the AA drawing, i just need it on my text while drawing on a canvas and while having a FMX form on a VCL application, i dont get that cleartype on text :( im trying to make a some sort of OSD/HUD.
Project showing my problem:
exe unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
unitLoadDLL, Winapi.GDIPOBJ;
procedure TForm1.Button1Click(Sender: TObject);
begin
showme();
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
closeme();
end;
end.
exe unitLoadDll.pas
unit unitLoadDLL;
interface
uses Windows, Dialogs;
type
TShowme = procedure();
TCloseme = procedure();
var
showme : TShowme = nil;
closeme : TCloseme = nil;
DllHandle : THandle;
implementation
initialization
if DllHandle = 0 then begin
DllHandle := LoadLibrary('C:\Users\Ja\Desktop\dupa\dll\Win32\Debug\Project1.dll');
if DllHandle > 0 then begin
#showme := GetProcAddress(DllHandle,'showme');
#closeme := GetProcAddress(DllHandle,'closeme');
end
else begin
MessageDlg('Select Image functionality is not available', mtInformation, [mbOK], 0);
end;
end;
finalization
if DLLHandle <> 0 then
FreeLibrary(DLLHandle);
end.
dll project1.dpr
library Project1;
uses
FMX.Forms,
System.SysUtils,
System.Classes,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
procedure showme(); stdcall export;
begin
TForm1.showme;
end;
procedure closeme(); stdcall export;
begin
TForm1.closeme;
end;
exports
showme, closeme;
begin
end.
dll unit1.pas
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs;
type
TForm1 = class(TForm)
Label1: TLabel;
private
{ Private declarations }
public
class procedure showme();
class procedure closeme();
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
class procedure TForm1.showme();
begin
Form1 := TForm1.Create(Application);
Form1.Show;
end;
class procedure TForm1.closeme();
begin
Form1.Free;
end;
end.
EDIT (FIX):
All answers ware helpfull, but what i've done is, that the GDI+ was shutdown BEFORE the dll unload... that appear's to be the problem.
new unitLoadDll.pas
unit unitLoadDLL;
interface
uses Windows, Dialogs;
type
TShowme = procedure();
TCloseme = procedure();
var
showme : TShowme = nil;
closeme : TCloseme = nil;
DllHandle : THandle;
function LoadLib : Boolean;
procedure UnloadLib;
implementation
function LoadLib : Boolean;
begin
if DllHandle = 0 then begin
DllHandle := LoadLibrary('C:\Users\Ja\Desktop\dupa\dll\Win32\Debug\Project1.dll');
if DllHandle > 0 then begin
#showme := GetProcAddress(DllHandle,'showme');
#closeme := GetProcAddress(DllHandle,'closeme');
end
else begin
MessageDlg('Select Image functionality is not available', mtInformation, [mbOK], 0);
end;
end;
Result := DllHandle <> 0;
end;
procedure UnloadLib;
begin
if DLLHandle <> 0 then begin
FreeLibrary(DLLHandle);
DllHandle := 0;
end;
end;
initialization
LoadLib;
finalization
UnloadLib;
end.
new unit1.pas
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Winapi.GDIPOBJ;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
unitLoadDLL;
procedure TForm1.Button1Click(Sender: TObject);
begin
showme();
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
closeme();
end;
end.
in unit1.pas i moved the Winapi.GDIPOBJ to "uses" just after interface directive, and it worked...
Thank you all for your answers! See you soon! very soon...
Does it help if you import sharemem on both sides?
You are not using packages, so both sides probably have an own instance all RTL state, as well as VMT tables (though that is only a problem with certain IS and AS cases). And the memory manager is RTL state :-)

Resources