I would like to use Span and stackalloc to allocate an array of struct and pass it to an interop call. Is it possible to retrieve a pointer (IntPtr) from the Span without being unsafe ?
Get pointer (IntPtr) from a Span<T> staying in safe mode
Asked Answered
Here is how i did it without unsafe
:
i just changed lpBuffer
to ref byte
instead of byte[]
(for c++ user COULD represent it as uint8_t*
)
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool ReadProcessMemory(nint hProcess, nuint lpBaseAddress, ref byte lpBuffer, int dwSize, out int lpNumberOfBytesRead);
Span<byte> bytes = stackalloc byte[8];
// Get reference to first byte in the span (for c++ user we COULD represent it as `uint8_t*`)
ref byte bytesReference = ref MemoryMarshal.AsRef<byte>(bytes);
// You can pass `ref MemoryMarshal.AsRef<byte>(bytes)` to the function directly
bool success = Win32.ReadProcessMemory(_processHandle, address, ref bytesReference, cSize, out int numberOfBytesRead);
lpBuffer
could be in byte
instead of ref byte
as that will allow you to use ReadOnlySpan
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool WriteProcessMemory(nint hProcess, nuint lpBaseAddress, in byte lpBuffer, int dwSize, out int lpNumberOfBytesWritten);
ReadOnlySpan<byte> bytes = stackalloc byte[8];
ref readonly byte bytesReference = ref MemoryMarshal.AsRef<byte>(bytes);
// You can pass `in MemoryMarshal.AsRef<byte>(bytes)` to the function directly
Win32.WriteProcessMemory(_processHandle, address, in bytesReference, bytes.Length, out int numberOfBytesWritten);
Notes:
[+] You could use GetPinnableReference instead of MemoryMarshal.AsRef but it is not intended to be called by user code.
[+] ReadProcessMemory Windows API function.
[+] ReadProcessMemory(kernel32) pinvoke Original implementation.
© 2022 - 2025 — McMap. All rights reserved.
unsafe
. I would say "use a typed pointer instead of anIntPtr
", though - i.e.int*
if you're usingSpan<int>
, etc. In the general case, you can use&span[0]
, but&MemoryMarshal.GetReference(span)
may be preferable (it handles empty spans correctly); but in your case you may prefer to bypass span completely. – PretypifySpan<T>
support to P/Invoke, it still wouldn't work except on .NET Core 3.1 or .NET Framework 5.0 (which doesn't exist, which is exactly the point). By not pretending to offer that, it means that what you do write stands a chance of actually working on an existing framework. – Pretypifyref T
from aSpan<T>
easily enough (but not from aReadOnlySpan<T>
), so if P/Invoke allowsref T
with implied pin semantics (for the general case - you obviously don't need pin semantics for astackalloc
span), then you should be golden - not sure that it does, though. – Pretypifyref T
would bespan[0]
or (preferred)MemoryMarshal.GetReference(span)
, as per my earlier comment - you can convert aref T
(managed pointer) to aT*
(unmanaged pointer) via&
, which is what I did above. Note, though, that usually when doing that, you'll want to usefixed
, i.e.fixed(int* ptr = &MemoryMarshal.GetReference(span)) {...}
- although IIRC there was a plan to make spans directly fixable, i.e.fixed(int* ptr = span) {...}
- I can't remember if that got implemented – Pretypify