19/09/2019, 06:43

[C#] Tìm kiếm ứng dụng đang mở file và đóng ứng dụng

Xin chào các bạn, bài viết hôm nay mình sẽ tiếp tục hướng dẫn các bạn các tìm kiếm ứng dụng đang mở file và đóng ứng dụng lại trong lập trình C# Winform sử dụng thư viện Win32. Bài viết này, chắc các bạn mới đọc qua tiêu đề, chắc chưa hiểu bài viết này mình ...

Xin chào các bạn, bài viết hôm nay mình sẽ tiếp tục hướng dẫn các bạn các tìm kiếm ứng dụng đang mở file và đóng ứng dụng lại trong lập trình C# Winform sử dụng thư viện Win32.

Bài viết này, chắc các bạn mới đọc qua tiêu đề, chắc chưa hiểu bài viết này mình viết dùng để làm gì. Mình sẽ có ví dụ sau, để giúp các bạn dễ hiểu về bài viết này.

Ví dụ: Hôm nay, mình đang viết một ứng dụng đọc file excel vào Winform.

Thì khi file Excel này của các bạn đang được mở bởi một ứng dụng nào đó vd: Microsoft Excel, MS Word hay Notepad chẳng hạn.

Thì khi các bạn import file này vào hay muốn xóa file, thì sẽ xuất hiện đến các bạn thông báo lỗi:

Đơn giản là nó thông báo, file này đã bị locked bởi một ứng dụng khác.

Và bài này công việc mình mong muốn sẽ là tự động tìm ứng dụng nào đang locked file này, và đóng ứng dụng nó đi để ứng dụng C# của chúng ta có thể làm việc với tập tin này.

Hoặc có thể có một ví dụ khác, hôm nay mình đang viết ứng dụng tự động cập nhật phần mềm của công ty, thì khi cập nhật file thì chúng ta sẽ ghi đè lên file đó, và mình mong muốn là file mình sắp ghi đè này sẽ không có bị một ứng dụng nào đang mở (locked file).

Giao diện demo ứng dụng Find Process Locked File C#:

locked_file_by_process

Đầu tiên các bạn tạo cho mình một class với tên Win32Processes.cs C#:

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

namespace FindAllProcessLockedFile
{
    public static class Win32Processes
    {
        
        public static List<Process> GetProcessesLockingFile(string path)
        {
            uint handle;
            string key = Guid.NewGuid().ToString();
            int res = RmStartSession(out handle, 0, key);

            if (res != 0) throw new Exception("Could not begin restart session.  Unable to determine file locker.");

            try
            {
                const int MORE_DATA = 234;
                uint pnProcInfoNeeded, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone;

                string[] resources = { path }; // Just checking on one resource.

                res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);

                if (res != 0) throw new Exception("Could not register resource.");

            
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);

                if (res == MORE_DATA)
                {
                    return EnumerateProcesses(pnProcInfoNeeded, handle, lpdwRebootReasons);
                }
                else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
            }
            finally
            {
                RmEndSession(handle);
            }

            return new List<Process>();
        }


        [StructLayout(LayoutKind.Sequential)]
        public struct RM_UNIQUE_PROCESS
        {
            public int dwProcessId;
            public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
        }

        const int RmRebootReasonNone = 0;
        const int CCH_RM_MAX_APP_NAME = 255;
        const int CCH_RM_MAX_SVC_NAME = 63;

        public enum RM_APP_TYPE
        {
            RmUnknownApp = 0,
            RmMainWindow = 1,
            RmOtherWindow = 2,
            RmService = 3,
            RmExplorer = 4,
            RmConsole = 5,
            RmCritical = 1000
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct RM_PROCESS_INFO
        {
            public RM_UNIQUE_PROCESS Process;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] public string strAppName;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] public string strServiceShortName;

            public RM_APP_TYPE ApplicationType;
            public uint AppStatus;
            public uint TSSessionId;
            [MarshalAs(UnmanagedType.Bool)] public bool bRestartable;
        }

        [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
        static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames,
            uint nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, uint nServices,
            string[] rgsServiceNames);

        [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
        static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

        [DllImport("rstrtmgr.dll")]
        static extern int RmEndSession(uint pSessionHandle);

        [DllImport("rstrtmgr.dll")]
        static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded,
            ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
            ref uint lpdwRebootReasons);

        private static List<Process> EnumerateProcesses(uint pnProcInfoNeeded, uint handle, uint lpdwRebootReasons)
        {
            var processes = new List<Process>(10);         
            var processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
            var pnProcInfo = pnProcInfoNeeded;

            // Get the list
            var res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);

            if (res != 0) throw new Exception("Could not list processes locking resource.");
            for (int i = 0; i < pnProcInfo; i++)
            {
                try
                {
                    processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                }
                catch (ArgumentException) { } 
            }
            return processes;
        }
    }
}

Và code sử dụng để tìm kiếm process và kill process C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FindAllProcessLockedFile
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var list_process = Win32Processes.GetProcessesLockingFile(textBox1.Text);
            
            StringBuilder str = new StringBuilder();
            foreach (var item in list_process)
            {
                str.Append(item.ProcessName + Environment.NewLine);
                item.Kill();
            }

            txt_result.Text = str.ToString();


        }

        private void btn_browser_Click(object sender, EventArgs e)
        {
            using(var dlg = new OpenFileDialog())
            {
                if(dlg.ShowDialog() == DialogResult.OK)
                {
                    textBox1.Text = dlg.FileName;
                }
            }
        }
    }
}

Thanks for watching!

DOWNLOAD SOURCE

Tags: find process locked file c#kill process locked file c#
0