C++ struct to Delphi

Posted on 2004-04-20
Last Modified: 2012-08-13
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.
Question by:GiulianoB
  • 4
  • 3
  • 2
  • +2

Author Comment

ID: 10874817
For the second part, I am thinking of making a wrapper DLL that will export the functions in STDCALL format. Would that work ?
LVL 26

Expert Comment

by:Russell Libby
ID: 10875091

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,


Expert Comment

ID: 10875417
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
Independent Software Vendors: 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!

LVL 20

Expert Comment

ID: 10875610
Sounds to me like Russell earned the points this time...   :-)
LVL 11

Expert Comment

ID: 10875685
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.
LVL 20

Expert Comment

ID: 10875715
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?

Author Comment

ID: 10876799
I'm not home at the moment but i will try when I get home. Thanks

Author Comment

ID: 10876874
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 ?
LVL 26

Accepted Solution

Russell Libby earned 175 total points
ID: 10878504

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.




Author Comment

ID: 10881843
I haven't tested it all but I understand a lot better and that's what I wanted to accomplish. Thanks!
LVL 26

Expert Comment

by:Russell Libby
ID: 10882520
Let us know if you run into any issues, and I (and hopefully others) will try to assist.



Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …
In a recent question ( here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question