/// <summary> /// Tries the get object name from the wrapped handle. /// </summary> /// <param name="fileName">Name of the file.</param> /// <param name="timeout">The timeout.</param> /// <returns></returns> /// <remarks> /// Since the call to NtQueryObject might hang infinitely, this method uses a separate thread with a timeout to call the API /// If the timeout expires the status 'NT_STATUS.STATUS_TIMEOUT' will be returned. /// </remarks> public NT_STATUS TryGetObjectNameFromHandle(out string fileName, TimeSpan timeout) { string name = null; NT_STATUS result = NT_STATUS.STATUS_SUCCESS; AutoResetEvent signal = new AutoResetEvent(false); Thread workerThread = null; ThreadPool.QueueUserWorkItem((o) => { workerThread = Thread.CurrentThread; result = TryGetObjectNameFromHandle(out name); signal.Set(); }); bool waitres = signal.WaitOne(timeout); fileName = name; if (workerThread != null && workerThread.IsAlive && waitres == false) { workerThread.Abort(); return(NT_STATUS.STATUS_TIMEOUT); } return(result); }
/// <summary> /// Enumerates all kernel object type-infos available in the operating system. /// </summary> /// <returns></returns> /// <exception cref="NtStatusException">NtQueryObject failed</exception> public static IEnumerable <ObjectTypeInfo> EnumerateAllObjectTypes() { int nLength = 0x1000; IntPtr ipBufferObjectType = IntPtr.Zero; ipBufferObjectType = Marshal.AllocHGlobal(nLength); while (true) { NT_STATUS res1 = NativeMethods.NtQueryObject(IntPtr.Zero, OBJECT_INFORMATION_CLASS.ObjectAllTypesInformation, ipBufferObjectType, nLength, out nLength); if (res1 == NT_STATUS.STATUS_SUCCESS) { break; } if (res1 != NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { throw new NtStatusException("NtQueryObject failed", res1); } Marshal.FreeHGlobal(ipBufferObjectType); ipBufferObjectType = Marshal.AllocHGlobal(nLength); } int typeInfoCount = Marshal.ReadInt32(ipBufferObjectType); // actually uint! C++: ULONG NumberOfTypes; IntPtr ipTypeInfo = IntPtr.Add(ipBufferObjectType, IntPtr.Size); // the int that we just read + padding (only in 64bit!) for (int nIndex = 0; nIndex < typeInfoCount; nIndex++) { OBJECT_TYPE_INFORMATION otiTemp = Marshal.PtrToStructure <OBJECT_TYPE_INFORMATION>(ipTypeInfo); string strType = Helpers.MarshalUnicodeString(otiTemp.TypeName); yield return(new ObjectTypeInfo(otiTemp, strType)); int currentSize = Marshal.SizeOf <OBJECT_TYPE_INFORMATION>() + otiTemp.TypeName.MaximumLength; int offsetToNext = Helpers.RoundUp(currentSize, IntPtr.Size); // padding depends on 32/64bit ipTypeInfo = IntPtr.Add(ipTypeInfo, offsetToNext); } }
/// <summary> /// Gets the type-info for the handle. /// </summary> /// <returns></returns> /// <exception cref="NtStatusException"> /// NtQueryObject failed /// </exception> public ObjectTypeInfo GetHandleType() { int length; NT_STATUS res1 = NativeMethods.NtQueryObject(_duplicatedObjectHandle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, IntPtr.Zero, 0, out length); if (res1 != NT_STATUS.STATUS_SUCCESS && res1 != NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { throw new NtStatusException("NtQueryObject call1 failed", res1); } IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ptr = Marshal.AllocHGlobal(length); } NT_STATUS res2 = NativeMethods.NtQueryObject(_duplicatedObjectHandle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, ptr, length, out length); if (res2 != NT_STATUS.STATUS_SUCCESS) { throw new NtStatusException("NtQueryObject call2 failed", res2); } OBJECT_TYPE_INFORMATION objectType = Marshal.PtrToStructure <OBJECT_TYPE_INFORMATION>(ptr); string typeName = Helpers.MarshalUnicodeString(objectType.TypeName); return(new ObjectTypeInfo(objectType, typeName)); } finally { Marshal.FreeHGlobal(ptr); } }
public RowViewModel(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX info) { _info = info; using (DuplicatedObjectHandle dhandle = new DuplicatedObjectHandle(_info.HandleValue, _info.UniqueProcessId)) { if (dhandle.ErrorMessage != null) { _name = "<" + dhandle.ErrorMessage + ">"; return; } string name; NT_STATUS status = dhandle.TryGetObjectNameFromHandle(out name, timeout); if (status != NT_STATUS.STATUS_SUCCESS) { _name = "<" + status.ToString() + ">"; return; } _name = name; } if (_name != null && !_name.StartsWith("<")) { if (this.ObjectTypeString == "File") { _prettyName = DevicePathConverter.ConvertDevicePathToDosPath(_name); } if (this.ObjectTypeString == "Key") { _prettyName = _name.Replace(@"\REGISTRY\MACHINE", @"HKLM").Replace(@"\REGISTRY\USER\" + cusid, @"HKCU").Replace(@"\REGISTRY\USER", @"HKU"); // todo: do not use replace, use code similar to DevicePathConverter.IsMatch } } }
public override NT_STATUS SetAttributes(UserContext UserContext, FileContext FileObject, DirectoryContext data) { NT_STATUS error = NT_STATUS.OK; //FIXME: attributes? what attributes? The attributes of the file, e.g. archive, hidden .... return(error); }
public override NT_STATUS Write(UserContext UserContext, FileContext FileObject, long Offset, ref int Count, ref byte[] Buffer, int Start) { // All locking issies are handled in the calling class, expect if other application access the files from outside // WinFUSE // It's possible to write all data to a cache and write it through to the final media after a flush or close. But this // write through should not last longer than 20 secounds NT_STATUS error = NT_STATUS.OK; MyFileContext HE = (MyFileContext)FileObject; if (HE.IsDirectory || HE.FS == null) { Debug.WriteLine("Warning->Cannot write to Directory."); Count = 0; return(NT_STATUS.INVALID_HANDLE); // ERROR_INVALID_HANDLE } if (!HE.FS.CanWrite && !HE.FS.CanSeek) { Debug.WriteLine("Warning->The file can not be written."); Count = 0; return(NT_STATUS.INVALID_PARAMETER); // ERROR_INVALID_PARAMETER; } if (Count > 0x0FFFFFFF) { Debug.WriteLine("Warning->Number of bytes to write is too large."); Count = 0; return(NT_STATUS.INVALID_PARAMETER); //ERROR_INVALID_PARAMETER } long NewOffset; try { NewOffset = HE.FS.Seek(Offset, System.IO.SeekOrigin.Begin); if (NewOffset != Offset) { Debug.WriteLine("Warning->The indicated position can not be written."); Count = 0; return(NT_STATUS.INVALID_PARAMETER); //132 ERROR_SEEK_ON_DEVICE } BinaryWriter Writer = new BinaryWriter(HE.FS); Writer.Write(Buffer, Start, Count); } catch (Exception ex) { Trace.WriteLine("Warning->Exception in Write: " + ex.Message); Count = 0; //error = 29; // ERROR_WRITE_FAULT error = (NT_STATUS)Marshal.GetHRForException(ex); } return(error); }
private static bool GetFileNameFromHandle(IntPtr handle, out string fileName) { IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { int length = 0x200; // 512 bytes RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees the assignment of the allocated // memory address to ptr, if an ansynchronous exception // occurs. ptr = Marshal.AllocHGlobal(length); } NT_STATUS ret = NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); if (ret == NT_STATUS.STATUS_BUFFER_OVERFLOW) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees that the previous allocation is freed, // and that the newly allocated memory address is // assigned to ptr if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); ptr = Marshal.AllocHGlobal(length); } ret = NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); } if (ret == NT_STATUS.STATUS_SUCCESS) { fileName = Marshal.PtrToStringUni((IntPtr)((int)ptr + 8), (length - 9) / 2); return(fileName.Length != 0); } } finally { // CER guarantees that the allocated memory is freed, // if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); } fileName = string.Empty; return(false); }
public override NT_STATUS Read(UserContext UserContext, FileContext FileObject, long Offset, ref int Count, ref byte[] Buffer, int Start) { // All locking issues are handled in the calling class, the only read collision that can occure are when other // application access the same file NT_STATUS error = NT_STATUS.OK; MyFileContext HE = (MyFileContext)FileObject; if (HE.IsDirectory || HE.FS == null) { Debug.WriteLine("Warning->Can not read from a Directory."); Count = 0; return(NT_STATUS.INVALID_HANDLE); // ERROR_INVALID_HANDLE } if (!HE.FS.CanRead && !HE.FS.CanSeek) { Debug.WriteLine("Warning->Can not Read or Seek the file."); Count = 0; return(NT_STATUS.INVALID_PARAMETER); // ERROR_INVALID_PARAMETER; } if (Count > 0x0FFFFFFF) { Debug.WriteLine("Warning->Number of bytes to read is too large."); Count = 0; return(NT_STATUS.INVALID_PARAMETER); //ERROR_INVALID_PARAMETER } long NewOffset; try { NewOffset = HE.FS.Seek(Offset, System.IO.SeekOrigin.Begin); if (NewOffset != Offset) { Debug.WriteLine("Warning->The indicated position can not be read"); Count = 0; return(NT_STATUS.INVALID_PARAMETER); // 132 = ERROR_SEEK_ON_DEVICE } BinaryReader Reader = new BinaryReader(HE.FS); Count = Reader.Read(Buffer, Start, Count); } catch (Exception ex) { Trace.WriteLine("Warning->Exception in Read: " + ex.Message); Count = 0; //error = 30; // ERROR_READ_FAULT error = (NT_STATUS)Marshal.GetHRForException(ex); } return(error); }
/// <summary> /// Gets the object name from the wrapped handle. /// </summary> /// <returns> /// For object-type 'File': the device path (serial-ports also have the type 'file') - starts always with '\Device\', if it doesn't the handle is invalid. /// For object-type 'Key': the registry Path - starts always with '\REGISTRY\', if it doesn't the handle is invalid. /// </returns> /// <exception cref="System.Exception"></exception> public string GetObjectNameFromHandle() { string name; NT_STATUS status = TryGetObjectNameFromHandle(out name); if (status != NT_STATUS.STATUS_SUCCESS) { throw new NtStatusException("TryGetObjectNameFromHandle failed", status); } return(name); }
public static SystemHandleEntry[] GetSystemHandles() { // Attempt to retrieve the handle information int length = 0x10000; IntPtr ptr = IntPtr.Zero; try { while (true) { ptr = Marshal.AllocHGlobal(length); int wantedLength; NT_STATUS result = NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out wantedLength); if (result == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { length = Math.Max(length, wantedLength); Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; } else if (result == NT_STATUS.STATUS_SUCCESS) { break; } else { throw new Exception("Failed to retrieve system handle information.", new System.ComponentModel.Win32Exception()); } } int handleCount = IntPtr.Size == 4 ? Marshal.ReadInt32(ptr) : (int)Marshal.ReadInt64(ptr); int offset = IntPtr.Size; int size = Marshal.SizeOf(typeof(SystemHandleEntry)); SystemHandleEntry[] systemHandleEntries = new SystemHandleEntry[handleCount]; for (int i = 0; i < handleCount; i++) { SystemHandleEntry struc = (SystemHandleEntry)Marshal.PtrToStructure((IntPtr)((long)ptr + offset), typeof(SystemHandleEntry)); systemHandleEntries[i] = struc; offset += size; } return(systemHandleEntries); } finally { if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } } }
public override NT_STATUS Rename(UserContext UserContext, string OldName, string NewName) { NT_STATUS error = NT_STATUS.OK; if (phone.Exists(root + OldName) && phone.IsDirectory(root + OldName)) { // We are in Directory case if (phone.Exists(root + NewName)) { return(NT_STATUS.OBJECT_NAME_COLLISION); } try { //FIXME: We don't have a way to move directories //DirectoryBroker.Move(phone,root + OldName, root + NewName); phone.Rename(root + OldName, root + NewName); return(NT_STATUS.OBJECT_NAME_COLLISION); } catch (Exception e) { Trace.WriteLine("Warning->Exception when renaming directory: " + e.Message); error = (NT_STATUS)Marshal.GetHRForException(e); //error = 3; // ListingError } } else { // We are in File case if (!phone.Exists(root + OldName)) { return(NT_STATUS.OBJECT_NAME_NOT_FOUND); // Orginalname nicht da } if (phone.Exists(root + NewName)) { return(NT_STATUS.OBJECT_NAME_COLLISION); } try { phone.Rename(root + OldName, root + NewName); } catch (Exception e) { Trace.WriteLine("Warning->Exception when renaming file: " + e.Message); error = (NT_STATUS)Marshal.GetHRForException(e); } } return(error); }
//Implements the search for listings by means of identification FindFirst and FindNext public override NT_STATUS ReadDirectory(UserContext UserContext, FileContext FileObject) { NT_STATUS error = NT_STATUS.OK; MyFileContext HE = (MyFileContext)FileObject; if (!HE.IsDirectory) { Debug.WriteLine("Warning->Handle is not a directory, can not get a listing"); return(NT_STATUS.INVALID_HANDLE); } if (!phone.Exists(root + HE.Name) || !phone.IsDirectory(root + HE.Name)) { return(NT_STATUS.OBJECT_PATH_NOT_FOUND); // Directroy not found, should never happen } HE.Items.Add(new DirectoryContext(".", FileAttributes.Directory)); HE.Items.Add(new DirectoryContext("..", FileAttributes.Directory)); DirectoryContext Item = null; foreach (string DirName in phone.GetDirectories(root + HE.Name)) { error = GetAttributes(UserContext, root + HE.Name + DirName, out Item); if (error != 0) { Trace.WriteLine("Warning->Error: '" + error + "' during listing directories: " + HE.Name + DirName); } HE.Items.Add(Item); } foreach (string FileName in phone.GetFiles(root + HE.Name)) { error = GetAttributes(UserContext, root + HE.Name + FileName, out Item); if (error != 0) { Trace.WriteLine("Warning->Error: '" + error + "' during listing files: " + FileName); } else { HE.Items.Add(Item); } } return(NT_STATUS.OK); }
public override NT_STATUS Create(UserContext UserContext, string Name, SearchFlag SearchFlags, FileMode Mode, FileAccess Access, FileShare Share, FileAttributes Attributes, out FileContext fileContext) { lock (this) { FSItem item = _topItem.GetItem(Name); if (item != null) { MTPFileContext mtpFileContext; NT_STATUS status = item.Create(UserContext, Name, SearchFlags, Mode, Access, Share, Attributes, out mtpFileContext); fileContext = mtpFileContext; return(status); } fileContext = null; return(NT_STATUS.NO_SUCH_FILE); } }
/// <summary> /// Tries the get object name from the wrapped handle. /// </summary> /// <param name="name">The name.</param> /// <returns></returns> /// <remarks> /// This method might hang infinitely in NtQueryObject, so it is safer to use the overload with the timeout parameter. /// The hangs have been observed for handles with GrantedAccess == 0x00120189 and 0x0012019f all of them were for type 'file' /// and process explorer showed that the handle names all were '\Device\NamedPipe' /// This was tested on win10 64bit 1511 and 1607. /// The problem seems only to appear when 'Prefer 32bit' is disabled /// </remarks> public NT_STATUS TryGetObjectNameFromHandle(out string name) { name = null; IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { int length = 0x200; // 512 bytes RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees the assignment of the allocated memory address to ptr, if an asynchronous exception occurs. ptr = Marshal.AllocHGlobal(length); } NT_STATUS ret = NativeMethods.NtQueryObject(_duplicatedObjectHandle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); if (ret == NT_STATUS.STATUS_BUFFER_OVERFLOW) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees that the previous allocation is freed, and that the newly allocated memory address is // assigned to ptr if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); ptr = Marshal.AllocHGlobal(length); } ret = NativeMethods.NtQueryObject(_duplicatedObjectHandle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); } if (ret == NT_STATUS.STATUS_SUCCESS) { OBJECT_NAME_INFORMATION nameInfo = Marshal.PtrToStructure <OBJECT_NAME_INFORMATION>(ptr); name = Helpers.MarshalUnicodeString(nameInfo.Name); } return(ret); } finally { // CER guarantees that the allocated memory is freed, if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); } }
public override NT_STATUS Delete(UserContext UserContext, string FileName) { NT_STATUS error = NT_STATUS.OK; string OriginalName = root + FileName; Debug.WriteLine("Info->File '" + FileName + "' with full path '" + OriginalName + "' is being deleted."); try { if (!phone.Exists(OriginalName) || phone.IsDirectory(OriginalName)) { return(NT_STATUS.OBJECT_NAME_NOT_FOUND); } phone.DeleteFile(OriginalName); } catch (Exception e) { Trace.WriteLine("Warning->Exception in Delete:" + e.Message); error = (NT_STATUS)Marshal.GetHRForException(e); // ERROR_READ_FAULT } return(error); }
static bool NT_SUCCESS(NT_STATUS status) { return(((uint)status & 0x80000000) == 0); }
/// <summary> /// Constructs a new NtStatusException. /// </summary> /// <param name="message">The exception message.</param> /// <param name="status">The value for the Status property.</param> /// <param name="innerException">The inner exception.</param> public NtStatusException(string message, NT_STATUS status, Exception innerException) : base(message, innerException) { this.status = status; }
/// <summary> /// Serialization constructor. /// </summary> protected NtStatusException(SerializationInfo info, StreamingContext context) : base(info, context) { this.status = (NT_STATUS)info.GetValue("Status", typeof(NT_STATUS)); }
public static Dictionary <int, string> GetHandleNames(int targetPid) { Dictionary <int, string> fileHandles = new Dictionary <int, string>(); int length = 0x10000; IntPtr ptr = IntPtr.Zero; try { while (true) { ptr = Marshal.AllocHGlobal(length); int wantedLength; // query for system handles we can read var result = Ntdll.NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out wantedLength); if (result == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { length = Math.Max(length, wantedLength); Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; } else if (result == NT_STATUS.STATUS_SUCCESS) { break; } else { throw new Exception("Failed to retrieve system handle information."); } } var offset = ptr.ToInt64(); offset += IntPtr.Size; int size = Marshal.SizeOf(typeof(SYSTEM_HANDLE_INFORMATION)); int handleCount = IntPtr.Size == 4 ? Marshal.ReadInt32(ptr) : (int)Marshal.ReadInt64(ptr); // open the target process for handle duplication IntPtr processHandle = Kernel32.OpenProcess(ProcessAccessFlags.DuplicateHandle, true, (uint)targetPid); IntPtr currentProcessHandle = Kernel32.GetCurrentProcess(); for (int i = 0; i < handleCount; i++) { if (Marshal.ReadInt32((IntPtr)offset) == targetPid) { SYSTEM_HANDLE_INFORMATION info = (SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(new IntPtr(offset), typeof(SYSTEM_HANDLE_INFORMATION)); // actually duplicate the handle so we can get its name int dummy = 0; IntPtr duplicatedHandle = new IntPtr(); bool success = Kernel32.DuplicateHandle(processHandle, new IntPtr(info.HandleValue), currentProcessHandle, out duplicatedHandle, 0, false, DuplicateOptions.DUPLICATE_SAME_ACCESS); // check if this handle is on disk (a file) so things don't hang if (Kernel32.GetFileType(duplicatedHandle) == FileType.Disk) { if (success) { int length2 = 0x200; IntPtr buffer = Marshal.AllocHGlobal(length2); // use NtQueryObject so we can get this object's name NT_STATUS status = Ntdll.NtQueryObject(duplicatedHandle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, buffer, length2, out dummy); if (status == NT_STATUS.STATUS_SUCCESS) { OBJECT_NAME_INFORMATION temp = (OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(buffer, typeof(OBJECT_NAME_INFORMATION)); if (!String.IsNullOrEmpty(temp.Name.ToString()) && !String.IsNullOrEmpty(temp.Name.ToString().Trim())) { // only add the file/object to the results if it ends with our target file search pattern fileHandles.Add(info.HandleValue, temp.Name.ToString().Trim()); } } else { // Console.WriteLine("[X] NtQueryObject status: {0}", status); } Marshal.FreeHGlobal(buffer); } } Kernel32.CloseHandle(duplicatedHandle); } offset += size; } Kernel32.CloseHandle(processHandle); } finally { if (ptr != IntPtr.Zero) { Marshal.FreeHGlobal(ptr); } } // convert all the paths to readable formats return(ConvertDevicePathsToDosPaths(fileHandles)); }
private static bool GetFileNameOfLocalHandle(IntPtr handle, out string fileName) { if (handle.ToInt32() == 0) { throw new Exception("Handle is null"); } IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { int length = 0x200; // 512 bytes RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees the assignment of the allocated // memory address to ptr, if an ansynchronous exception // occurs. ptr = Marshal.AllocHGlobal(length); } NT_STATUS ret = NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); if (ret == NT_STATUS.STATUS_BUFFER_OVERFLOW) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees that the previous allocation is freed, // and that the newly allocated memory address is // assigned to ptr if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); ptr = Marshal.AllocHGlobal(length); } ret = NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); } if (ret == NT_STATUS.STATUS_SUCCESS) { // fileName = Marshal.PtrToStringUni((IntPtr)((int)ptr + 16), (length - 9) / 2); OBJECT_NAME_INFORMATION objObjectName = Marshal.PtrToStructure <OBJECT_NAME_INFORMATION>(ptr); if (objObjectName.Name.Buffer != IntPtr.Zero) { string strObjectName = Marshal.PtrToStringUni(objObjectName.Name.Buffer); fileName = GetRegularFileNameFromDevice(strObjectName); //return strObjectName; } else { fileName = string.Empty; } return(fileName.Length != 0); } } finally { // CER guarantees that the allocated memory is freed, // if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); } fileName = string.Empty; return(false); }
/// <summary> /// Constructs a new NtStatusException. /// </summary> /// <param name="message">The exception message</param> /// <param name="status">The value for the Status property.</param> public NtStatusException(string message, NT_STATUS status) : base(message) { this.status = status; }