While I’ve been buried in meetings for the past few weeks, Seppy’s been a busy fellow. I asked him to get started on figuring out exactly what .NET bits are missing in CF that the Delphi compiler codegen and RTL rely upon. Here’s his reply:
Wahoo! He found the easiest way to figure out what was broken was to build an app and have the compiler report what wasn’t available.
So I immediately copied it to my MPX220 SmartPhone, with this result:
Nuts. Ok, so the .NET Compact Framework on PDAs has significant differences from .NET Compact Framework on SmartPhones. SmartPhones don’t have a clickable button. When you consider the fact that PDAs have a pointer device (stylus) but SmartPhones do not, this makes sense (how can you click a button without a pointing device?), but it’s still another fragmentation factor to make CF development more complicated.
A few minutes of tinkering, and we have this:
Wahoo!
These screenshots show minimal WinForms application written in Delphi syntax. The WinForms functionality is provided by the .NET Framework; the language binding and core RTL are Delphi.
This is the second Delphi “hello world” app running on .NET Compact Framework. The first was a quick test performed on the Delphi for .NET technology preview compiler that shipped with Delphi 7. We now know that that test worked mostly because the Delphi compiler was incomplete – the codegen model was so primitive at that time that the hello world test didn’t trip over any of CF’s now famous functionality voids. As the codegen model evolved to flesh out the Delphi language requirements, dependencies on .NET Framework methods crept in. A surprising number of those .NET methods don’t exist in CF.
What’s Working
From Seppy’s investigations so far, it’s looking very likely that all of the Delphi for .NET language support will work in CF without major modification. He’s got the core RTL up and running and is working on fleshing out the rough spots. Using the Delphi language to build WinForms apps on CF is a sure thing.
What’s Missing in CF
Here’s a snapshot of the Delphi RTL items that are affected by things that appear to be missing in .NET Compact Frameworks and/or Windows CE. This list is a work in progress, and may contain errors. It’s definitely not complete, but it should give you an idea of what kinds of Delphi things are simple to do in CF and which are not.
Unit | Function/Class | Status | Reason/Notes | |
System | _Halt | Stub | System.Environment.Exit not supported, does nothing | |
System | CmdLine | Stub | System.Environment.CommandLine not supported, returns empty string | |
System | IsLibrary | Stub | Assembly.GetEntryAssembly not supported, returns False | |
System | ParamCount | Stub | System.Environment.GetCommandLineArgs not supported, returns zero | |
System | ParamStr | Stub | System.Environment.GetCommandLineArgs not supported, returns empty string | |
System | VCL Locale Override | Removed | Intentionally removed from CF/RTL | |
SysUtils | AnsiPos (AnsiString) | Removed | CompareStringA API not present, WideString overload will get called which will yield incorrect results for MBCS | |
SysUtils | CharLength (AnsiString) | Removed | CharNextA API not present, WideString overload will get called which will yield incorrect results for MBCS | |
SysUtils | CheckThreadingModel | Removed | System.Threading.Thread.ApartmentState not supported | |
SysUtils | ExceptionErrorMessage | Changed | System.Exception.StackTrace not supported (uses blank) | |
SysUtils | ExceptionHelper.HelpContext | Removed | System.Exception.HelpLink not supported | |
SysUtils | ExtractShortPathName | Stub | GetShortPathName API not present, returns original path | |
SysUtils | FindCmdLineSwitch | Removed | System.Environment.GetCommandLineArgs not supported | |
SysUtils | GetEnvironmentVariable | Removed | System.Environment.GetEnvironmentVariable not supported | |
SysUtils | NextCharIndex (AnsiString) | Removed | CharNextA API not present, WideString overload will get called which will yield incorrect results for MBCS | |
SysUtils | SafeLoadLibrary | Stub | SetErrorMode API not present, acts like LoadLibrary | |
SysUtils | TLangRec | Removed | Used by TLanguages | |
SysUtils | TLanguages | Removed | Intentionally removed from CF/RTL | |
SysUtils | TMultiReadExclusiveWriteSynchronizer | Removed | System.Threading.ReaderWriterLock not supported | |
SysUtils | VCL Locale Override | Removed | Intentionally removed from CF/RTL | |
Math | Log2 | Removed | System.Math.Log(X, Base) not supported | |
Math | LogN | Removed | System.Math.Log(X, Base) not supported | |
Registry | TRegistry.LoadKey | Removed | RegLoadKey API not supported | |
Registry | TRegistry.RegistryConnect | Removed | RegConnectRegistry API not supported | |
Registry | TRegistry.RestoreKey | Removed | RegRestoreKey API not supported | |
Registry | TRegistry.UnLoadKey | Removed | RegUnLoadKey API not supported | |
Variants | OleVariantHelper | Removed | Intentionally removed from CF/RTL | |
Variants | VariantHelper (CustomVariants) | Removed | TMultiReadExclusiveWriteSynchronizer not supported | |
WinUtils | FinalizeNativeVariants | Removed | Support function for dbGo | |
WinUtils | FreeNativeVariants | Removed | Support function for dbGo | |
WinUtils | GetCmdShow | Stub | GetStartupInfo API not supported, returns SW_SHOWDEFAULT | |
WinUtils | GetNativeVariantsForObjects | Removed | Support function for dbGo | |
Classes | CheckSynchronized | Changed | TimeOut not supported, ManualResetEvent.WaitOne doesn’t support TimeOut | |
Classes | TThread.Resume | Removed | Not supported by System.Threading.Thread | |
Classes | TThread.Suspend | Removed | Not supported by System.Threading.Thread | |
Classes | TThread.Suspended | Removed | Not supported by System.Threading.Thread | |
Classes | TWin32Thread,ThreadID | Removed | Not supported by System.Threading.Thread | |
Classes | TWriter.WriteProperty | Remove? | Browseable (published) attribute not supported. | |
IniFIles | TIniFile | Removed | GetPrivateProfileString/WritePrivateProfileString API not supported |
Broader issues
The AnsiPos(AnsiString) and CharLength(AnsiString) items above are the tip of an iceberg: While Windows CE does provide locale information, it does not appear to support Ansi (multibyte) strings in the API functions. If you write code using AnsiStrings and want to carry locale or multibyte char data in those strings, these will run into conversion problems in CF. Best solution: Don’t use AnsiString in .NET code. Use String, which is wide (Unicode).
VCL.NET for CF?
So far we’ve talked about the Delphi language, core RTL and WinForms apps. What about VCL for .NET on CF? Windows CE is after all very similar to the Windows API. The answer is still up in the air. Divergence from the Windows desktop platform increases dramatically when you venture into the realm of user interaction and display models. We’ll have to sink a lot more effort into backfilling missing OS functionality critical to VCL or finding alternate solutions with what’s available to produce a VCL based UI framework on CF devices. Developing VCL apps for mobile devices will never be a seamless migration from desktop VCL apps, but it certainly would be nice to have something (anything) less severe than CF’s stripped down WinForms classes.
The System.Browseable attribute is not present in CF. Delphi uses this attribute to implement Delphi’s published visibility. One option would be for us to define our own Browseable attribute for CF and just plow ahead. The VCL.NET streaming system relies on this Browseable attribute to decide which properties of a class should be streamed out (because they were marked as published in the original source). Another option would be to retain VCL stream reading (TReader) but jettison VCL stream writing (TWriter) on the CF device. DFM reading happens in almost every VCL app, but DFM writing is almost never done at runtime by VCL apps.
With the exception of a few operations such as Arc and Chord, TCanvas survives the CF transition rather well. TBitmap, however, does not fare as well. We chose to implement VCL.NET’s TBitmap class using System.Drawing.Image.FromStream to load a bitmap from a file, for example. Guess what’s missing from .NET CF’s Image class? FromStream. I guess someone decided small devices are too small to display graphics? It’s certainly not because of storage constraints, because I have more storage in my phone’s SD storage card (512MB) than in all of my first 5 desktop computers, combined (RAM and HD)!
We will continue to explore the feasibility of adapting VCL to the .NET CF platform, but no promises with this post.
Ongoing Research
If you see something here that you know (by your experience in writing Windows CE or .NET CF applications) is available but not in the usual place, please let us know in email or in a blog comment. We definitely welcome advice from developers with experience in this field.