New in XE3: FireMonkey “TPlatform” refactored as a registry of services
RAD Studio XE3 is a very solid release to me. There are no new compilers since XE2, but there are many new features plus improvements in performance and architecture. This is quite obvious when looking into source code and refactorings of the second edition of FireMonkey framework, now called “FM2”, and originally introduced in RAD Studio XE2 for cross-platform compilation to multiple operating systems.
Architecting one framework and one code base for compiling for multiple different operating systems, both desktop and mobile, poses new challenges. At the end certain things make sense on a tablet, but they simply do not exist on a desktop computer and vice versa. Delphi and C++Builder were always excelling in hiding the underlying complexity of the operating system from a programmer, so she or he could focus on a business problem in hand and implementing application logic without worrying about plumbings. The Visual Component Library introduced in Delphi 1 almost 18 years continues making Windows programming so much easier as compared to writing low-level code and calling Windows APIs directly.
FireMonkey in a sense is a “VCL+”. It provides high-level, object-oriented abstractions and reusable visual components designed for working on many operating systems, not just Windows.
In XE2 “TPlatform” class was an abstract singleton class with concrete implementations on different operating systems. In XE3 this design has been changed, and now “TPlatformServices” class (defined in “FMX.Platform” unit) is a registry of services. You can query the platform static class in code if it implements a certain service, and if it does, you can use obtained interface reference and call methods belonging to a given service. In my opinion this is a much cleaner design and more prepared for the future, when FireMonkey is targeting even more operating systems and devices.
Darren Kosinski has blogged about “TPlatformServices” class recently and explains how to query in code this class for a specific interface. The way to determine whether the current platform supports a particular service is to call “TPlatformServices.Current.SupportsPlatformService”. This function will return a boolean to indicate whether the service is supported or not. An overloaded version provides an out parameter which will return an instance of the service. The usage of this is modeled after the RTL’s Supports function.
A registration procedure, “RegisterCoreServices”, is called during startup to register core FireMonkey platform services that used to be part of the “TPlatform” class.
In Delphi this code could look like this:
if TPlatformServices.Current.SupportsPlatformService(IFMXScreenService, IInterface(ScreenSvc)) then
LSize := ScreenSvc.GetScreenSize;
In C++ the code would be as follows:
if ((TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService)) && (screensvc = TPlatformServices::Current->GetPlatformService(__uuidof(IFMXScreenService)))))
TPointF sz = screensvc->GetScreenSize();
It is always fun to create demo projects and try out new things:-) I have put together a very simple FireMonkey HD Delphi XE3 “Platform Tester” application, with just one button and a memo component. In the OnClick event I’m first displaying information about the version of the operating system that the application is running on using “System.SysUtils.TOSVersion” type and then querying for all interfaces defined in the “FMX.Platform” unit and then calling some methods on every interface, if it makes sense.
You can download this project from CodeCentral and here is the output from this application running on Windows 8
… and on OSX Mountain Lion:
The Delphi XE3 source code for this application is available on CodeCentral.