/// <summary>
        /// Get a list of handles
        /// </summary>
        /// <param name="pid">A process ID to filter on. If -1 will get all handles</param>
        /// <param name="allow_query">True to allow the handles returned to query for certain properties</param>
        /// <returns>The list of handles</returns>
        public static IEnumerable <NtHandle> GetHandles(int pid, bool allow_query)
        {
            SafeHGlobalBuffer handleInfo = new SafeHGlobalBuffer(0x10000);

            try
            {
                NtStatus status        = 0;
                int      return_length = 0;
                while ((status = NtSystemCalls.NtQuerySystemInformation(SystemInformationClass.SystemHandleInformation,
                                                                        handleInfo.DangerousGetHandle(),
                                                                        handleInfo.Length,
                                                                        out return_length)) == NtStatus.STATUS_INFO_LENGTH_MISMATCH)
                {
                    int length = handleInfo.Length * 2;
                    handleInfo.Close();
                    handleInfo = new SafeHGlobalBuffer(length);
                }
                status.ToNtException();

                IntPtr          handleInfoBuf = handleInfo.DangerousGetHandle();
                int             handle_count  = Marshal.ReadInt32(handleInfoBuf);
                List <NtHandle> ret           = new List <NtHandle>();
                handleInfoBuf += IntPtr.Size;
                for (int i = 0; i < handle_count; ++i)
                {
                    SystemHandleTableInfoEntry entry = (SystemHandleTableInfoEntry)Marshal.PtrToStructure(handleInfoBuf, typeof(SystemHandleTableInfoEntry));

                    if (pid == -1 || entry.UniqueProcessId == pid)
                    {
                        ret.Add(new NtHandle(entry, allow_query));
                    }
                    handleInfoBuf += Marshal.SizeOf(typeof(SystemHandleTableInfoEntry));
                }
                return(ret);
            }
            finally
            {
                handleInfo.Close();
            }
        }
        private SafeHGlobalBuffer CreateRelativeSecurityDescriptor()
        {
            using (var sd_buffer = CreateAbsoluteSecurityDescriptor())
            {
                int      total_length = 0;
                NtStatus status       = NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer, new SafeHGlobalBuffer(IntPtr.Zero, 0, false), ref total_length);
                if (status != NtStatus.STATUS_BUFFER_TOO_SMALL)
                {
                    status.ToNtException();
                }

                var relative_sd = new SafeHGlobalBuffer(total_length);
                try
                {
                    NtRtl.RtlAbsoluteToSelfRelativeSD(sd_buffer, relative_sd, ref total_length).ToNtException();
                    return(Interlocked.Exchange(ref relative_sd, null));
                }
                finally
                {
                    relative_sd?.Close();
                }
            }
        }