Historical Documents: Delphi 1 launch demos source code, launch script, and marketing video

By: John Kaster

Abstract: Anders Hejlsberg provided the original launch script and projects used in the Delphi 1 launch on February 14, 1995.

A few weeks before February 14th, 2005, we emailed Anders Hejslberg to arrange an interview for Delphi's 10th Anniversary on February 14th, 2005. One of his replies was an email with some historic attachments. Here's the email:


Hi Guys,

Imagine that, 10 years. I still remember the Valentine's Day launch in San Francisco. It was an awesome moment. You don't get a standing ovation from several thousand people every day--boy, did that feel great.

Over the years several Microsoft folks that attended the launch have told me how they were constantly hearing oohs and aahs from people around them, and how they were completely floored when I forced a GP fault in the demo, but the app kept running. Good stuff!

I found the script and all the demo files I used in my launch talk. They are all in the attached .zip file. The Athena bust shown in the little "speed is" clip now sits in my home office.

Anders


He attached two zip files to the email:

    It's in the script!

Here is the text version of the demo script in HTML. You can also download the original Word Document from CodeCentral.

    Code Sync / Two-Way Tool

Delphi is a "two-way" tool. When you do things visually, Delphi automatically keeps your code in sync. You can switch between code and visual editing at any time. Let's start a blank project.

  File|New Project.
  Resize form to be above editor.
  Delete private/public sections and comments.

First, let me explain that in Delphi, for every form there's an associated module, or unit, that contains the form's code. You can of course have code modules without forms. In a form's code module, there's a class declaration for the form. As you can see, forms you create are actually subclasses of a generic form. Now, as I drop components onto the form, they show up as instance variables in my class declaration.

  Drop TButton, TButton, TEdit, TCheckBox.

And when I rename them, the code is kept in sync.

  Rename to OkButton, CancelButton, FirstName, UpToDate.

If I double-click on a button, the system automatically adds a member function to my class.

  Double-click on first button.
  Add "Caption := 'Hello';"

When I scroll back, you can see header in the class declaration.

  Zoom.
  Scroll back to class declaration.

Now, what's really important is that Delphi isn't just a one-shot code generator with "__\\ don't delete me" kinds of comments. Instead, Delphi is actually constantly analyzing your code as you work with it, so that it knows where to make its surgical incisions. And any changes you make to the code, Delphi automatically recognizes. For example

  Select OkButton.
  Go to events page in object inspector.
  Drop down event list for OnClick.

Here you see that the only available event handler for OnClick is the OkButtonClick method we just wrote. Now, if I go to the editor and add

  procedure HelloWorld(Sender: TObject);

And drop the list down again, you'll see that Delphi picked up on it. But if I change the declaration to take an extra parameter

  procedure HelloWorld(S: string; Sender: TObject);

it disappears because it is no longer compatible with the OnClick event.

But Delphi doesn't just understand your code. It can also convert objects to code. For example, let's select the OkButton, and cut it to the clipboard.

  Select OkButton.
  Shift-Del.

And now, let's paste it in the editor.

  Select editor.
  Scroll to end.
  Shift-Ins

Here you see a textual representation of the button and its properties. Now let's change it around a bit.

  Change "OkButton: TButton" to "OkButton: TRadioButton"
  Add
    Font.Name = 'Arial'
    Font.Size = 14
    Font.Color = clRed
  Change
    Caption = 'Hello'

Now let's move it back into the form

  Select object...end
  Shift-Del
  Select form
  Shift-Ins

There's our button, which is now a radio button with a different font. And if we look at the code, we'll see that the class declaration has been updated to reflect the new type of the button.

  Select editor.
  Scroll to form class declaration.

All of this code sync is managed by a highly fault-tolerant background compiler that can analyze code even if it isn't syntactically correct. For example, if I add some garbage characters

  Add '*&*&^*&^*&^' just above type declaration.

You'll see that I get a syntax error if I try to run.

  F9

