C++ struct to Delphi

This question is a bit extended..
I am trying to use an exported function of another DLL that looks like this:
void __fastcall PrintMessage(ptMsg * Message)

I need to convert this structure to a Delphi structure. I can convert some of it but i get stuck in the boolean and the string parts:

struct ptMsg
 BYTE Unk0;
 BYTE id;
 BYTE Unk1;
 BYTE type;
 bool overhead;
 byte Unk2[3];
 WORD Unk3;
 char PlayerName[0x10];
 char Message[542]

I need the new structure in delphi to have the same number of bytes since it will be passed into the function

(I can probably figure the part below myself but any help is appreciated and will be awarded pts)

The beginning of the function looks like this in ASM (used madshi's madAsm)
6fb1e120 sub_6fb1e120:                    ; function entry point
6fb1e120   sub     esp, $dd8
6fb1e126   push    ebx
6fb1e127   push    ebp
6fb1e128   mov     ebp, ecx
6fb1e12a   push    esi
6fb1e12b   push    edi
6fb1e12c   mov     al, [ebp+3]
6fb1e12f   test    al, al
6fb1e131   jnz     loc_6fb1e143
6fb1e133   mov     ecx, [ebp+4]
6fb1e136   call    -$6d61b ($6fab0b20)
6fb1e13b   test    eax, eax
6fb1e13d   jz      loc_6fb1e656

Since it uses fastcall, I think I will have to change the function a bit from
procedure PrintMessage(mMessage: ptMsg)
so that it sends the parameters correctly.
Who is Participating?
Russell LibbyConnect With a Mentor Software Engineer, Advisory Commented:

I would bet on packed record as well, as it is typically the norm (especially nowadays). But then again, looking at a library that exports functions as __fastcall doesn't leave me with a lot of confidence in that bet ;-)

Regading the bool issue: Yes, it could be 1 byte. The bool data type is not part of the standard ANSI C, and it was usually the case to typedef it as an int. It IS part of the C++ standard, but not all compilers are standard in the implementation of such things. So, this is just another case where context means everything. I will offer this though...

Looking at the declaration again, it would appear that this is not the bool data type from the windows header, as the windows header type define is "BOOL"
(and C/C++ is case sensitive). So, there is a very good chance that the compiler's native data type was used.

Anyways, it would have been nice to see a "bool" field (with size comments) in the second struct listing.

Also, I made a mistake with my statement on Delphi's passing. Delphi passes up to 3 values in the registers, but the registers are:


My apologies on that (It was late, and I was tired...). You still need to pad the function 2 places, as suggested. For _fastcall declarations with 2 params, the declaration would be

function foo(Filler: Integer; Param2: datatype; Param1: datatype);

Please note the reverse order of param1 and param2 in order to get them into their correct registers. In regards to calling _fastcall functions with more than 2 parameters.... well, let's just say that I personally would not want to touch it.



GiulianoBAuthor Commented:
For the second part, I am thinking of making a wrapper DLL that will export the functions in STDCALL format. Would that work ?
Russell LibbySoftware Engineer, Advisory Commented:

The struct part I can help you with (to a point)...

  // You need to figure out the byte alignment the dll was compiled with...
  // eg, this may need to be: ptMsg = record
  lpPtMsg       = ^ptMsg;
  ptMsg          =  packed record
     Unk0:       Byte;
     id:         Byte;
     Unk1:       Byte;
     _type:      Byte;
     overhead:   BOOL; // Defined in Windows.pas (4 byte long bool)
     Unk2:       Array [0..2] of Byte;
     Unk3:       Word;
     PlayerName: Array [0..15] of Char;
     Message:    Array [0..541] of Char;

Problem is, its impossible to tell the byte alignment of the structure (no C\C++ source context to go from). Where it would end up getting messed up is after the Unk2 field, which is 3 bytes long (if not packed). Unless you know for sure, this will be a trial and error situation.

Regarding the fastcall declaration...
This is kind of a combination of register PLUS stdcall calling convention:

(I quote)
The first two parameters are passed in ECX and EDX, with the remainder passed on the stack as in __stdcall. Again, the callee cleans the stack. Function names are decorated by a leading @-sign and a trailing @-sign followed by the number of bytes of parameters taken by the function (including the register parameters).

Anyways, there is no calling convention in Delphi that "quite" fits this. I offer this suggestion (I take no credit for it, as Madshi has mentioned this in another question somewhat similar to this; I only agree with his suggestion as well).

Pad the function with 2 integer params before the Message param, thus making the
Message param come in as ECX (Delphi passes in EAX, EBX, ECX...) . Leave the function calling convention alone (it will be register by default). As the register function cleans up after the call, you **should** be ok.

procedure PrintMessage(Fill1, Fill2: Integer; Message: lpPtMsg); external 'dllname';


Regarding  your other suggestion. A wrapper would work as well, as long as the wrapper language understood the __fastcall calling convention. (meaning, it needs to be done in C/C++). This would be the safest way IMHO...

Hope this helps,

Cloud Class® Course: MCSA MCSE Windows Server 2012

This course teaches how to install and configure Windows Server 2012 R2.  It is the first step on your path to becoming a Microsoft Certified Solutions Expert (MCSE).

Windows.pas in Delphi source contains {ALIGN ON} compiler directive.
Delphi help says:
In the {$A8} or {$A+} state, fields in record types that are declared without the packed modifier and fields in class structures are aligned on quad word boundaries.
If you owner C++ & Delphi code then making same alignment in both sources same used in windows dll's is good idea
Sounds to me like Russell earned the points this time...   :-)
I would bet on packed record. Unk3 being the first and only candidate for alignment seems to indicate that packing was considered when the record was designed.
I'm just wondering. The alignment would be perfect if the "bool" would only be 1 byte long. Is that possible? Does a one byte bool exist in C++ or is it always 4 bytes?
GiulianoBAuthor Commented:
I'm not home at the moment but i will try when I get home. Thanks
GiulianoBAuthor Commented:
I have this also btw:
it's the same structure but diff variable names.. this has the sizes
struct ChatMsg {
   BYTE Identifier;        // 0x00
   BYTE MessageType;       // 0x01
   BYTE Unk1;              // 0x02
   BYTE Style;             // 0x03
   DWORD UnitId;           // 0x04
   BYTE Color;             // 0x08
   BYTE Unk2;              // 0x09
   char Name[0x10];        // 0x0A
   char Message[0x100];    // 0x1A

also will the method to add 2 fill integers work on any fastcall or does it have to have a certain amt of parameters ?
GiulianoBAuthor Commented:
I haven't tested it all but I understand a lot better and that's what I wanted to accomplish. Thanks!
Russell LibbySoftware Engineer, Advisory Commented:
Let us know if you run into any issues, and I (and hopefully others) will try to assist.


Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.