TFDGUIxWaitCursor in formless application - delphi

The error I become is:
Object factory for class {3E9B315B-F456-4175-A864-B2573C4A2201} is missing. To register it, you can drop component [TFDGUIxWaitCursor] into your project
Well, I would like to do it if I did not have a VCL-less (not console) application ...
There is just a "script" in DPR file and that's it.
Following does not help:
wCur := TFDGUIxWaitCursor.Create(nil);
conn := TFDConnection.Create(nil);
try
.....
conn.Connected := True;
conn.ExecSQL('blah blah blah');
conn.Connected := False;
finally
conn.Free();
wCur.Free();
end;

There is no need to create TFDGUIxWaitCursor explicitly.
In your case it is enough to include FireDAC.VCLUI.Wait in uses clause of your project file. All the neccessary initializations and finalizations are performed in initialization and finalization sections of this unit.
The concept of a wait cursor is abstracted in FireDAC (with the interface IFDGUIxWaitCursor) to work within FireMonkey, VCL and console applications. Therefore there exists different implementation for each kind in different units. Depending on your app-type, you have to choose the appropriate implementation. The designer usually add the right one if you drop a FireDAC component onto a form, frame or datamodule.
Console: FireDAC.ConsoleUI.Wait
FMX: FireDAC.FMXUI.Wait
VCL: FireDAC.VCLUI.Wait

Related

CHM file not displaying correctly when Delphi VCL style active

