Home | Shorter Path | About Me
Home
About Me

Archive

2004

01

02

03

04

05

06

07

08

09

10

11

12

 

2005

01

02

03

04

05

06

07

08

09

10

11

12

 

2006

01

02

03

04

05

06

07

08

09

10

11

12


Disposing BDP objects
Wednesday, May 24, 2006 06:30 PM

One of the tasks in the BDN 2 project was migrating the old BDN content from the Oracle database where it was stored. Of course, we wrote a migration program using Delphi and accessed the database using BDP. When running the migration, however, we kept getting errors from Oracle: the program was opening cursors but not closing them. The BDP documentation isn't very detailed, but BDP is simply an ADO.NET provider, so what works on other providers should work with BDP, right?

Well, not exactly. For the providers included in the .NET framework, you're required to call Close for any command or data reader object. Turns out this isn't enough for BDP - you also have to dispose of the object. You can do so by explicitly calling the Dispose method. If you're using Delphi, calling Free automatically calls Dispose for you. So, if you're accessing Oracle using BDP, make sure to call Dispose or Free when you're done with the object (you should probably do that with other databases as well, but I've only seen the open cursors issue with Oracle so far).

BDN 2
Wednesday, May 24, 2006 05:11 PM

BDN 2 is now public. The site looks pretty much like BDN 1, but is in fact a complete rewrite using Borland Developer Studio 2006 (and yes, I'm just going to ignore the fact I haven't posted here in almost a year). You can read about the new features here. I've been heavily involved in the project, and my most visible contribution is the new GetPublished system. On BDN 1, GetPublished was a form that let community members submit articles. We've kept the name, but extended the system to a full content management system for the site.

One of the cool things about GetPublished is that it implements a community process for publishing content. The basic workflow for a new article is as follows:

  • An author posts a new article.
  • The author signs a agreement allowing Borland to publish the article.
  • The article is reviewed for accuracy, usefulness, depth and clarity.
  • A price for the article is negotiated.
  • The article is published and the author is paid.

There are additional workflows, such as updating an existing article, translating an article, or reviewing and editing articles. GetPublished implements these processes based on roles, which are greanted to community members and Borland employees. The roles dictate what each user can see and do. The main difference from the old system is that the entire process is implemented in publicly accessible system, and any user could be granted any role. For example, community members could be granted the "reviewer" role, allowing them to review unpublished content. Trusted members could even be allowed to publish content, since the system already makes sure only content meeting spcific criteria could be made public.

The big news for authors, though, is the new submission interface. Authors are no longer forced to write their articles in HTML format (although they still can). You can write your article in Word (or any word processor that can save Word files) and upload it directly. GetPublished will convert the document to HTML, extract embedded images, and post the article. You can even sign the necessary agreement electronically on BDN's new digital signatures system.

