• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 261
  • Last Modified:

How do I call Dll functions (Written in C)

I would like to call functions from a .dll compiled in C.
I have the .dll itself and the .h file.
I understand I have to write my own .pas file that will include the interface to the .dll.
What shold be the format of the functions there?
How do I use callback functions in that .dll - specifically, how do I send a pointer of one of my (delphi) functions to that .dll?
0
tommyq
Asked:
tommyq
  • 4
  • 4
  • 3
  • +2
1 Solution
 
erajojCommented:
Hi,
Usually, you would use stdcall, like:
  function ext(value: Integer): Integer; stdcall; external 'mydll.dll' name 'Extfunc';

A pointer to the above function is "@ext".

If you find this troublesome;
send us the .h-file and we will have a look.

/// John
0
 
erajojCommented:
Hi,
Usually, you would use stdcall, like:
  function ext(value: Integer): Integer; stdcall; external 'mydll.dll' name 'Extfunc';

A pointer to the above function is "@ext".

If you find this troublesome;
send us the .h-file and we will have a look.

/// John
0
 
erajojCommented:
Whooah! My first doublepost ever... ;-)

/// John
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
tommyqAuthor Commented:
Thanks erajoj for the prompt reply.
Let me try and use your double experies in C and Delphi.

Here is the function declerations from the .h file
/*
 * Functions prototypes.
 */
V_NODE __declspec(dllexport) initHeart ( char *heart_fname );
int    __declspec(dllexport) traverseTree ( void *(* callback)( void *x, void *y ), V_NODE tree );
V_NODE __declspec(dllexport) getNextVertex ( V_NODE v, int new_x, int new_y );
void   __declspec(dllexport) getData ( double *V0p, double *total_distp, V_NODE *current_nodep );
void   __declspec(dllexport) destructHeart ( V_NODE *root );
int      __declspec(dllexport)      TestDll ();

VNode is a struct with doubles and pointers.
1. Is this the right way to export the functions?
2. Could you give me an exmple for an apropriate decleration of the function traversTree which recieves a pointer to a callback function?
3. what should be the pascal decleration of the function that is being sent to traverse tree?

Thanks,
Tommy
0
 
DPedrelliCommented:
interface
function FunctionName(Param1: type; Param2: type): type; stdcall;
implementation
function FunctionName; external; 'DLLName.dll'; name 'CallNameInDelphi';

You may have to check the calling convention but stdcall is standard in C functions.  After the name directive, replace CallNameInDelphi with the name you want to use to call the function in Delphi.
Hope this helps.
David.
0
 
tommyqAuthor Commented:
DPedrelli, Sorry for the rejection. I need some more info.

For example, how would I send the C code pointers to my functions, pointers to strings (char * in C = Pchar in Delphi).
How should I store pointers I receive from the called C function?
0
 
BoRiSCommented:
tommyq

As far as I know you need to use extern or a full function

       eg. of extern

       extern "C" {
       int _EXP MyFunc (int i)
       {
         return (i+10);
       }
       }

       or the function using cdelc

       function MyFunc(i: integer): integer; cdecl; far; external 'MYDLL' index 12;

       you can declare the functions with FAR PASCAL and then call the function in the        normal way.

       If there are problems, make sure that you declare the DLL functions with "_loadds".         Remember that, normally, a DLL function
       runs on the caller's DS, unless you specifically load the correct one.
Later
BoRiS
0
 
LischkeCommented:
Hi Tommy,

if you always keep in mind that the calling convention in C and Delphi are different then the solution isn't hard to find:

1) function declarations in your interface unit
- V_NODE __declspec(dllexport) initHeart ( char *heart_fname );

   function InitHeart(heart_fname: PChar): V_NODE; cdecl;

- int    __declspec(dllexport) traverseTree ( void *(* callback)( void *x, void *y ), V_NODE tree );

    function traverseTree(Func: TTraverseCallback; Tree: V_Node): Integer; cdecl;

- V_NODE __declspec(dllexport) getNextVertex ( V_NODE v, int new_x, int new_y );
    function GetNextVertex(V: V_Node; New_X, New_Y: Integer): V_NODE; cdecl;

- void   __declspec(dllexport) getData ( double *V0p, double *total_distp, V_NODE *current_nodep );
   procedure GetData(var VOp, total_siatp, current_nodep: Double; cdecl;

- void   __declspec(dllexport) destructHeart ( V_NODE *root );
   procedure destructHeart(root: PV_NODE); cdecl;

- int __declspec(dllexport) TestDll ();
    function TestDLL: Integer; cdecl;

PV_NODE is, as you surely already know a pointer to a V_NODE. The pointers to the double values in GetData can also be PDouble (pointer to double) in case you don't want to use the var key word. But since these parameters seems to be used to pass data back the declaration I've given is appropriate.

2) Specifying implemenation:

const HeartDLL = 'Heart.DLL';

function InitHeart(heart_fname: PChar): V_NODE; cdecl; external HeartDLL;
function traverseTree(Func: TTraverseCallback; Tree: V_Node): Integer; cdecl; external HeartDLL;
function GetNextVertex(V: V_Node; New_X, New_Y: Integer): V_NODE; cdecl; external HeartDLL;
procedure GetData(var VOp, total_siatp, current_nodep: Double; cdecl; external HeartDLL;
procedure destructHeart(root: PV_NODE); cdecl; external HeartDLL;
function TestDLL: Integer; cdecl; external HeartDLL;

If you use exactly the same names in Delphi as they are declared in C (case sensitive!) then you don't need to specify the names again in the external clause.

3) Callback definition:
type TTraverseCallback = function(X,Y: Pointer): Pointer; cdecl;

4) callback implementation:

function TraverseCallback(X, Y: Pointer): Pointer;

begin
  // do something
  Result:=MyValue;
  // etc.
end;

Use then

traverseTree(TraverseCallback,TheNode);

to actually traverse the tree.

If you don't have the source for the DLL then you should expect that there also could be used the stdcall calling convention (as it is used in all system DLLs). If you encounter access violations then try stdcall instead of cdecl.

The memory for the value passed to InitHeard can simply be gotten by declaring a String variable and calling:

MyNode:=InitHeart(PChar(AName));

with

var AName : String;

Anymore questions? Just ask :-)

Ciao, Mike
0
 
LischkeCommented:
Ooops,

found some typos in the text (the input window here is horrible...).

to 4) the function must also be declared with cdecl

GetData needs a closing parenthesis before cdecl

Ciao, Mike
0
 
tommyqAuthor Commented:
Mike,

Thanks for your ELABORATED answer. It is amazing how an expert can help when you are desperate.
I will check it out and let you know.

Thanks again,
Tommy
0
 
tommyqAuthor Commented:
Mike,

Thanks.
It worked.
You are great.

Tommy
0
 
erajojCommented:
Mike, impressive answer!
If we had an "achiever of the month" award, I would vote for you this month. :-)

/// John
0
 
LischkeCommented:
;-)
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 4
  • 4
  • 3
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now