Reputation: 225
I'm targeting .NET 4.6.1, and I have C# code that calls C++/CLI code that calls the native Win32 method EnumProcessModulesEx
, which needs a HANDLE as its first input parameter:
// 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, /*...*/);
// ...
}
I have control over both the C# and C++/CLI code, and I'm not doing any P/Invoke. My C++/CLI method currently accepts a Process
parameter, but it's only using the Process.Handle
property (and doing a cast to obtain the necessary HANDLE value). Is this safe, or do I need a SafeProcessHandle
somewhere? If so, how do I pass the SafeProcessHandle
value to EnumProcessModulesEx
? Do I have to call SafeHandle.DangerousGetHandle
?
Upvotes: 1
Views: 622
Reputation: 51330
The purpose of SafeHandle
is to make sure the handle will get released when the SafeHandle
is finalized, so there are no resource leaks. In other words, it lets the GC manage the lifetime of the handle, if you ever neglect to release it manually. P/Invoke understands it and makes sure it's not finalized during the WinAPI call even if you don't hold a reference to it anywhere else.
You can't really use it when using the Win32 API directly, you'd have to call DangerousGetHandle()
which simply returns the raw handle you already have.
In your case, the handle is retrieved with the OpenProcess
WinAPI function, by the Process
class. The docs state that:
When you are finished with the handle, be sure to close it using the
CloseHandle
function.
Which means the Process
class will free it. It does so on the Dispose
call, and also in Close
(Dispose
calls Close
). If you don't dispose the Process
object, the GC will close the handle for you.
So all you have to do is to make sure the GC won't collect the process
object while you're using the handle, or the handle will be invalid. One simple way to ensure that is to call:
System::GC::KeepAlive(process);
after all the code that makes use of the handle. When the JIT sees this function call, it will ensure the process
reference will be marked as used at least until that line (the JIT will report reference reachability to the GC).
If you don't do that, and if you don't use the process
object later in your code, and if a GC occurs, the GC will notice the object is unreachable and collect it (yes, even though you have a local variable referencing it in your code - if you don't access it in the remaining code chunk it will get collected, the GC is very aggressive about that).
See my answer here for more details, although it's about P/Invoke usage.
Upvotes: 1