Delphi Clinic C++Builder Gate Training & Consultancy Delphi Notes Weblog Dr.Bob's Webshop
Dr.Bob's Delphi Notes Dr.Bob's Delphi Clinics Dr.Bob's Delphi Courseware Manuals
 Dr.Bob Examines... #37
See Also: other Dr.Bob Examines columns or Delphi articles

An earlier version of this article originally appeared in Hardcore Delphi (November 2002). Copyright Pinnacle Publishing, Inc. All rights reserved.

Delphi COM in .NET
In this latest article about Delphi and COM, we'll make the final move to .NET, and see if and how we can take our COM knowledge (and more important objects) with us to the .NET world.

Note: for this article, you again need the .NET Framework and SDK installed, as well as the Delphi for .NET preview command-line compiler which ships as separate CD in the box with Delphi 7 Studio.

Legacy COM Objects
Last time, I showed how we can use new .NET assemblies with Delphi 7 by importing them as COM Objects. However, the reverse situation will occur more often: a legacy COM object that has to be used ini a .NET environment (often simply because there is no time or money to rewrite the COM object as a .NET assembly). So, the purpose of this article is to demonstrate how we can use legacy COM objects in .NET. Remember, however, that even if we succeed, the result will be good for a temporary solution only, since COM objects are treated as unsafe and unmanaged code - in other words: not true safe, managed .NET code.

Delphi 7 COM Object
If you don't have a legacy COM object, then we can simply build one using Delphi 7 (just for demonstration purposes - it will also work with more complex COM objects). The steps to build a "legacy" COM object as follows - for more details see the April 2002 issue of Delphi Developer:

After this, you'll end up in the Type Library Editor for the IeBob42 interface. Add a new method called Unmanaged (just a name to illustrate that we'll be calling a method from an unmanaged COM object). Go to the Parameters tab of the Type Library Editor, clear the result type (to turn it into a procedure), and add a parameter called Message of type BSTR and [in]. Now click on the Refresh Implementation button and write the a single line of code for the Unmanaged method.

  unit eBob42;
    Windows, ActiveX, Classes, ComObj, D7Win32COM_TLB, StdVcl;

    TeBob42 = class(TTypedComObject, IeBob42)
      procedure Unmanaged(const Message: WideString); stdcall;

    ComServ, Dialogs;

  procedure TeBob42.Unmanaged(const Message: WideString);

      TeBob42, Class_eBob42, ciMultiInstance, tmApartment);
