2012-10-24 1 views
3

까지 마샬링하는 데 문제가 있습니다. 내가 검색 한 모든 것을 시도했지만 여전히 작동하지 않습니다.구조체 데이터의 배열을 C++에서 C#

세부 사항 : 제 관리되지 않는 dll을 호출하는 타사 주식 거래 애플 리케이션이 있습니다. dll이 처리/필터 한 다음 전역 링 버퍼에 저장하는 데이터를 제공합니다. 링 버퍼는 100 개의 구조체 배열입니다. 이 모든 것은 주식 거래 애플 리케이션 프로세스에서 실행됩니다.

나는 또한 가능한 한 빠르고 효율적으로 글로벌 링 버퍼에 정보를 가져와야하는 다른 프로세스에서 동일한 dll을 호출하는 관리되는 C# 응용 프로그램을 가지고 있습니다. 배열의 첫 번째 구조에 대한 데이터 만 가져올 수 있다는 것을 제외하고는 모두 작동합니다. 또한 C#에서 dll을 호출 한 후 C# 코드는 더 이상 arrayMD가 구조체의 배열임을 알지 못합니다.이 구조체는 간단한 구조로 디버거에 나타납니다. 문제를 일으키는 DLL에서 memcpy가 될 수 있습니까? 필자는 [In, Out], IntPtr 및 Marchal.PtrToStructure 조합과 함께 모든 종류의 조합을 시도했습니다. 나는 크게 후 발적이다. 어떤 도움이라도 대단히 감사하겠습니다.

감사합니다.

다음은 내가 시도한 것입니다. 는 C# 측면에서

struct stMD 
{ 
    float Price; 
    unsigned int PriceDir; 
    unsigned int PriceDirCnt; 
}; 

// Global memory 
#pragma data_seg (".IPC") 
    bool NewPoint = false;  // Flag used to signal a new point. 
    static stMD aryMD [100] = {{0}}; 
#pragma data_seg() 

void __stdcall RetrieveMD (stMD *LatestMD []) 
{ 
    memcpy(*LatestMD, aryMD, sizeof(aryMD)); 
} 

: dll을 측면에서 는

void __stdcall RetrieveMD (stMDP *LatestMD []) 

당신은 크기를 지정하지 :

[StructLayout(LayoutKind.Sequential)] 
public struct stMD 
{ 
    public float Price; 
    public uint PriceDir; 
    public uint PriceDirCnt; 
}; 

public static stMD[] arrayMD = new stMD[100]; 

[DllImport(@"Market.dll")] 
public static extern void RetrieveMD(ref stMD[] arrayMD); 

RetrieveMD(ref arrayMD); 
+0

아마도 : http://stackoverflow.com/questions/1197181/how-to-marshal-a-variable-sized-array-of-structs-c-sharp-and-c-interop-help –

답변

2

문제는 DLL 진입 점의 정의입니다 배열의, 그래서 얼마나 많은 요소가 그것에 복사 된 알고 C는 무엇입니까? 이것은 다른 언어의 문제이기도합니다. 구현은 단순히 제공된 메모리가 aryMD를 포함 할만큼 충분히 크다고 가정합니다. 하지만 그렇지 않다면? 방금 버퍼 오버런을 만들었습니다.

호출자가 배열을 할당하게하려면 호출자는 배열에 포함 된 요소 수를 전달해야합니다. ,

[DllImport(@"Market.dll")] 
public static extern void RetrieveMD(
    [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] ref stMD[] arrayMD, 
    [In, Out] ref int length); 
0

귀하의 문제는, 내가 생각 :

// On input, length should be the number of elements in the LatestMD array. 
// On output, length should be the number of valid records copied into the array. 
void __stdcall RetrieveMD(stMDP * LatestMD, int * length); 

는 C# 선언은 다음과 같이 보일 것입니다 :

편집하는 것은

는 C++ 선언은 다음과 같이 될 것이다 C#에서 C 로의 참조에 의해 배열을 전달하려고 시도하는 것이므로 거의 그렇게 할 필요가 없습니다. 귀하의 경우에는 C#에서 구조체 100 개에 메모리를 할당 한 다음 그 메모리를 C로 전달하여 채우십시오. 포인터를 구조체의 배열로 전달하면됩니다. 이는 당신이 정말로 필요하지 않은 간접적 인 수준입니다.

고정 크기의 배열을 사용하는 C 함수는 거의 볼 수 없습니다. 대신 함수는 일반적으로 C에서 포인터와 길이를 허용하도록 정의됩니다. 예 :

void __stdcall RetrieveMD (stMDP *LatestMD, int size) 
{ 
    int count = 0; 
    if (size < sizeof(aryMD)) 
    count = size; 
    else 
    count = sizeof(aryMD); 

    memcpy(LatestMD, aryMD, count);  
} 

이 방법을 C#에서 호출하려면 두 가지 작업을 수행해야합니다. 먼저 전달할 적절한 크기의 배열을 할당해야합니다.

[DllImport(@"Market.dll")] 
public static extern void RetrieveMD (
    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] stMDP[] arrayMD, 
    int length 
); 

var x = new stMDP[100]; 
RetrieveMD(x, 100); 
0

를 내가 일을 가지고 다음 [MarshalAs] 속성을 통해, 마샬링 할 얼마나 많은 데이터를 파악하는 방법 - 둘째, (> C 복사는 C#을 않는) 마샬링 코드를 알 필요가있다. 내가 이것을 이보다 더 힘들게 만들었습니다.

".NET 2.0 상호 운용성 레시피 : 문제 해결 방법"의 2 장을 다시 읽었습니다.

다음은 작동 방식입니다.

는 C++ 측면에서 나는 두 (REF)를 제거 C#을 측면에서 포인터를
struct stMD 
{ 
float Price; 
unsigned int PriceDir; 
unsigned int PriceDirCnt; 
}; 

// Global memory 
#pragma data_seg (".IPC") 
bool NewPoint = false; // Flag used to signal a new point. 
static stMD aryMD [100] = {{0}}; 
#pragma data_seg() 

void __stdcall RetrieveMD (stMD LatestMD [100]) 
{ 
memcpy(LatestMD, aryMD, sizeof(aryMD)); 
} 

을 제거 s와 [에서, 아웃] 도움을 제공하는 모든 사람에게

[StructLayout(LayoutKind.Sequential)] 
public struct stMD 
{ 
    public float Price; 
    public uint PriceDir; 
    public uint PriceDirCnt; 
}; 

public static stMD[] arrayMD = new stMD[100]; 

[DllImport(@"Market.dll")] 
public static extern void RetrieveMD([In, Out] stMD[] arrayMD); 

RetrieveMD(arrayMD); 

감사를 추가했다.

관련 문제