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_vs_dll.htm
- 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.
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.
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.
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.
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!
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.
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
Related
When you compile a DLL in Delphi XE6, it automatically exports the function TMethodImplementationIntercept from System.Rtti.pas. I tried to find a way to avoid this export but didn't find any configuration or compiler directive that could do the trick.
The System.Rtti unit is nearly impossible to avoid because it's used indirectly by almost everything in delphi.
Is there a way to avoid exporting this function when building a DLL in XE6?
The code in the System.Rtti unit looks like this:
{ This function has been added to be used from .s .c files in order to avoid use mangled names}
procedure TMethodImplementationIntercept(const obj:TMethodImplementation; AFrame: Pointer); cdecl;
begin
obj.Intercept(AFrame);
end;
exports TMethodImplementationIntercept;
This function and the exports directive, were added in XE5.
Is there a way to avoid exporting this function when building a DLL in XE6?
If your library includes the System.Rtti unit then the DLL will export that function. If you want to produce a DLL that does not export the function I can see the following options:
Use an older version of Delphi.
Don't include System.Rtti in your library.
Use a modified version of System.Rtti that does not export the function.
Modify the DLL after it has been produced to remove the function from the PE export table.
The first two options seem to me to be not very appealing. The third option seems attractive but I think it might turn out to be difficult to make work. It seems that this long standing trick no longer works. I've not yet been able to re-compile an RTL unit and avoid the dreaded X was compiled with a different version of Y error.
So that leaves the final option. Again, not massively attractive. You may well decide to just suck it up and accept this stray export. Perhaps a QC report might put a little pressure on Embarcadero to reconsider this decision.
For what it is worth, in my opinion no compiler library code should ever unconditionally export a function. It should be the consumer of the library rather than the implementer of the library that takes that decision.
I have project group in Delphi XE2 which function is to load plugins from packages. I created these projects:
PluginInterface.bpl – package with interfaces to plugins and to MainForm
UClassManager.pas – plugins manager
UPlugin.pas – plugins interface
MultiPlug2.exe – Main Form with configurable menu
MainUnit.pas (*.dfm) – MainForm (MDI Owner)
etc... – some forms (e.g. Splash, Database Login)
TestPlugin.bpl – Test plugin
UTestPlugin.pas – Test Plugin Interface
TestForm.pas (*.dfm) – Test Form (MDI Child).
Here are some listings.
I have problem with
procedure TMainForm.RefreshPluginsList;
var
Pair: TPair<string, TMenuItem>;
I: integer;
begin
for I := 0 to ClassManager.Count - 1 do
RegisterPlugin(ClassManager[i]);
for Pair in MenuDict do
Pair.Value.Visible := Pair.Value.Count > 0;
end;
where ClassManager.Count is always zero, so RegisterPlugin is never called. What should I do to make it 1 and to register my plugin properly?
EDIT: I removed Handles.Add(LoadPackage('PluginInterface.bpl')) as suggested. This didn't help. I see 2 instances of Manager when tracing program.
Looks like you made your EXE without using BPLs - either "Use Runtime Packages" is off, or common shared PluginInterface package is not in "Required" list.
Another possible (but less probable) reason is using weak packaging -
which also mean that UClassManager unit (including extra instances of
ClassManager function and variable) would be copied into every binary.
http://docwiki.embarcadero.com/RADStudio/XE5/en/Using_the_Weak_Packaging_Directive
You can not and should not load that package dynamically - because the link to UClassManager should be made in compile-time already. Hence LoadPackage('PluginInterface.bpl') is redundant at best and breaking at worst and should be removed.
I think you did not do it, so now you have TWO instances of ClassManager - one in EXE and another in DLL. You can check for it issuing commands like
ShowMessage(IntToHex(Integer(Pointer(ClassManager()))))
in EXE and both BPLs and seeing what those instances really were.
Read manual or some Delphi textbook about using Runtime Packages. Few examples:
http://www.obsof.com/delphi_tips/DL613.html
http://pluginmgr.dennislandi.com/
Build with runtime packages on Delphi XE2
How to divide a Delphi project into BPLs properly?
How do I call Delphi functions in a bpl from an executable?
How to program a plugin in Windows/Delphi?
http://delphi.about.com/od/objectpascalide/l/aa012301a.htm
https://groups.google.com/forum/#!topic/borland.public.delphi.vcl.components.writing/E_HyoAiai28
After properly bulding your project you can check whether your EXE actually make use of unit UClassManager from the BPL rather than making its own independent clone of it.
You can look into imported functions table and DLL dependency tree of the EXE, so to see whether EXE really does call UClassManager initialization function from the proper BPL. Some programs allowing doing this:
http://wincmd.ru/plugring/fileinfo.html (and http://www.totalcmd.net/plugring/fileinfo.html)
http://ntcore.com/exsuite.php
http://ru.wikipedia.org/wiki/Dependency_Walker
One more option is to use "Project / Analyze" command from Delphi IDE menu and check "show packages" option to see which binary file contains which unit. You can find this command after installing Project Analyzer package which is part of Jedi CodeLib as http://jcl.sf.net
PS. Since you use XE2, i suggest you to avoid using TList with binary pointers and dangerous unchecked typecasts. You better base your TClassManager upon good old TClassList (already existed in Delphi 5 and maybe even earlier) or upon TList<TPlugin>
PPS. Since you're using XE2 and dynamically loading/unloading BPLs, avoid in your packages constants (or pre-initialized variables) of array [...] of string type. They are being destroyed. I have some ideas why that might happen and how it was fixed in XE3/4 but am somewhat lazy to implement a patch. I just switched to array [....] of PChar constants for that matter.
What is the best way to implement an external module system for a DELPHI application?
What I need is very basic really:
The main APP detects if a module is present and loads it(Run time)
Modules can store form
Modules can store DataModules
Modules can Store code
I need the use the store forms inside other forms, and only as a standAlone
I use something like this
if Assigned(pNewClass) then begin
Application.CreateForm(pNewClass, _lFrm);
_lFrm.Hide;
_lFrm.BorderStyle := bsNone;
_lFrm.Parent := pBasePNL //(TPanel);
_lFrm.Align := alClient;
end;
So I create a TForm, but place it inside a TPanel.
As for DataModules I usally store ImageLists so the ideia is to change the app ICOs just bit changing the external module.
So what is the best way to achieve this?
Looked at runtime BPLs but don’t seem to understand how to do it.
Thanks.
UPDATE : .....................................
After reading some related question and answers i think I found my answer and solution.
http://edn.embarcadero.com/article/27178
The article is old stuff but amazingly simple.
Well the logic is there I just don’t seem to get it to Show the forms
I am just testing example 2
It loads the BPL, but doesn’t get the Form:
AClass := GetClass('TForm2');
Always retrievex ‘nil’
But the BPL as it registered:
RegisterClass(TForm2);
Can anyone help with this one.
Packages are an easy solution but they have one huge drawback. Using packages forces plugin authors to use not only Delphi, but the same version of the compiler as you do.
I personally would prefer to expose the functionality of the app through a number of interfaces. This allows accessibility from languages other than Delphi.
Typically the plugin would be implemented in a DLL and would export a function that the app would call to pass in the root interface representing the app. The plugin would then call methods of that interface thus establishing two-way interaction.
I made you a demo, it's so easy to get started! However... Started is not finished.
Every time I started using plugins, I later regretted it. However, as you say, you want a binary plugin system. So BPLs are the correct solution. David suggests using interfaces (with plain DLLs instead of the full runtime package BPL) and this would solve some of the commonly encountered BPL-instability problems due to not versioning your classes, and thus your Application-and-package-binary-compatibility dependencies, properly. If you do not need to share memory and do not need to use borlandmm.dll (shared memory management) then a straight DLL with interfaces will work fine.
If you can do everything you need to do with just scripting, and make your plugin system with just scripts, then do it that way. If you can get away with DLLs, interfaces, and no memory sharing, then use plain DLLs. If you must share Memory and class types, then yes, use BPLs.
Beware that using BPLs (Runtime Packages) comes with a lot of side effects you might not have been expecting. The largest BPL-based applications I have worked on have been more of a mess, and less stable, than any monolithic apps I have worked on. It seems that it is only possible to pine for packages until you try them, and then I find, I pine for monoliths again.
If you use BPL packages correctly, and you version your plugins properly, everything is fine. BPLs are great. But in the real world, it seems that sane versioning and ABI compatibility and interoperability, and stability are at a premium.
Update: I made you a demo it's here (plugin_r2.zip). It was done in Delphi XE, but if you are using an older version of delphi, you just delete the .dproj files and open the .dpr file for the main app, and the .dpk for the package.
I'd like to use a .dll with a delphi application, but I'm curious if a delphi package is more flexible than dll?
You can read this article on my Blog: "DLL's, BPL's Static and dynamic loading, and Packages in Runtime"; Is 's writed in Spanish but you can try the Automatic translation (on right part of the page).
Basically BPL is an extension of a DLL. It's a DLL with some things added.
(POSITIVE) If you use BPL's you can do more things with the DLL. More power. You can use RTTI (you must build your applicaction with runtime package for accesss RTTI).
(NEGATIVE) If you use BPL's with more powerfull, you can only use it with Delphi, no with other languages.
If you're sure that you only use it with Deplhi, I think that you must use BPL. Search samples about RTTI, RegisterClasses, GetClass method, LoadPackage (for dynamic load),...
Regards.
Escuse-me for my poor english. It's not my natural language.
Not knowing excactly what you mean, and believing you are a newbie (so I may omit some specialized aspects), and implying you know what a DLL is:
The first and foremost reason to build a package is authoring a design-time component.
You can do quite everything (well..almost...) that a package does just as well with DLLs -- except for the design-time stuff.
Additionally, you can package multiple compiled packages into one Borland Package Library (BPL file) without having the design-time features in mind. If you think deploying and runtime-binding one BPL is better than various DLLs, go for it. The primary purpose is design-time support, though.
Packages are special DLLs that can export classes, while DLLs can only export functions. Yes, you can write a DLL function that creates and instance of a given class, but you can't use a class declared in a DLL (unless using some hacks maybe), while you can use a class declared in a package directly. Packages "know" about Delphi object architecture, while DLLs don't. On the other end, DLLs can be used from any language able to use them, while packages are Delphi-specific.
I read this article and find the concept of Virtual Library Interfaces nice for runtime loading of DLLs. However it seems that they aren't available for Win32. Is this true? And if so: Why? I don't see what would tie the idea to .NET.
EDIT: I'm mostly rephrasing here what Rob already wrote. :-)
I'm not after plugins or similar - it's about plain old Win32 DLLs. What appeals to me is the idea to let the compiler deal with all the details of loading a DLL at runtime - no need to call GetProcAddress for every function in the DLL etc.
It seems to me like the three answers so far have completely missed the point of your question. That, or I have. You're asking why Win32 Delphi doesn't have something like the magical Supports function that Hallvard's article talks about, aren't you? Namely, a function that, given the name of a DLL and the type information of an interface, returns an object that implements that interface using the standalone functions exported from the DLL.
Hydra seems to be all about calling .Net code from a Win32 program, not about importing functions from a DLL. TJvPluginManager requires that the plug-in DLLs export a special self-registration function that the manager will call when it loads the DLL, and the function must return an instance of the TJvPlugin class, so the plug-in DLL must be written in Delphi or C++ Builder. The Supports function, on the other hand, works with any DLL written in any language. You could use it on kernel32, if you wanted.
I don't know why Win32 Delphi doesn't have such a thing. Maybe CodeGear didn't see much demand for it since Delphi and Turbo Pascal had already gone for so long without it.
It's certainly possible to write a function that works like that, and I don't expect it would be any harder to write than the .Net version must have been, unless Microsoft's .Net libraries already provide most of the pieces and Delphi just wraps them up into a convenient-to-call function that looks like the several other overloaded versions of Supports that Delphi has had for years.
There would be a few steps to implementing that function in Win32. (I'm providing only a sketch of what's necessary because I don't have a running copy of Delphi handy right now. Ask nicely, and maybe I'll find more details.) First, you'd need to make sure that type information for an interface held, at a minimum, the undecorated names of its methods. Then, Supports would need to generate a function stub for each method in the interface (besides _AddRef, _Release, and QueryInterface). The stub would go something like this, assuming the calling convention is stdcall:
asm
// Pop the return address,
// discard the "this" pointer,
// and restore the return address
pop eax
pop ecx
push eax
jmp AddressOfFunction
end;
As Supports generated each stub, it would fill in the actual function address, gotten from calling GetProcAddress with the name of the corresponding interface method. The stdcall calling convention is easy to wrap like that; cdecl is a little cumbersome; register is a pain in the neck.
Once it has all the stubs generated, it would need to generate an "object" that looks like it implements the given interface. It doesn't have to be an actual class. At compile time, Supports doesn't know the layout of the interface it's going to be asked to implement, so having a class wouldn't accomplish much.
The final step is to provide implementations of the _AddRef, _Release, and QueryInterface. _AddRef would be unremarkable; _Release is where you'd call FreeLibrary when the reference count reached zero; QueryInterface wouldn't do much at all, except claim that it supports IUnknown and the interface given to Supports.
Delphi used to come with a sample program that demonstrated implementing an interface without any classes at all. It was all done with records and function pointers (which is all an interface ultimately is, after all). Delphi also came with the corresponding code to do it with classes, in part to show how much easier Delphi can make things. I can't find the name of the demo program now, but I'm sure it's still around somewhere.
There are a number of Win32 options for this type of functionality. Project JEDI has an open source plugin system as part of the JVCL that loads either DLLs or packages, and can include forms and whatnot as additional functionality.
There are also a number of commercial products available, including the TMS Plugin Framework and RemObjects Hydra.
This is nothing new or special. The article's just talking about plugins. Native code's been able to do plugins for years. The only special thing about P/Invoke is that it allows native code and .NET to talk to each other in a plugin system, and the little trick where "the DLL can be seen as a singleton object that implements the interface [so that] you can use the Supports function from the Borland.Delphi.Win32 unit to check if the DLL and all the methods are available."
If you want to do what the article's talking about in Delphi for Win32, look at the LoadLibrary, GetProcAddress and FreeLibrary Windows API functions. If you absolutely must have an interface like the article describes, you have to write it yourself, either in the DLL (if you wrote the DLL yourself) by writing an exported function that returns an interface, or in the calling app, by writing a function that uses GetProcAddress to create an interface dynamically. (Caution: this requires mucking around with pointers, and is usually more trouble than it's worth.)
Your best bet is probably just to do what Tim Sullivan mentioned: use TJvPluginManager from the JEDI VCL if you only need native code, or Hydra if you have to talk to .NET assemblies.
I've used Hydra myself for a Delphi only solution (i.e., didn't interface to .NET) and it works great for that too. It's easier to use and adds some niceties, but I think that it's basically implemented the same way as the "roll-your-own" plugin framework that is well-described in this article:
http://www.saxon.co.uk/SinglePkg/
I would look for a plugin framework that's interface-based (like Hydra and the "roll-your-own" system in above paragraph), rather than one that simply sends messages between apps.
There is a Delphi plugin framework on sourceforge, don't know whether it's the same one as in JEDI project or not: http://sourceforge.net/projects/rd-dpf
There are also a couple of other commercial solutions, one of which is Dragonsoft's:
http://www.dragonsoft.us/products_dsps.php
What is wrong with doing this with simple com objects? Declare a simple interface that all of your plugins implement, and require that each com object include an exported function that returns its class guid. Then using the "plugins" is as simple as walking thru the plugins directory looking for DLL's which expose the special registration function, invoking it and then using the class guid to then invoke the com object.
I used something like this in a WIN32 commercial application with great success. The advantage was I could switch plugins in and out at will (provided of course the application wasn't running to remove existing ones), the magic was all in the interface that each one implemented.