byte[]Bir yönteme geçmek istiyorum IntPtrC # bir Parametre alır , bu mümkün mü ve nasıl?
GCHandleyöntem bir cazibe gibi çalışır ... aynı zamanda fixedyöntem. : P :))
byte[]Bir yönteme geçmek istiyorum IntPtrC # bir Parametre alır , bu mümkün mü ve nasıl?
GCHandleyöntem bir cazibe gibi çalışır ... aynı zamanda fixedyöntem. : P :))
Yanıtlar:
Bir diziye bir IntPtr alma konusunda emin değilsiniz, ancak Mashal.Copy kullanarak verileri yönetilmeyen kodla kullanmak için kopyalayabilirsiniz:
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
// Call unmanaged code
Marshal.FreeHGlobal(unmanagedPointer);
Alternatif olarak, bir özellik içeren bir yapı bildirebilir ve ardından Marshal.PtrToStructure kullanabilirsiniz, ancak bu yine de yönetilmeyen bellek ayırmayı gerektirir.
Düzenleme: Ayrıca, Tyalis'in belirttiği gibi, güvenli olmayan kod sizin için bir seçenekse, düzeltildi de kullanabilirsiniz.
Marshal.Copybu aşırı yük ile bir başlangıç indeksine ihtiyaç var. ÇağrıMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
Diğer yol,
GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();
Bu işe yaramalı ancak güvenli olmayan bir bağlamda kullanılmalıdır:
byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
IntPtr ptr = (IntPtr)p;
// do you stuff here
}
dikkat edin, sabit bloktaki işaretçiyi kullanmanız gerekir! Artık sabit blokta olmadığınızda gc nesneyi hareket ettirebilir.
Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)Diziye bir bellek işaretçisi almak için kullanabilirsiniz .
İşte @ user65157'nin cevabında bir değişiklik (bunun için +1, BTW):
Sabitlenmiş nesne için IDisposable bir sarmalayıcı oluşturdum:
class AutoPinner : IDisposable
{
GCHandle _pinnedArray;
public AutoPinner(Object obj)
{
_pinnedArray = GCHandle.Alloc(obj, GCHandleType.Pinned);
}
public static implicit operator IntPtr(AutoPinner ap)
{
return ap._pinnedArray.AddrOfPinnedObject();
}
public void Dispose()
{
_pinnedArray.Free();
}
}
sonra bunu şu şekilde kullanın:
using (AutoPinner ap = new AutoPinner(MyManagedObject))
{
UnmanagedIntPtr = ap; // Use the operator to retrieve the IntPtr
//do your stuff
}
Bunu Free () aramayı unutmamanın güzel bir yolu olarak buldum :)
Marshal.Copy işe yarıyor ama oldukça yavaş. Daha hızlı, baytları bir for döngüsünde kopyalamaktır. Daha da hızlı olanı, bayt dizisini çok uzun bir diziye dönüştürmek, bayt dizisine sığabildiği kadar çok sayıda kopyalamak ve ardından kalan olası 7 baytı (8 bayt hizalı olmayan iz) kopyalamaktır. En hızlısı, yukarıda Tyalis'in cevabında önerildiği gibi bayt dizisini sabit bir ifadeye sabitlemektir.
IntPtr GetIntPtr(Byte[] byteBuf)
{
IntPtr ptr = Marshal.AllocHGlobal(byteBuf.Length);
for (int i = 0; i < byteBuf.Length; i++)
{
Marshal.WriteByte(ptr, i, byteBuf[i]);
}
return ptr;
}
Bazı durumlarda, IntPtr durumunda bir Int32 türü (veya Int64) kullanabilirsiniz. Yapabiliyorsanız, başka bir kullanışlı sınıf BitConverter'dır. İstediğiniz şey için örneğin BitConverter.ToInt32'yi kullanabilirsiniz.
Int32işaretçi olarak doğru ve güvenli bir şekilde kullanabileceğiniz geçerli bir durum yoktur . Bu yıllar önce yapılan kötü bir uygulamaydı ve her türlü taşıma sorununa yol açtı. Bir bile Int64güvenli değildir çünkü zaten 128 bit mimariler vardır ve işaretçi boyutu artacaktır. İşaretçiler yalnızca işaretçiler olarak temsil edilmelidir.
int/ için kullanmanın tek geçerli senaryosu, kullanılan longdilin bunlarla ilgili bir kavramının olmadığı durumdur (örneğin, VB6). C # işaretçileri destekler ve sahiptir IntPtr- intbir işaretçi yerine bir işaretçi kullanmaya hiç gerek yoktur . Cevabınıza net uyarılar ve olası sorunların açıklamasını eklerseniz -1'imi kaldırırım.