PDA

View Full Version : Delphi libs can be used in C++ ?



arthurprs
23-10-2007, 07:50 PM
The lib Have some classes, but the rest is very simple :?

it can be done?

arthurprs
24-10-2007, 04:30 PM
i need some help here :( :?

I think classes in C++ are not compatible with Pascal classes,
what i will need to do?

JernejL
24-10-2007, 04:33 PM
use plain objects or records.

chronozphere
24-10-2007, 05:17 PM
You can always make a DLL and make it C++ compatible

You cannot use dynamic array's and most string types (Use PChar instead). You cannot use pascal classes either. If you want your library to be a little more Object oriented you can also use Interfaces (derived from IUnknown). That way you can make C++ compatilbe API's with pascal :)

P.S: all exported DLL routines need STDCALL calling conventions :)

arthurprs
24-10-2007, 05:42 PM
use plain objects or records.

Appers to be same as C++ libs -> delphi,

i was writing irrlang headers to pascal using ""Flattening" the object" model, but i stoped, there are many better libs around already converted to pascal,

i have some doubts,

how can i generate a .lib of a delphi dll ?

i will use type def to define a own type of void type, and pass it on a argument to the exported plain functions of the class?

Thill will work?


typedef void Psomeclass;
// i will need more coding to import the functions here, but this is just an example
Psomeclass Psomeclass_create(void)
void Psomeclass_dosomething(void handle)



type
Psomeclass = ^TsomeClass;
TsomeClass = class
public
procedure dosomething;
constructor create;
end;

constructor Tsomeclass.create;
begin
// CONSTRUCTOR
end;

procedure Tsomeclass.dosomething;
begin
// DO SOMETHING
end;




function Psomeclass_create: Psomeclass; stdcall;
begin
result := @TSomeclass.create;
end;

procedure Psomeclass_dosomething(handle : Psomeclass); stdcall;
begin
handle.dosomething;
end;

exports
Psomeclass_dosomething, Psomeclass_create;

~chronozphere:
Yeah im very interested in OO, but i don't know what is interfaces ;p
can you give me more details?


sorry my english :?

Mirage
24-10-2007, 05:56 PM
I'm afraid that if you want to create an object oriented library in Delphi to use from C++ you will need to create something similar to COM objects. :shock: Like DirectX and so on.
So start to learn interfaces. They are necessary to create COM objects. :roll:

arthurprs
24-10-2007, 07:44 PM
I read some things about interface, its like an skeleton for classes, them i create a real class from it that implements all its functionalities;

all right in pascal but how i will import that on C++ ?

chronozphere
24-10-2007, 10:35 PM
First you have to learn C. :roll: :razz:

You must translate the interface, type and constant definitions to a C and assemble them in a C header. This will be the import header for your library, and it should contain all datatypes, constants, interfaces etc etc, that are needed to work with your library.

Then the user can e.g Call The "MyEngine_Init" routine that is defined in that header to initialize the library and start working with it:)

First step is to learn how to create DLL's with exported functions, after that, learn how to use interfaces for Application <-> DLL communication. And finally, learn some C++ so you can make a C header for your lib.

Good luck ;)

arthurprs
25-10-2007, 02:06 AM
First you have to learn C. :roll: :razz:

You must translate the interface, type and constant definitions to a C and assemble them in a C header. This will be the import header for your library, and it should contain all datatypes, constants, interfaces etc etc, that are needed to work with your library.

Then the user can e.g Call The "MyEngine_Init" routine that is defined in that header to initialize the library and start working with it:)

First step is to learn how to create DLL's with exported functions, after that, learn how to use interfaces for Application <-> DLL communication. And finally, learn some C++ so you can make a C header for your lib.

Good luck ;)

so use dynamic loading insted of static, good, i will don't need .lib's :P

I know a descent level of C++ programming, nothing that some google don't solve

I already have writed all structs, types and consts to the .h
but the main code still blank =/

after some research
i noticed that best way, is to work with full abstract classes, i will make some tests

