This documentation is archived and is not being maintained.

7.8 Direct Access to Characters

Visual Studio .NET 2003

Managed Extensions allows direct access to the characters of a String object for high-performance calls to unmanaged functions that take wchar_t* strings. The method yields an interior __gc pointer to the first character of the String object. This pointer can be manipulated directly or can be pinned and passed to a function expecting an ordinary wchar_t string.

Example

// __gc_pointer22.cpp
// compile with: /clr /LD
#using <mscorlib.dll>
#include <string.h>
#include <vcclr.h>
using namespace System;

size_t getlen(String *s) {
   // make sure it doesn't move during the unmanaged call
   const wchar_t __pin* pinchars = PtrToStringChars(s); 
   return wcslen(pinchars);
};
Note   String objects are immutable and cannot be modified.

PtrToStringChars returns a System::Char*, which is an interior pointer (also known as a byref). As such, it is subject to garbage collection. You don't have to pin this pointer unless you're going to pass it to a native function.

Consider the following code:

Char * ppchar = PtrToStringChars( mystring ); // __pin not needed
for( ; ppchar != 0; ++ppchar )
{
   // do stuff with each Char
}

Pinning is not needed because ppchar is an interior pointer, and if the garbage collector moves the string it points to, it will also update ppchar. Without __pin the code will work and not have the potential performance hit caused by pinning.

If you pass ppchar to a native function, then it must be a pinning pointer; the garbage collector will not be able to update any pointers on the unmanaged stack frame.

An interior gc (byref) pointer has all the properties of a native C++ pointer. For example, you can use it to walk a linked data structure and do insertions and deletions using only one pointer:

//__gc_PtrToStringChars.cpp
// compile with: /clr /LD
#using <mscorlib.dll>
using namespace System;
__gc struct ListNode
{
   Int32 elem; 
   ListNode*Next;
};

void deleteNode( ListNode*list, Int32 e )
{
   ListNode ** ptrToNext = &list;   // ptr-to-ptr to gc node is byref ptr
   while (*ptrToNext != 0)
   {
      if ( (*ptrToNext) -> elem == e )
      {
         *ptrToNext = (*ptrToNext) -> Next;   // delete the node
      }
      else
      {
         ptrToNext = &(*ptrToNext) -> Next;   // move on to the next node
      }
   }
}
Show: