How to link a DLL in a Delphi package? - delphi

I'm creating a Delphi package using OpenGL and the GLEW extension. I downloaded GLEW from the official website. That was a painful way to make it usable with Embarcadero, but I finally succeeded. At this point, I'm able to compile and use GLEW in any C++ Builder or Delphi application project.
However, I experiment difficulties to use GLEW in my Delphi package. As GLEW is a DLL, I declare the external functions that I need as in the following example:
procedure glBindVertexArray(glArray: GLuint); external 'glew32.dll' name '__glewBindVertexArray';
This works well when I compile an application project, so I'm sure that the declaration is correct. I can compile and link my package without problems. However, when I try to use it in a demo project, I receive the following link error:
[ilink32 Error] Error: Unresolved external '__glewBindVertexArray' referenced from C:\USERS\PUBLIC\DOCUMENTS\EMBARCADERO\STUDIO\15.0\DCP\QRMODELS.LIB|TQRMD2_OpenGL
So my GLEW functions are not found by the linker. The problem is that I don't know how to link an external DLL into a Delphi package. When I try to add the DLL in the "Requires" section, my package can no more be compiled and I receive the following error:
[dcc32 Fatal Error] QRModels.dpk(35): E2202 Required package 'glew32' not found
I also tried to add glew32.lib in my package, and tried to link GLEW in my target project, but without success.
So, what is the correct way to link an external standard DLL, that isn't a .dcp, in Embarcadero Delphi packages? I remember you that I can use this DLL without problems in any Delphi application project, and I own the corresponding .lib too, that is already converted to be used with Embarcadero compiler.
Regards
NOTE: As suggested in the comment posted by David Heffernan, I tried to create a small package that includes an external function to the user32.dll. This worked well. I also tried to include one of my GLEW external function. Now the issue is different: the package links and builds well, and the target project too. But when the exe runs, I get an error message saying that glew32.dll is missing on my computer. So my issue is basically a bad installation of the GLEW library. However, all my other projects using GLEW works well, including those I create with other compilers, as e.g. Code::Blocks.
I also compared my package options, and the only thing that is different is that the package I create is divided in 2 projects, one for the design time and one for the runtime. I already created such other packages without problems, but I never tried to include external DLL in them.
Here is my test unit:
unit Unit1;
interface
uses OpenGL;
function MessageBeep(uType: Cardinal): LongBool; stdcall; external 'user32';
procedure glBindVertexArray(glArray: GLuint); stdcall; external 'glew32.dll' name '__glewBindVertexArray';
type
TTest = class(TObject)
public
procedure TestBeep; virtual;
procedure TestGlew; virtual;
end;
implementation
procedure TTest.TestBeep;
begin
MessageBeep($40);
end;
procedure TTest.TestGlew;
begin
glBindVertexArray(0);
end;
end.
Regards

is it possible for the linker to find 'glew32.dll' (is it in the search path or in the working path of the Debugger)?
maybe this can help you
http://rvelthuis.de/articles/articles-cobjs.html
http://docwiki.embarcadero.com/RADStudio/Sydney/en/Link_object_file_(Delphi)
https://hub.packtpub.com/implementing-c-libraries-in-delphi-for-hpc-tutorial/
The last article is part of Delphi High Performance from Packt (a very good book on Delphi)
By the way, if you want to include a .lib file in Delphi, it is not enough to just add the .lib file to the project. You have to include the .lib file with {$ L 'LibName.lib'}
here's an Embarcadero Link http://docwiki.embarcadero.com/RADStudio/Sydney/en/Link_object_file_(Delphi)
You just have to make sure that your .lib file is in the correct format e.g. OMF, COFF, ELF coz Visual Studio uses COFF, Delphi OMF and C++ Builder ELF
Delphi 64-Bit Windows Compiler http://docwiki.embarcadero.com/RADStudio/Sydney/en/DCC64
Delphi 32-Bit Windows Compiler http://docwiki.embarcadero.com/RADStudio/Sydney/en/DCC32
C++ Builder 64-Bit Windows Compiler http://docwiki.embarcadero.com/RADStudio/Sydney/en/BCC64
if your .lib file is not in the correct format, you can use the following open source project to convert it
https://github.com/gitGNU/objconv

Related

DesignIntf not found in bpi but works with dcp

In Rad Studio Rio, I create a package for Delphi.
In the PAS unit, I add:
uses DesignIntf;
The compiler complains about "DesignIntf not found". Adding DesignIntf.dcp as reference solves the problem.
Now, if I create the same package but from C++ Builder, I add "uses DesignIntf;" in the PAS unit, if I add DesignIntf.bpi as reference, the error is not fixed.
Why in Delphi DesignIntf.dcp solves the problem but DesignInt.bpi does not solve it for C++Builder with exactly the same code?
UPDATE;
It is win32 platform. The following image shows how designintf.bpi is referenced but I continue getting the error. It works as expected if the package is for Delphi and using designintf.dcp.
In both Delphi and C++, your design-time package needs a reference to the DesignIDE package in order to use the DesignIntf unit.
Please read Embarcadero's documentation:
Compiling C++ Design-Time Packages That Contain Delphi Source
Creating or Extending a Package to Use the Tools API
Finally I have solved it. I missed to add -LUDesignIDE under Delphi Compiler options. It is explained at http://docwiki.embarcadero.com/RADStudio/Rio/en/Compiling_C%2B%2B_Design-Time_Packages_That_Contain_Delphi_Source
The reason is because I mix Delphi and C++ code.

