c# - F# 中是否有 C# 和 VB 兼容的 System.Void*? (关闭指向非托管 Alloc 的指针?)

标签 c# vb.net f# interop kernel32

    [<DllImport("kernel32")>]
    extern bool CloseHandle(System.Void* handle);
    //System.Void also throws same error
    //extern bool CloseHandle(System.Void handle); 

给出错误:

'System.Void' can only be used as 'typeof' in F#

但是

    extern bool CloseHandle(typeof<System.Void> handle);

不编译。同样的错误,

"System.Void can only be used as typeof..."

F# void* 编译

    extern bool CloseHandle(void* handle);

但在 C# 中使用它会引发设计时转换错误

public void CloseBeforeGarbageCollection(IntPtr someAllocIntPtr)
{
    //test unmanaged block
    var result = CloseHandle(someAllocIntPtr.ToPointer());
    return result;
}

'cannot convert from 'void*' to 'System.IntPtr'

虽然传递托管 IntPtr 将编译

//test managed IntPtr
var result = CloseHandle(someAllocIntPtr); //throws error at runtime

但是当 someAllocIntPtrMarshal.AllocHGlobal 的结果时,它会抛出运行时异常 External component has thrown an exception.。 据我了解,发生这种情况是因为 someAllocIntPtr(作为 Marshal.AllocHGlobal 的结果)在技术上是指向非托管指针的托管指针,与普通 IntPtr 不同。 Peter Ritchie 在对他的回答的回复中指出了这一点:System.Runtime.InteropServices.SEHException (0x80004005): External component has thrown an exception

避免此运行时异常的唯一方法是将句柄包装在 SecureHandle() 子类中,但我认为这违反了 ref-ref\out-out MSDN 上的规则:CA1021: Avoid out parameters . IE,System.Void* realPointer = someAllocIntPtr.ToPointer() 是 ACTUAL 指针(对非托管指针的引用),或者换句话说,SecureHandle safeHandle = new SecureHandle(someAllocIntPtr) 实际上是“对 - 的另一个引用 - 一个实际指针的引用”,不应使用 outref 关键字,根据 MSDN 文章。

最佳答案

我通过以下方式做了一个小测试:

在 f# 程序集(dll 库)中,我有以下模块:

module MyWin32
open System
open System.Runtime.InteropServices

[<DllImport("kernel32")>]
extern bool CloseHandle(IntPtr handle);

[<DllImport("kernel32")>]
extern IntPtr CreateToolhelp32Snapshot(IntPtr flag, IntPtr procId);

在引用上述库的 F# 控制台程序中,我有:

open System
open System.Runtime.InteropServices
open MyWin32

[<EntryPoint>]
let main argv = 

  let handle = CreateToolhelp32Snapshot(IntPtr(4), IntPtr(System.Diagnostics.Process.GetCurrentProcess().Id))
  printfn "%A" handle
  printfn "%b" (CloseHandle handle)

  // A HGlobal should always be released by FreeHGlobal
  let intPtr = Marshal.AllocHGlobal(1024)
  Marshal.FreeHGlobal(intPtr)

在引用上述库的 C# 控制台程序中,我有:

using System;

namespace CSTest
{
  class Program
  {
    static void Main(string[] args)
    {
      var handle = MyWin32.CreateToolhelp32Snapshot(new IntPtr(4), new IntPtr(System.Diagnostics.Process.GetCurrentProcess().Id));
      Console.WriteLine(handle);
      Console.WriteLine(MyWin32.CloseHandle(handle));

      Console.ReadLine();
    }
  }
}

F# 和 C# 测试均按预期编译和运行。希望对您有所帮助。

关于无效*:

将上面显示的 f# 程序集 MyWin32 更改为以下内容并将 IntPtr 替换为 void* 仍然适用于 F# 和 C# 客户端,无需任何其他修改(MyWin32 的 C# 元数据代码将 void* 替换为 IntPtr):

module MyWin32
open System
open System.Runtime.InteropServices

[<DllImport("kernel32")>]
extern bool CloseHandle(void* handle);

[<DllImport("kernel32")>]
extern void* CreateToolhelp32Snapshot(IntPtr flag, IntPtr procId);

因此以上小测试的结论是,您可以在 F# 中使用 void* 作为 IntPtr 的有效替代。

我认为应该只在 C# 的不安全 {} 部分使用 IntPtr.ToPointer(),因为指针只在 C# 的不安全模式下才有意义。

关于c# - F# 中是否有 C# 和 VB 兼容的 System.Void*? (关闭指向非托管 Alloc 的指针?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39783269/

相关文章:

c# - 为什么默认枚举值是 0 而不是最小值?

c# - 为什么我的 GridView CSSClass 没有被应用?

c# - .Net Winforms 中 Graphics.DrawString 和 TextRenderingHint 的可能错误

c# - 拆分字符串并忽略引号内的定界符

functional-programming - FsCheck 生成器能否创建不断增加的序列

visual-studio-2010 - 如何在 Visual Studio 2010 中更改 F# 交互式 shell 的颜色

visual-studio - 在 Visual Studio 上调试 F# 代码时,未处理异常的位置不正确

c# - Windows Phone 8 上的 UDP 多播组

c# - System.Web.HttpUtility.UrlEncode/UrlDecode ASP.NET 5 的替换

mysql - 为什么不正确地命令 asc?