1

私は、C# と C++ の間のインターフェイスとなる自社のライブラリ コードの過剰設計された保守不可能なチャンクを書き直しているところです。P/Invoke の調査を開始しましたが、アクセス可能なヘルプの方法はあまりないようです。

さまざまなパラメーターと設定を含む構造体をアンマネージ コードに渡すため、同一の構造体を定義しています。C++ 側でこれらのパラメーターを変更する必要はありませんが、P/Invoked 関数が戻った後にそれらにアクセスする必要があります。

私の質問は次のとおりです。

  1. 文字列を渡す最良の方法は何ですか? 一部は短く (デバイス ID は弊社が設定できます)、一部はファイル パスです (アジア文字を含む場合があります)。
  2. IntPtr を C# 構造体に渡す必要がありますか、それとも関数シグネチャに構造体型を入れて Marshaller に処理させるべきですか?
  3. bool や enum などのポインタ以外のデータ型 (他の関連する構造体) について心配する必要がありますか? C++ で警告をエラーとして扱うフラグが設定されているため、列挙型に Microsoft 拡張機能を使用してデータ型を強制することはできません。
  4. 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;
}
4

1 に答える 1

2

blittableタイプは、マネージコードとアンマネージコードの間で共通の表現を持つタイプであるため、byte、int32など、ほとんどまたはまったく問題なくそれらの間で受け渡すことができます。

ブリット不可能なタイプには、System.Array、System.String、System.Booleanなどの一般的な表現はありません。

ブリッタブルでないタイプのMarshalAs属性を指定することにより、マーシャラーに変換先を指示できます。詳細については、BlittableおよびNonBlittableタイプに関するこの記事を参照してください。

1-文字列を渡すための最良の方法は何ですか?短いもの(私たちが設定できるデバイスID)もあれば、ファイルパス(アジアの文字が含まれている場合もあります)もあります。

StringBuilderは一般的に最も使いやすいものとして推奨されていますが、私はプレーンバイト配列をよく使用します。

2-IntPtrをC#構造体に渡す必要がありますか、それとも関数シグネチャに構造体タイプを入れてマーシャラーに処理させる必要がありますか?

メソッドがポインターを期待している場合は、IntPtrを渡しますが、使用目的によっては、多くの場合、refを使用して回避できる可能性があります。同じ場所に長時間留まる必要がある場合は、Marshalを使用して手動でメモリを割り当て、結果のIntPtrを渡します。

3-boolsやenums(他の関連する構造体)のような非ポインターデータ型について心配する必要がありますか?警告をC++で設定されたエラーフラグとして扱うため、列挙型にMicrosoft拡張機能を使用してデータ型を強制することはできません。

すべてが正しいマーシャリング属性で設定されたら、なぜ心配する必要があるのか​​わかりません。疑わしい場合は属性を入力し、構造体がマネージコードによってのみ使用される場合は、属性は使用されません。

4-P / Invokeは実際に進むべき道ですか?Implicit P / Invokeについては、タイプセーフでパフォーマンスが高いというMicrosoftのドキュメントがいくつかありました。

これについてコメントすることはできません。あなたはそこでVisualC++の領域にいます。

于 2012-07-10T16:19:57.203 に答える