   [Delphi] Classes and structures not compatible
  I have a C++ structure in memory which I need to use in Delphi.  I have the pointer to the structure, but the problem is that the address of the C++ structure  is the address of the first property of that structure.  Eg.struct sStruct{   dword dwProperty;   ...}sStruct tmp;&tmp is equal to &(tmp.dwProperty).However, in Delphi the equivilent data type is:sStruct = class(TObject)begin   dwProperty: DWORD;   ...end;tmp: sStruct;@(tmp.dwProperty) is 4 bytes further along than tmp (@tmp is not needed as tmp is a pointer).I have investigated, and record types behave like C++ structs (same memory address, although C++ structs seem to actually be like Classes in that they allow methods, constructors and destructors), but I have to use classes, as I have circular references, ie:sStructA = class(TObject)begin   pObject: sStructB;   ...end;sStructB = class(TObject)begin   pObject: sStructA;   ...end;That wouldn't be possible with records.  Also, I would like to have constructors and destructors to initialise the data, but this is less essential.The only solution I can think of at the moment is to go through and manually decrease all the object pointers by 4, but that would be highly inconvenient.  Is there any way to make Delphi objects able to point to C++ structures?  Thanks for your time.[Edited by - hpesoj on May 23, 2006 2:08:05 PM]
  Trying to make assumptions about the binary layout of language-specific structures is not recommended, for example C++ doesn't mandate how classes should be implemented memory-wise (correct me if I'm wrong) so it may differ among compilers. A better way to share data would be to pass a pointer to an array of byte-encoded data, about which there can be no misunderstandings. Another idea is to write C-style wrapper code around your C++ objects, so it can easily be used from other languages. Hope this helps.;Quote:Original post by hpesojHowever, in Delphi the equivilent data type is:No, it's not.You are comparing a stand alone data structure in C to a Object in Delphi. They are not the same.The Delphi version of a struct is called a recordTStruct = record   dwProperty: DWORD;end;If you are using more then one member you might want to look into packed structs/records (if they are not packed, your compiler/settings will decide how best to space multiple members, which usually means they will be 32bit aligned).So to review:C++   Delphi-----------------int   integer{...} begin...endstructrecordclass class;  Michalson, in C++ struct and class keywords are almost interchangeable.So, more correctly:C++   Delphi-----------------int   integer{...} begin...endPOD struct recordclass classwhere POD stands for "plain old data", a technical term in the C++ standard.POD struct/classes are, basically, classes/structs whose pointers point at the first data member, and have some other rudimentary memory-layout guarantees.The rest of your advice is sound.;  // c/c++struct sStruct {   dword dwProperty;};// delphisStruct = packed record  dwProperty: DWORD:end;You can pass these structures back in forth. For example if you have a dll created in c/c++ and an exported routine that expects a record or pointer of this type, you can safely pass this from Delphi to the dll. The thing to insure is that the data alignments for the record structures are the same.In the case of sharing classes, since Delphi supports COM and if all the methods are virtual they share the same binary layout in memory with that of a c++ class with all virtual methods. With this in mind you can create an all method virtual class in c/c++ and using a factory, return a pointer to that class instance. If you create the same class in Delphi, you will be able to use that class in Delphi. You have to make sure your factory will also destroy the class also. If it's destroyed on the opposite side of creation, bad things will happen. I use all these techniques in my game engine GameVision SDK. Feel free to contact me if you have more questions or concerns.;Quote:Original post by PrototypeTrying to make assumptions about the binary layout of language-specific structures is not recommended, for example C++ doesn't mandate how classes should be implemented memory-wise (correct me if I'm wrong) so it may differ among compilers. A better way to share data would be to pass a pointer to an array of byte-encoded data, about which there can be no misunderstandings. Another idea is to write C-style wrapper code around your C++ objects, so it can easily be used from other languages. Hope this helps.Well, so long as I use the same compiler all the time there shouldn't be a problem, however I see your point.  Using structures (or similar) is faster than reading the whole thing byte by byte, though that would be possible and probably quite feasable if you wanted to read/write only one part of the data.  It is of course a lot more convenient to be able to refer to a piece of data as something like 'Object.Array[3].SubObject.Property', than having to scan though the data and follow pointers, but you can't have everything I guess.  Note that the data is being written by a separate application, so I only really have control over the Delphi side of things.  I have been converting the C++ header files for loading the data, but have run into a wall with this.Quote:Original post by MichalsonNo, it's not.You are comparing a stand alone data structure in C to a Object in Delphi. They are not the same.The Delphi version of a struct is called a recordTStruct = record   dwProperty: DWORD;end;If you are using more then one member you might want to look into packed structs/records (if they are not packed, your compiler/settings will decide how best to space multiple members, which usually means they will be 32bit aligned).So to review:C++   Delphi-----------------int   integer{...} begin...endstructrecordclass classWell, kind of.  Like I said, Delphi records appear to have the same internal data structure as C++ structures, but in C++ (or at least VC++) structures can have methods, and seem to be handled exactly like classes (I'm not a C++ guru).  Also, as I said, I need circular references.  Circular references with records would not work if it were actually allowed by the Delphi compiler (forward declarations of records are forbidden).  The solution is to use classes.I will look into the packed records thing, thanks.I have found this article that seems to deal with the problem at hand.  It would require me to persuade the C++ developer to change his program though.  I am not very well grounded in C++ as I said, so if anyone could summarise what this would entail that'd be good (the C++ structures have a constructor and destructor, and no members).http://rvelthuis.de/articles/articles-cppobjs.htmlThanks for your replied both.   ;  C++ "plain old data" (POD) structs and classes have the same binary layout.  And probably line up with Delphi records.C++ POD structs and classes can have methods.  They cannot have constructors, destructors, or virtual (overrideable) methods.  They cannot contain references (but can contain pointers).  The C++ standard describes what can go into a POD struct.C++ non-POD structs and classes have very little in the way of binary layout guarentees.  Practically, they often consists of a pointer to their virtual function table followed by their data.  But this varies.;Quote:Original post by hpesojWell, kind of.  Like I said, Delphi records appear to have the same internal data structure as C++ structures, but in C++ (or at least VC++) structures can have methods, and seem to be handled exactly like classes (I'm not a C++ guru).  Also, as I said, I need circular references.  Circular references with records would not work if it were actually allowed by the Delphi compiler (forward declarations of records are forbidden).  The solution is to use classes.Actually you could still use records, you would only need to replace "circular references to classes" (actually compiled into pointers by the compiler) with explicit pointers. It would look kind of like this:type  PStructA = ^TStructA;  PStructB = ^TStructB;  TStructA = record    B: PStructB;    ...  end;  TStructB = record    A: PStructA;    ...  end;CAUTION: In case you decide to use pointers be sure to call New(...) and Dispose(...) on the records pointed to by PStructX (unless those records were defined among static variables of course), otherwise you will get overflows, leaks and other kinds of nasty things ;)   