2008-10-09 12 views
25

C++ aşağıdaki yapı vardır:Mareşal C++ yapı dizisi

void GetData(LPRData *data); 
: bu yapıların 3 dizisini almak için ben içine çağırarak/p olduğum

#define MAXCHARS 15 

typedef struct 
{ 
    char data[MAXCHARS]; 
    int prob[MAXCHARS]; 
} LPRData; 

Ve bir işlev C

++ ben böyle bir şey yapmak sadece olacaktır:

LPRData *Results; 
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData)); 
GetData(Results); 

Ve sadece iyi çalışır, ancak C# Ben çalışmak için görünmektedir olamaz. Oluşturduğum böyle bir C# yapı:

public struct LPRData 
{ 

    /// char[15] 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    /// int[15] 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
} 

Ve o 3 (ve tüm bunların alt diziler) dizisi başlatmak ve bu içine geçerse:

GetData(LPRData[] data); 

It başarı ile döndürür, ancak LPRData dizisindeki veriler değişmedi.

Hatta bir ham bayt sırayı 3 LPRData 's boyutunu oluşturmak ve böyle bir fonksiyon prototip içine geçmesi çalıştık:

GetData (byte [] veriler);

Ancak bu durumda, ilk LPRData yapısından "veri" dizesini elde edeceğim, ancak aynı LPRData'dan "prob" dizisi de dahil olmak üzere bundan sonra hiçbir şey yapamayacağım.

Bunu nasıl düzeltebileceğimize dair herhangi bir fikir var mı?

cevap

23

Ben senin yapı decloration bazı özellikleri ekledikten çalışacaktı

[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable] 
public struct LPRData 
{ 
/// char[15] 
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
public string data; 

/// int[15] 
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
public int[] prob; 
} 

* TotalBytesInStruct değişken

JaredPar temsil etme amaçlıdır ıntptr sınıfını kullanarak yararlı olabileceğini de doğrudur değildir Not Ama ben PInvoke kullandım, bu yüzden paslıyım.

+1

Bu yaklaşımı kullandım, ancak Mono'da değişkenlerin boş başvurular olarak ayarlandığına dair istisnalar alıyorum. Örneğin, "prob" sıfırdır, bu yüzden çalışmak istemez. Bunları bir noktada yenmek zorunda mıyım yoksa çerçevenin bir şekilde ele alınması gerekiyor mu? Teşekkürler – swinefeaster

13

İşaretçilerle çalışırken bir numara sadece bir IntPtr kullanmaktır. Marshal.PtrToStructure öğesini, sonuçlarınızı almak için yapının boyutuna bağlı olarak işaretçi ve artış üzerinde kullanabilirsiniz.

static extern void GetData([Out] out IntPtr ptr); 

LPRData[] GetData() 
{ 
    IntPtr value; 
    LPRData[] array = new LPRData[3]; 
    GetData(out value); 
    for (int i = 0; i < array.Length; i++) 
    { 
     array[i] = Marshal.PtrToStructure(value, typeof(LPRData)); 
     value += Marshal.SizeOf(typeof(LPRData)); 
    } 
    return array; 
} 
+2

11 ya çakışmalıdır: ToInt64' 'için' = ve 'ToInt32' değişiklik' + = '64-bit çalışıyorsa; veya, 'value.ToInt32() 'kaldırır? – maxwellb

+0

@maxwellb, evet. Yazılan kod 64 bit güvenli değildir. – JaredPar

+4

gerçekten ne alıyorum, pointer.toInt + sizeof (struct) artışına göre arttırma atamasıdır. Artış sadece boyut değil mi (struct)? – maxwellb

2

GetData parametresini OutAttribute ile işaretlediniz mi? diziler uygulanmış ve, olmayan blittable türleri biçimlendirilirken InAttribute ve OutAttribute birleştiren

özellikle yararlıdır. Arayanlar, her iki özniteliği uyguladığınızda, numaralı bir arayanın bu tür türlerini değiştirdiğini görür.

2

Benzer bir konu this question üzerinde tartışıldı ve sonuçlardan biri CharSet isimli parametre CharSet.Ansi ayarlanması gerekir olmasıydı.Aksi takdirde, char dizisi yerine wchar_t dizisi yapardık. Böylece, olduğu gibi olacaktır doğru kod aşağıdaki gibidir:

[Serializable] 
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct LPRData 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)] 
    public string data; 

    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)] 
    public int[] prob; 
}