Why can I compile 64 bit Delphi libraries through runtime package but not through source?

We are just starting on migrating some of our projects to 64-bit in Delphi, we also have a couple of 3rd party Delphi libraries that we are using.
Traditionally, when we use a 3rd party library we do so by using the design time package .bpl OR we just have the compiler compile the source code.
However, in 64-bit it seems we have to do it completely differently. If we are compiling a 64-bit library we need to use DCU.
For example, we have a library that we needed to use in 64-bit. The library supports 64-bit. To get it to work, I had to compile the runtime package as 64-bit then point the compiler to the outputted 64-bit DCU files. When I try to compile the library from source as 64-bit we get all kinds of errors.
So my question basically is: Why/How can we compile the source code through the runtime packages in 64-bit just fine, but when we try to compile as just source code in 64-bit we get errors?
To further illustrate just in case that wasn't clear:
A. Put all source files on search path. Compile program as 64-bit. ERRORS.
B. Open up supplied runtime .dproj from 3rd party library. Compile runtime library as 64-bit. Put outputted 64-bit DCU on search path. Compile program. Works fine.
Thanks
Edit: I'm going to be much more specific because it appears that i have failed in conveying what I'm trying to ask here.
We are using Clever Internet Suite 9.1 for Delphi.
We DO NOT use the design time package when compiling in 32-bit. We link directly to the source code through Delphi's search path. This works fine.
When I change my application to build as 64-bit We get this error:
[dcc64 Error] clSocket.pas(1971): E2089 Invalid typecast
A sample of the offending code (Slightly changed):
procedure cldostuff.WndProc(var Message: TMessage);
begin
if (Message.Msg = cl_const)
and (clSpecialType(Message).LookupHandle = FLookupHandle) then
begin
syncerror:= clSpecialType(Message).syncerror;
SetEvent(FCompleted);
end;
end;
The error is on the casting of the TMessage. I understand why TMessage would cause an error. I am not concerned about the error.
I am curious as to HOW compiling through a "package" works but not in DCU. Apparently I have misused the terminology of "Runtime package". I will post exactly what the clever developers told me on how to use in 64 bit.
The Clever Internet Suite fully supports 64-bit platform. The installer includes binaries for both 32-bit and 64-bit. Also, if you want to re-compile the library, you need to switch the platform option within the clinetsuite_x.dproj file, and recompile it (where _x depends on your Delphi version, e.g., in case of Delphi 10.3 Rio, the project file will be clinetsuite_103.dproj).
So I do Exactly that. I open up that .Dproj file and compile it. Once I do that it creates a Win64/Output folder that has ALL the dcus of the library. I can link to that and work in win64 bit just fine.
My questions is WHY does it work when I compile through the "Supplied .dproj file" but not when I compile through source code.
Hopefully I've done a better job of articulating what I am asking.
That compiler error is typically caused by a typecast between two value types of different size. If the code works in some compilation scenarios but not others then the obvious conclusion is that the record alignment options differ in those scenarios.
Most likely the package dproj file defines aligned records, i.e. {$ALIGN ON}. But your project does not. Perhaps it uses packed alignment, {$ALIGN 1}.
Make sure that all the units in the library are compiled with the same options as specified in the package dproj file. Typically that is done by the library providing an include file that specifies desired options and then the include file is included in all units. That insulates the code from compiler options specified in the host dproj file that are incompatible with those that the code requires.
You can add such a common include file since you have the source. In the longer term you should ask the developers of the library to make their code standalone and not require external specification of critical compiler options.

Delphi XE6 DLL: Unwanted export: TMethodImplementationIntercept

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.

How to use Delphi conditional compilation to generate exe or dll?

I am using Delphi XE2 and I have a program that can be compiled as Win32 EXE or ISAPI DLL. That works fine.
However my problem is how to conditionally compile.
{$include MyConditionals.Inc}
{$ifdef ISAPISERVER}
library
{$else}
program
{$endif}
MyProgram;
That works, but the FILE extension is getting wrong. It generates an EXE extension always. I need that when selected the library condition to have the DLL extension generated.
How can easily change the condition and have the right extension?
AFAIK you can't use a conditional compilation to change the extension of the binary. The extension of the file is set in the build process depending of the value (Application, Library, Console) for the AppType entry in the .dproj file. My recommendation is create a build batch file for the dll and another for the application.
Apparently, IDE itself is preventing you from doing that. I successfully produced both executable binary and dynamic-link library from the following source:
{$IFDEF CGI}program{$ELSE}library{$ENDIF} test;
begin
end.
using dcc32 -DCGI test.pas and dcc32 -DNSAPI test.pas commands.
Delphi IDE thinks what it "owns" the project source, so it is advised against placing conditional directives there even in newer MSBuild-based IDEs.

Loading a Delphi Object Run Time using BPL

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

Resources