PS: im getting confused, you are giving me some good tips but i still have unanswered questions :(

chronozphere
25-10-2007, 04:39 PM
PS: im getting confused, you are giving me some good tips but i still have unanswered questions


Okay... I guess you need to tell me agian, what you want to know :)



how can i generate a .lib of a delphi dll ?


I don't really know what i lib is (i think it has to do with Linux), but i don't think you can do that.
Just using the DLL will be sufficient (unless you want your application to work on Linux or Mac).



i will use type def to define a own type of void type, and pass it on a argument to the exported plain functions of the class?


Sorry, i don't completely understand the question :? Maybe you can rephrase it?

JernejL
25-10-2007, 04:40 PM
P.S: all exported DLL routines need STDCALL calling conventions :)

don't be uninformed.. you can use ANY calling convention, as long as they match in C and pascal, most libraries actually use cdecl.

Pyrogine
25-10-2007, 05:25 PM
Hi, maybe you can try this:

1. Create a class in Delphi with all virtual methods. Use STDCALL for compatibility.

2. Create the same class in C++ with all virtual methods. Make sure the methods are in the same order. Again, use STDCALL.

3. Export a routine in the Delphi DLL to create/destroy instances of your classes. In my implementation I pass an integer ID to tell which class I want.

4. Pass the pointer of the C++ class in and it will return a fully qualified object that you can then use in C++ or any language that supports standard COM.

5. When your done, pass the object pointer to the destroy routine to free the class instance. (needed because of memory management and DLL boundary issues)

6. This works because Delphi supports COM which means the VMT (virtual method table) is binary compatible (laid out in memory the same) with the VMT of the C++ class.

7. What I've also done too was to export these interfaces out of the DLL and on the host side wrap them up (in this case Delphi classes) in classes so that I can extend them just like a normal class.

This gives you a lightweight (and much easier) COM across different languages. There are a number of articles on the NET about this concept for more information.

Hope this helps.

arthurprs
25-10-2007, 06:16 PM
chronozphere:~
.lib are a file that C/C++ compilers use for static linking, and its required on win

pyroengine:~
im not returning an int, but the class pointer, take a look at the demo, returning a int is best?

i don't know how create them from an existing dll, so im now using dynamic loading to avoid using them

i will use pure virtual classes, easy and works well

after some search and some tests its done
http://www.mediafire.com/?5bd9ydbj992
(60kb demo including binary and source)

again sorry my english

Pyrogine
25-10-2007, 06:33 PM
The ID is the integer id of the class you wish to create. So you only have to export two routines from you DLL. If you have a CreateInterface type routine where you pass the ID and it will create an instance of the object and return it to the calling application. Like such:
procedure CreateInterface&#40;aIID&#58; Integer; var aObj&#41;; stdcall;
begin
case aIID of
0&#58; TMyClass0&#40;aObj&#41; &#58;= TMyClass0.Create;
1&#58; TMyClass1&#40;aObj&#41; &#58;= TMyClass1.Create;
end;
end;

procedure DestroyInterface&#40;var aObj&#41;; stdcall;
begin
FreeNilObject&#40;aObj&#41;;
end;

You now have a factory that can create and return any of the interfaces you support.

arthurprs
25-10-2007, 06:36 PM
I was saying that you only have to export two routines from you DLL. If you have a CreateInterface type routine where you pass the the ID and it will create an instance of the object and return it to the calling application. Like such:
procedure CreateInterface&#40;aIID&#58; Integer; var aObj&#41;; stdcall;
begin
case aIID of
0&#58; TMyClass0&#40;aObj&#41; &#58;= TMyClass0.Create;
1&#58; TMyClass1&#40;aObj&#41; &#58;= TMyClass1.Create;
end;
end;

procedure DestroyInterface&#40;var aObj&#41;; stdcall;
begin
FreeNilObject&#40;aObj&#41;;
end;

You now have a factory that can create and return any of the interfaces you support.

sorry my english, now i understand :oops:

a very good tip! Thanks :)


