Conditional compilation for various Delphi versions

If you are maintaining a library, component or plugin for various Delphi versions you will sooner or later hit a point where it becomes necessary to have different code for some of them. Some examples are: The constants faTemporary and faSymlink are only declared in Delphi 2009 and later, so you have to declare them yourself for older versions. Some Open Tools API function have bugs in some versions so you have to implement a workaround. Some classes or functions have been added to later versions of the RTL so you need to implement them yourself for older versions, but you don’t want to use these implementations for newer versions The traditional way of masking code for some Delphi versions is using the VERxxx symbols which the compiler defines, where xxx is the compiler version multiplied by 10. Note that the compiler versions started with Turbo Pascal, not with Delphi, so VER60 is not Delphi 6 but Turbo Pascal 6, while Delphi 6 is compiler version 14 and therefore defines VER140. By the time of this writing the current Delphi version is 10.3 Rio which contains the compiler version 33. {$IFDEF VER330} // Delphi 10.3 Rio // do some version specific stuff here {$ENDIF} There are various include files that make this more convenient by adding symbols like DELPHInn and DELPHInn_UP so you don’t have to memorize those VERxxx symbols. {$IFDEF DelphiX103} // do some version specific stuff here {$ENDIF} But using these include files has got a major drawback: If you forget to include it into your source code, all your IFDEFS will fail and in the worst case your workaround won’t be active (the best case is that the compiler runs into an error so you will notice the missing include). An alternative is the {$IF } compiler directive which can test for arbitrary Boolean expressions, like const SomeConstantValue = 5; //later on {$IF SomeConstantValue >= 5} // do some stuff here that requires SomeConstValue to be at least 5 {$ENDIF} It was added to the Delphi compiler in Delphi 6, so it covers quite a few Delphi versions. Combined with predefined constants (in the System unit) like CompilerVersion RtlVersion FireMonkeyVersion (in FMX.Types) this is a powerful method for conditional compilation. {$IF CompilerVersion = 330} // Delphi 10.3 Rio // do some version specific stuff here {$ENDIF} It can also replace those additional symbols DELPHInn_UP I mentioned above: “>=” replaces {$IFDEF DELPHInn_UP} and “=” you can “future proof” your code, assuming that code for Delphi 10.3 Rio will also work with all newer versions of Delphi. {$IF CompilerVersion >= 330} // Delphi 10.3 Rio // do some version specific stuff here that will // hopefully also work in the future {$ENDIF} But unfortunately we are back to memorizing compiler and RTL version constants. Even with tools like the IF Directive Expert in GExperts this is a nuisance because if you forget to add a comment (or if you later change the expression and forget to update the comment), you will still have to know those values to understand the code. So, what can be done? An idea that occurred to me today (Yes, I am a bit slow on creativity.) would be to define additional constants which can then be used to compare against the CompilerVersion and RtlVersion constants. unit CompilerAndRtlVersions; interface const CompilerVersionDelphi6 = 14; CompilerVersionDelphi7 = 15; // we all want to forget Delphi 8, but it had compiler version 16 CompilerVersionDelphi2005 = 17; CompilerVersionDelphi2006 = 18; CompilerVersionDelphi2007 = 18.5; // anybody remember Delphi 2007 for dotNET? That one had compiler version 19 CompilerVersionDelphi2009 = 20; // and so on until CompilerVersionDelphiRio = 33; // and of course we would also need the RtlVersions: const RtlVersionDelphi6 = 14; RtlVersionDelphi7 = 15; // and so on until RtlVersionDelphiRio = 33; implementation end. Add the above unit to the uses clause and you can do: {$IF CompilerVersion >= CompilerVersionDelphiRio} // do some version specific stuff here {$ENDIF} These constants should go into a unit rather into an include file so the compiler will complain if you forget to add that unit to the uses clause. In addition a unit will be compiled once and afterwards the compiler will use the DCU file it created, while an include fill will be parsed every single time it is included. This should speed up compilation a (probably tiny) bit. I am not aware if such a unit already exists, but I would probably write it and make it available if not (it’s not excactly rocket science after all). Edit: Here you go, my brand new u_dzCompilerAndRtlVersions unit. I already blogged about using and ab-using ifdef in 2013, if you are interested in this topic.
Read More

New Delphi 10.3 Warning "Unknown Custom Attribute"

