Skip to content

Two FireMonkey nasties

20 January, 2012

As the title says, here’s two little FireMonkey nasties I’ve got round to QC’ing that may be of interest to someone starting to play around with the framework:

  1. TBitmap.LoadFromFile does not raise an exception when the file does not exist – instead, it just silently returns (see QC 102636).
  2. TFmxObject.Children (which is equivalent to TWinControl.Controls in the the VCL) always returns nil on an out-of-range index rather than raising an exception. Combined with the fact the ‘as’ operator accepts a nil source, this causes typos to generate nasty, generic access violations rather than exceptions that tell you what the error actually is (see QC 102747).

Mac troubles redux

20 January, 2012

Not long after I posted previously about an anonymous blogger having problems with running Delphi applications on OS X Lion – the error message was ‘You cannot open the application test01.app because the Classic environment is no longer supported’, which in itself didn’t make any sense – some helpful hints were posted in a comment:

For what it’s worth, I run applications built with XE2 on OSX Lion just fine. Other people do too.

I think it’s unlikely that Carbon APIs would cause this. This error normally occurs for a OS9 application, i.e. something is probably making the loader think it is not a OSX app. They have very different executable formats. This is guesswork, but makes more sense than an old API somehow drawn in – I don’t see how Embarcadero could have done that, given they provide translations of the Apple-provided headers / APIs and were probably working with those same translations themselves.

Some googling would have turned up threads like this: http://forums.digitalspy.co.uk/showthread.php?p=39579653 where other new apps, in this case iTunes itself (!) gives this error. The solutions imply it’s due to corruption of some sort: possibly of the app, the app bundle, permissions, or even the OS.

Things to try would be:
- Clean and rebuild the app (and completely remove it from where it’s located on OSX, to be sure to make the IDE moves everything across again.)
- Open the app bundle and compare it to a working app. What’s different? Can he execute the program located in the bundle from the command line? If not, what error does it give?
- Reinstall the remote debugger. Maybe it’s this thats corrupted, not even his app…? It’s impossible to know from his post when this error occurs (running from the IDE, i.e. debugging? Running the app normally on OSX? …?)
- Open Disk Utility and verify the disk, and check / fix file permissions.

After that, if he still has problems, I’ll admit it’s more complicated. The next appropriate move would be to post on the Embarcadero forums or open a support request.

Thanks to David M for the advice.

Anyone want to help out Mr Hater…?

19 January, 2012

Poor Mr Hater is having trouble running FireMonkey applications and/or the remote debugger (it’s unclear what) on OS X Lion. Would any XE2-user-with-a-Mac have a suggestion? The error message reported (‘You cannot open the application test01.app because the Classic environment is no longer supported’) doesn’t make any sense in itself, since the ‘Classic’ environment was the emulator that ran OS 9 applications compiled for PowerPC, and XE2 has as much chance compiling for OS 9 and PowerPC as it has targeting CP/M on a Motorola 68000.

In fact, in the main, XE2′s RTL and FMX sources keep well away from legacy Mac APIs. Despite some (probably unintentional) misinformation around, the frame of an FMX form is a Cocoa window, not a Carbon one (‘Carbon’ was/is the API Apple provided to allow C and C++ applications to cross compile for OS 9 and OS X, ‘Cocoa’ the ‘modern’ Objective-C and OS X-only API). As for the RTL, this delegates to the POSIX layer as much as possible, and failing that CoreFoundation, which is C-based but OS X specific API layer. There is however one exception – due to OS X’s apparently incomplete implementation of POSIX threading (it doesn’t support unnamed semaphores), the Carbon ‘Multiprocessing Services’ API is used instead for TSemaphore, TEvent and TMonitor. This then brings in TCriticalSection and a few other things, which are based on TMonitor when targeting OS X. While the RTL team should probably be at least investigating an alternative to the Carbon API here pretty sharpish, surely use of an API only recently marked ‘deprecated’ (‘v10.7′ = Lion) wouldn’t have caused Mr Hater’s problem…?

Nice post on writing a custom FireMonkey control

16 January, 2012

Just a quick post to say if you’re interested in the basic mechanics of custom control creation in the FireMonkey framework, you may want to check out this article by Mike Sutton on his MonkeyStyler blog.

XE2 update for my image metadata reading/writing library (CCR Exif)

16 January, 2012

