How to name files to differentiated VCL and FireMonkey code - delphi

I have a VCL component that runs on Delphi 7 to 10.3. I am now porting it to FMX.
To avoid maintaining two codebases, I will use conditional defines in my source to separate any custom FMX and VCL code. When I compile the component for distribution a script will output either the VCL or FMX source files.
My problem is how to make the VCL DCUs and FMX DCUs co-exist on the same system (for users who have both the VCL and FMX versions of my component) as both folders will need to be on the Delphi path.
In other words, my VCL units are named: myunit1.pas, myunit2.pas, etc.
And the FMX versions: fmx.myunit1.pas, fmx.myunit2.pas, etc
(Ideally I would name the VCL ones vcl.myunit1.pas, vcl.myunit2.pas, etc. That way the VCL version of the component would only see the vcl.-.pas files and the FireMonkey only the fmx.-.pas files. Unfortunately I cannot do this because then it won't work on older Delphi versions).
Now when I compile a FireMonkey app it tries to use the non-fmx prefixed source files, in preference to the fmx._.pas ones. I need to "hide" the vcl source folder to get it to compile (re-ordering the Delphi paths does not help).
If there another way to make FireMonkey avoid using the vcl files?
(I fear I will need to write a script to give all the files a new name, e.g. FMXmyunit1.pas and update all of the references in all of the files).

Because Delphi does not provide predefined compiler conditionals to distinguish between the Firemonkey and the VCL framework you can add the symbol $(FrameworkType) into the conditional defines list of the application project settings. This enables the differentiation of the framework within your library by using the conditional compiling symbols FMX and VCL.
Example of typical usage:
uses
{$IFDEF FMX}
FMX.Forms,
{$ENDIF}
{$IFDEF VCL}
VCL.Forms,
{$ENDIF}
This works in my own cross-platform library for pure VCL and FMX projects, where I let integrate the source files directly into the project. In this simple way, the DCU will be recompiled each time. In the case of mixed projects, the $(FrameworkType) contains the initial framework of the application.
When you deliver a package (bpl) things get more complex. You must provide two versions of your bpl for FMX and VCL. If you also provide the source code for debugging purposes, the only option is to completely differentiate the source code files for the FMX and VCL versions, as long as they have platform-dependent code.

Well, I don't know if it's really a solution, but it works for me.
I wrote an application that copies all my VCL files to my FireMonkey folder and renames them with an FMX prefix, i.e myunit.pas becomes FMXmyunit.pas. It also updates all the references in the pas files and adds a {$DEFINE FMX} to the header. Now both my VCL and FMX versions coexist happily.
Also, I have set my merge tool (Beyond Compare) to ignore the FMX prefix, so I can merge either platform version directly to my local Git copy.

Related

Cannot add TMS async components to win32 firemonkey program

I have a firemonkey app targeted only at win32. I want to add the tms async serial communications component. When I do so and try to build it gets upset trying to compile the tms source code. It is non-trivial to change the tms source code.
Where is it picking up the library path to the source code? If I remove that path will it use the existing .dcu files and work? Is there any other suggestions?
What was catching me is that even though I had removed the directories from the options search path,, I had one of the tms rtl files still open in the ide. As a precaution, I also went and moved the tms source files elsewhere...
The form compiled and the components work.

Can I make the `requires` clause in a package conditional?

I'm using Anders Melander's DragDrop package.
It works fine in Win32 mode, but needs adjustment for 64 bit.
I do this by adding {$IFNDEF CPUX64} to comment out the references to the designIDE.
However when I change the package source from
requires
rtl,
DesignIDE;
to
requires
rtl
{$IFNDEF CPUX64} ,DesignIDE{$ENDIF};
The compiler simply throws away the DesignIDE line in the package source, leaving only:
requires
rtl;
Which works fine for X64, but breaks as soon as I rebuilt for 32-bit.
Is there a way to have one package including design-time items for win32 with the conflicting items IFDEF'ed out for X64? Or am I forced to create a separate Runtime package for X64?
No, you cannot use conditionals in any project main file. The IDE owns and controls it, and is subject to discarding (and even destroying) any customization you do with conditionals. You will need to create a second package for this, which is normal practice for using DesignIDE anyway. Even if it weren't for supporting 64bit, you're not permitted to deploy DesignIDE with any application. It is for the sole purpose of integrating with the IDE, which for legal reasons, must only reside in a Design-Time package.
Bear in mind also that the Design-Time package must only be Win32, as the Delphi IDE is only 32bit. Then, the Run-Time package can be any supported platform you wish (i.e. Win64), of course as long as it's supported by any framework it might be using.

How to include Vcl.ImgList in Delphi

In compiling a Delphi 2007 project, I receive the following error:
E203: Undeclared identifier: TChangeLink
This appears to belong to the Vcl > ImgList library.
My limited understanding is that Vcl is part of the native Delphi libraries. How do I verify that it is correctly referenced?
It's because ImgList isn't in your uses clause. Based on information you provided in a comment,
uses contains this line:
Clipbrd{$IFDEF DELPHI4}, ImgList {$ENDIF}, dxCommon{$IFDEF DELPHI6}, Variants{$ENDIF}
It's because the {$IFDEF DELPHI4} is excluding it, presumably because DELPHI4 isn't defined. This is typically caused by using code that is in open-source or commercial component sets that use those version defines to support multiple Delphi versions with the same source. (This is usually done in a .INC file of some sort; Jedi uses JEDI.INC, for instance, for all of the version defines for various compiler and IDE related differences.)
The best solution (to maintain cross-version compatibility) would be to update the definitions to include Delphi 2007, but I can't offer advice on how to do so because I don't know where the define is located. The other alternative is to just remove the {$IFDEF DELPHI4} from the uses clause, if you don't need to worry about earlier versions of the IDE/compiler.

TOleServer and its unit not available for Firmenkey in Delphi?

As the title suggest, I can't find that unit.
Is there an equivalent?
I am trying to port a unit from VCL to Firemonkey which contains OleServer in its uses clause, but I can't find any information on Embarcaderos website regarding this problem.
I have also tried to Google it, but no success.
Where can I find TOleServer and/or its unit OleServer that is compatible with Firemonkey?
Or how can I implement that unit in my Firemonkey project?
Hi i have the same problèm before and i made change in OleServer
Copy Vcl.OleSever to your project and rename it to FMX.OleServer
in implementation section do change like this:
implementation
uses
FMX.Controls;
resourcestring
sNoRunningObject = 'Unable to retrieve a pointer to a running object registered with OLE for %s/%s';
at the initialization section change to FMX.Controls.TControl
initialization
GroupDescendentsWith(TOleServer, FMX.Controls.TControl);
end.
Finally rename VCL.OleServer to FMX.OleServer in your imported library unit
Indeed the main issue with compiling TLB (typelibrary) units for COM/OLE Servers seems to be some unit renaming that has occured. Ideally the Delphi IDE should detect this automatically and fix it.
Based on Doug Rudd's comment above I fixed my "uses OleServer" to "uses Vcl.OleServer" in my TLB unit.
Since there's a "source" folder under Delphi installation folder even for the Pro version now (at least at 10.2.2 Tokyo version that I'm currently using), I could also easily spot (using GrepWin free tool) where the "EmptyParam" that was causing my TLB to not compile had gone. It is under System.Variants unit that one also needs to use in their TLB (before it was in System so you didn't need to use some unit for it).
Guess I could have imported the COM/OLE Server again to make new TLB import unit, but since it was hand-ended (to remove using of "Graphics", "StdVcl" and "OleCtrls" units that were bloating the executable size in older versions of Delphi) and that hand-edited imported TLB used to work fine for a command-line application, I didn't have any reason to reimport the Type Library.
You can see the changes I did to make my XSLer tool work with the latest Delphi at https://github.com/Zoomicon/tranXform/commit/e99f42049b8a4c1534d9edb78ed5e6493e6e5786. That XSLer command-line tool is using MSXML (Microsoft XML) automation server.

Error: F1026 File not found: 'System.Actions.dcu' switching back to Delphi XE2 from XE3

I'm moving my code to Delphi XE3 from XE2, but it should compile in both. I notice that some units get 'System.Actions' auto added to the USES clause. This then causes an error when returning to XE2 with:
F1026 File not found: 'System.Actions.dcu' (unit scope "System" indicates Win64, OSX32, Win32 only)
I've never really understood unit scope properly. Is there a correct solution to resolve this rather than wrapping stuff within compiler version {$IFDEF}'s?
Thanks
There is no Actions unit in XE2. It is new in XE3, as part of refactoring work to bring Actions support into FireMonkey. This is documented:
What's New in Delphi and C++Builder XE3:
Actions: FireMonkey now supports actions and action lists, two features that were previously supported only in VCL:
Important: Every FireMonkey or VCL application that uses actions must specify the System.Actions and System.Classes units in the uses section.
Changes in Implementation of VCL Actions
The System.Actions unit is created in the RTL package. Classes from the Vcl.ActnList unit that provide framework-independent action features are moved into this unit. Classes in System.Actions extend the most fundamental behavior of action features introduced in the TBasicAction and TBasicActionLink classes.
Important: As a result of these changes, you need to add the System.Classes and System.Actions units into the uses section.
Implementation of Actions in FireMonkey and VCL
FireMonkey (FMX)
The framework-independent implementation is common to FireMonkey and VCL:
This basic actions functionality is extended in the new System.Actions RTL unit.
VCL
Framework-independent action features that were implemented in the Vcl.ActnList unit in previous RAD Studio releases are now in the new System.Actions unit in the RTL (common to VCL and FireMonkey).
Important: As a result of these changes, you need to add the System.Actions unit to the uses section (or #includes) in your VCL applications that use actions.
You will have to either remove the reference to Actions if you are not actually using actions in your code, or else {$IFDEF} it out.
What Remy said is quite correct, but there may be an easier way to make your code work in both XE2 and XE3. Simply add a unit alias from System.Actions to Vcl.ActnList.
Add this in your project options, on the Delphi Compiler page. You need to add the following:
System.Actions=Vcl.ActnList
Note that if you need to compile in both XE2 and XE3 using the same .dproj file then you are out of luck. That unit alias setting will stop the program compiling under XE3. However, if you have have different .dproj files for XE2 and XE3, then this will allow you to use the same source in both. Or, if you only need to compile for XE2 at the command line, then you could add this unit alias there. I can't tell whether or not this will help you, but I know that the unit alias feature has helped me out of a similar spot on more than one occasion in the past.
If you have ONE project file you still can solve the problem with a "dummy" System.Actions.pas file in your project path directory:
This file will be taken under XE2.
The XE3 compiler will find his System.Actions.dcu in the IDE /lib directory.
Anyway: In normal cases you should use different project files - then the solution with the unit alias is recommended.
The dummy System.Actions.pas could look like:
unit System.Actions;
(*
XE2 compatibility unit: since XE3 unit System.Actions will be inserted into every
interface in units which use actions.
compilerswitch in [uses] is ignored by IDE - so this solution enable successful
compilation in XE2 with same project file than XE3
*)
interface
implementation
end.

Resources