Delphiで記述されたネイティブDLLがあり、コールバックメカニズムを積極的に使用しています。コールバック関数は「登録」され、後でDLLの内部から呼び出されます。
function RegisterCallback(CallbackProc: TCallbackProc): Integer; stdcall;
ほとんどのコールバック関数は、次のように、参照によってプレーン構造を渡します。
TCallbackProc = procedure(Struct: PStructType); stdcall;
ここで、PStructTypeは次のように宣言されています
TStructType = packed record
Parameter1: array[0..9] of AnsiChar;
Parameter2: array[0..19] of AnsiChar;
Parameter3: array[0..29] of AnsiChar;
end;
PStructType = ^TStructType;
このDLLは、C#で記述された.NETアプリケーションによって使用されます。C#コードは非常に怠慢に記述されており、アプリケーションは全体として信頼性が低く、実行ごとに異なる場所で発生する、識別が難しい例外を示しています。
DLLは、他の多くのアプリケーションで使用されている非常に堅牢なソフトウェアであることがすでに証明されているため、疑う理由はありません。私が現在懸念しているのは、これらの構造がC#でどのように使用されるかです。
上記のレコードがC#で次のように再宣言されていると仮定します。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct TStructType
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
public string Parameter1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string Parameter2;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 30)]
public string Parameter3;
}
コールバックは次のように宣言されます
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void CallbackProc(ref TStructType Struct);
今、何か面白いことが始まります。DLLで、登録されたコールバックが次のように呼び出されると仮定します。
var
Struct: TStructType;
begin
// Struct is initialized and filled with values
CallbackProc(@Struct);
end;
しかし、C#アプリケーションで見たものと、まったく気に入らないものは、マーシャリングされた構造が将来の使用のためのポインターとして脇に保存されていることです。
private void CallbackProc(ref TStructType Struct)
{
SomeObjectList.Add(Struct); // !!! WTF?
}
私が理解しているように、Struct変数は、DLLの奥深くにあるDelphiのスタック上に作成されたものであり、それへのポインターをクライアントアプリケーションのヒープに格納することはまったくの冒険です。
私はC#の大ファン/専門家ではないので、私の素朴な質問を許してください。マーシャラーは、構造をヒープにコピーするなど、舞台裏で何かをしますか、またはアプリケーションが時々機能するという事実は純粋な問題ですチャンス?
前もって感謝します。