【问题标题】:Using C/C++ DLL in Delphi 2010在 Delphi 2010 中使用 C/C++ DLL
【发布时间】:2011-04-03 05:05:38
【问题描述】:

我想使用来自 ssdeep (http://ssdeep.sourceforge.net/) 的 dll。 API 是:

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

然后在Delphi中,我是这样写的:

函数fuzzy_hash_buf(buf:Pbyte;buf_len:基数;结果:PAnsiChar):整数;标准调用;外部“fuzzy.dll”名称“fuzzy_hash_buf”;

如何在 Delphi 中使用该功能?

谢谢!

【问题讨论】:

    标签: c++ c delphi api dll


    【解决方案1】:

    如果 fuzzy.dll 导出带有 C 声明的函数 fuzzy_hash_buf

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

    那么你是对的,德尔福声明是

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

    要在 Delphi 中使用它,请在单元的 interface 部分中编写

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

    然后,在同一单元的implementation 部分中,您不自己实现该功能,而是指向外部DLL:

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

    请注意,您不必重新声明参数、结果类型和调用约定 (stdcall)。

    现在您可以像使用本机的实际功能一样使用此功能。例如,你可以写

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

    来自uses 声明fuzzy_hash_buf 的单元的任何单元。

    更新

    恐怕我对CreateFileMapping函数还不够熟悉。不过看了MSDN文档后,相信你可以做到

    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.
    

    【讨论】:

    • 谢谢安德烈亚斯,我知道。我有来自文件的缓冲区(使用 CreateFile、CreateFileMapping 读取),如何将此缓冲区传递给第一个参数?谢谢!
    • 不,我知道如何使用 CreateFileMapping,问题不在于。我的意思是如何将文件缓冲区传递给fuzzy_hash_buf(buffer..)。我试过了。查看我的代码:GetMem(Ssdeep, FUZZY_MAX_RESULT); GetMem(Ssdeep_Buf, FFileSize); Ssdeep_Buf := @PAnsiChar(FFileMappingPtr)[0]; Hash.Ssdeep := AnsiString(fuzzy_hash_buf(Ssdeep_Buf, FFileSize, Ssdeep));结果:访问冲突错误。我不知道问题出在哪里。
    • 什么是FFileMappingPtr?如果它是我上面代码的buf,那么只需将其用作fuzzy_hash_buf 的第一个参数。那么FFileMappingPtr是一个(the)指针,所以你不需要取这个的地址(使用@)。此外,[0] 部分看起来很奇怪。最后,fuzzy_hash_buf 返回状态码,而不是字符串。字符串写入最后一个参数的缓冲区!
    • fuzzy_hash_buf(FFileMappingPtr, FFileSize, Ssdeep); SsdeepStr := AnsiString(Ssdeep);状态码返回 0(成功),但随后发生访问冲突。
    • MrKimbo:你确定你有FFileMappingPtr := MapViewOfFile(FFileMappingHandle, FILE_MAP_READ, 0, 0, 0);
    【解决方案2】:

    除了调用约定可能有误(stdcallcdecl)之外,您似乎已经正确声明了该函数。

    根据参数名称和类型,我的猜测是你应该在第一个参数中传递一个指向字节数组的指针,在第二个参数中你告诉函数如何你给了它很多字节。您还可以传递一个指向该函数将为您填充的字符数组的指针。 假定该数组的大小足以容纳函数将放在那里的任何内容。函数结果可能是表示成功或失败的状态码。

    咨询the documentation 表明我的猜测是正确的。结果缓冲区应至少为FUZZY_MAX_RESULT 字节长。你可以通过声明一个字符数组来得到它:

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

    将其传递给函数:

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

    文档没有说明确保结果缓冲区为空终止,因此我们在末尾保留一个额外的字节,然后在其中放置一个空字符。这使得将结果缓冲区传递给像 ShowMessage 这样需要 string 参数的函数是安全的。

    【讨论】:

    • 您好,Rob,感谢您的回复!是的,你是真的,但我仍然不知道如何传递第一个参数。缓冲区来自文件缓冲区,如下所示: FFileHandle := CreateFile(PWideChar(WideString(FFileName)), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);如果 FFileHandle INVALID_HANDLE_VALUE 那么 FFileMappingHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, FFileSize, nil);现在我有了文件缓冲区,但是如何将它传递给第一个参数(缓冲区)?谢谢!
    • 还没有缓冲区。你有一个文件映射句柄。要获取缓冲区地址,您需要调用MapViewOfFile。但是如果你想对整个文件进行散列,那么使用文件散列函数而不是内存散列函数:fuzzy_hash_filename
    • 是的,我有 MapViewOfFile。模糊哈希文件名运行正常,但在这种情况下我想使用模糊哈希缓冲区,所以我可以确定缓冲区大小(不是整个文件)。
    • 当你调用MapViewOfFile时,它会返回一个地址。将其作为第一个参数传递给fuzzy_hash_buf
    • 我不知道“不起作用”是什么意思。你需要更具体。您预计会发生什么,但会发生什么?
    猜你喜欢
    • 1970-01-01
    • 2016-11-07
    • 1970-01-01
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多