Bisakah Anda memberikan detail lebih lanjut? Mengapa Anda ingin melakukannya?
Grzenio
2
Anda memerlukan ini jika Anda menggunakan DirectShow API misalnya ... untuk mendapatkan data dari VideoRenderer, Anda harus menggunakan ini ... dan GCHandlemetode berfungsi seperti pesona ... juga fixedmetodenya. : P :))
Cipi
Anda memerlukan ini untuk apa pun yang mentransfer data terrabyte dan Anda ingin menghindari salinan tambahan. Gunakan imajinasimu.
Brain2000
Jawaban:
93
Tidak yakin tentang mendapatkan IntPtr ke array, tetapi Anda dapat menyalin data untuk digunakan dengan kode yang tidak dikelola dengan menggunakan Mashal.Copy:
Atau Anda bisa mendeklarasikan struct dengan satu properti dan kemudian menggunakan Marshal.PtrToStructure, tetapi itu masih membutuhkan alokasi memori yang tidak dikelola.
Sunting: Selain itu, seperti yang ditunjukkan Tyalis, Anda juga dapat menggunakan fixed jika kode yang tidak aman adalah pilihan untuk Anda
Hanya untuk memperjelas, Marshal.Copydengan kelebihan itu perlu indeks awal. Panggilan harusMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
mkenyon
lebih baik untuk mendapatkan IntPtr tanpa membuat memori baru, seperti jawaban @ user65157.
Lin
208
Cara lain,
GCHandle pinnedArray =GCHandle.Alloc(byteArray,GCHandleType.Pinned);IntPtr pointer = pinnedArray.AddrOfPinnedObject();// Do your stuff...
pinnedArray.Free();
@Cipi Per salah satu posting Eric Lipperts lainnya, ini harus memiliki kata kunci Tetap alih-alih menggunakan GC
goodguys_activate
Terima kasih banyak. Bekerja dengan baik dan sangat mudah. Saya tidak begitu ahli dalam GCHandles dan Marshal. Dapatkah seseorang mengatakan kepada saya apa plus yang dimiliki Marshal dan apa GCHandle dan di mana menggunakan yang mana? Terima kasih
piggy
1
Bisakah seseorang memberikan referensi ke pos Eric Lippert?
Cameron
3
@piggy: Saya pikir kerugian Marshal adalah Anda harus membuat salinan data Anda (yang bisa memakan waktu lama dan membuang-buang memori yang mungkin Anda butuhkan)
Riki
6
@ makerofthings7 Saya tidak percaya Lippert mengatakan untuk menggunakan 'tetap' bukan GC [untuk menyematkan objek], saya percaya dia mengatakan jangan menggunakan GC untuk menyematkan objek tanpa batas, bersama dengan mengatakan jangan gunakan tetap untuk melakukan sama juga.
Cameron
129
Ini harus berfungsi tetapi harus digunakan dalam konteks yang tidak aman:
byte[] buffer =newbyte[255];fixed(byte* p = buffer){IntPtr ptr =(IntPtr)p;// do you stuff here}
Waspadalah, Anda harus menggunakan pointer di blok tetap! Gc dapat memindahkan objek setelah Anda tidak lagi berada di blok tetap.
Anda mungkin ingin menyelidiki untuk mendapatkan AutoPinner Anda dari SafeHandle karena kelas tersebut memperhitungkan "gotchas" keamanan dan penghitungan, serta mendorong / menggunakan pola IDisposable yang direkomendasikan.
kkahl
0
Marshal. Salinan bekerja tetapi agak lambat. Lebih cepat adalah menyalin byte dalam for loop. Bahkan lebih cepat adalah dengan melemparkan array byte ke array ulong, salin sebanyak ulong sesuai dengan array byte, kemudian salin sisa 7 byte yang tersisa (jejak yang tidak selaras 8 byte). Tercepat adalah pin array byte dalam pernyataan tetap seperti yang diusulkan di atas dalam jawaban Tyalis.
IntPtrGetIntPtr(Byte[] byteBuf){IntPtr ptr =Marshal.AllocHGlobal(byteBuf.Length);for(int i =0; i < byteBuf.Length; i++){Marshal.WriteByte(ptr, i, byteBuf[i]);}return ptr;}
Ini adalah duplikat yang lebih tidak efisien dari jawaban yang diterima. Mengapa Anda menyalin byte demi byte alih-alih sekaligus?
BDL
Saya menemukan kesalahan dalam jawaban yang diterima dalam kode saya. Saya memanggil fungsi C ++ dll di c #. Parameter char * digunakan dalam c ++, jadi saya menggunakan metode yang diterima. [DllImport ("MyDll.dll", EntryPoint = "functionName", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] tetapi anehnya, ketika menggunakan metode yang diterima, tidak bisa mendapatkan IntPtr yang benar, saya mendapat beberapa buffer rusak , beberapa buffer ditampilkan sebagai Unicode. jadi saya menggunakan metode ini
nexdev
-6
Dalam beberapa kasus, Anda dapat menggunakan tipe Int32 (atau Int64) untuk IntPtr. Jika Anda bisa, kelas berguna lainnya adalah BitConverter. Untuk apa yang Anda inginkan, Anda bisa menggunakan BitConverter.ToInt32 misalnya.
Anda seharusnya tidak pernah menggunakan Int32 atau Int64 sebagai pengganti pointer . Jika Anda harus mem-porting kode Anda ke platform lain (32-bit-> 64-bit), Anda akan mengalami semua jenis sakit kepala.
xxbbcc
5
Tidak, tidak ada kasus yang valid di mana Anda dapat menggunakan dengan benar dan aman Int32sebagai penunjuk. Ini adalah praktik buruk yang dilakukan bertahun-tahun yang lalu dan itu menyebabkan semua jenis masalah porting. Bahkan Int64tidak aman karena sudah ada arsitektur 128-bit dan ukuran pointer akan meningkat. Pointer seharusnya hanya direpresentasikan sebagai pointer.
xxbbcc
1
Saya menggunakannya dalam proyek .NET CF tanpa masalah, tentu saja Anda akan memiliki masalah jika Anda mencoba untuk port itu ke sistem lain, tetapi ada kode di luar sana yang tidak dimaksudkan untuk diangkut.
Alejandro Mezcua
Memang benar bahwa beberapa kode tidak direncanakan untuk porting tetapi hal-hal dapat berubah dengan cepat. Bahkan jika penggunaan Anda pada CF dibenarkan (saya tidak tahu) itu masih saran buruk untuk pertanyaan umum. Satu-satunya skenario yang valid untuk menggunakan int/ longuntuk pointer adalah ketika bahasa yang digunakan tidak memiliki konsep mereka (misalnya VB6). C # mendukung pointer dan memiliki IntPtr- tidak perlu sama sekali untuk menggunakan intdi tempat pointer. Saya akan menghapus -1 saya jika Anda menambahkan peringatan yang jelas dan penjelasan tentang kemungkinan masalah pada jawaban Anda.
xxbbcc
3
Nah, Anda yang membandingkan penggunaan kode marshalling yang sangat spesifik untuk pertanyaan umum ini tentang menggunakan pointer di C #. Dalam C # normal tidak ada skenario di mana ini akan valid. Saya tahu ini adalah pertanyaan lama tetapi saya menolaknya karena saya menemukannya dengan mencari cara untuk mengalokasikan memori untuk IntPtr - orang lain akan melihatnya juga. Saya melihat saran Anda sangat berbahaya karena orang-orang akan pergi dengan berpikir mereka lolos dengan menyelesaikan masalah dengan mudah ketika semua yang mereka dapatkan adalah masalah di masa depan.
GCHandle
metode berfungsi seperti pesona ... jugafixed
metodenya. : P :))Jawaban:
Tidak yakin tentang mendapatkan IntPtr ke array, tetapi Anda dapat menyalin data untuk digunakan dengan kode yang tidak dikelola dengan menggunakan Mashal.Copy:
Atau Anda bisa mendeklarasikan struct dengan satu properti dan kemudian menggunakan Marshal.PtrToStructure, tetapi itu masih membutuhkan alokasi memori yang tidak dikelola.
Sunting: Selain itu, seperti yang ditunjukkan Tyalis, Anda juga dapat menggunakan fixed jika kode yang tidak aman adalah pilihan untuk Anda
sumber
Marshal.Copy
dengan kelebihan itu perlu indeks awal. Panggilan harusMarshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
Cara lain,
sumber
Ini harus berfungsi tetapi harus digunakan dalam konteks yang tidak aman:
Waspadalah, Anda harus menggunakan pointer di blok tetap! Gc dapat memindahkan objek setelah Anda tidak lagi berada di blok tetap.
sumber
Anda bisa menggunakan
Marshal.UnsafeAddrOfPinnedArrayElement(array, 0)
untuk mendapatkan pointer memori ke array.sumber
Berikut ini twist pada jawaban @ user65157 (+1 untuk itu, BTW):
Saya membuat pembungkus IDisposable untuk objek yang disematkan:
kemudian gunakan seperti ini:
Saya menemukan ini sebagai cara yang bagus untuk tidak lupa menelepon Gratis () :)
sumber
Marshal. Salinan bekerja tetapi agak lambat. Lebih cepat adalah menyalin byte dalam for loop. Bahkan lebih cepat adalah dengan melemparkan array byte ke array ulong, salin sebanyak ulong sesuai dengan array byte, kemudian salin sisa 7 byte yang tersisa (jejak yang tidak selaras 8 byte). Tercepat adalah pin array byte dalam pernyataan tetap seperti yang diusulkan di atas dalam jawaban Tyalis.
sumber
sumber
Dalam beberapa kasus, Anda dapat menggunakan tipe Int32 (atau Int64) untuk IntPtr. Jika Anda bisa, kelas berguna lainnya adalah BitConverter. Untuk apa yang Anda inginkan, Anda bisa menggunakan BitConverter.ToInt32 misalnya.
sumber
Int32
sebagai penunjuk. Ini adalah praktik buruk yang dilakukan bertahun-tahun yang lalu dan itu menyebabkan semua jenis masalah porting. BahkanInt64
tidak aman karena sudah ada arsitektur 128-bit dan ukuran pointer akan meningkat. Pointer seharusnya hanya direpresentasikan sebagai pointer.int
/long
untuk pointer adalah ketika bahasa yang digunakan tidak memiliki konsep mereka (misalnya VB6). C # mendukung pointer dan memilikiIntPtr
- tidak perlu sama sekali untuk menggunakanint
di tempat pointer. Saya akan menghapus -1 saya jika Anda menambahkan peringatan yang jelas dan penjelasan tentang kemungkinan masalah pada jawaban Anda.