How to test using conditional defines if the application is Firemonkey one? - delphi

I use DUnit. It has an VCL GUITestRunner and a console TextTestRunner.
In an unit used by both Firemonkey and VCL Forms applications I would like to achieve the following:
If Firemonkey app, if target is OS X, and executing on OS X -> TextTestRunner
If Firemonkey app, if target is 32-bit Windows, executing on Windows -> AllocConsole + TextTestRunner
If VCL app -> GUITestRunner
{$IFDEF MACOS}
TextTestRunner.RunRegisteredTests; // Case 1
{$ELSE}
{$IFDEF MSWINDOWS}
AllocConsole;
{$ENDIF}
{$IFDEF FIREMONKEY_APP} // Case 2 <--------------- HERE
TextTestRunner.RunRegisteredTests;
{$ELSE} // Case 3
GUITestRunner.RunRegisteredTests;
{$IFEND}
{$ENDIF}
Which is the best way to make Case 2 work?

There are no built in conditionals that tell you whether the project's FrameworkType, as specified in the .dproj file, is VCL or FMX. To the very best of my knowledge you cannot switch on that setting in code. Remember also that it is perfectly possible, although certainly not mainstream, to have an application that uses both VCL and FMX. It's really not an either or condition.
So I recommend that you declare your own conditional define that controls whether you use the GUI runner or the text runner.
In fact, you presumably already have some sort of a mechanism to do this. You code names the unit GUITestRunner. So that means it must be in a uses in the same file as the code in the question. How did you conditionally include GUITestRunner in the uses clause?
Note: The same question has been asked on the Embarcadero forums: https://newsgroups.embarcadero.com/message.jspa?messageID=400077

use {$IF Defined(MSWINDOWS)}
instead of {$IFDEF MSWINDOWS}
because {$IFDEF MSWINDOWS} is not working correctly in Firemonkey VCL applications.

Related

How can I detect from code when FastMM4 is used

I want to show a label on a form when FastMM4 is being used ('Uses' in the project file), so that I don't make the mistake of giving the executable to someone who doesn't have FastMM_FullDebugMode.dll installed.
I tried these, but they have are no effect:
{$ifdef FullDebugMode}
LblFastMM4.Visible := true;
{$endif}
{$ifdef EnableMemoryLeakReporting}
LblFastMM4.Visible := true;
{$endif}
How can I detect FastMM4 at runtime?
Note: I don't 'officially' distribute the app with FastMM4. This is just a reminder to myself when I want to give the alpha version to a non-technical user for a quick look. It's annoying if they then bump into the error.
Your {$ifdef}'s don't work because your own code is not including FastMM4Options.inc directly, so FastMM's conditionals are not defined in scope of your code. They are only defined in scope of FastMM's code. You can't test for conditionals that are {$define}'d in someone else's unit.
However, you can use {$If Declared(...)} to check for public symbols that are in scope from using another unit. In this case, the interface section of FastMM4.pas declares various symbols under certain conditions, for instance TRegisteredMemoryLeak when EnableMemoryLeakReporting is defined, DebugGetMem when FullDebugMode is defined, etc.
{$if declared(DebugGetMem)}
LblFastMM4.Visible := true;
{$endif}
{$if declared(TRegisteredMemoryLeak)}
LblFastMM4.Visible := true;
{$endif}
A lot of options can be configured for FastMM. In your case the option DoNotInstallIfDLLMissing can be of value. A nice application is available for setting options: https://jedqc.blogspot.com/2007/07/new-fastmm4-options-interface.html
try this:
LblFastMM4.Visible := InitializationCodeHasRun;

Compiler directive is not set in Delphi 10.2

I have the following unit implementation in my delphi probject.
uses
{$IFDEF Ver270} JSON, {$ELSE} DBXJSON, {$ENDIF}
In Delphi XE4 DBXJSON will be implemented - that's fine.
In Delphi XE6 JSON will be implemented - that's fine too.
But in Delphi 10.2, DBXJSON will be implemented - not JSON. Why? Is this a bug in Delphi 10.2?
This is not a bug, it is by design. Each version has exactly one VERXXX definition. VER270 is defined in XE6 and XE6 only. For version 10.2 VER320 is defined.
In your scenario it is much simpler to use code like this:
uses
{$IF RTLVersion >= 27} JSON, {$ELSE} DBXJSON, {$IFEND}
Another option is to use a standard include file like jedi.inc. This takes the pain out of such conditional statements. If you use jedi.inc then you can code it like this:
uses
{$IFDEF DELPHIXE6_UP} JSON, {$ELSE} DBXJSON, {$ENDIF}

PathDelim VS DirectorySeparatorChar

One can use either
System.IOUtils.TPath.DirectorySeparatorChar
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.IOUtils.TPath.DirectorySeparatorChar
OR
System.SysUtils.PathDelim
Are there any particular differences, benefits using one over another part from System.IOUtils.TPath is more object oriented interface?
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.SysUtils
System.SysUtils.PathDelim was introduced in Delphi 6 / Kylix 1, as a means to enable the writing of platform independent code. The introduction of Kylix, the original Delphi Linux compiler, meant that for the first time Delphi code executed on a *nix platform, as well as its original target of Windows.
System.IOUtils.TPath.DirectorySeparatorChar is part of the IOUtils unit that was introduced more recently to support the current wave of cross-platform tooling, which supports MacOS, iOS, Android and will soon encompass Linux once more.
Where you have a choice between System.SysUtils and System.IOUtils, you are generally expected to use the latter. The System.IOUtils is the cross-platform unit for file system support. That said, you commonly would not use DirectorySeparatorChar directly, but instead would use methods like System.IOUtils.TPath.Combine.
TPath.DirectorySeparatorChar is defined in System.IOUtils as
{$IFDEF MSWINDOWS}
FDirectorySeparatorChar := '\'; // DO NOT LOCALIZE;
// ...
{$ENDIF}
{$IFDEF POSIX}
FDirectorySeparatorChar := '/'; // DO NOT LOCALIZE;
// ...
{$ENDIF}
while PathDelim is defined in System.SysUtils as
PathDelim = {$IFDEF MSWINDOWS} '\'; {$ELSE} '/'; {$ENDIF}
While the conditionals are slightly different, they would only differ if neither or both of MSWINDOWS and POSIX were defined, which is not the case for any platform. And if there would be such a platform in the future, the declarations would surely be fixed accordingly.
TL;DR: There is no difference, you can use either based on your preference.

