Hi,

Am Freitag, den 30.12.2005, 18:07 -0500 schrieb Alexandre Leclerc:
> On 12/30/05, L505 <[EMAIL PROTECTED]> wrote:
> > * how can you allocate memory for a function result, on the calling side, 
> > and then
> > free it on the calling side too? The function result is not a parameter 
> > that can be
> > controlled by you, on the calling side. A parameter can be allocated 
> > precisely,
> > controlled precisely, freed precisely.
> >
> > Now I don't have the original email - is he returning static or constant 
> > text? It may
> > be safe. I forget now, what he was trying to do. Where is the memory being 
> > allocated
> > for the Pchar, again?
> 
> This is what looks the best to me: the calling application must passe
> a pointer to the DLL so that it would be filled. I'm currently doing
> this:
> 
> function MakeMD5Hash(aValue: pchar): pchar; stdcall;
> var
>  s: string;
>  size: Integer;
> begin
>  s := MD5Print(MD5String(aValue));
>  size := Length(s) + 1;
> 
>  Result := nil;
>  GetMem(Result,size);
> //  Result := StrAlloc(size); //Use strings;
> 
>  Move(Pointer(s)^, Result^, size);
> end;
> 
> But as I see, it should be a procedure, or a function that returns an
> integer/boolean value. Then that would be like in a API. I need that
> my pascal DLL works with other languages (any of them that support
> stdcall and dlls).
> 
> I dont know yet the best way to do that... like the calling
> application must 'reserve' the 32+1 chars in the string...

C string handling is a mess which is why everyone avoids/wraps it.
But the usual unix way at least is (ok, unix usually returns 0 or -1,
not true or false, but... :))

function MakeMD5Hash(ASource: PChar; 
                     ADestination: PChar; 
                     ADestinationMaxSize: Cardinal): Boolean; stdcall;
var
  s: string;
  sSize: Cardinal;
begin
  s := MD5Print(MD5String(ASource));
  sSize := Length(s) + 1;
  if sSize <= ADestinationMaxSize then begin
    Move(PChar(s)^, ADestination^, sSize);
    Result := True;
  end else begin
    Result := False;
  end;
end;

that is _reasonably_ safe... 

some (i.e. snprintf) also support the especially convoluted way:

function MakeMD5Hash(ASource: PChar; 
                     ADestination: PChar; 
                     ADestinationMaxSize: Cardinal): Integer; stdcall;
var
  s: string;
  sSize: Cardinal;
begin
  s := MD5Print(MD5String(ASource));
  sSize := Length(s) + 1;

  if not Assigned(ADestination) then begin
    Result := sSize;
  end else begin
    if sSize <= ADestinationMaxSize then begin
      Move(PChar(s)^, ADestination^, sSize);
      Result := sSize;
    end else begin
      Result := -1;
    end;
  end;
end;

which is safer, but for most cases overkill (depends on the use case of
course).

Windows sometimes has issues with freeing something that has been
allocated by some other DLL, so if you go with the "return a newly
allocated PChar" you have to either 
1) be lucky and it works after all, or
2) provide a FreeMD5Hash(Destination: PChar) that does the freeing too

> 
> Would that works?:
> 
> procedure MakeMD5Hash(aValue, hash: pchar); stdcall;
> var
>  s: string;
> begin
>  s := MD5Print(MD5String(aValue));
>  Move(Pointer(s)^, hash^, Length(s) + 1);

No, don't convert to pointer... use PChar.
 
Other than that it looks fine for the MD5 corner case (apart from the
fact that the wrapper generator for whatever language needs to know that
Hash needs to be a block that is ??? bytes long - or the programmer even
needs to set it manually before calling that - UGH...)

> end;
> 
> Regards.
> 
> --
> Alexandre Leclerc

cheers,
   Danny


_________________________________________________________________
     To unsubscribe: mail [EMAIL PROTECTED] with
                "unsubscribe" as the Subject
   archives at http://www.lazarus.freepascal.org/mailarchives

Reply via email to