2

このシグネチャを持つ C の関数があります。

int addPos(int init_array_size, 
           int *cnt, 
           int *array_size, 
           PosT ***posArray, 
           char *infoMsg);

PostT は次のようになります。

typedef union pu
{
    struct  dpos   d;
    struct  epo    e;
    struct  bpos   b;
    struct  spos   c;
} PosT ;

P/Invoke を介して C# でこのメソッドを呼び出す最良の方法は何ですか? C# で PostT を表すクラスを定義する必要がありますか? PostT ***posArray パラメータを C# から C に渡すにはどうすればよいですか?

4

2 に答える 2

2

PosTがどのように見えるかを説明しましたが、これだけでは不十分です。まず、関数が*** PosT引数として渡されることを期待していることを知っておく必要があります。そうすれば、C ++またはC#側から呼び出すことを考えることができます。

私はそれがおそらくあなたの望みに合わないことを知っていますが、見てください:

PosT p;
PosT* ptr = &p;
PosT** ptr2 = &ptr;
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!?


PosT* ptr = new PosT[123];
PosT** ptr2 = &ptr;
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!?


PosT** ptr2 = new PosT[5];
for(int i=0;i<5;++i) ptr2[i] = new PosT[123];
PosT*** ptr3 = &ptr2;
func(...., ptr3, ...); // OK!??

等々。私がすぐに構築したメモリ内構造のどれがその機能に適していますか?これが、C#側から渡す必要のあるデータ型を決定するものです。

関数が「ギザギザのarayへの可変参照」と呼ぶものを受け取る場合(つまり、私が提供した最後の例)、P/Invoke宣言は次のようになります。

[..extern..]
void func(....., ref PosT[][] posArray, ...);

次のように呼び出されます:

func(...., new PosT[][] { 
         new PosT[] { new PosT{ d = ... }, new PosT{ d = ... }, ... },
         new PosT[] { new PosT{ d = ... }, new PosT{ d = ... }, ... },
         ... },
    .... );

ただし、最初にこの関数が何を期待するかを確認してください。*を使用すると、推測するには非常に多くの可能性があります。あなたはそれがいくつかのAPIからのものであると言います-最初にそのドキュメントをチェックしてください!この関数が正確に何を期待しているのかを教えてください。私/誰かがC#でそのようなPODを構築する方法を教えてくれます。他の方法では機能しません!:)

PS。くだらないC++/ C#コードでごめんなさい、私は急いでいて、これを書くのにほんの数分しかありませんでした:/

于 2012-12-19T18:28:30.040 に答える
1

質問 #1 PostT を表す CSharp でクラスを定義する必要がありますか?
C# では、PostT を構造体として定義する必要があります。これはユニオン構造体であるため、StructLayout 属性を適用し、他の構造体を完全に定義する必要があります。次のようになります。

struct  dpos { };
struct  epo  { };
struct  bpos { };
struct  spos { };
[System.Runtime.InteropServices.StructLayout(
    System.Runtime.InteropServices.LayoutKind.Explicit, Size=99)]
struct PosT {
    [System.Runtime.InteropServices.FieldOffset(0)] dpos   d;
    [System.Runtime.InteropServices.FieldOffset(0)] epo    e;
    [System.Runtime.InteropServices.FieldOffset(0)] bpos   b;
    [System.Runtime.InteropServices.FieldOffset(0)] spos   c;
    };

** "Size=99"正しくないことに注意してください。理想的には、このサイズを、囲まれた最大の構造体によって使用されるバイト数に設定する必要があります。

質問 2 - CSharp から C に PostT ***posArray パラメータを渡すにはどうすればよいですか?
特に C# で posArray にメモリを割り当てることが予想される場合は、この種のことを行うには十分に注意する必要があります。.NET GC が移動/変更しようとしているバッファーを C に渡したくありません。C がバッファを返す場合は問題ありません (ただし、メモリを解放できる C 関数がない場合はメモリ リークが発生します)。Default Marshaling for Arrays をご覧くださいwww.pinvoke.net にはいくつかの例があります。posArray バッファーを C# から C に送信する場合は、安全でないコンテキストに頼る必要があります (以下を参照)。そのレベルまたはリダイレクトを処理する方法が正確にはわかりません。cnt と array_size は、「ref」キーワードを使用して処理できます。

質問 #3 - すべてのマーシャリングを指定するにはどうすればよいですか?
上記のリンク、特に配列のデフォルトのマーシャリングを見てください。また、いくつかのテスト コードをいじって、呼び出し後に中断し、イミディエイト ウィンドウを使用して構造を調査する必要がある場合もあります。


覚えて

「UNSAFE」スイッチを使用して c# をコンパイルすると、ほとんどストレート (c のような) 呼び出しを行うことができます。例えば:

unsafe public MainWindow() {
    InitializeComponent();
    int abc = 4;
    int* abcPtr = &abc;
    *abcPtr = 8;

    fixed (PosT* gog = new PosT[30]) {
        PosT* gogPtr = (gog + 1);
        }
    }

C# はそれ自身のメモリを管理し、物事を移動できるため、非常に注意する必要があります (上記の「固定」を参照)。私はこれをお勧めしませんが、手早くて汚れたものに役立ちます

また、API が tlb (テーブル ライブラリ) で定義されている場合、ビジュアル スタジオは通常、スタブ dll を介してバインディングを作成することを提案します (tlbimp コマンドを参照)。


うまくいけば、誰かがより具体的な回答を提供してくれることを願っていますが、この情報は少なくともあなたの出発点になると思います.

于 2012-12-19T20:43:10.837 に答える