My Delphi application includes a help file that the user can call from anywhere in the application (well... that is, for all the parts I've written so far...)
It also includes the ability for the user to switch from the regular style to another VCL style from a list.
When no style is applied, the help file displays normally like this :
But as soon as a VCL style is active, the Help file does not display correctly anymore, like this :
Is this due to the way I declare the HelpFile on main Form creation like this (path being a global variable pointing to the main exe folder):
Application.HelpFile := path+'Help\D.R.A.M.A. 2.0 Help.chm';
or is this a known problem that can not be solved ?
SIDE NOTE : the help is called on helpContext should that be important to mention and the HtmlHelpViewer is added to the uses clause.
This answer was taken from https://forums.embarcadero.com/thread.jspa?threadID=227785 and I've confirmed works very well.
Drop a TApplicationEvents component onto the applications main form.
Implement the OnHelp event of that component as this:
function TfmMain.ApplicationEvents1Help(Command: Word; Data: NativeInt; var CallHelp: Boolean): Boolean;
begin
CloseHelpWnd;
Result := ShellExecute(0,'open','hh.exe',
PWideChar('-mapid '+IntToStr(Data)
+' ms-its:'+Application.HelpFile),
nil,SW_SHOW) = 32;
CallHelp := false;
end;
On the main form, implement the CloseHelpWnd method as this:
procedure TfmMain.CloseHelpWnd;
var
HlpWind: HWND;
const
HelpTitle = 'Your help file title';
begin
HlpWind := FindWindow('HH Parent',HelpTitle);
if HlpWind <> 0 then PostMessage(HlpWind,WM_Close,0,0);
end;
You would replace 'Your help file title' with the title of your help file. This is the window caption title when you open the help file directly.
In the FormDestroy event for the main form, include a call to
CloseHelpWnd;
So far we've not seen any issues with the above method, and because we are running the help file in a separate process, it is not affected by the VCL Styles problems evident in Delphi 10.2 Tokyo.
NOTE: It does not have to be the applications main form, but it must be a form that is created before the help system is needed and remains instantiated while the application is running. In our case, we did it on a common resources form and then all programs we rebuilt with the new form had the help problem resolved.
NOTE: You still need to set the Application.HelpFile property as normal, but you don't need to include the HtmlHelpViewer unit in the Uses clause.

DUnit Cannot create form. No MDI forms are currently active

Hey there i have a problem with my Unit Testing in Delphi XE3 i have a project that consist of 1 MDIForm and allot of MDIChild forms then problem is that when i run test on my MDIChild forms i get this error:
TestAllDataSrouces: EInvalidOperation
at $0064346F
SetUp FAILED: Cannot create form. No MDI forms are currently active
my Setup method looks like this:
procedure TestTCustomerCard.SetUp;
begin
FCustomerCard := TCustomerCard.Create(Application);
end;
what can i do to solve this error? so far i tried:
FCustomerCard := TCustomerCard.Create(Application.MainForm);
FCustomerCard := TCustomerCard.Create(nil);
And
procedure TestTCustomerCard.SetUp;
var
a : TForm;
begin
a := TForm.Create(nil);
a.FormStyle := fsMDIForm;
FCustomerCard := TCustomerCard.Create(a);
end;
and my test is:
procedure TestTCustomerCard.TestAllDataSrouces;
var
I: Integer;
begin
for I := 0 to FCustomerCard.ComponentCount-1 do
begin
if (FCustomerCard.Components[i] is TcxLookupComboBox) then
begin
Check(TcxLookupComboBox(FCustomerCard.Components[i]).Properties.ListSource = nil,'Error no ListSource, Lookup: '+TcxLookupComboBox(FCustomerCard.Components[i]).Name+' Parent: '+TcxLookupComboBox(FCustomerCard.Components[i]).Parent.Name);
end;
if (FCustomerCard.Components[i] is TcxDBTextEdit) then
begin
Check(TcxDBTextEdit(FCustomerCard.Components[i]).DataBinding.DataSource = nil,'Error No DataSet, Text Edit: '+TcxDBTextEdit(FCustomerCard.Components[i]).Name+' Parent: '+TcxDBTextEdit(FCustomerCard.Components[i]).Parent.Name);
end;
if (FCustomerCard.Components[i] is TcxGridDBTableView) then
begin
Check(TcxGridDBTableView(FCustomerCard.Components[i]).DataController.DataSource = nil,'Error no Data Source, DB Grid View: '+TcxGridDBTableView(FCustomerCard.Components[i]).Name);
end;
end;
end;
Demo Project: Here
What you are doing is more like a functional or integration test. You are checking that your UI is correctly set up. That kind of test is different from a unit test.
Unit tests are supposed to check that if you give a module certain inputs, then they produce certain outputs. Unit tests are localized. They are meant to test the behaviour of a unit independently from other units. A UI specifically depends on other units. They take data from input devices and operate on databases and on the whole have quite complicated set of dependencies. That makes them a bad target for unit testing.
Take a look at this question - Unit tests vs Functional tests
To do the kind of testing you want, it is probably best to make your own tool that can set up the environment correctly and perform the test.
The error message pinpoints the problem. If you need an MDI child form, it must have an MDI parent form. And that parent form must be the main form of your program. Hard to achieve in a DUnit project. Your solutions appear to be:
Make the main form of your program be an MDI main form. I think that will be tricky to achieve.
Make your form under test not be an MDI child form.
Find a way to test that does not require instantiation of this form.
I have encountered the same problem, and I decided to implement advice of David Heffernan and "Make your form under test not be an MDI child form".
Here I will describe how I could reach this. I have made all changes in my testcase unit.
Make test form that inherits original MDI child form
type TTestCustomerCard = class(TCustomerCard) end;
Add this just before your test case class.
Copy dfm file or the form, say CustomerCard.dfm, to TestCustomerCard.dfm
Open TestCustomerCard.dfm in any text editor, delete line
FormStyle = fsMDIChild (because fsNormal is default value),
change first line
object CustomerCard: TCustomerCard
to
object TestCustomerCard: TTestCustomerCard
Add directive
{$R TestCustomerCard.dfm }
In your SetUp method instead of
FCustomerCard := TCustomerCard.Create(Application);
write
FCustomerCard := TTestCustomerCard.CreateNew(Application);
InitComponentRes( 'TTESTCUSTOMERCARD', FCustomerCard );

Method in Delphi to set database connections to disconnected upon compile

Is there a method or compiler directive or some way of assuring certain components, such as queries or database connections get set to active=false or disconnected when you run a build/compile? Seems so often these are turned on by something else and you don't notice it until its too late.
My particular install is Delphi 7
The Set Component Properties feature of GExperts is able to do that.
i think the best option would be to subclass stock connection component and in your own one override .Loaded method like that
if not csDesigning in Self.ComponentState then
if not Self.ActiveInDFM {new boolean published property} then
if Self.Active then Self.Active := false;
inherited;
http://docwiki.embarcadero.com/Libraries/XE3/en/System.Classes.TComponentState
http://docwiki.embarcadero.com/Libraries/XE3/en/System.Classes.TComponent.Loaded
By (ab)using Delphi Form Designer stupidness you can use it even without actually installing your new component into IDE Palette - just give it the same name as to the stock component class, then put your own method as last in the form's interface-uses list: thus in design-time you would have stock component and when compiling it would be transparently substituted with your own one.
Or you can sub-class it right above the very form declaration like (for another component):
type
TPanel = class(ExtCtrls.TPanel)
private
...
TForm1 = class(TForm) ....
I guess this approach might be seen as analogue to aspect-oriented programming, using limitations of IDE in developer-benefitting way.
Another approach might be some script, that cleans .Active properties in DFM on save or before build, but this way is complex for
i may be harder to integrate with stand-alone build severs (new script for each different CI framework tried)
it would reset Active property for design-time as well. This is a proper thing to do, from rigorous point of view. Yet this might be not very convenient.
You may just use similar code in your Form's and DataModule's .Loaded method (you would have to override it instead connection's method then).
You can copy-paste the same code into every Form's Loaded method.
procedure TMyForm.Loaded; // override
var c: TComponent; i: integer;
begin
try
for i := 0 to Self.ComponentsCount - 1 do begin
c := Self.Components[i];
if c is TCustomConnection then
with TCustomConnection(c) do // Hate those redundant typecasts!
if Connected then Connected := false;
if c is TDataSet then
with TDataSet(c) do // Delphi could took a lesson from Component Pascal
if Active then Active := false;
if c is ... // transactions, stored procedures, custom libriaries...
end;
finally
inherited;
end;
end;
This seems to be less sly way - thus most reliable. Yet that is a lot if copy-paste, and if you would later add some new component or library, that may ask for modifying copy-pasted code in all the forms.
You may centralize this code in some MyDBUtils unit into global procedure like Disconnect(const owner: TComponent); and then
procedure TMyForm.Loaded; // override
var c: TComponent; i: integer;
begin
try
MyDBUtils.Disconnect(Self);
finally
inherited;
end;
end;
This approach also has drawbacks though:
This would make MyDBUtils unit tightly coupled with all and every the database-related libs and components you might use. For large inherited projects, consisting of different binary modules, historically based on different db-access libraries and in process of migration, thus pulling all the access libraries into every binary module.
It can be overcome by ad hoc DI framework, but then the opposite can happen: you risk under-delivering, you may just forget to inject some library or component handler into the project that actually use it or got modified to use it.
If your form would have some components, whose connectivity should NOT be reset (object arrays as datasets, in-memory tables, in-memory NexusDB or SQLite databases, etc), you'd have to come up with ad hoc non-obvious convention to opt them out.
In my applications, I set my connection's Tag property to 1 at design time. In the OnBeforeConnect event, I check Tag, and if it is equal to 1, I abort the connection and set it to 0.

Delphi 7, Add a dll to application directory on dropping a component

i am developing a a component in delphi 7 and delphi 2006,component uses a .pas (Not mine )file which requires a DLL file to be present in the application directory.
It is possible to embed the DLL file into the component, so that when the user drops it on the form or create it at run time the DLL will be placed in the application directory?
currently
1) i am telling the user to place DLL file in the application directory.
2) Add the DLL file in the Resources , so that on create, i can drop the DLL into the application directory? from delphidabbler_embed_resource. This i have done using
{Drop the Resource..!!!}
procedure DropDllToApplicationDirectOry(applicationPath : string);
var
RS: TResourceStream;
begin
// Create resource stream
RS := TResourceStream.CreateFromID(HInstance, 100, RT_RCDATA);
try
// applicationPath : example c:\MyTestProject Lee\
if DirectoryExists(applicationPath) then RS.SaveToFile(applicationPath+'myDllFileWhichIsNeeded.dll')
finally
// Free the stream
RS.Free;
end;
end;
this DropDllToApplicationDirectOry take the resource from the {$RmyDllFileWhichIsNeeded.dll.RES} and drope to the location but
how do i call DropDllToApplicationDirectOry this when i drop the component on the Form?
i tried initialization of the component but DLL is not copied so i get the error
EDIT
For RXControls's TRxClock when we drop the clock runs on this form, the clock begins to run(show the curent time)...
so i tried this
constructor Tmycomponeny.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{add dll}
DropDllToApplicationDirectOry(ExtractFilePath(Application.ExeName));
end;
But this doesnt work..
The code OF RXControls
constructor TRxClock.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if not Registered then begin
ClockInit;
Registered := True;
end;
Caption := TimeToStr(Time);
ControlStyle := ControlStyle - [csSetCaption]
{$IFDEF WIN32} - [csReplicatable] {$ENDIF};
BevelInner := bvLowered;
BevelOuter := bvRaised;
FTimer := TRxTimer.Create(Self);
FTimer.Interval := 450; { every second }
FTimer.OnTimer := TimerExpired;
FDotsColor := clTeal;
FShowSeconds := True;
FLeadingZero := True;
GetTime(FDisplayTime);
if FDisplayTime.Hour >= 12 then Dec(FDisplayTime.Hour, 12);
FAlarmWait := True;
FAlarm := EncodeTime(0, 0, 0, 0);
end;
This idea is not going to work, in general. You are assuming that the developer will always drop your component onto a form. But they could just as well check an existing project out from revision control and then the DLL would not be created.
In my opinion you should simply document the dependency and let the developer ensure that the dependency is met. Suggest that they add the DLL to their revision control system so that it is checked out into the application directory.
The developer is going to need to be aware of this dependency when it comes to deployment. That has to be the developer's responsibility. So it is just cleaner and easier to let the developer manage this full stop.
Although David is correct that documenting is probably the only reliable approach, your question is an interesting one.
You seem to have written the code to write the dll to a file so the problem is responding to an event that will be fired when the component is created?
If I was to do this I think I would check on component creation that the dll exists and if not create it at this stage if not. Is it possible for you to load the dll dynamically? If you can only use the dll linked statically, then David's way is really the only reliable way.
What you are asking for is technically doable, but ONLY if the DLL is dynamically loaded at runtime using LoadLibrary(). The "Unable to Locate Component" error is a result of statically linking to the DLL at compile-time instead, which makes it impossible to extract the DLL at runtime (unless the static linked DLL is delay-loaded, which utilizes LoadLibrary() internally).
If, and only if, the DLL is dynamically/delay loaded, then you can extract it from your component's resources at runtime before the DLL is used. When calling TResourceStream.CreateFromID(), do not use the global HInstance variable, use the FindClassHInstance() function instead. The global HInstance variable will not point to the component's module if the component is used in a project with Runtime Packages enabled, but FindClassHInstance() can find the correct module no matter how the component is linked in to the project.
Try putting the dll file in the Contains folder of the Package you're creating, using the Project Manager from Delphi.

