4

文字列を返す関数を含む C で記述された従来の DLL があり、Delphi からこの関数にアクセスする必要があります。DLL について私が持っている唯一の情報は、関数にアクセスするための VB 宣言です。

Public Declare Function 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 がクラッシュします。私は途方に暮れています。

助言がありますか ?

4

9 に答える 9

5

テスト コードを次のように書き直すことを検討してください。

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をよくお読みください。

于 2008-10-26T07:26:42.497 に答える
4

p2 は初期化されていません。StrPCopy は、文字列をランダムなメモリ位置にコピーします。ほとんどの場合、呼び出し規約は stdcall です。

于 2008-10-26T06:24:13.887 に答える
2

私はここで推測していますが、それはcdeclですか?VB 宣言で言及されていない場合は、実際には STDCALL 関数であると思います (Windows では、ほとんどすべてのネイティブ API で使用されているため、STDCALL は非常に一般的です)。ある呼び出し規約の関数を別の呼び出し規約の関数であるかのように呼び出すと、スタックがめちゃくちゃになり、通常はクラッシュにつながります。

また、文字列が ANSI (LPSTR/LPCSTR) か UNICODE (LPWSTR/LPCWSTR) かを必ず確認してください。VBもDelphiも知らないので、それぞれがデフォルトで何を使っているかわかりません。

于 2008-10-26T00:15:01.013 に答える
1

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,...) を呼び出して割り当てたメモリは、DecryptStr から返される関数によって p1 が上書きされたため、リークされていました。

ただし、DecryptStr が正確に何を返しているのか、p1 が指すメモリを誰が所有しているのかについては少し心配です。DLL によって割り当てられたメモリへのポインターを返す場合は、そのメモリを解放する方法に注意する必要があります。

于 2008-10-27T10:22:46.043 に答える
0

文字列を「初期化」する必要があるという提案は正しいようです。これは、C では、渡される文字列が null で終わる必要があるためです。テキストの末尾の直後のバッファー内の文字がヌル (#0) であることを確認します。

渡された文字列の長さが正確に 255 文字であると想定するのはなぜですか? Length(p1) + 1 バイトを割り当てる必要があります - p1 の文字と、最後に #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;

より良い変数名は、これをより明確にするのに役立ちます。

于 2008-10-27T10:53:44.420 に答える
0

私はCesarBに同意します.stdcallディレクティブで次のように宣言してみてください:

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

うまくいかない場合は、VB 宣言をここに投稿してください。

于 2008-10-26T00:39:54.193 に答える
0

私はそれでかなり苦労し、どの回答にもそれが見つからなかったので、自分のソリューションに落としています。

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;

PAnsiChar の代わりに PChar を使用してみましたが、返されるのはゴミだけです。また、パラメータをvarに設定して Delphi で関数を宣言すると、それを読み取ろうとすると例外が発生します。

これが誰にも役立つことを願っています..

于 2013-03-18T12:55:08.750 に答える
0

このような状況での最善の方法は、プログラムをデバッグし、コールバックの実行前後にスタックをチェックすることです。外部 DLL のバグでさえあるかもしれません。

このようにして、これを修正する方法が非常に簡単にわかります。

于 2008-10-26T17:20:55.700 に答える
0

dll は、Delphi で使用することを意図して Borland C または C++Builder で作成されたものですか? その場合、パスカル ディレクティブを使用してコンパイルできた可能性があります。

于 2008-10-26T17:25:29.747 に答える