Presentations and code samples from DAPUG 2014 workshop are now available online.
Big thanks to organizers (and especially Jens) – we had great time in Denmark! Hope to see you again some time!
If you install RAD Studio XE7 and then upgrade Android SDK to version 23, you won’t be able to deploy applications to Android devices anymore.
The reason for that is that ZipAlign.exe was moved out of sdk\tools folder in SDK 23 and XE7’s deployment process cannot find it anymore. Now it is located in sdk\build-tools\20.0.0, but only is Android SDK Build-tools rev. 20 are installed, which doesn’t happen automatically.
To fix my Delphi I first had to install Build tools rev. 20. Then I copied sdk\build-tools\20.0.0\zipalign.exe to sdk\tools\zipalign.exe. That fixed the deployment problem.
I’m hoping Embarcadero will fix this in the next update, but for now you can use this workaround.
[Android sdk folder can be found in c:\Users\Public\Documents\Embarcadero\Studio\15.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk]
This is a job offer for a full time programming job in Ljubljana.
Iščemo Delphi programerja za dolgotrajno razmerje; človeka, ki se ne ustraši stare kode in z veseljem programira s sodobnimi orodji. [XE2, prehod na sodobno različico je že v teku in ga bo pomagal zaključiti prav programer ali programerka, ki ga iščemo.] Delo se opravlja v pisarni v Ljubljani.
Več o podjetju: www.fab-online.com. Kontakt: primoz (pri) fab-online.com.
A snapshot from the XE7 presentation in Ljubljana.
Highlights of the presentation were FireUI, System.Threading, dynamic arrays, and OmniXML.
‘Twas a very nice crowd, asking LOTS of questions. It was also good to see some young(er) people and some Delphi [insert a prehistoric version here] users who finally decided that they should upgrade.
If you want to see all the great new stuff in XE7, join me on Wednesday, 17th in Ljubljana. We’ll cover the new VCL stuff, multithreading support, improvements for multi-device development, business mobile services and more.
As usual, presentation will be in Slovenian language.
This is one of rare posts on my blog that doesn’t cover pascal programming. Proceed on your own risk ;)
For the last half a year, I’ve been a happy owner of a Chromecast device. Great stuff, especially as it allows me (with a small hack) to watch Netflix on my TV and listen to Pandora. At the beginning, it was a bit unstable, but through regular updates it stabilized quite a bit – until build 17977 got installed.
Since that time I got random crashes while playing any media (video or audio) from any source (in-house or external provider). It would load the player app, start playing, then crash after a few seconds. It would work fine for days, even weeks, but then it would start crashing and I would not be able to use for for half a day, after which it would start working again.
I’ve decided that the hardware is broken, maybe overheating, and I bought another one. (Did I mention it’s cheap?) But no luck – it started behaving the same as soon as it has upgraded to build 17977.
Few days ago I found a network forum thread where someone (sorry, no link, it got lost) mentioned a possibility of a bad power source. (My Chromecast is plugged into TV’s USB port.) And when the device started playing tricks on me today, I plugged it into an external USB power supply. And – surprise, surprise – it started working!
Something weird is still going on. When I start playing in a new player (i.e. when I switch apps), media is played for few seconds, then the TV goes blank and its power light starts blinking, then the picture reappears and media continues to play.
My current guess is that Chromecast does something weird which basically quick-resets the TV. When Chromecast was plugged into TV’s USB port, that also reset the Chromecast, but now that it’s plugged into an external power source, Chromecast continues playing while the TV does its yoyo trick.
I’m not completely satisfied with this solution as I would rather see my Chromecast to turn off together with the TV, but it is a “good enough” workaround. I still love that device, though. It’s the best stuff Google made in a long long time.
I’m posting this blog in hope that it will help other Chromecast users who may run into the same problem.
If you are still deciding whether to attend my workshop, you should hurry up. The organizers have notified me that there are only few places left as there are some physical constraints they have to observe, namely how many people fit in the conference room ;)
BTW, if you are interested in the parallel part of the workshop, you’ll be glad to know that I’ll also be covering the new cross-platform multithreading support in XE7.
DAPUG, the Database Application Programmers Users Group (aka Danish Embarcadero User Group) is one of Delphi user groups which organizes great events twice a year. I’m very proud that they have invited me to speak in October, even though I’ll miss ITDevCon because of that :(
(A note to ITDevCon organizers – DAPUG’s autumn workshop is traditionally organized near the end of October.)
First day will be completely dedicated to multithreading. We’ll start with basics – why and how – and proceed with TThread-based multithreading on all supported platforms. After lunch we’ll focus more on high-level multithreading with the open-sourced OmniThreadLibrary.
A note to participants: I’ll be presenting multiple small problems for you to solve during the workshop. At least you should have Delphi installed on the computer (for best experience it should be one of the latest versions). If you really want to come prepared, you can also preload OmniThreadLibrary and if you are trying for the best in class award ;) you can read all about high-level multithreading in advance on the OmniThreadLibrary wiki.
The second day will be organized around three topics – attributes, regular expressions and continuous integration. The common point is productivity – in the first two sessions I’ll be showing you how to use some of the incredible power of Delphi to simplify your programming life and in the latter I’ll be focusing on the last stage of any application – building and deploying the release version.
Workshop will be held on October 21st and 22nd in Hotel Hesselet in Nyborg.
More information and registration form can be found here.
If you need to write software for phones/browsers/node.js/microcontrollers, you should check out the new Smart Mobile Studio 2.1 (beta 1). The list of new and fixed features is much too long to list here so I’ll just focus on the most important additions.
A deceptively simple question – how do you update a progress bar from a ForEach loop – popped up on the Google+ OmniThreadLibrary community. The implementation turned out to be quite tricky so I created an example (55_ForEachProgress) which is now part of the OmniThreadLibrary SVN repository.
The starting point was a simple Parallel.ForEach loop which I further simplified in the demo.
procedure (const task: IOmniTask; const i: integer)
// do some work
// update the progress bar - how?
We cannot simply update the progress bar from the ForEach executor as that code executes in a background thread and one must never ever access VCL GUI from a background thread! It is also no good to send “please update” Windows messages to main thread as Parallel.ForEach is by default blocking – it waits for all workers to stop working – and messages won’t be processed during ForEach execution.
Yesterday I had to write a mapping from a set of radio buttons to an integer (and back). I couldn’t use TRadioGroup and so I had to iterate over controls to find out which one is checked. To do that, I used an enumeration helper which I wrote long time ago.
function TfrmColorRemappingDlg.GetMapping: integer;
Result := 0;
for ctrl in EnumControls(Self, TRadioButton) do
if TRadioButton(ctrl).Checked then
At that point I decided that this old-way enumeration is not good enough for the modern times. What I particularly dislike about it is that I know the type of objects enumerator will return (TRadioButton in this example) but I still have to cast the enumeration variable to that type. The solution is simple – use generics!
Besides being a programmer, I like taking pretty pictures (and working with wood, but that’s another story). And from time to time I like to print some pictures and hang them on a wall.
Because framing pictures is expensive and, frankly, most of them don’t deserve it, I like to print a “virtual frame” – a thin black border followed by a wide white border – around each photo. Until recently, I was adding them in some stupid program I found on the Internet (it doesn’t deserve to be named), but I was always having problems because you had to specify border width in pixels – and if I wanted to set the same border (for example, a 1,5 mm black border followed by a 20 mm white border) for a set of pictures in a different resolutions, I had to calculate pixel sizes for each photo, which was a pain.
So I sat down and wrote a border-adding program. It allows you to specify border sizes in “real” measures, it can process one picture or a folder full of them and it can add a suffix to processed pictures (plus it will skip files containing this suffix if they are found in the source folder) and that’s about it. It is small, simple, solves a real problem and – what I found the most impressing – I wrote it in a single working day. Truth to be told, I needed about a month of work – an hour here, 15 minutes there – but all together I needed less than eight hours. That is the power of Delphi!
If you have a need for such tool, go ahead and download it from my Dropbox. You can also get the source, which is released to a public domain (i.e., do with it whatever you want). It depends on few external libraries, which are all released with an open source license: JCL, JVCL, GpDelphiUnits, OmniXML. At the moment the GUI is written in VCL, because I really didn’t want to spend too much time on this project and I know VCL by heart, but if somebody wants to go ahead and rewrite it in FireMonkey, I certainly won’t stand in his/her way.
You cannot safe-cast a pointer. This will fail:
ptr as TProject
You can only cast pointers the unsafe way:
That is, unless you use this neat trick:
TObject(ptr) as TProject
This will also catch programming errors, specifically a pointer that doesn’t point to an object.
If you have problems processing PNG images because you are using DevExpress components, add this to the beginning of your program’s uses list:
DevExpress registers PNG handler with doesn’t behave exactly the same as Delphi’s built-in TGraphics descendants. With this addition, PNGImage.RegisterFileFormat will be called after dxGDIPlusClasses.RegisterFileFormat and will overwrite DevExpress’ PNG handler.
There was a nasty race condition in the IOmniPipeline termination code which could result in access violations. It has been fixed in the SVN so please update to the latest version if you are using Parallel.Pipeline, Parallel.BackgroundWorker, or Parallel.ForkJoin.
Great thanks go to Dean from DeNovo Software who narrowed down the problem and make sure I can repeat it on my machine.
This Tuesday (March 4th) Embarcadero and Marand are organizing a RAD Studio XE5 presentation in Ljubljana. We’ll be showing great features that were implemented in RAD Studio in the past few years – from 64-bit Windows compilation, Unicode support and styling to multiplatform development, LiveBindings and FireDAC. For the first time in Slovenia we’ll be presenting the new REST library and C++ support for iOS.
Presentation will be given in Slovenian language. Register here.
As seen on Blogger:
I have just written a reply and clicked “Sign out”. For the third time since the Google changed the Blogger UI!
I don’t care that the “Publish” button is highlighted. “Sign out” is just placed in perfect position to click on when you are typing a response.
Fix this, Google!
Yesterday I noticed a big nasty bug in the OmniThreadLibrary which was present in for a long long time. If a thread priority was not explicitly specified (by calling SetPriority OTL function or SetThreadPriority Windows API), a thread was started with idle priority (instead of normal).
How comes nobody has noticed that? Well, it looks like the Windows thread scheduler is really great and nicely schedules threads even in such case. Still, this is something that has to be fixed and I have immediately released new version.
Go to https://leanpub.com/omnithreadlibrary and buy the “The Book + Webinars” package for mere $29.99!
By the way, now you can buy a site-wide license – buy the book and give it to anybody in your organisation for mere $250! Plus you get all three webinars in the deal.
I know we promised it for November so here it is – Smart Mobile Studio 2.0 beta 1, released on November 39th ;)
I know some were waiting anxiously for this release so joke aside – we are sorry that we couldn’t release it in November but you know how it goes – there is always one more showstopper problem :( We know that this beta is not yet perfect (and we’ll release another one before the product is finalized) but as we do want your feedback we have exposed it for the public consumption.
In case you were not actively following Smart since the last release, I would like to recommend few interesting articles on our site:
And remember – Smart targets everything from microcontrollers (Espruino) to mobile devices (in-browser, PhoneGap, Cordova), desktop (in-browser) to servers (NodeJS).
This is a guest post, written by Anton Alisov, software PM and developer from Ivanovo city, Russia.
I’m posting it here because I want to increase visibility of this new memory manager which featured quite well on my recent test (guest posted at Eric’s blog). I’m perfectly aware that my test was superficial and I intend to do a better test with more memory managers in the following weeks.
Arnaud Buchez already posted a overview of the memory manager on his blog.
And now I’ll give word to my colleague Anton.
We were waiting for the robust and scalable memory manager for Delphi for the long time. Our best choice - FastMM - did not scale well under multithreaded use in memory intensive applications. Memory manager with
a new design was required. We have tested many scalable managers such as TopMM, ScaleMM and other. Some of them are quite robust, but not supported currently by its developers (TopMM), some are not yet ready
for production. So, we decided to develop our own memory manager to have more control over it. We believe, one doesn't have to be big to be efficient. Meet a new player - SapMM - Simple As Possible Memory Manager.
SapMM is robust, production quality memory manager, developed by software guru Alexei Nedoria from Ivanovo city, Russia. SapMM was designed for use in memory intensive multithreaded applications with the
scalability in the first place. In single threaded use SapMM is only a bit (up to 40% on certain scenarios) slower than FastMM (on some scenarios SapMM is faster than FastMM even in single threaded use), but
the real power of SapMM shows in multihreaded applications. SapMM scales very well and in a vast majority of scenarios is much faster than FastMM in multithreaded use.
SapMM is used in production 24/7 system since June 2013. Currently SapMM was well tested only with Delphi XE and XE3, small code changes may be required in order to use it with other versions of Delphi. Currently SapMM supports only 32-bit mode and cannot be used in 64-bit applications. You can grab SapMM sources and do some tests yourself: https://code.google.com/p/sapmm/
Next Tuesday (December 3rd) we’ll continue the Embarcadero Academy line of presentations for Slovenian developers. This time I’ll cover programming for Android devices in Delphi XE5.
Predavanje bo v slovenskem jeziku.
ITDevCon 2013 has finished and as always it was a beautiful (but wearying) experience. I’m still trying to pull myself together.
My session slides and code are now available on this blog – just click on the Presentations link on the right.
Some snapshots from the conference (take with the crappy camera on the Sony Xperia P phone):
Smart Mobile Studio everywhere
OmniThreadLibrary 3.03a has just been released. This is purely a bugfix release which fixes ugly problem in the ForEach abstraction. If the code has called ForEach with empty input set (for example, ForEach(0, –1)), the program would block infinitely.
The ITDevCon conference is almost there (register while you still can!). As four times before, the organizer has invited an impressive list of speakers which will be giving 19 presentations (if I counted correctly), divided in three parallel tracks over two days. The conference will occur on 14th and 15th in the beautiful city of Verona.
On the first day of the conference I’ll be presenting two Delphi-related sessions. In the Using attributes and RTTI to automate programming tasks talk, I’ll introduce a concept of attributes in Delphi and present few different practical uses for this interesting but underused language concept.
In my second session of the day, Continuous Integration, delivery and deployment, I’ll talk about continuous integration and its cousins, continuous delivery and continuous deployment. In the session I’ll present few different software tools that support those concepts and I’ll also speak about practical experiences with continuous integration in the field.
I hope I’ll see you in Verona so we can talk about Delphi, Pascal, and everything related and unrelated!
Yesterday’s 3.03 version was somehow corrupted (in a way that it doesn’t compile). I have no idea what I did wrong as I did recompile test apps before committing and they did compile. Anyhow, if you’re one of the first 85 downloaders, please download the corrected version or implement a very simple fix. In the OtlParallel unit on the line 1663 a class prefix is missing. Just type it in and everything will work.
class procedure Parallel.ApplyConfig(const taskConfig: IOmniTaskConfig; ...
The management apologizes for the inconvenience. ;)
EDIT 2013-10-16: It has been brought to my attention that both the original 3.03 and yesterday's fix were missing the XE5 packages. This has been now fixed. You can download missing packages from here.
OmniThreadLibrary is simple to use threading library for Delphi. It's main "selling" points (besides the price, of course are power, simplicity, and openess. With just few lines of code, you can set up multiple threads, send messages between them, process Windows messages and more. OmniThreadLibrary doesn't limit you in any way - if it is not powerfull enough for you, you can ignore any part of its "smartness" and replace it with your own code. If you don't like working with threads - no problem! You can use high-level primitives like parallel for, futures and pipelines to introduce parallelism into your application.
OmniThreadLibrary is an open source project. It lives in the Google Code and is licensed under the BSD license.
At the moment, OmniThreadLibrary supports Delphi 2007, 2009, 2010, XE, XE2, XE3, XE4, and XE5 on the Win32 and Win64 platforms. Currently, there are no plans to support older Delphi compilers and .NET. XE2+
support is limited to Windows targets. Firemonkey is currently not supported.
Home page: http://www.omnithreadlibrary.com/
Web discussion forum: http://otl.17slon.com/forum/
Issue tracker: http://code.google.com/p/omnithreadlibrary/issues/list
SVN checkout instructions: http://code.google.com/p/omnithreadlibrary/source/checkout
Author's blog: http://thedelphigeek.com
Author's home page: http://www.glagolite.si/delphi/
Documentation wiki: http://otl.17slon.com/book/
Documentation book: http://http://leanpub.com/omnithreadlibrary
Sometimes you write a blog post that you wish you wouldn’t. Maybe you don’t, but I certainly did. Yesterday I wrote about TStreamAdapter.Seek Broken For Large Files I completely incorrectly stated that “the bug was not fixed in XE4/XE5”.
The reason for my mistake was that although I verified the problem in the XE2, I didn’t write any test code for it (we already had a failing application so I didn’t have to – or so I thought) and I only checked the RTL for changes. I found out that the TStreamAdapter.Seek didn’t change from XE2 to XE4/5 and assumed the worst.
Well, the good guys at Embarcadero did fix the problem in the meantime – but in a different place. They have added a new Seek overload to the TStream class and this new Seek (which is implemented as an inline function) acts as an intermediary between the TStreamAdapter and the correct TStream.Seek method. This solution is much better than our quick fix as it also fixes all other code in the world which mistakenly calls the wrong Seek overload.
function Seek(Offset: Longint; Origin: Word): Longint; overload; virtual;
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; overload; virtual;
function Seek(const Offset: Int64; Origin: Word): Int64; overload; deprecated; inline;
function TStream.Seek(const Offset: Int64; Origin: Word): Int64;
Result := Seek(Offset, TSeekOrigin(Origin));
Thanks to the Arioch’s prompt in the original post I did write a test code today and when I finally tested it on the XE5, it run just fine! Imagine my shame. :(
What have I learned today? That looking at the source code is not enough, especially if you want to complain. Always write a test case (and then run it!).
I deeply apology to Embarcadero programmers (especially to the guy who fixed the original error) and to you, my readers.
And now, if you’ll excuse me, I’ll pull a cover over my head and gently weep.
This is simple test code which tests TStreamAdapter.Seek functionality and doesn’t require creating 4+GB files on the disk. A fix is also included.
Windows, SysUtils, Classes, ActiveX;
TTestStream = class(TStream)
function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
(* quick fix
TStreamAdapter = class(Classes.TStreamAdapter)
function Seek(dlibMove: Int64; dwOrigin: Integer;
out libNewPosition: Int64): HRESULT; override; stdcall;
function TStreamAdapter.Seek(dlibMove: Int64; dwOrigin: Integer;
out libNewPosition: Int64): HRESULT;
if (dwOrigin < STREAM_SEEK_SET) or (dwOrigin > STREAM_SEEK_END) then
Result := STG_E_INVALIDFUNCTION;
NewPos := Stream.Seek(dlibMove, TSeekOrigin(dwOrigin));
if @libNewPosition <> nil then
libNewPosition := NewPos;
Result := S_OK;
Result := STG_E_INVALIDPOINTER;
function TTestStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
GSeekOffset := Offset;
Result := Offset;
ts := TTestStream.Create;
sa := TStreamAdapter.Create(ts, soOwned);
sa.Seek($123456789, soFromBeginning, np);
if GSeekOffset = $123456789 then
Writeln('Seek is OK')
Writeln('Seek is broken');