【问题标题】:Get string return value from C DLL in Delphi在 Delphi 中从 C DLL 获取字符串返回值
【发布时间】:2008-10-25 22:15:50
【问题描述】:

我有一个用 C 编写的旧版 DLL,其中包含一个返回字符串的函数,我需要从 Delphi 访问这个函数。我拥有的关于 DLL 的唯一信息是用于访问函数的 VB 声明:

公开声明函数 DecryptStr Lib "strlib" (Str As String) As String

我尝试了以下方法但没有成功:

声明:

function DecryptStr(s: PChar): PChar; cdecl; external 'strlib.dll';

用法:

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 );
  StrPCopy( p2, 'some string to decrypt' );
  p1 := DecryptStr( p2 );
end;

这会始终使 DLL 因访问冲突而崩溃。我很茫然。

有什么建议吗?

【问题讨论】:

  • 行“StrPCopy(p2”正确吗?不应该是“StrPCopy(p1”吗?

标签: c delphi dll


【解决方案1】:

考虑重写你的测试代码如下:

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 ); // initialize
  GetMem( p2, 255 );
  StrPLCopy( p2, 'some string to decrypt', 255 ); // prevent buffer overrun
  StrPLCopy( p1, DecryptStr( p2 ), 255); // make a copy since dll will free its internal buffer
end;

如果调用 DecryptStr 仍然失败,请仔细阅读http://support.microsoft.com/kb/187912

【讨论】:

    【解决方案2】:

    p2 未初始化。 StrPCopy 将字符串复制到随机内存位置。调用约定很可能是 stdcall。

    【讨论】:

      【解决方案3】:

      我猜这里,但你确定它是 cdecl 吗?如果 VB 声明没有提到它,我会假设它实际上是一个 STDCALL 函数(STDCALL 在 Windows 上很常见,因为几乎所有的原生 API 都使用它)。调用一个调用约定的函数,就好像它是另一个调用约定的函数一样,真的会弄乱堆栈,通常会导致崩溃。

      另外,请务必检查字符串是 ANSI (LPSTR/LPCSTR) 还是 UNICODE (LPWSTR/LPCWSTR)。我不知道VB和Delphi,所以不知道每个默认使用什么。

      【讨论】:

        【解决方案4】:

        正如 Jozz 所说,p2(您将字符串复制到的位置)在您的示例中从未初始化。

        试试这个。

        var
          p1, p2 : pchar;
        begin
          GetMem( p2, 255 ); // allocate memory for 'some string...'
          StrPCopy( p2, 'some string to decrypt' );
          p1 := DecryptStr( p2 );
        end;
        

        此外,您通过调用 Getmem(p1,...) 分配的内存可能已经泄漏,因为 p1 被 DecryptStr 的函数返回覆盖。

        但是,我有点担心 DecryptStr 返回的确切内容,以及谁拥有 p1 指向的内存。如果它返回指向由 DLL 分配的内存的指针,则需要小心如何释放该内存。

        【讨论】:

          【解决方案5】:

          我同意 CesarB,尝试使用 stdcall 指令将其声明为:

          function DecryptStr(s: PChar): PChar; stdcall; external 'strlib.dll';
          

          如果不起作用,请在此处发布 VB 声明。

          【讨论】:

          • 他已经发布了VB声明,比Delphi高了两段。
          • opps 对不起,你是对的 CesarB,我没注意到,因为他没有将其标记为代码。
          【解决方案6】:

          在这种情况下,最好的方法是调试您的程序并在执行回调之前和之后检查堆栈。怎么知道,它甚至可能是外部 DLL 中的错误?

          这样你会很容易看到如何纠正这个问题。

          【讨论】:

            【解决方案7】:

            这个 dll 是用 Borland C 或 C++Builder 编写的,是为了与 Delphi 一起使用吗?在这种情况下,它可以使用 pascal 指令进行编译。

            【讨论】:

              【解决方案8】:

              字符串必须“初始化”的建议似乎是正确的。这是因为 C 将要求传入的字符串以空值结尾。检查缓冲区中文本末尾的字符是否为空 (#0)。

              为什么你认为传入的字符串正好是 255 个字符长?您需要为 p1 中的字符分配 Length(p1) + 1 个字节,并在末尾分配一个 #0 字符。

              此外,您的代码示例似乎对 p1 和 p2 的使用感到困惑。看起来 p1 是传递给您分配的 C DLL 的缓冲区,而 p2 是 DLL 分配的返回字符串。但随后代码将是(注意使用 p1 和 p2)

              var
                p1, p2 : pchar;
              begin
                GetMem( p1, 255 );
                StrPCopy( p1, 'some string to decrypt' );
                p2 := DecryptStr( p1 );
              end;
              

              更好的变量名会帮助你更清楚。

              【讨论】:

                【解决方案9】:

                我正在放弃我的解决方案,因为我对此感到困惑,但在任何答案中都没有找到它。

                C++ 函数如下所示:

                int  __stdcall DoSomething(char * _name);
                

                为了让它在 Delphi 中运行,我声明了以下函数

                function DoSomething(name: PAnsiChar): integer; stdcall; external 'somedll.dll';
                

                然后当我拨打电话时,我有一个看起来像这样的函数:

                var s: PAnsiChar;
                begin
                  GetMem(s, 255);
                  DoSomething(s);
                  // s now contains the value returned from the C DLL
                end;
                

                我尝试使用 PChar 代替 PAnsiChar,但我得到的只是垃圾。另外,如果我在 Delphi 中声明函数并将参数设置为 var ,当我尝试读取它时会出现异常。

                希望这对任何人都有帮助..

                【讨论】:

                  猜你喜欢
                  • 2021-12-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-01-27
                  • 2017-02-23
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多