Это пример кода, который вызывает исключение MarshalDirectiveException. Хорошее объяснение SafeHandle s можно найти здесь .
[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.
}
Проще говоря, голый дескриптор, полученный как int или IntPtr, может быть утечкой, когда исключение - броски перед переносом в соответствующий шаблон Dipose. При возврате «голого» дескриптора в собственный код, он имеет тенденцию собираться до того, как нативный код использует дескриптор. Мне интересно узнать, как обойти эту проблему с достаточной безопасностью. Меня особенно беспокоит возвращающаяся ручка. Это всего лишь примеры для краткости, в действительности я не работаю с дескриптором файла. Я бы предпочел унаследовать свое от 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.
}