Up to Delphi 102, if you used a custom attribute that was not known to the compiler (because you typed it incorrectly or a unit was missing in the uses statement), you'd receive the warning: Warning: W1025 Unsupported language feature: 'custom attribute' This message was misleading, because the feature has been in the language for quite some time, it was just using an undefined symbol in it. There is a large list of reports on this issue, including https://quality.embarcadero.com/browse/RSP-20384.  Starting with 10.3, the same code will trigger a new specific warning: Warning: W1074 Unknown custom attribute This conveys a more specific information. It also makes it is easier to turn this warning into an error -- which would often make sense, by using the directive: {$WARN UNKNOWN_CUSTOM_ATTRIBUTE ERROR} In the past you could achieve the same by turning the unsupported language feature warnings into errors, but that could have included also other unwanted scenarios.
Read More

Delphi RTL Improvements in 10.3 Rio

While working on 10.2 updates, we started delving into some performance issues of the Delphi RTL, that were effecting other libraries like JSON processing, streaming, string processing, DataSnap and RAD Server web services, and more. In many cases, addressing these issues required adding new methods to existing classes, or adding new global functions, something we can do only in interface breaking releases like 10.3. Optimization and performance was a guiding factor to many of the changes listed below, but not the only element. We also wanted to update external libraries, improve conformance to standards like JSON and HTTP, and improve quality overall. With this scenario in mind, the list of improvements is fairly long (and a bit boring, sorry). Change in Data Structures Growth Strategy Several data structures (like TStringList, TList, TList , TQueue and TStack) have now a flexible growth strategy when the internal storage is full and needs to be expanded after adding an additional item. In the past, the strategy was to double the size of the underlying structure, something that works fine for smaller sizes, but not when you have several MB of storage. Now the rules is to increase capacity by 1.5 times. For example you can check a TStringList growth by checking the Capacity property, which now grows as follows (from 14K to 74K): 14,761 22,141 33,211 49,816 74,724 This behavior, shared by multiple collection classes, is defined in the new function, declared in SysUtils.pas: function GrowCollection(OldCapacity, NewCount: Integer): Integer; Now the interesting element is that the implementation can be replaced with a custom function growth strategy, by writing a new compatible function and calling the global SetGrowCollectionFunc procedure.  Changes in TStringBuilder Class The TStringBuilder class has had several changes with the goal of improving its performance, including a similar change in memory growth strategy, the removal of some redundant code, and an overall implementation cleanup. The TStringBuilder enumerator has been optimized, however it expects that the TStringBuilder object will be not modified while the enumerator is processing it (which is a common behavior for enumerations). There is also an additional parameter for the TStringBuilder.ToString method. The signature is ToString (UpdateCapacity: Boolean). ToString(True) will give better performance if no more modifications expected for TStringBuilder, as it reduces the amount of data being copied. Lists-Related Improvements There are other improvements related with lists and collections. The generic TList and the generic TDictionary have new public properties to make their comparers (the definition of their comparison operations for sorting) accessible after initialization. We've added a TryAdd method to TDictionary, an ExtractAt to TObjectList and significantly improved the performance of several operations (IndexOf, Add, and more). We have also specifically optimized for-in loops for generic collections and string lists, with an empty "for in" loop about 3 times faster  JSON-Related Improvements In 10.3 we have improved the correctness of JSON content, in terms of the JSON code generated by the TJSONValue class and derived ones, but also in terms of parsing. We have also worked on performance improvements. There is a new TAsciiStreamWriter class that can be combined with a TJSONTextWriter to give the best JSON string generation performance (as it does almost no conversion at all). There is now “pretty print” JSON output with the introduction of the new TJSONAncestor.Format(Indentation: Integer = 4). As a consequence, TJSON.Format has been deprecated. We have also clarified (and properly implemented) the difference between calling ToJSON and ToString for a JSON object: TJSONAncestor.ToJSON always produces a formally valid JSON string TJSONAncestor.ToString produces a similar JSON string, but without converting non-ASCII symbols to \uNNNN (faster, but not formally valid) JSON parsing support has a new behavior in case of errors in the JSON source text, allowing you to raise an exception with information about the error position in the source text, rather than just returning nil. The new option controlling the behavior is TJSONParseOption.RaiseExc. If the exception is enabled, ParseJSONValue raises the new System.JSON.EJSONParseException (which has the properties Path, Offset, Line, and Position). Additionally, the method TJSONObject.ParseJSONValue has a third new parameter: RaiseExc, which overrides the global setting causing the exception to be raised, in case of JSON parsing errors. TMemIniFile Class Improvements In Delphi 10.3 we have optimized the TMemIniFile implementation. Reading and constructing a TMemIniFile is 10 to 25 times faster and consumes half of the memory. Other TMemIniFile operations are improved too and they are 50 to 100% faster compared to the previous implementation. We have also added the ability to load a TMemIniFile from a stream, with two additional overloaded constructors: TMemIniFile.Create(Stream) and TMemIniFile.Create(Stream, UseLocale). These constructors parameters remain available in the class and are exposed in new properties, Stream and UseLocale. External Libraries Updates (zLib, PCRE, Unicode) We have done some improvements to external libraries we incorporate: zlib has been upgraded to version 1.2.11 1.2.8 with additional fixes (and it is now compiled with RAD Studio C++ compiler for 64-bit) The regular expression engine, PCRE, has been upgraded to 8.42 (and also now compiled with RAD Studio C++ compiler), and supports the UTF-16 native version on Windows (to reduce the conversions from UTF-16 string to UTF-8 strings). The Unicode table (System.Character unit) supports Unicode v11.0. A Lot Was Done in 10.3 for Delphi RTL As you can see the number of improvements in Delphi RTL for 10.3 Rio is fairly significant, not to mention the work focused on fixing bugs and improving quality. There is more for the HTTP and other client libraries, which I'll cover in a separate blog post.
Read More

