Search code examples
c++windowswinapievent-viewer

Windows Event Viewer holds a lock on my EXE file


I'm curious about something. I'm developing a Windows service and log all the diagnostic events into the Windows Event Log. So when the service is running I open the Event Viewer (from Administrative tools) to view the results of my service's operation.

This works great except for the moment when I need to uninstall my program (again, for the testing purposes.) For some weird reason the Event Viewer holds a lock on the .exe image file for my service so the uninstaller fails to delete it with the error code ERROR_SHARING_VIOLATION:

The process cannot access the file because it is being used by another process.

This happens only on Vista and later OS and seems not to be an issue on XP.

Any idea how to make Event Viewer release the file lock? (I'm asking about programmatic approach. I can obviously close it manually, but that's not what I'm after.)


Solution

  • There's a less known feature introduced in Vista called Restart Manager that can help you release file locks via a user-mode code. Since you tagged it as C++, based on this article here's a small code sample to do that:

    #include <RestartManager.h>
    #pragma comment(lib ,"Rstrtmgr.lib")
    
    BOOL ReleaseFileLock(LPCTSTR pFilePath)
    {
        BOOL bResult = FALSE;
    
        DWORD dwSession;
        WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = { 0 };
        DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
        if (dwError == ERROR_SUCCESS) 
        {
            dwError = RmRegisterResources(dwSession, 1, &pFilePath,
                0, NULL, 0, NULL);
            if (dwError == ERROR_SUCCESS) 
            {
                UINT nProcInfoNeeded = 0;
                UINT nProcInfo = 0;
                RM_PROCESS_INFO rgpi[1];
                DWORD dwReason;
    
                dwError = RmGetList(dwSession, &nProcInfoNeeded,
                    &nProcInfo, rgpi, &dwReason);
                if (dwError == ERROR_SUCCESS ||
                    dwError == ERROR_MORE_DATA) 
                {
                    if(nProcInfoNeeded > 0)
                    {
                        //If current process does not have enough privileges to close one of
                        //the "offending" processes, you'll get ERROR_FAIL_NOACTION_REBOOT
                        dwError = RmShutdown(dwSession, RmForceShutdown, NULL);
                        if (dwError == ERROR_SUCCESS)
                        {
                            bResult = TRUE;
                        }
                    }
                    else
                        bResult = TRUE;
                }
            }
        }
    
        RmEndSession(dwSession);
    
        SetLastError(dwError);
        return bResult;
    }