Wednesday, August 29, 2007

Pointers in C#

Because i need conversions from and to pointers for arrays and structures, i made a little class that can to the job for me.

The most common problem is that all examples that I've found, copies arrays, or fills them up. But no examples of getting a pointer back into an array, without giving the startindex and count of the elements.

I made it possible to convert an array to pointer and visa versa, without those boundaries. You will have to use this class however to convert to and from the pointers. Because I add a 'delimiter' to the end of the data in the pointer.

I hope some of you can use the snippet(s) below. If so, let me know ;)

Regards


1: public static unsafe class Pointers

   2: {
   3:     #region To Pointer
   4:  
   5:     /// <summary>
   6:     /// Converts an array to a pointer.
   7:     /// Ex. int[] to int*
   8:     /// </summary>
   9:     /// <param name="array">Array to convert.</param>
  10:     /// <returns>Pointer to array</returns>
  11:     public static int* ConvertArrayToPointer(int[] array)
  12:     {
  13:         fixed (int* pArray = array)
  14:         {
  15:             int* reference = pArray;
  16:             *(reference + array.Length) = int.MinValue;
  17:             return pArray;
  18:         }
  19:     }
  20:  
  21:     /// <summary>
  22:     /// Converts an array to a pointer.
  23:     /// Ex. uint[] to uint*
  24:     /// </summary>
  25:     /// <param name="array">Array to convert.</param>
  26:     /// <returns>Pointer to array</returns>
  27:     public static uint* ConvertArrayToPointer(uint[] array)
  28:     {
  29:         fixed (uint* pArray = array)
  30:         {
  31:             uint* reference = pArray;
  32:             *(reference + array.Length) = uint.MaxValue;
  33:             return pArray;
  34:         }
  35:     }
  36:  
  37:     /// <summary>
  38:     /// Converts an array to a pointer.
  39:     /// Ex. char[] to char*
  40:     /// </summary>
  41:     /// <param name="array">Array to convert.</param>
  42:     /// <returns>Pointer to array</returns>
  43:     public static char* ConvertArrayToPointer(char[] array)
  44:     {
  45:         fixed (char* pArray = array)
  46:         {
  47:             char* reference = pArray;
  48:             *(reference + array.Length) = char.MinValue;
  49:             return pArray;
  50:         }
  51:     }
  52:  
  53:     #endregion
  54:  
  55:     #region FromPointer
  56:  
  57:     /// <summary>
  58:     /// Converts a pointer to an array to a managed array.
  59:     /// Ex. int* to int[]
  60:     /// </summary>
  61:     /// <param name="array">Pointer to an array to convert</param>
  62:     /// <param name="startIndex">StartIndex from where to convert</param>
  63:     /// <param name="count">Number of elements to include in result-array</param>
  64:     /// <returns>Requested array of elements.</returns>
  65:     public static int[] ConvertPointerToArray(int* array, int startIndex, int count)
  66:     {
  67:         int[] data = new int[count -startIndex];
  68:  
  69:         for (int i = startIndex; i < count; i++)
  70:         {
  71:             int tempVal = *(array + i);
  72:             data[i] = tempVal;
  73:         }
  74:         return data;
  75:     }
  76:  
  77:     /// <summary>
  78:     /// Converts a pointer to an array to an array.
  79:     /// This array has an delimitor at the end to know when to stop converting.
  80:     /// </summary>
  81:     /// <param name="array">Pointer to an array</param>
  82:     /// <returns>Requested array</returns>
  83:     public static int[] ConvertPointerToArray(int* array)
  84:     {
  85:         List<int> data = new List<int>();
  86:  
  87:         int index = 0;
  88:         int tempVal = *(array + index++);
  89:         data.Add(tempVal);
  90:  
  91:         while (tempVal != int.MinValue)
  92:         {
  93:             tempVal = *(array + index++);
  94:             if(tempVal != int.MinValue)
  95:                 data.Add(tempVal);
  96:         }
  97:  
  98:         return data.ToArray();
  99:     }
 100:  
 101:     /// <summary>
 102:     /// Converts a pointer to an array to a managed array.
 103:     /// Ex. char* to char[]
 104:     /// </summary>
 105:     /// <param name="array">Pointer to an array to convert</param>
 106:     /// <param name="startIndex">StartIndex from where to convert</param>
 107:     /// <param name="count">Number of elements to include in result-array</param>
 108:     /// <returns>Requested array of elements.</returns>
 109:     public static char[] ConvertPointerToArray(char* array, int startIndex, int count)
 110:     {
 111:         char[] data = new char[count - startIndex];
 112:  
 113:         for (int i = startIndex; i < count; i++)
 114:         {
 115:             char tempVal = *(array + i);
 116:             data[i] = tempVal;
 117:         }
 118:         return data;
 119:     }
 120:  
 121:     /// <summary>
 122:     /// Converts a pointer to an array to an array.
 123:     /// This array has an delimitor at the end to know when to stop converting.
 124:     /// </summary>
 125:     /// <param name="array">Pointer to an array</param>
 126:     /// <returns>Requested array</returns>
 127:     public static char[] ConvertPointerToArray(char* array)
 128:     {
 129:         List<char> data = new List<char>();
 130:  
 131:         int index = 0;
 132:         char tempVal = *(array + index++);
 133:         data.Add(tempVal);
 134:  
 135:         while (tempVal != char.MinValue)
 136:         {
 137:             tempVal = *(array + index++);
 138:             if (tempVal != char.MinValue)
 139:                 data.Add(tempVal);
 140:         }
 141:  
 142:         return data.ToArray();
 143:     }
 144:  
 145:     /// <summary>
 146:     /// Converts a pointer to an array to a managed array.
 147:     /// Ex. uint* to uint[]
 148:     /// </summary>
 149:     /// <param name="array">Pointer to an array to convert</param>
 150:     /// <param name="startIndex">StartIndex from where to convert</param>
 151:     /// <param name="count">Number of elements to include in result-array</param>
 152:     /// <returns>Requested array of elements.</returns>
 153:     public static uint[] ConvertPointerToArray(uint* array, int startIndex, int count)
 154:     {
 155:         uint[] data = new uint[count - startIndex];
 156:  
 157:         for (int i = startIndex; i < count; i++)
 158:         {
 159:             uint tempVal = *(array + i);
 160:             data[i] = tempVal;
 161:         }
 162:         return data;
 163:     }
 164:  
 165:     /// <summary>
 166:     /// Converts a pointer to an array to an array.
 167:     /// This array has an delimitor at the end to know when to stop converting.
 168:     /// </summary>
 169:     /// <param name="array">Pointer to an array</param>
 170:     /// <returns>Requested array</returns>
 171:     public static uint[] ConvertPointerToArray(uint* array)
 172:     {
 173:         List<uint> data = new List<uint>();
 174:  
 175:         int index = 0;
 176:         uint tempVal = *(array + index++);
 177:         data.Add(tempVal);
 178:  
 179:         while (tempVal != uint.MaxValue)
 180:         {
 181:             tempVal = *(array + index++);
 182:             if (tempVal != uint.MaxValue)
 183:                 data.Add(tempVal);
 184:         }
 185:  
 186:         return data.ToArray();
 187:     }
 188:  
 189:     #endregion
 190:  
 191:     #region Internal Pointers
 192:  
 193:     /// <summary>
 194:     /// Converts a structure to a IntPtr
 195:     /// </summary>
 196:     /// <typeparam name="T">Type of structure</typeparam>
 197:     /// <param name="value">Struct to convert</param>
 198:     /// <returns>IntPtr of the struct</returns>
 199:     public static IntPtr ToIntPtr<T>(T value)
 200:         where T : struct
 201:     {
 202:         IntPtr pointer = Marshal.AllocHGlobal(Marshal.SizeOf(value));
 203:         Marshal.StructureToPtr(value, pointer, true);
 204:         return pointer;
 205:     }
 206:  
 207:     /// <summary>
 208:     /// Converts an IntPtr to a struct
 209:     /// </summary>
 210:     /// <typeparam name="T">Type of structure</typeparam>
 211:     /// <param name="pointer">Internal Pointer of structure</param>
 212:     /// <returns>Requested struct</returns>
 213:     public static T FromIntPtr<T>(IntPtr pointer, bool destruct)
 214:         where T : struct
 215:     {
 216:         T structure = (T)Marshal.PtrToStructure(pointer, typeof(T));
 217:         if (destruct)
 218:         {
 219:             Marshal.Release(pointer);
 220:         }
 221:         return structure;
 222:     }
 223:  
 224:     #endregion
 225:  
 226:  
 227:     public static void DoTest(int[] array)
 228:     {
 229:         // Make a pointer of the array
 230:         int* pointer = Pointers.ConvertArrayToPointer(array);
 231:         // Make an array of the pointer-data
 232:         int[] data = Pointers.ConvertPointerToArray(pointer, 0, array.Length);
 233:         // Same as above, but without bounderies.
 234:         data = Pointers.ConvertPointerToArray(pointer);
 235:  
 236:         // Make us a testing structure
 237:         TestStruct ts = new TestStruct("This is my teststruct");
 238:         // Convert the struct to an IntPtr
 239:         IntPtr ptr = ToIntPtr<TestStruct>(ts);
 240:         // Convert IntPtr back to a struct.
 241:         // Don't forget the destruction, for memory leak prevention!
 242:         TestStruct test = FromIntPtr<TestStruct>(ptr, true);
 243:     }
 244:  
 245:     internal struct TestStruct
 246:     {
 247:         private string _msg;
 248:  
 249:         public TestStruct(string message)
 250:         {
 251:             _msg = message;
 252:         }
 253:  
 254:         public string Msg
 255:         {
 256:             get { return _msg; }
 257:             set { _msg = value; }
 258:         }
 259:     }
 260: }

1 comment:

OlegVK said...

Per Microsoft Documentation on "fixed":

After the code in the statement is executed, any pinned variables are unpinned and subject to garbage collection. Therefore, do not point to those variables outside the fixed statement.

So, returned pointer from your routines is un-fixed. Object can be moved in memory...