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?
 
The program just calls a particular function in the DLL and passes in some parameters, including those.

Just in case I messed up elsewhere, a HWND is the same as a THandle right?
 
so if I understand correct, the pchar's malloc() must be done in delphi... for hwnd you can use Thandle or integer. Thandle MUST be used with delphi functions that use thandle, for win API and so on I use integer.

 
malloc? :|

I haven't played around with PChars much, and when I have they just worked straight out of the box (including passing them to my own dlls and back). I'm more confused now.
 
Works without any extra bits, just need to declare them as PChar and it sorts everything out itself. Was declaring them as var PChar before which I guess makes little sense as that's a pointer to a pointer to a string (which is how VB handles them coincedentially, fools).
 
Hmmm.... it's not passing the values back in the parameters, they keep the values the function was called with. Any thoughts?
 
"malloc" is C function for Memory ALLOCation (look at Getmem and Freemem for Delphi counter parts). what I mean is that a PChar is nothing more than a pointer to a string (which ends with #0). the most easy way to deal with pchar's is to use strings in delphi in typecast them as pchar towards your function DLL. I made myself easy by copying the help example from delphi about pchars but I think it's the best example :

Code:
To eliminate the overhead of copying the buffer, you can cast the string to a PChar (if you are certain that the routine does not need the PChar to remain in memory). However, synchronizing the length of the string does not happen automatically, as it does when you assign an array of char to a string. You should reset the string Length so that it reflects the actual width of the string. If you are using a function that returns the number of bytes copied, you can do this safely with one line of code:

var
  S: string;
begin
  SetLength(S, MAX_SIZE;	// when casting to a PChar, be sure the string is not empty
  SetLength(S, GetModuleFilename( 0, PChar(S), Length(S) ) );
  // statements
end;

 
The program wasn't written by me, I just have the parameter list that the function needs to use to be able to be called by the program. The part I can't sort out are the bits I mentioned in my first post. I can pass values into the DLL perfectly fine at the moment and it gets the right ones, I just can't pass any values back (I assume because the parameters aren't declared as var, which I can't do because it then crashes the main program).
 
Code:
int __stdcall procname(HWND mWnd, HWND aWnd, char *data, char *parms, BOOL show, BOOL nopause)

which I have translated into

Code:
function procname(mWnd:THandle; aWnd:THandle; data:PChar; parms:PChar; show:Boolean; nopause:Boolean):integer; stdcall;

This works perfectly except for not being able to pass back values in data and parms.
 
Values in data and parms, as I've been saying, they're the whole point of this thread.
 
then your function must be imported as :

function procname(mWnd:THandle; aWnd:THandle; var data:pChar; var parms:pChar; show:Boolean;
nopause:Boolean):integer; stdcall;

as you said this gives access violations, and that's because you MUST allocate memory (like I already told you)

like this :

Code:
var

  F: file;
  Size: Integer;
  Buffer: PChar;
begin
  AssignFile(F, 'test.txt');
  Reset(F, 1);
  try
    Size := FileSize(F);
    GetMem(Buffer, Size);
    try
      BlockRead(F, Buffer^, Size);
      ProcessFile(Buffer, Size);
    finally
      FreeMem(Buffer);
    end;
  finally
    CloseFile(F);
  end;

end;


 
Ok, I can't see where that code relates to my situation at all, it just want to know how to a value back to the calling application, that's all. I know I have to declare a variable as var if I want to pass a value back, it's one of the first things you learn, I also accept that I may need to do some wierd memory allocation thing, but I have no idea how to. I have to pass the value back in a variable that a value is passed in with, so how do I allocate memory to a variable which already exists and already contains a value?

Sometimes I wish programming was still a nice simple thing involving line numbers and no subroutines of any kind...
 
Kemp:

The problem is somewhat convoluted.

1) Prototyping an OUT parameter char *data as data : PChar will work only if the called function is NOT allocating memory on itself.

Note you are passing a pointer by copy, so the pointer need to stay unchanged. If the callee is allocating memory the pointer will change and the new value will not be reflected back to the caller.

This situation is solved (as whosrdaddy said) prototyping as var data : PChar, son the caller become aware of the new pointer value.

2) If the caller is allocating memory up front and the caller is NOT allocating memory in ANY way, then data : PChar will work for an OUT parameter, as the pointer remains unchanged.

