2013-02-11 6 views
1

의 내가마샬링를 float [] []로 플로트 **

int someFunction(const float ** raws) 

가 어떻게 C#을에서 float[][] 인수를 사용하여이 함수를 호출 할 수있는 프로토 타입과 C++ 기능이 있다고 가정 해 봅시다? 안전하지 않은 코드를 사용하지 않았을 가능성이 있습니다.

+4

'float [] []'은 기본적으로'float ** '와 근본적으로 다르므로 아마 그렇지 않을 것입니다. –

+2

글쎄 그건 불가능해서는 안됩니다. 나는 방법이있을 것이라고 확신합니다. 그것이 내가 "마샬링"이라고 부른 이유입니다. – hattenn

+0

나는 그것을하기위한 해킹 방법은 float [] []를 클래스/구조체에 넣고 그 대신에 주위를 전달하는 것이다. 만약 스택에가 함수에 전달할 때마다 전체 플로트 [] []과 중복되지 않도록 –

답변

3

내가 아는 한 대부분의 작업을 직접해야합니다. Interop은 최상위 배열을 정렬하는 데 도움이되지만 중첩 된 배열을 모두 고정한 다음 완료되면 고정 해제하는 것이 좋습니다. 이 입력 float 어레이에서 데이터 포인트 각각은, 포인터 배열을 구축

using System; 
using System.Runtime.InteropServices; 

namespace ManagedClient 
{ 
    class Program 
    { 
     [DllImport("UnmanagedDll.dll", CallingConvention = CallingConvention.StdCall)] 
     private static extern int UseFloats([MarshalAs(UnmanagedType.LPArray)] IntPtr[] raws); 

     static void Main(string[] args) 
     { 
      float[][] data = 
      { 
       new[] { 0.0f, 0.1f, 0.2f, 0.3f, 0.4f }, 
       new[] { 1.0f, 1.1f, 1.2f, 1.3f }, 
       new[] { 2.0f }, 
       new[] { 3.0f, 3.1f } 
      }; 

      var handles = new GCHandle[data.Length]; 
      var pointers = new IntPtr[data.Length]; 

      try 
      { 
       for (int i = 0; i < data.Length; ++i) 
       { 
        var h = GCHandle.Alloc(data[i], GCHandleType.Pinned); 
        handles[i] = h; 
        pointers[i] = h.AddrOfPinnedObject(); 
       } 

       UseFloats(pointers); 
      } 
      finally 
      { 
       for (int i = 0; i < handles.Length; ++i) 
       { 
        if (handles[i].IsAllocated) 
        { 
         handles[i].Free(); 
        } 
       } 
      } 
     } 
    } 
} 

이 코드는 한 가지 방법을 도시한다. (C 함수가 데이터가 도착하기를 기대하는 형식입니다.) C 코드가 각 하위 배열의 길이를 아는 방법은 당신에게 달려 있습니다. 현실에서

__declspec(dllexport) int __stdcall UseFloats(const float ** raws) 
{ 
    printf("%f %f %f %f %f\n", raws[0][0], raws[0][1], raws[0][2], raws[0][3], raws[0][4]); 
    printf("%f %f %f %f\n", raws[1][0], raws[1][1], raws[1][2], raws[1][3], raws[0][4]); 
    printf("%f\n", raws[2][0]); 
    printf("%f %f\n", raws[3][0], raws[3][1]); 
    return 0; 
} 

당신은 아마도 서브 어레이의 각이 얼마나 오랫동안 관리되지 않는 코드를 말할 뭔가를하고 싶은거야 : 내 테스트 코드에서 난 그냥 C# 코드는 전달 일치하도록 하드 코딩 - 선택한 관리되지 않는 함수 서명은 호출 된 코드가 각 하위 배열의 길이를 알 수있는 방법을 제공하지 않습니다. (아마도 당신이 ** 플로트를 사용하는 이유는 당신이 들쭉날쭉 배열을 원하기 때문에.이 아닌 경우, 각 부분 배열이 정확히 같은 길이 인 경우, 그것은 배열 대신 여기 직사각형 배열을 사용하는 것이 더 효율적 훨씬 것 포인터를 사용하면 쉽게 마샬링을 할 수 있습니다.)

+0

좋은 답변입니다. 당신은 아마 "아마도 당신은 플로트를 사용하는 이유는 [] []" "** 떠"하지 의미와 그 밑줄 또는 두 개의 차원 배열 ([,], float를) 자동으로 마샬링 할 수있는 경우가 있기 때문에 경우에 굵은 글씨로해야한다. –

+0

감사합니다. 그러나 나는 내가 쓴 것을 의미했다 : 나는 그가 부르려고하는 관리되지 않는 기능의 서명이기 때문에 "float **"이라고 비난했다.그것은 문제의 근본 원인 인 서명입니다. (C#에서 float [,]로 전환하면 관리되지 않는 서명이 계속 float ** 인 경우 많은 도움이되지 않습니다. 관리되지 않는 서명에는 문제의 핵심 인 포인터 배열이 필요합니다. float [,]로 시작하면 하나의 객체 만 고정해야하지만 IntPtr []을 작성해야합니다.) 가능한 한 관리되지 않는 서명을 변경하는 것이 가장 좋은 해결책이라고 생각합니다. –

+0

@Ian 왜 [MarshalAs (UnmanagedType.LPArray)]를 사용합니까? 그리고 당신이 그 속성을 사용하지 않는다면 디폴트 마샬링은 무엇입니까? – hattenn

1

이안이 이미 귀하의 질문에 대답 했으므로 C++ 측에서 SAFEARRAY를 사용하는 것이 좋습니다.

SAFEARRAY는 C/C++의 모호한 배열 정의 문제에 대한 COM 응답으로, 기본 요소의 수와 크기를 포함하고 .Net 배열에 더 적합한 구조입니다. 이들을 사용하면 C#의 배열을 자동으로 마샬링 할 수 있습니다.

SAFEARRAY는 C++에서 작동하기가 어렵지만 ATL에는 일을 쉽게하기위한 멋진 래퍼가 있습니다. 가능하다면 C++ 함수를 사용하거나 C++에서 작성된 마샬링 코드가있는 .Net을 사용하는 interop 용 C++ 래퍼 작성을 고려하십시오.

+0

불행히도, C++ 코드는 다른 사람이 작성한 것으로,이를 제어 할 권한이 없습니다. 생각을 제안! – hattenn