But the background compiler can still analyze the code.

  Drop new button.
  Notice class declaration is updated.
  Delete button again.

The two-way tool and code sync features of Delphi are important because.

  • You're never playing the "where's the code" game that other tools suffer from, because all your code is in one module, not in little boxes.
  • Your code doesn't have to be syntactically correct until you run the application. Other tools force you to correct your code before you can leave a code box.
  • You can leave the Delphi environment and take your code with you, so to speak. For example, some programmers may have a favorite editor that they want to use when doing big editing sessions.
  • Everything you do visually can be represented as text. For team development this is an invaluable feature because you can do source code merges even on your form files.

    Exception Handling

The next thing I wanted to talk about is exception handling. Even though this is not a visual feature, it is probably one of the most important aspects of Delphi, particularly when it comes to writing database and C/S apps.

For those of you who aren't familiar with exceptions, they are the structured and object-oriented equivalent of ON ERROR GOTO found in some languages.

But exceptions go way further than that.

And Delphi was engineered from the ground up with exception handling built in.

Whenever something goes wrong in an app, an exception is raised. As a result of an exception, components automatically clean themselves up, and back out of whatever operation failed.

This all happens without any programmer intervention.

As a result, Delphi apps automatically have error detection and correction built-in, without you having to worry about it.

I'm sure you've heard something like this before: "Yeah, this app is great, but boy when something goes wrong you get GP faults all over the place".

Well not with Delphi.

In fact, speaking of GP faults, let me show you what happens in Delphi.

  File|New Project
  Drop button on form.
  Double-click button.

Add code:

  procedure TForm1.Button1Click(Sender: TObject);
  var
    P: ^Byte;
  begin
    P := nil;
    P^ := 0;
  end;

And let's run.

  F9
  Click button.

As you can see, a GP fault occurred, and Delphi's default exception handler caught it and is showing an error dialog.

But notice that the app is still running.

  Click button again.
  Close app.

Delphi has a bunch of built-in exception classes, and you can also create your own. And you can write exception handlers. For example:

Modify code to read:

  procedure TForm1.Button1Click(Sender: TObject);
  var
    P: ^Byte;
  begin
    try
      P := nil;
      P^ := 0;
    except
      on EGPFault do Caption := 'I say, that pointer is a little off!';
    end;
  end;

As in C++, Delphi exceptions are classes. Let me show you the hierarchy.

  View|Browser.

As you can see, the hierarchy is:

  Exception
  EProcessorException
  EFault
  EGPFault

I could change my handler to handle EFault, in which case I would also catch stack faults, etc.

    Creating a New Component

Here I'll show how to create a new component.

  Start Delphi.
  File|Close project.
  File|New component.
  Class name: TRunButton.
  Ancestor type: TSpeedButton.
  Press OK.
  Press F5.

This automatically generates a module that implements the new class. The comments indicate where we can implement private, protected, public, and public fields. The call to the Register procedure registers the component. First we'll add a new field, FCommand, which holds the command we want executed when the button is pressed.

  Private "FCommand: string;"

Next, we'll add a property.

  Published "property Command: string read FCommand write FCommand;"

The property is in the published section so that run-time type information is automatically generated for it. In the property declaration we specify that to read it we'll get the value of the FCommand field, and to write it we'll set the value of the FCommand field. We could have used member functions here, to associate actions with reading and writing the property. Or we could have made the property read only or write only by only having a read or a write clause.

Next we'll override the button's Click method.

  Public "procedure Click; override;"  <--->

And we'll implement the method.

In implementation section add:

  procedure TRunButton.Click;
  var
    Buffer: array[0..255] of Char;
  begin
    WinExec(StrPCopy(Buffer, FCommand), SW_SHOW);
  end;

We're calling the "WinExec" function in the Windows API. All Windows API functions are directly accessible in Delphi. You don't have to first come up with a declaration that specifies parameters, DLL names, and so on.

