SoFunction
Updated on 2025-03-06

c# Use to solve the problem of program update file occupied

Recently, our company's upgrade program often reports update failure problems. The reason is that when the update is updated, they may have opened the updated file again, which causes the file to be occupied by other processes when updating the file and cannot be updated normally, and an error is reported. In order to solve this problem, I spent a week querying information from multiple parties and researching, and finally found a tool for querying the process:, download address:/en-us/sysinternals/, I used it to find the occupied process, then KILL the occupied process, and finally update it. This perfectly solves the problem of file occupied errors during update. The implementation method is very simple. I have listed the main methods below, and I have explained some precautions. Everyone will understand it at a glance. Of course, if you have a better solution, welcome to communicate, thank you!

IsFileUsing:

Determine whether the file is occupied

[DllImport("")]
public static extern IntPtr _lopen(string lpPathName, int iReadWrite);
 
[DllImport("")]
public static extern bool CloseHandle(IntPtr hObject);
 
public const int OF_READWRITE = 2;
public const int OF_SHARE_DENY_NONE = 0x40;
public readonly IntPtr HFILE_ERROR = new IntPtr(-1);
private bool <strong>IsFileUsing</strong>(string filePath)
{
    if (!(filePath))
    {
        return false;
    }
    IntPtr vHandle = _lopen(filePath, OF_READWRITE | OF_SHARE_DENY_NONE);
    if (vHandle == HFILE_ERROR)
    {
        return true;
    }
    CloseHandle(vHandle);
    return false;
}

GetRunProcessInfos:

Get the (associated) run process information present in the specified file or directory so that the occupancy can be later released