Edit: i don't understand the "var aObj" where is the type ?

Pyrogine
25-10-2007, 06:46 PM
NP, glad to help.

Note: if you get an AV on the C++ side or if you find that when you call a C++ method it seems to be calling the wrong method from the DLL side, keep in mind the the order and number of virtual methods much match (you do not have to have all of them, but down to the one you are calling must match). Remember that TObject defines a few virtual methods by default where as a C++ class does not. So you may have to create a few dummy methods on the C++ side. Look at the TObject class implementation in the System.pas unit for the version of Delphi you are using. The latest version of Delphi (d2007) has I think 3-4 virtual methods in TObject including Destroy. So keep this in mind if you have problems on the C++ side.

Pyrogine
25-10-2007, 06:55 PM
var aObj allows you to pass any type as a variable parameter. Otherwise the compiler will complain about the wrong types. This is the same technique used by the FreeAndNil routine. If the param for this routine was a TObject type for example it would complain saying the types much match for a var param when you tried to FreeAndNil any type of class other than TObject.

When you pass a var param you are able to make changes to inside the routine which is what we will be doing. So to prevent bad things from happening the compiler make sure the types match. By specifying an unknown type, you are saying, bypass strict type checking and I will be responsible for the object types myself.

arthurprs
25-10-2007, 08:25 PM
NP, glad to help.

Note: if you get an AV on the C++ side or if you find that when you call a C++ method it seems to be calling the wrong method from the DLL side, keep in mind the the order and number of virtual methods much match (you do not have to have all of them, but down to the one you are calling must match). Remember that TObject defines a few virtual methods by default where as a C++ class does not. So you may have to create a few dummy methods on the C++ side. Look at the TObject class implementation in the System.pas unit for the version of Delphi you are using. The latest version of Delphi (d2007) has I think 3-4 virtual methods in TObject including Destroy. So keep this in mind if you have problems on the C++ side.

Is there something that i can do to avoid that?

Pyrogine
25-10-2007, 10:13 PM
If you use TObject (class) you will have to deal with the dummy methods because as I've stated, TObject automatically defines a few virtual methods. But, you can use the old object declaration rather than class, then you do not have to worry about the dummy methods.

TMyClass = class vs. TMyClass = object

NOTE, the old object interface is not guaranteed to be around in future version of Delphi so you have use at your discretion. You loose some benefits but like I said, there are no default virtual methods defined so it will be 1 to 1 like a pure virtual c++ class.

You can also use interfaces (TMyClass = interface) which is very easy to do in Delphi as interface support is build into the language, but it gets hairy and narley on the C++ side.

If you do use interfaces, then what I've done is to disable automatic reference counting by overriding AddRef/Release to do nothing in my base interface class. Then I can build a hierarchy of interfaces just like you would do a normal class and continue to use deterministic destruction. In this case, I was using Delphi on both sides.

But all you have to do is add the dummy methods to your c++ base class once. No big deal compared to what you gain, but yes they will be there and if someone tries to call one of them it will call the methods that corresponds to the ordered ones on the Delphi side.

So in summary:

1. You can use pure virtual methods using class - you have to deal with the dummy virtual methods on the host side.

2. You can use pure virtual methods using object - it will be 1 to 1 on the c++ side, but you loose all the automatic stuff of TObject.

3. You can use pure interfaces - easy to do on Delphi side, kinda of a pain to setup/use on the c++ side. You have to use macros and other shenanigans.

4. You can export flatten methods from the dll - easy and simple, but when the number of routines become large it becomes a pain to manage.

Over the years I've tried each one and various combinations. All have pros and cons. You have to decide which one will work for you. It would be so much easier if Delphi had better support for this. Sure packages, but its those HUGE run-time DLLs that I don't want to distro with my games. RTL + VCL package dll become larger than some of our downloadable games. Arrrg. I've been struggling with these problems for a long time. If you put the RTL and VCL into your own package and link to it at run-time, fine, but then your run-time package can not be used with other packages as the same units can not exist in multiple packages. Again, arrrg. So.... *sigh* you have pick something that works for you and go with it.

