2017-11-27 36 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#에서 일반적 때문에 메모리 관리 (일명 GC)의 포인터를 사용할 수 없기 때문에

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

이입니다. ref-s 또는 안전하지 않은 코드를 사용하여 "강제로"해야합니다.

P.

GCHandle.Alloc 기능이 없어도 작동하지만 관리되지 않는 코드에서 작업하는 동안 GC가 값을 이동시키고 손상 될 수 있습니다. 이 경우에는 필요하지 않지만 값 유형 (struct 대신 클래스) 대신 참조 유형을 사용하면 매우 유용합니다.

+0

왜 int를 사용하고 size_t를 사용하지 않습니까? – cool

1

예를 들어 예상대로 작동하려면 몇 가지 문제가 있습니다. 먼저 매개 변수를 통해 C void 반환 함수에 설정된 C 유형 size_t의 값을 검색하는 것이 귀하의 목표입니다. 매개 변수를 통해 값을 검색하는

먼저 간단한 문제의 값에 하나의 포인터를 사용하여 도움으로 해결 모두 C# 및 C 또는 A와 C# 1 파라미터의 전달을 강제 할 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 유형 시스템에서 네이티브 크기의 정수 유형이 누락되었습니다. 해결 방법은 관리되는 부호없는 포인터 유형 UIntPtr을 사용하여 관리되는 유형 시스템에서 size_t을 에뮬레이션하는 것입니다.

.NET 팀이 한계를 인식하고 소위 기본 정수를 구현하는 방법에 대한 토론과 계획이 - 참조 :

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

Support natural size data types in the CLR 마지막으로 표면에 쉽게 것 같다 문제가 모두 간단 이후 그렇게 간단하지 않다 우아한 솔루션은 .NET 런타임 및 BCL 라이브러리 변경이 필요합니다.