Paul Toth, a well known Delphi Developer rewrote his CubeMan3D with FireMonkey, making it a cross platform application. The application shows an animated man made of 3D cubes. The man walk in place and turn on himself.
Actually, each cube is a standard FireMonkey TRoundCude 3D component. They are all linked together to form the body and members. The animation is made with a TFloatAnimation for each cube.
It is amazing how short the code is. The code is just the implementation for the AnimationFinish event for the leg. The event handler simply reverse the direction and restart.
The code source is available from here.
Paul Toth is a freelance Certified Delphi Developer. If you need some help with Delphi, feels free to contact him.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts
January 23, 2014
January 21, 2014
New blog about Delphi FireMonkey
There is a new blog talking mostly about Delphi FireMonkey on the mobile platform (iOS and Android). The blog also covers other topics, mostly related to FireMonkey and the various supported platforms.
This new blog is named FMXexpress.
Actually, this blog is collecting blog articles from everywhere, display a short abstract and redirect to the original blog article. This is a place to visit on a regular basis. Click here to visit the blog. There is also a corresponding FaceBook page.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
This new blog is named FMXexpress.
Actually, this blog is collecting blog articles from everywhere, display a short abstract and redirect to the original blog article. This is a place to visit on a regular basis. Click here to visit the blog. There is also a corresponding FaceBook page.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Labels:
Android,
delphi,
FireMonkey,
IOS,
Mobile,
Mobile Development
January 11, 2014
TIniFile for Windows and Android (Source code)
I made available a zip file with the full source code for my TIniFile class compatible with both Windows and Android. You need Delphi XE5 to compile it for Android and a reasonably recent Delphi to compile it for Windows.
You can read the article on my blog. This article explain how it works.
You can download the source code here.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
You can read the article on my blog. This article explain how it works.
You can download the source code here.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
January 9, 2014
Programming Android and iOS Devices and Gadgets
Our modern world is full of programmable and interactive devices.
Delphi and C++Builder can be used to work with these devices and gadgets in innovative ways and extend your apps in ways you never may have imagined.
Devices are platforms that can load and execute your program directly, such as an iPhone, Android phone, tablet or even Google Glass. A gadget on the other hand is something your program interacts with, like 3D input, a brain-computer interface, or a flying drone.
Embarcadero will show this in a webminar. See details at http://edn.embarcadero.com/article/43573
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Delphi and C++Builder can be used to work with these devices and gadgets in innovative ways and extend your apps in ways you never may have imagined.
Devices are platforms that can load and execute your program directly, such as an iPhone, Android phone, tablet or even Google Glass. A gadget on the other hand is something your program interacts with, like 3D input, a brain-computer interface, or a flying drone.
Embarcadero will show this in a webminar. See details at http://edn.embarcadero.com/article/43573
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
January 5, 2014
TIniFile for Android and Windows
When writing cross platform applications, you are faced with different ways of doing thing depending on the platform. Thanks to the OOP paradigm, we may encapsulate those things in a class and create an implementation specific to each platform. This class hides all the details which are not readily portable.
In this article, I will model a class depending on the operation of the well-known Windows INI files. Of course, Windows own system will be used in the Windows implementation. On Android side, I will use the SharedPreferences API which is very close.
In an INI file, you have Key-Value pairs organized by sections. You can read or write values.
Under Windows, the INI file format is a simple text file with a Key=Value per line. All Key-Value pairs related to the same section are grouped under a header line in the form of the section name between brackets.
Under Android, the file format is not specified. You are not supposed to access the file directly. You use a “Shared Preference Editor” to access it. Android API lacks the “section” concept we have in Windows. This is not a problem. To create the section concept, I will simply prefix each key by his section name surrounded by brackets like this: ‘[‘ + Section + ‘]_’ + Key
Since the beginning, Delphi has a class encapsulation Windows INI files. It is well named “TIniFile” and sits into “System.IniFiles” unit.
I will use the same class name in my implementation and even the save class signature by inheriting from the existing TCustomIniFile for Android and TIniFile for Windows.
Using the same class name as an existing one will force you to pay some attention to the units used in the uses clause, and/or prefix the class name you intent to use with the unit name.
I made things simples. Under both Windows and Android, in your application, you do not use System.IniFiles but FMX.Overbyte.IniFiles. No other change is required. Your application will compile targeted for Windows as well as Android. The conditional compilation is located in FMX.Overbyte.IniFiles and you can safely ignore it!
TIniFile constructor takes a filename as argument. This will be the file where the sections and key-value pairs will be stored. The Windows API store the file exactly where you specify it when using a full path. When you omit the path, Windows tore the file in the Windows directory. Since Windows Vista, normal user cannot write to the Windows directory. So it fails.
I slightly changed the base class so that when a full path is omitted, the INI file is stored in the user profile LoaclAppData special directory (non-roaming version). This is a convenient place most of the time. You may always specify a full path name if you want to store it elsewhere.
Android has a “well known” place to store the preference files. We are not supposed to know where. The actual files are not available directly unless your Android device is rooted.
TIniFile constructor in the Android implementation will simple ignore any path you specify and let Android API store the file where it want it to be stored. This could cause a problem if you want to use the same file name for different files stored in different folders. This will cause trouble since the path is ignored.
The windows implementation is quite trivial since it already exists in Delphi RTL. As stated above, I derived my class from Delphi existing class and only override the constructor to adjust the path when left empty.
The resulting declaration is trivial:
The implementation is simple:
This implementation makes use of SHgetFolderPath API function to get the special directory “LocalAppData” located in each user profile. I used ForceDirectories to create the directory if it does not already exist.
You may want to change the location by changing the constant CSIDL_LOCAL_APPDATA to another one (There is a bunch of such constant, see the API documentation or Delphi source code if you have an edition which includes it).
You may also want to change the string constant “CompanyFolder” to your actual company name instead of OverByte which is my company name.
Using the demo application named “IniFileDemo”, running under Win7, the INI files without path will be stored in “C:\Users\\AppData\Local\OverByte\IniFileDemo”.
Android implementation makes use of SharedPreferences API which is already defined by Delphi runtime library. You handle that API using an interface named “JSharedPreferences” which is located in Androidapi.JNI.GraphicsContentViewText.
We need to implement most of the TIniFile methods. We can skip the read/write for other data types than string because they are all based on the read/write string.
The class declaration looks like this:
The class TIniFile derives from existing TCustomIniFile. I used the fully qualified class name to avoid confusion (Here it is not strictly necessary since we do not redefine TCustomIniFile).
All the public methods are those required to make TIniFile work as it does under Windows. Private members are required as helpers for the implementation. As their visibility implies, you will never directly use them.
All methods need to get hand on a JSharedPreferences interface. That is why I created a member variable FPrefs to store it and an InitPrefs method to initialize it.
Once you get FPrefs, you may use it to fetch a value. look at ReadString implementation:
FPrefs.GetString is themethod use to retrieve (read) a stored value given his key. Here, as explained above, we implement the concept of section, so the key is really constructed using the section name and the identifier used outside of the class as key.
JStringToString and StringToJString are support functions to marshal back and forth a Delphi string to a Java string (Remember Android API is written in Java).
ReadSection, ReadSections and ReadSectionValues all require to enumerate all keys are save values in a string list for some of the keys if they match a condition. Iterating all the keys is a common process so I moved it to a specialized private method ReadSectionKeysValues.
Here is the implementation:
SharedPreferences Android API make use of string collection returned by getAll method to store all the preferences values. It is a generic Java class which can be accessed using a JMap interface which is available to Delphi program. Accessing the individual strings is 4 steps process:
1) Get the JMap interface by calling getAll
2) Get the JSet interface on behalf f the JMap
3) Get the JIterator on behalf og the JSet
4) Iterate with the JIterator to get hand of all object in the collection
The objects are here JStrings we can convert to Delphi string and process them.
The enumerated strings looks like this: “[Section1]_Key1=Value1”. We can then easily parse the string to extract the parts and do whatever we need with it.
The rest of the class implementation is quite trivial.
http://www.overbyte.be/frame_index.html?redirTo=/blog_source_code.html
FMX.Overbyte.IniFiles.pas
FMX.Overbyte.Android.IniFiles.pas
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
In this article, I will model a class depending on the operation of the well-known Windows INI files. Of course, Windows own system will be used in the Windows implementation. On Android side, I will use the SharedPreferences API which is very close.
INI file concept
In an INI file, you have Key-Value pairs organized by sections. You can read or write values.
Under Windows, the INI file format is a simple text file with a Key=Value per line. All Key-Value pairs related to the same section are grouped under a header line in the form of the section name between brackets.
Under Android, the file format is not specified. You are not supposed to access the file directly. You use a “Shared Preference Editor” to access it. Android API lacks the “section” concept we have in Windows. This is not a problem. To create the section concept, I will simply prefix each key by his section name surrounded by brackets like this: ‘[‘ + Section + ‘]_’ + Key
Delphi TIniFile revisited
Since the beginning, Delphi has a class encapsulation Windows INI files. It is well named “TIniFile” and sits into “System.IniFiles” unit.
I will use the same class name in my implementation and even the save class signature by inheriting from the existing TCustomIniFile for Android and TIniFile for Windows.
Using the same class name as an existing one will force you to pay some attention to the units used in the uses clause, and/or prefix the class name you intent to use with the unit name.
I made things simples. Under both Windows and Android, in your application, you do not use System.IniFiles but FMX.Overbyte.IniFiles. No other change is required. Your application will compile targeted for Windows as well as Android. The conditional compilation is located in FMX.Overbyte.IniFiles and you can safely ignore it!
Storage location
TIniFile constructor takes a filename as argument. This will be the file where the sections and key-value pairs will be stored. The Windows API store the file exactly where you specify it when using a full path. When you omit the path, Windows tore the file in the Windows directory. Since Windows Vista, normal user cannot write to the Windows directory. So it fails.
I slightly changed the base class so that when a full path is omitted, the INI file is stored in the user profile LoaclAppData special directory (non-roaming version). This is a convenient place most of the time. You may always specify a full path name if you want to store it elsewhere.
Android has a “well known” place to store the preference files. We are not supposed to know where. The actual files are not available directly unless your Android device is rooted.
TIniFile constructor in the Android implementation will simple ignore any path you specify and let Android API store the file where it want it to be stored. This could cause a problem if you want to use the same file name for different files stored in different folders. This will cause trouble since the path is ignored.
Windows implementation
The windows implementation is quite trivial since it already exists in Delphi RTL. As stated above, I derived my class from Delphi existing class and only override the constructor to adjust the path when left empty.
The resulting declaration is trivial:
TIniFile = class(System.IniFiles.TIniFile) public constructor Create(const AFileName : String); end;
The implementation is simple:
constructor TIniFile.Create(const AFileName: String); var FileName : String; Path : array [0..1023] of Char; AppExeName : array [0..1023] of Char; AppName : String; LocalAppData : String; begin if ExtractFilePath(AFileName) = '' then begin GetModuleFileName(0, AppExeName, Sizeof(AppExeName)); SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, SHGFP_TYPE_CURRENT, @Path[0]); AppName := ChangeFileExt(ExtractFileName(AppExeName), ''); LocalAppData := IncludeTrailingPathDelimiter(Path) + CompanyFolder + '\' + AppName + '\'; FileName := LocalAppData + AFileName; ForceDirectories(LocalAppData); end else FileName := AFileName; inherited Create(FileName); end;
This implementation makes use of SHgetFolderPath API function to get the special directory “LocalAppData” located in each user profile. I used ForceDirectories to create the directory if it does not already exist.
You may want to change the location by changing the constant CSIDL_LOCAL_APPDATA to another one (There is a bunch of such constant, see the API documentation or Delphi source code if you have an edition which includes it).
You may also want to change the string constant “CompanyFolder” to your actual company name instead of OverByte which is my company name.
Using the demo application named “IniFileDemo”, running under Win7, the INI files without path will be stored in “C:\Users\
Android implementation
Android implementation makes use of SharedPreferences API which is already defined by Delphi runtime library. You handle that API using an interface named “JSharedPreferences” which is located in Androidapi.JNI.GraphicsContentViewText.
We need to implement most of the TIniFile methods. We can skip the read/write for other data types than string because they are all based on the read/write string.
The class declaration looks like this:
TIniFile = class(System.IniFiles.TCustomIniFile) private FPrefs : JSharedPreferences; function InitPrefs : JSharedPreferences; function Key(const Section, Ident : String) : JString; procedure ReadSectionKeysValues(const Section : String; const KeyOnly : Boolean; Strings : TStrings); public constructor Create(const FileName: String); function ReadString(const Section, Ident, Default: String): String; override; procedure WriteString(const Section, Ident, Value: String); override; procedure ReadSection(const Section: String; Strings: TStrings); override; procedure ReadSections(Strings: TStrings); override; procedure ReadSectionValues(const Section: String; Strings: TStrings); override; procedure DeleteKey(const Section, Ident: String); override; procedure EraseSection(const Section: string); override; procedure UpdateFile; override; end;
The class TIniFile derives from existing TCustomIniFile. I used the fully qualified class name to avoid confusion (Here it is not strictly necessary since we do not redefine TCustomIniFile).
All the public methods are those required to make TIniFile work as it does under Windows. Private members are required as helpers for the implementation. As their visibility implies, you will never directly use them.
All methods need to get hand on a JSharedPreferences interface. That is why I created a member variable FPrefs to store it and an InitPrefs method to initialize it.
Once you get FPrefs, you may use it to fetch a value. look at ReadString implementation:
function TIniFile.ReadString(const Section, Ident, Default: String): String; begin InitPrefs; Result := JStringToString(FPrefs.GetString(Key(Section, Ident), StringToJString(Default))); end;
FPrefs.GetString is themethod use to retrieve (read) a stored value given his key. Here, as explained above, we implement the concept of section, so the key is really constructed using the section name and the identifier used outside of the class as key.
JStringToString and StringToJString are support functions to marshal back and forth a Delphi string to a Java string (Remember Android API is written in Java).
ReadSection, ReadSections and ReadSectionValues all require to enumerate all keys are save values in a string list for some of the keys if they match a condition. Iterating all the keys is a common process so I moved it to a specialized private method ReadSectionKeysValues.
Here is the implementation:
procedure TIniFile.ReadSectionKeysValues( const Section : String; // Section to read, or empty for keys and values const KeyOnly : Boolean; Strings : TStrings); var AMap : JMap; ASet : JSet; AIter : JIterator; AObj : JObject; AString : JString; DString : String; ASection : String; AIdent : String; I, J : Integer; begin if not Assigned(Strings) then Exit; InitPrefs; Strings.Clear; AMap := FPrefs.GetAll; if not Assigned(AMap) then Exit; ASet := AMap.entrySet; if not Assigned(ASet) then Exit; AIter := ASet.iterator; Strings.BeginUpdate; while AIter.hasNext do begin AObj := AIter.next; AString := AObj.toString; DString := JStringToString(AString); // We get "[Section]_Ident" if (Length(DString) > 3) and (DString[Low(DString)] = '[') then begin I := Pos(']', DString); if I > 0 then begin ASection := Copy(DString, 2, I - 2); if Section = '' then begin // We are reading section names if Strings.IndexOf(ASection) < 0 then Strings.Add(ASection); end else if SameText(Section, ASection) then begin // We are reading the key names (Ident) if KeyOnly then J := PosEx('=', DString) else J := Length(DString) + 1; if J > 0 then begin AIdent := Copy(DString, I + 2, J - I - 2); Strings.Add(AIdent); end; end; end; end; end; Strings.EndUpdate; end;
SharedPreferences Android API make use of string collection returned by getAll method to store all the preferences values. It is a generic Java class which can be accessed using a JMap interface which is available to Delphi program. Accessing the individual strings is 4 steps process:
1) Get the JMap interface by calling getAll
2) Get the JSet interface on behalf f the JMap
3) Get the JIterator on behalf og the JSet
4) Iterate with the JIterator to get hand of all object in the collection
The objects are here JStrings we can convert to Delphi string and process them.
The enumerated strings looks like this: “[Section1]_Key1=Value1”. We can then easily parse the string to extract the parts and do whatever we need with it.
The rest of the class implementation is quite trivial.
Full source code
The source code as well as a demo application is available from my website athttp://www.overbyte.be/frame_index.html?redirTo=/blog_source_code.html
FMX.Overbyte.IniFiles.pas
unit FMX.Overbyte.IniFiles; {$DEFINE OVERBYTE_INCLUDE_MODE} {$IFDEF ANDROID} {$I FMX.Overbyte.Android.IniFiles.pas} {$ENDIF} {$IFDEF MSWINDOWS} {$I FMX.Overbyte.Windows.IniFiles.pas} {$ENDIF}FMX.Overbyte.Windows.IniFiles.pas
{$IFNDEF OVERBYTE_INCLUDE_MODE} unit FMX.Overbyte.Windows.IniFiles; {$ENDIF} interface uses System.SysUtils, System.Classes, System.IniFiles, WinApi.Windows, WinApi.ShlObj; const CompanyFolder = 'OverByte'; type // We are enhancing Embarcadero implementation TIniFile = class(System.IniFiles.TIniFile) public constructor Create(const AFileName : String); end; implementation { TIniFile } constructor TIniFile.Create(const AFileName: String); var FileName : String; Path : array [0..1023] of Char; AppExeName : array [0..1023] of Char; AppName : String; LocalAppData : String; begin // When the path is empty, Windows use Windows directory (C:\windows). This // is bad since Win7 which requires special permission to write to this // directory. // This implementation redirect the INI file to the user profile, that is //\Local Settings\Application Data (non roaming) // If you really want to write to Windows directory, then you must // specify that path name specifically. if ExtractFilePath(AFileName) = '' then begin GetModuleFileName(0, AppExeName, Sizeof(AppExeName)); SHGetFolderPath(0, CSIDL_LOCAL_APPDATA, 0, SHGFP_TYPE_CURRENT, @Path[0]); AppName := ChangeFileExt(ExtractFileName(AppExeName), ''); LocalAppData := IncludeTrailingPathDelimiter(Path) + CompanyFolder + '\' + AppName + '\'; FileName := LocalAppData + AFileName; ForceDirectories(LocalAppData); end else FileName := AFileName; inherited Create(FileName); end; end.
FMX.Overbyte.Android.IniFiles.pas
{$IFNDEF OVERBYTE_INCLUDE_MODE} unit FMX.Overbyte.Android.IniFiles; {$ENDIF} interface uses System.SysUtils, System.Classes, System.IniFiles, System.StrUtils, FMX.Helpers.Android, Androidapi.NativeActivity, Androidapi.JNI, Androidapi.JNI.App, Androidapi.JNI.GraphicsContentViewText, Androidapi.JNI.JavaTypes; type TIniFile = class(System.IniFiles.TCustomIniFile) private FPrefs : JSharedPreferences; function InitPrefs : JSharedPreferences; function Key(const Section, Ident : String) : JString; procedure ReadSectionKeysValues(const Section : String; const KeyOnly : Boolean; Strings : TStrings); public constructor Create(const FileName: String); function ReadString(const Section, Ident, Default: String): String; override; procedure WriteString(const Section, Ident, Value: String); override; procedure ReadSection(const Section: String; Strings: TStrings); override; procedure ReadSections(Strings: TStrings); override; procedure ReadSectionValues(const Section: String; Strings: TStrings); override; procedure DeleteKey(const Section, Ident: String); override; procedure EraseSection(const Section: string); override; procedure UpdateFile; override; end; implementation { TIniFile } constructor TIniFile.Create(const FileName: String); begin // Under Android, just ignore the path part because Android has a well // known place to store preferences files inherited Create(ExtractFileName(FileName)); end; procedure TIniFile.DeleteKey(const Section, Ident: String); var Edit : JSharedPreferences_Editor; begin InitPrefs; Edit := FPrefs.Edit; Edit.Remove(Key(Section, Ident)); Edit.Apply; end; procedure TIniFile.EraseSection(const Section: String); var Idents : TStringList; Edit : JSharedPreferences_Editor; I : Integer; begin Idents := TStringList.Create; ReadSectionKeysValues(Section, TRUE, Idents); InitPrefs; Edit := FPrefs.Edit; for I := 0 to Idents.Count - 1 do Edit.Remove(Key(Section, Idents[I])); Edit.Apply; end; function TIniFile.InitPrefs : JSharedPreferences; begin if not Assigned(FPrefs) then FPrefs := SharedActivityContext.getSharedPreferences( StringToJString(FileName), TJActivity.JavaClass.MODE_PRIVATE); Result := FPrefs; end; function TIniFile.Key(const Section, Ident: String): JString; begin Result := StringToJString('[' + Section + ']_' + Ident); end; procedure TIniFile.ReadSection(const Section: String; Strings: TStrings); begin if Section = '' then begin if Assigned(Strings) then Strings.Clear; end else ReadSectionKeysValues(Section, TRUE, Strings); end; procedure TIniFile.ReadSections(Strings: TStrings); begin ReadSectionKeysValues('', FALSE, Strings); end; procedure TIniFile.ReadSectionKeysValues( const Section : String; // Section to read, or empty for keys and values const KeyOnly : Boolean; Strings : TStrings); var AMap : JMap; ASet : JSet; AIter : JIterator; AObj : JObject; AString : JString; DString : String; ASection : String; AIdent : String; I, J : Integer; begin if not Assigned(Strings) then Exit; InitPrefs; Strings.Clear; AMap := FPrefs.GetAll; if not Assigned(AMap) then Exit; ASet := AMap.entrySet; if not Assigned(ASet) then Exit; AIter := ASet.iterator; Strings.BeginUpdate; while AIter.hasNext do begin AObj := AIter.next; AString := AObj.toString; DString := JStringToString(AString); // We get "[Section]_Ident" if (Length(DString) > 3) and (DString[Low(DString)] = '[') then begin I := Pos(']', DString); if I > 0 then begin ASection := Copy(DString, 2, I - 2); if Section = '' then begin // We are reading section names if Strings.IndexOf(ASection) < 0 then Strings.Add(ASection); end else if SameText(Section, ASection) then begin // We are reading the key names (Ident) if KeyOnly then J := PosEx('=', DString) else J := Length(DString) + 1; if J > 0 then begin AIdent := Copy(DString, I + 2, J - I - 2); Strings.Add(AIdent); end; end; end; end; end; Strings.EndUpdate; end; procedure TIniFile.ReadSectionValues(const Section: String; Strings: TStrings); begin if Section = '' then Strings.Clear else ReadSectionKeysValues(Section, FALSE, Strings); end; function TIniFile.ReadString(const Section, Ident, Default: String): String; begin InitPrefs; Result := JStringToString(FPrefs.GetString(Key(Section, Ident), StringToJString(Default))); end; procedure TIniFile.UpdateFile; begin // Nothing to do end; procedure TIniFile.WriteString(const Section, Ident, Value: String); var Edit : JSharedPreferences_Editor; begin InitPrefs; Edit := FPrefs.Edit; Edit.PutString(Key(Section, Ident), StringToJString(Value)); Edit.Apply; end; end.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Labels:
Android,
API,
delphi,
FireMonkey,
Mobile,
Mobile Development,
opensource,
pascal,
programming
December 28, 2013
Compiling to native code begets better performance
Todays with Mobile platforms such as IOS and Android, developers are faced with writing application targeted to several platforms. Of course developers want to do that with minimal effort. This is why the market of cross platform tools is growing.
Embarcadero do it well with RAD Studio XE5 (Includes Delphi and C++ Builder). There is an interesting article on NetworkWorld talking about the subject and comparing different solutions.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Embarcadero do it well with RAD Studio XE5 (Includes Delphi and C++ Builder). There is an interesting article on NetworkWorld talking about the subject and comparing different solutions.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Labels:
Android,
ARM,
C++Builder,
delphi,
embarcadero,
IOS,
Mobile,
Mobile Development,
RAD Studio
December 18, 2013
Mandelbrot Explorer for Android and Windows
Using Delphi XE5, I rewrote my Mandelbrot fractal explorer with the FireMonkey component framework. The result is a working application for Android and Windows. To generate Windows or Android version, it is enough to just change the target operating system. Nice cross-platform application!
On the picture below, you see the Windows version running on my desktop and the Android version running on my Nexus 7 device.
The source code is making use of what I described in two previous articles:
http://francois-piette.blogspot.be/2013/12/firemonkey-android-windows-and.html
http://francois-piette.blogspot.be/2013/12/mandelbrot-fractal-explorer.html
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
December 15, 2013
FireMonkey, Android, Windows and PostMessage
FireMonkey framework (FMX for short) is definitely able to use custom [Windows] messages much like we have always done with the VCL. And this is also true when using FireMonkey to build Android applications.
Both Windows and Android support a messaging system. It is well known by Windows developers who use it with PostMessage, GetMessage, PeekMessage and similar Windows API call. It is much less known by Android developers. Android has a “looper” API which has the same purpose as Windows own messaging system although it is implemented differently and has somewhat more features.
Often, we use FireMonkey framework to build multi-platform applications. Thanks to Delphi XE5, we can build an application for different targets such as Win32, Win64, Android, iOS and MAC OSx. If correctly written, the same application source code can be recompiled for different target and run unchanged. Embarcadero made a lot of efforts to hide differences between the supported platforms.
Speaking about the messaging system, it must admit that Embarcadero forgot to write the abstraction layer required for the platforms. They made some work but it is incomplete and undocumented. This is why I wrote it. At least for Win32, Win64 and Android which are the 3 platforms I currently use.
The layer I wrote is made of a single class I named “TMessagingSystem”. I made two different implementations: one for Android and one for Win 32/64. TMessagingSystem class allows you to register any number of custom messages to a form and associate a custom message handler. Of course it also allows you to call PostMessage to put a message into the message queue.
At the application level, you use the exact same code for Windows or Android. You just have to make use of one of the implementations. You’ll do that using a conditional compilation.
Before showing the implementation details, I will present a demo application. That you can target for Windows or Android without changing a single line.
I built a simple application to emphasize how to use TMessagingSystem. Actually it does not do anything very interesting. It is made of a single form having a button and a memo. When you click on the button, it starts a new thread which will periodically PostMessage a custom message to the main form. You can click many times on the button to start many threads. Each thread will do the same.
The image above shows on the left a screen dump of the application running under Win7 and on the right, the same application running on my Nexus7.
All you see is a memo with messages. Nevertheless, this is really one of the main usages of a messaging system: organize asynchronous operation between threads.
Each line looks like this:
“8380” is the thread ID of the thread doing the display. This is always the same and is the main thread ID. “Thread=2” is the sequential thread number having generated the message, “Count=8” is the number of messages generated by this thread and finally, “ThreadID=7528” is the thread ID of the thread generating the message. The later change according to each started thread.
This source code is really simple, isn’t it? The beauty is that it can be compiled for Win32, Win64 and Android targets without changing anything.
All the code depending on the platform has been moved to “FMX.Overbyte.MessageHandling” unit. That one takes care of calling the correct API function according to the compiler used. This is the power of OOP.
There is nothing special in the demo application except one thing: The worker thread generates messages to be displayed by the main thread. We have to take care of what happens with the storage used for the message. We cannot simply pass a string because messages are limited to two parameters of type WParam and LParam, both mapped to NativeInt. We can neither pass a reference to a string variable because it is possible a new message is generated before the previous is consumed (This happens if the main thread is heavily busy while the worker thread runs at full speed). We have to dynamically allocate storage for the message and pass the reference thru one of the message parameters. I’ve chosen to use a simple memory block allocated by GetMem and freed by FreeMem. The pointer is then passed thru the LParam parameter. The thread allocates the memory and the main thread frees it. The same allocation size is always used regardless of the message length. It is better for the memory allocator, limiting memory fragmentation.
TMessagingSystem class must be instantiated when the form is allocated a handle. It must be freed when the form’s handle is destroyed. After instantiation, or at any point in time, RegisterMessageHandler must be called for each custom message. That’s all!
We have seen in the demo code that the same unit to “FMX.Overbyte.MessageHandling” is used whatever the target platform is. The magic is in that unit. Here is very short source code:
The magic is into the conditional compilation. Symbols ANDROID and MSWINDOWS are automatically defined by the compiler according to the target platform you compile for. So that small unit actually includes the Android or the Windows specific unit depending on the compiler target platform.
The two included units are just normal unit, well almost. You cannot include a unit into another one without having a problem with the “unit” line. You cannot have two such lines. This is why the symbol “OVERBYTE_INCLUDE_MODE” is defined. In the two included units, this symbol is used to conditionally compile the “unit” line.
Messaging system on Android platform is hidden in the “Looper” API. Basically, the idea is simple: Android monitors a list of handle for data availability. The list of handles is maintained by the API. You can add a new handle using ALooper_addFd API function. Each handle is associated with a callback function that Android calls when data is available.
As a handle, I use the read side of a pipe. A pipe, under Android as well as other operating systems, is like a first-in first-out queue. It has two ends identified by two handles. One is the writing end; the other is the reading end. What you write at one end is available for reading at the other end. Between both ends is a buffer. Reads and writes are asynchronous. If writing is faster than reading, the buffer is filled and nothing is lost.
This pipe is used here is the message queue. When PostMessage is called, a record with the parameters is written to the pipe. When data is available for reading, the looper API will call the LooperCallBack function we registered. From this callback, we read the pipe to remove one record at a time. When a record is read, the message number written in it is used to fetch the message handler to be executed.
In that code, you’ll find a few data types frequently used in Windows applications. I used the same data types for compatibility with existing code.
TMessagingSystem class is very simple. Basically, it registers a pipe read handle with the looper API with an associated callback function. It also maintains a dictionary of message handlers. The key is the message number. The looper API also carries one pointer for you. It will give it back as an argument of the callback function. Here the pointer is used as a reference to the class instance, making is available when the callback function is called.
A critical section is used to avoid problems accessing the class data from several threads at the same time. Using this critical section makes the class fully thread safe.
The Windows implementation makes obviously use of Windows own messaging API. There is no queue in the class because Windows queue is used.
FireMonkey forms does not provide any support for custom messages. This is not really a problem because a FireMonkey forms are just a Windows window. As any window, a FireMonkey form running on Windows has a HWND (Handle of WiNDow) and a window procedure handling all messages for the window.
To hook into this system, we must use standard Windows programming. By standard I mean it has always existed as far as I remember. What we need is to “subclass” the window. And surprisingly, this is very easy!
Windows internally maintain a structure for each window. In that structure you have all informations required for Windows to handle the window. This includes the pointer to the window procedure.
And Windows provides a function to access his internal structure. Our problem is just to get the current pointer to the window procedure and replace it with a pointer to our own procedure. From our own procedure, we will call the original procedure, or not. Our own window procedure has access to all messages sent/posted to the window, including those we add.
We have just one small problem: Windows does not know anything about a Delphi class instance. A window procedure is a simple procedure, not an object method. The problem is to get hand on our TMessagingSystem class instance from our own window procedure.
Fortunately Windows is incredibly well designed. We, as developer, can associate with any window a small piece of data called an “Atom” in Windows terminology. Once an “Atom” is created (It just has a name), you can associate the atom with any window along with a piece of data. That piece of data will be the reference to our TMessagingSystem class instance.
When called by Windows, our window procedure receives the handle of the window. We use it to fetch the piece of data we associated using the atom. From there we have access to TMessagingSystem class instance and check for the message to handle. if it is one of our registered messages, we just call the handler. If not one of our messages, the the original window procedure is called.
Here is the source code:
All the code is shown above. If you are interested by the complete project as source code, just drop me a private email.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Both Windows and Android support a messaging system. It is well known by Windows developers who use it with PostMessage, GetMessage, PeekMessage and similar Windows API call. It is much less known by Android developers. Android has a “looper” API which has the same purpose as Windows own messaging system although it is implemented differently and has somewhat more features.
Often, we use FireMonkey framework to build multi-platform applications. Thanks to Delphi XE5, we can build an application for different targets such as Win32, Win64, Android, iOS and MAC OSx. If correctly written, the same application source code can be recompiled for different target and run unchanged. Embarcadero made a lot of efforts to hide differences between the supported platforms.
Speaking about the messaging system, it must admit that Embarcadero forgot to write the abstraction layer required for the platforms. They made some work but it is incomplete and undocumented. This is why I wrote it. At least for Win32, Win64 and Android which are the 3 platforms I currently use.
The layer I wrote is made of a single class I named “TMessagingSystem”. I made two different implementations: one for Android and one for Win 32/64. TMessagingSystem class allows you to register any number of custom messages to a form and associate a custom message handler. Of course it also allows you to call PostMessage to put a message into the message queue.
At the application level, you use the exact same code for Windows or Android. You just have to make use of one of the implementations. You’ll do that using a conditional compilation.
Before showing the implementation details, I will present a demo application. That you can target for Windows or Android without changing a single line.
Demo application for Windows and Android
I built a simple application to emphasize how to use TMessagingSystem. Actually it does not do anything very interesting. It is made of a single form having a button and a memo. When you click on the button, it starts a new thread which will periodically PostMessage a custom message to the main form. You can click many times on the button to start many threads. Each thread will do the same.

