Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Data types going C++ -> Delphi 1

Status
Not open for further replies.

KempCGDR

Programmer
Jan 10, 2003
445
GB
Hi, I'm writing a plugin for a program using Delphi. Two of the parameters one of my functions needs to take are listed as:

Code:
char *data, char *parms

And I need to be able to pass data back to the main program in these parameters as well. I've tried various combinations of PChars and arrays of characters with the result being the main program crashing every time. Does anyone know what I'm meant to declare them as?
 
Code:
Move(S[1], P^, Length(S)) 

where A is an AnsiString and P is the foreign PChar pointer.

Did you mean Move(A[1], P^, Length(A))? And why only the first character of A?
 
Don't worry, got it sorted. Works like a charm. :) Thanks
 
Ok, new problem, if I type the string in the move procedure myself then it works, but this isn't very useful. However, doing something like:

Code:
var
   messBack:String;
begin
   messBack := 'The DLL now functions properly';
   Move(messBack, data^, Length(messBack));
end;

passes garbage to the calling program. If figured it might need a null terminated string so I tried

Code:
messBack := 'The DLL now functions properly' + chr(0);

with the same result. I even tried messBack as a PChar to cover more bases, with the same result again. What is it converting the string to when I type it in myself?
 
I've tried the following to try to force it to work:

Code:
var
   messBack:Array of char;
   temp:String;
   i:integer;
begin
   temp := 'DLL now functions properly';
   setLength(messBack, Length(temp));
   For i := 1 to Length(temp) do
   begin
      messBack[i] := temp[i];
      showmessage(messBack[i]);
   end;
   Move(messBack, data^, Length(messBack));
end;

The message dialogs show each character of messBack being set correctly, but the program still gets garbage back. According to the help files, a char array works fine in a move command.

:S
 
Lets get back to the first "move".

Code:
Move(S[1], P^, Length(S));

Is telling the compiler: move Length(S) chars, from S and starting in S[1] to P^.

You need to use S[1]. Being S an AnsiString (or String) it have some control data before the chars.

So

Code:
Move(S, P^, Length(S));

is moving said control data, adding garbage in the start of P^ and not moving all the chars you want to move.

Note "Move" interprets source and destination as untyped memory areas; it is not smart enough to say "hey, this is an AnsiString, lets skip the control data and move only the chars" as other Pascal functions use to do.

And that is the problem you are getting with

Code:
Move(messBack, data^, Length(messBack));
BTW, adding the trailing #0 is mandatory.

Putting all together:

Code:
messBack := 'The DLL now functions properly' + #0;
Move(messBack[b][1][/b], data^, Length(messBack));

is the way to do it

buho (A).


 
Please, check this code:

Code:
procedure Refill(P : Pointer);
var
  A : AnsiString;
begin
  // P is an untyped pointer, pointing to 
  // some pre allocated memory.
  A := 'Refilled' + #0;
  Move(A[1], P^, Length(A));
end;

procedure Main;
var
  AC  : array[0..100] of char;
  P   : pointer;
  A   : AnsiString;
begin
  A := 'Start String';
  GetMem(P, 100);  // Allocate memory
  Move(A[1], P^, Length(A)); // Initialize to have a clue
  Move(A[1], AC, Length(A));  // Initialize to have a clue
  Refill(P);
  Refill(@AC);
  // 
  Application.MessageBox(PChar(P), 'P is...', 0);
  Application.MessageBox(PChar(@AC), 'AC is...', 0);
  //
  FreeMem(P);
end;

It is working perfectly.

If you can't get your data back using Move over an untyped pointer probably you are having another issues, not exactly related to the way you are filling the data space.

Is you are sure your code is right, you need to check what the caller is doing with the pointers after your function returns.

In your DLL project set Run\Parameters\Host Application to the program which is using your DLL. Put a breakpoint in your function and issue a Run command.

Delphi will start the "host" (the program calling your DLL) and stop in the breakpoint. At the end of your function code, open the CPU window and continue steping thru the caller machine code. In this way you can check if something weird is affecting the pointers.

buho (A).
 
Addendum:

"Array of char" is a dynamic array, structurally like an AnsiString. (Hint: the same procedure SetLength is used to allocate the memory space in both structures.)

buho (A).
 
And suddenly it clicks....

The reason you have S[1] is because, as you should before, it just treats it as a chunk of memory, so it goes all assembly on you and keeps reading until it hits a terminating chr(0).

And now that I think about it, it's obvious that it's copy the control data over.

Sorry about that, guess I was tired or something.
 
> [...] and keeps reading until it hits a
> terminating chr(0).

Not exactly.

"Move" is a shell for the machine instruction REP MVSD; the CPU (and Move) knows nothing about zero ended strings or any other structural convention.

The syntax for Move is Move(src, dst, LEN) and it moves LEN bytes from src to dst. It don't care about src and dst having the right size to support a LEN bytes move, or src and dst being legal addresses or not, or zeros or whatever. LEN and only LEN is the law of the land.

What is tricking you is the C-ist IDE debugger, wich will only show an AnsiString up to the first zero, paying no attention to the real string length.

So, if you "ascii dump" the whole string structure and see something like &%..8...mystring (where '.' stands for #0), the debugger will show you only '&%'.

Of course, passsing back this data to a C program waiting for a zero ended string will have the same effect: the program will see only '&%'.

The control data are two dwords: the reference counter and the real string length. It have zeros for any reasonable sized string. That is what you was seeing only a few apparently random chars in the debugger.

buho (A).

 
Ok, one last thing, how do I get the string out of data when I've been passed it? I can't pretend the pointer or the pointer^ is a string, I can't use move because I don't know how long it is (moving the maximum number into the string and then cutting it myself at the first #0 which I hope it's terminated by seems clunky as hell) and I can't see other ways.

Can you tell I haven't used pointers much before? :|
 
I think I'm not getting your meaning here, can you rephrase, please?

buho (A).
 
The data parameter (pointer) has data being passed in as well, I just can't figure out how to get it into a string. I know that I know the answer to this, I just won't come to me.
 
Is ok, I sorted it, I can set a PChar (rather than a string) to the pointer and then use that.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top