Re: Convert C-Builder program to Delphi?

M

Maarten Wiltink

Rudy Velthuis said:
W. D. wrote: [...]
void __fastcall TMainForm::Button1Click(TObject *Sender)
{
// Do some stuff
} [...]
Why isn't 'MainForm' used instead of 'TMainForm'? I
thought 'TMainForm' was a type!

No, it isn't. You thought wrong. <g>

Er... come again?

Groetjes,
Maarten Wiltink
 
W

W. D.

Thanks everyone for your help on this problem! I really do
appreciate the thought and time you put into your answers to
my questions.

After quite a few attempts at adding the forms, I found
that the easiest way to do it is to open up both C-Builder
and Delphi to the "Project Manager". This is done by
mousing to: View -> Project Manager (Shortcut: Ctrl-Alt-F11).
Once this window is open in both environments, try to make
the Delphi project structure look exactly like the C-Builder
structure.

For each .pas file, just put together a very short, syntactically
correct file like Walter suggested:

=================================================================
unit Unit1;

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls;

interface

type
TForm1 = class(TForm)
end;

implementation
{$R *.dfm}

end.
=================================================================

Highlight the proper place in the Project Manager, then mouse to:
Project -> Add to Project (Shortcut: Shift-F11). This will
add the .pas file in the proper place relative to all the other
elements. Once the .pas file is added, add the form (.dfm) right
next to it. When these forms are added, the event handlers
are forced to be discarded.

After having done this, I now have a structure that looks
very much like the C-Builder program, and the forms in
the Delphi project are exactly the same.

However, I am running into rough territory translating the
code. (As I mentioned before, both my Delphi and C coding
skills are quite rusty--although it is coming back to me
fairly quickly.)

I've been trying to incorporate the .h files into the
Interface section of one unit. Ralph's suggestion
of putting the C++ code into a comment just before
the Delphi translation helps to understand things more
clearly. This is a medium sized program, so I've
resorted to writing some regular expressions in order
to convert much of the simpler code.

However, I can't seem to find the proper way to
translate some entries in the .h file. Does anyone
have some idea what might be appropriate?

#1:
--------------------------------------------------------
extern TMainForm *MainForm;
--------------------------------------------------------

#2:
--------------------------------------------------------
typedef struct
{
BYTE header[8];
BYTE *data;
DWORD size;
}
DATA_STORE;
--------------------------------------------------------

#3:
--------------------------------------------------------
extern int MAX_STORED_UNITS;
--------------------------------------------------------

#4:
--------------------------------------------------------
extern THE_BUFFER *buffer;
--------------------------------------------------------

#5:
--------------------------------------------------------
extern DWORD req_data;
--------------------------------------------------------

Again, I really appreciate any shoves in the proper
direction on all this. I've been digging through Google
and GoogleGroups for much of this, but there's not a lot
out there.
 
M

Maarten Wiltink

[...]
However, I can't seem to find the proper way to
translate some entries in the .h file. Does anyone
have some idea what might be appropriate?
#1, 3..5:
--------------------------------------------------------
extern TMainForm *MainForm;
extern int MAX_STORED_UNITS;
extern THE_BUFFER *buffer;
extern DWORD req_data;
--------------------------------------------------------

These are all variable declarations. In C, an explicit separation is
made between declarations and definitions. Declarations tell the compiler
that a variable (or function!) may be expected to exist and has some type.
A definition _makes_ it exist, by allocating space in the data segment or
the stack, and of course also gives it a type.

Declarations go into header files, so that everybody may include them.
Definitions go into source files and occur only once.

It's possible to declare a variable (a hundred times over) but forget to
define it. I don't know if that's a linker error or if it's then defined
implicitly.

#2:
--------------------------------------------------------
typedef struct
{
BYTE header[8];
BYTE *data;
DWORD size;
}
DATA_STORE;
--------------------------------------------------------

A simple type declaration.

type DATA_STORE = record
header: array [1..8] of Byte;
data: PByte;
Size: Cardinal;
end;

Groetjes,
Maarten Wiltink
 
M

Maarten Wiltink

Maarten Wiltink said:
[...]
However, I can't seem to find the proper way to
translate some entries in the .h file. Does anyone
have some idea what might be appropriate?
#1, 3..5:
--------------------------------------------------------
extern TMainForm *MainForm;
extern int MAX_STORED_UNITS;
extern THE_BUFFER *buffer;
extern DWORD req_data;
--------------------------------------------------------

<declarations vs. definitions>

What I forgot to say here is that the appropriate way to translate
external declarations to Delphi is "uses <unit>;". That's really
the translation of "#include <header>", an intermediate step to
the actual declarations that is widespread in C as well.

