2017-11-27 18 views
-3

ネイティブdll(DllImport)からエクスポートされたC関数を呼び出すC#コードがあります。C#marshalネイティブサイズの符号なし整数size_t、ref/outパラメータで値を取得

Cコードから渡されたxの値を変更して、マネージコードで変更された値を使用するようにCコードを設定します。 C関数はvoid戻り関数でなければなりません。 C#コード:

uint x=0; 
Func(x); 

Cコード:

void Func(size_t x) 
{ 
    x=8; 
} 

は、私が試した:

[DllImport("1.dll")] 
public static extern void Func(size_t x); 

しかし、C#はFunc VARを呼び出した後xがあるが、まだ0私はまた、次のCコードを試してみました。しかし、それはどちらもうまくいかない。私のエラーは何ですか?

void Func(size_t* x) 
{ 
    x=8; 
} 
+0

「void」メソッドからx = 8を返すと誤解されていない場合は、正しいデータ型を返すためにc関数の戻り値の型を変更できますか? – MethodMan

+1

ポインタとリファレンスについて読む。 – tkausl

+2

cコードは渡された値を変更せず、コピーのみを変更します。 – ROX

答えて

0

アンマネージコードとの間でポインタを使用する場合は、ref修飾子を使用する必要があります。

同様:

[DllImport("1.dll", CallingConvention = CallingConvention.Cdecl)] 
public static extern void Func(ref int x); 

static void Main(string[] args) 
{ 
    int value = 0; 
    GCHandle handle = GCHandle.Alloc(value, GCHandleType.Pinned); 

    Func(ref value); 

    handle.Free(); 

    Console.WriteLine(value); 
} 

外部コード:C#で使用すると、通常のポインタを使用することはできませんので

extern "C" __declspec(dllexport) void Func(int * nStatus) 
{ 
    *nStatus = 10; 
} 

これは、メモリ管理(別名GC)で、です。 ref-sまたは安全でないコードを使用して "強制"する必要があります。

P.S.

これはGCHandle.Alloc関数なしでも機能しますが、アンマネージドコードで作業している間にGCが値を移動して壊れてしまう可能性があります。この場合は必要ありませんが、値型(structではなくクラス)ではなく参照型を使用すると、非常に便利になります。

+0

なぜintを使用し、size_tを使用しませんか? – cool

1

あなたの例には、期待通りに動作させるために解決しなければならないいくつかの問題があります。まずはあなたの目標は、パラメータを介してC void returns関数で設定されたCタイプsize_tの値を取得することです。

C#とCの両方の値へのポインタを使用するか、C#パラメータの引き渡しを強制するC#パラメータ修飾子(refまたはout)の組み合わせを使用すると、パラメータ経由で値を取得するという簡単な問題が解決されます。ポインタとCのポインタ、次のように関数のシグネチャは次のようになります

// Implementation with pointers 
[DllImport("MyC.dll", CallingConvention = CallingConvention.Cdecl, PreserveSig = true, EntryPoint = "Func")] 
public static extern unsafe void CSharpFuncPtr(UIntPtr* x); 

// Implementation with parameter modifiers - ref can be raplaced by out 
[DllImport("MyC.dll", CallingConvention = CallingConvention.Cdecl, PreserveSig = true, EntryPoint = "Func")] 
public static extern void CSharpFuncMod(ref UIntPtr x); // 

// C function implementation 
void Func(size_t* x) { *x = 7; } 

マーシャリング中に解決されなければならない第二のさらに重要な問題は、C型などのネイティブサイズの符号なし整数size_tの使用です。 x86アーキテクチャでは32ビットの符号なし整数、x64アーキテクチャでは64ビットの符号なし整数のいずれかと定義されています(他のすべてのプロセッサアーキテクチャを意図的にスキップします)。 .NET型システムでは、ネイティブサイズの整数型がありません。この問題を回避するには、マネージタイプのシステムでsize_tをエミュレートするために、管理された符号なしポインタタイプUIntPtrを使用します。

。NETチームはこの制限を認識しており、いわゆるネイティブ整数の実装に関する議論や計画があります - 参照:Support natural size data types in the CLR

[DllImport("MyC.dll", CallingConvention = CallingConvention.Cdecl, PreserveSig = true, EntryPoint = "Func")] 
public static extern void CSharpFuncNativeInt(ref nuint x); 

最後に表面に簡単であると思われる問題は、そのすべての後に、シンプルで簡単なものではなく、エレガントなソリューションには、.NETランタイムとBCLライブラリの変更が必要です。

関連する問題