私は、C# と C++ の間のインターフェイスとなる自社のライブラリ コードの過剰設計された保守不可能なチャンクを書き直しているところです。P/Invoke の調査を開始しましたが、アクセス可能なヘルプの方法はあまりないようです。
さまざまなパラメーターと設定を含む構造体をアンマネージ コードに渡すため、同一の構造体を定義しています。C++ 側でこれらのパラメーターを変更する必要はありませんが、P/Invoked 関数が戻った後にそれらにアクセスする必要があります。
私の質問は次のとおりです。
- 文字列を渡す最良の方法は何ですか? 一部は短く (デバイス ID は弊社が設定できます)、一部はファイル パスです (アジア文字を含む場合があります)。
- IntPtr を C# 構造体に渡す必要がありますか、それとも関数シグネチャに構造体型を入れて Marshaller に処理させるべきですか?
- bool や enum などのポインタ以外のデータ型 (他の関連する構造体) について心配する必要がありますか? C++ で警告をエラーとして扱うフラグが設定されているため、列挙型に Microsoft 拡張機能を使用してデータ型を強制することはできません。
- P/Invoke は実際に進むべき道ですか? Implicit P/Invoke について、より型安全でパフォーマンスが高いと述べた Microsoft のドキュメントがいくつかありました。
参考までに、これまでに作成した構造体のペアの 1 つを次に示します。
C++
/**
Struct used for marshalling Scan parameters from managed to unmanaged code.
*/
struct ScanParameters
{
LPSTR deviceID;
LPSTR spdClock;
LPSTR spdStartTrigger;
double spinRpm;
double startRadius;
double endRadius;
double trackSpacing;
UINT64 numTracks;
UINT32 nominalSampleCount;
double gainLimit;
double sampleRate;
double scanHeight;
LPWSTR qmoPath; //includes filename
LPWSTR qzpPath; //includes filename
};
C#
/// <summary>
/// Struct used for marshalling scan parameters between managed and unmanaged code.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ScanParameters
{
[MarshalAs(UnmanagedType.LPStr)]
public string deviceID;
[MarshalAs(UnmanagedType.LPStr)]
public string spdClock;
[MarshalAs(UnmanagedType.LPStr)]
public string spdStartTrigger;
public Double spinRpm;
public Double startRadius;
public Double endRadius;
public Double trackSpacing;
public UInt64 numTracks;
public UInt32 nominalSampleCount;
public Double gainLimit;
public Double sampleRate;
public Double scanHeight;
[MarshalAs(UnmanagedType.LPWStr)]
public string qmoPath;
[MarshalAs(UnmanagedType.LPWStr)]
public string qzpPath;
}