What is the Delphi 10 equivalent to DesignIntf?

Just updated the SynEdit RunTime module for Delphi 10.1 Berlin, but now I need to update the DesignTime Module... The Designer units from Delphi XE versions do not appear to be available in 10.1.
What is the recommended Design Editor and Interface module to replace the old Delphi Designers?
I was thinking there would be built-in XAML designers, since the new Delphi supports .NETCore.
Is there an alternate designer to use for FMX and cross-platform projects?
example found... requires FMX.Types unit and a header over the class
https://delphihaven.wordpress.com/2013/02/03/writing-a-simple-firemonkey-tlistlayout-implementation/
uses
System.SysUtils, System.Classes, FMX.Types;
type
[ComponentPlatforms(pidWin32 or pidWin64 or pidOSX32)]
TListLayout = class(TControl)
Here's how I changed my headers for XE, Delphi 10 and Firemonkey
(*
Directive Description
------------------------------------------------------------------------------
LINUX Defined when target platform is Linux // FOR KYLIX
// FOR WINDOWS VERSIONS USE VCL
WIN32 Defined when target platform is 32 bit Windows
WIN64 Defined when target platform is 64 bit Windows
CLR Defined when target platform is .NET
WINVCL // ADDING TO REPRESENT ALL VCL platforms
// FOR OTHER USE ELSE
// *)
{$IFDEF WIN32}
{$DEFINE WINVCL}
{$ELSE}
{$IFDEF WIN64}
{$DEFINE WINVCL}
{$ELSE}
{$IFDEF CLR}
{$DEFINE WINVCL}
{$ENDIF}
{$ENDIF}
{$ENDIF}
uses
{$IFDEF LINUX} // Kylix is target platform
QControls,
{$ELSE}
{$IFDEF WINVCL}
VCL.Controls,
{$ELSE} // ALL OTHER PLATFORMS USE FIREMONKEY CONTROLS
FMX.Controls,
FMX.Types,
{$ENDIF}
{$ENDIF}
System.Classes;
And the new controls start out like this now...
[ComponentPlatforms(pidWin32 or pidWin64 or pidAndroid or pidOSX32)]
TMyCustomComponent = class(TControl)
Nothing has changed. Your design-time package should require designide.dcp and the necessary runtime package. Designide contains what you need.
Use the Getit Package Manager
But this can be a lot simpler. I just did the following:
In the IDE, selected Getit Package Manager from the Tools menu.
Searched for Synedit
Found Synedit Turbo Pack and clicked Install
A dialog popped up. I clicked agreement and it went on installing Synedit (although with the old 230 version suffix - this ought to be changed to 240 for Berlin)
After that, I could continue editing what I was editing before this, and the latest Synedit was installed.
SyneditPropertyReg.pas still uses the same units, like DesignIntf, DesignEditors, etc.
Note that now, there are (at least) two packages: SyneditDD.dpk and SyneditDR.dpk. The latter is the runtime package, the former is the designtime package and that should require the runtime package as well as designide. I think the installer compiled a little more, but it went so fast, I couldn't see properly.

How to force LeakCheck Delphi library to not collect data?

I use Delphi's LeakCheck library https://bitbucket.org/shadow_cs/delphi-leakcheck.
I know I can disable leak reporting using a construct like this:
{$IFDEF DEBUG}
System.ReportMemoryLeaksOnShutdown := true; // this will enable LeakCheck to display a message on Windows
{$ELSE}
System.ReportMemoryLeaksOnShutdown := false;
{$ENDIF}
But I also need the library to NOT collect any data when compiled in RELEASE mode.
I can easily "hack" the LeakCheck.pas initialization/finalization sections like this:
...
{$IFDEF DEBUG} // <--- Code added by me
initialization
TLeakCheck.Initialize;
finalization
TLeakCheck.Finalize;
{$ENDIF} // <--- Code added by me
end.
Is there any better way? A conditional define I miss or a global property?
I don't use the specific library (LeakCheck) you mention, but I typically do this by only including the unit when the right configuration is defined (in this case, DEBUG). This means that in release it's not even included in the executable.
uses
...,
{$IFDEF Debug}
LeakCheck,
{$ENDIF}
...;
As is pointed out in a comment, LeakCheck has to be the first unit listed in the .dpr's uses clause, which may cause an occasional problem with the IDE; it sometimes ends up breaking due to the {$IFDEF}. I usually don't find this to be a major issue, because once it happens and you've seen what the cause is, it's pretty easy to just go back in and fix it.
If that becomes too much of an issue, there is another workaround - create a new unit that does nothing but use LeakCheck and SysUtils, and add the above {$IFDEF} in that unit. You then include the new unit first in your .dpr. As it's only task is actually to use LeakCheck, it still puts LeakCheck in first-compile order in the .dpr when needed, and does not include it at all when not.

Resources