Shareware Beach

Tuesday, 27 November 2007

Don’t Lie to Me

Filed under: Software Development — Jan @ 7:50

If there’s one thing that I dislike more than helpless software that throws up error messages, it’s error messages that lie. After freshly booting my computer on a sunny Tuesday morning, Thunderbird tells me:

Thunderbird is already running but not responding.  To open a new window, you must first close the existing Thunderbird process, or restart the system.

Duh. I did just start up the system. There’s only one Thunderbird process. And it’s a big fat liar.

The actual problem is that I’m keeping my email on an encrypted volume. On sunny Tuesday mornings, it happens that I forget to mount it. Then of course Thunderbird can’t access my user profile and mailbox. In fact, the whole drive isn’t available until I retrieve the password from my dusty braincells.

How hard would it be for Thunderbird to give me a helpful error message? It notices it can’t access the profile, and that there isn’t another Thunderbird instance that it can bring to front. Check if the file exists. If it doesn’t, tell me the profile can’t be found, show me the path it’s trying to access, tell me why the profile is needed, and offer to cancel, retry or create a new profile. If it does exist, explain that the profile is locked, most likely due to another Thunderbird process having opened it and then gone the way of the Dodo. Apologize for the stuck process (as that could only be a bug), and suggest to kill it via the task manager or restart.

If you’re selling a product that pulls stunts like this, it’s costing you sales. Somebody will run into this on day two of their trial, reboot three times as the error message suggest, uninstall your product in frustration, and tell twenty-five people that you suck. Don’t expect your prospective customers, who are very unfamiliar with your software, to realize that they’ve shot themselves in the foot. So try to make those error messages helpful.

What does your software tell me when I select a recently used file from the “reopen” menu, and the file doesn’t seem to exist? Most software throws up its hands in despair: “File is gone–OK”. Well, that’s not OK. Here’s what you get in EditPad:

c:\I'm a goner.txt does not seem to exist any longer--Cancel--Retry

If I want to give up, clicking Cancel takes no more effort than clicking OK. But if I forgot to pop in the CD or mount the network drive that holds the file, I can do so and be on my way in a jiffy without having to go through the Reopen menu again.

Thursday, 22 November 2007

TMainMenu and Screen Readers

Filed under: Software Development — Jan @ 17:31

I figured out why screen readers don’t read the menu bar in EditPad Pro 6, even though it’s a plain vanilla Delphi TMainMenu. Since the menu uses images, it is an “owner-drawn” menu. That means that the Delphi code in Menus.pas does the drawing, rather than Windows. Screen readers apparently don’t like that.

There are several ways to fix this in your application. A simple fix is to set TMainMenu.Images and TPopupMenu.Images to nil as a user preference.

A more elegant fix, requiring no user intervention, is to call SystemParametersInfo(SPI_GETSCREENREADER, 0, @ScreenReaderActive, 0); where ScreenReaderActive is a variable of type BOOL. If the call sets it to True, the user has a screen reader, and menu Images should be set to nil.

A permanent fix is to edit Menus.pas to never owner-draw anything. Then you can’t forget removing the images from any menu. Define var ScreenReaderActive: BOOL; near the top of the unit’s implementation section. Put the SystemParametersInfo(SPI_GETSCREENREADER, 0, @ScreenReaderActive, 0); call in the initialization section. That handles the detection.

Then find the TMenuItem.AppendTo procedure. There’s a line:

IsOwnerDraw := Assigned(ParentMenu) and

Change it to:

IsOwnerDraw := not ScreenReaderActive and Assigned(ParentMenu) and

In TMenuItem.AdvancedDrawItem, below the (long) nested procedures, there is a line:

if (ParentMenu <> nil) and (ParentMenu.OwnerDraw or (ImageList <> nil)) and

Append not ScreenReaderActive and to this line.

Finally, change the TMenu.IsOwnerDraw function to:

Result := not ScreenReaderActive and (OwnerDraw or (Images <> nil));

Now your menu items will never be owner drawn when there’s a screen reader active.