/// &lt;summary&gt;
/// Get the (associated) running process information in the specified file or directory so that the occupancy can be released later/// &lt;/summary&gt;
/// &lt;param name="filePath"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
private Dictionary&lt;int, string&gt; GetRunProcessInfos(string filePath)
{
 
    Dictionary&lt;int, string&gt; runProcInfos = new Dictionary&lt;int, string&gt;();
    string fileName = (filePath);
    var fileRunProcs = (fileName);
    if (fileRunProcs != null &amp;&amp; () &gt; 0)
    {
        runProcInfos = (p =&gt; , p =&gt; );
        return runProcInfos;
    }
 
    string fileDirName = (filePath); //Query running processes under the specified path    Process startProcess = new Process();
     = RelaseAndGetHandleExePath();
     = ("\"{0}\"", fileDirName);
     = false;
     = false;
     = true;
     = true;
     = ASCIIEncoding.UTF8;
     += (sender, e) =&gt;
    {
        if (!() &amp;&amp; ("pid:", ) &gt; 0)
        {
            //var regex = new (@"(^[\w\.\?\u4E00-\u9FA5]+)\s+pid:\s*(\d+)", );
            var regex = new (@"(^.+(?=pid:))\bpid:\s+(\d+)\s+", );
            if (())
            {
                var mathedResult = ();
 
                int procId = ([2].Value);
                string procFileName = [1].();
 
                if ("".Equals(procFileName, ))
                {
                    return;
                }
 
                //var regex2 = new ((@"\b{0}.*$", (@"\", @"\\").Replace("?",@"\?")), );
                var regex2 = new (@"\b\w{1}:.+$", );
                string procFilePath = (().Value ?? "").Trim();
 
                if ((procFilePath, ) || (PathJoin(procFilePath, procFileName), ))
                {
                    runProcInfos[procId] = procFileName;
                }
                else //If the code is garbled, make a special comparison                {
                    if (("?") || ("?")) //?Garbage code comparison logic                    {
                        var regex3 = new ((@"\", @"\\").Replace(".", @"\.").Replace("?", ".{1}"), );
                        if ((filePath))
                        {
                            runProcInfos[procId] = procFileName;
                        }
                        else
                        {
                            string tempProcFilePath = PathJoin(procFilePath, procFileName);
 
                            regex3 = new ((@"\", @"\\").Replace(".", @"\.").Replace("?", ".{1}"), );
                            if ((filePath))
                            {
                                runProcInfos[procId] = procFileName;
                            }
                        }
                    }
                    else if ( ==  || PathJoin(procFilePath, procFileName).Length == ) //Other garbled code comparison logic, only the comparison length, if the same is true, it will be judged by the user                    {
                        if ((("Discover files:{0}Probably by a process({1})Occupancy,\nDo you need to force the process to terminate?", filePath, procFileName), "发现疑似被Occupancy进程", , ) == )
                        {
                            runProcInfos[procId] = procFileName;
                        }
                    }
                }
            }
        }
    };
 
    ();
    ();
    ();
 
    return runProcInfos;
}

Brief description of the above code logic: Create a construction program to start (embedded into the project in the form of a resource), then receive the return data asynchronously, and obtain the process data through regular expressions. Since it is not compatible with Chinese paths or file names, the returned data exists? Or other garbled characters, so I made some special fuzzy matching logic;

RelaseAndGetHandleExePath:

Release and save it from the project to the APPData directory of the system so that it can be used directly in the future (Note: Since the tool is required to be used normally after authorization and consent, I will directly run the process when I first generate it, so that the user can choose Agree before performing the subsequent logical processing. Although this can solve the problem, it is a bit unfriendly. Currently, one is in Chinese garbled code, and the other is required to agree to use it. I think it might be better if Microsoft solves it)

private string RelaseAndGetHandleExePath()
{
    var handleInfo = new FileInfo(() + "\\SysUpdate\\");
    if (!())
    {
        if (!())
        {
            ();
        }
 
        byte[] handleExeData = ;
        (, handleExeData);
 
        var handleProc = ();//If the first time, a prompt box will pop up and you need to click agree to agree to it.        ();
    }
 
    return ;
}

PathJoin:

Splicing paths (but filtering special characters), because they are not compatible with Chinese paths or file names, the returned data exists? Or other garbled characters, if you use: method, an error will be reported, so you can customize a method here, just a simple splicing

/// &lt;summary&gt;
///Split path (but filtering special characters)/// &lt;/summary&gt;
/// &lt;param name="paths"&gt;&lt;/param&gt;
/// &lt;returns&gt;&lt;/returns&gt;
private string PathJoin(params string[] paths)
{
    if (paths == null ||  &lt;= 0)
    {
        return ;
    }
 
    string newPath = paths[0];
 
    for (int i = 1; i &lt; ; i++)
    {
        if (!("\\"))
        {
            newPath += "\\";
        }
 
        if (paths[i].StartsWith("\\"))
        {
            paths[i] = paths[i].Substring(1);
        }
 
        newPath += paths[i];
    }
 
    return newPath;
}

CloseProcessWithFile:

Core method, closes the process occupied by the specified file. All the above methods are to implement the function of this method.

private void CloseProcessWithFile(string filePath)
{
    if (!IsFileUsing(filePath)) return;
 
    ShowDownInfo(("Trying to unoccupied files {0}", _FilePaths[_FileIndex]));
 
    var runProcInfos = GetRunProcessInfos(filePath); //Get the occupied process 
 
    ((, ""), ("\r\n", (p =&gt; ("ProdId:{0},ProcName:{1}", , )).ToArray()));// Use DEBUG, it can be removed when it is officially released 
    var localProcesses = ();
    bool hasKilled = false;
    foreach (var item in runProcInfos)
    {
        if ( != currentProcessId) //Exclude the current process        {
            var runProcess = (p =&gt;  == );
            //var runProcess = ();
            if (runProcess != null)
            {
                try
                {
                    (); // Force shutdown of occupied processes                    hasKilled = true;
                }
                catch
                { }
            }
        }
    }
 
    if (hasKilled)
    {
        (500);
    }
}

Brief description of the above code logic: first determine whether it is occupied. If it is occupied, obtain the list of processes occupied by the file, then obtain the list of all processes in the current operating system, and finally obtain the list of process IDs that exclude the current program's own process ID (currentProcessId = ().Id) through process ID query. If it can be obtained, it indicates that the process is still running, force the process to terminate the process to achieve the release of file occupation.

Note: After KILL is dropped and occupied by the process, it may be due to cache reasons. If the file is overwritten, replacement or transfer operations are performed directly, an error may still be reported. Therefore, a judgment is made here. If the process is successfully dropped by KILL, you need to wait 500MS before doing operations such as updating the file;

The above is the detailed content of using c# to solve the problem of using program update files. For more information about using c# to solve the problem of using program updates, please pay attention to my other related articles!