Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2015-03

how to use procedure of object in C

9 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Xiangrong Fang

Hi all,

I define a procedure like this:

type
  TDataHandler = procedure(data: Pointer) of object;
procedure SetHandler(h: TDataHandler); external cdecl;

Now, can I implement SetHandler in a library written in C, then call h in C?

Thankyou.

Sent from Gmail Mobile

Reply by email

Michael Van Canneyt
to Xiangrong Fang
Xiangrong Fang wrote 9 lines
Hi all, I define a procedure like this: type   TDataHandler = procedure(data: Pointer) of object; procedure SetHandler(h: TDataHandler); external cdecl; Now, can I implement SetHandler in a library written in C, then call h in C?

IMHO Not without separate assembler code for each CPU.

Michael.

Reply by email

OBones
to Michael Van Canneyt
Michael Van Canneyt wrote 18 lines
On Mon, 9 Mar 2015, Xiangrong Fang wrote: > Hi all, > I define a procedure like this: > > type > TDataHandler = procedure(data: Pointer) of object; > > procedure SetHandler(h: TDataHandler); external cdecl; > > Now, can I implement SetHandler in a library written in C, then call > h in C? IMHO Not without separate assembler code for each CPU. Michael.

How about using TMethod?

procedure DataHandler(DummySelf: Pointer; data: Pointer);
begin
   // do what you want to do, DummySelf is always nil.
end;
var
   Method: TMethod;
begin
   Method.Data := nil;
   Method.Code := @DataHandler;
   SetHandler(TDataHandler(Method));
end;

Reply by email

Michael Van Canneyt
to OBones
OBones wrote 34 lines
Michael Van Canneyt wrote: > > > On Mon, 9 Mar 2015, Xiangrong Fang wrote: > >> Hi all, >> I define a procedure like this: >> >> type >> TDataHandler = procedure(data: Pointer) of object; >> >> procedure SetHandler(h: TDataHandler); external cdecl; >> >> Now, can I implement SetHandler in a library written in C, then call h in >> C? > > IMHO Not without separate assembler code for each CPU. > > Michael. How about using TMethod? procedure DataHandler(DummySelf: Pointer; data: Pointer); begin // do what you want to do, DummySelf is always nil. end; var Method: TMethod; begin Method.Data := nil; Method.Code := @DataHandler; SetHandler(TDataHandler(Method)); end;

You must be sure that self is passed in the correct register. I am not sure this is the case if you declare it as an extra argument. It may be so, but compiler people should confirm this. I don't think you can take it for granted.

Michael.

Reply by email

Ewald
to Michael Van Canneyt
Michael Van Canneyt wrote
You must be sure that self is passed in the correct register. I am not sure this is the case if you declare it as an extra argument.

It is, as long as the `self` is the first parameter. Same goes for `Class Procedure XXX;` kind of declarations (in constrast to `Class procedure XXX; static;`).

I don't know how long that is going to last however (since this hidden parameter thingy is an implementation detail of the compiler I think). So I fully agree: it would be a kindness of the compiler people to confirm this :-)

Ewald

Reply by email

Xiangrong Fang
to OBones: How about using TMethod? procedure DataHandler(DummySelf: Pointer; data: Pointer); begin…

2015-03-10 0:33 GMT+08:00 OBones :

Show quoted text 16 lines
How about using TMethod? procedure DataHandler(DummySelf: Pointer; data: Pointer); begin // do what you want to do, DummySelf is always nil. end; var Method: TMethod; begin Method.Data := nil; Method.Code := @DataHandler; SetHandler(TDataHandler(Method)); end;

​I'm not sure how this works, but it seems that you are deliberately converting a normal procedure to a method. What I want is exactly opposite
- I want to convert a method to a normal procedure.

If I define the interfact of DataHandler like this:

​TDataHandler = procedure(data: Pointer); cdecl;

It is very easy to use in an so, no matter it is written in C or pascal.

But the problem is, I want to do this:

SetHandler(h);

where h is a METHOD, not a normal procedure​.

Because I want to use the handler wrapped in my Class.

However, like in my first mail, if I define THandler a procedure of object, it makes easier to SetHandler(AMethod); but how can I use that "procedure of object" pointer in the so?

Thanks!

​

Reply by email

Michael Schnell
to Xiangrong Fang: I define a procedure like this: type TDataHandler = procedure(data: Pointer) of object;…
Xiangrong Fang wrote
can I implement SetHandler in a library written in C, then call h in C?

For inter-language calls you obviously need to to define the calling style on both sites. e.g. "STDCALL" or "PASCAL", to make both use compatible calling conventions.

I don't know if/how such keywords exist for "procedure of object" style of functions (and hence for the types of the variables pointers to them are stored in).

If not you should use a "flat" calling scheme: on both sites use standard (non-object) functions with e.g. "STDCALL" (adding/extracting the Self pointer explicitly on the way, if appropriate). Regarding variables for holding (pointers to) such functions they need to be a record of a (flat) function pointer plus a Self pointer.

This said, you can't (easily) pass objects to a C library, anyway, as the memory management is not synchronized by default. Like with Pascal Strings, a e.g. Free will lead into chaos.

-Michael

Reply by email

OBones
to Xiangrong Fang: 2015-03-10 0:33 GMT+08:00 OBones : ​I'm not sure how this works, but it seems that you…
Xiangrong Fang wrote
However, like in my first mail, if I define THandler a procedure of object, it makes easier to SetHandler(AMethod); but how can I use that "procedure of object" pointer in the so?

It works the same, cast the data you receive to a TMethod and call the "code" member with the appropriate parameters. So, in the "C" library do this:

typedef struct
{
   Data: Pointer;
   Code: Pointer;
}TMethod;
void SetHandler(TMethod h);
{
   StoredH = h;
}
typedef void (*TDataHandler)(void* Self, void* Data);
void DoSomething();
{
   ((TDataHandler)(StoredH.Code))(StoredH.Data, SomeData);
}

Warning, this is pseudo code, you should adapt it so that it can compile.

Reply by email

Jonas Maebe
to OBones
OBones wrote 8 lines
Xiangrong Fang wrote: > However, like in my first mail, if I define THandler a procedure of > object, it makes easier to SetHandler(AMethod); but how can I use > that "procedure of object" pointer in the so? > It works the same, cast the data you receive to a TMethod and call the "code" member with the appropriate parameters. So, in the "C" library do this:

Note that you have to make sure that you declare your "procedure of object" as "cdecl" in that case, and as a result you'll also have to declare all methods that you want to assign to this procvar as "cdecl".

Jonas

Reply by email