But in C, you can actually interject an "int printf();" in your
code to get the compiler to allow calling an as yet unimplemented
function printf in the expectation that someone, somewhere, will
make it accessible. There is no substitute for that in Pascal;
you have to point the compiler at a source file from which it will
extract a list of public identifiers.

Groetjes,
Maarten Wiltink
 
W

W. D.

Thanks, guys, for your answers to my previous questions!
I am slowy but surely(?) getting this C++ code
converted to Delphi.

In the process of translating, I need to combine
the .h (header) files, and the .CPP (implementation)
into a single Delphi unit.

In one unit, I've translated a fairly complicated
class, but the CPP file contains some lines
(put in the Implementation block) that I don't know
how to translate. These variables have
all been previously declared in the class. They
all seem to be 'static' variables.

=======================================================
// Static Class Members:
uint16 TheMainClass::Some_Table[256];
uint8 TheMainClass::Some_Table_Exists = false;

char TheMainClass::VersionFlag = 'A';
int TheMainClass::MajorVersion = '7';
int TheMainClass::MinorVersion = 00;
char TheMainClass::VersionStr[40];
=======================================================

This block of code comes just before the
Constructor definition. It comes just after all of
the '#include' lines.

Before this implementation block, I have the
Interface section that has been translated from
the .h (header) file.

Does anyone have any idea on how to translate this
block of code? I've tried all sorts of variations,
but the compiler just chokes on them all.
 
M

Maarten Wiltink

[...]
// Static Class Members:

Static class members are associated with the class, not repeated
in every instance. Older versions of Delphi for win32 do not have
any support for this at all, I think it was introduced with D2005
because it needed to support it on .Net anyway.

Use global (unit-scope) variables instead. Normally you put them in
the implementation section, making them invisible outside the unit.
They are not in the class but code that _is_ in the class can
access them because they're in the same unit.

Groetjes,
Maarten Wiltink
 
M

Martin Harvey (Demon account)

Use global (unit-scope) variables instead. Normally you put them in
the implementation section, making them invisible outside the unit.
They are not in the class but code that _is_ in the class can
access them because they're in the same unit.

I might add that by the looks of some of those variables, a const
would be more appropriate.

MH.
 
W

W. D.

Many, many thanks for all your help!!!! You have helped me trudge
along in this project.

Right now I am stumped on some fairly simple C code that
initializes a packed struct/record:

memset(&PackedStruct, 0, sizeof(PackedStruct));

Does anyone have some idea how to do this in Delphi?
 
W

W. D.

W. D. said:
Many, many thanks for all your help!!!! You have helped me trudge
along in this project.

Right now I am stumped on some fairly simple C code that
initializes a packed struct/record:

memset(&PackedStruct, 0, sizeof(PackedStruct));

Does anyone have some idea how to do this in Delphi?

Many thanks to Stephen Posey!...who suggested:

FillChar(PackedStruct, SizeOf(TPackedStruct), 0);

Now I am stumped again with a 'new' dynamic allocation
line:

PackedStruct.maindata = new uint8[MAX_DATA_LEN];

I looked around: in the Help file, here:
http://www.delphibasics.co.uk/RTL.asp?Name=New
and other places on the 'Net, but not sure
what to do. Can this statement be done on
one line in Delphi?

FYI, the RECORD type looks similar to this:

type
Packed_Struct = PACKED record
soh: UINT8;
Data_Type: UINT8;
Data_Size: UINT16;
maindata: UINT8;
CRC: UINT16;

// In the C++ code there is something like:
// Packed_Struct()
// ~Packed_Struct()

// Are these by chance constructor and destructor?
// If so, would this code make sense:

// Constructor Create;
// Destructor Destroy; Override;

end; // Packed_Struct


Again, thanks a bunch for any help you can provide!

(I apologize for emailing you directly. :-(
I'll just post to the various forums from now on)
 
M

Maarten Wiltink

[...]
Now I am stumped again with a 'new' dynamic allocation line:

PackedStruct.maindata = new uint8[MAX_DATA_LEN];

It's a simple memory allocation for an array of uint8s (bytes),
MAX_DATA_LEN of them. The simplistic Delphi equivalent is GetMem,
the idiomatic Delphi equivalent would be SetLength'ing a dynamic
array.


[...]
FYI, the RECORD type looks similar to this:

type
Packed_Struct = PACKED record
soh: UINT8;
Data_Type: UINT8;
Data_Size: UINT16;
maindata: UINT8;

....But maindata would need to be a pointer to uint8 for the
above to be valid. While UINT8 is not equal to uint8 in C++, I
doubt that it means anything different. It seems unlikely that
an indirection (pointer) would be introduced without so much as
a hint.

But then, you say "similar". It doesn't look like C++, either.
Please copy and paste actual compiling code next time, so we
don't have to guess what mistakes were introduced in retyping.

CRC: UINT16;

// In the C++ code there is something like:
// Packed_Struct()
// ~Packed_Struct()

// Are these by chance constructor and destructor?
// If so, would this code make sense:

// Constructor Create;
// Destructor Destroy; Override;

Yes. It would make sense, but there are subtleties. The C++ type
is a record that could be "instantiated" on the stack, by declaring
a variable that holds the record. Delphi class types are always on
the heap, and are always a pointer away.

Constructors and destructors have slightly different semantics in
C++ and Delphi. That's minor, though, compared to the differences in
memory allocation.

end; // Packed_Struct [...]
(I apologize for emailing you directly. :-(
I'll just post to the various forums from now on)

That's the idea.

Groetjes,
Maarten Wiltink
 
J

Jamie

W. D. said:
Many, many thanks for all your help!!!! You have helped me trudge
along in this project.

Right now I am stumped on some fairly simple C code that
initializes a packed struct/record:

memset(&PackedStruct, 0, sizeof(PackedStruct));

Does anyone have some idea how to do this in Delphi?
Fillchar(PackefStruct, 0 Sizeof(PackedStruct));
 
W

W. D.

W. D. said:
W. D. said:
Many, many thanks for all your help!!!! You have helped me trudge
along in this project.

Right now I am stumped on some fairly simple C code that
initializes a packed struct/record:

memset(&PackedStruct, 0, sizeof(PackedStruct));

Does anyone have some idea how to do this in Delphi?


Many thanks to Stephen Posey!...who suggested:

FillChar(PackedStruct, SizeOf(TPackedStruct), 0);

Now I am stumped again with a 'new' dynamic allocation
line:

PackedStruct.maindata = new uint8[MAX_DATA_LEN];

I looked around: in the Help file, here:
http://www.delphibasics.co.uk/RTL.asp?Name=New
and other places on the 'Net, but not sure
what to do. Can this statement be done on
one line in Delphi?

FYI, the RECORD type looks similar to this:

type
Packed_Struct = PACKED record
soh: UINT8;
Data_Type: UINT8;
Data_Size: UINT16;
maindata: UINT8;
CRC: UINT16;

// In the C++ code there is something like:
// Packed_Struct()
// ~Packed_Struct()

// Are these by chance constructor and destructor?
// If so, would this code make sense:

Yep, looks like a static class (basically a record with methods), which
Delphi doesn't support (not 100% strictly true, but the way to do it is
deprecated and you probably would be better served by going about it a
dfferent way).

The way this is being used, it looks like "maindata" is being treated as
a pointer rather than a strict UINT8 field, are you sure there's not a
"*" in the original C++ declaration somewheres?

Right you are: UINT8 *maindata; // Pointer to maindata

Anyway, assuming that's the case, the statement appears to be allocating
memory for the data, so something like this should suffice:

GetMem(PackedStruct.maindata, MAX_DATA_LEN);


Are these constructors and destructors?

Packed_Struct()
~Packed_Struct()

If so, would this be the proper translation?

Constructor Create;
Destructor Destroy; Override;
If you can't figure out how maindata is being used as a pointer, please
post some more context code so I can see more exactly what's going on
with it.

My guess is that there's a more Delphi-like way of going about this
involving pointers to array types, or perhaps using a dynamic array,
depending on how it's actually being used in the code.

Hmmm. Would that mean declaring the packed record type then
declaring a pointer to that record, like this:

type
Packed_Struct = PACKED record
soh: UINT8;
Data_Type: UINT8;
Data_Size: UINT16;
maindata: UINT8;
CRC: UINT16;

Constructor Create;
Destructor Destroy; Override;

end; // Packed_Struct

Var
PkdStrPtr: ^Packed_Struct;

????

Thanks!!!!!!!!!
 
W

W. D.

Bjørge Sæther said:
FillChar(TheRecord, SizeOf(TheRecord), 0);

Thanks, Bjørge! (and Maarten!)


Is anyone familiar with 'strtol'? What the heck is a radix?

m_TheType = strtol(&SomeVar[5], NULL, 16);

I tried a 'StrToInt' but the format is different.
 
W

W. D.

red said:
W. D. said:
Is anyone familiar with 'strtol'? What the heck is a radix?

A base. (base 2, base 10, base 16...)
m_TheType = strtol(&SomeVar[5], NULL, 16);

OK, Thanks Red Floyd!

I just used:
m_TheType := StrToInt(SomeVar[5]);

It compiled OK. We'll see if it runs--I'll be amazed if
this thing doesn't crash right out of the gate. ;^)

This program is throwing another monkey wrench at me:

===================================
#if defined (PROC_PAUSE)

volatile bool bPauseProc;

#endif
===================================

Although I found a very nice description of 'volatile':
http://www.programmersheaven.com/articles/pathak/article1.htm ,

I couldn't find any equivalent keyword that will disallow
compiler optimizations in Delphi. Any hints?
 
W

W. D.

Marco said:
There isn't. Protect the var with a mutex.

Thanks, Marco!

I've just commented out the code for now. We'll see if it
explodes when I get the whole program to compile.

Just now I've been thrown a 'pointer' curve ball:

Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);


I realize that this is casting the PackedStruct as
an array of bytes, and we are trying to collect 7
bytes to put into Temp32 starting at the first
byte. (Temp32 is a uint32).

Does anyone have an idea why I would get errors
using this?
Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));