P.S.: For Delphi to actually use a unit you’ve edited, you’ll need to delete its .dcu files from the \lib and \lib\debug folders in your Delphi install folder, and copy or move the modified .pas file to a folder that’s on Delphi’s library path. You can edit the implementation section of any unit with impunity. Editing the implementation section will cause the compiler to refuse any units that are linked from .dcu files rather than compiled from a .pas file that have the modified unit in their uses clause.

Wednesday, 15 August 2007

What You’re Missing if You’re Stuck with Delphi 7

Filed under: Software Development — Jan @ 8:13

My Delphi 2007 for Win32 post from last February has been attracting a lot of comments. Whaddayaknow! Searching for Delphi 2007 on Google lists that post as the 4th result.

The initial release of Delphi 2007 was a bit marred by new bugs in the Forms.pas unit. These were caused by code changes needed to support the Application.MainFormOnTaskBar property. If you set this to True before you call Application.Initialize, then your application will associate the main form’s Handle with the taskbar button rather than Application.Handle. This should do away with longstanding issues like Tile Horizontally leaving a gap the size of one phantom window, or your application appearing twice in certain Alt-Tab replacements.

Fortunately, Delphi 2007 update 1 is out already, and fixes the Forms.pas bugs. If you don’t make any change to your code, it’ll work the same when compiled with Delphi 2007 as with previous versions.

If you’re still using Delphi 7 or earlier, Delphi 2007 is a must have upgrade. You can buy the Delphi for Win32 personality separately if that’s all you need (unlike Delphi 2005 and 2006 which bundled all personalities). Don’t worry about the impending “Highlander” release. Highlander will have no new features on the Win32 side. Highlander updates the Delphi for .NET personality. If you buy the Highlander studio product (all personalities), you’ll get the same Delphi 2007 for Win32 and C++Builder 2007 that are already available separately, plus the new version of Delphi for .NET.

The main reason to upgrade is that the IDE now runs without issue on Vista. Though you may not use Vista as your primary development platform (I use XP), you definitely want to be testing all your products on Vista. And that’s much easier if you can debug right within the IDE.

CodeGear has published some articles on their site explaining important new features available in Delphi 2007, but not in Delphi 7. I’ll reiterate that all of this applies to good old Win32 development. The new IDE requires the .NET framework, but your applications definitely won’t.

Language and compiler features since Delphi 7

The most popular language feature is probably the new “for..in” syntax. E.g. to iterate over all stings in a list, you can write “for S in MyList do Something(S);”. This is like the foreach operator in other languages, without introducing a new keyword.

Operator overloading allows you use any class in an expression using Delphi’s standard operators. E.g. if A, B and C are types of TMatrix, you could do matrix addition simply with C := A + B. All you need to do is to add one class function to the TMatrix type that takes two parameters and returns the result of the addition. You’ll use the new “operator” keyword instead of “function”, and give the method a predetermined name like “Add” for the + operator.

Class helpers were first introduced in Delphi 8 (the maligned .NET-only release). A class helper essentially allows you to add methods to an existing class, without creating a new class as descending from the original class would do. If the exising class has descendants, the helper methods will also be available in the descendants. E.g. if you create a class helper for TStrings, then all its descendants like TStringList and TComboBoxItems will also have the helper methods. This is a bit of a hack, actually. The only situation in which you should use this is when you really can’t modify the original class directly, e.g. because you don’t have the source code. That’s exactly the situation Borland faced with the classes provided by the .NET framework. No source for Borland to modify. Class helpers are now also available in the Win32 personality.

A lot of class design features from .NET were added to Delphi for .NET and now to Delphi for Win32 as well. These include “strict private” and “strict protected”, for design purists who believe that friends (classes in the same unit) shouldn’t touch each other’s private members. Classes can now be declared abstract in their entirity. Classes can be marked sealed, and methods marked final, preventing descendants and overridden methods. Classes can now contain class constants, class types (including nested classes), class variables and class properties. All of these apply to the class as a whole rather than each instance. In C# parlance these are “static” members.

