tags:

views:

111

answers:

2

Hi All,

I want to use dll from ssdeep (http://ssdeep.sourceforge.net/). The API is:

int fuzzy_hash_buf(unsigned char *buf, uint32_t buf_len, char *result);

then in Delphi, i write it like this:

function fuzzy_hash_buf(buf : Pbyte; buf_len : Cardinal; result : PAnsiChar): integer; stdcall; external 'fuzzy.dll' name 'fuzzy_hash_buf';

How to use that function in Delphi?

Thanks!

+1  A: 

If fuzzy.dll exports a function fuzzy_hash_buf with the C declaration

int fuzzy_hash_buf(unsigned char *buf, uint32_t buf_len, char *result);

then you are right that the Delphi declaration would be

function fuzzy_hash_buf(buf: PAnsiChar; buf_len: cardinal; result: PAnsiChar):
  integer;

To use this in Delphi, in the interface section of a unit, write

function fuzzy_hash_buf(buf: PAnsiChar; buf_len: cardinal; result: PAnsiChar):
  integer; stdcall;

Then, in the implementation section of the very same unit, you do not implement the function yourself, but rather point to the external DLL:

function fuzzy_hash_buf; external 'fuzzy.dll' name 'fuzzy_hash_buf`

Notice that you do not have to redeclare the parameters, the result type, and the calling convention (stdcall).

Now you can use this function as if it were an actual function of this unit. For instance, you might write

val := fuzzy_hash_buf(buf, len, output);

from any unit that uses the unit in which you declared fuzzy_hash_buf.

Update

I am afraid that I am not familiar enough with the CreateFileMapping function. However, after reading the MSDN documentation, I believe that you can do

var
  buf: PAnsiChar;

buf := MapViewOfFile(FFileMappingHandle, FILE_MAP_READ, 0, 0, 0);

// Now, if I have understood MapViewOfFile correctly, buf points to the first byte of the file.

var
  StatusCode: integer;
  TheResult: PAnsiChar;

GetMem(TheResult, FUZZY_MAX_RESULT);

StatusCode := fuzzy_has_buf(buf, FFileSize, TheResult);

// Now TheResult points to the first byte (character) of the output of the function.
Andreas Rejbrand
Thanks Andreas, i know that. I have buffer from file (read using CreateFile, CreateFileMapping), how to pass this buffer to first parameter? Thanks!
MrKimbo
No, I know how to use CreateFileMapping, the problem is not that. I mean how to pass the file buffer to fuzzy_hash_buf(buffer..). I had try it. See my code:GetMem(Ssdeep, FUZZY_MAX_RESULT);GetMem(Ssdeep_Buf, FFileSize);Ssdeep_Buf := @PAnsiChar(FFileMappingPtr)[0];Hash.Ssdeep := AnsiString(fuzzy_hash_buf(Ssdeep_Buf, FFileSize, Ssdeep));Result: Access Violation ERROR.I don't know where is the problem.
MrKimbo
What is `FFileMappingPtr`? If it is the `buf` of my code above, then simply use this as the first argument of `fuzzy_hash_buf`. Then `FFileMappingPtr` is a (*the*) pointer, so you do not need to take the address of this (using `@`). Also, the `[0]` part looks very strange. Finally, `fuzzy_hash_buf` returns a status code, not a string. The string is written to the buffer of the last parameter!
Andreas Rejbrand
fuzzy_hash_buf(FFileMappingPtr, FFileSize, Ssdeep);SsdeepStr := AnsiString(Ssdeep);Status code returns 0 (success), but then Acess Violation occured.
MrKimbo
MrKimbo: Are you sure that you have `FFileMappingPtr := MapViewOfFile(FFileMappingHandle, FILE_MAP_READ, 0, 0, 0);`.
Andreas Rejbrand
Yes, of course. I don't have any idea why this error.
MrKimbo
Thanks Andres, problem solved. The problem is on calling convention. It must be cdecl. Thanks!
MrKimbo
+1  A: 

Aside from possibly having the calling convention wrong (stdcall or cdecl), it looks like you have declared that function correctly.

Based on the parameter names and types, my guess is that you're supposed to pass a pointer to an array of bytes in the first parameter, and in the second parameter you tell the function how many bytes you've given it. You also pass a pointer to an array of characters that the function will fill for you. The size of that array is assumed to be large enough to hold whatever the function will put there. The function result is probably a status code indicating success or failure.

Consulting the documentation shows that my guesses are correct. The result buffer should be at least FUZZY_MAX_RESULT bytes long. You could get that by declaring an array of characters:

var
  HashResult: array[0..Fuzzy_Max_Result] of AnsiChar;

Pass that to the function:

status := fuzzy_hash_buf(buffer, buffer_length, HashResult);
if status <> 0 then
  Abort;
HashResult[Fuzzy_Max_Result] := #0;
ShowMessage(HashResult);

The documentation doesn't say anything about ensuring that the result buffer is null-terminated, so we reserve an extra byte on the end, and then put a null character there. That makes it safe to pass the result buffer to functions like ShowMessage that expect string parameters.

Rob Kennedy
Hi Rob,Thanks for the response! Yes, you're true, but I still don't know how to pass first parameter. The buffer is from a file buffer, like this:FFileHandle := CreateFile(PWideChar(WideString(FFileName)), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);if FFileHandle <> INVALID_HANDLE_VALUE then FFileMappingHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, FFileSize, nil);Now I have the file buffer, but how to pass it to the first parameter (buffer)?Thanks!
MrKimbo
You *don't* have the buffer yet. You have a file-mapping handle. To get a buffer address, you need to call `MapViewOfFile`. But if you want to hash the whole file, then use the file-hashing function instead of the memory-hashing function: `fuzzy_hash_filename`.
Rob Kennedy
Yes, i have MapViewOfFile. The fuzzy_hash_filename is run ok, but in this case i want using fuzzy_hash_buf, so I can determine the buffer size (not the whole file).
MrKimbo
When you call `MapViewOfFile`, it returns an address. Pass that into `fuzzy_hash_buf` as the first parameter.
Rob Kennedy
Yes, and it doesn't works :(
MrKimbo
I have no idea what "doesn't work" means. You need to be more specific. What did you expect to happen, and what happens instead?
Rob Kennedy
I mean, when I call this function fuzzy_has_buf(FFileMappingPtr, FFileSize, ssdeep); returns = 0 (mean success) but then ACCESS VIOLATION occurred. I can't get the ssdeep hash.
MrKimbo
Ah, thanks Rob! Problem solved, calling convention must be cdecl.
MrKimbo