Is there some better way to do this?
 
M

Maarten Wiltink

[...]
Just now I've been thrown a 'pointer' curve ball:

Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);


I realize that this is casting the PackedStruct as
an array of bytes, and we are trying to collect 7
bytes to put into Temp32 starting at the first
byte. (Temp32 is a uint32).

Second byte, actually.

Does anyone have an idea why I would get errors
using this?
Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));

Is there some better way to do this?

Same mistake as last time. (uint8 *) is a PByte, not a byte.

It looks like odd C code anyway. &x[1] should be written as x+1,
and apparently indexing has higher priority than taking the
address, but I'd be using more parentheses _and_ more temporary
variables.

Groetjes,
Maarten Wiltink
 
W

W. D.

Thanks again, Maarten! I do appreciate you pointing
me in the proper direction.

I'm still having problems with this, though. Below is
what I've come up with so far:

Maarten said:
[...]
Just now I've been thrown a 'pointer' curve ball:

Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]);


I realize that this is casting the PackedStruct as
an array of bytes, and we are trying to collect 7
bytes to put into Temp32 starting at the first
byte. (Temp32 is a uint32).

Second byte, actually.
Does anyone have an idea why I would get errors
using this?
Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));

Is there some better way to do this?

Same mistake as last time. (uint8 *) is a PByte, not a byte.

It looks like odd C code anyway. &x[1] should be written as x+1,
and apparently indexing has higher priority than taking the
address, but I'd be using more parentheses _and_ more temporary
variables.

// Declared this temporary variable:
Var
BytePointer: ^Byte;

BytePointer := Addr(packet); // This compiles.

Temp32 := GetChunk(7, BytePointer^); // This also compiles.

However, this code presumable references the FIRST byte of
data. As you correctly pointed out, we are trying to
suck in 7 bytes starting at the SECOND byte.

Any time I tried to do something like:

BytePointer := Addr(packet) +1; // or,
Temp32 := GetChunk(7, (BytePointer +1)^ );

the compiler can't figure out that I want to start at the
next byte. Any ideas on how to "phrase" this properly?

Also, should I dipose of these temporary pointer variables
at the end of the function or procedure?

Thanks in advance for helping me stop stumbling around in
the dark!
 
M

Maarten Wiltink

W. D. said:
Maarten said:
Temp32 = GetChunk(7, &((uint8*)&PackedStruct)[1]); [...]
Temp32 := GetChunk(7, Addr(uint8(Addr(PackedStruct)[1])));
[...]
Same mistake as last time. (uint8 *) is a PByte, not a byte.
[...]
// Declared this temporary variable:
Var
BytePointer: ^Byte;

BytePointer := Addr(packet); // This compiles.

Temp32 := GetChunk(7, BytePointer^); // This also compiles.

However, this code presumable references the FIRST byte of
data. As you correctly pointed out, we are trying to
suck in 7 bytes starting at the SECOND byte.

Any time I tried to do something like:

BytePointer := Addr(packet) +1; // or,
Temp32 := GetChunk(7, (BytePointer +1)^ );

the compiler can't figure out that I want to start at the
next byte. Any ideas on how to "phrase" this properly?

The compiler knows that BytePointer is a pointer to byte, but
Addr() returns a Pointer, an untyped pointer. That can be assigned
to any typed pointer but it does not have an "element size" of
itself. You can either cast the Addr() to a pointer to byte and
add, or add to BytePointer (in a new statement).

Adding one to a Pointer isn't, or shouldn't be, allowed. This
may vary between versions. Adding one to a pointer to byte
should be allowed and dereferencing that pointer also. Please
post actual compiled code and exact error messages and cursor
locations.

(BytePointer+1)^ can be written as BytePointer[1].

Also, should I dipose of these temporary pointer variables
at the end of the function or procedure?

Did you allocate the memory they point to? That should normally
tell you if you need to free it.

In this case, it points halfway into Packet. You could try to
dispose its second half just once if you want to see the fireworks.
But that's not how memory allocation works.

Groetjes,
Maarten Wiltink
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,139
Latest member
JamaalCald
Top