I have a Delphi application that I have written a fairly simple wrapper .exe for.
Basically, there was a dll that had a bunch of functions, one of which I would call iteratively once my wrapper did what it needed to. I am not in control of this dll file, and will never be.
Well, now this DLL is a BPL, and I'm not sure how to call functions within that file. Thanks in advance.
The easy way to use functions from a package is to "use" the unit that contains the function, call it as usual, and put the package on the list of your project's runtime packages. For that to work, there are a few requirements:
Your project must use the same Delphi version as was used to compile the package.
You must have access to the DCU file for the unit, or at least the DCP file for the package.
The package must exist in the operating system's search path when your program starts.
If you can't satisfy the third requirement, or if you don't want to have the package loaded all the time, then you can call LoadPackage for it instead. The way to make that work is to have another package that is loaded all the time. It will be used by both your project and the package you wish to load. The intermediate package will expose an interface (such as some registration functions, a variable, or a class) that the main package can use to tell the application what its functions are. You won't be able to "use" the main package's unit in your application directly.
If you can't satisfy the first two requirements, then there is the much harder way, which is also what you'd need to do if your application isn't written in Delphi or C++ Builder. Treat the package like an ordinary DLL. Load it with LoadLibrary. Use GetProcAddress to load its Initialize function, and then call it. (Remember that the calling convention is register, not stdcall.) Then load the address of the function you wish to call, keeping in mind that the name of the function has been mangled to include some unit and type information. Call the Finalize function before you call FreeLibrary. Check the source for LoadPackage and UnloadPackage; whether you need to call CheckForDuplicateUnits probably depends on whether you can satisfy requirement number 1.
A BPL is just a DLL with a few specific additions to it. You should have no trouble calling functions from it just like you did with the DLL, with one specific caveat: The BPL has to be built in the same version of Delphi as you're using. This can be a major drawback if you don't have the source code. If this is a problem for you, you should probably talk with whoever created it and ask them to make it back into a DLL.
A BPL can eliminate a lot of DLL problems. If you can statically link it, the border becomes all but transparent. If you have to load it dynamically, you need one DLL-style access function (usually one that returns an object or an interface) and some common type (interface) definitions. All that should be supplied by the maker of the BPL.
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.
So, I have a myself written run-time package. If a package is statically linked, the project that uses has full access to exported data because the compiler has full knowledge of what is imported from it, am I right? But it's also possible to load a package dynamically via LoadPackage(). But, how to work with imported complex data structures like classes then? I couldn't find a feasible way other than constructing complex expressions like using FindClass('TSomeClass') and invoking RTTI to operate on an instance of the imported class.
The compiler has full knowledge of what's in the package because the DCU and DCP files tell it what's there.
The IDE knows what's in the package because it knows how to find the Register procedure in all the units, and that procedure tells the IDE about the available classes.
In most cases, a program knows what's in a package because the program used units from that package, and the compiler assured that mentioning names of things in those units would resolve to corresponding things in the BPL file at run time. This includes mentioning the BPL file in the program's import table, so the OS loads the BPL automatically.
If the list of BPLs you wish to load can only be determined at run time, then you cannot use any units from those packages. You have to load the package dynamically.
There's still the matter of how to use what's in those packages. You could try to discover the entire contents with RTTI. That's no picnic, though. Instead, define an intermediary package that all involved modules will use.
Define an interface or a common base class for all your packages' classes to have. Put the definition of that class in a unit that's in its own package, which we'll call Shared.bpl. Include that package in the "requires" list of all your other packages and your EXE. Now, everything can refer to the shared unit and the common base class.
This is exactly what Delphi itself does. The shared packages are called RTL and VCL. There are several common base classes already defined there, including TComponent. In your case, it sounds like you need some common definitions beyond what TComponent has.
Short answer:
What you need is the compiler/linker to set you up and use DCPs to do all the linking to types and such.
Then loading of BPLs should be delayed/done by you in custom code.
Unfortunately Delphi won't allow this, probably because of political reasons, you could try and hack it though, see below for more thorough answer.
Long answer:
Apperently DCP describe to the compiler/linker/Delphi yadayadayada what's in those packages/DLLs/BPLs type-wise.
These DCPs can be considered the interface to these DLLs/BPLs, these DCPs are probably somehow compiled into the executable.
Then the BPL probably contains the "implementation".
Now here is where the problem begins. These BPLs are "auto-loaded" as somebody else already mentioned by mentioning "import table".
What you could try is "nuking" / altering the import table so that these BPLs are not loaded automatically anymore.
Then you could try loading these BPLs manually.
I am not sure if it's just as simple as doing a "load package" operation.
Perhaps the loading involves more like acquiring pointers to routines/methods/classes, not sure how that works.
However perhaps that code can be re-used, so all you need to do is "hack" into the import table and hack into the "load bpl" and disable it.
Then you should be able to replace that with your own custom loading code and perhaps finally "re-patch" into other importing routines... like routines calling getprocaddress and such if so required, not sure about this last part.
Anyway this is very sloppy from Delphi developers that there is no functionality to do this little "import table"/"load step" yourself.
This is politics at play though, there is no technical reason why this could not be delayed, done custom by you and then call the rest if necessary.
For some reason they do not want you loading these BPLs manually. They probably want you to keep using the IDE this way.
If you were able to load these things manually, maybe the IDE would then no longer be necessary.
Currently the IDE is necessary to specify where to load this stuff from, without the IDE it will get difficult. Though there are probably also some compiler options somewhere to specify the same, though few would use that.
So to me it seems some very weird "tie-in" into this product, which I honestly must admit is pretty fucking retarded.
They did the same with winsock for example which has two different versions, very easy to load this yourself manually so you can choose which version to use instead of always v1 or v2. For easy for them to delay these getprocs and such, yet they do not...
If they did, Delphi would be much more backwards compatible with windows 95/98, currently Delphi exes no longer works for those older operating systems, though there is no real technical reason why it could not work, it basically has to do with which DLLs are loaded, just a few lines of code could very easily make it work.
This is probably again politics as play to make Delphi only support the latest Windows versions a deal struck between Delphi creators and Microsoft.
Same thing with Windows 10, it apperently detects older processors and then refuses to run on them, removing/hacking these few lines of code/instructions will make Windows 10 work on older processors. Surprise ! =D
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'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've done About.com guide to embedding dll's in Delphi EXE's which seems to work, so long as I don't actually use the DLL as an external function. Is there anyway to get the code I linked to to work earlier than an unit referenced in the uses clause.
I've tried:
Doing exactly what this code says.
Placing this code in the initialization section of the form that uses the unit that uses the external functions.
Placing this code in the initialization section of the unit that uses the external functions.
And by external functions I'm referring to a function that looks like:
function MyFunction: Integer; stdcall; external 'fundll.dll';
The problem I'm getting is the usual 'fundll.dll' cannot be loaded (because it's not in the directory) . Zarko's code works (pretty sweet, it creates the dll in that folder) when the code gets that far. But it just crashes before the project even gets rolling when I'm using the external functions I need.
You can't do this with external functions - use LoadLibrary() and GetProcAddress() instead after extracting the DLL, and everything should work.
The reason is that any code will be executed only after all entry points have been resolved by the OS loader. Kind of a chicken and egg problem, if you will.
If you are going to use LoadLibrary() and GetProcAddress(), you might prefer to use BTMemoryModule, which would allow you to use the DLL embedded as a resource without saving it to the filesystem (which the user might not be able to do, depending on the machine's security).
http://www.jasontpenny.com/blog/2009/05/01/using-dlls-stored-as-resources-in-delphi-programs/
if you want to call a function in it, you have two choices ...
1) use an exe/dll bundler instead of the resource method.
2) don't link to the library with the external style declaration. instead use LoadLibrary, GetProcAddress, etc to reference the function you need to call.
the resource method and the declaration of the function as external will not mix. windows wants to link your exe to the dll in memory before your code runs to extract the dll.