Found the cause of the AV on exiting the Delphi IDE

There was a bug in the (yet unreleased) GExperts code that caused an access violation every time the Delphi IDE was closed. I have just found it, but boy was that difficult! I knew the problem existed in the current source code and by trial and error I found a source code revision that did not yet have it: #2415. So I compared those revisions and step by step narrowed it down to the changes in the unit GX_IdeFormChangeManager in revision #2433 which was a fix for a redrawing bug in the Delphi 10.2 Search Path dialog. So I removed the code I had added, which consisted of two parts: procedure TFormChangeManagerInternal.ProcessActivatedForm(Form: TCustomForm); var i: Integer; NeedsWorkaround: Boolean; begin Assert(Assigned(Form)); // We are executing the callbacks in last registered first order to allow callbacks to // unregister themselves. (And we don't check whether a callback only unregisters itself, so // please be cautios!). That means registering a new callback while executing a callback // is not allowed. FIsInFormChangeCallback := True; try // ------------- workaround part 1 starts here ------------ // Workaround for redraw issue in Delphi 10.2 when theming is enabled: // https://sourceforge.net/p/gexperts/bugs/86/ // Disable redraws while we change the window NeedsWorkaround := HasRedrawProblems(Form); if NeedsWorkaround then SendMessage(Form.Handle, WM_SETREDRAW, WParam(False), 0); // ------------- workaround part 1 ends here ------------ try for i := FFormChangeCallbacks.Count - 1 downto 0 do begin try TFormChangeCallbackItem(FFormChangeCallbacks[i]).FCallback(Self, Form); except // just so we can have a look at any exceptions that might be raised ... raise; end; end; finally // ------------- workaround part 2 starts here ------------ if NeedsWorkaround then begin // Allow and force a redraw of the whole window SendMessage(Form.Handle, WM_SETREDRAW, WParam(True), 0); RedrawWindow(Form.Handle, nil, 0, RDW_INVALIDATE or RDW_ALLCHILDREN); // see Remarks on // https://docs.microsoft.com/en-us/windows/desktop/gdi/wm-setredraw end; // ------------- workaround part 2 ends here ------------ end; finally FIsInFormChangeCallback := False; end; end; I didn’t really think this could make a difference because the HasRedrawProblems function only returns true in Delphi 10.2 but the AV occurred in all versions of the IDE. And guess what? It didn’t make a difference at all! The AV still happened. So I reverted all the changes to the unit, which included the addition of a few units to the uses clause in the implementation section: Messages, Registry and GX_IdeSearchPathEnhancer The AV was gone! Now what? I added Messages and Registry again, everything still was fine. Then I added GX_IdeSearchPathEnhancer and boom, the AV was back. After I knew what to look for, the cause was simple to spot: Both units GX_IdeSearchPathEnhancer and GX_IdeFormChangeManager have got a finalization section. They both free an instance of a class that gets created some time during the life time of a GExperts session. By adding GX_IdeSearchPathEnhancer to the uses list of GX_IdeFormChangeManager, the execution order of the finalization sections changed. The unit GX_IdeFormChangeManager provides a singleton instance of TFormChangeManagerInternal which gets created on demand in any of the class methods of TIDEFormChangeManager. That instance is freed in the finalization section. The unit GX_IdeSearchPathEnhancer has an internal instance of TSearchPathEnhancer which also gets freed in its finalization section. TSearchPathEnhancer.Create registers itself for Screen.OnActiveFormChanged events to detect when the IDE’s Sarch Path dialog is being shown. In the Destructor it unregisters itself for that event. So far, so good, now the problem occurs when the finalization of GX_IdeFormChangeManager runs before the one of GX_IdeSearchPathEnhancer: The singleton instance of TFormChangeManagerInternal gets freed and afterwards the destructor of TSearchPathEnhancer tries to use it to unregister itself from the OnActiveFormChanged event. This created a new TFormChangeManagerInternal instance which hooked the Screen.OnActiveFormChanged event. Since the finalization of GX_IdeFormChangeManager had already run, this new instance never got freed, so as soon as the GExperts DLL was unloaded, the event pointed to uninitialized memory and thus the access violation occurred. This of course will never show anything usable in the debugger as the offending code has already been unloaded. Now you might ask, why in the world I added the additional unit to the uses clause? That was because of the fix introduced in that revision. It needed to know if the new active form as the Search Path dialog, and following the Don’t repeat yourself (DRY) principle [1] of good software development, I moved the code for detecting that, which was already in a method of TSearchPathEnhancer, to a public class method of that class. So I avoided duplicating the code. but in order to call that class method, I had to add the unit to the uses clause. Which introduced the bug. Even though it was difficult to trace it, at least it was a reproducible bug, so I could finally track it down. Now I’m going to fix it and then I will start testing GExperts in Delphi 10.3 so I can make a new release. [1] Yes, it is DRY, because the knowledge of how to detect if a form is the Sarch Path dialog is “business knowledge”, in this case knowledge about what class and name that form has in any of the IDE versions.
Read More

