public unsafe static int Main(string[] args) { try{ const int intManaged = 1000; const int intNative = 2000; const int intReturn = 3000; const int stackGuard = 5000; Console.WriteLine("MarshalPointer_In"); int int1 = intManaged; int * int1Ptr = &int1; HandleRef hr1 = new HandleRef(new Object(), (IntPtr)int1Ptr); Assert.AreEqual(intReturn, MarshalPointer_In(hr1, stackGuard), "The return value is wrong"); Assert.AreEqual(intManaged, int1, "The parameter value is changed"); Console.WriteLine("MarshalPointer_InOut"); int int2 = intManaged; int * int2Ptr = &int2; HandleRef hr2 = new HandleRef(new Object(), (IntPtr)int2Ptr); Assert.AreEqual(intReturn, MarshalPointer_InOut(hr2, stackGuard), "The return value is wrong"); Assert.AreEqual(intNative, int2, "The passed value is wrong"); Console.WriteLine("MarshalPointer_Out"); int int3 = intManaged; int * int3Ptr = &int3; HandleRef hr3 = new HandleRef(new Object(), (IntPtr)int3Ptr); Assert.AreEqual(intReturn, MarshalPointer_Out(hr3, stackGuard), "The return value is wrong"); Assert.AreEqual(intNative, int3, "The passed value is wrong"); // Note that this scenario will always pass in a debug build because all values // stay rooted until the end of the method. Console.WriteLine("TestNoGC"); // Keep the int boxed and pinned to prevent it from getting collected. // That way, we can safely reference it from finalizers that run on shutdown. BoxedInt boxedInt = new BoxedInt(); GCHandle.Alloc(boxedInt, GCHandleType.Normal); int *int4Ptr; fixed(int *tempIntPtr = &boxedInt.MyInt) { // Smuggle the pointer out of the fixed scope int4Ptr = tempIntPtr; } Console.WriteLine("2"); *int4Ptr = intManaged; CollectableClass collectableClass = new CollectableClass(int4Ptr); HandleRef hr4 = new HandleRef(collectableClass, (IntPtr)int4Ptr); Action gcCallback = () => { Console.WriteLine("GC callback now"); GC.Collect(2, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); GC.Collect(2, GCCollectionMode.Forced); }; Assert.AreEqual(intReturn, TestNoGC(hr4, gcCallback), "The return value is wrong"); Console.WriteLine("Native code finished"); return(100); } catch (Exception e) { Console.WriteLine($"Test Failure: {e}"); return(101); } }
public unsafe static int Main(string[] args) { try{ const int intManaged = 1000; const int intNative = 2000; const int intReturn = 3000; const int stackGuard = 5000; Console.WriteLine("MarshalPointer_In"); int int1 = intManaged; int * int1Ptr = &int1; HandleRef hr1 = new HandleRef(new Object(), (IntPtr)int1Ptr); Assert.AreEqual(intReturn, MarshalPointer_In(hr1, stackGuard), "The return value is wrong"); Assert.AreEqual(intManaged, int1, "The parameter value is changed"); Console.WriteLine("MarshalPointer_InOut"); int int2 = intManaged; int * int2Ptr = &int2; HandleRef hr2 = new HandleRef(new Object(), (IntPtr)int2Ptr); Assert.AreEqual(intReturn, MarshalPointer_InOut(hr2, stackGuard), "The return value is wrong"); Assert.AreEqual(intNative, int2, "The passed value is wrong"); Console.WriteLine("MarshalPointer_Out"); int int3 = intManaged; int * int3Ptr = &int3; HandleRef hr3 = new HandleRef(new Object(), (IntPtr)int3Ptr); Assert.AreEqual(intReturn, MarshalPointer_Out(hr3, stackGuard), "The return value is wrong"); Assert.AreEqual(intNative, int3, "The passed value is wrong"); // Note that this scenario will always pass in a debug build because all values // stay rooted until the end of the method. Console.WriteLine("TestNoGC"); int *int4Ptr = (int *)Marshal.AllocHGlobal(sizeof(int)); // We don't free this memory so we don't have to worry about a GC run between freeing and return (possible in a GCStress mode). Console.WriteLine("2"); *int4Ptr = intManaged; CollectableClass collectableClass = new CollectableClass(int4Ptr); HandleRef hr4 = new HandleRef(collectableClass, (IntPtr)int4Ptr); Action gcCallback = () => { Console.WriteLine("GC callback now"); GC.Collect(2, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); GC.Collect(2, GCCollectionMode.Forced); }; Assert.AreEqual(intReturn, TestNoGC(hr4, gcCallback), "The return value is wrong"); Console.WriteLine("Native code finished"); Console.WriteLine("InvalidMarshalPointer_Return"); Assert.Throws <MarshalDirectiveException>(() => InvalidMarshalPointer_Return()); return(100); } catch (Exception e) { Console.WriteLine($"Test Failure: {e}"); return(101); } }