Came by a curious case today, that got me thinking about how the object model in delphi really works.
The case:
We have imported a SOAP service that expose a couple of methods, taking objects as parameters. Delphi generates classes/interfaces that we use to communicate with the soap service, and the objects used as parameters all inherit from TRemotable.
For different reasons, we have put all the communication with the soap service into a dll.
We then tried to instantiate the objects that should be sent in the main executable, and pass it over to the library for serialization and sending.
Now, that did not work, but gave an exception that I did not expect.
It said that the object we where trying to send to the soap service, must inherit from TRemotable, but it does. By inspecting the object, we can see that the class is the imported class from the wsdl, and that the parent class is indeed TRemotable.
Building with packages solves this issue.
The question:
Is it so that a class defined in a source file, shared between two libraries, ends up as different classes at runtime? If so, why is that?
As far as I know, it should be ok to pass objects between libraries. How, then, is strong typing ensured, and to what extent will object instances be compatible to each other?
Yes, the same class in different DLLs are different. The classes in each DLL will be loaded at runtime and point to different memory, so A.ClassType = B.ClassType will fail, even for the same source files. You can still pass the objects around and they'll work correctly, except in cases like this where it's using "is" or "as" to compare the classes themselves. Strong typing is only ensured in that the compiler assumes the classes match when you compile the DLL and main application. There's no protection against loading a DLL with one version of an object and a newer application trying to use an modified object declaration. If you want that you'll need to use packages.
You can try passing the parameter as a TObject, and on either end, cast as your TRemotable. I haven't tried this particular case, but I know I've passed TObject into a DLL like that. I also have a similar DLL for SOAP, and in my case this wouldn't work as my SOAP DLL is compiled with D2007 SOAP libraries and for complicated/legacy reasons, the rest of the app is D2005.
Related
I would like to write a component with the ability for a developer to either require a DLL or include a unit in their app which compiles the library with the project, without the DLL.
For example, let's say it's called "MyLibrary". If I include MyLibrary in the uses clause, it will by default require that a DLL be distributed with the application. On the other hand, if another unit MyLibraryImplementation is in the uses clause, it will compile everything inside the app without requiring the DLL.
This component is inside a package installed into the IDE.
I'm not even sure the terminology for this, or anything about how to go about this. I'm very familiar with writing DLL's, and not looking for someone to write any full code.
What are the fundamental things I need to know to make this optional DLL possible?
You probably won't find the result very satisfying. Delphi cannot directly load classes from a DLL. Instead, you'll need to define some class in your MyLibrary unit. You'll also have to implement most of the methods there. You're welcome to make those methods be little more than stubs that delegate all the work to functions in the DLL, though. In the stub constructor, call a DLL function that allocates a data structure and returns a handle. In all three other stub methods, pass that handle to the corresponding DLL functions along with the methods' other arguments.
You'll essentially have three parallel implementations of the class:
The one in MyLibrary.pas that's nothing but stubs.
The one in MyLibrary.dll that backs the stubs.
The one in MyLibraryImplementation.pas that does all the same things as the DLL, but internally.
You can probably avoid duplicating too much, but not completely.
You don't need to do any of this, though. For years, Delphi has already offered comparable functionality built in: packages.
If your customers want to have your class's implementation live in a separate module, they can choose the "build with runtime packages" option in their projects' linker settings. Disabling that setting will cause your code to be compiled in to their EXE files instead, and they won't need to distribute the BPL file anymore.
I am writing a localization application in which i am reading the DFM information from the application resource through EnumResourceNames API call.
However, the function returns me a name of the form for which the DFM is associated. I tried getting the class from the FindClass, but since this whole operation is coded in a package, the FindClass fails. RegisterClass routine is called from the exe's intialization section.
FindClass works fine when called from within the code written in the exe project. So, i have developed my own registration framework wherein i add all the Form classes, but this is real pain as i need to add the unit of the form and then pass the form class to the RegisterClass routine.
I was hoping if anyone can provide a simple solution of getting all the classes that are in the executable from which the instance of the object can be created by searching the classname.
BTW I am using Delphi 6 Update 2.
Thanks
Rahul W
If the application is calling RegisterClass() and the package is calling FindClass() (or vice versa), that will only work if both the package and the application are compiled with Runtime Packages enabled so they share a single instance of the RTL (which means you have to deploy the RTL and VCL packages alongside your application and package). Otherwise, your application and package will have their own local copies of the RTL instead. In order to share classes in that situation, one project will have to export extra functions that the other project can call when needed to register its local classes in the other project's local class list.
As for detecting the available classes dynamically, that is not possible in D6. The RTTI system did not gain enough detailed information to perform that kind of enumeration until D2010.
I was toying around with the idea of using dynamically loading BPL's and passing object instances from the main app to a method in a BPL. This poses a problem units between used by the application and by the BPL.
I wrote a small little prototype which did this and was curious how Delphi internally manages differences between classes defined in the app vs. the BPL.
For example, say a basic Widget class like:
TmyWidget = class
private
fId:Integer;
fDescription:String;
public
procedure DoSomething1();
end;
Now the app and the BPL are built using the unit containing TmyWidget class. Later, something changes in TMyWidget and the app is rebuilt, but the BPL is not (or vice-versa.) I added another method DoSomething2() and created an instance of TmyWidget in the app and passed it to the BPL for processing and in the basic example, it worked. But it's 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 definitely doesn't feel ideal.
The main question is - how does one typically pass objects to and from the main application and DLLs or BPLs? I've never attempted it before and likely for a good reason, but I've got this idea that lends itself to this approach...
I'd imagine that the best approach is to serialize the object and pass those bytes over and deserialize it in the DLL/BPL with this process being mindful of potential version differences between the host and the dynamically loaded module but I was hoping the new SimpleSharedMem option might bring this new functionality without the overhead of serialization, but it seems to be not very useful unless you are strict in keeping the app and dll rebuilt on any shared code changes...but in this prototype, the app would stay fairly constant and the dynamically loaded modules would be changing frequently with functionality being added to TmyWidget. (The server app serves as the factory for building TmyWidget's based on client requests and the app would pass instances to the various modules for processing.)
...was curious how Delphi internally manages differences between classes defined in the app vs. the BPL
Delphi manages this by not allowing it. You can't have a unit with the same name in multiple packages at the same time: if you do, you get an error message saying something similar to Package XYZ already contains ABC (haven't seen that in a while...). Since the type name includes the unit name, you can't have the same type in two different packages. Unless it's a Interface defined by it's GUID, but that's a different story.
... how does one typically pass objects to and from the main application and DLLs or BPLs?
You don't pass objects to DLL, that's not a good idea. When you need to pass objects to a BPL, make sure the base class for that BPL is defined into an 3rd BPL.
Example. Polymorphic behavior for your TmyWidget is probably defined using some virtual methods. Make sure you have a TmyWidgetBase class that defines all of those virtual methods, derive all your TmyWidget's from that base class and pass around objects with the type TmyWidgetBase. Make sure the TmyWidgetBase class is in it's own Package.
When I attempted doing this I ended up with an tiny "bootstrap" exe and lot's of BPL's. Essentially all the logic was in BPL's, to facilitate passing objects around.
One of the projects I've worked on has successfully used a large number of runtime packages for more than a decade now so I'll share a few of my experiences dealing with packages.
As Cosmin pointed out different packages cannot contain the same units. If you use implicit linking, by adding a package to the requires clause of another package or by adding a package to the the Runtime packages list in Project Options the compiler will do the work for you and report one of the following error messages:
E2199: Packages '%s' and '%s' both contain unit '%s' (if your compiling project that depends on two packages containing the same unit)
E2200: Package '%s' already contains unit '%s' (if your compiling a package that contains a unit this is already contained in one of the packages it depends on)
If you are using explicit linking, using LoadPackage, a check will normally be attempted a runtime (though it can be circumvented) and raise an:
EPackageError: Cannot load package
'%s.' It contains unit '%s', which is
also contained in package '%s'
Resolving these errors isn't really all that difficult.
If you have two packages that both need to use a unit just let one of them contain the unit and the other one require the first.
If you have two packages that need to use each other's contained unit you'll have to move those units to an new package that both can depend on.
Implicitly linked packages have the advantage that you can directly access class definitions as though they were statically linked. Just add a unit to the uses clause of the unit you need to use it in. The compiler and the runtime environment take care of resolving everything.
Explicitly linked packages will need to rely on class registration in the initialization section.
After this question, I need to know what principles should be followed in order to make an encapsulation of a class in a dll compatible to other version of Delphi.
I made a class using generics feature in RAD2010 and make a dll which has a function that return an instance of it. When I tried to use the dll using BDS2006 or Delphi 6, the DLL didn't work as expected. But if I use RAD2010 in other computer, there is no issue. Is it caused by using the feature that not available in previous Delphi version (the stack<> stuffs?)?
For string matters, I already follow the comment guidance in the library file, that I put ShareMem in both library first uses clause and my project. And I have copied borlndmm.dll from RAD2010 to the same folder where I tried the DLL using BDS2006. It didn't crash, but it didn't work es expected. A function return an empty string when in RAD2010 environment it worked very well.
Once again, I have a question : what principles should be followed in order to make an encapsulation of a class in a dll compatible to other version of Delphi? Thank you in advance. (For encapsulating functions in a dll when no OOP is used, I have no issued for other version of Delphi).
The definition of a string changed with D2009. If you want to make string communication safe, use a PAnsiChar or a WideString.
The basic rule of communication through DLLs is to not use anything specific to Delphi, so no Delphi strings and no TObject descendants. Interfaces, records and COM types work fine, though.
You ask:
Once again, I have a question : what principles should be followed in order to make an encapsulation of a class in a dll compatible to other version of Delphi?
and there is only one: Don't do it. You can't do it. Either you write a DLL, then use idioms and data types that can safely be used in DLLs, which precludes (among other things) classes.
Or you write a BPL, then you can safely export classes, use strings and such, but you are tied to the same Delphi version. This limitation is of technical nature, so writing a DLL will not work around it. There may be tricks to overcome this, and there may be different Delphi versions that use the same class layout so that it works, but you must not tie your public DLL interface to such implementation details.
Stick with only fundamental types. If you use interfaces, create them using the type library editor so your constrained by the compatible types by the start. A good rule of thumb is to look at the windows API and try to emulate its calling conventions.
You can use classes in your DLL, you just can't expose them as such. A good idiom that works well for DLL's is the handle concept. Your DLL creates an object and returns a handle to that object. When you need to work with that object again, you pass a function in the DLL a handle. Just remember that your DLL needs to be completely responsible for the memory and lifetime of the object. Its a trivial process to create DLL functions to expose the pieces of the class that you will need access too.
From the Delphi side, you can then write a proxy wrapper which hides the handle from the user. For events you can use a callback method. Basically you pass non object function pointers to the dll, which then invokes the function on the event. A quick overview of this process is available on Delphi 3000.
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.