Solved

C++ struct to Delphi

Posted on 2004-04-20
11
1,875 Views
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
6fb1e131
6fb1e133   mov     ecx, [ebp+4]
6fb1e136   call    -$6d61b ($6fab0b20)
6fb1e136
6fb1e13b   test    eax, eax
6fb1e13d   jz      loc_6fb1e656
6fb1e13d

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.
0
Comment
Question by:GiulianoB
  • 4
  • 3
  • 2
  • +2
11 Comments
 

Author Comment

by:GiulianoB
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 ?
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10875091

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

type
  // 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;
  end;

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.

Example:
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,
Russell

0
 
LVL 3

Expert Comment

by:MikProg
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
0
Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

 
LVL 20

Expert Comment

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

Expert Comment

by:robert_marquardt
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.
0
 
LVL 20

Expert Comment

by:Madshi
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?
0
 

Author Comment

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

Author Comment

by:GiulianoB
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 ?
0
 
LVL 26

Accepted Solution

by:
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:

EAX, EDX, ECX // not EAX, EBX, ECX

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.

----------

Russell


0
 

Author Comment

by:GiulianoB
ID: 10881843
I haven't tested it all but I understand a lot better and that's what I wanted to accomplish. Thanks!
0
 
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.

Russell

0

Featured Post

Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

Question has a verified solution.

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

Suggested Solutions

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
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…
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
In a recent question (https://www.experts-exchange.com/questions/28997919/Pagination-in-Adobe-Acrobat.html) here at Experts Exchange, a member asked how to add page numbers to a PDF file using Adobe Acrobat XI Pro. This short video Micro Tutorial sh…

813 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now