SafeHandle против IntPtr в WinAPI и CloseHandle в C#
Я прочитал много статей о SafeHandle
а также IDiposable
но я все еще не понимаю, должен ли я использовать SafeHandle и CloseHandle или нет в C#.
IntPtr, SafeHandle и HandleRef - Объяснено
https://blog.benoitblanchon.fr/safehandle/.
Первый источник похож на мой вопрос, но не отвечает на мой вопрос.
Допустим, у меня есть следующие 3 различных примера, которые я получил из Интернета:
// Example 1
byte[] temp = new byte[IntPtr.Size];
fixed (byte* p = temp)
{
IntPtr SectionHandle = new IntPtr(p);
LARGE_INTEGER MaximumSize = new LARGE_INTEGER();
MaximumSize.LowPart = pNTHeader->OptionalHeader.SizeOfImage;
status = NtCreateSection(
SectionHandle,
SectionAccess.SECTION_MAP_EXECUTE | SectionAccess.SECTION_MAP_READ | SectionAccess.SECTION_MAP_WRITE,
IntPtr.Zero,
ref MaximumSize,
MemoryProtectionConstants.PAGE_EXECUTE_READWRITE,
AllocationTypes.SEC_COMMIT,
IntPtr.Zero);
}
// Example 2
IntPtr hFile = CreateFile(
path,
GenericRights.GENERIC_READ,
FileFlags.FILE_SHARE_DELETE | FileFlags.FILE_SHARE_READ | FileFlags.FILE_SHARE_WRITE,
IntPtr.Zero,
FileCreationFlags.OPEN_EXISTING,
FileFlags.FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero);
if (hFile == INVALID_HANDLE_VALUE)
return false;
// Example 3
IntPtr hMap = CreateFileMapping(
hFile,
IntPtr.Zero,
MemoryProtectionConstants.PAGE_READONLY,
0,
0,
IntPtr.Zero);
if (hMap == IntPtr.Zero)
return false;
Примерами являются API-интерфейсы Windows, поэтому они неуправляемые. То, что я не понимаю, это:
1) Должны ли все 3 примера использовать SafeHandle поверх IntPtr, потому что они неуправляемые, и если один из них не должен, почему?
2) Я нашел CloseHandle для хорошей практики в C/C++, но в C# я не знаю, закрывает ли сборщик мусора автоматически в конце? Следует ли использовать CloseHandle в приведенных выше примерах и почему?
3) В первом примере используется неуправляемый byte*
выделить память на куче. Можно ли выполнить эту процедуру, не используя неуправляемый указатель? Код ниже - мое предположение, что вы об этом думаете?
IntPtr SectionHandle = Marshal.AllocateHGlobal(sizeof(int));
... code ...
Marshal.FreeHGlobal(SectionHandle);
Редактировать: Размещение кода, который я редактировал:
[SecurityCritical]
public sealed class SafeHandleBuffer : SafeBuffer
{
public SafeHandleBuffer()
: base(true)
{
handle = Marshal.AllocHGlobal(IntPtr.Size);
}
public int GetValue() =>
Marshal.ReadInt32(handle);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
}
public sealed class SafeHandleToken : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeHandleToken()
: base(true)
{
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle() =>
CloseHandle(handle);
}
// Including the IDisposable implementation in the class where the next example calls are found
private SafeHandleToken _fileHandle, _mappingHandle;
private SafeHandleBuffer _sectionHandle;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
protected virtual void Dispose(bool disposing)
{
if (_fileHandle != null && !_fileHandle.IsInvalid)
{
_fileHandle.Dispose();
}
if (_mappingHandle != null && !_mappingHandle.IsInvalid)
{
_mappingHandle.Dispose();
}
if (_sectionHandle != null && !_sectionHandle.IsInvalid)
{
_sectionHandle.Dispose();
}
}
// Example 1
SafeHandleBuffer tempHandle = new SafeHandleBuffer();
LARGE_INTEGER MaximumSize = new LARGE_INTEGER();
MaximumSize.LowPart = pNTHeader->OptionalHeader.SizeOfImage;
status = NtCreateSection(
tempHandle,
SectionAccess.SECTION_MAP_EXECUTE | SectionAccess.SECTION_MAP_READ | SectionAccess.SECTION_MAP_WRITE,
IntPtr.Zero,
ref MaximumSize,
MemoryProtectionConstants.PAGE_EXECUTE_READWRITE,
AllocationTypes.SEC_COMMIT,
IntPtr.Zero);
// Example 2
SafeHandleToken tempHandle = CreateFile(
path,
GenericRights.GENERIC_READ,
FileShare.ReadWrite | FileShare.Delete,
IntPtr.Zero,
FileMode.Open,
FileAttributes.Normal,
IntPtr.Zero);
Thread.Sleep(500);
_fileHandle = tempHandle;
if (_fileHandle.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
// Example 3
tempHandle = CreateFileMapping(
_fileHandle,
IntPtr.Zero,
(uint)MemoryProtectionConstants.PAGE_READONLY | (uint)AllocationTypes.SEC_IMAGE,
0,
0,
IntPtr.Zero);
Thread.Sleep(500);
_mappingHandle = tempHandle;
if (_mappingHandle.IsInvalid)
throw new Win32Exception(Marshal.GetLastWin32Error());
Как вы думаете, я все сделал хорошо? Должен SafeHandle
использоваться на каждом Windows API, как GetModuleHandle
, GetProcAddress
, MapViewOfFile
и еще немного я не помню прямо сейчас. Некоторые из них возвращаются LPVOID
,