I have an IntPtr
that represents a memory address. Is there a simple way to determine the size of the bytes located at the memory address the IntPtr
points to?
I have tried creating a loop, but it results in an access violation without producing the result.
EDIT: I do not have the bitmap. I have an IntPtr
. Nowhere in my question do I ask about a bitmap.
Instead of returning as int, returned void and write to stream. Writes the data to file but still access violation even with a try/catch.
I can do this knowing the size but on the unknown Scan0
I can get a result but not without the access violation. If the access violation could be caught, I could predetermine the size.
public record struct MemoryPointer(IntPtr Scan0, int Size)
{
public async Task Save(string filePath)
{
byte[] bytes = new byte[Size];
using Stream stream = File.Create(filePath);
unsafe
{
byte* pointer = (byte*)Scan0;
for (int index = 0; index < Size; index++, pointer++)
{
bytes[index] = *pointer;
}
}
await stream.WriteAsync(bytes);
}
}
The actual problem here is simply: passing the wrong Size
- we can't help there, it is upstream to this code.
A pointer by itself, as discussed in the comments, is just the start location. You can't determine the size range from just a pointer (unless that is a pointer to a managed object with type metadata, which isn't the case here). There is a concept that defines what you want .NET - a "span". A span is effectively a managed pointer and the number of elements (bytes in your case) to be considered. If you switched your code to think in terms of spans rather than start/size pairs, it is often easier to keep track of what is happening.
The main reason I mention this, however, is because you're currently copying the data to a byte[]
in order to use WriteAsync
. There is a second WriteAsync
approach that takes a ReadOnlyMemory<byte>
argument. If you were using the synchronous Write
API, then creating a span from a pointer and size is trivial, but for async we need an extra step and we need to know that a [ReadOnly]Memory<T>
is simply an access for [ReadOnly]Span<T>
, and then we can create a "memory" over our span and size using something like this.
To make a ong story short (too late!):
var mgr = new UnmanagedMemoryManager<byte>(Scan0, Size);
await stream.WriteAsync(mrg.Memory);
Ok modern runtimes this should completely avoid any additional copying. On down-level runtimes, it might use a leased array-poop buffer to copy the data, and use the old byte[]
path, but a: you didn't have to write that copy and b: it will at least be leased rather than an allocation each time!