|
Delphi 8 for .NET Assemblies; Packages and Libraries 以下内容转自:http://www.drbob42.com/examines/examin55.htm In this article, Bob Swart will explain what .NET Assemblies are, how we can use them in Delphi 8 for .NET applications, and especially how we can make them ourselves (it actually turns out that there is more than one way, and even some special way to use some of them in Win32 applications).
DLLs and .NET Assemblies The world of Windows application development introduced the DLL - Dynamic Link Library. A DLL can contain a number of functions that can be called from an application that loads the DLL (statically or dynamically). The Windows API consists mainly of DLLs. These DLLs were written in C or C++, and came with a header file that described the interface of the DLL. For Pascal and Delphi developers, it was not easy to use the DLL if you didn't have a DLL import unit. And back in 1989 I released HeadConv - my first C DLL Header Converter, which is now available as free tool under management of the Delphi-Jedi DARTH project. The Delphi Jedi project itself was founded to produce Delphi import units for C DLL header files - a tedious job, but well appreciated by all Delphi developers who ever needed to use a C DLL header file. Why am I telling you this? Because the world has changed. The .NET Framework is taking over the Windows world, and the DLL is being replaced by a new kind of library, called the .NET Assembly. .NET Assemblies are more powerful than DLLs in a number of ways. First of all, where a DLL can only export functions (and not classes), the .NET Assembly can define classes that can be used and extended by other .NET Assemblies or applications. Another significant benefit is the fact that the .NET Framework is language neutral. As a consequence, a .NET Assembly written in language X can be used by any language, including Delphi 8 for .NET. No more C DLL header conversions ever!
Add References For a Delphi 8 for .NET application to use an assembly, all we need to do is add a reference to the assembly. And this is as easy as it sounds: you can either use the Project | Add Reference dialog, or use the Project Manager and right-click on the project node and select Add Reference. In both cases, you get a dialog that will help you to select a specific .NET Assembly and add it to your project.
The same dialog can also be used to add references to COM Objects and ActiveX to your project, using the COM Interop tab.
Delphi 8 for .NET Assemblies Using Delphi 8 for .NET, we can create our own assemblies as well. However, at first you may wonder how to start, since the Delphi 8 for .NET Object Repository actually contains two different project types that will both result in a .NET Assembly: the Library, and the Package.
Both solutions will work (although in general one is preferred over the other), but you may need a little additional information about their use and deployment specifics.
Package or Library? Let me tell you on beforehand that the recommendation from Borland is to use a Package when you're planning to write a .NET Assembly with Delphi 8 for .NET. However, because the Delphi 8 for .NET helpfiles contain information about packages and libraries, this isn't made very clear in the helpfile to be honest. And as a result, I've been using both a package and a library project to build my Delphi 8 for .NET Assemblies, with mixed results. So just to let you know the inside store and to explain how and why, I'll use both ways and show the details.
Library Let's start with the Library Assembly. Use the dialog of Figure 2 to create a new Library project. This will lead to the following Library1 project in the Project Manager:
As you can see, this is a Library project with a reference node that has no references added to it as this time. You can add functionality to this Library project by adding a unit to it. As example unit for this article, I want to use the following unit that defined a class TRandomNumber that we can "export" from the .NET Assembly: unit Hardcore.Delphi.Final.Issue;
interface
type
TRandomNumber = class
constructor Create;
function Random10: Integer; virtual;
end;
implementation
constructor TRandomNumber.Create;
begin
inherited;
Randomize
end;
function TRandomNumber.Random10: Integer;
begin
Result := Random(10)
end;
end.
It's only a very simple example, but it will be good enough to demonstrate the way in which we can build and use the two different .NET Assembly types with Delphi 8 for .NET. For the Library Assembly, right-click on the project node and do Add, which offers a dialog in which you can select the Hardcore.Delphi.Final.Issue.pas unit. Now, compile the project, resulting in a Library1.dll of 1.3 MBytes. Wow! How come? Well, take a look at the Library source code in Library1.dpr and you'll see the following uses clause: uses
SysUtils,
Classes,
System.Reflection,
Hardcore.Delphi.Final.Issue in 'Hardcore.Delphi.Final.Issue.pas';
I don't why SysUtils and Classes are automatically added to the uses clause, but it causes almost the entire VCL for .NET to be linked in with the DLL Assembly. So, to make it a bit smaller, remove the SysUtils and Classes units from the uses clause and recompile the Library1 project. This time the result is a 94 KByte Project1.dll. That's more like it. Note that the Library project still doesn't have any references added to it in the Project Manager. This means that the Project1.dll Assembly doesn't depend on any other .NET Assemblies, apart from mscorlib and System, which are always present. You can use this Library assembly with any development environment like Visual Studio.NET, C#Builder, etc. with one exception: you can't add the Project1.dll Assembly to a Delphi 8 for .NET application. Again, you read it right: the Project Assembly that we just made with Delphi 8 for .NET cannot be loaded in any other project we make with Delphi 8 for .NET. The reason is simple, but surprising. The fact that the Library project contained no external references, resulted in the fact that the Borland.Delphi.System unit was linked into it. And adding this Library Assembly to another Delphi 8 for .NET project, which also contains the Borland.Delphi.System unit, leads to a Fatal Error message that says that it could not import assembly 'Library1' because it contains namespace 'Borland.Delphi.System' (which is also included in the new project itself). According to Danny Thorpe, the main issue is process-wide global data defined in the system unit.
In order to solve this problem, you need to reload the Library Assembly project in the IDE, and right-click on the Library1 project node to add a reference to the Borland.System.dll. This way, the Library Assembly will still use the Borland.Delphi.System unit, but from an external assembly reference. Like a run-time package. And this time, the Library1.dll will even be 6.5 KBytes big! Now when you add the Library1.dll Assembly to a Delphi 8 for .NET project, it will compile just fine, since both the Library1.dll assembly and the Delphi 8 for .NET project will refer to the same external Borland.System.dll. Of course, there's one little issue: in order to deploy the Library1.dll now, you also need to deploy the Borland.System.dll, where previously you could get away with only deploying the Library1.dll (in order to use it in Visual Studio.NET or C#Builder for example). One final remark: the Delphi 8 for .NET IDE is a bit sensitive when it comes to building or importing assemblies, and seems to lock them and keep a lock on them, so you can't rebuild an assembly before you close down and restart the IDE, and you cannot re-import an assembly correctly either. This problem will most likely be fixed in the upcoming second patch of Delphi 8 for .NET, but until that time you may want to restart the IDE before you start another project anyway.
Package OK, so far for the Library Assembly. Let's now see what the Package Assembly offers us. As soon as you select the New Package option, you get a different view in the Project Manager, as shown in Figure 4 (compared to Figure 3).
A Delphi 8 for .NET package automatically gets the Borland.Delphi.dll assembly added to the Requires list, so we won't get any problems with duplicate Borland.Delphi.System namespaces if we want to use it in a Delphi 8 for .NET project later. And we can add units to the Contains node, like the Hardcore.Delphi.Final.Issue unit with our TRandomNumber class. Compiling the package will lead to a Package1.dll Assembly of 6.5 KBytes big. Hmm, I've seen that number before. That's exactly the same size we ended with when building the Library1.dll assembly - only took it three steps to get it right. The Package1.dll assembly can be used in any development environment, including Delphi 8 for .NET, but it has the slight disadvantage that you need to deploy all required units together with the assembly. In this case, that's only [1] [2] [3] 下一页
|