Search code examples
c#pointerspinvoke

Can't seem to get a non-zero IntPtr from a byte[] instance variable


I've found many ways of getting an IntPtr from a byte[], all of which I could successfully pass into external unmanaged code, but only if I allocate the byte[] on the stack. Attempting to do the same on a byte[] instance variable, I get a null (IntPtr.Zero) result, no matter which method of getting an IntPtr I choose. I haven't found any information on whether or not instance variables are treated differently than those allocated on the stack, in this case.

Here is what I would like to use to acquire a valid IntPtr to a byte[] instance variable:

GCHandle pinned = GCHandle.Alloc(outBytes, GCHandleType.Pinned);
IntPtr ptr = pinned.AddrOfPinnedObject();

// Always true, for reasons I'm unaware.
if (ptr == IntPtr.Zero) {}

pinned.Free();

Thanks!


Solution

  • The only time that GCHandle.Alloc( thing, GCHandleType.Pinned ) results in a handle to IntPtr.Zero is when thing is null.

    Your byte array reference is null when you provide it to GCHandle.Alloc().

    Here's where it returns zero:

    public class ZeroTest
    {
        private byte[] someArray;
    
        public Test()
        {
            this.someArray = null;
        }
    
        public void DoMarshal()
        {
            GCHandle handle = GCHandle.Alloc( this.someArray, GCHandleType.Pinned );
    
            try
            {
                // Prints '0'.
                Console.Out.WriteLine( handle.AddrOfPinnedObject().ToString() );
            }
            finally
            {
                handle.Free();
            }
        }
    }
    

    Here's where it returns non-zero:

    public class Test
    {
        private byte[] someArray;
    
        public Test()
        {
            this.someArray = new byte[1];
        }
    
        public void DoMarshal()
        {
            GCHandle handle = GCHandle.Alloc( this.someArray, GCHandleType.Pinned );
    
            try
            {
                // Prints a non-zero address, like '650180924952'.
                Console.Out.WriteLine( handle.AddrOfPinnedObject().ToString() );
            }
            finally
            {
                handle.Free();
            }
        }
    }