Saturday, July 7, 2007

Pointer in C#

In case of C# you cannot get the pointer to any object, or object is not fixed in a position or you want your object reference will be same. But to communicate with legacy technology you may need a pointer which can be handle, pointer or something like that. There is a way so that the object will construct in the same location always or you have access to the object from same location. That is you fixed it in that location. This is called pin/unpin mechanism.

Here I build a class which is simply storage for an object but the location of that object is always remains constant. So, once you get the location of storage object any value you assign as object will be accessible from that location. Thats the trick,

This is very much similar to create a pointer first then assign any object to that pointer. Is it possible in C#? yes of course...

class Pointer
{
object internalObject;
GCHandle handle;
public IntPtr Pin()
{
if (handle.IsAllocated == false)
{
long _long = 0;
internalObject = _long;
handle = GCHandle.Alloc(internalObject, GCHandleType.Pinned);
}
return handle.AddrOfPinnedObject();
}
public void Unpin()
{
if (handle.IsAllocated == true)
{
handle.Free();
}
return ;
}
public T Value
{
get { return (T)internalObject; }
set { internalObject = (object)value; }
}
}


First create an instance of this object then Pin in by calling Pin() method you get the pointer as return value, and then assign your object to this object which is now accessible from your previously obtain pointer. This is very useful to create Stream object.

4 comments:

  1. Do you have a concrete example that you can show? Also does this make the C# code unsafe? Cool blog!

    ReplyDelete
  2. yes of course, this is if want to communicate with legacy technology.
    So, may lot of unsafe code can be out there.

    Here is a stream class that use a legacy stream class in C#

    public class AMStream : System.IO.Stream, IDisposable
    {
    private bool disposed = false;
    protected IStream thisStream;
    private string ID = "";
    private Pointer<long> NewPosition = new Pointer<long>();
    private Pointer<ulong> BytesTransferred = new Pointer<ulong>();

    internal AMStream(object newStream)
    {
    thisStream = (IStream)newStream;
    }
    public override long Position
    {
    get
    {
    thisStream.Seek(0, (int)STREAM_SEEK.STREAM_SEEK_CUR, NewPosition.Pin());
    NewPosition.Unpin();
    return (long)NewPosition.Value;
    }
    set
    {
    Pointer ignored = new Pointer(0);
    thisStream.Seek(0, (int)STREAM_SEEK.STREAM_SEEK_CUR, ignored);
    }
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
    thisStream.Read(buffer, count, BytesTransferred.Pin());
    BytesTransferred.Unpin();
    return (int)BytesTransferred.Value;
    }
    public override void Write(byte[] buffer, int offset, int count)
    {
    thisStream.Write(buffer, count, BytesTransferred.Pin());
    BytesTransferred.Unpin();
    }
    }

    ReplyDelete
  3. Thanks that helps. Couple more questions - do you have to compile this as unsafe? Also I have a case that where I want to pass a delegate into unmanged code (C). This unmanged code will hold onto the delagate and call it later. Can your Pointer class be used in this scenario?

    ReplyDelete

Please, no abusive word, no spam.