I was going to get round to it eventually, though having an explicit request prompted me to actually do it: updating my open source image metadata reading/writing library (CCR Exif) to properly support XE2. The updates I’ve just posted to Google Code has it cross compiling for each of Delphi XE2′s three DCC-targeting platforms, Win32, Win64 and OS X; it should also still compile back to D2006, though at least D2007, and preferably D2009 are preferred. On the downside, iOS isn’t supported because the code remains as Delphi-specific as ever (and no, FPC 2.6.0 doesn’t help much). Also, there aren’t any FireMonkey demos as yet, though the console ones all cross compile if you have XE2 and add OS X as a target platform.

In practical terms, Win64 took as long as it took to add ‘Win64′ as a target for each of the demos; OS X was somewhat longer for a mixture of reasons, primarily because the code had some entanglement with the VCL graphics classes, and there’s no ‘clean’ way for the same code to work with both VCL and FMX on that score. By far the biggest waste of time effort was managing project files across an array of Delphi versions though, with battling Subversion a close second, i.e. not actual coding at all. As I wanted to make running the demos as newbie-friendly as possible, I’ve ended up with separate project files for D2006, D2007, D2009-10 and XE+ – just open the appropriate project group located at the top of the trunk and do a Project|Compile All. If compiling under D2007 or later, executables will then be outputted in a sub-directory off the Bin folder next to the individual projects, and DCUs in a ‘DCUs’ folder off of the main trunk.

Anyhow, the Google Code page is here; if using the File|Open From Version Control… command in the XE or XE2 IDE, the URL to enter is http://ccr-exif.googlecode.com/svn/trunk/; choose either Console Demos (XE+).groupproj or VCL Demos (XE+).groupproj as appropriate when prompted.

Running console applications on Lin… er, OS X

14 January, 2012

Here’s a few small small OS X (or more generally, Unix and Unix-y) console application tips. All of them are pretty trivial, but I easily forget such things, so they’re for my own future benefit really…

  • If a application isn’t on the system PATH, then you always need to provide a path when running the program on the command line. Happily, relative paths are acceptable, and the symbol for ‘the current directory’ (i.e., a single full stop) is the same on Unix and Windows. For example, say you have a console program called MyUtil that has been put in ~/Applications. If in a Terminal window you go into that folder, the command for running the program will involve prefixing its name with a full stop and a forward slash:
  cd ~/Applications
  ./myutil
  • There are numerous ‘standard’ locations to put console applications where they will be globally available — on my iMac, the system path (with no changes to it on my part) is composed of /opt/local/bin, opt/local/sbin, /usr/bin, /usr/sbin, /sbin, /usr/local/bin and /usr/X11/bin! Of the main Linux-y stuff I’ve installed, Wine has dumped a load of things in /opt/local/bin and Mono has liberally fly-tipped /usr/bin. Since out of the root directories, only /opt isn’t hidden by default in Finder (well, at least for me), I’ve put things of my own in /opt/local/bin. This still requires getting past the equivalent of a UAC prompt, though that isn’t a bad thing IMO.
  • When distributing a Delphi-produced console application, remember there is one dependency you can’t avoid – libcgunwind.1.0.dylib. This must be placed in the same directory as the executable. However, it is only 25KB. The much bigger, and program-specific, .rsm file the compiler produces should not be required – this is just for debugging.
  • When the user passes a parameter to a console application that contains a wildcard, the command-line interpreter will expand it before the application gets a chance to do anything. For example, say the command myutil *.jpg is entered, where MyUtil is a console application written in Delphi; inside of the application, ParamCount will return the number of *.jpg files in the current directory, ParamStr(1) the first *.jpg file, ParamStr(2) the second and so on.
  • If you want to prevent wildcard auto-expansion, wrap the parameter in quotes, just as you would wrap a parameter that contains one or more spaces in quotes:
  myutil "*.jpg"
  • ParamStr(0) on OS X will return whatever was typed by the user to start the program. If that was ./myutil , then ./myutil will be returned (you won’t notice this in a FireMonkey application, since a graphical OS X application is ‘bundled’, and so never run directly by the user). If you want a path, you can use GetModuleName(0) instead (as you can on Windows in fact). This however is likely to return the executable’s path concatenated with whatever ParamStr(0) returns, meaning both a superfluous ./ could be embedded and the ‘wrong’ casing used (on Windows, ParamStr(0) will return the file name with the case of the actual EXE file – MyUtil.exe not myutil.exe). To fix both, pass whatever GetModuleName returns to ExpandFileNameCase:

  function GetExecutableName: string;
  var
    MatchedCase: TFilenameCaseMatch;
  begin
    Result := ExpandFileNameCase(GetModuleName(0), MatchedCase);
  end;

While unnecessary, this extra handling is harmless when targeting Windows, so you don’t need to IFDEF it when targeting both platforms.

Follow

Get every new post delivered to your Inbox.