Dynamically loaded BPL object exchange / transfer code

I was going to use the idea of ​​dynamically loading the BPL and passing instances of objects from the main application to the method in the BPL. This creates problematic units between the application being used and the BPL.

I wrote a small little prototype that did this, and I was curious how Delphi internally manages the differences between the classes defined in the application and the BPL.

For example, let's say the base class of widgets, for example:

TmyWidget = class private fId:Integer; fDescription:String; public procedure DoSomething1(); end; 

Now the application and the BPL are built using a device containing the TmyWidget class. Later, something changes in TMyWidget and the application is rebuilt, but the BPL is not (or vice versa). I added another DoSomething2 () method and created an instance of TmyWidget in the application and passed it to the BPL for processing and basically, it worked. But this is obviously fraught with potential problems.

If another dynamically loaded BPL also uses TmyWidget, then things get even more interesting. It seems to work, but it is definitely not perfect.

The main question is: how do you usually transfer objects to the main application and DLLs or BPLs? I have never done this before, and probably for a good reason, but I have this idea that lends itself to this approach ...

I would suggest that the best approach is to serialize the object and transfer these bytes and deserialize it to a DLL / BPL so that this process takes into account potential version differences between the host and the dynamically loaded module, but I was hoping the new SimpleSharedMem parameter could bring this new functionality without overhead serialization, but it doesn't seem to be very useful if you don’t strictly adhere to the fact that the application and dll are rebuilt with any general code changes ... but in this prototype the application remains fairly constant, and dynamically loaded modules will change frequently when functions are added to TmyWidget. (The server application serves as a factory to build TmyWidget based on client requests, and the application will pass instances to various modules for processing.)

+4
source share
2 answers

... it was curious how Delphi internally manages the differences between the classes defined in the application and the BPL

Delphi manages this without allowing it. You cannot have a single unit with the same name in several packages at the same time: if you do, you will receive an error message resembling something similar to Package XYZ already contains ABC (did not see it at that time ...) . Since the type name includes the unit name, you cannot have the same type in two different packages. If this is not an interface, the GUID that it defines is a different story.

... how can you usually transfer objects to and from the main application and DLLs or BPLs?

You do not pass objects to the DLL, this is not a good idea. When you need to transfer objects to the BPL, make sure that the base class for this BPL is defined in the 3rd BPL.

Example. The polymorphic behavior for your TmyWidget is probably determined using some virtual methods. Make sure you have a TmyWidgetBase class that defines all these virtual methods, TmyWidget all TmyWidget from this base class, and TmyWidgetBase objects of type TmyWidgetBase . Make sure the TmyWidgetBase class is in its own package.

When I tried to do this, I got a tiny "bootstrap" exe and a lot of BPL. Essentially, all the logic was in the BPL to facilitate the transfer of objects around.

+10
source

One of the projects that I have been working on has been successfully using a large number of runtime packages for more than ten years, so I will talk about several of my experiences with packages.

As Cosmin noted, different packages cannot contain the same units. If you use implicit binding by adding a package to the require clause of another package or adding the package to the Runtime package list in the project settings, the compiler will do the job for you and report one of the following error messages:

E2199: Packages '%s' and '%s' both contain unit '%s' (if your compiling project depends on two packages containing the same block)

E2200: Package '%s' already contains unit '%s' (if you compile a package containing a block that is already contained in one of the packages on which it depends)

If you use explicit binding using LoadPackage, the check will usually be performed at runtime (although you can bypass it) and raise:

EPackageError: Unable to load package '% S.' It contains the unit '% s', which is also contained in package '% s'

Resolving these errors is actually not that difficult.

If you have two packages that need to use the device, just let one of them contain a block and the other the first. package dependency graph

If you have two packages that should use each other, you will need to move these units to a new package that both can depend on. dependency graph

Implicitly linked packages have the advantage that you can directly access class definitions as if they were statically linked. Just add one to the uses clause of the device in which you must use it. The compiler and runtime take care of resolving everything.

Explicitly related packages will need to rely on registering classes in the initialization section.

+6
source

Source: https://habr.com/ru/post/1343030/


All Articles