Passing Managed Memory to a Native Function

Native pointers should not refer into the managed heap, because a managed object that a native pointer would refer to could be relocated. So far, I have discussed two concepts for referring into the managed heap. These are tracking handles (and tracking references) that refer to a managed object's header, as well as interior pointers that refer to a part of the managed object's state. The runtime is able to automatically update all tracking handles and interior pointers. However, the runtime is not aware of native pointers referring into the managed heap. Therefore, it cannot update native pointers.

Nevertheless, there can be scenarios in which reading or updating the state of a managed object directly from native code is desired. For example, instead of copying a managed byte array into a native memory block so that native code can access the copied state, it would be more efficient if native code could directly read the managed array's state. For write operations, the situation is similar: instead of modifying a native memory block and copying it byte by byte into a managed array, it would likely be faster to update the managed array directly from native code. Reading or modifying the copied state could also require special attention with respect to concurrent updates from other threads.

.NET has a concept that allows native pointers to temporarily refer to a managed object. To understand this concept, it is useful to take a step back and review interior pointers. An interior pointer allows managed code to iterate through a managed array via pointer arithmetic, as this sample from Chapter 2 shows:

void WeakEncrypt(array<unsigned char>A bytes, unsigned char key) {

cli::interior_ptr<unsigned char> pb = &(bytes[0]); interior_ptr<unsigned char> pbEnd = pb + bytes->Length;

If you have a native function that expects a pointer to a native array as an argument, an interior pointer is not sufficient. The following prototype shows a native encryption function:

void NativeWeakEncrypt(unsigned char* rgb, int cb, unsigned char key);

Even though an interior pointer supports pointer arithmetic, it cannot be converted or casted into a native pointer. Trying to call NativeWeakEncrypt by passing an interior pointer will cause a compiler error:

cli::interior_ptr<Byte> pb = &(bytes[0]); NativeWeakEncrypt(pb, bytes->Length, key); // error: cannot convert from interior_ptr<unsigned char> to unsigned char*

NativeWeakEncrypt uses the parameter it receives to access memory. If an interior pointer could be passed as a native pointer and the array were relocated during garbage collection, NativeWeakEncrypt would touch the wrong memory after the relocation. To avoid this dilemma, objects on the GC heap can be temporarily pinned. While an object is pinned, it cannot be relocated during a garbage collection phase. The following code shows how to pin an object:

void CallNativeWeakEncrypt(array<unsigned char>A bytes, unsigned char key) {

Was this article helpful?

0 0

Post a comment