Delphi - Form in DLL - Hints not showing

I have a Delphi form inside a DLL (I know that this restricts the use of the DLL to Delphi but this is not a problem in this case).
The DLL exports a function ShowForm that looks roughly like this:
procedure ShowForm (App : TApplication);
begin
OldApp := Application;
try
Application := App;
MyForm := TMyForm.Create (nil);
try
MyForm.ShowModal;
finally
FreeAndNil (MyForm);
end;
finally
Application := OldApp;
end;
end;
Now on the form I use a TAdvOfficeHint (from the TMS component pack). Unfortunately the hints do not show up.
Am I missing something here? How can I make the form behave exactly as it would if I showed it from the main application?
Thanks!
I don't know TAdvOfficeHint but I guess it hooks Application.OnShowHint to set its own THintWindowClass, and even if both the main executable and the DLL are linking in the TMS unit, they each have their own copy of the class which is where things go wrong.
Assigning Application is not enough: there are other global variables, like Screen, Mouse, etc. Others are even hidden in the implementation so I'd say your chances to make the form behave exactly as from the main application are slim.
Just found the reason why it does not work. As TOndrej states, TAdvOfficeHinthooks Application.OnShowHint and internally executes the following line of code:
FHintInfo.Assign (AHintInfo);
Assign internally uses a dynamic type check
if (Source is TAddvHintInfo) then ...
which fails due to the separate type registries of the DLL and the main application.
I have run into this problem a few times now and maybe I really have to switch to runtime packages to avoid all this stuff.
Anyway, if there's anything I can do to prevent this, please comment.
Wrong setting of Application.
Try this and see if it solves your problem:
procedure ShowForm (AppHandle : THandle);
begin
OldAppHandle := Application.Handle;
try
Application.Handle := AppHandle;
........
finally
Application.Handle := OldAppHandle;
end;
end;
I guess in Delphi 2006 and later versions you can call System.ShareMemoryManager method in the EXE code, so that its memory manager is shared with other modules loaded in the process memory space.

Resources