arthurprs
26-10-2007, 12:50 AM
C++ are good but some things makes me hate it :evil:

i will stay with "1. You can use pure virtual methods using class - you have to deal with the dummy virtual methods on the host side. "

i just need to declare create, destroy etc.. on the c++ class ?

thanks for your attention you are giving me a HUGE help

Pyrogine
26-10-2007, 01:16 AM
NP, I struggled with these problems too so happy to share the stuff I've learned about it.

1. You just need to export CreateInterface/DestroyInterface routines from your Delphi made dll, such as I outlined above.

2. You need to dynamically load this DLL on the c++ side (use LoadLibrary) and bind to these two routines.

3. Define the interface class on the C++ side and pass a pointer to this class to CreateInterface:
CMyClass *myclass;

// create object instance
CreateInterface&#40;0, &myclass&#41;;
...

// destroy object when your done
DestroyInterface&#40;&myclass&#41;; Note: You need to define the aObj as a pointer to a pointer (CreateInterface(int aIID, void **aObj); )because you need the modified pointer on return.

arthurprs
26-10-2007, 08:02 PM
NP, I struggled with these problems too so happy to share the stuff I've learned about it.

1. You just need to export CreateInterface/DestroyInterface routines from your Delphi made dll, such as I outlined above.

2. You need to dynamically load this DLL on the c++ side (use LoadLibrary) and bind to these two routines.

3. Define the interface class on the C++ side and pass a pointer to this class to CreateInterface:
CMyClass *myclass;

// create object instance
CreateInterface&#40;0, &myclass&#41;;
...

// destroy object when your done
DestroyInterface&#40;&myclass&#41;; Note: You need to define the aObj as a pointer to a pointer (CreateInterface(int aIID, void **aObj); )because you need the modified pointer on return.

Here the code only compile with a single *, and works nice :)

Pyrogine
26-10-2007, 09:01 PM
Opps, yes, that is correct, only one * needed. You are passing by reference.

Glad to hear it's working for you. Keep us posted on your progress.

arthurprs
28-10-2007, 02:11 AM
Everything is working perfectly until now, i will post some results soon;

marcov
28-10-2007, 02:07 PM
[quote="arthurprs"]chronozphere:~
.lib are a file that C/C++ compilers use for static ]

Only MSVC. GCC uses .a

arthurprs
04-11-2007, 06:09 PM
http://img91.imageshack.us/img91/5637/clipboard012jw2.th.jpg (http://img91.imageshack.us/img91/5637/clipboard012jw2.jpg)

someone know why c++ don't have inttostr? wtf!

Pyrogine
04-11-2007, 06:19 PM
Check sprintf.

WILL
04-11-2007, 06:58 PM
someone know why c++ don't have inttostr? wtf!
C++ was invented by a telecom company... you do the math. ;)

arthurprs
09-11-2007, 01:57 AM
Im getting real problems now,
when compile the dll in FreePascal 2.2 the C++ program crashes...

someone knows if freepascal have problems in abstract classes, sddcall or dll's :?:

Pyrogine
09-11-2007, 02:45 AM
The VMTs must match. I don't use FPC so I can't comment what the base object type is like, but make sure the VMT on the host side match what's on the DLL side. If you did not change the VMT on the C++ to match what it's like in FPC, then this can be a source of the problem. For example if you have more virtual methods in the C++ side than on the DLL side, when you call a c++ method it maybe calling the wrong method in the DLL side.

So, make sure your virtual methods and the calling conventions all match. There maybe other issue related to FPC, but again, I don't use it so I'm unable to offer any suggestions on its usage, sorry.

arthurprs
09-11-2007, 05:31 PM
I looked at fpc documentation and noticed that fpc Tobject have 5 more methods than delphi Tobject,

what i have to do?

Pyrogine
09-11-2007, 05:57 PM
If they are virtual, then those methods will be in the VMT so this means that you will have to have more dummy methods on the C++ side so that they are still in sync.