We are reversing Delphi internal structures, does anyone know of any good resource or other details about how Delphi executables are compiled and linked together and what is the layout of the various parts inside the final exe.
I am not looking for high level details like it has n sections.
I am looking for something (the following is 'made up') like section '.text' has 3 parts:
data (a)
pointers table (b)
code interleaved with data which can be identified by using mechanism (c)
etc,etc.
Ok, I am looking for references or knowledge about the structures. I already have the tools mentioned below, and a ton more to aid in reverse engineering this from scratch.
I should have mentioned that I know the resource layout as that is well documented. It's the internal compiled structures embedded in code and data sections I am after. (e.g. how RTTI info is compiled in, where is the mapping between event handlers and form resources, etc).
Start with using existing tools like IDR (Interactive Delphi Reconstructor) and IDA (the Interactive Disassembler) and the already mentioned PE Explorer.
I would also suggest compiling some simple executables and studying the disassembly of that.
The most identifiable parts of a Delphi or C++ Builder executable are the resources.
They will contain a resource section named RCDATA. This section contains the following:
A section named DVCLAL, which identifies the compiler's SKU, such as Personal, Professional or Enterprise.
A section named PACKAGEINFO, which contains a list of contained units and a flag for Delphi or C++ Builder
Individual resources for each DFM.
On some settings, compressors like UPX may hide these resources, so you won't be able to see them unless you decompress the executable.
It could be worthwhile to have a look at Jedi JCL. IIRC their traceback tools (jcldebug unit?) open binaries to recover debug info. It would at least teach the global structure of the file.
Some bits might be delphi version specific btw.
Downloading the evaluation version of PE-Explorer might be a good start too.
You can find all types in a Delphi module (exe or dll) because they are always prepended with a pointer to the structure itself. You can create a small app and scan the exe to see for yourself how to get that information. With type information comes good information where units are / where methods are etc etc.
Combine that information with the resources available (a good resource viewer can decode the binary resources in text for all forms /frames / datamodule ).
Now if you disassemble the application you can use the information from the resources / typeinfo to make sense of the assembly code found.
Related
Using Delphi (or in general any tools, if exist of course), is it possible to reduce size of an exe file, removing all code that not is used but that is present there?
(for example, a function or procedure that is present but is never called).
I remember that with Pascal, using unit (without objects) the compiler includes only procedures and functions that are really used and will strip out non-used routines in a unit from the final exe.
With Object-pascal, I remember that in Delphi 1 all members of a object are included in the exe;
Has something has changed since than till Delphi-XE2?
If you aren't using RTTI you can add this to the top of your .dpr file (immediately after program) to remove the extra RTTI information:
{$IFOPT D-}{$WEAKLINKRTTI ON}{$ENDIF}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
If you want to strip it out of all the RTL/VCL units then you'd need to include those in your project file too so that the settings above could take effect. I don't think I would recommend doing that since I don't believe the reduction in executable size is worth the complications of compiling your own RTL/VCL.
You can also add the following, again somewhere in your .dpr file:
{$SetPEFlags IMAGE_FILE_RELOCS_STRIPPED}
This will strip the relocation information which is not needed in a .exe. Don't add this to a DLL or package!
reduce the application EXE size - excellent article
(Taken from the link above)
Generally, EXE files created with Delphi are larger than EXE files
created with another programming language. The reason is the VCL.
(Sure, VCL has many advantages...)
There are several ways to reduce a EXE's size:
01) Use a EXE-Packer (UPX, ASPack,...)-UPX
02) Use KOL.
03) Write your application without VCL
04) Use the ACL (API Controls Library)
05) Use StripReloc.
06) Deactivate remote debugging information and TD32.
07) You might want to put code in a dll.
08) Don't put the same images several times on a form. Load them at runtime.
09) Use compressed images (JPG and not BMP)
10) Store less properties in DFM files
If your aim is to reduce the size of your executable, you can use a tool which compress it and allow to execute it as it was not compress.. (=not a zip)
For instance, you can check UPX which works nicely with delphi programs.
Delphi has a smart linking option that is ON by default if I remember correctly. It does exactly what you describe. Only used functions and data are linked to your exe. If you need further size compression you can try one of the many "exe compressor" programs out there.
Just to supplement what other's have written...
The smart linker will eliminate unused routines except under the following conditions:
The unit has an initialization section - unfortunately many of the largest units in the RTL/VCL (Classes, SysUtils, Windows, Forms... to name a few) have initialization sections so if they are in your uses clause you get the whole enchilada linked into your code. Much of the code in the RTL/VCL could be refactored to reduce or eliminate this but it would break backward compatibility.
The routine is part of a class and is marked as virtual or dynamic - If you instantiate and object in your code that has virtual or dynamic methods, those methods are linked into your executable whether you call them or not.
Additional steps to can take to reduce exe file size:
Take advantage of form inheritance - If you have many similar forms, create a base form for them to inherit from. These child forms will only store properties that differ from the base form in their dfms. This can drastically reduce the size of your executable by eliminating redundant information in your dfms.
Store any large graphics in external files and load them on demand - Splash screens, "skins", icon sets, etc. can really bloat the size of an exe. Delphi doesn't always store these files in the most efficient format when they're embedded in the exe.
You can shave 10% - 30% off an exe's size by stripping certain unused data from the exe after its been compiled. There are third party tools that can do this but you can eliminate some of the cruft by setting appropriate PE header flags. Make sure you understand the implications of each flag before using it as some flags could make your exe unusable.
Copy portions of the RTL/VLC into your own units - instead of including Classes or SysUtils in your uses clause, create an new unit and copy just the classes and functions you need into the unit. Then use it instead.
Break code up into loadable modules - If you have multiple exes that reuse the same units you can make them smaller by using dlls or bpls rather than statically linking everything into the exes. A dll/bpl will only be loaded into memory once no matter how many exes need it.
Yet another option:
Use WinRar to create a Setup file (yes, WinRar can do that).
WinRar can automatically execute an EXE file once the unpacking is done.
WinRar has a superior compression ratio. One of the reasons is that it will merge all your files as a single file and then will start the compression, while ZIP (and other similar not-so-sophisticated compressors) will compress each file individually and merge them in a large file after the compression.
This give RAR's algorithm a better chance to find duplicate data among your files.
Plus, WinRar is less complicated than other installers (minus: it does not offer an uninstaller also, but that it is easy to fix with your own program).
Disclaimer: I am not affiliated with WinRAR.
The company I work for develops a system in Delphi, that contains dozens of exe modules, and each of them is identical to a certain degree if it comes to source code. Sadly, nobody has ever cared about using libraries to put the shared code in. This means that each time there is a bug fix to do in the code all these modules share, a programmer has to make corrections in all of them separately! It always takes so much time...
I decided to find a method to put the shared code into libraries. I considered DLLs and BPLs. In this case BPLs seemed much more programmer-friendly and much less troublesome, especially that the code is used only in our software and only in Delphi.
I put all the code shared by all the exe modules into BPLs and everything seems fine, but there are certain things I don't understand and would be grateful if you explained them to me.
What I expected after dividing the code into BPLs was that it would be enough to deploy exe files with the BPLs I created. But it turned out that they need an rtl100.bpl and vcl100.bpl as well. Why is it so? I want to deploy exes and my BPLs only. I don't want to provide end users with a whole bunch of libraries supplied by Borland and third party companies :). I want them to be compiled within exes as they used to be compiled before. Is it possible to do that?
What I did so far was:
I put all shared pas units to BPLs. Each BPL contains units belonging to the same category so it is clear for programmers what code to expect in a given BPL.
Each BPL is a "runtime and designtime" library.
Each BPL is "rebuilt explicitly".
The two latter are default project settings for BPLs.
And if it comes to the exe projects:
I deleted all units that I had earlier put to BPLs.
I installed my BPLs from the Tools->Install package menu in BDS 2006.
In my exe project settings I checked the option "build with runtime packages" and I listed all my BPL packages in the edit box below (only my packages, as I cleared all other ones that appeared there).
This is all I did. The exe projects compile properly, but I have no access to the source code of BPLs (I can't navigate into that code from my exe projects), even though all BPLs are stored together with their source code files. Why? It seems strange to me.
I always tend to write lengthy descriptions - sorry for that :). I will appreciate your help. I just need a few words of explanation to the points I mentioned: deploying exe with my BPLs only, the correctness of what I did as a whole, and the inability to navigate into BPL source codes. Thank you very much in advance!
Thank you all for the discussion. Some said the approach I chose was not a good idea. Our software consists of more than 100 modules (most of them being something like drivers for different devices). Most of them share the same code - in most cases classes. The problem is that those classes are not always put into separate, standalone pas units. I mean that the shared code is often put into units containing code specific to a module. This means that when you fix a bug in a shared class, it is not enough to copy the pas unit it is defined in into all software modules and recompile them. Unfortunately, you have to copy and paste the fixed pieces of code into each module, one by one, into a proper unit and class. This takes a lot of time and this is what I would like to eliminate, choosing a correct approach - please help me.
I thought that using BPLs would be a good solution, but it has some downsides, as some of you mentioned. The worst problem is that if each EXE needs several BPLs, our technical support people will have to know which EXE needs which BPLs and then provide end users with proper files. As long as we don't have a software updater, this will be a great deal for both our technicians and end user. They will certainly get lost and angry :-/.
Also compatibility issues may happen - if one BPL is shared by many EXEs, a modification of one BPL can bee good for one EXE and bad for some other ones - #Warren P.
What should I do then to make bug fixes quicker to make in so many projects? I think of one of the following approaches. If you have better ideas, please let me know.
Put shared code into separate and standalone pas units, so when there is a bug fix in one of them, it is enough to copy it to all projects (overwrite the old files) and recompile all of them.
This solution seems to be OK as far as a rearly modified code is concrened. But we also have pas units with general use functions and procedures, which often undrego modifications - we add new functions there whenever necessary, but in single projects. So imagine that you write a new function in one of the 100 modules and put it into its general use unit. After a month or two you modify a different module and you think you need the same function you wrote 2 months ago. You have to find the module (it's difficult if you don't remember which one it was) and copy the function to your code. And obviously - the general use units become completely different in each module as long as they are stored in each project separately. And then, if there is a bug fix to do... the whole story repeats.
Create BPLs for all the shared code, but link them into EXEs, so that EXEs are standalone.
For me it seems the best solution now, but there are several cons. If I do a bug fix in a BPL, each programmer will have to update the BPLs on their computer. What if they forget? But still, I think it is a minor problem. If we take care of informing each other about changes, everything should be fine.
#CodeInChaos: I don't know if I understood you properly. Do you mean sharing pas files between projects? How to do that? We store source codes in SVN. This means that we would have to store shared code in a separate folder and make all projects search for that code there, right? And download from the SVN a project and all folders it is dependent on...
Please, help me choose a good solution. I just don't want the company to lose much more time and money than necessary on bugfixes just because of a stupid approach to software development.
Thank you very much.
Even though this question has an accepted answer I'm going to take a stab at it.
The title asks how to divide a project into bpls but the real question appears to be:
"What's the best way to share code between projects?"
There are a few ways to do this:
Shared units
Dlls
BPLs
Regardless of which direction you go you will likely need to restructure your projects. From your description it sounds like each project is developed in relative isolation. Code is shared using copy/paste, which quickly gets out of sync and result in a lot of duplicated effort. So lets examine each of the techniques for sharing code.
Shared units
This is the most straightforward approach. You create a shared location and place code you would like to reuse among your projects into this location. The units are statically linked into your projects so you don't need to worry about deploying extra dependencies along with the main executables. Statically linked units are by far the easiest to troubleshoot and debug.
The compiler needs to be able to find your shared units. There are 4 ways to tell the compiler where to look.
Add them to the project - SHIFT+F11 - Adds a reference to the unit into the project files (dpr, dproj). The IDE will normally use relative paths if the unit is located under the same directory tree as the project files, otherwise it will use absolute paths, which can be problematic if developer machines aren't configured identically.
The project's Search Path - CTRL+SHIFT+F11 Delphi Compiler > Search path - Add a directory and the compiler will look there to find units mentioned in the uses clause of any unit in the project. Its best to use relative paths if you can. You can also use environment variables: $(MyPath)
Global Search Path - Tools > Options > Environment Options > Delphi Options > Library - Win32 > Library Path - Any paths listed here are available to all projects on a machine. This is machine dependant
Command line - If you build from a script or build automation tool you can set the search path using the dcc32's -U switch or msbuild's /property:UnitSearchPath= switch.
Options 1 and 2 will be the most useful.
As far as your SVN repository goes you have a few options for organizing the projects and shared units. The simplest would be to place all projects under single trunk along with the shared units:
Projects
trunk
ProjectA
ProjectB
ProjectC
Library (shared units)
If for some reason the above structure isn't possible you could try this alternative:
ProjectA
trunk
Library (branch of main library)
ProjectB
trunk
Library (branch of main library)
ProjectC
trunk
Library (branch of main library)
Library
trunk (main library)
In this configuration changes made to each project's library folder would not be immediately available to the other projects. Each project would need to synchronize changes with the main Library project on a regular basis. A side effect of this is that changes that break other projects will be delayed until the other projects are synchronized. Whether you consider this a good or bad thing depends. On the one hand bugs are easier and cheaper to fix when the code they involve is still fresh in the developer's mind. On the other hand if you don't practice unit testing (which I highly recommend you do) or the code is very fragile or you just have developers prone to making reckless changes you may want to control how frequently those changes get pushed into other projects.
Dlls
Dlls allow you to share code by linking to it at runtime. They expose functions that can be called from a main executable or another dll.
While dlls are always linked at runtime you decide whether they are loaded at application startup or only when needed. Loading at startup is called static loading and in Delphi is accomplished using the external directive. The vast majority of the rtl/vcl classes that wrap system api calls use static loading. Dynamic loading lets to delay the loading of a dll until it is required. This uses the WinAPI functions LoadLibrary and GetProcAddress. A corresponding call to FreeLibrary will unload a dll.
Unfortunately standard dlls limit what kind of datatypes can be passed. If you need to access a dll from non-Delphi projects you will need to limit yourself to using c style data types. If you will only be using a dll with Delphi projects you can safely use Delphi strings and dynamic arrays as well if you use the SharedMem unit in the dll and any projects that use it.
You can safely use object's within the dll without problems but if you want to pass objects between the dll and the application you'll need to extract the object's data and pass it as primitive types and reassemble it into an object on the other end. This is called (de)serialization or marshalling and there are much easier ways to do this than rolling your own.
COM (Component Object Model) is well supported in Delphi but it has a bit of a learning curve. Consuming COM objects is pretty straightforward but designing one will take time if you're not familiar with COM. COM has the advantage that it is language neutral and is supported in the majority of languages targeting the Windows platform (including languages targeting the .NET framework).
Bpls
Bpls (also called simply "packages") are specially formatted dlls that make working with objects a lot easier. Like standard dlls they are linked at runtime and can be statically or dynamically loaded. They are easier to learn and use than COM dlls and provide more seamles integration into your projects than COM. Packages are composed of two parts: the bpl and the dcp. The dcp is like the dcu files generated when you compile a normal unit file except it contains a whole bunch of units in it. Using a class that is compiled in a bpl is as simple as adding the dcp to the project's package list then adding a unit to a uses clause of one of the project's units.
When you deploy the app you'll need to install the bpl as well. As other's have noted you have to include the rtl package at a minimum and most likely the vcl package if you use any forms. There is a way around deploying Borland supplied bpls with your projects. You can create a "mini" rtl package that contains only the units your project need. The difficultly is in determining which units to include.
Summary
From the description you've given creating a library of shared unit files to statically link against may be the most expedient route. I would also suggest trying out a program called Simian. It will help you track down duplicate code in your code base for inclusion in your shared library. It doesn't directly support pascal but it does a decent enough job using the plain text parser with a little tweaking of its configuration.
Also I can't stress enough the value of unit testing. Especially if you're moving toward shared libraries. A suite of well written unit tests run on a frequent basis will give you instant feedback when a developer changes a class and it breaks an unrelated project.
Imagine you have a project with an EXE and two different BPL modules, and somewhere in that codebase, there's a line that says if MyObject is TStringList then DoSomething;. The is operator works by examining the object's class metadata, stored in the VMT, and then following a chain of VMTs through the ClassParent pointer, to see if any of them match the class reference (also a VMT pointer) for TStringList. In order to make sure that this will work correctly, there needs to be one single VMT for TStringList that's the same throughout your entire program, no matter how many BPLs it's divided up into, which means it has to be in its own package. That's why system runtimes like rtl*.bpl and vcl*.bpl are necessary, and there's not much you can do about that. It's part of the price of using BPLs.
As for not being able to debug, you need to make sure that the BPLs are built with debug info enabled and that the debugger knows how to find the folder where the DCP (the file containing the debug info for the BPL) is located. And you won't be able to trace into system BPLs, because debug-enabled DCPs weren't shipped with your version. They were added pretty recently, I think in XE but it might have been in D2010.
Why can't I browse my source code? Is there a way to fix this?
You can not browse the source code of the units included in the packages because they are neither in your project, your library or search path.
The way I solve this is adding the directories to the project search path. This way the compiler does not know about those files (and does not try to recompile them) but the IDE let's you browse their content and debug into them.
"In my exe project settings I checked the option "build with runtime packages"
That is why you cannot deploy without the BPL's etc - this option is confusing for a lot of developers -"build with runtime packages" means that you will need the bpl's present at runtime. Uncheck that option and the packages will be linked into your exe at compileTime. (Your exe will g-r-o-w in size.) The idea behind the "build with runtime packages" is to keep the size of exe's down and allow several apps to share common bpl's because they are NOT linked into the exe # compileTime - that's the upside. The downside you are now experiencing - you must distribute your bpl's with your exe.
in C# you can easily open an assembly (just another word from an EXE) and then get reflection information from that assembly. I've been looking for something similar for Delphi where I can write a Delphi program that can point to a Delphi EXE then get me reflection information. How can I archive this? Thanks
There are a handful of programs that can extract RTTI from Delphi programs and DLLs. It's not as rich as what's available for .NET, but it can be done to a limited degree. There's a lot more RTTI available in Delphi 2010 and later versions, but as far as I know there's no program out yet that can extract info from them.
I was at the conference where this system was formally announced, and a bunch of people asked how this would affect security. Barry Kelly, who created the new RTTI, said that there would not be enough metadata available to create a "Delphi Reflector".
Well, sad news is, you probably can't. You can easily view .NET assemblies because they a) are compiled to what is called intermediate language (thus you can even get the code back using the likes of Reflector etc.), and b) contain metadata. Delphi, on the other hand, compiles to native code that and produces regular PE files that do not include rich metadata like a .NET assembly.
Delphi just doesn't work that way.
There are tools that can assist in reversing (Delphi written) executables but it will never be easy and it requires good x86 assembly knowledge.
Some examples of such tools are:
IDA Pro and/or Hex Rays
DeDe
Interactive Delphi Reconstructor
PE Explorer
The resource sections of a Delphi Executable also reveals usefull info like the form and it's components.
See also Is there a program to decompile Delphi?
If you have Delphi2010+ you can load a bpl and then use the rich rtti over it lik. e you do with c# and a .net assembly. If you need to do this in a .exe AFAIK you can't.
TestComplete seems to identify most objects in a running Delphi executable. You can extract this information with a script. A demo can be downloaded from http://www.automatedqa.com/downloads/testcomplete
This is maybe not the type of application you want as it is big and made for GUI-testing, but yes it can identify the objects.
As mentioned Remko, IDR (Interactive Delphi Reconstructor) can extract all RTTI information (if program contains it!) for Delphi version from 2 to 2009. Version 2010 will be available later. Moreover IDR can use all information that it finds in program to create a lot of comments to disassemled program code (this is a first step of analyses). You can also look forms and easy go to event hadlers associated with controls.
It's easy enough to find all your external dependencies. Just run the program and open up the Modules info window. But how can I find all my internal dependencies? I know the program keeps a list of all the units, because I've traced my way through the initialization code a time or two. But is there any easy way to access this list from the debugger?
The Delphi debugger can show you which units were compiled into a module (exe, dll or package). You can see this in the Modules view (View | Debug Windows | Modules). Click on a module in the upper left pane, and the lower left pane will show all the compilation units that were built into that module. If a particular compilation unit was made up of multiple source files (i.e a .pas and a .inc file), that will be shown too (when you expand the comp unit).
Alternatively, you can have the Delphi compiler show you a list of used .dcus by passing --depends when you compile a project. It will output a .d file with a list of the .dcus (and .dcps) that were required.
Another, but rather cumbersome way, is to generate a map file, it contains a list of all units used in a program.
see also this answer:
How can I find all the units in my Delphi app?
I use the GExperts Project Dependencies.
With the "Used By...", you can see units included but not used by anyone.
But you can't see unit included in uses clauses that could be removed when they don't have any code actually called.
Here's the help:
Project Dependencies
The project dependency expert enables you to see what units a particular unit uses, and in turn what units use a particular unit. When this expert is activated, it parses all of the current project's source code for uses clauses and builds up a list of dependencies. To view the dependency information for a particular unit, click on it in the left pane. The right pane will contain the dependency information. Indirect dependencies are units that are used by used units of a particular unit.
You can refresh the dependency information at any time by clicking the refresh button on the toolbar and you can sort the file listing by clicking on the column headers.
(source: gexperts.org)
OTOH, you can also use free Peganza's ICARUS as a more detailed reporting tool but less interactive...
Have you looked at Pascal Analyzer or the free limited version, Icarus, from Peganza Software? They will create "uses reports" telling you what module uses what others, so that should give you the info you're after.
Marc
GExperts has a Project Dependencies tool. I have used it before when trying to track down used units. You can't search in it but you can export the list to a CSV file and search there. This also only lists what is in the uses section. If you have a module included that is not being used it will still show up.
I know of at least two ways you could try to get a view of all the units used in your project
CTRL-SHIFT-B opens the object browser. If I'm not mistaken, here you can get a view of used units. I'm not entirely sure about this method and don't have Delphi available to verify it.
Use Modelmaker; Modelmaker can give you a tree like view of all your unit dependancies. Look at the Visualizing existing code section for more information.
The easiest way is to compile program and check which .dcu was created by compiler. Make sure to setup compiler to create .dcu in a separate directory, for example c:\dcu. I have created simple utility that searches .pas for every .dcu file in directories that are in a compiler search path (that can be read from .cfg, .dof or .bdsproject file).
You can use a MAP file in conjunction with MapFileStats, this will not just give you all your dependencies, but the amount of code (and resources) they contribute in the final executable.
Useful to spot units you have dependencies to, but use little of, as well as spotting "fat hog" units, which take everything plus the kitchen sink with them.
FWIW, reducing dependencies and eliminating hogs isn't just beneficial to executable size, it's also beneficial down the road when it'll be time to upgrade to a new version.
There is a (rather old) utility called UsgParse. It builds a treeview of all units referenced by a project.
I found a copy on the NexusDB site via
http://coding.derkeiler.com/Archive/Delphi/borland.public.delphi.thirdpartytools.general/2004-03/0231.html
source: http://www.nexusdb.com/downloads/USGParse/USGParse_src.zip
binary: http://www.nexusdb.com/downloads/USGParse/USGParse.zip
I am looking to add the capability for users to write plugins to the program I have developed in Delphi. The program is a single executable with no DLLs used.
This would allow the user community to write extensions to my program to access the internal data and add capabilities that they may find useful.
I've seen the post at: Suggestions for Adding Plugin Capability? but its answers don't seem transferrable to a Delphi program.
I would like, if possible, to add this capability and keep my application as a single executable without any DLLs or additional modules required.
Do you know of any resources, components or articles that would suggest how to best do this in Delphi, or do you have your own recommendation?
The first question I would ask is, do you need the plugins to access the UI of your host application, or add any UI elements of their own? Or will the plugins be limited to querying and/or supplying data to your host app?
The latter is much easier and opens up two possibilities. Others have already mentioned DLLs, which is the first way to go. Certain caveats apply - in general you should be interfacing with a dll using only the data types that are used in Windows API. THat way you can be sure that the plugin DLLs will understand your data types, no matter what language/compiler they were created in. (So for example, use PChars, not strings. Do not as a rule pass Delphi classes such as TStream to a DLL. This will appear to work in some cases, but is unsafe in general, because even if the DLL was compiled in Delphi, it may have been a different version of the compiler, with a slightly different idea of what TStream is). Google for using DLLs in Delphi, and you'll find plenty more tips.
Another way that hasn't been mentioned yet is to enable scripting in your application itself. There are several very capable 3rd-party scripting engines, both commercial and free, and most of them allow you to exchange Delphi objects with the script. Some of these libraries support only Pascal as the scripting language, others will let you use Basic (perhaps better for beginner users) or other languages. See for example RemObjects Pascal Script (free) at http://www.remobjects.com/free.aspx .
My favorite scripting solution at the moment is Python for Delphi (P4D, also free) from http://mmm-experts.com/Products.aspx?ProductID=3 It can interface beautifully with your classes via RTTI, and allows you to execute Python code in your Delphi app, as well as use Delphi classes in Python scripts. Given the popularity of Python, this may be a viable solution if you want to attract developers to your project. However, every user will need to have a Python distribution installed.
It seems to me that the barrier to entry, from the point of view of potential plugin writers, is lower if you use scripting than if you choose DLLs.
Now, back to my initial question: things get much more complicated if you need the plugins to interact with your user interface, e.g. by placing controls on it. In general, DLLs cannot be used to do this. The Borland/CodeGear-sanctioned way is to use packages (BPLs). With BPLs, you can access and instantiate classes offered by a plugin as if they were declared in your host application. The catch is, all BPLs must be compiled with the same exact version and build of Delphi that your main application is. In my opinion this makes packages completely impractical, since it's hard to expect that all the potential plugin writers around the world will be using the same version of Delphi you are. A major pitfall.
To get around this, I have experimented with a different approach: keep using DLLs, and develop a syntax for the plugin to describe the UI it needs, then create the UI yourself in the host app. (XML is a convenient way to express the UI, since you get the concept of parenting / nesting for free.) The UI description syntax can include callbacks to the DLL triggered when the contents or state of the control changes. This method will restrict plugins to the set of VCL controls your application already uses or has registered, though. And it's not a one-nighter job, while BPLs certainly are.
Google for "Delphi plugin framework", too. There are some ready-made solutions, but as far as I know they usually use BPLs, with their limited usefulness.
Actually, the accepted answer to the question you cite is quite appropriate for Delphi as well. Your plug-ins will be DLLs, and you can dictate that they should export a function with a certain name and signature. Then, your program will load the DLL (with LoadLibrary) and get the address of the function (with GetProcAddress). If the DLL doesn't load, or the function isn't there, then the DLL is not a plug-in for your application.
After you have the address for the DLL, you can call it. You can pass the function an interface to something that represents the parts of your application that you wish to expose. You can also require that the function return an interface with methods that your application will call at various times.
When testing your plug-in system, it will be wise to write a plug-in yourself with a language other than Delphi. That way, you can be more confident that you haven't inadvertently required everyone to use Delphi.
At first I went for BPL and DLL base plugins. And found them hard to mantain.
If you use BPL system, then you need to match BPL version with EXE version. This includes Delphi updates which can break something. I found out (the hard way) that if I need to include all my plugins with every release, there is no point in having plugins at all.
Then I switched to plain DLL plugins. But that system just complicated code base. And that's not a good thing.
While crusing the net I found out Lua embedded script language, and delivered with it. Lua is 150K DLL, embedding bytecode compiler, interpreter and very simple and smart dynamic programing language.
My plugins are simple lua scripts. Easily mantaind and made. There are premade Delphi examples, so you can export any class or procedure as Lua table or function. GUI or not. For example I had TurboPower Abbrevia in my app for zipping. I exported my zipping class to lua, and all plugins now can call zip('.', 'dir.zip') and unzip(). Then I switched to 7zip and only implemented old class to use 7zip. All plugins work as they did, with support for new zip('.', 'dir.7z').
I made TLuaAction which calls Execute(), Update(), Hint() procedure from its script.
Lua allso have it's own plugin system that makes it easy to add funcionality to it. Eg luacom make is easy to use COM automation, luainterface allows calling .net from lua.
See luaforge for more. There is Lua IDE made in Delphi, with source.
I tried to make an overview of all such options some time ago. Together with my readers/commenters we built this list:
DLL/BPL loaded from the program.
DLL/BPL loaded from a sandbox (which could be another copy of the program or a specialized "server" application and which communicates with the main program via messages/sockets/msmq/named pipes/mailslots/memory mapped files).
COM (in any of its variants).
DDE (please not).
External program that communicates via stanard input/output.
External program that communicates via files (file name is a parameter to the program).
External program that works via drop folder (useful for batch processing).
External program that communicates with windows messages/windows sockets/msmq/named pipes/mailslots/memory mapped files/database publish-subscribe.
The most universal method of adding plug-in capability is to use COM. A good book to get you started on the road is Delphi Com Programming by Eric Harmon. While it was originally written for Delphi versions 3 through 5, the books contents are still valid with the latest versions of Delphi.
Personally, I have used this technique along with active scripting to allow end user customization.
I'm using plug-ins to implement most of the functionality in the game engine I'm building. The main EXE is made up of a script engine, a plug-in manager, some basic graphics routines and not much else. I'm using TJvPluginManager from the JEDI VCL library. It's a very good manager, and it can add just about anything you want to your program. Check out the demos included with the package to see how it works. The only downside is that it adds a lot of JCL/JVCL code to your program, but that's not really an issue if you're already using other JVCL components.
If plugins will be developed in Delphi or C++ builder, use packages + interfaces. Delphi OTA is a good example for that.
If plugins will be language independent, COM is a good way to go.
Addition: If you won't use COM, u may need to provide SDKs for each language. And datatype handling between different languages can be pain(for example delphi string type). Delphi COM support is excellent, u don't need to worry about kind of details. Those are mostly impilicit with Delphi COM support. Don't try to invent the wheel again. I'm surprised why people doesn't tend to mention about it.
I found an article by Tim Sullivan:
Implementing Plug-Ins for Your Delphi Applications
You could have a look at Hydra from Remobjects. Not only will this allow you to add plugins, but also to mix win32 and .net.