2010-12-17 30 views
3

ありがとうございました。Interop C#/ Cの問題:AccessViolationException

iがCでこの些細な機能を有する:

__declspec(dllexport) Point* createPoint (int x, int y) { 
    Point *p; 

    p = (Point*) malloc(sizeof(Point)); 
    p->x = x; 
    p->y=y; 

    return p;  
} 

ポイントは、二つのintフィールド、xとyとの非常にシンプルな構造体です。

私はこの機能をC#から呼びたいと思います。

私はこのコードを使用します

[DllImport("simpleC.dll", EntryPoint = "createPoint", CallingConvention = CallingConvention.Cdecl, SetLastError = true, CharSet = CharSet.Auto)] 
[return: MarshalAs(UnmanagedType.LPStruct)] 
public static extern Point createPoint(int x, int y); 

Point p = Wrapper.createPoint(1, 2); 

をしかし、実行時に、私はAccessViolationExceptionを持っています。詳細は例外を見て、私は例外がMarshal.CoTaskMemFree(IntPtr)メソッドからスローされることを発見した。

この方法では、C mallocによって割り当てられたメモリを解放できないようです。

私は間違っていますか?

本当にありがとうございます。

答えて

2

CoTaskMemFreeは、異なるアロケータを使用するため、mallocによって割り当てられたメモリを解放することはできません。​​によれば、 "ランタイムは常にCoTaskMemFreeメソッドを使用してメモリを解放します。作業しているメモリがCoTaskMemAllocメソッドで割り当てられていない場合は、IntPtrを使用し、適切なメソッドを使用してメモリを手動で解放する必要があります。

Adam Nathan notes「UnmanagedType.LPStructは、特定のケースでのみサポートされています。つまり、System.Guidの値の型を管理対象外のGUIDとして扱い、余分なレベルの間接参照をしています。 LPStruct。

  1. IntPtrとしてメソッドの戻り値の型を宣言し、構造体のフィールドを読み取るためにMarshal.ReadInt32を使用し、または管理構造体にデータをコピーするためにMarshal.PtrToStructureを使用するか、または:「

    は、2つの解決策があります。 Point *IntPtr値をキャストするために危険なコードを使用しています。Cライブラリがメモリを解放するdestroyPoint(Point *)メソッドを公開する必要があります。

  2. 変更Cメソッドシグネチャvoid getPoint(int x, int y, Point *)に。これは、C#は構造体を割り当てることができますし、単にCの方法データ値を入力します(ほとんどのWin32 APIはこのように定義されています)。

最後の注意:あなたの方法はSetLastErrorのWin32 APIを使用していない限り、あなたはP /呼び出し属性にSetLastError = trueを指定する必要はありません。

+0

ありがとうございます、あなたは私に何か考えてください!私の本当の目標は、正規表現用のpcre CライブラリをC#に統合することです)、mallocとsructポインタが返されます。 私は2番目の解決策を使用していますが、動作しますが、ハードな空きメモリ(C関数のデオロケータを記述する必要があります)ですが、2番目の方法が好きです。どうもありがとう! –

1

"p"を解放するコードがないので、言うことは難しいです。しかし、malloc()とfree()が一緒に動作する方法は、C#がメモリを管理する方法とはまったく異なります。 C#はガベージコレクションを持っているので(私は信じています)、これはまったく異なるメモリ管理システムを使用している可能性があります。

いずれの場合でも、オブジェクトを作成するためにライブラリを使用する場合は、ライブラリを使用してオブジェクトを破棄する必要があります。 Cライブラリのメモリを解放し、C#コードにインポートし、そこから呼び出して、Cライブラリによって作成されたオブジェクトを破棄する「destroyPoint」関数を実装します。

一般的なデザイン/コーディング規則として、すべての「作成」機能には一致する「フリー/破棄/削除」機能が必要です。それ以外には、作成されたすべてのアイテムが適切に破棄されることを確実にすることが容易になります。

+0

ありがとうございます:) akk私は、Cから割り当てられたオブジェクトが他のC関数からのみ割り当て解除できるという確認をしてくれます! –

1

ポイントタイプはC#側でどのように定義されていますか?
安全でないか、voidポインタ(IntPtr)を返す必要があります。 GCは外部からの参照(ここでは割り当てられたメモリ)を数えることができないため、コードはGCを介して外部に割り当てられたメモリを管理することはできません。
アプリケーションの実行中にオブジェクトを永続的に保持する必要がある場合は、ガベージコレクションを避けるために静的参照を保持する方法もあります。

+0

こんにちは、あなたのanswareのおかげで...実際には、私は正しいキャストを行うには、C#で今のところポインタを返します。問題は、ポインタによって参照されるメモリが余分なC関数を負荷しない限り、割り振り不能であることです。 –