c#→c++ / CLI→本机方法-需要safeproceshandle

本文关键字:需要 safeproceshandle 方法 CLI c++ 本机 | 更新日期: 2023-09-27 17:53:21

我的目标是。net 4.6.1,我有c#代码调用c++/CLI代码调用本地Win32方法EnumProcessModulesEx,需要一个HANDLE作为其第一个输入参数:

// C#
System.Diagnostics.Process process = // ...
var allModuleNames = ProcessHelper.GetAllModuleNames(process);
// C++/CLI
#include <Psapi.h>
// ...
using namespace System;
using namespace System::Diagnostics;
// ...
array<String^>^ ProcessHelper::GetAllModuleNames(Process^ process)
{
    // Should I use a SafeProcessHandle instead?
    HANDLE processHandle = static_cast<HANDLE>(process->Handle.ToPointer());
    BOOL result = EnumProcessModulesEx(processHandle, /*...*/);
    // ...
}

我控制了c#和c++/CLI代码,我没有做任何p/Invoke。我的c++/CLI方法目前接受Process参数,但它只使用Process.Handle属性(并进行强制转换以获得必要的HANDLE值)。这安全吗,还是我需要一个SafeProcessHandle ?如果是这样,我如何将SafeProcessHandle的值传递给EnumProcessModulesEx ?我必须呼叫SafeHandle.DangerousGetHandle吗?

c#→c++ / CLI→本机方法-需要safeproceshandle

SafeHandle的目的是确保当SafeHandle结束时句柄将被释放,因此没有资源泄漏。换句话说,它允许GC管理句柄的生命周期,如果您忽略了手动释放的话。P/Invoke理解它,并确保它在WinAPI调用期间没有最终确定,即使你没有在其他任何地方保存对它的引用。

当你直接使用Win32 API时,你不能真正使用它,你必须调用DangerousGetHandle(),它只是返回你已经拥有的原始句柄。

在您的例子中,句柄是由Process类通过OpenProcess WinAPI函数检索的。文档声明:

当您完成句柄时,请确保使用CloseHandle函数关闭它。

这意味着Process类将释放它。它在Dispose调用和Close (Dispose调用Close)中都这样做。如果您不处理Process对象,GC将为您关闭句柄。

因此,您所要做的就是确保GC在使用句柄时不会收集process对象,否则句柄将无效。一个简单的方法就是调用:

System::GC::KeepAlive(process);

之后的所有使用句柄的代码。当JIT看到这个函数调用时,它将确保process引用至少在之前被标记为已使用 (JIT将向GC报告引用可达性)。

如果你不这样做,如果你在代码中不使用process对象,如果发生GC, GC将注意到对象不可达并收集它(是的,即使你在代码中有一个引用它的局部变量-如果你不在剩余的代码块中访问它,被收集,GC对此非常积极)。

查看我的答案在这里获得更多细节,尽管它是关于p/Invoke的使用。