Member 8653959 Ответов: 3

файл используется другим процессом в c sharp


как проверить файл используется другим процессом в C# framework 3.5 pls help me out..

Savy17

Я использую решение 3, чтобы найти процесс word, который был использован для открытия конкретного документа word. Как только процесс найден, я убиваю процесс с помощью метода process.kill (). Это убивает процесс, и я вижу, что процесс исчезает из Диспетчера задач. Однако если я попытаюсь снова открыть тот же документ, то появится диалоговое окно с сообщением, что файл заблокирован для редактирования "abc".
Если я закрою приложение и перезапущу его, оно будет работать нормально. Пожалуйста, подскажите,как справиться с этой проблемой.

3 Ответов

Рейтинг:
28

Grasshopper.iics

Пожалуйста, проверьте, можете ли вы найти этот процесс с помощью вашего файла. Заменить имя файла в Главном

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace FileLockInfo
{
    public class Win32Processes
    {
        /// <summary>
        /// Return a list of processes that hold on the given file.
        /// </summary>
        /// 

        static void Main()
        {
            Console.WriteLine("C:\\Users\\Rupam\\Desktop\\Transaction Details.pdf");

            GetProcessesLockingFile("C:\\Users\\Rupam\\Desktop\\Transaction Details - PayPal.pdf");
            Console.Read();
         
        }
        public static List<Process> GetProcessesLockingFile(string filePath)
        {
            var procs = new List<Process>();

            var processListSnapshot = Process.GetProcesses();
            foreach (var process in processListSnapshot)
            {
                Console.WriteLine( process.ProcessName);
                if (process.Id <= 4) { continue; } // system processes
                var files = GetFilesLockedBy(process);
                if (files.Contains(filePath))
                {
                    
                    Console.WriteLine("--------------->"+process.ProcessName);
                    procs.Add(process);
                }
            }
            return procs;
        }

        /// <summary>
        /// Return a list of file locks held by the process.
        /// </summary>
        public static List<string> GetFilesLockedBy(Process process)
        {
            var outp = new List<string>();

            ThreadStart ts = delegate
            {
                try
                {
                    outp = UnsafeGetFilesLockedBy(process);
                }
                catch { Ignore(); }
            };

            try
            {
                var t = new Thread(ts);
                t.IsBackground = true;
                t.Start();
                if (!t.Join(250))
                {
                    try
                    {
                        t.Interrupt();
                        t.Abort();
                    }
                    catch { Ignore(); }
                }
            }
            catch { Ignore(); }

            return outp;
        }


        #region Inner Workings
        private static void Ignore() { }
        private static List<string> UnsafeGetFilesLockedBy(Process process)
        {
            try
            {
                var handles = GetHandles(process);
                var files = new List<string>();

                foreach (var handle in handles)
                {
                    var file = GetFilePath(handle, process);
                    if (file != null) files.Add(file);
                }

                return files;
            }
            catch
            {
                return new List<string>();
            }
        }

        const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
        private static string GetFilePath(Win32API.SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process)
        {
            var ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
            var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
            var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
            var objObjectName = new Win32API.OBJECT_NAME_INFORMATION();
            var strObjectName = "";
            var nLength = 0;
            IntPtr ipTemp, ipHandle;

            if (!Win32API.DuplicateHandle(ipProcessHwnd, systemHandleInformation.Handle, Win32API.GetCurrentProcess(), out ipHandle, 0, false, Win32API.DUPLICATE_SAME_ACCESS))
                return null;

            IntPtr 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);

            IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
            nLength = objBasic.TypeInformationLength;
            // this one never locks...
            while ((uint)(Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
            {
                if (nLength == 0)
                {
                    Console.WriteLine("nLength returned at zero! ");
                    return null;
                }
                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;
            }

            var strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
            Marshal.FreeHGlobal(ipObjectType);
            if (strObjectTypeName != "File")
                return null;

            nLength = objBasic.NameInformationLength;

            var ipObjectName = Marshal.AllocHGlobal(nLength);

            // ...this call sometimes hangs. Is a Windows error.
            while ((uint)(Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectNameInformation, ipObjectName, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
            {
                Marshal.FreeHGlobal(ipObjectName);
                if (nLength == 0)
                {
                    Console.WriteLine("nLength returned at zero! " + strObjectTypeName);
                    return null;
                }
                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)
            {

                var baTemp = new byte[nLength];
                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())
            {
                var 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 IEnumerable<Win32API.SYSTEM_HANDLE_INFORMATION> GetHandles(Process process)
        {
            var nHandleInfoSize = 0x10000;
            var ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
            var nLength = 0;
            IntPtr ipHandle;

            while (Win32API.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
            {
                nHandleInfoSize = nLength;
                Marshal.FreeHGlobal(ipHandlePointer);
                ipHandlePointer = Marshal.AllocHGlobal(nLength);
            }

            var baTemp = new byte[nLength];
            Marshal.Copy(ipHandlePointer, baTemp, 0, nLength);

            long lHandleCount;
            if (Is64Bits())
            {
                lHandleCount = Marshal.ReadInt64(ipHandlePointer);
                ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
            }
            else
            {
                lHandleCount = Marshal.ReadInt32(ipHandlePointer);
                ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
            }

            var lstHandles = new List<Win32API.SYSTEM_HANDLE_INFORMATION>();

            for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
            {
                var shHandle = new Win32API.SYSTEM_HANDLE_INFORMATION();
                if (Is64Bits())
                {
                    shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
           


Sergey Alexandrovich Kryukov

И проблема этого решения заключается в полной потере совместимости платформ. На этот раз я не голосовал, так как это могло бы сработать, но я бы не согласился использовать такой зависящий от системы метод...
—СА

Grasshopper.iics

Это прекрасно работает под Windows 7, не требует открытия другого процесса ( handle.exe). Все, что вы делаете, это используете метод GetProcessesLockingFile (). Решение нетривиальных задач не может быть тривиальным. Даже handle.exe стреляет вверх куча проблем !

Sergey Alexandrovich Kryukov

В какой-то степени вы правы. Вот мои аргументы:
Я также упомянул, что вы убиваете совместимость платформ. OP-новичок, но код, созданный сейчас, может быть использован позже, и в эти дни я вижу все больше и больше используемых различных платформ, и не Microsoft, через Mono. Несовместимый.

Я вижу, что вы предоставляете гораздо больше информации о блокировке файлов. Но ОП нужно только знать: работать с файлом или нет. Я почти уверен, что это так. Цель не в том, чтобы написать такую утилиту, как HANDLE.EXE твои знают.

Так что не то чтобы ваше решение было плохим: я буду категорически препятствовать его использованию. И я еще сильнее не согласен с вашей оценкой исключительного подхода. Тем не менее, после некоторого раздумья, я проголосовал за это решение, но своим 4. В конце концов, у вас есть серьезные знания по этому предмету; и код довольно впечатляющий. Я все еще не могу согласиться с вашим мнением.

—СА

Рейтинг:
14

Grasshopper.iics

Сначала проверьте, существует ли файл (File.Существует) если это так, попробуйте открыть для записи в блоке try and catch, если генерируется исключение, то оно используется другим процессом. Однако найти что-то через исключение-не самый лучший способ!


Sergey Alexandrovich Kryukov

Вы, по-видимому, понятия не имеете о сути этой проблемы. Это не так тривиально. Я проголосовал за 1, извините.
—СА

Grasshopper.iics

Что касается вашего вопроса, то он должен был быть "если файл используется другим процессом". Позвольте мне понять, если ваш вопрос предполагает что-то конкретное, на что нет ответа? Скажите, Если вам нужна информация о том, " какой процесс в данный момент обращается к файлу?"

Если бы вы это сделали, я бы дал вам следующее решение, которое будет отображать процесс, который на самом деле удерживает ваш доступ к файлам ( что-то вроде того, что я делал раньше, см. stackoverflow.com)

использование системы;
использование системы.Коллекции.Общий;
используя системы.Во время выполнения.InteropServices;
использование системы.Диагностика;
используя системы.Текст;
использование системы.Нарезание резьбы;

пространство имен FileLockInfo
{
открытый класс Win32Processes
{
///


/// Возвращает список процессов, которые удерживают данный файл.
///

///

статический недействительным Главная()
{
Приставка.WriteLine("C:\\Users\\Rupam\\Desktop\\Transaction подробности. pdf");

GetProcessesLockingFile("Детали C:\\Users\\Rupam\\Desktop\\Transaction - Через Платежную Систему PayPal.формат PDF");
Приставка.Прочитай();

}
public static List & lt;Process> GetProcessesLockingFile(string filePath)
{
var procs = новый список & lt;процесс>();

var processListSnapshot = процесс.GetProcesses();
по каждому элементу (ВАР процесса в processListSnapshot)
{
Приставка.WriteLine( процесс.Параметр processname);
если (процесс.Id <= 4) { continue;} / / системные процессы
var files = GetFilesLockedBy(process);
если (файлы.Содержит(filePath))
{

Приставка.WriteLine("---------------> " + процесс.Параметр processname);
процессы.Добавить (процесс);
}
}
возвратные процессы;
}

///
/// Возвращает список блокировок файлов, удерживаемых процессом.
///

public static List & lt;string & gt; GetFilesLockedBy(Process process)
{
var outp = новый список & lt;string>();

ThreadStart ts = делегат
{
пробовать
{
outp = UnsafeGetFilesLockedBy(процесс);
}
catch { игнорировать(); }
};

пробовать
{
ВАР Т = Новый Поток(ц);
t. IsBackground = true;
Т.Начать();
if (! t. Join(250))
{
пробовать
{
Т.Прервать();
Т.Прервать();
}
catch { игнорировать(); }
}
}
catch { игнорировать(); }

возвращение выходного;
}


#внутреннее устройство области
частных статических недействительным игнорировать() { }
частный статический список & lt;string & gt; UnsafeGetFilesLockedBy(Process process)
{
пробовать
{
ВАР ручки = GetHandles(процесс);
var files = new List & lt;string>();

по каждому элементу (ВАР ручки в ручки)
{
var file = GetFilePath(дескриптор, процесс);
if (file != null) файлы.Добавить файл);
}

возврат файлов;
}
ловить
{
вернуть новый список & lt;string>();
}
}

const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
частная статическая строка GetFilePath (Win32API.SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process)
{
var ipProcessHwnd = Win32API. OpenProcess(Win32API.ProcessAccessFlags.Все, ложь, process.Id);
var objBasic = новый Win32API.OBJECT_BASIC_INFORMATION();
var objObjectType = новый Win32API.OBJECT_TYPE_INFORMATION();
var objObjectName = новый Win32API.OBJECT_NAME_INFORMATION();
ВАР strObjectName = "";
var nLength = 0;
IpTemp указателя IntPtr, ipHandle;

если (!Win32API.Дубликат

Рейтинг:
10

Sergey Alexandrovich Kryukov

По умолчанию файл открыт для исключительного использования, хотя только один дескриптор файла. Если какой-то другой процесс откроет его, у вас будет исключение при попытке открыть его снова. Существует возможность открыть файл для множественного доступа, но это редко бывает, и это не тот случай, который вы описали.

Вы не сможете закрыть файл, если не прекратите процесс "оскорбления".

Прежде всего, подобный вопрос задавался здесь много раз, и из этого опыта я знаю: в большинстве случаев процесс блокировки-это ваш собственный процесс. Вы могли забыть избавиться/закрыть что-то в том же приложении. Итак, прежде всего, проверьте это. Чтобы изучить эту возможность, пожалуйста, посмотрите мой прошлый ответ:
Сняв ручку в C#[^].

В тех же случаях вам действительно нужно исследовать, какой процесс содержит какой файл. Для этого я рекомендую использовать одну утилиту из Sysinternals Suite. Этот набор утилит (ранее от Компании winternals компания, в настоящее время в Microsoft) является обязательным для любого разработчика, пожалуйста, смотрите:
http://technet.microsoft.com/en-us/sysinternals/bb842062[^],
http://technet.microsoft.com/en-us/sysinternals/bb545027[^].

Утилита, которая вам нужна, это "handle.exe", пожалуйста, смотрите:
http://technet.microsoft.com/en-us/sysinternals/bb896655[^].

В вашем случае вы используете его с параметром имени файла:

handle.exe <file_name>


Эта утилита будет сканировать все виды дескрипторов, а не только дескрипторы файлов. Для файла он будет сканировать все дескрипторы файлов, соответствующие имени файла (поэтому он не должен быть полным именем пути), и возвращать информацию, достаточную для идентификации каждого процесса, включая его имя. pid Таким образом, если вам нужна дополнительная информация о рассматриваемом процессе, вы также можете использовать другие утилиты Sysinternals, в частности, его Исследователь Процессов:
http://technet.microsoft.com/en-us/sysinternals/bb896653[^].

[Правка #1]

Теперь, если вы просто хотите проверить, открыт ли файл уже каким-то процессом в данный момент (но почему?), я обычно советую очень простую вещь. Это хорошая идея-использовать наступательное Программирование вместо оборонительного. Вы можете просто работать с файлом, как будто он не заблокирован. Бутерброд этой части кода в блоке try-catch-finally. Если блок бросает код в часть catch, это означает, что файл был использован другим процессом. Это абсолютно безопасно.

Делать что-то другое очень трудно и вряд ли может оправдать усилия. Кроме того, он сильно зависит от системы и, конечно же, потребует P/Invoke. Вы полностью убьете независимость вашего кода от платформы, если попытаетесь это сделать.

[Правка #2]

В принципе, можно было бы запустить и другой вариант handle.exe через System.Diagnostics.Process.Start Вам также нужно будет перенаправить StandardOutput вашего процесса, чтобы захватить и извлечь результат диагностики. Образец перенаправления можно найти здесь: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx[^].

Однако такой подход далек от элегантности. И если вам нужно развернуть свой продукт, это будет какая-то проблема (юридическая, техническая… третья сторона - это третья сторона).

Удачи,
—СА