0

BTMemoryModule を使用し、DLL から関数をインポート/呼び出す Delphi アプリケーションがあります。DLL は C/C++ で書かれています。

Delphi アプリケーションは、元の pwidechar (4 バイトの配列または widechar の配列) を関数に送信します。

C/C++ 疑似コードはありませんが、次のようになります。

type
 TMyFunc = function ( p  : pointer ): pointer; stdcall;

procedure anynamehere();
var
 Addr     : TMyFunc;
 MyString : WideString;
begin
 [...]
  Addr := BTMemoryGetProcAddress('mydll.dll', 'ExportedFunc');
  MyString := 'TEST';
 [...]
 ExportedFunc (pwidechar(MyString));
 MessageBoxW (0, pwidechar(MyString), '', 0);
end;

DLL には、MyString 変数への元のポインターが含まれているはずです。delphiapp のプロシージャはアクティブなままです (dll ExportedFunc が終了するまで)。そのため、MyString var はプロシージャの終了後に破棄されません。私の質問は次のとおりです。DLL 内で MyString の値を変更することは可能ですか? (技術的には可能...) でもどうやって?文字列は null で終了するため、ユーザーはポインターの長さがわかります。しかし、C++ DLL が値を変更した場合、ユーザーは新しいスペースなどを割り当てませんか? それとも、これは自動的に行われますか?

ご協力いただきありがとうございます。

4

3 に答える 3

3

DLL は、必要に応じて参照先メモリを変更できます。DLL のアドレスを知る必要もありませんMyStringに格納され ているアドレスを知る必要があるだけMyStringです。これは、既に渡されているものとまったく同じです。関数は null で終わるWideChar値の配列へのポインターを受け取るため、関数は次のように宣言する必要があります。

void* __stdcall ExportedFunc(wchar_t* arg);

を使用してバッファの長さを確認しwcslen、通常の方法でバッファの内容を変更できます。例えば:

{
  size_t const len = wcslen(arg);
  for (size_t i = 0; i < len; ++i)
    if (arg[i] == 'a')
      arg[i] = 'e';
  return 0;
}

必要に応じて他のポインター値を返すようにすることもできますが、呼び出し元はそれを無視するため、この状況では問題になりません。

呼び出し元が に値をMyString割り当てると、プログラムに代わって OS が を介して領域を自動的に割り当てましたSysAllocString。次に、呼び出し元がそのバッファーを DLL に渡すと、DLL はそれを変更できます。呼び出し元は、後でバッファーに対して特別なことをする必要はありません。Delphi は、呼び出し元の関数が終了してスコープ外になるとSysFreeString、自動的に呼び出します。MyString

型キャストを削除して、Delphi では a 、C++ ではaPWideCharを受け取る関数を宣言することもできます。代わりに. 関数に直接渡すことができます:WideStringBSTRSysStringLenwcslenMyString

ExportedFunc(MyString);
于 2012-07-30T16:39:32.323 に答える
2

The C++ code can alter the content of the pwidechar array that is passed in, but it would not be able to change the length of the string as understood by delphi, as the C++ code doesn't understand delphi-style strings natively. All it receives is a wchar * parameter.

If you wanted to make major changes to the string e.g. make it longer, then you would need to allocate at least as much space as you wanted in the caller by using SetLength(MyString, size), and then check the length on return, so you then call SetLength(MyString, retSize) on the string to make it the returned size.

Again, usual caveats against buffer overruns and the like.

I notice that the function returns a pointer; if the C++ code is allocating memory using new(), then you will have no possibility of managing this memory from the Delphi code as the two memory allocation systems are different.

于 2012-07-30T16:37:09.017 に答える
2

DLL には、バッファーへのポインターが渡されます。DLL がそのバッファを変更することは完全に可能です。DLL は、コードが渡す 4 つのワイド文字のいずれかを変更できます。また、5 番目の文字である null ターミネータを変更することもできます。

ただし、DLL は新しいバッファーを作成できず、呼び出し元のコードにその新しいバッファーを認識させることができません。

于 2012-07-30T16:37:15.163 に答える