This is code example which causes MarshalDirectiveException. Good explanation of SafeHandles could be found here.
[SuppressUnmanagedCodeSecurity]
private delegate SafeHandle testDelegate();
[SuppressUnmanagedCodeSecurity]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static SafeHandle test(){
FileStream fs=new FileStream("a.txt", FileMode.Create);
return fs.SafeFileHandle;
}
private static void Main(){
MethodInfo methodInfo = typeof (Program).GetMethod("test", BindingFlags.Static | BindingFlags.Public);
Delegate delegateInstance = Delegate.CreateDelegate(typeof (testDelegate), methodInfo);
//System.Runtime.InteropServices.MarshalDirectiveException
//Cannot marshal 'return value': SafeHandles cannot be returned from managed to unmanaged.
IntPtr fcePtr = Marshal.GetFunctionPointerForDelegate(delegateInstance);
// alternatively for method parameter
// throws System.Runtime.InteropServices.MarshalDirectiveException
// Cannot marshal 'parameter #1': This type can only be marshaled in restricted ways."
// alternatively for HandleRef
// System.Runtime.InteropServices.MarshalDirectiveException
// Cannot marshal 'parameter #1': HandleRefs cannot be marshaled ByRef or from unmanaged to managed.
}
Simply said, naked handle, received as int or IntPtr could be leaking, when exception is throws before wrapped to appropriate Dipose patter. When returning naked handle to native code, it tends to be g-collected before native code uses the handle. I'm interested to learn how to workaround this problem with enough safety. Specially returning handle worries me. These are just examples for brevity, I don't work with File handle in reality. I would rather like inherit my own from SafeHandle.
[DllImport("mydll")]
public static extern void naked(IntPtr nakedHandle);
private static void Main(){
IntPtr intPtr = getHandle();
naked(intPtr);
}
private static IntPtr getHandle(){
FileStream fs = new FileStream("myfile", FileMode.CreateNew);
IntPtr ha = fs.Handle;
return ha;
// at this point, fs is garbage collected.
// ha is pointing to nonexistent or different object.
}