Delphi 10.3 Rio got released; I’ll wait a while hoping to see more positive comments

The first messages on G+ saw about Delphi 10.3 Rio are these: [WayBack] Delphi 10.3 is online. – Ralf Stocker – Google+ [WayBack] The platform selection in Delphi Rio seems to be down. – Gert Scholten – Google+ [WayBack] license.embarcadero.com is down. Perhaps this is a good sign, because of overwhelming interest in Rio, but it does not make a great impression. Can thi… – Johan Bontes – Google+ [WayBack] Just installed Delphi 10.3 and used migrationtool.exe to import 10.2 settings, and my projects fail to compile with the following error (I am not even c… – Eric Grange – Google+ [WayBack] FMX minimize bug fix for Delphi Rio Community. The two screenshots show you how. https://quality.embarcadero.com/browse/RSP-17322 You at home would ne… – Gustav Schubert – Google+ [RSP-17285] Window minimize-restore via taskbar icon click is broken in all Windows flavours – Embarcadero Technologies (10.1/10.2 problem that was supposedly fixed in 10.3) [RSP-17322] Window minimize-restore via taskbar icon click is broken in all Windows flavours – Embarcadero Technologies has the fix for 10.3, but did not make it in 10.3 [WayBack] I think I figured it out and here is my unofficial update to FMX.Platform.Win ready for beta testing. Improvement claims: 1) click on task bar button w… – Gustav Schubert – Google+ [WayBack] … but I am working on it. I have already installed the new version and it compiles on my machine. But don’t hold your breath, there are some issues. Unt… – Thomas Mueller (dummzeuch) – Google+ I think I will wait a while before installing until more positive messages are being published. If you do want to try, the hashes of delphicbuilder10_3_0_94364.iso are these: crc32 157b6e36 md5 0882d58cb53a7d0a828cc45d06c6ecd0 sha1 21579b530f781895885923809d9e670b439ebf9d sha256 9213de93c2abdd6a2ee23aa84fc7e63a87d62d0344f0d0f0ee162d0e7dce7c7d ––jeroen PS: [WayBack] How to verify file hashes on macOS | ModMy
Read More

RAD Studio 10.3 Rio supports Android runtime permissions

RAD Studio 10.3 Rio has just been released for General Availability, as you’ll have doubtless learned from the spree of blog posts on the subject. This is a great new release with a lot of bug fixes and some nice updates to product behaviour and features.One feature that seems to have not received its fair share of attention in the documentation is the support for the Android 6.0 (and later) runtime permissions model. This caused a bit of frustration earlier in the year when Google changed the Play Store submission rules so that from August 2018 new apps have to follow this new permissions model and from November 2018 app updates also new apps have to.RAD Studio 10.3 enhances the basic Android support to ensure that Android apps built with Delphi or C++ now understand and can support this new model, which may require a bit of change to your application logic.In essence, instead of all permissions being granted on application installation, so-called dangerous permissions now need to be requested at runtime where the user can grant or deny them as they see fit. Additionally the user can change their mind in the app settings and toggle the permissions at any time.The Android RTL has been enhanced with a framework to support requesting permissions at runtime and being notified of the user’s decision, and potentially offering a little explanation for the need for the permission.As mentioned the documentation for this framework falls a little short right now (at product launch), but hopefully will improve over time. To try and plug the gap I’ve written an article showing how the permission framework can be used, both in Delphi and in C++. If interested in learning more about the Android runtime permission framework introduced in RAD Studio 10.3 Rio, please follow one of these links:Runtime permissions in Android (new in Delphi 10.3)Runtime permissions in Android (new in C++ 10.3)Finally, while I have your attention on things Android, I would like to draw your attention to the Android-specific release notes for RAD Studio 10.3. You should read these to be sure of getting on with your first Android project with the new product release. It needs and uses a later Android SDK and NDK and you mat encounter some teething niggles on installation. These notes should help you!
Read More

TMS WEB Core v1.0 Brescia tips & tricks part 3

Lots of enthusiast Delphi developers already got started exploring TMS WEB Core web application development and some even successfully building their first web applications for customers. There are literally tons of little tips and tricks for creating polished first-class web applications. So, we thought it was about time to share two new tips!

Facilitating credential persistence in the browser

To capture user credentials, we commonly use a TWebEdit for the username and another TWebEdit for the password with PasswordChar set to *.
This can be sufficient to get the username and password to let a user login, but let’s polish this somewhat more to todays’ standards where we are used to the browser recognizing login and offering to persist the credentials for reuse later.

To do this in a TMS WEB Core application is straightforward. All we need to do is set the WebEdit.AutoCompletion to acUserName for the username edit box and WebEdit.AutoCompletion to acCurrentPassword for the password. This is sufficient to have most browsers recognize the login fields and offering to persist.

For the sample app we created for this, we added some more pizzazz by adding Bootstrap and a Google Material design icon to a login button. To add support for this, select “Manage JavaScript Libraries” from the project context menu in the IDE and check Bootstrap and Google Material design.

Once this is selected, we can set the Bootstrap classname ‘form-control’ to WebEdit.ElementClassName and we set ‘btn btn-primary’ to WebButton.ElementClassName.
We can use the Google Material icon for a lock in the button caption, by setting the caption to:

<i class="material-icons">lock</i>Login

In the Chrome browser, this looks like:

In the Safari browser on iOS the login is recognized and iOS proposes to autocomplete the entry coupled to its Touch ID technology or Face ID on newer devices:

 

Persisting values in localstorage

There are various ways to store data with the browser. Cookies and session data offer this capability as well as local storage or for more extensive use something like IndexedDB.
For this tip, we show persisting the content of a TWebMemo control in local storage. This way, we can at any time persist the memo content and when the user would leave the application and return later to it, the memo content would be the same as where he left off.

To do this, we implement the TWebMemo.OnExit event and use the TLocalStorage class to persist:

uses
  WebLib.Storage;

procedure TForm2.WebMemo1Exit(Sender: TObject);
var
  cs: TLocalStorage;
begin
  cs := TLocalStorage.Create;
  try
    cs.SetValue('memo', WebMemo1.Lines.Text);
  finally
    cs.Free;
  end;
end;

To load the TWebMemo with data where the user left off, we add following code to the Form’s OnShow event:

procedure TForm2.WebFormShow(Sender: TObject);
var
  cs: TLocalStorage;
begin
  cs := TLocalStorage.Create;
  try
    WebMemo1.Lines.Text := cs.GetValue('memo');
  finally
    cs.Free;
  end;
end;

Interested in fast RAD component based web client application development with Delphi? Get started today: TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are all available separately now or as part of the TMS-ALL-ACCESS subscription!

Read More

Read More

Reminder to self: check if David Nottage published source code the Firebase application analytics

I need to check the outcome of this comment at [WayBack] Google analytics is no more avaliable for analytic Apps and send to firebase when you want to track a new App. How to do with firebase analytics? there … – Xavi P. – Google+: I’m working on an implementation. It’ll be an extension of what I did with Firebase Cloud Messaging: [WayBack] Adding Firebase Cloud Messaging to your mobile apps – part 1 – Delphi Worlds However, my implementation may or may not become a part of a commercial solution that includes other Firebase services, including Firebase Database, using the Android and iOS SDKs –jeroen
Read More

What’s New and Updated in GetIt for November 2018

The GetIt Package Manager is your source for RAD Studio, Delphi, and C++Builder add-ins and packages built right into your favorite IDE. Here’s a look at what was new and updated during the month of October 2018 along with the most popular downloads. Find a new favorite for November today!

Want your Package, Library, Trial, or Open Source Project in GetIt? Just fill out this form.

New and Updated

The following components are new to GetIt this month, or were recently updated to a newer version.

 

Delphi Console – Delphi Console is a Delphi implementation of the well-known C# class: System.Console. With this in hand you can easily use all the functions of the console window. For example: Console.WriteLine.

[GitHub]

 

Eigen – C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms.

[More info]

 

Trial – FMX Skeez – An animated list view component for Delphi FireMonkey. The package includes derived components: filesystem browser, picture list viewer and audio file list viewer.

[More info]

 

Trial – ImageEn – A native image library for Delphi and C++ Builder. It includes a complete suite of components to handle all aspects of image and editing, analysis and display. 

[More info]

 

Trial – nrComm Lib – Helps with wide range of device communication tasks and industrial issues. It contains ready solutions for RS232, modbus, GSM, HID and etc.

[More info]

 

Trial – Clever Internet Suite – A Delphi and C++Builder library for Internet communication protocols. It provides support for HTTP, FTP, SMTP, POP, IMAP, SFTP (SSH), DKIM, OAUTH, SOAP, WebDAV, complete client and server solutions for supported protocols, digital signatures and encryption.

[More info]

GetIt Top and Trending

Here are the top 10 most popular downloads from October, and any from the top 30 that are increasing in popularity.

1

    JEDI Code Library: The JEDI Code Library (JCL) consists of a set of thoroughly tested and fully documented utility functions and non-visual classes which can be instantly reused in your Delphi and C++ Builder projects.

2

    JEDI Visual Component Library: JVCL is a library of over 600 Delphi visual and non-visual Delphi/C++Builder components.

3

    Icons8: Single icon pack with 64,800 free icons. Each icon is in 5 flat styles.

4

    CnWizards: CnPack IDE Wizards (CnWizards) is an extremely popular, well established and comprehensive free open source plug-in toolset for Delphi/C++ Builder/RAD Studio to help improve development efficiency by proving a large number of useful add-ons and wizards to enhance the Delphi/C++ Builder/RAD Studio IDE.

5

    Aqua Light Slate 2 VCL Style: Free to use VCL Style

6

    CodeSite Express: Live Local and Remote Application Logging

7

    Abbrevia: Abbrevia is a compression toolkit for Delphi and C++Builder.
Supported on platforms: Windows, Android, macOS, and iOS.

8

    AsyncPro for VCL: Async Professional is a comprehensive communications toolkit for Embarcadero Delphi and C++Builder. Supported on platforms: Win32, Win64

9📈

    FortesReport Community Edition: The FortesReport is a powerful report generator available as a package of components for Delphi. In FortesReport, the reports are composed of bands that have specific functions in the print stream. You define groupings, sub-levels and totals simply by hierarchical relationship between bands. Moreover, the FortesReport has a rich palette of components for text, charts, formulas, bar codes, filters and layout.

10

    Glossy 2 VCL Style: Free to use VCL Style

15📈

    EhLib: EhLib is a Delphi and C++Builder library of visual and non-visual components. Most advanced component is DBGridEh, component to operate tabular data in DataSet. Library includes more than 30 components in total.

20📈

    SysTools for VCL: Utility routines and classes for Delphi and C++Builder. It includes bar codes, sorting, money routines, logging, high precision math…Supported on platforms: Windows

28📈

    Clever Internet Suite: Clever Internet Suite is a Delphi and C++Builder library for Internet communication protocols. It provides support for HTTP, FTP, SMTP, POP, IMAP, SFTP (SSH), DKIM, OAUTH, SOAP, WebDAV, complete client and server solutions for supported protocols, digital signatures and encryption.

30📈

    TFrameStand: TFrameStand is a component to ease use of FMX frames in your application. Take advantage of TFrameStand functionalities to build stunning visual transitions and improve the visual continuity of your UI. Supported on platforms: Win32, Win64, Android, OS X. Open source by Andrea Magni.

Read More

Read More