Save this unit in eBob42.pas and compile the D7Win32COM project. Now, we can register the COM object fro inside the Delphi 7 IDE with Run | Register ActiveX Server (or you can do it from the command-line using regsvr32 or Borland's TRegSvr).

Delphi for .NET
Once we have a D7Win32COM.dll with a IeBob42 interface and TeBob42 class, we can execute a first attempt to use this unsafe, unmanaged COM object from within the safe, managed .NET managed environment. The Delphi for .NET preview command-line compiler will be our test development environment.
First of all, we need to import the D7Win32COM.dll with tlbimp (the Microsoft .NET Framework Type Library to Assembly Converter). Tlbimp converts a COM object from an executable or DLL, or even a type library .TLB file, and generates a so-called Runtime-Callable Wrapper (also called RCW). The RCW is a managed wrapper around the unmanaged COM object, and allows the managed .NET code to make calls to the unmanaged COM object (where the RCW is acting as a proxy in between the two).
Since I want to put the resulting assembly in the GAC (Global Assembly Cache) later, I should start by making a strong key with the sn tool (the Microsoft .NET Framework Strong Name Utility) as follows:

  sn -k eBob42.snk
After the strong key has been generated in eBob42.snk, we can call tlbimp and allow it to work on our unsafe D7Win32COM.dll, using the eBob42.snk keyfile, and generating a .NET import unit eBob42.dll (note that the following must be executed on one long command line):
  tlbimp D7Win32COM.dll /keyfile:eBob42.snk /out:eBob42.dll
The eBob42.dll is now the RCW .NET assembly that imports the interface of the D7Win32COM.dll, and will act as the proxy to this interface. Since we used a Strong Key from eBob42.snk, we can now place the eBob42.dll assembly in the Global Assembly Cache (GAC), in two steps: first register the assembly using regasm, and then place it in the GAC using gacutil:
  regasm eBob42.dll
  gacutil -i eBob42.dll
The advantage of using the Global Assembly Cache (GAC) is that the eBob42.dll no longer has to be placed in the same directory as the client executable (and we can even have multiple versions of the same assembly installed on our system, but that's a topic for another day).
The Delphi for .NET preview command-line compiler can use (read: link) .NET assemblies by adding the -LU compiler command-line switch. In the current example, the call would be as follows:
  dccil -LUeBob42
Never mind the fact that I didn't include a project .dpr file to compile as well, because the compiler won't get that far: it starts to complain right away that it can't find the eBob42 package (instead of assembly). Although we've registered the eBob42 assembly and placed it in the GAC (so our client .NET executables can find it), the command-line compiler can't find it. Not even if it's in the current (and same) directory. The only workaround to make the Delphi for .NET preview command-line compiler happy is by copying the eBob42.dll into the C:\WinNT\Microsoft.NET\Framework\v1.0.3705\ directory (the same directory that holds the mscorlib.dll among others). After the eBob42.dll assembly is copied to that location, the -LU compiler flag can find it without problems.
But this leaves a little Delphi for .NET client application to actually use the (unsafe) COM object. A short example to illustrate that use - but nothing more - can be seen in Listing 2.
  program DotNet;
    Q: eBob42.eBob42Class;
    Q := eBob42.eBob42Class.Create;
      Q.Unmanaged('Hello from Delphi for .NET')
Note that I'm using the explicit namespace eBob42 here as prefix for the eBob42Class type name. Talking about the eBob42Class type name, you may wonder where this came from, since we started (in Listing 1) with the eBob42 CoClass Name resulting in the IeBob42 interface name and TeBob42 class name - in Delphi 7 for Win32. However, the tlbimp type library importer automatically generates the eBob42Class class name - something we as Delphi developers have to get used to, just as we have to get used to not using the T-prefix for class names in the .NET world.

Compiling the DotNet.dpr project from Listing 2 with the Delphi for .NET preview command-line compiler will now succeed with the following command:

  dccil -LUeBob42 DotNet.dpr
Assuming you've followed the steps in this article, the result will be a DotNet.exe that can be run to demonstrate that this safe, managed .NET code will go through the Runtime-Callable Wrapper proxy eBob42.dll and call the unsafe, unmanaged COM object inside D7Win32COM.dll. The result is the following dialog, which is the result of the unsafe, unmanaged code:

Delphi 7 COM Object used by Delphi for .NET

And while this screenshot proves that we can indeed use COM objects through a RCW proxy in a .NET environment, you should never forget that this undermines the safe, managed nature of .NET (since the COM object is unsafe and unmanaged), so should only be used when you have to use legacy COM objects today - until you have the time and/or money to rewrite them as truly safe managed .NET assemblies.

With this article and the previous one, we can now import COM objects in .NET, and import .NET assemblies as COM objects in the Win32 world. Almost like being in the Twilight Zone. From now on, I will mainly operate in the .NET world, and hope you'll join me.

Delphi and .NET
This ends my coverage of Delphi and the combination of COM and/in .NET. In the next few articles I will explore the capabilities of Delphi for .NET, using the preview command-line compiler to build console, visual we well as web server and web service applications, joining forces with ASP.NET when needed for the web examples. If you want to make the move with Delphi to .NET, then stay with me and be sure to get back to this website! So stay tuned, and don't hesitate to send me feedback or comments (or suggestions for topics to cover using Delphi for .NET).

This webpage © 2003-2010 by Bob Swart (aka Dr.Bob - All Rights Reserved.