views:

794

answers:

6

I have a class in a unit. Usually, when I changed the algorithm of its methods, I have to recompile it and deliver the patch as a whole. I think to create the instance of the class using DLL. After searching in delphi.about.com, I found that instead of using DLL, I can use BPL. It is a DLL for Delphi. The problem is almost all examples I found is only telling how to export a function. I want to dynamically load the BPL, and whenever I replace the BPL, I can get the latest algorithm of the class, not only the functions I export.

Article I have read:
- http://delphi.about.com/od/objectpascalide/a/bpl%5Fvs%5Fdll.htm
- http://stackoverflow.com/questions/1192734/plugins-system-for-delphi-application-bpl-vs-dll
- http://delphi.about.com/library/weekly/aa012301a.htm

Any URL or SAMPLE how to create a BPL from scratch to encapsulate a component or a class is greatly appreciated.


Dear Guru,

Suppose I have code like this:

unit unitA;

interface

type
  B = class(TObject)
  public
    procedure HelloB;
  end;

  A = class(TObject)
  public
    function GetB: B;
    function HelloA: String;
    procedure Help;
  end;

  implementation

  uses
      Dialogs;

  { B }

   procedure B.HelloB;
   begin
     ShowMessage('B');
   end;

  { A }

  function A.GetB: B;
  begin
    Result := B.Create;
  end;

  function A.HelloA: String;
  begin
    Result := 'Hello, this is A';
  end;

  procedure A.Help;
  begin
    //do something
  end;

  end.

I want to export all public methods of A. How to make it a DLL? How to use it from another unit where to import it? let's say:

 var a: A;

 a := A.Create;
 a.GetB;
 showMessage(a.HelloA);

A is not declared in the unit (it is in the DLL). Please advise.


Hurray. I got it last night. All I have to do is make the object implement an interface which is used in the caller unit to catch the instance of object returned by the DLL.

Thank you all.

A: 

Delphi can create DLL to export functions or BPL to export component.

You can create component, compile it (use the same compiler settings as in your main app), and Delphi will create .bpl. Then import this component to Delphi and compile your app with this compomponent as a package.

My experience with components created with Delphi 4 proved that one, big application is more reliable than application with separate .bpls. It was multithreaded server and it worked fine if compiled standalone, while crashed after short time if compiled with packages. I hope newer versions of Delphi improved in this area.

Be aware of memory management (in app do not free memeory allocated in package and vice versa) and compiler settings.

If you like about.com then this link will be useful: Introduction to Packages; BPLs are special DLLs!

Michał Niklas
If you play be the rules and use the same memory manager for application and BPLs it should not be a problem to free memory in a different module than where it was allocated. If you didn't play by these rules I'm not surprised you found your monolithic app to be more stable. Your experience doesn't *prove* anything about lack of reliability, though. For that you would have to prove you did not make any mistake, first.
mghie
I know about memory management and warned component creators/users to use the same memory managers and the same compiler options in both components and apps. In my case I used the same memory manager. BPL worked fine in single threaded apps, but I found mysterious crashes with multithreaded apps. They appeared after some time (sometimes after 15 minutes, sometimes after an hour). They disappeared when I compiled my server app without packages. This was time of Delphi 4 so now it is prehistoric.
Michał Niklas
+2  A: 

The problem with putting a class in an external file is that your main application needs to know some way to refer to it. It will either have to descend from a base class that exposes all the methods you need as virtual methods, or implement an interface that contains all the functionality you need from it.

If you already know what the interface of the object should look like, and all you're changing is implementation details such as internal algorithms, probably the easiest thing would be to make your class implement an interface and put it in a DLL that exports a function that returns an instance of this interface. That way you don't need to worry about breaking your app up into packages, which can be a real hassle.

Mason Wheeler
Ok.. I still have to read about DLL. I thought DLL is only encapsulate procedural / functions only, not object. I don't know that it can return a descendant of TObject or instance of interface. Yes in my case right now, the interface will never be changed. Actually it is a calculator with many functions. I started with small amount of functions, and now it'g getting more and more functionality. It just called Evaluate(expression: String) and return the result in String. When the expression is getting richer, I don't want to replace the exe, but I just want to replace the Calculator class. Tq
WishKnew
A: 

BPLs have their usage. For example if you have to make a very huge application like an Erp, you need to try to use BPLs seriously.

In the other hand, BPLs aren't responsible of crashing applications. Bad usage of BPLs does it.

Francis Lee
BPLs introduce the worst kind of versioning hell ever. You are dependent not only on your compiler and RTL/VCL version, nope, also on the version of every DCU in all shared packages as well. For this kind of shared code usage, you are referring to, DLLs, which share objects via interfaces) is the most stable, interoperable (no need to write a DLL in Delphi, could be C#, C++, FPC, etc) and painless path, besides monolithic exes.
Robert Giesecke
You are right Robert, I'll vote for it.
Francis Lee
+1  A: 

I see nothing in your problem description suggesting you would need to explicitly export anything from the package or that you would need to load it dynamically at run time. Instead, it's enough that your functions reside in a run-time package that can be replaced separately from the main program.

Start a new package project and move your class's unit into that project along with any other units it depends on. Compile the project. If the compiler warns about "implicitly including" any other units, add those to the package, too.

Now, remove any of the package units from the EXE project. There should be no units that are members of both projects. Next, turn on the "build with run-time packages" checkbox in your EXE's project options. Add your package to the semicolon-separated list of package names. The RTL and VCL packages will probably also be on that list.

Compile both projects, and you're done.

If you make changes to your class implementation, you can recompile the package only and send a new version to customers. The program will automatically get the new changes when you replace the original file with the new one. The package is listed in the program's import table, so the OS will automatically load the BPL file when it loads the EXE. The EXE doesn't need to run any special code to load the package.

Rob Kennedy
Ok, I'll try both BPL and DLL. Thank you!
WishKnew
+4  A: 

Mason nailed it already, but let me elaborate on why BPLs aren't what you are looking for. BPLs are a means for the Delphi IDE to load components that share the same memory manager and RTL. (Type identity works almost transparently using BPLs)

However, the dependencies you are getting tied up in are almost always unacceptable. Except for the IDE, which cannot handle different versions of RTL and VCL anyway.

When you pass only interface references between your application and its DLLs, then you don't have to share RTL, VCL or shared packages at all.

It also means that you could write some DLLs in another language (C++, C#, FPC, another Delphi version), and still use objects. Which can be tempting when you don't want to port your main app but still want to use existing libraries that are not available for Delphi, or your version of Delphi.

Robert Giesecke
Ok, now I'm bold to pursue how to do it using DLL. Tq. But how about COM? Do you have any comments how to solve the problem using COM approach?
WishKnew
COM is an entirely different animal, and even though COM via Delphi is greatly simplified, it still is massively beyond the scope of a stackoverflow thread.
Robert Giesecke
A: 

you can try the MAF Components, they handle plugins and much more for you without extra code. Comes with tutorials and a demo application with source.

http://www.maf-components.com

Helge Lange
Sorry, I'm looking for a native solution, without involving any other paid solution. Thank you anyway.
WishKnew