2012-04-30 87 views
2

我需要從C++向C#傳遞一個結構數組。我有下面的代碼,它首先創建一個臨時結構,然後將它轉換爲C#端結構的地址memcpy。我用相同的元素順序定義了兩側的結構。從C#向C++傳遞一個結構數組

當我調試時發現臨時結構被正確填充時,temp_buf(目標變量的地址)在每次迭代中增加了結構的大小,並且memcpy不返回任何錯誤。

但是,只有數組的第一項在C#端設置。

下面是在C#側的定義:

[DllImport(@"MyAwesomeDLL.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "[email protected]@[email protected]@@Z", CharSet = CharSet.Auto)] 
public static extern Int32 GetCoolDevices(out UInt32 p_deviceCount, out Device_s p_devicesBuf); 

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public struct Device_s 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)] 
    public String DeviceName; 
    public UInt32 DeviceID; 
} 

下面是在C++方面的定義:

#pragma pack (1) 
typedef struct 
{ 
    TCHAR device_name [51]; 
    UINT32 device_rid; 
} DEVICE_S; 


int GetDevices (UINT32 *device_count, DEVICE_S *devices_buf) 
{ 
.... 

    while(....) 
    { 
     DEVICE_S tmp_device; 
     memset(&tmp_device, 0, sizeof(DEVICE_S)); 

     tmp_device.device_id = 5; 
     sprintf(tmp_device.device_name, "a string"); 

     DEVICE_S *temp_buf = &(devices_buf[i]); 
     size_t mysize = sizeof(DEVICE_S); 
     memcpy(temp_buf, &tmp_device, mysize); 

     i++; 
     getNextDevice(); 
    } 

..... 
} 

而且,這裏是我怎麼稱呼它:

UInt32 MyDecDeviceCnt = 0; 
Device_s[] MyDecDevices = new Device_s[10]; 
int ret = GetCoolDevices(out MyDecDeviceCnt, out MyDecDevices[0]); 

任何建議表示讚賞!

+0

@ SamFisher83 - 你的建議沒有任何意義。使用字符串是正確的過程。當然,這兩個結構的大小並不一樣,C#結構至少要大12位。 –

+0

@Ramhound我改正了我的錯字錯誤。現在,device_name長度爲51個字符。是否仍然存在不匹配? – mustafa

回答

2

您創建的API存在問題。您爲託管端數組(10個元素)分配內存,但不會將數組中的元素數傳遞給非託管端。編組人員無法確定您想編組10個元素,而非託管代碼不知道它正在寫入的緩衝區的大小。您可以使用MarshalAsAttribute.SizeParamIndex向編組提供關於數組大小的信息。也看看文章Default Marshaling for Arrays。 (特別是關於C風格陣列的信息。)

考慮到API的性質,您可以對其進行更改,以便在非託管端分配內存。你將不得不使用一個安全的數組或者全局的方式來讓內存在託管端被釋放。

+1

您還應該提及'TCHAR device_name [20];'vs SizeConst = 51' - 這會導致DeviceID存在錯誤的偏移量。 – ildjarn

+0

我認爲這是一個簡單的錯字,但它需要修復。 –

+0

@MartinLiversage - 出現錯誤的可能性不大。 –