New VCL features since Delphi 7

Starting with Delphi 2007, VCL applications are themed by default, so they look great on XP and Vista. The TForm.GlassFrame property now allows your forms to use the Vista Aero glassing effect.

New VCL components for new Vista features include TTaskDialog, TFileOpenDialog and TFileSaveDialog.

TFlowPanel and TGridPanel are two new VCL components for automatic layout management. The new Margin and Padding properties work like margin and padding in cascading style sheets (CSS) on the web when you set AlignWithMargins to True and use the Align property to align the control. If you’re tired of setting pixel positions and sizes on all your controls, these new components and properties will save your day.

The TCategoryButtons and TButtonGroup components allow you to easily implement a control like the new component palette in the IDE. And if you’re not using one of the heaps of freeware TTrayIcon components, Delphi finally includes one of its own.

New IDE features since Delphi 7

Actually, this should read: “totally new IDE since Delphi 7″. The first time you try the new IDE, it’ll come across as a big slow beast. But it’ll quickly grow on you when you discover all the new features. The article linked above has a bunch of screen shots.

Only two items in that article don’t have screen shots. This includes the “enhanced debugging features” item. This item alone is well worth the upgrade. E.g. the local variables view can now show local variables for any function on the call stack. All variable views, including local variables, watches, and even the tooltips can now show all fields in objects when you click the + to expand the object’s node. If some of those fields are objects, those can be expanded too. This is tremendously useful. Delphi 7 would only show a useless pointer address, requiring you to manually add watches to see individual object fields.

If you’re interested enough in Delphi 2007 to make it all the way to the bottom of this long article, you know you need it! Unless you always write bug-free code, those debugging features alone are well worth the few hundred dollars for the upgrade. Remember: you get the Delphi 2007 upgrade discount no matter which previous version you have, even if that’s Delphi 1.

Friday, 16 March 2007

Support & Maintenance for Delphi 2007 Win32 Profes

Filed under: Software Development — Jan @ 7:41

With the imminent public release of Delphi 2007 for Win32, Michael Swindell blogged about the new options to buy Delphi 2007, in particular the electronic download. If CodeGear also releases a free trial as Borland had been doing for some time, Delphi will now truly be shareware!

But I’d like to talk a bit more about the “Support & Maintenance for Delphi 2007 Win32 Profes” that gets added automatically to your CodeGear shopping cart when you put Delphi 2007 into it. This is not some overpriced extended warranty. Nor is it one of Digital River’s tricks to increase DR’s revenue.

“Support & Maintenance for Delphi 2007 Win32 Profes” is in fact what Borland used to call “Software Assurance”. If you buy this, then for the next 365 days, you get all releases, including major updates, of all personalities in CodeGear’s RAD Studio (previously Borland Developer Studio or BDS). These are Delphi for Win32, Delphi for .NET, C++Builder and C#Builder.

Since CodeGear looks set to update Delphi annually or even have more than one release per year, this seems too good to pass up. Since you can renew this contract anually, you can effectively get all Delphi releases for only $360 per year (if you choose the Professional edition, which is what most shareware authors need). That comes to only $30 per month, which is very little money if Delphi is your bread-and-butter development tool.

The products you receive as part of the Software Assurance contract are full licenses. They do not expire if you let your SA contract lapse. However, if you let it lapse, you’ll pay full price again for the next update. SA cannot be purchased separately. You have to buy it together with a new license or upgrade license purchase.

There have been some complaints in the past that SA was not good value, because Borland took far more than one year between Delphi releases. But we’re not buying from Borland any more. This CodeGear thing is a very different beast.

Last Wednesday, I saw a big picture of Tod Nielsen, Borland’s CEO, on the front page of the weekly IT section in the Bangkok Post, with an article on how he was going to change the world. (Or something like that. I forget the details.) Ben Smith, CodeGear’s CEO, on the other hand, took the time to write a comment on my very own blog. (His initials are BTS.) I know which approach I like best.

« Previous PageNext Page »