GetPublished and BDN 2 are a work in progress. Just yesterday I added an option to edit HTML directly on the submission page (although we're still working out the kinks - if anyone has experience with making FreeTextBox work well with FireFox, or knows of a really good ASP.NET HTML editor we should use, drop me a line), and more improvements are coming. If you find any problems or want to suggest new features, post a report to the GetPublished area in QualityCentral.

Right now, there isn't much documentation for GetPublished. More information should be available soon, but in the mean time I'll try to post here and elsewhere about some of the features.

24
Tuesday, July 19, 2005 10:38 PM

The 24 Hours of Delphi event was really cool. I didn't stay up for all of it (my day started a lot earlier), and there were some problems with the streaming during some of the segments, but the recordings have now been posted to BDN. You can download the recordings or listen to them online.

I talked a little about some work I'm doing for BDN. It's a really interesting project, and is a lot of fun. It's also a lot of hard work, which is why I haven't posted in a while. In the meantime, check out the new ECO articles on BDN ("What is ECO anyway?" and "Combining ECO OCL constraint validation with ASP .net page validation" by Peter Morris).

24 Hours of Delphi
Sunday, July 10, 2005 07:53 PM

The 24 Hours of Delphi start on July 13, 2005 12:00 AM PDT. Mark your calendar. You'll hear lots of people talking about Delphi, .NET, and other cool stuff, plus you'll get to hear what David I is like after staying up for over 24 hours.

I'll be online in hour 13 (1:00 PM PDT, 9:00 PM London, check for your local time), ranting about the VCL, VCL for .NET, ASP.NET, and some of the language features in Delphi 2005. You'll be able to submit questions during the broadcast. You can also submit questions in advance by e-mailing Anders Ohlsson (see the event description for deatils). Looking forward to hearing from you!

Accessing Outlook in Delphi 2005
Saturday, June 25, 2005 09:20 PM

A question was posted to the Delphi newsgroups about accessing Outlook from a .NET application witting in Delphi 2005. This is actually pretty easy, but there are a few catches. I recently worked on a .NET project that used Office objects, and had to struggle a little to get Delphi to work with them, so I'm posting this in the hope it would save people some time.

Microsoft Office exposes a set of COM Automation objects that can be used by macros and external applications. Like other COM objects, these can be accessed by .NET applications. .NET allows you to import a type library and generate an interop assembly. For Office, Microsoft already provides Primary Interop Assemblies (PIAs). A Primary Interop Assembly is a special interop assembly, signed by the published and labeled with the PrimaryInteropAssembly attribute. It is the "official" interop assembly for a specific type library. Office 2003 includes PIAs for its type libraries. The PIAs are installed during a complete installation of office. If you haven't installed them, see this page for installation instructions. You can also download the Office XP PIAs here.

To access Outlook objects, you'll need to reference the Outlook PIA. Unlike other assemblies, PIAs are added by referencing the underlying COM object, rather than by adding a direct reference to the assembly. In Delphi 2005, right-click on the References node in the Project Manager tree, and select the Add Reference menu item. This will open the Add Reference dialog box. Select the COM Imports tab, and locate the Microsoft Outlook object library. For Office 2003, the library's full name is "Microsoft Outlook 11 Object Library". Add the library to the
project's references. This will add a reference to Microsoft.Office.Interop.Outlook.dll, which is the PIA for Outlook.

In a C# project, this would be enough. Delphi 2005 appears to have a problem with locating PIAs, however. If you try to compile the application, you'll get an error because the compiler can't find the assembly. Even though the assembly is in the GAC, Delphi may not be able to find it when compiling the project. You'll need to add some paths to the project's search path. Right click the project name in the Project Manager and select the Options menu item. In the Project Options dialog, click on Directories/Conditionals.

You'll need to add a couple of items to the Search path field: First, add the location of the Outlook interop assembly. You can get the path for the assembly by selecting the reference in the Project Manager and examining the Full Path entry in the Object Inspector. On my computer, the Outlook PIA is located at C:\Windows\Assembly\GAC\microsoft.office.interop.outlook\11.0.0.0__71e9bce111e9429c.

If you try compiling now, Delphi will find the Outlook PIA, but will complain about not finding stdole.dll. You'll need to add a reference to stdole.dll's interop assembly. On my computer, this is located at C:\Windows\Assembly\GAC\stdole\7.0.3300.0__b03f5f7f11d50a3a.

Now that all references are set, you can start using Outlook objects in your code. Add "Microsoft.Office.Interop.Outlook" to your uses clause. You can now access Outlook's Application object by creating an instance of the ApplicationClass class. From there, you can access any Outlook object much like you could with COM. For example, the following code lists the name of all appointments in the user's default calendar folder:

var
  App: ApplicationClass;
  Cal: MAPIFolder;
  Appointment: AppointmentItem;
  i: Integer;
begin
  App := ApplicationClass.Create;
  Cal := App.GetNamespace('MAPI').GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
  for i := 1 to Cal.Items.Count do
  begin
    Appointment := AppointmentItem(Cal.Items[i]);
    if Assigned(Appointment) then
      ListBox1.Items.Add(Appointment.Subject);
  end;
end;

Little head, big headache
Tuesday, May 24, 2005 03:03 AM

Years ago, I worked on a pretty large failed project. There are many ways for a project to fail. Some never get delivered. Others are delivered, then discarded. These are obvious failures, and companies try their best to hide them.  This project failed in a slightly less obvious way, by being late, over budget, and buggy as hell. It's still an obvious failure, but since the project was actually delivered, management called it a success and blamed everybody else for any problems.

I was really inexperienced (at the time I had only worked as a professional programmer for just over a year), but because I was a pretty good coder, my boss made my technical lead for one of the trickier parts of the project. This basically meant I had full responsibility if anything went wrong, but absolutely no authority for making sure things worked. I took the job. I was an idiot.

My boss, you see, was an idiot too - and a much bigger one at that. He was also a jerk. An arrogant, rude man, he ignored the opinions and ideas of everyone else. Since he began his professional life as a programmer, he though he knew everything better than anybody. He set impossible schedules, accepted ridiculous feature requests, and dismissed the ideas of source control, configuration management, requirements management, and quality assurance as impractical and unnecessary. He made every possible mistake (kind of impressive, when you think about it). It was actually a valuable - if painful - learning experience. A few years later, as a project manager, I found that all I had to do for the project to be an incredible success was just the exact opposite of everything he did.

The reason I just remembered this fun period of my professional life (rated just above poking my eyes with a sharp stick) is that I just read Johanna Rothman's "Schedule Games" posts (via Coding Horror.) Johanna has great insights about project management, but I got to thinking about what to do when you're a developer stuck in such a project, or working for such a boss (I did mention he was - and still is, from what I hear - an idiot, didn't I?)

From my experience, if you identify yourself in such a situation, you have four options:

  1. Do as you're told. This is what's called in Hebrew "Rosh Katan" (little head). Basically, it means you do your work, avoid any responsibility, and try to find satisfaction elsewhere, since clearly you're not going to get any at work.
  2. Work until you're too depressed to live. If it still hurts, you're not there yet.
  3. Ignore your boss, do what you think is right, and hope he doesn't notice.
  4. Walk away.

The only option that really works is the last one. Trust me - I've tried options #2, #3, and #4, and know a lot of people who are still stuck in #1, #2, or #3. They have good reasons, such as families to support. And what's all this nonsense about job satisfaction? A lot of our parents spent their lives doing something they hated just so they can put food on the table.

But programming is different. Most, if not all, programmers love it. They'd write code even if they had other jobs. We're very lucky to be able to have jobs doing something we love, and we should make every effort to keep it that way.

Planners 2.0: Backward Compatibility
Thursday, March 17, 2005 11:10 AM

Well, Planners 2.0 is out, and although I didn't get much (or any) rest, the pressure is a little down. Even after the product has been signed off, there's a lot to be done: setting up order pages, uploading a trial version, registering the new version with some download sites, updating the product web pages, and so on.

As promised, I'll try and write a little about the process of building and releasing this version, in hope that this would help aspiring component developers prepare for what they're about to face. In this post, I'll focus on backward compatibility.

The three main aspects of backward compatibility, in any software product, are data, interface, and installation. The actual implications of these aspects depend on the type of product. In the case of a component library, these are:

  • Data - code built with a previous version should be compatible with the current version. It should compile, and produce the same results at run-time. While bug-fixes may change the result of some code, known workarounds should still work.
  • Interface - the programming interfaces should remain unmodified. Extensions to the interfaces, such as new components, methods, and properties, should follow the same design principles and models of the previous version.
  • Installation - the installation should be aware of the previous version, and take steps to prevent incompatibilities.

The difference between data and interface compatibility is obvious in applications: data compatibility means the ability to view and edit data produced by a previous version, and interface compatibility means the user interface is similar enough to the previous version's interface so users don't have to learn everything from scratch. For code libraries, the line is somewhat blurry.

Data Compatibility

Data compatibility in Planners 2.0 is implemented at the source code level: application source code written for Planners 1.0 should compile without errors with Planners 2.0.

The level of code compatibility often depends on the scope of the release. For example, when Borland releases a new version of Delphi, the expected compatibility is at the source code level: code written for one version of Delphi is expected to work with later versions. When Borland releases a patch, the expected compatibility is at the binary level: units compiled with a specific version of Delphi are expected to work with the patched version. Borland tries to avoid DCU-breaking changes in patches so that component vendors won't have to distribute multiple versions of their products with every Delphi patch. Unfortunately, this sort of compatibility is not always possible: Delphi 8 incorrectly relied on internal data in the .NET Framework. When Microsoft released Service Pack 1 for .NET 1.1, it broke Delphi 8, and Borland had to release a DCU-breaking update.

In fact, Planners 2.0 has already benefited from Borland's patch policy. The Delphi 2005 packages and units have been compiled with Delphi 2005 Update 1, but are compatible with both Update 2 and with Delphi 2005 without any patches.

In Planners 2.0, we support application source code level compatibility, and - with a couple of exceptions - source code compatibility. This means that any code written using Planners 1.0 and using public or published properties, events, and methods will compile unmodified with Planners 2.0. Application code will not break.

Technically speaking, Planners 2.0 does introduce two breaking changes at the source code level: two properties (AutoSizeRows and RowCount) have been made read-only. These properties should never have been made writable, and modifying them in application code would produce unexpected results. Inherited components should be able to modify these properties, so we've added a couple of protected methods for this purpose. While strictly speaking this is a breaking change, the fact is that there probably isn't any code out there modifying these properties. It just wouldn't work.

Interface Compatibility

While code compatibility can be preserved by not breaking existing code and by regression testing, interface compatibility is more of a design principle. When adding new components, properties, methods and events, we maintained interface compatibility by following several guidelines:

  • Naming conventions - new elements follow the naming conventions used in the previous version.
  • Element re-use - whenever possible, existing elements were used. For example, new components derive from the same base components included in the previous version.
  • Design consistency - use the same design principles as the previous version. For example, in Planners 1.0, all controls derive from a single base component, TSPBasePlanner, which implements common logic. Derived controls override certain methods to implement their own custom behavior, such as drawing. Printing support in Planners 2.0 was implemented by adding a new method, Print, to TSPBasePlanner, which calls protected methods of derived classes to do the actual drawing.
  • Extend, don't replace - whenever possible, new features were written as extensions to existing components, rather than creating new components.

Installation Compatibility

Maintaining installation compatibility is always tricky. Application installations can usually replace the previous version, but are expected to keep data and settings from the previous version. Development tools and libraries, on the other hand, are expected to support multiple versions on the same machine. Developers usually have to maintain code written using previous versions of the tool, so multiple versions have to leave peacefully side-by-side. There are restrictions, though. In the case of Delphi components, for example, two sets of components with the same name cannot be loaded by the IDE (or, in Delphi 2005, by an IDE personality) at the same time. There are two ways of handling this restriction:

  • A component package could rename all components with each version.
  • Registration of components from a previous version could be replaced with the new version.

The former method is almost never used, as it would break code compatibility. Planners 2.0 uses the latter method, by removing the Planners 1.0 packages from Delphi and C++Builder's list of packages, and registering the new packages instead.

The installation program has to take any conflicting version into account. There are currently four conflicting versions of Planners out there, and the installation program has to know about all of them. There's Planners 1.0, Planners 2.0, the Planners 1.0 trial, and the Planners 2.0 trial. The Planners 2.0 installer performs three steps when registering the components: first, it registers the new components; then it removes registrations for Planners 1.0 components; finally, when installing the full product, it removes the registration for the Planners 2.0 trial version.

At no point during the installation is any previous version of Planners removed. No files are deleted, and no directories are removed from the system and IDE's search paths. Planners 2.0 installs to a different directory than Planners 1.0, so no files are overwritten.

While the unit names for Planners 2.0 have to remain the same as the 1.0 unit names (again, code compatibility), the package names have changed. The Planners package names indicate both the product version and the version of the supported IDE. Here are a few names for the Planners design-time package:

  • DclSPPlan9020.bpl - Planners 2.0 on Delphi 2005.
  • DclSPPlan7020.bpl - Planners 2.0 on Delphi 7.
  • DclSPPlan7010.bpl - Planners 1.0 on Delphi 7.

... and so on.

An interesting problem was raised when determining names for the Planners assemblies. Planners supports VCL for .NET in addition to the VCL on Win32. While it's possible to use any file name for a .NET assembly, the common convention is to use names that are similar (if not identical) to the namespaces supported by the assembly. Further complications arose because of the need to support both Delphi 8 and Delphi 2005. Delphi's namespace model has changed in Delphi 2005: in Delphi 8, the namespace was identical to the unit name, while in Delphi 2005, the namespace is the full unit name minus the last identifier, separated by dots. The Delphi assemblies, such as Borland.Delphi.dll, have the same file name for both Delphi 8 and Delphi 2005, but are in fact different. We also had to maintain compatibility with the Delphi 8 assembly names in Planners 1.0.

The issue was resolved by using strong-named assemblies. Planners 2.0 includes three assembly files:

  • ShorterPath.Planners.Vcl.dll
  • ShorterPath.Planners.Vcl.Data.dll
  • ShorterPath.Planners.Vcl.Design.dll

There are, in fact, two versions of each assembly: one for Delphi 8 and one for Delphi 2005. Both versions have the same file name, but are strong-named, so they have a different assembly name. The assembly names for ShorterPath.Planners.Vcl.dll, for example, are:

ShorterPath.Planners.Vcl, Version=2.90.1.0, Culture=neutral, PublicKeyToken=235f6e5b184e6f81

and

ShorterPath.Planners.Vcl, Version=2.80.1.0, Culture=neutral, PublicKeyToken=235f6e5b184e6f81

The difference is in the assembly version. We used the major version number, as well as the release and build numbers, to indicate the version of Planners. The minor version number indicates the version of Delphi used by the assembly. Another advantage of strong-naming our assemblies is the ability to install them into the Global Assembly Cache.

We took similar measures with the Planners help files. The Planners 2.0 help files have a different name than the Planners 1.0 help files. The installation program installs the new help files but does not remove the old help files. Another feature we added to the installer was the ability to select which versions of the Planners packages and help files are installed. We've even added an option to completely skip automatic registration of components and help files, allowing users to manually register only the items they want.

More to come

I'll be writing more about the issues we faced with this release and the solutions we chose. If you want to know more about the process, or have specific questions, leave a comment here (comments can only be added by viewing this page in a browser).

Upgraded
Monday, March 14, 2005 01:07 PM

Planners for VCL 2.0 is now available. Tons of new features have been included. Check it out.

I'll write more about the process after I get some rest.

Upgrades
Saturday, February 19, 2005 09:31 AM

Releasing an upgrade is very different from releasing a 1.0 product. When planning the next version, I've encountered many issues I've been able to avoid in the first release. Some of them are totally new issues, while others could have been foreseen, and would have been better off handled even before the first version. Some are relevant to any shrink-wrapped product, while others are only relevant to libraries. If you're a developer considering releasing a commercial library, you may benefit from this post. If you're a Planners customer waiting for a new version, this post will expose some of the issues we're dealing with. Don't worry, though - we will release a new version, Real Soon Now. Read more...

Even better than the real thing
Tuesday, February 01, 2005 04:06 PM

I have a confession - I've never seen "Titanic." It's not really my kind of film, plus I'm allergic to Leonardo DiCaprio. But this version was excellent: Titanic, in 30 seconds, and re-enacted by bunnies.

 

Copyright 2004 Yorai Aminov