gpt4 book ai didi

c# - 如何使用 SafeHandle 或解决方法获取方法的 GetFunctionPointerForDelegate

转载 作者:行者123 更新时间:2023-11-30 17:23:41 31 4
gpt4 key购买 nike

这是导致 MarshalDirectiveException 的代码示例。很好的解释SafeHandle可以找到 s 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.
}

简单地说,当异常在包装到适当的 Dipose 模式之前抛出时,作为 int 或 IntPtr 接收的裸句柄可能会泄漏。将裸句柄返回给 native 代码时,它往往会在 native 代码使用该句柄之前被 g-collected。我有兴趣了解如何在足够安全的情况下解决此问题。特地返回句柄让我担心。这些只是为了简洁起见的示例,我实际上并没有使用文件句柄。我宁愿从 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.
}

最佳答案

处理此问题的典型方法是在调用非托管函数之前将数据固定在托管代码中。 Here是固定数据和调用非托管调用的示例。

更新:根据评论,您可以使用 HandleRef 使对象引用保持事件状态。然后您仍然可以将“句柄”传递给您的 PInvoke 调用。这是一个对我有用的例子:

  [DllImport("kernel32.dll", SetLastError=true)]
static extern bool ReadFile(HandleRef hFile, byte[] lpBuffer,
uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);

private static HandleRef getHandle()
{
FileStream fs = new FileStream("myfile", FileMode.OpenOrCreate, FileAccess.ReadWrite);
return new HandleRef(fs, fs.SafeFileHandle.DangerousGetHandle());
}

private static void Main()
{
HandleRef intPtr = getHandle();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
System.Threading.Thread.Sleep(1000);

const uint BYTES_TO_READ = 10;
byte[] buffer = new byte[BYTES_TO_READ];
uint bytes_read = 0;

bool read_ok = ReadFile(intPtr, buffer, BYTES_TO_READ, out bytes_read, IntPtr.Zero);
if (!read_ok)
{
Win32Exception ex = new Win32Exception();
string errMsg = ex.Message;
}
}

差点忘了清理这里:

  IDisposable is_disposable = intPtr.Wrapper as IDisposable;
if (is_disposable != null)
{
is_disposable.Dispose();
}

关于c# - 如何使用 SafeHandle 或解决方法获取方法的 GetFunctionPointerForDelegate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2035528/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com