I want to consume c obj files in delphi xe3.
When linked obj files, shows this error:
`[dcc32 Error] Unit1.pas(149): E2065 Unsatisfied forward or external declaration: '_exit'`
can i implement _exit function?
Yes you can indeed do this. Typically you will link the .obj file to a single unit in your project. Implement the exit function in that unit and the Delphi linker will find it.
....
implementation
....
{$LINK foo.obj}
procedure _exit(status: Integer); cdecl;
begin
// your implementation goes here
end;
As I've illustrated this you place the function in the implementation section of the unit. It does not need to be visible externally to the unit.
You might have multiple different units that link to C objects, in which case you can place your C runtime functions, like exit, in a single unit, and use that from each other unit that links to C objects. In that scenario then you need to expose each function in the interface section so that the linker can see the function.
Related
I have a project that has two forms that have the same name. I need to use one or the other. I assumed I could use an IFDEF to differentiate between them but I find I can't add both of them into the project without the compiler complaining. My uses clause looks like this.
uses
uFileManager, uMount, uSkyMap, uAntenna,
{$IFDEF SDR}
uSDR,
{$ENDIF}
{$IFDEF R7000Serial}
uR7000,
{$ENDIF}
uDatabase;
{$R *.dfm}
Both the 'uSDR' and the 'uR7000' units have a form named 'Receiver' in them. When I attempt to add 'uR7000' unit the project I get:
"The project already contains a form or module named Receiver"
How can I add both units to a project?
First of all, it's not the compiler complaining but the IDE.
The compiler doesn't care if you have forms - or other types - with the same name as long as they are in different units. A famous example from the VCL was the presence of two TBitmap types, one in Graphics the other in Windows. If you ever need to be explicit as to which type you mean, you simply qualify the type name in the code and the compiler does as it's told.
bmpA: Graphics.TBitmap; // bmpA is a TBitmap as defined in the Graphics unit
bmpB: Windows.TBitmap; // bmpB is a TBitmap as defined in the Windows unit
No problem there.
However, the persistence framework in Delphi does care if you have persistent classes with the same name since the persistence framework identifies types only by their unqualified name.
This is why every third party component framework for Delphi uses a prefix on their class names. It's not just vanity or fashion. It ensures that a component in one library cannot be confused (by Delphi persistence mechanisms) with another from a different library if both libraries are used in the same project.
Bottom line: Stick to unique names for your forms and find some other way to distinguish or switch between them if/as needed.
Precisely how to then go about managing your reference to which particular form is in use is difficult to suggest without further details about your project. You might derive both from a common base class or you might define an interface for each to implement.
For example (and this is just an illustrative sketch, not a recommendation or fully worked solution):
// Define the interface that your Receiver implementations
// must satisfy. This might include returning a reference to the implementing form.
//
// e.g. in a unit "uiReceiver"
type
IReceiver = interface
function Form: TForm; // returns the form using the common base type, not the specific implementation class
end;
// in unit uSDR
TfrmSDRReceiver = class(TForm, IReceiver)
..implements IReceiver as well as your SDR specific needs
end;
// in unit u7000
TfrmR7000SerialReceiver = class(TForm, IReceiver)
..implements IReceiver as well as your R7000 Serial specific needs
end;
// In uReceiver (some unit to "resolve" the receiver)
interface
uses
uSDR,
uR7000;
type
TReceiver = class
class function GetReceiver: IReceiver;
end;
implementation
class function TReceiver.GetReceiver: IReceiver;
begin
{$ifdef SDR}
result := frmSDRReceiver;
{$endif}
{$ifdef R7000}
result := frmR7000SerialReceiver;
{$endif}
end;
end.
Your application code then uses the uReceiver unit (and uiReceiver if you want to refer to the interface type, e.g. in a variable declaration) and accesses the particular Receiver implementation through the static class provided, e.g.:
uses
uReceiver;
implementation
uses
uiReceiver;
..
var
rcvr: IReceiver;
begin
rcvr := TReceiver.GetReceiver;
rcvr.... // work with your receiver through the methods/properties on the interface
// You can also work with the receiver form, accessing all aspects
// common to any TForm via the Form function on the interface (assuming
// you chose to provide one):
rcvr.Form.Show;
..
end;
I have a dll which defines a simple functions to show a message:
library testdll;
uses SysUtils, Classes, Dialogs;
{$R *res}
procedure ShowDll;stdcall;
begin
ShowMessage('ShowDLL testdll.dll');
end;
exports ShowDLL;
begin
end.
And my main file call this dll dynamicly using this procedure:
i defined a new type:
type
testdll = procedure;stdcall;
Then on my button click event:
procedure TForm1.Button1Click(Sender:TObject);
var
dllHandle: THandle; //Don't use Cardinal; it's limited to 32-bits
test : testdll;
begin
dllHandle := LoadLibrary('testdll.dll');
if dllHandle <> 0 then
begin
#test := GetProcAddress(dllHandle,'ShowDLL');
if Assigned(test) then
ShowDLL
else
ShowMessage('Func not found');
end
else
ShowMessage('dll not found');
end;
This works. But I don't know if it's possible to handle not defined functions with my dll. My purpose here is to call a function without knowing if it will be defined in my dll. So i would like the dll to tell me if the functions exists or not.
For example here i only have a ShowDLL procedure. If i call another method which does not exists it will show 'Func not found' from my main application. But i would my dll to tell me this. Is this possible? If yes, how could i achieve this pls?
EDIT: I can't modify the main function this is only a test. In my final version there will be only the dll. So exporting all functions into my main application is not possible here. That's why i want to know id the dll alone can handle it rather than doing this in my main application which i can't do.
I don't have acces to the main application to modify any code in it. I only know what are functions that will be used in this application that i will later export in my dll using exports statement. So what i try to achieve is to catch a not defined function with the dll if it's possible.
Your code already demonstrates how to detect the presence of an export. Namely to call GetProcAddress and compare the result with nil.
You can reduce the amount of boiler plate code by using delay loading. This essentially lets the compiler generate the code the performs the checks. This relies on the delayed keyword.
procedure testdll; stdcall;
external 'testdll.dll` delayed;
When you call this function, if it cannot be found, an exception is raised. Indeed this behaviour can be customised, as described in the documentation: http://docwiki.embarcadero.com/RADStudio/en/Libraries_and_Packages#Delayed_Loading
Update
In a comment to this answer you state that the executable cannot be changed. In which case, the message that you wish to avoid will be shown if the function is missing. You ask if the missing export can be handled by the DLL but that is not possible. When you call GetProcAddress, no code inside the DLL is executed. All the processing is done external to the DLL by reading its PE metadata.
The obvious conclusion is that the DLL must export the function. If the true DLL does not, put another DLL in its place. Use an interposer DLL that exports the function. Implement the function by delegating to the true DLL, if the true DLL exports the function. Otherwise do something else, whatever you please.
I work on Delphi project who interac with many other small libraries.
I use FastMM4 and I would like work with complex classes passed on dll parameter.
So for exemple I send my form to my dll. Into the dll I test the type of parameter with the operator "IS".
But into the Dll the operator "IS" return always "false"
Exemple
library Dll;
uses
FastMM4,
System.SysUtils,
System.Classes,
Vcl.Dialogs,
Vcl.Forms;
{$R *.res}
procedure Complex(L : TObject);stdcall;
begin
if L is TForm then
showmessage('Ok')
else
showmessage('Pas ok') ;
if L is TCustomFrame then
showmessage('Ok')
else
showmessage('Pas ok')
end;
exports
Complex;
begin
end.
And the call
procedure TffsIsOperator.Button2Click(Sender: TObject);
var
MaDLL : THandle;
Proc : procedure (l : TObject);
begin
try
MaDLL := LoadLibrary(PChar('Dll.dll'));
#Proc := GetProcAddress(MaDLL, 'Complex');
Proc(self);
finally
FreeLibrary(MaDLL);
end;
end;
Firstly, you have a calling convention mis-match. You must fix that by making the calling convention the same on both sides of the interop boundary.
Even when you fix that, the apparent misbehaviour of the is operator is to be expected. You have two instances of the VCL in your process. One in the host and one in the DLL. They each have distinct versions of the classes defined in the VCL. So, the DLL's TForm is a different class form the TForm in the host. And that is why is evaluates false.
The traditional way to handle this is to arrange that you only have one instance of the RTL/VCL in your process. And you achieve that through the use of runtime packages.
If runtime packages are not a viable option for you, and you must use a DLL, then you will have to give up passing any Delphi classes across the DLL boundary. I fully expect this to be unwelcome news, but that is just how it is. You cannot pass TObject instances across a DLL boundary and attempt to call methods, query type identity, etc. That is simply not supported for DLLs. Only for runtime packages.
So, if you have to use DLLs then you need to stick to simple types. Integers, floating point values, character types, arrays (but not dynamic arrays), records, pointers to such types, interfaces. As a simple rule of thumb, if you cannot find an example of your proposed interop in Win32, then it is probably invalid.
I need to create a dll within fpc (delphi-mode). It works fine - but for some reasons, I want to do something (in a unit) like
function doSomeThing(a:type1):type2;stdcall;
function doSomeThing(a:type3):type4;stdcall;
and in the library (for building the dll using the unit above)
exports
doSomeThing(a:type1) name 'doSomeThingTYPE1',
doSomeThing(a:type3) name 'doSomeThingTYPE3';
The syntax is self explanatory and is told in How to export Overload functions from DLL? . But it seems to be unavailable in fpc (version 2.6.0-9 [2013/04/14] for x86_64). Is there a chance to do something like that - or do I have to rename the functions within my source?
The question that you link to discusses Delphi. The syntax that Delphi supports, that allows you to export overloaded functions, is not supported by FPC.
To the best of my knowledge, overloaded functions are not exportable. Although, I could easily be wrong on that score. Perhaps there is a way, as Marco proposes in his answer.
David consulted me in another thread, I devised something that compiles, but don't know if it works.
It is based on exporting the function using a defined linker level identifier, and then declaring an external function reimporting it with different Pascal names. Note that bla and bla2 doesn't even have to be in the same unit as dosomething variants.
library testdll;
{$mode delphi}
type
type1=integer;
type3=char;
type2=smallint;
type4=widechar;
function doSomeThing(a:type1):type2;stdcall; overload; [public, alias:'bla'];
begin
result:=a+1;
end;
function doSomeThing(a:type3):type4;stdcall; overload; [public, alias:'bla2'];
begin
result:=widechar(ord(a)+1000);
end;
procedure bla; external name 'bla';
procedure bla2; external name 'bla2';
exports
bla name 'doSomeThingTYPE1',
bla2 name 'doSomeThingTYPE3';
end.
I am complete new to pascal.
I want to call my function in .dll file in free pascal and I get following error when I run the project:
The procedure entry point GetProcAddress could not be located in the dynamic link library HNLib.dll.
here is the code:
Program Test;
function GetProcAddress : Integer; cdecl; external 'HNLib.dll';
function GetProcAddress : Single; cdecl; external 'HNLib.dll';
procedure GetProcAddress( X : Single); cdecl; external 'HNLib.dll';
procedure GetProcAddress; cdecl; external 'HNLib.dll';
begin
GetProcAddress( 5.5 );
readln;
end.
.pas file and dll are in one directory.
Please Help ME!
GetProcAddress is not what you seem to think it is; it's purpose is to locate named procedures or functions in a DLL and return the address of that function so it can be called from your code. You have to first use LoadLibrary to load the dynamic link library (DLL) into memory, and then pass a handle to that DLL as the first parameter of GetProcAddress and the name of the function whose address you want as the second parameter. If the function can be found in the DLL, it's address is returned, and you can use that address to call the function.
(In addition, GetProcAddress is pretty Windows-specific, and the majority of functions in the WinAPI are stdcall and not cdecl. Unless you have documentation saying that the functions are using the cdecl calling convention, you should probably use stdcall.)
You would also need at least the Windows unit in your uses clause, since that's where GetProcAddress and LoadLibrary are declared.
See the WinAPI documentation on LoadLibrary and GetProcAddress for more information.
For a beginning programmer, you'll probably find it easier to use static linking of the functions instead of dynamic (which you get with GetProcAddress). An example of static linking would be (untested !!!- just a quick code example, since I don't have 'HNLib.DLL' to link against):
// Your Dll import unit
unit MyDllProcs;
interface
function GetIntCalcResult(const IntVal: Integer);
implementation
function GetIntCalcResult(const IntVal: Integer); stdcall; external 'HNLib.dll';
end.
// Your own app's code
program Test;
interface
uses MyDllProcs;
implementation
function DoSomethingWithDll(const ValueToCalc: Integer): Integer;
begin
Result := GetIntCalcResult(ValueToCalc);
end;
begin
WriteLn('DoSomethingWithDll returned ', DoSomethingWithDll(10));
ReadLn;
end.
Note that when statically linking DLL functions like this, your DLL must be available when your app starts, and the function must be contained in that DLL; if not, your application won't load.
Also, note that you can't typically have multiple functions with the same name in the DLL, as there's no information available to use to figure which one to load when the load is being done. Each should have a separate, distinct name or the loading will probably fail.