Search code examples
c#interop

Converting Intptr to size


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);
    }
}

Solution

  • 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!