2012-10-24 58 views
3

我已經尋找了幾天,已經嘗試了所有我能找到,但仍不能得到這個工作。麻煩編組結構數據的陣列從C++到C#

詳情: 我有一個調用到我的非託管的DLL第三方股票交易應用程序。它提供的數據是dll進程/過濾器,然後保存到全局環形緩衝區中。環形緩衝區是一個100長的結構陣列。所有這些都在股票交易應用程序進程中運行。

我也有一個託管C#應用程序調用到一個不同的過程,需要儘可能快速,高效地獲取全球環形緩衝區的信息相同的dll。除了我只能獲得數組中第一個結構的數據外,其他所有工作都可以使用。在從C#調用dll之後,C#代碼不再知道arrayMD是一個結構數組,它在調試器中顯示爲一個簡單的結構。它可能是dll中的memcpy導致問題?我嘗試過[In,Out],IntPtr和Marchal.PtrToStructure組合的各種組合。我非常喜歡。任何幫助將不勝感激。

謝謝

這是我正在嘗試。 中的DLL方面:

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)); 
} 

在C#的一面:

[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入口點的定義:

void __stdcall RetrieveMD (stMDP *LatestMD []) 

不指定大小的數組,那麼C#應該如何知道有多少元素被複制到它中?這在其他語言中也是一個問題。你的實現只是假設提供的內存足夠大以容納aryMD。但如果不是?你剛剛創建了一個緩衝區溢出。

如果你想調用者來分配數組,然後調用者也必須通過該數組包含元素的數量。

編輯

C++的聲明應該是這個樣子:然後

// 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#的聲明將是這個樣子:

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

你的問題,我認爲,是你正試圖通過從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#中調用此方法,您需要執行兩項操作。首先,你需要分配一個合適大小的數組來傳入。其次,你需要告訴封送處理代碼(即做的C# - 「ç複製)如何找出多少數據被封,通過[MarshalAs]屬性:

[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

我得到它的工作。我有沒有想過要比現在更難。

我重新閱讀「.NET 2.0互操作性食譜​​:問題解決方案方法」的第2章。

這是有用的。

在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)); 
} 

在我刪除兩者(REF)的C#側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); 

謝謝大家誰提供了幫助。