2011-01-02 12 views
14

arasındaki farkları anlama Sabit {}, Marshal.AllocHGlobal() ve GCHandle kullanımının açıklamalarını inceledim ve buldum diyerek başlayalım. .Alloc() bu forum boyunca ve web üzerinde birçok linkte. Ancak, Mareşal sınıfının GCHandle sınıfına ne zaman kullanılacağını (sabit {} kullanarak ve kullanmadan) kısa bir açıklama henüz bulamadım.Sabit {}, Marshal.AllocHGlobal() ve GCHandle.Alloc()

Bir "Buffer" sınıfında Readline() adlı bir yöntemi olan bir üçüncü taraf .NET kitaplığı kullanıyorum. Bu kılavuz aşağıdaki prototipini gösterir:

bool ReadLine (int x1, int y1, int x2, int y2, System.IntPtr bufData, int intRead); diyor bufData ilgili bir açıklama da

: ... bellek alanı satır uzunluğu zamanlarda BytesPerPixel özelliği tarafından döndürülen değeri eşit veya büyük bayt numarası olmalıdır.

Şimdi sonradan kılavuzdaki onlar (benim özel örnek vermek gerekirse biraz küçük değişiklikler yaptık) tampon erişen bir örnek vermek yapmak :

// Create an array large enough to hold one line from buffer 
int size = 640; 
byte[] dataLine = new byte[size * 2]; // 2 bytes per pixel 

// Pin the array to avoid Garbage collector moving it 
GCHandle dataLineHandle = GCHandle.Alloc(dataLine, GCHandleType.Pinned); 
IntPtr dataLineAddress = dataLineHandle.AddrOfPinnedObject(); 

ve yukarıda takip edebilir "örnek" kod ile:

hikayenin sonu olabilir
// Read one line of buffer data 
success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 

// Unpin the array 
dataLineHandle.Free() 

(ve ben yukarıdaki kodu test henüz), ama .NET yolunu beni sürdü GCHandle sınıfını googling sona erdi interoperab vb ility, PInvoke,

Yani benim sorular ... 1) Neden kullanamazsınız:

IntPtr dataLineAddress = Marshal.AllocHGlobal(size * 2); 

ve) (taleb içine geçmesi?

2) Ayrıca aşağıdaki kod parçacığını (web'de örneklerden çıkarılan ve tweaked) kullanabilir miyim: Yukarıdaki teknikler ışık tutacak ve işaret edebilir

int size = 640; 
byte[] dataLine= new byte[size * 2]; // 2 bytes per pixel 

// prevent garbage collector from moving buffer around in memory 
fixed (byte* fixedDataLine = dataLine) 
{ 
    // get IntPtr representing address of first buffer element 
    IntPtr dataLineAddress= Marshal.UnsafeAddrOfPinnedArrayElement(fixedDataLine , 0); 
    success = buffer.ReadLine(0, 0, 639, 0, dataLineAddress, out numRead); 
} 

kimseye ilgilerini çekebilir Uygulamamdaki hatalarımın yanı sıra yukarıdaki yöntemler uygun olduğunda da işaret ediyor. Son olarak, yukarıdaki yöntemler geçerli olsa bile, son birkaç yılda bir yaklaşıma ya da diğerine yönelik genel bir itici güç var mı?

Şimdiden teşekkürler! Hyped

+0

Bu, korkunç bir API'ye benziyor. – SLaks

cevap

2

Peki, alternatif de işe yarayacaktır. Ancak Marshal.AllocHGlobal örneği tamamlanmadı, artık verileri yönetilmeyen bellekte aldınız. Hala yönetilen bir nesneye (dizi) almak için iş yapman gerekiyor, böylece ona kolayca erişebilirsiniz, Marshal.Copy() 'yi çağırmalısınız. Veriler, bu verileri iki kez kopyalar. Ve Marshal.FreeHGlobal() çağırmayı unutmayın.

Sabit örnek, satıcı örneğiyle aynı şeyi yapıyor, dolaylı olarak belleğe iğneliyor. Buradaki gariplik, API'nin bir bayt * değil, bir IntPtr almasıdır. Ve güvensiz anahtar sözcüğüne izin vermek için derleme ayarlarını değiştirmeniz gerekir. Aksi takdirde daha verimli değil.

Bunu farklı şekilde yaparak ilerlemiyorsunuz.

+0

Hans - Eğer "doldurmak" için bir bellek bloğuna bir bayt işaretçi gerektiren bir yönetilmeyen DLL işlevi vardı, "Marshal" vs "GCHandle" kullanarak bir tercih var mı? Yukarıdaki cevabınız için teşekkürler. – Hyped

+0

@Hyped - tercihiniz * daima * P/Invoke marshaller'ın bunu yapmasına izin vermelidir. Bu neredeyse her zaman mümkün. Argümanı, örneğinizde bir dizi olarak bildirirsiniz. PixelData'nın iki bayt üyeli bir yapı olduğu bayt [] veya PixelData [] gibi. –