The image above shows on the left a screen dump of the application running under Win7 and on the right, the same application running on my Nexus7.
All you see is a memo with messages. Nevertheless, this is really one of the main usages of a messaging system: organize asynchronous operation between threads.
Each line looks like this:
8380] Thread=2 Count=8 ThreadID=7528
“8380” is the thread ID of the thread doing the display. This is always the same and is the main thread ID. “Thread=2” is the sequential thread number having generated the message, “Count=8” is the number of messages generated by this thread and finally, “ThreadID=7528” is the thread ID of the thread generating the message. The later change according to each started thread.
Demo application source code
unit FmxMultiplatformPostMessageDemoMain; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, Generics.Collections, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Layouts, FMX.Memo, FMX.Overbyte.MessageHandling; const WM_SHOW_MESSAGE = WM_USER + 1; type TWorkerThread = class(TThread) public MsgSys : TMessagingSystem; Id : Integer; procedure Execute; override; end; TForm1 = class(TForm) RunThreadButton: TButton; DisplayMemo : TMemo; ToolPanel: TPanel; procedure RunThreadButtonClick(Sender: TObject); private FMsgSys : TMessagingSystem; FThreadCount : Integer; procedure Display(const Msg: String); procedure WorkerThreadTerminate(Sender: TObject); procedure WMShowMessage(var Msg: TMessage); protected procedure CreateHandle; override; procedure DestroyHandle; override; end; var Form1: TForm1; implementation {$R *.fmx} { TForm1 } procedure TForm1.CreateHandle; begin inherited CreateHandle; FMsgSys := TMessagingSystem.Create(Self); FMsgSys.RegisterMessageHandler(WM_SHOW_MESSAGE, WMShowMessage); end; procedure TForm1.DestroyHandle; begin FreeAndNil(FMsgSys); inherited DestroyHandle; end; procedure TForm1.RunThreadButtonClick(Sender: TObject); var WorkerThread : TWorkerThread; begin Inc(FThreadCount); Display('Start thread ' + IntToStr(FThreadCount)); WorkerThread := TWorkerThread.Create(TRUE); WorkerThread.MsgSys := FMsgSys; WorkerThread.Id := FThreadCount; WorkerThread.FreeOnTerminate := TRUE; WorkerThread.OnTerminate := WorkerThreadTerminate; WorkerThread.Start; end; procedure TForm1.WorkerThreadTerminate(Sender: TObject); begin Display('Thread ' + IntToStr((Sender as TWorkerThread).Id) + ' terminated'); end; procedure TForm1.WMShowMessage(var Msg: TMessage); var Buffer : PChar; begin Buffer := PChar(Msg.LParam); Display(Buffer); FreeMem(Buffer); end; procedure TForm1.Display(const Msg: String); begin Displaymemo.Lines.Add(IntToStr(GetCurrentThreadID) + '] ' + Msg); end; { TWorkerThread } procedure TWorkerThread.Execute; var I : Integer; Buffer : PChar; const MaxLen = 100; begin // For demo, let's do it 10 times for I := 1 to 10 do begin // Simulate some processing time by sleeping Sleep(1000); // Allocate memory to hold a message, take care of the ending nul char GetMem(Buffer, SizeOf(Char) * (MaxLen + 1)); // Copy message to allocated memory, protecting overflow StrLCopy(Buffer, PChar('Thread=' + IntToStr(Id) + ' Count=' + IntToStr(I) + ' ThreadID=' + IntToStr(GetCurrentThreadID)), MaxLen); // Force a nul char at the end of buffer Buffer[MaxLen] := #0; // Post a message to the main thread which will display // the message and then free memory MsgSys.PostMessage(WM_SHOW_MESSAGE, I, LParam(Buffer)); end; end; end.
This source code is really simple, isn’t it? The beauty is that it can be compiled for Win32, Win64 and Android targets without changing anything.
All the code depending on the platform has been moved to “FMX.Overbyte.MessageHandling” unit. That one takes care of calling the correct API function according to the compiler used. This is the power of OOP.
There is nothing special in the demo application except one thing: The worker thread generates messages to be displayed by the main thread. We have to take care of what happens with the storage used for the message. We cannot simply pass a string because messages are limited to two parameters of type WParam and LParam, both mapped to NativeInt. We can neither pass a reference to a string variable because it is possible a new message is generated before the previous is consumed (This happens if the main thread is heavily busy while the worker thread runs at full speed). We have to dynamically allocate storage for the message and pass the reference thru one of the message parameters. I’ve chosen to use a simple memory block allocated by GetMem and freed by FreeMem. The pointer is then passed thru the LParam parameter. The thread allocates the memory and the main thread frees it. The same allocation size is always used regardless of the message length. It is better for the memory allocator, limiting memory fragmentation.
How to use it?
TMessagingSystem class must be instantiated when the form is allocated a handle. It must be freed when the form’s handle is destroyed. After instantiation, or at any point in time, RegisterMessageHandler must be called for each custom message. That’s all!
Single unit, multiple platforms
We have seen in the demo code that the same unit to “FMX.Overbyte.MessageHandling” is used whatever the target platform is. The magic is in that unit. Here is very short source code:
unit FMX.Overbyte.MessageHandling; {$DEFINE OVERBYTE_INCLUDE_MODE} {$IFDEF ANDROID} {$I FMX.Overbyte.Android.MessageHandling.pas} {$ENDIF} {$IFDEF MSWINDOWS} {$I FMX.Overbyte.Windows.MessageHandling.pas} {$ENDIF}
The magic is into the conditional compilation. Symbols ANDROID and MSWINDOWS are automatically defined by the compiler according to the target platform you compile for. So that small unit actually includes the Android or the Windows specific unit depending on the compiler target platform.
The two included units are just normal unit, well almost. You cannot include a unit into another one without having a problem with the “unit” line. You cannot have two such lines. This is why the symbol “OVERBYTE_INCLUDE_MODE” is defined. In the two included units, this symbol is used to conditionally compile the “unit” line.
Implementation for Android
Messaging system on Android platform is hidden in the “Looper” API. Basically, the idea is simple: Android monitors a list of handle for data availability. The list of handles is maintained by the API. You can add a new handle using ALooper_addFd API function. Each handle is associated with a callback function that Android calls when data is available.
As a handle, I use the read side of a pipe. A pipe, under Android as well as other operating systems, is like a first-in first-out queue. It has two ends identified by two handles. One is the writing end; the other is the reading end. What you write at one end is available for reading at the other end. Between both ends is a buffer. Reads and writes are asynchronous. If writing is faster than reading, the buffer is filled and nothing is lost.
This pipe is used here is the message queue. When PostMessage is called, a record with the parameters is written to the pipe. When data is available for reading, the looper API will call the LooperCallBack function we registered. From this callback, we read the pipe to remove one record at a time. When a record is read, the message number written in it is used to fetch the message handler to be executed.
{$IFNDEF OVERBYTE_INCLUDE_MODE} unit FMX.Overbyte.Android.MessageHandling; {$ENDIF} interface uses System.SysUtils, System.Types, System.Classes, System.SyncObjs, Generics.Collections, FMX.Platform.Android, Androidapi.AppGlue, Androidapi.Looper, Posix.UniStd, Posix.Errno, Posix.StrOpts, Posix.PThread; const WM_USER = 1024; type LPARAM = NativeInt; WPARAM = NativeInt; LRESULT = NativeInt; TMessage = record Msg : NativeInt; WParam : WPARAM; LParam : LPARAM; Result : LRESULT; end; TMessageHandler = procedure (var Msg: TMessage) of object; TMessagingSystem = class(TComponent) protected FPipeFD : TPipeDescriptors; FData : Byte; FHandlers : TDictionary; FLastError : String; FCritSect : TCriticalSection; procedure HandleMessage(var Msg : TMessage); function CreatePipe: Integer; procedure ClosePipe; procedure InstallEventHandler; procedure UninstallEventHandler; public constructor Create(AOwner : TComponent); override; destructor Destroy; override; function RegisterMessageHandler(uMsg : NativeInt; Handler : TMessageHandler) : Boolean; function PostMessage(uMsg : NativeInt; WParam : WPARAM; LParam : LPARAM) : Boolean; property LastError : String read FLastError; end; HWND = TMessagingSystem; function GetCurrentThreadID : TThreadID; implementation function LooperCallback( FileDescriptor : Integer; Events : Integer; Data : Pointer): Integer; cdecl; var Len : Integer; Msg : TMessage; Obj : TMessagingSystem; begin Result := 1; // Data contains a reference to our class if Data = nil then Exit; // Ready to cast to our class Obj := TMessagingSystem(Data); // Check if it's our ReadDes Obj.FCritSect.Enter; try if FileDescriptor <> Obj.FPipeFD.ReadDes then Exit; finally Obj.FCritSect.Leave; end; while TRUE do begin Len := __read(FileDescriptor, @Msg, SizeOf(Msg)); if Len <= 0 then break; Obj.HandleMessage(Msg); end; end; { TMessagingSystem } constructor TMessagingSystem.Create(AOwner: TComponent); begin inherited Create(AOwner); FCritSect := TCriticalSection.Create; FHandlers := TDictionary .Create; CreatePipe; InstallEventHandler; end; destructor TMessagingSystem.Destroy; begin UninstallEventHandler; ClosePipe; FreeAndNil(FCritSect); inherited Destroy; end; function TMessagingSystem.CreatePipe: Integer; var Status : Integer; Val : Integer; const FIONBIO = $5421; begin FCritSect.Enter; try if (FPipeFD.ReadDes <> 0) or (FPipeFD.WriteDes <> 0) then begin FLastError := 'Pipe already created'; Result := -1; Exit; end; Status := Pipe(FPipeFD); if Status = -1 then begin Result := errno; FLastError := 'Pipe() failed. Error #' + IntToStr(Result); end else begin Result := 0; Val := 1; if ioctl(FPipeFD.ReadDes, FIONBIO, @Val) = -1 then begin Result := errno; FLastError := 'ioctl(FIONBIO) failed. Error #' + IntToStr(Result); Exit; end; end; finally FCritSect.Leave; end; end; procedure TMessagingSystem.ClosePipe; begin FCritSect.Enter; try if FPipeFD.ReadDes <> 0 then begin __close(FPipeFD.ReadDes); FPipeFD.ReadDes := 0; end; if FPipeFD.WriteDes <> 0 then begin __close(FPipeFD.WriteDes); FPipeFD.WriteDes := 0; end; finally FCritSect.Leave; end; end; procedure TMessagingSystem.InstallEventHandler; var AndroidApp : PAndroid_app; Data : Pointer; const LOOPER_ID_MESSAGE_OVERBYTE = LOOPER_ID_USER; begin AndroidApp := GetAndroidApp; Data := Self; ALooper_addFd(AndroidApp.looper, FPipeFD.ReadDes, LOOPER_ID_MESSAGE_OVERBYTE, ALOOPER_EVENT_INPUT, LooperCallback, Data); end; procedure TMessagingSystem.UninstallEventHandler; var AndroidApp : PAndroid_app; begin FCritSect.Enter; try if FPipeFD.ReadDes <> 0 then begin AndroidApp := GetAndroidApp; ALooper_removeFd(AndroidApp.looper, FPipeFD.ReadDes); end; finally FCritSect.Leave; end; end; function TMessagingSystem.RegisterMessageHandler( uMsg : NativeInt; Handler : TMessageHandler): Boolean; begin FCritSect.Enter; try FHandlers.AddOrSetValue(uMsg, Handler); finally FCritSect.Leave; end; Result := TRUE; end; function TMessagingSystem.PostMessage( uMsg : NativeInt; WParam : WParam; LParam : LParam): Boolean; var Msg : TMessage; begin Result := FALSE; FCritSect.Enter; try if FPipeFD.WriteDes = 0 then begin FLastError := 'Pipe is not open'; Exit; end; Msg.Msg := uMsg; Msg.WParam := WParam; Msg.LParam := LParam; Msg.Result := 0; if __write(FPipeFD.WriteDes, @Msg, SizeOf(Msg)) = -1 then begin FLastError := 'write() failed. ErrCode=' + IntToStr(errno); Exit; end; finally FCritSect.Leave; end; Result := TRUE; end; procedure TMessagingSystem.HandleMessage(var Msg: TMessage); var Handler : TMessageHandler; Status : Boolean; begin FCritSect.Enter; try Status := FHandlers.TryGetValue(Msg.Msg, Handler); finally FCritSect.Leave; end; if Status then Handler(Msg); end; function GetCurrentThreadID : TThreadID; begin Result := Posix.PThread.GetCurrentThreadID; end; end.
In that code, you’ll find a few data types frequently used in Windows applications. I used the same data types for compatibility with existing code.
TMessagingSystem class is very simple. Basically, it registers a pipe read handle with the looper API with an associated callback function. It also maintains a dictionary of message handlers. The key is the message number. The looper API also carries one pointer for you. It will give it back as an argument of the callback function. Here the pointer is used as a reference to the class instance, making is available when the callback function is called.
A critical section is used to avoid problems accessing the class data from several threads at the same time. Using this critical section makes the class fully thread safe.
Implementation for Windows
The Windows implementation makes obviously use of Windows own messaging API. There is no queue in the class because Windows queue is used.
FireMonkey forms does not provide any support for custom messages. This is not really a problem because a FireMonkey forms are just a Windows window. As any window, a FireMonkey form running on Windows has a HWND (Handle of WiNDow) and a window procedure handling all messages for the window.
To hook into this system, we must use standard Windows programming. By standard I mean it has always existed as far as I remember. What we need is to “subclass” the window. And surprisingly, this is very easy!
Windows internally maintain a structure for each window. In that structure you have all informations required for Windows to handle the window. This includes the pointer to the window procedure.
And Windows provides a function to access his internal structure. Our problem is just to get the current pointer to the window procedure and replace it with a pointer to our own procedure. From our own procedure, we will call the original procedure, or not. Our own window procedure has access to all messages sent/posted to the window, including those we add.
We have just one small problem: Windows does not know anything about a Delphi class instance. A window procedure is a simple procedure, not an object method. The problem is to get hand on our TMessagingSystem class instance from our own window procedure.
Fortunately Windows is incredibly well designed. We, as developer, can associate with any window a small piece of data called an “Atom” in Windows terminology. Once an “Atom” is created (It just has a name), you can associate the atom with any window along with a piece of data. That piece of data will be the reference to our TMessagingSystem class instance.
When called by Windows, our window procedure receives the handle of the window. We use it to fetch the piece of data we associated using the atom. From there we have access to TMessagingSystem class instance and check for the message to handle. if it is one of our registered messages, we just call the handler. If not one of our messages, the the original window procedure is called.
Here is the source code:
{$IFNDEF OVERBYTE_INCLUDE_MODE} unit FMX.Overbyte.Windows.MessageHandling; {$ENDIF} interface uses WinApi.Windows, WinApi.Messages, System.Classes, System.SysUtils, System.SyncObjs, Generics.Collections, FMX.Forms, FMX.Platform.Win; const WM_USER = WinApi.Messages.WM_USER; type TMessage = WinApi.Messages.TMessage; WPARAM = WinApi.Windows.WPARAM; LPARAM = WinApi.Windows.LPARAM; TMessageHandler = procedure (var Msg: TMessage) of object; TWndProc = function (hwnd : HWND; uMsg : UINT; wParam : WPARAM; lParam : LPARAM): LRESULT; stdcall; TMessagingSystem = class(TComponent) protected FHWnd : HWND; FHandlers : TDictionary; FOriginalWndProc : TWndProc; FLastError : String; FCritSect : TCriticalSection; public constructor Create(AOwner : TComponent); override; destructor Destroy; override; function RegisterMessageHandler(uMsg : NativeInt; Handler : TMessageHandler) : Boolean; function PostMessage(uMsg : NativeInt; WParam : WPARAM; LParam : LPARAM) : Boolean; property LastError : String read FLastError; end; function GetCurrentThreadId: DWORD; stdcall; implementation var MsgSysAtom : TAtom; MsgSysAtomString : String; function WndProc(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var Msg : TMessage; MsgSys : TMessagingSystem; Handler : TMessageHandler; Status : Boolean; begin // Search if the window handle is associated with TMessageingInstance // We know this because we registered an atom for that purpose if GlobalFindAtomW(PChar(MsgSysAtomString)) <> MsgSysAtom then begin // Not found, just do default processing Result := DefWindowProc(hwnd, uMsg, wParam, lParam); Exit; end; // Fetch the atom property and cast it to a TMessagingSystem class MsgSys := TMessagingSystem(GetProp(hwnd, MakeIntAtom(MsgSysAtom))); // Now use the dictionary to see if the message is one we'll handle MsgSys.FCritSect.Enter; try Status := MsgSys.FHandlers.TryGetValue(uMsg, Handler); finally MsgSys.FCritSect.Leave; end; if Status then begin // Found the message and his message handler. Call it using // the TMessage record to hold the values Msg.Msg := uMsg; Msg.WParam := wParam; Msg.LParam := lParam; Msg.Result := 0; Handler(Msg); Result := Msg.Result; end else begin // Not one of our messages, just execute original window procedure Result := MsgSys.FOriginalWndProc(hwnd, uMsg, wParam, lParam); end; end; { TMessagingSystem } constructor TMessagingSystem.Create(AOwner: TComponent); begin if not (AOwner is TCommonCustomForm) then raise Exception.Create('TMessagingSystem.Create failed. Invalid owner'); inherited Create(AOwner); FCritSect := TCriticalSection.Create; FHandlers := TDictionary .Create; // Find window handle corresponding to the owner form FHWnd := WindowHandleToPlatform(TCommonCustomForm(AOwner).Handle).Wnd; // If not already done, register the atom we'll use to associate // our messaging system with the window handle if MsgSysAtom = 0 then begin MsgSysAtomString := 'OverbyteMessagingSystem' + IntToHex(GetCurrentProcessID, 8); MsgSysAtom := GlobalAddAtomW(PChar(MsgSysAtomString)); end; // Associate our messaging system with the window handle SetProp(FHWnd, MakeIntAtom(MsgSysAtom), THandle(Self)); // Subclass the form. That is change his handling procedure FOriginalWndProc := TWndProc(GetWindowLongPtr(FHWnd, GWLP_WNDPROC)); SetWindowLongPtr(FHWnd, GWLP_WNDPROC, NativeInt(@WndProc)); end; destructor TMessagingSystem.Destroy; begin if Assigned(FOriginalWndProc) then begin SetWindowLongPtr(FHWnd, GWLP_WNDPROC, NativeInt(@FOriginalWndProc)); FOriginalWndProc := nil; end; FreeAndNil(FHandlers); FreeAndNil(FCritSect); inherited Destroy; end; function TMessagingSystem.RegisterMessageHandler( uMsg : NativeInt; Handler : TMessageHandler): Boolean; begin FCritSect.Enter; try FHandlers.AddOrSetValue(uMsg, Handler); finally FCritSect.Leave; end; Result := TRUE; end; function TMessagingSystem.PostMessage( uMsg : NativeInt; WParam : WPARAM; LParam : LPARAM): Boolean; begin Result := WinApi.Windows.PostMessage(FHWnd, uMsg, WParam, LParam); end; function GetCurrentThreadId: DWORD; stdcall; begin Result := WinApi.Windows.GetCurrentThreadId; end; end.
All the code is shown above. If you are interested by the complete project as source code, just drop me a private email.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Labels:
Android,
API,
ARM,
delphi,
embarcadero,
FireMonkey,
FMX,
generics,
language,
message queue,
microsoft,
Mobile Development,
multithreading,
Parallel Programming,
postmessage,
queue,
subclassing,
Windows,
wndproc,
XE5
December 11, 2013
Update 2 for RAD Studio XE5, Delphi XE5 and C++Builder XE5
If you have not noticed yet, Embarcadero published the second update for their latest tools: Delphi XE5 as well as RAD Studio XE5 and C++ Builder XE5.
More than one hundred bugs have been fixed. Thanks for the users having taken the time to write a bug report to Quality Central, the web tool used to keep track of bugs and feature requests.
Most fixed bugs are related to the mobile platforms and FireMonkey component set. Obviously the Windows, RTL and VCL parts of the product are very stable.
The update is available freely for registered users of the product.
Download from http://cc.embarcadero.com/item/29662
There is also an article with a partial list of fixes: http://dn.embarcadero.com/article/43522
Update 16/12/2013: Hot fixes are available: HF1 and HF2
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
More than one hundred bugs have been fixed. Thanks for the users having taken the time to write a bug report to Quality Central, the web tool used to keep track of bugs and feature requests.
Most fixed bugs are related to the mobile platforms and FireMonkey component set. Obviously the Windows, RTL and VCL parts of the product are very stable.
The update is available freely for registered users of the product.
Download from http://cc.embarcadero.com/item/29662
There is also an article with a partial list of fixes: http://dn.embarcadero.com/article/43522
Update 16/12/2013: Hot fixes are available: HF1 and HF2
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
This article is available from http://francois-piette.blogspot.be
Labels:
Android,
C++Builder,
delphi,
embarcadero,
FireMonkey,
FMX,
IDE,
IOS,
Mobile,
Mobile Development,
RAD,
RAD Studio,
VCL,
XE5
October 5, 2013
All about Delphi XE5 and mobile development
CodeRage 8
is just around the corner on October 15th through 17th.
This online event is completely free and full of technical sessions all about
Delphi XE5 and mobile development.
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
October 3, 2013
ICS version 8 released
ICS which exists since 1996, has been released in his version 8. V8 was at beta stage for about one year. Now it is released!
The new ICS-V8 is for Delphi 7 / C++ Builder 2006 to Delphi XE5 / C++ Builder XE3 with FireMonkey cross platform support for POSIX/MacOS, also IPv6 support (main development tree, 32 and 64-bit). Note that latest C++ Builder version supported is XE3 (lack of spare time, sorry).
The major changes in V8 include:
- Support for Delphi 7 to RAD Studio XE5
- Support for Firemonkey and Mac OS-X (still beta)
- New support for IPv6 in most components
- New SocketFamily property (sfAny, sfAnyIPv4, sfAnyIPv6, sfIPv4, sfIPv6)
- New MultiListenSockets property for most servers to add extra listening sockets, each with Addr/Port/SocketFamily/SslEnable
- New IPv4 and IPv6 string addresses helpers
- New SMTP mail server component
- New threaded ping component and trace route demo
- Revised directory structure with more, smaller sample directories
You can download ICS-V8 from http://www.overbyte.be as well as from the wiki download page at http://wiki.overbyte.be/wiki/index.php/ICS_Download
If you use the SVN repository, you will get the V8 automatically since it has been merged to the trunk.
Look at the readme: http://svn.overbyte.be:8443/svn/ics/trunk/ReadMe8.txt (User code and password are both "ics").
If you need help please don't ask thru this blog, but use the support mailing list. I will NOT answer to questions posted as comment to this blog post. If you don't know the mailing list, just go to the support page at http://www.overbyte.be.
By the way, there is a ICS-V9 in preparation. It will support Android. Stay tuned!
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
The new ICS-V8 is for Delphi 7 / C++ Builder 2006 to Delphi XE5 / C++ Builder XE3 with FireMonkey cross platform support for POSIX/MacOS, also IPv6 support (main development tree, 32 and 64-bit). Note that latest C++ Builder version supported is XE3 (lack of spare time, sorry).
The major changes in V8 include:
- Support for Delphi 7 to RAD Studio XE5
- Support for Firemonkey and Mac OS-X (still beta)
- New support for IPv6 in most components
- New SocketFamily property (sfAny, sfAnyIPv4, sfAnyIPv6, sfIPv4, sfIPv6)
- New MultiListenSockets property for most servers to add extra listening sockets, each with Addr/Port/SocketFamily/SslEnable
- New IPv4 and IPv6 string addresses helpers
- New SMTP mail server component
- New threaded ping component and trace route demo
- Revised directory structure with more, smaller sample directories
You can download ICS-V8 from http://www.overbyte.be as well as from the wiki download page at http://wiki.overbyte.be/wiki/index.php/ICS_Download
If you use the SVN repository, you will get the V8 automatically since it has been merged to the trunk.
Look at the readme: http://svn.overbyte.be:8443/svn/ics/trunk/ReadMe8.txt (User code and password are both "ics").
If you need help please don't ask thru this blog, but use the support mailing list. I will NOT answer to questions posted as comment to this blog post. If you don't know the mailing list, just go to the support page at http://www.overbyte.be.
By the way, there is a ICS-V9 in preparation. It will support Android. Stay tuned!
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
September 29, 2013
Delphi language for mobile development
Marco Cantù wrote a white paper about using the Delphi language for mobile development. Altough this has been written back in april 2013, it is really hot now that Delphi XE5 is out.
Android development is growing fast with Delphi XE5 and reading this white paper will help you write better code for the mobile platform. Delphi compiler for Android (and iOS by the way) is different than Delphi compiler for Windows and MAC. The new compiler is an ARM compiler based on LLVM. This has implications on the speed of some operations. The white paper will tell you what.
You can read the white paper here: http://embt.co/DelphiWP
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
Android development is growing fast with Delphi XE5 and reading this white paper will help you write better code for the mobile platform. Delphi compiler for Android (and iOS by the way) is different than Delphi compiler for Windows and MAC. The new compiler is an ARM compiler based on LLVM. This has implications on the speed of some operations. The white paper will tell you what.
You can read the white paper here: http://embt.co/DelphiWP
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
August 20, 2013
Delphi XE5 to develop Android applications
Delphi XE5 is about to be announced. I have the chance to use a preview version for several weeks now. I’m very impressed!
Using Delphi XE5 I was able to write my first Android application and deploy it to my Nexus 7 in a couple of minutes. OK, for now it is a very basic application: I just took one of the predefined application templates, added a few buttons and labels, hit F9. After a few seconds, the application was compiled and deployed on my Nexus 7 connected to my PC with an USB cable. The application was up and running and I was able to debug it. Waouw!
As you know, I the author of the Internet Component Suite (aka ICS). ICS is about internet programming according to the asynchronous non-blocking programming model. I already started porting my code to Android.
Delphi XE5 is a native compiler for Android. It means Delphi XE5 compile into ARM machine language. It is neither Java nor running under a Java Virtual Machine (Renamed Dalvik on Android). No, Delphi XE5 produces native code which runs fast.
This will help me porting ICS to Android because Delphi XE5 gives me access to the underlying operating system which is… Linux! ICS is all about low level programming and I’m very happy about how it is done in XE5.
Of course XE5 comes with the famous FireMonkey framework (FMX) which covers a lot of thing. The most noticeable is the user interface. For ICS I don’t care about the user interface but of course most application using ICS do. They will simply use FMX. And guess what? FMX is cross platform: the same components (You know edits, labels and hundreds of UI components) can be used for Windows, Android, iOS and MAC OSx.
In the upcoming blog articles, I will enter in more details about Delphi XE5. Stay tuned!
Note: This article is based on a preview version (beta). Retail product may be different. I have been given special permission from Embarcadero to speak about XE5 despite the NDA covering the beta version.
Visit the official RAD Studio/Delphi Android page: http://embt.co/RADAndroid
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
Using Delphi XE5 I was able to write my first Android application and deploy it to my Nexus 7 in a couple of minutes. OK, for now it is a very basic application: I just took one of the predefined application templates, added a few buttons and labels, hit F9. After a few seconds, the application was compiled and deployed on my Nexus 7 connected to my PC with an USB cable. The application was up and running and I was able to debug it. Waouw!
As you know, I the author of the Internet Component Suite (aka ICS). ICS is about internet programming according to the asynchronous non-blocking programming model. I already started porting my code to Android.
Delphi XE5 is a native compiler for Android. It means Delphi XE5 compile into ARM machine language. It is neither Java nor running under a Java Virtual Machine (Renamed Dalvik on Android). No, Delphi XE5 produces native code which runs fast.
This will help me porting ICS to Android because Delphi XE5 gives me access to the underlying operating system which is… Linux! ICS is all about low level programming and I’m very happy about how it is done in XE5.
Of course XE5 comes with the famous FireMonkey framework (FMX) which covers a lot of thing. The most noticeable is the user interface. For ICS I don’t care about the user interface but of course most application using ICS do. They will simply use FMX. And guess what? FMX is cross platform: the same components (You know edits, labels and hundreds of UI components) can be used for Windows, Android, iOS and MAC OSx.
In the upcoming blog articles, I will enter in more details about Delphi XE5. Stay tuned!
Note: This article is based on a preview version (beta). Retail product may be different. I have been given special permission from Embarcadero to speak about XE5 despite the NDA covering the beta version.
Visit the official RAD Studio/Delphi Android page: http://embt.co/RADAndroid
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
Labels:
Android,
delphi,
embarcadero,
FMX,
ICS,
IOS,
Mobile,
Mobile Development,
RAD
August 14, 2013
Android application with Delphi
The next version of Delphi will include a new compiler for the Android ARM Platform. This compiler is based on LLVM architecture like Delphi for IOS compiler. It will produce native code (That is ARM assembly language) which is executed on your device (Phone, tablet of whatever).
You''ll said: Native? I tough that Android was Java. Actually no. Android is based on Linux and has of course a physical processor. Most implementations use ARM architecture, but not all.
Every Android application is a Java application. Well, almost. The truth is that the entry point for an Android process must be in a Java application. This application may be minimal, just a simple class with the only role of loading the native code. Android for Delphi will create a shared object Library containing everything you coded in Delphi. This shared object will be loaded by a minimal application - included with Delphi - that will load the shared object. So what the user see is an normal Android application.
Everything is done transparently for you. You write your Delphi application the usual way, you hit F9, after compilation, Delphi automatically creates an APK (an Android Package Application) with all required files (manifest, resources, and the binary), Delphi deploy the application to your device using Platform Tools, and start it.
To deploy your application using Delphi, you must connect your device thru USB and enable USB debugging on it. You can also deploy the application thru GMail by sending a mail to the user which can then accept to install it on his device. No need to send your application to Android Play Store!
To do all this magic, Delphi for Android requires both the NDK and the SDK to be available on the developer machine. The SDK and NDK are free of charge from Google.
Source: http://blog.marcocantu.com/blog/compiling_android_apps_delphi.html and http://blog.marcocantu.com/blog/fire_icons_nexus_4.html
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
You''ll said: Native? I tough that Android was Java. Actually no. Android is based on Linux and has of course a physical processor. Most implementations use ARM architecture, but not all.
![]() |
Look at the 4 Delphi for Android default icons |
Every Android application is a Java application. Well, almost. The truth is that the entry point for an Android process must be in a Java application. This application may be minimal, just a simple class with the only role of loading the native code. Android for Delphi will create a shared object Library containing everything you coded in Delphi. This shared object will be loaded by a minimal application - included with Delphi - that will load the shared object. So what the user see is an normal Android application.
Everything is done transparently for you. You write your Delphi application the usual way, you hit F9, after compilation, Delphi automatically creates an APK (an Android Package Application) with all required files (manifest, resources, and the binary), Delphi deploy the application to your device using Platform Tools, and start it.
To deploy your application using Delphi, you must connect your device thru USB and enable USB debugging on it. You can also deploy the application thru GMail by sending a mail to the user which can then accept to install it on his device. No need to send your application to Android Play Store!
To do all this magic, Delphi for Android requires both the NDK and the SDK to be available on the developer machine. The SDK and NDK are free of charge from Google.
Source: http://blog.marcocantu.com/blog/compiling_android_apps_delphi.html and http://blog.marcocantu.com/blog/fire_icons_nexus_4.html
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
August 11, 2013
A first look at Delphi for Android
Delphi for Android has been in beta for a while now. The progress has been awesome. Since a few months, Delphi for iOS allowed us to build applications for iPhone and iPad. Now with Delphi for Android, you can simply change the target and rebuild it for Android. It's really Amazing said John Ray Thomas (AKA "JT"), director of Product Management at Embarcadero technologies.
On his blog, JT published a number of photos showing the same application running on an iPhone 5, A Samsung Galaxy S4 and an Nexus 7 tablet.
For those willing to dig into Delphi for Android, the beta program is open to the public: Register here
The roadmap for Delphi is here: http://francois-piette.blogspot.be/2013/08/rad-studio-mobile-roadmap-updated.html
Source: John Thomas blog
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
On his blog, JT published a number of photos showing the same application running on an iPhone 5, A Samsung Galaxy S4 and an Nexus 7 tablet.
For those willing to dig into Delphi for Android, the beta program is open to the public: Register here
The roadmap for Delphi is here: http://francois-piette.blogspot.be/2013/08/rad-studio-mobile-roadmap-updated.html
Source: John Thomas blog
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
August 8, 2013
RAD Studio Mobile Roadmap updated
Embarcadero updated his RAD Studio Mobile Roadmap. This concern Delphi and C++ Builder for Android and iOS.
- NDK based Android Platform support (Gingerbread, ICS and Jelly Bean)
- FireMonkey mobile Framework for Android
- Mobile designer for Android
- iOS 7 support
- Mobile sensor support for Android (GPS, Camera, Gyro, Accelerometer)
- Advertizing and payment for Android and iOS
- Native Android UX w/Native UI styles
- iOS 7 UX w/Native UI style
- High performance iOS and Android mobiel DACs for popular databases
- Interbase Lite and IBtoGo for Android support
- Datasnap middleware mobile enterprise enhancements
- Cross Platform desktop/tablet/phone
- Automatic retina/Hi-Res display handling
- Integrated Android Design, development, simulation, debugging and deployment
- Rest client Framework and mobile BaaS support
- Ad Hoc and AppStore deployment
- C++ Builder for Android: estimated winter 2013
Source: http://edn.embarcadero.com/article/42544
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
What is in development:
- Integrated C++ and Delphi Native ARM toolchains for iOS and Android (compiler, linker, debugger)- NDK based Android Platform support (Gingerbread, ICS and Jelly Bean)
- FireMonkey mobile Framework for Android
- Mobile designer for Android
- iOS 7 support
- Mobile sensor support for Android (GPS, Camera, Gyro, Accelerometer)
- Advertizing and payment for Android and iOS
- Native Android UX w/Native UI styles
- iOS 7 UX w/Native UI style
- High performance iOS and Android mobiel DACs for popular databases
- Interbase Lite and IBtoGo for Android support
- Datasnap middleware mobile enterprise enhancements
- Cross Platform desktop/tablet/phone
- Automatic retina/Hi-Res display handling
- Integrated Android Design, development, simulation, debugging and deployment
- Rest client Framework and mobile BaaS support
- Ad Hoc and AppStore deployment
Roadmap:
- Delphi for Android: estimated fall 2013- C++ Builder for Android: estimated winter 2013
Source: http://edn.embarcadero.com/article/42544
Follow me on Twitter
Follow me on LinkedIn
Follow me on Google+
Visit my website: http://www.overbyte.be
Subscribe to:
Posts (Atom)