有没有c# &VB兼容系统.f#中的Void* ?(关闭指向非托管Alloc的指针?)
本文关键字:指针 Alloc VB 系统 有没有 Void 中的 | 更新日期: 2023-09-27 18:09:40
[<DllImport("kernel32")>]
extern bool CloseHandle(System.Void* handle);
//System.Void also throws same error
//extern bool CloseHandle(System.Void handle);
给出错误:
"系统。Void'只能在f#
中用作'typeof'
,
extern bool CloseHandle(typeof<System.Void> handle);
不能编译。同样的错误,
"系统。Void只能用作typeof…"
f# void*
does compile
extern bool CloseHandle(void* handle);
但是在c#中使用它会抛出设计时转换错误
public void CloseBeforeGarbageCollection(IntPtr someAllocIntPtr)
{
//test unmanaged block
var result = CloseHandle(someAllocIntPtr.ToPointer());
return result;
}
'无法从'void*'转换为'System '。IntPtr '
通过传递托管IntPtr将编译
//test managed IntPtr
var result = CloseHandle(someAllocIntPtr); //throws error at runtime
但是当someAllocIntPtr
是Marshal.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()
子类中,但我认为这违反了MSDN上的ref-ref'out-out
规则:CA1021:避免输出参数。IE, System.Void* realPointer = someAllocIntPtr.ToPointer()
是实际指针(对非托管指针的引用),或者换句话说,SecureHandle safeHandle = new SecureHandle(someAllocIntPtr)
实际上是"的另一个引用 -一个实际指针",根据MSDN文章,不应该与out
或ref
关键字一起传递。
我用下面的方法做了一个小测试:
在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#测试都按预期编译和运行。我希望这对你有帮助。
关于void *:
将上面显示的f#汇编MyWin32用IntPtr替换为void*仍然适用于f#和c#客户端,而无需任何其他修改(MyWin32的c#元数据代码用IntPtr替换void*):
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#中只有在不安全的模式下才有意义。