And that's it! We now have a functional component.

  File|Save File As...
  File name: "runbtns"

And let's install it into Delphi.

  Options|Install Components...
  Add.
  Browse.
  File name: "runbtns"
  OK

Now if we go to the Samples page, there's our new component. Notice that it inherited the icon of its ancestor class. Let's test it out.

  File|New Project
  Drop a TRunButton on the form.
  Make it bigger.
  Load a glyph (MSDOS.BMP).
  Set Command property to "c:\command.com"
  Run

And now, when we click, here's a DOS box.

Now let me show you a little project I built using the TRunButton class.

  File|Open Project...
  LAUNCHER.DPR

This form has eight TRunButtons on it, which launch apps that I use a lot. Let me try and run it.

  F9

As you can see, it stays on top of all other windows. And we have little fly-by hints that explain the icons.

  Launch various apps
  Joke about EDLIN
  Click on Delphi button to get back

Now the neat thing about this app is that there's no code in it.

Zoom editor window to show no code.

It was built entirely by tweaking properties and using the TRunButton component we just put together. As you might imagine, this'll help us get a 32-bit version of Dashboard ready real soon!

    Dynamic Component Creation / Delegation

One of the truly powerful features of Delphi is that everything you can do visually you can also do in code. This means that you can dynamically create forms and controls. For example, I have a little database browser app here:

  File|Open Project...
  DBBROWSE.DPR

Let's run it.

  F9

The browser allows me to pick tables in a database and view and modify them.

  Close the app.
  Zoom the editor.

As you can see, this app only has about five lines of code.

Now, let's say I want to dynamically create data entry form for the table I'm looking at. I obviously don't know what's in the table, so I'll have to create the entry form on the fly. So let me add some code to do it.

First, I'll declare a private instance variable called EntryForm.

In TTableForm class declaration add:

  private
    EntryForm: TForm;

Next, I'll change the TableNameClick method which gets executed when the user picks a new table.

Modify TTableForm.TableNameClick method:

  procedure TTableForm.TableNameClick(Sender: TObject);
>>>
  var
    I: Integer;
<<<
  begin
>>>
    EntryForm.Free;
<<<
    Table.Close;
    Table.TableName := TableName.Text;
    Table.Open;
>>>
    EntryForm := TForm.Create(Self);
    EntryForm.Font := Font;
    EntryForm.Caption := Table.TableName;
    for I := 0 to Table.FieldCount - 1 do
    begin
      with TLabel.Create(EntryForm) do
      begin
        Parent := EntryForm;
        Caption := Table.Fields[I].FieldName;
        Alignment := taRightJustify;
        SetBounds(0, I * 25 + 11, 80, 20);
      end;
      with TDBEdit.Create(EntryForm) do
      begin
        Parent := EntryForm;
        DataSource := TableForm.DataSource;
        DataField := Table.Fields[I].FieldName;
        SetBounds(88, I * 25 + 8, Table.Fields[I].DisplayWidth * 7, 20);
      end;
    end;
    EntryForm.Height := Table.FieldCount * 25 + 40;
    EntryForm.Show;
<<<
  end;

Now, let's run.

  F9

And when I pick a table, a dynamic entry form shows up.

  Pick COUNTRY.DB
  Pick ITEMS.DB
  Pick PARTS.DB
  Pick CUSTOMER.DB

Now, one thing you'll note is that the two forms are synchronized because the data aware controls refer to the same data source.

  Scroll up and down.
  Notice both forms changing.

Even if I insert a new record

  Click on grid.
  Press Ins key.

they both show the same data.

  Type in grid.
  Notice entry form shows the data.
  Type in entry form.
  Notice grid shows the data.

    Delphi in Delphi

more...

    Conclusion

Our sincere thanks to Anders Hejlsberg for his generosity and the organizational skills that made it possible for him to find this launch material 10 years later!

Server Response from: ETNASC04