// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using Microsoft.Win32.SafeHandles;
namespace Security2
{
using HANDLE = System.IntPtr;
internal sealed class SafeHGlobalHandle : IDisposable
{
#region Constructor and Destructor
SafeHGlobalHandle()
{
pointer = IntPtr.Zero;
}
SafeHGlobalHandle(IntPtr handle)
{
pointer = handle;
}
~SafeHGlobalHandle()
{
Dispose();
}
#endregion
#region Public methods
public static SafeHGlobalHandle InvalidHandle
{
get { return new SafeHGlobalHandle(IntPtr.Zero); }
}
///
/// Adds reference to other SafeHGlobalHandle objects, the pointer to
/// which are refered to by this object. This is to ensure that such
/// objects being referred to wouldn't be unreferenced until this object
/// is active.
///
/// For e.g. when this object is an array of pointers to other objects
///
/// Collection of SafeHGlobalHandle objects
/// referred to by this object.
public void AddSubReference(IEnumerable children)
{
if (references == null)
{
references = new List();
}
references.AddRange(children);
}
///
/// Allocates from unmanaged memory to represent an array of pointers
/// and marshals the unmanaged pointers (IntPtr) to the native array
/// equivalent.
///
/// Array of unmanaged pointers
/// SafeHGlobalHandle object to an native (unmanaged) array of pointers
public static SafeHGlobalHandle AllocHGlobal(IntPtr[] values)
{
SafeHGlobalHandle result = AllocHGlobal(IntPtr.Size * values.Length);
Marshal.Copy(values, 0, result.pointer, values.Length);
return result;
}
public static SafeHGlobalHandle AllocHGlobalStruct(T obj) where T : struct
{
Debug.Assert(typeof(T).StructLayoutAttribute.Value == LayoutKind.Sequential);
SafeHGlobalHandle result = AllocHGlobal(Marshal.SizeOf(typeof(T)));
Marshal.StructureToPtr(obj, result.pointer, false);
return result;
}
///
/// Allocates from unmanaged memory to represent an array of structures
/// and marshals the structure elements to the native array of
/// structures. ONLY structures with attribute StructLayout of
/// LayoutKind.Sequential are supported.
///
/// Native structure type
/// Collection of structure objects
/// Number of elements in the collection
/// SafeHGlobalHandle object to an native (unmanaged) array of structures
public static SafeHGlobalHandle AllocHGlobal(ICollection values) where T : struct
{
Debug.Assert(typeof(T).StructLayoutAttribute.Value == LayoutKind.Sequential);
return AllocHGlobal(0, values, values.Count);
}
///
/// Allocates from unmanaged memory to represent a structure with a
/// variable length array at the end and marshal these structure
/// elements. It is the callers responsibility to marshal what preceeds
/// the trailinh array into the unmanaged memory. ONLY structures with
/// attribute StructLayout of LayoutKind.Sequential are supported.
///
/// Type of the trailing array of structures
/// Number of bytes preceeding the trailing array of structures
/// Collection of structure objects
///
/// SafeHGlobalHandle object to an native (unmanaged) structure
/// with a trail array of structures
public static SafeHGlobalHandle AllocHGlobal(int prefixBytes, IEnumerable values, int count) where T
: struct
{
Debug.Assert(typeof(T).StructLayoutAttribute.Value == LayoutKind.Sequential);
SafeHGlobalHandle result = AllocHGlobal(prefixBytes + Marshal.SizeOf(typeof(T)) * count);
IntPtr ptr = new IntPtr(result.pointer.ToInt32() + prefixBytes);
foreach (var value in values)
{
Marshal.StructureToPtr(value, ptr, false);
ptr.Increment();
}
return result;
}
///
/// Allocates from unmanaged memory to represent a unicode string (WSTR)
/// and marshal this to a native PWSTR.
///
/// String
/// SafeHGlobalHandle object to an native (unmanaged) unicode string
public static SafeHGlobalHandle AllocHGlobal(string s)
{
return new SafeHGlobalHandle(Marshal.StringToHGlobalUni(s));
}
///
/// Operator to obtain the unmanaged pointer wrapped by the object. Note
/// that the returned pointer is only valid for the lifetime of this
/// object.
///
/// SafeHGlobalHandle object
/// Unmanaged pointer wrapped by the object
public IntPtr ToIntPtr()
{
return pointer;
}
#endregion
#region IDisposable implmentation
public void Dispose()
{
if (pointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(pointer);
pointer = IntPtr.Zero;
}
GC.SuppressFinalize(this);
}
#endregion
#region Private implementation
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope",
Justification = "Caller will dispose result")]
static SafeHGlobalHandle AllocHGlobal(int cb)
{
if (cb < 0)
{
throw new ArgumentOutOfRangeException("cb", "The value of this argument must be non-negative");
}
SafeHGlobalHandle result = new SafeHGlobalHandle();
//
// CER
//
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
result.pointer = Marshal.AllocHGlobal(cb);
}
return result;
}
#endregion
#region Private members
///
/// Maintainsreference to other SafeHGlobalHandle objects, the pointer
/// to which are refered to by this object. This is to ensure that such
/// objects being referred to wouldn't be unreferenced until this object
/// is active.
///
List references;
//
// Using SafeHandle here doesn't buy much since the pointer is
// eventually stashed into a native structure. Using a SafeHandle would
// involve calling DangerousGetHandle in place of ToIntPtr which makes
// code analysis report CA2001: Avoid calling problematic methods.
//
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
///
/// Unmanaged pointer wrapped by this object
///
IntPtr pointer;
#endregion
}
//
// Adopted from: http://msdn.microsoft.com/en-us/magazine/cc163823.aspx
//
///
/// Safe wrapper for HANDLE to a token.
///
internal class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
{
#region Constructors
///
/// This safehandle instance "owns" the handle, hence base(true)
/// is being called. When safehandle is no longer in use it will
/// call this class's ReleaseHandle method which will release
/// the resources
///
private SafeTokenHandle() : base(true) { }
// 0 is an Invalid Handle
internal SafeTokenHandle(HANDLE handle)
: base(true)
{
SetHandle(handle);
}
#endregion
internal static SafeTokenHandle InvalidHandle
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Retain to illustrate semantics")]
get { return new SafeTokenHandle(HANDLE.Zero); }
}
#region Private implementation
///
/// Release the HANDLE held by this instance
///
/// true if the release was successful. false otherwise.
override protected bool ReleaseHandle()
{
return NativeMethods.CloseHandle(handle);
}
#endregion
#region Nested class for P/Invokes
static class NativeMethods
{
[DllImport(Win32.KERNEL32_DLL, SetLastError = true),
SuppressUnmanagedCodeSecurity,
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(HANDLE handle);
}
#endregion
}
///
/// Safe wrapper for AUTHZ_RESOURCE_MANAGER_HANDLE.
///
internal class SafeAuthzRMHandle : SafeHandleZeroOrMinusOneIsInvalid
{
#region Constructors
///
/// This safehandle instance "owns" the handle, hence base(true)
/// is being called. When safehandle is no longer in use it will
/// call this class's ReleaseHandle method which will release
/// the resources
///
SafeAuthzRMHandle() : base(true) { }
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
Justification = "Retain to illustrate semantics and for reuse")]
SafeAuthzRMHandle(HANDLE handle)
: base(true)
{
SetHandle(handle);
}
#endregion
public static SafeAuthzRMHandle InvalidHandle
{
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode",
Justification = "Retain to illustrate semantics")]
get { return new SafeAuthzRMHandle(HANDLE.Zero); }
}
#region Private implementation
///
/// Release the resource manager handle held by this instance
///
/// true if the release was successful. false otherwise.
override protected bool ReleaseHandle()
{
return NativeMethods.AuthzFreeResourceManager(handle);
}
#endregion
#region Nested class for P/Invokes
static class NativeMethods
{
[DllImport(Win32.AUTHZ_DLL, SetLastError = true),
SuppressUnmanagedCodeSecurity,
ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool AuthzFreeResourceManager(HANDLE handle);
}
#endregion
}
}