2012-04-09 9 views
1

내가 관리되지 않는 Win32에서 C++ DLL의 일반적인 구조를 가지고 할당 할 수 있었던 바이트 배열의 요소잘못된 관리/비 관리 형 겸용, 동적으로 할당 된 배열

다음이 정의를 사용하여 할당 채우기 및 구조체의 할당을 해제하는 기능을 보냅니다 DLL : 기본 호출자의 잘

// The exported allocator function. 
extern "C" _declspec(dllexport) 
    FirstElemPtrContainer *BuildStruct(int elem_count) 
{ 
    FirstElemPtrContainer *fepc_ptr = new FirstElemPtrContainer; 
    fepc_ptr->num_elems = elem_count; 
    elem_type *ary = new elem_type[fepc_ptr->num_elems]; 
    for (int i = 0; i < fepc_ptr->num_elems; i++) 
    { 
     ary[i] = ((i + 1) * 5); // multiples of 5 
    } 
    fepc_ptr->allocd_ary = ary; 

    return fepc_ptr; 
} 

// The exported deallocator function. 
extern "C" _declspec(dllexport) void 
    DestroyStruct(FirstElemPtrContainer *fepc_ptr) 
{ 
    delete[] fepc_ptr->allocd_ary; 
    delete fepc_ptr; 
} 

이 일을.

[StructLayout(LayoutKind.Sequential)] 
public struct FirstElemPtrContainer 
{ 
    public byte num_elems; 
    [MarshalAs(UnmanagedType.LPArray, 
     ArraySubType = UnmanagedType.U1, SizeConst = 4)] 
    public IntPtr allocd_ary; 
} 

... 그래서 같이 호출 인터페이스를 설명합니다 : C#에서

, 나는 PInvoke를 통해이 같은 구조를 설명하려고

public static class Imports 
{ 
    [DllImport("MyLib", CallingConvention = CallingConvention.Winapi)] 
    public static extern IntPtr BuildStruct(int elem_count); 

    [DllImport("MyLib", CallingConvention = CallingConvention.Winapi)] 
    public static extern void DestroyStruct(IntPtr fepc_ptr); 
} 

지금 내 인터페이스 호출을 시도 :

class Program 
{ 
    const int NUM_ELEMS = 4; 
    static void Main(string[] args) 
    { 
     IntPtr fepc_ptr = Imports.BuildStruct(NUM_ELEMS); 
     if (fepc_ptr == IntPtr.Zero) 
     { 
      Console.WriteLine("Error getting struct from PInvoke."); 
      return; 
     } 

     FirstElemPtrContainer fepc = 
      (FirstElemPtrContainer)Marshal.PtrToStructure(fepc_ptr, 
     typeof(FirstElemPtrContainer)); 
     //... 
    } 
} 

PtrToStructure() 호출은 수 "없습니다 원수 필드 'allocd_ary'유형 '을 오류를 제공 MyLibInvoke .FirstElemPtrContainer ': 잘못된 관리되는/관리되지 않는 형식 조합 (Int/UInt는 SysInt 또는 SysUInt와 쌍을 이루어야 함). "

호출자가 준수한다고 가정하는 특정 수의 요소를 하드 코딩 한 것을 볼 수 있습니다. 차이점을 보이지는 않지만 ArraySubType 절도 추가했습니다. 왜 유형 불일치가 불만 사항입니까?

답변

2

귀하의 구조체는 다음과 같이 선언한다 :

[StructLayout(LayoutKind.Sequential)] 
public struct FirstElemPtrContainer 
{ 
    public byte num_elems; 
    public IntPtr allocd_ary; 
} 

allocd_ary가 관리되지 않는 메모리에 대한 포인터이기 때문에이 방법을 수행해야합니다과 p에 의해 정렬 화 될 수없는/마샬를 호출합니다.

allocd_ary의 내용을 읽으려면 Marshal.Copy을 사용할 수 있습니다.

FirstElemPtrContainer fepc = (FirstElemPtrContainer)Marshal. 
    PtrToStructure(fepc_ptr, typeof(FirstElemPtrContainer)); 
byte[] ary = new byte[fepc.num_elems]; 
Marshal.Copy(fepc.allocd_ary, ary, 0, ary.Length); 

나는 CallingConvention.Winapi 잘못이며 CallingConvention.Cdecl을 이용해야한다는 것을 생각한다.

+0

맞습니다. 바이트 배열을 포함하도록 PInvoke 정의를 변경하라는 원래의 제안을 시도했지만 다른 오류가 발생했습니다 : "배열의 런타임 유형과 메타 데이터에 기록 된 하위 형식간에 불일치가 발생했습니다." 나는 이미 마샬을하고 있었다. 코드()를 복사하고 있었기 때문에 문자 그대로 내가했던 마샬 (MarshalAs()) 잡담을 주석 처리했다. 그런 다음 나는 여기로 돌아와 내가 방금 한 것과 똑같은 것을 제안했음을 알았다. – Buggieboy

+0

@Buggieboy 당신을 잘못 이끌어 준 것에 대해 사과드립니다. 나는 충분히 처음으로 질문을 자세히 읽지 않았다. 하지만 국제 대회에 관해서는 어떻습니까? 명시 적으로 C++ 코드에서 설정하지 않으면 'Cdecl'이됩니다. –

+0

David - 글쎄, Visual Studio 2005에서 C++ Win32 DLL 프로젝트를 만들었고 내 함수 정의 앞에 "extern"C "_declspec (dllexport)"이 있으면 아무 것도 알려줍니다. "CallingConvention.Winapi"는 아무 것도 해를 끼치 지 않는 것처럼 보였으므로 나는 그대로 두었다. – Buggieboy

관련 문제