3) Reading what you have posted (your pointers pointing to nothing/garbagge on return) and the declaration of the C function (the function asks for char pointers but not for info about the max length) my best bet is the callee allocating memory on itself.

My point is: the programmer needs to know how much data he can stuff in your strings, so he needs the max length info. If he is not asking for, my guess is he getting the memory on his own. Or may be he is a very uncaring programmer.

But it is a guess. An educated guess but a guess. Some other things can transpire into the DLL we can't know from outside.

4) How to know? We have a way.

4.1) Prototype your functions as var. Assign to the pointers an invalid but not nil value like pointer(dword(-1)). Call the DLL. If the call crash on the spot, the callee is NOT assigning memory.
4.2) If the call don't crash, the callee IS assigning memory, check to see is you got some sensible data in the caller.

5) What to do? Depends...

5.1) If the callee is NOT assigning memory, the work is easy: assign your memory, call the function, use the data, free the memory.
5.2) If the callee IS assigning memory I don't know a sure way to deallocate it from a different compiler. The DLL is compiler-tied.

HTH.
buho (A).
 
whosrdaddy:

The info changed along the way. Check this post:

>>>
[...] translated into
Code:
function procname(mWnd:THandle; aWnd:THandle; data:PChar; parms:PChar; show:Boolean; nopause:Boolean):integer; stdcall;
This works perfectly except for not being able to pass back values in data and parms.
<<<

(Bolds mine).

Now he is not crashing.

1) If he is not allocating memory before the call, the callee is allocating it, that is why he is not crashing.

2) For the same reason (callee allocating on itself) he needs the var declaration to solve the returned data issue.

Actually, all here is at blind. Kemp is not producing the needed info.

Kemp:

1) The char* params are only out or in/out, please?
2) Have you checked the addresses the pointers are pointing to before and after the call? They change?

buho (A).



 
Ok, those last two questions:

1) I'm being given values in the char* parameters when my function is called, and I need to pass values back out in those same parameters.

2) I can't check where they're pointing to before and after the call as I didn't write the program, as I said before, I'm just writing a plugin for it.


Just to have all the info in one place, here's what I've tried so far:

Using the parameters as PChar with no var:
I can use the values that are passed in perfectly fine, they get to me as they should be. If I change the value of either then the program still sees the value from before the call, as can be expected with no var.

Using the parameters as var PChar:
If I try to use the values (eg ShowMessage(data)) then the program that called the DLL crashes. Same thing happens if I try to modify them. The parent program crashes before the message box is shown in the former case, possibly while trying to call the function.
 
Sorry!! I got your meaning all way wrong!

What you are writing is the callee, not the caller, and you need to comply with the caller needs. Is that?

Lemme think again.

>>>>>
Using the parameters as PChar with no var:
I can use the values that are passed in perfectly fine, they get to me as they should be. If I change the value of either then the program still sees the value from before the call, as can be expected with no var.
<<<<<

What probably meants the caller is allocating memory for you.

The point here is Delphi making some tricky things with PChar pointers, as changing them in your back.

Check this code:

Code:
var
  A : AnsiString;
  T : PChar;
begin
  GetMem(T, 1000); // Hint here!
  T := 'Start'; // And here!
  T := PChar(A);
  ...
end;

Hint: Value assigned to 'T' never used.
Hint: Value assigned to 'T' never used.

What the hints are telling us is that Delphi is changing the pointer in the assignment T := 'Start' and in T := PChar(A). It can be checked watching the pointers values while the code run.

So, if you are receiving PChars from outside Delphi, never handle the pointers as PChars but as untyped memory buffers, say using
Code:
Move(S[1], P^, Length(S)) 

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

May be your best prototyping is

Code:
function procname
 (mWnd : THandle; aWnd : THandle; 
 [b]data : pointer; 
 parms : pointer;[/b] 
 show:Boolean; nopause:Boolean):integer; stdcall;

 NO [b]var[/b] def.

to have the compiler working on your side and blocking you from making direct assignements to the char* params.

buho (A).

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top