Please excuse the massive code-dump, but here's a little class to do it -- work on Win 7 and Windows Server 2003 (the only two I've tested on so far). Uses threads to protect against some nasty Win32 bugs. Mostly stuff found on the 'net.
Please excuse the massive code-dump, but here's a little class to do it -- work on Win 7 and Windows Server 2003 (the only two I've tested on so far). Uses threads to protect against some nasty Win32 bugs. Mostly stuff found on the 'net.
Using System; using System.Collections. Generic; using System.Runtime. InteropServices; using System.
Diagnostics; using System. Text; using System. Threading; namespace FileLockInfo { public class Win32Processes { /// /// Return a list of processes that hold on the given file.
/// public static List GetProcessesLockingFile (string filePath) { var procs = new List(); foreach (var process in Process.GetProcesses()) { var files = GetFilesLockedBy(process); if (files. Contains(filePath)) procs. Add(process); } return procs; } /// /// Return a list of file locks held by the process.
/// public static List GetFilesLockedBy (Process process) { var outp = new List(); ThreadStart ts = delegate { try { outp = UnsafeGetFilesLockedBy(process); } catch { } }; try { var t = new Thread(ts); t.Start(); if (!t. Join(250)) { try { t.Abort(); } catch { } } } catch { } return outp; } #region Inner Workings private static List UnsafeGetFilesLockedBy (Process process) { try { var handles = GetHandles(process); var files = new List(); foreach (var handle in handles) { var file = GetFilePath(handle, process); if (file! = null) files.
Add(file); } return files; } catch { return new List(); } } const int CNST_SYSTEM_HANDLE_INFORMATION = 16; const uint STATUS_INFO_LENGTH_MISMATCH = 0xc0000004; private static string GetFilePath (Win32API. SYSTEM_HANDLE_INFORMATION sYSTEM_HANDLE_INFORMATION, Process process) { IntPtr m_ipProcessHwnd = Win32API. OpenProcess(Win32API.
ProcessAccessFlags. All, false, process. Id); IntPtr ipHandle = IntPtr.
Zero; var objBasic = new Win32API. OBJECT_BASIC_INFORMATION(); IntPtr ipBasic = IntPtr. Zero; var objObjectType = new Win32API.
OBJECT_TYPE_INFORMATION(); IntPtr ipObjectType = IntPtr. Zero; var objObjectName = new Win32API. OBJECT_NAME_INFORMATION(); IntPtr ipObjectName = IntPtr.
Zero; string strObjectTypeName = ""; string strObjectName = ""; int nLength = 0; int nReturn = 0; IntPtr ipTemp = IntPtr. Zero; if (!Win32API. DuplicateHandle(m_ipProcessHwnd, sYSTEM_HANDLE_INFORMATION.
Handle, Win32API. GetCurrentProcess(), out ipHandle, 0, false, Win32API. DUPLICATE_SAME_ACCESS)) return null; ipBasic = Marshal.
AllocHGlobal(Marshal. SizeOf(objBasic)); Win32API. NtQueryObject(ipHandle, (int)Win32API.
ObjectInformationClass. ObjectBasicInformation, ipBasic, Marshal. SizeOf(objBasic), ref nLength); objBasic = (Win32API.
OBJECT_BASIC_INFORMATION)Marshal. PtrToStructure(ipBasic, objBasic.GetType()); Marshal. FreeHGlobal(ipBasic); ipObjectType = Marshal.
AllocHGlobal(objBasic. TypeInformationLength); nLength = objBasic. TypeInformationLength; while ((uint)(nReturn = Win32API.
NtQueryObject(ipHandle, (int)Win32API. ObjectInformationClass. ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32API.
STATUS_INFO_LENGTH_MISMATCH) { Marshal. FreeHGlobal(ipObjectType); ipObjectType = Marshal. AllocHGlobal(nLength); } objObjectType = (Win32API.
OBJECT_TYPE_INFORMATION)Marshal. PtrToStructure(ipObjectType, objObjectType.GetType()); if (Is64Bits()) { ipTemp = new IntPtr(Convert. ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32); } else { ipTemp = objObjectType.Name.
Buffer; } strObjectTypeName = Marshal. PtrToStringUni(ipTemp, objObjectType.Name. Length >> 1); Marshal.
FreeHGlobal(ipObjectType); if (strObjectTypeName! = "File") return null; nLength = objBasic. NameInformationLength; ipObjectName = Marshal.
AllocHGlobal(nLength); while ((uint)(nReturn = Win32API. NtQueryObject(ipHandle, (int)Win32API. ObjectInformationClass.
ObjectNameInformation, ipObjectName, nLength, ref nLength)) == Win32API. STATUS_INFO_LENGTH_MISMATCH) { Marshal. FreeHGlobal(ipObjectName); ipObjectName = Marshal.
AllocHGlobal(nLength); } objObjectName = (Win32API. OBJECT_NAME_INFORMATION)Marshal. PtrToStructure(ipObjectName, objObjectName.GetType()); if (Is64Bits()) { ipTemp = new IntPtr(Convert.
ToInt64(objObjectName.Name.Buffer.ToString(), 10) >> 32); } else { ipTemp = objObjectName.Name. Buffer; } if (ipTemp! = IntPtr.
Zero) { byte baTemp = new bytenLength; try { Marshal. Copy(ipTemp, baTemp, 0, nLength); strObjectName = Marshal. PtrToStringUni(Is64Bits()?
New IntPtr(ipTemp. ToInt64()) : new IntPtr(ipTemp. ToInt32())); } catch (AccessViolationException) { return null; } finally { Marshal.
FreeHGlobal(ipObjectName); Win32API. CloseHandle(ipHandle); } } string path = GetRegularFileNameFromDevice(strObjectName); try { return path; } catch { return null; } } private static string GetRegularFileNameFromDevice (string strRawName) { string strFileName = strRawName; foreach (string strDrivePath in Environment. GetLogicalDrives()) { StringBuilder sbTargetPath = new StringBuilder(Win32API.
MAX_PATH); if (Win32API. QueryDosDevice(strDrivePath. Substring(0, 2), sbTargetPath, Win32API.
MAX_PATH) == 0) { return strRawName; } string strTargetPath = sbTargetPath.ToString(); if (strFileName. StartsWith(strTargetPath)) { strFileName = strFileName. Replace(strTargetPath, strDrivePath.
Substring(0, 2)); break; } } return strFileName; } private static List GetHandles (Process process) { uint nStatus; int nHandleInfoSize = 0x10000; IntPtr ipHandlePointer = Marshal. AllocHGlobal(nHandleInfoSize); int nLength = 0; IntPtr ipHandle = IntPtr. Zero; while ((nStatus = Win32API.
NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength)) == STATUS_INFO_LENGTH_MISMATCH) { nHandleInfoSize = nLength; Marshal. FreeHGlobal(ipHandlePointer); ipHandlePointer = Marshal. AllocHGlobal(nLength); } byte baTemp = new bytenLength; Marshal.
Copy(ipHandlePointer, baTemp, 0, nLength); long lHandleCount = 0; if (Is64Bits()) { lHandleCount = Marshal. ReadInt64(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer. ToInt64() + 8); } else { lHandleCount = Marshal.
ReadInt32(ipHandlePointer); ipHandle = new IntPtr(ipHandlePointer. ToInt32() + 4); } Win32API. SYSTEM_HANDLE_INFORMATION shHandle; List lstHandles = new List(); for (long lIndex = 0; lIndex SYSTEM_HANDLE_INFORMATION(); if (Is64Bits()) { shHandle = (Win32API.
SYSTEM_HANDLE_INFORMATION)Marshal. PtrToStructure(ipHandle, shHandle.GetType()); ipHandle = new IntPtr(ipHandle. ToInt64() + Marshal.
SizeOf(shHandle) + 8); } else { ipHandle = new IntPtr(ipHandle. ToInt64() + Marshal. SizeOf(shHandle)); shHandle = (Win32API.
SYSTEM_HANDLE_INFORMATION)Marshal. PtrToStructure(ipHandle, shHandle.GetType()); } if (shHandle. ProcessID!
= process. Id) continue; lstHandles. Add(shHandle); } return lstHandles; } private static bool Is64Bits () { return Marshal.
SizeOf(typeof(IntPtr)) == 8? True : false; } internal class Win32API { DllImport("ntdll. Dll") public static extern int NtQueryObject (IntPtr ObjectHandle, int ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength, ref int returnLength); DllImport("kernel32.
Dll", SetLastError = true) public static extern uint QueryDosDevice (string lpDeviceName, StringBuilder lpTargetPath, int ucchMax); DllImport("ntdll. Dll") public static extern uint NtQuerySystemInformation (int SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength, ref int returnLength); DllImport("kernel32. Dll") public static extern IntPtr OpenProcess (ProcessAccessFlags dwDesiredAccess, MarshalAs(UnmanagedType.
Bool) bool bInheritHandle, int dwProcessId); DllImport("kernel32. Dll") public static extern int CloseHandle (IntPtr hObject); DllImport("kernel32. Dll", SetLastError = true) return: MarshalAs(UnmanagedType.
Bool) public static extern bool DuplicateHandle (IntPtr hSourceProcessHandle, ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, MarshalAs(UnmanagedType. Bool) bool bInheritHandle, uint dwOptions); DllImport("kernel32. Dll") public static extern IntPtr GetCurrentProcess (); public enum ObjectInformationClass : int { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } Flags public enum ProcessAccessFlags : uint { All = 0x001F0FFF, Terminate = 0x00000001, CreateThread = 0x00000002, VMOperation = 0x00000008, VMRead = 0x00000010, VMWrite = 0x00000020, DupHandle = 0x00000040, SetInformation = 0x00000200, QueryInformation = 0x00000400, Synchronize = 0x00100000 } StructLayout(LayoutKind.
Sequential) public struct OBJECT_BASIC_INFORMATION { // Information Class 0 public int Attributes; public int GrantedAccess; public int HandleCount; public int PointerCount; public int PagedPoolUsage; public int NonPagedPoolUsage; public int Reserved1; public int Reserved2; public int Reserved3; public int NameInformationLength; public int TypeInformationLength; public int SecurityDescriptorLength; public System.Runtime.InteropServices.ComTypes. FILETIME CreateTime; } StructLayout(LayoutKind. Sequential) public struct OBJECT_TYPE_INFORMATION { // Information Class 2 public UNICODE_STRING Name; public int ObjectCount; public int HandleCount; public int Reserved1; public int Reserved2; public int Reserved3; public int Reserved4; public int PeakObjectCount; public int PeakHandleCount; public int Reserved5; public int Reserved6; public int Reserved7; public int Reserved8; public int InvalidAttributes; public GENERIC_MAPPING GenericMapping; public int ValidAccess; public byte Unknown; public byte MaintainHandleDatabase; public int PoolType; public int PagedPoolUsage; public int NonPagedPoolUsage; } StructLayout(LayoutKind.
Sequential) public struct OBJECT_NAME_INFORMATION { // Information Class 1 public UNICODE_STRING Name; } StructLayout(LayoutKind. Sequential, Pack = 1) public struct UNICODE_STRING { public ushort Length; public ushort MaximumLength; public IntPtr Buffer; } StructLayout(LayoutKind. Sequential) public struct GENERIC_MAPPING { public int GenericRead; public int GenericWrite; public int GenericExecute; public int GenericAll; } StructLayout(LayoutKind.
Sequential, Pack = 1) public struct SYSTEM_HANDLE_INFORMATION { // Information Class 16 public int ProcessID; public byte ObjectTypeNumber; public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT public ushort Handle; public int Object_Pointer; public UInt32 GrantedAccess; } public const int MAX_PATH = 260; public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004; public const int DUPLICATE_SAME_ACCESS = 0x2; } #endregion } }.
This works like a charm! – Sandor Drieënhuizen Jan 27 at 14:34 Haha, I like this but it seems to be getting a lock of its own... – Boog Jun 3 at 23:42 Any idea how to fix this code from acquiring a lock of its own on files? – Boog Jun 10 at 21:56.
Not very straight forward, but on Vista and above you can use the restart manager API's to see who is using a file. blogs.msdn.com/vistacompatteam/archive/2... includes details on using this to detect which process has iexplore. Exe open.
Omitting a lot of detail: // Start an RM session RmStartSession(&sessionHandle, 0, sessionKey); // Register the file you are checking RmRegisterResources(sessionHandle, 1, filePathArray, 0, NULL, 0, NULL); // Get all processes that have that file open. RmGetList(sessionHAndle, &nProcInfoNeeded, &nProcInfo, processes, &rebootReason); RmEndSession(sessionHandle).
Thanks for this. Here's also a good article on the Restart Manager topic: msdn.microsoft. Com/en-us/magazine/cc163450.aspx.
Detailed here is a method for getting processes that use a file. – Michael Detras May 30 at 7:44.
Try WhosLocking, it comes with source code.
Try unlocker (ccollomb.free.fr/unlocker/) if you try and delete the file that is locked by another process it will list the process(es) that have the file locked. You can then unlock the file by shutting down those processes.
Oops did not notice that you wanted it progmaticly – AndrewB May 13 '09 at 23:05 this is a great app, i'm voting up your answer because of it. – aronchick May 14 '09 at 16:40.
Handle, from Windows Sysinternals This is a free command-line utility provided by microsoft You could run it, and parse the result.
– Daniel Silveira May 13 '09 at 22:12 Not sure running a 3rd party tool and parsing output counts as "programatically". – Michael May 13 '09 at 22:20 Well, if you can write a program that executes the 3rd party tool (you can) and parses the output (you can) then I'd say that's programmatic. Albeit, not quite what the OP was looking for.
– DevinB May 13 '09 at 22:25 2 @Daniel You need to have it installed, have administrative privileges and rely on the user interface output. Can't think of a less elegant solution let alone a 'programmatical' one. – Trap May 13 '09 at 22:45.
I believe that you need code running in kernel mode to completely answer the question (but I haven't looked at the restart manager API). You can enumerate all processes and their modules - so if the file you're looking for is a module (DLL, EXE, OCX...), you're good to go. But if it's a text file for example, you have to look at the kernel handle table which you cannot see from user mode.Handle.
Exe has a kernel driver in order to do that.
You absolutely don't need to run in Kernel mode (!) It's a Win32 FAQ since Windows 95 (!) (in C, Google groups, Win32) : read the handle table, from User mode of course, and get the PID from the File handle ...
The code I found here, https://vmccontroller.svn.codeplex. Com/svn/VmcController/VmcServices/DetectOpenFiles. Cs Works for me much better than the code provided by Iain.
Iain's code seemed to be acquiring a lock of its own. Here is my slightly modified version of the code above modified to return the string path of the files locked instead of the FileSystemInfo object, using System; using System.Collections. Generic; using System.
EnterpriseServices; using System. IO; using System.Runtime. CompilerServices; using System.Runtime.
ConstrainedExecution; using System.Runtime. InteropServices; using System.Security. Permissions; using System.
Text; using System. Threading; using Microsoft. Win32.
SafeHandles; namespace Crmc.Core. BuildTasks { #region ENUMs internal enum NT_STATUS { STATUS_SUCCESS = 0x00000000, STATUS_BUFFER_OVERFLOW = unchecked((int)0x80000005L), STATUS_INFO_LENGTH_MISMATCH = unchecked((int)0xC0000004L) } internal enum SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, SystemProcessInformation = 5, SystemProcessorPerformanceInformation = 8, SystemHandleInformation = 16, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45 } internal enum OBJECT_INFORMATION_CLASS { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } Flags internal enum ProcessAccessRights { PROCESS_DUP_HANDLE = 0x00000040 } Flags internal enum DuplicateHandleOptions { DUPLICATE_CLOSE_SOURCE = 0x1, DUPLICATE_SAME_ACCESS = 0x2 } #endregion SecurityPermission(SecurityAction. LinkDemand, UnmanagedCode = true) internal sealed class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeObjectHandle() : base(true) { } internal SafeObjectHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { base.
SetHandle(preexistingHandle); } protected override bool ReleaseHandle() { return NativeMethods. CloseHandle(base. Handle); } } SecurityPermission(SecurityAction.
LinkDemand, UnmanagedCode = true) internal sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeProcessHandle() : base(true) { } internal SafeProcessHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { base. SetHandle(preexistingHandle); } protected override bool ReleaseHandle() { return NativeMethods. CloseHandle(base.
Handle); } } #region Native Methods internal static class NativeMethods { DllImport("ntdll. Dll") internal static extern NT_STATUS NtQuerySystemInformation( In SYSTEM_INFORMATION_CLASS SystemInformationClass, In IntPtr SystemInformation, In int SystemInformationLength, Out out int ReturnLength); DllImport("ntdll. Dll") internal static extern NT_STATUS NtQueryObject( In IntPtr Handle, In OBJECT_INFORMATION_CLASS ObjectInformationClass, In IntPtr ObjectInformation, In int ObjectInformationLength, Out out int ReturnLength); DllImport("kernel32.
Dll", SetLastError = true) internal static extern SafeProcessHandle OpenProcess( In ProcessAccessRights dwDesiredAccess, In, MarshalAs(UnmanagedType. Bool) bool bInheritHandle, In int dwProcessId); DllImport("kernel32. Dll", SetLastError = true) return: MarshalAs(UnmanagedType.
Bool) internal static extern bool DuplicateHandle( In IntPtr hSourceProcessHandle, In IntPtr hSourceHandle, In IntPtr hTargetProcessHandle, Out out SafeObjectHandle lpTargetHandle, In int dwDesiredAccess, In, MarshalAs(UnmanagedType. Bool) bool bInheritHandle, In DuplicateHandleOptions dwOptions); DllImport("kernel32. Dll") internal static extern IntPtr GetCurrentProcess(); DllImport("kernel32.
Dll", SetLastError = true) internal static extern int GetProcessId( In IntPtr Process); ReliabilityContract(Consistency. WillNotCorruptState, Cer. Success) DllImport("kernel32.
Dll", SetLastError = true) return: MarshalAs(UnmanagedType. Bool) internal static extern bool CloseHandle( In IntPtr hObject); DllImport("kernel32. Dll", SetLastError = true) internal static extern int QueryDosDevice( In string lpDeviceName, Out StringBuilder lpTargetPath, In int ucchMax); } #endregion ComVisible(true), EventTrackingEnabled(true) public class DetectOpenFiles : ServicedComponent { private static Dictionary deviceMap; private const string networkDevicePrefix = "\\Device\\LanmanRedirector\\"; private const int MAX_PATH = 260; private enum SystemHandleType { OB_TYPE_UNKNOWN = 0, OB_TYPE_TYPE = 1, OB_TYPE_DIRECTORY, OB_TYPE_SYMBOLIC_LINK, OB_TYPE_TOKEN, OB_TYPE_PROCESS, OB_TYPE_THREAD, OB_TYPE_UNKNOWN_7, OB_TYPE_EVENT, OB_TYPE_EVENT_PAIR, OB_TYPE_MUTANT, OB_TYPE_UNKNOWN_11, OB_TYPE_SEMAPHORE, OB_TYPE_TIMER, OB_TYPE_PROFILE, OB_TYPE_WINDOW_STATION, OB_TYPE_DESKTOP, OB_TYPE_SECTION, OB_TYPE_KEY, OB_TYPE_PORT, OB_TYPE_WAITABLE_PORT, OB_TYPE_UNKNOWN_21, OB_TYPE_UNKNOWN_22, OB_TYPE_UNKNOWN_23, OB_TYPE_UNKNOWN_24, //OB_TYPE_CONTROLLER, //OB_TYPE_DEVICE, //OB_TYPE_DRIVER, OB_TYPE_IO_COMPLETION, OB_TYPE_FILE }; private const int handleTypeTokenCount = 27; private static readonly string handleTypeTokens = new string { "", "", "Directory", "SymbolicLink", "Token", "Process", "Thread", "Unknown7", "Event", "EventPair", "Mutant", "Unknown11", "Semaphore", "Timer", "Profile", "WindowStation", "Desktop", "Section", "Key", "Port", "WaitablePort", "Unknown21", "Unknown22", "Unknown23", "Unknown24", "IoCompletion", "File" }; StructLayout(LayoutKind.
Sequential) private struct SYSTEM_HANDLE_ENTRY { public int OwnerPid; public byte ObjectType; public byte HandleFlags; public short HandleValue; public int ObjectPointer; public int AccessMask; } /// /// Gets the open files enumerator. /// /// The process id. /// public static IEnumerable GetOpenFilesEnumerator(int processId) { return new OpenFiles(processId); } private sealed class OpenFiles : IEnumerable { private readonly int processId; internal OpenFiles(int processId) { this.
ProcessId = processId; } #region IEnumerable Members public IEnumerator GetEnumerator() { NT_STATUS ret; int length = 0x10000; // Loop, probing for required memory. Do { IntPtr ptr = IntPtr. Zero; RuntimeHelpers.
PrepareConstrainedRegions(); try { RuntimeHelpers. PrepareConstrainedRegions(); try { } finally { // CER guarantees that the address of the allocated // memory is actually assigned to ptr if an // asynchronous exception occurs. Ptr = Marshal.
AllocHGlobal(length); } int returnLength; ret = NativeMethods. NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS. SystemHandleInformation, ptr, length, out returnLength); if (ret == NT_STATUS.
STATUS_INFO_LENGTH_MISMATCH) { // Round required memory up to the nearest 64KB boundary. Length = ((returnLength + 0xffff) & ~0xffff); } else if (ret == NT_STATUS. STATUS_SUCCESS) { int handleCount = Marshal.
ReadInt32(ptr); int offset = sizeof(int); int size = Marshal. SizeOf(typeof(SYSTEM_HANDLE_ENTRY)); for (int I = 0; I 0 && (i = devicePath. LastIndexOf('\\', I - 1))!
= -1) { string drive; if (deviceMap. TryGetValue(devicePath. Substring(0, i), out drive)) { dosPath = string.
Concat(drive, devicePath. Substring(i)); return dosPath. Length!
= 0; } } dosPath = string. Empty; return false; } private static void EnsureDeviceMap() { if (deviceMap == null) { Dictionary localDeviceMap = BuildDeviceMap(); Interlocked. CompareExchange(ref deviceMap, localDeviceMap, null); } } private static Dictionary BuildDeviceMap() { string logicalDrives = Environment.
GetLogicalDrives(); Dictionary localDeviceMap = new Dictionary(logicalDrives. Length); StringBuilder lpTargetPath = new StringBuilder(MAX_PATH); foreach (string drive in logicalDrives) { string lpDeviceName = drive. Substring(0, 2); NativeMethods.
QueryDosDevice(lpDeviceName, lpTargetPath, MAX_PATH); localDeviceMap. Add(NormalizeDeviceName(lpTargetPath.ToString()), lpDeviceName); } localDeviceMap. Add(networkDevicePrefix.
Substring(0, networkDevicePrefix. Length - 1), "\\"); return localDeviceMap; } private static string NormalizeDeviceName(string deviceName) { if (string. Compare(deviceName, 0, networkDevicePrefix, 0, networkDevicePrefix.
Length, StringComparison. InvariantCulture) == 0) { string shareName = deviceName. Substring(deviceName.
IndexOf('\\', networkDevicePrefix. Length) + 1); return string. Concat(networkDevicePrefix, shareName); } return deviceName; } #endregion } }.
This code appears to show all files opened by a given process but the OP is asking for quite the opposite. – jpierson Jul 12 at 2:29.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.