Which process has locked a file?

Started by Theo Gottwald, March 29, 2012, 03:28:52 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Theo Gottwald

I found an interesting blog

OldNewThing

It answers the question, "How can i find out, which process has locked a file?"

But the code is only in C. Does anybody want to transfer it to PB?
Thats something we can use from time to time ...

#include <windows.h>
#include <RestartManager.h>
#include <stdio.h>

int __cdecl wmain(int argc, WCHAR **argv)
{
DWORD dwSession;
WCHAR szSessionKey[CCH_RM_SESSION_KEY+1] = { 0 };
DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
wprintf(L"RmStartSession returned %d\n", dwError);
if (dwError == ERROR_SUCCESS) {
   PCWSTR pszFile = argv[1];
   dwError = RmRegisterResources(dwSession, 1, &pszFile,
                                 0, NULL, 0, NULL);
   wprintf(L"RmRegisterResources(%ls) returned %d\n",
           pszFile, dwError);
  if (dwError == ERROR_SUCCESS) {
   DWORD dwReason;
   UINT i;
   UINT nProcInfoNeeded;
   UINT nProcInfo = 10;
   RM_PROCESS_INFO rgpi[10];
   dwError = RmGetList(dwSession, &nProcInfoNeeded,
                       &nProcInfo, rgpi, &dwReason);
   wprintf(L"RmGetList returned %d\n", dwError);
   if (dwError == ERROR_SUCCESS) {
    wprintf(L"RmGetList returned %d infos (%d needed)\n",
            nProcInfo, nProcInfoNeeded);
    for (i = 0; i < nProcInfo; i++) {
     wprintf(L"%d.ApplicationType = %d\n", i,
                              rgpi[i].ApplicationType);
     wprintf(L"%d.strAppName = %ls\n", i,
                              rgpi[i].strAppName);
     wprintf(L"%d.Process.dwProcessId = %d\n", i,
                              rgpi[i].Process.dwProcessId);
     HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION,
                                   FALSE, rgpi[i].Process.dwProcessId);
     if (hProcess) {
      FILETIME ftCreate, ftExit, ftKernel, ftUser;
      if (GetProcessTimes(hProcess, &ftCreate, &ftExit,
                          &ftKernel, &ftUser) &&
          CompareFileTime(&rgpi[i].Process.ProcessStartTime,
                          &ftCreate) == 0) {
       WCHAR sz[MAX_PATH];
       DWORD cch = MAX_PATH;
       if (QueryFullProcessImageNameW(hProcess, 0, sz, &cch) &&
           cch <= MAX_PATH) {
        wprintf(L"  = %ls\n", sz);
       }
      }
      CloseHandle(hProcess);
     }
    }
   }
  }
  RmEndSession(dwSession);
}
return 0;
}

Pierre Bellisle

#1
Hi Theo,

Interesting indeed.
Here is some CC 4.04 code...
First part will create and lock a file named "C:\Tmp\LockedFile.txt",
the second part is a traduction of the C code you provided, it will check if our .txt file is locked and if so, it will provide which process is responsable and, of course, the corresponding .exe name.

Have fun...

Pierre


'You may run many instances of this program to see RmGetList result.

#COMPILE EXE '#CC 4.04#
#DIM ALL
#INCLUDE "Win32Api.inc"
'______________________________________________________________________________

FUNCTION PBMAIN() AS LONG
LOCAL hFile AS LONG
LOCAL sFile AS STRING

MKDIR "C:\Tmp"
sFile = "C:\Tmp\LockedFile.txt"
ERRCLEAR
PRINT "Opening and locking " & sFile
OPEN sFile FOR BINARY ACCESS READ LOCK WRITE AS hFile
PRINT "Error report: Error" & STR$(ERR) & " : (" & ERROR$(ERR) & ")"

PRINT : PRINT "Press any key or click to close and delete " & sFile : MOUSE ON : MOUSE 3, UP : WAITKEY$
CLOSE hFile
KILL sFile

PRINT "Done..."
PRINT : PRINT "Press any key or click to end program..." : MOUSE ON : MOUSE 3, UP : WAITKEY$

END FUNCTION
'______________________________________________________________________________
'


'http://www.jose.it-berater.org/smfforum/index.php?topic=4515.msg16797;topicseen#msg16797
'http://blogs.msdn.com/b/oldnewthing/default.aspx?PageIndex=4

'How can i find out, which process has locked a file?

'Restart manager api.
' RmStartSession      is used to create a new Restart Manager session. A maximum of 64 concurrent session can be used at the same time.
'                     The session will encapsulate all of the actions required to do a setup, allowing you to stop/restart applications.
' RmRegisterResources takes in a list of resources that have to be "managed" by the Restart Manager in the current session.
'                     Such resources can be a file (that is to be replaced by the setup), a process (e.g. when upgrading an application) and a Windows Service.
' RmShutdown          shuts down the registered resources so that setup can proceed without being faced with files in use.
' RmRestart           restarts the registered resources that have been shut down previously by RmShutdown.
' RmEndSession        stops a session that has been created by RmStartSession previously.
' RmJoinSession       can be used to join a secondary installer to an existing Restart Manager session.
' RmAddFilter         allows to change actions that will be performed on applications, e.g. to prevent restart or shutdown of a given application.
' RmRemoveFilter      reverses filters added by RmAddFilter.
' RmGetFilterList     lists all of the filters applied by the RmAddFilter function.
' RmGetList           provides information of the applications and services that are using resources that were registered by means of RmRegisterResources.
'                     In case a system restart is needed, the reason is provided.
' RmCancelCurrentTask cancels a RmGetList, RmShutdown or RmRestart action in progress.

'Application type
'0    : RmUnknownApp:  The application cannot be classified as any other type. An application of this type can only be shut down by a forced shutdown.
'1    : RmMainWindow:  A Windows application run as a stand-alone process that displays a top-level window.
'2    : RmOtherWindow: A Windows application that does not run as a stand-alone process and does not display a top-level window.
'3    : RmService:     The application is a Windows service.
'4    : RmExplorer:    The application is Windows Explorer
'5    : RmConsole:     The application is a stand-alone console application.
'1000 : RmCritical:    A system restart is required to complete the installation because a process cannot be shut down. The process cannot be shut down because of the following reasons.
'                      The process may be a critical process. The current user may not have permission to shut down the process. The process may belong to the primary installer that started the Restart Manager.

#COMPILE EXE '#CC 4.04#
#DIM ALL
#INCLUDE "Win32Api.inc"

%RM_SESSION_KEY_LEN                = 16 'SIZEOF(GUID)
%CCH_RM_SESSION_KEY                = %RM_SESSION_KEY_LEN * 2
%CCH_RM_MAX_SVC_NAME               = 63
%CCH_RM_MAX_APP_NAME               = 255
%PROCESS_QUERY_LIMITED_INFORMATION = &H1000

TYPE RM_UNIQUE_PROCESS
  dwProcessId      AS DWORD
  ProcessStartTime AS FILETIME
END TYPE

TYPE RM_PROCESS_INFO
  Process             AS RM_UNIQUE_PROCESS
  strAppName          AS STRING * (%CCH_RM_MAX_APP_NAME + 1) * 2
  strServiceShortName AS STRING * (%CCH_RM_MAX_SVC_NAME + 1) * 2
  ApplicationType     AS LONG
  AppStatus           AS DWORD
  TSSessionId         AS DWORD
  bRestartable        AS LONG
END TYPE

DECLARE FUNCTION RmStartSession LIB "Rstrtmgr.dll" ALIAS "RmStartSession" _
(BYREF DWORD, BYVAL DWORD, BYREF ANY) AS DWORD

DECLARE FUNCTION RmRegisterResources LIB "Rstrtmgr.dll" ALIAS "RmRegisterResources" _
(BYVAL DWORD, BYVAL DWORD, BYREF ANY, BYVAL DWORD, BYREF RM_UNIQUE_PROCESS, BYVAL DWORD, BYREF ANY) AS DWORD

DECLARE FUNCTION RmGetList LIB "Rstrtmgr.dll" ALIAS "RmGetList" _
(BYVAL DWORD, BYREF DWORD, BYREF DWORD, BYREF RM_PROCESS_INFO, BYREF DWORD) AS DWORD

DECLARE FUNCTION QueryFullProcessImageNameW LIB "KERNEL32.DLL" ALIAS "QueryFullProcessImageNameW" _
(BYVAL DWORD, BYVAL DWORD, BYREF DWORD, BYREF DWORD) AS LONG

DECLARE FUNCTION RmEndSession LIB "Rstrtmgr.dll" ALIAS "RmEndSession"(BYVAL DWORD) AS DWORD
'______________________________________________________________________________

FUNCTION PBMAIN() AS LONG
LOCAL ftCreate        AS FILETIME
LOCAL ftExit          AS FILETIME
LOCAL ftKernel        AS FILETIME
LOCAL ftUser          AS FILETIME
LOCAL sSessionKey     AS STRING * (2 * %CCH_RM_SESSION_KEY) + 2
LOCAL sz              AS STRING * %MAX_PATH * 2
LOCAL sFile           AS STRING
LOCAL sFileName       AS STRING
LOCAL dwSession       AS DWORD
LOCAL dwError         AS DWORD
LOCAL psFile          AS DWORD
LOCAL dwReason        AS DWORD
LOCAL i               AS DWORD
LOCAL nProcInfoNeeded AS DWORD
LOCAL nProcInfo       AS DWORD
LOCAL hProcess        AS DWORD
LOCAL cch             AS DWORD

sFileName = "C:\Tmp\LockedFile.txt"

dwError = RmStartSession(dwSession, 0, BYVAL VARPTR(sSessionKey))
PRINT "RmStartSession, Error       =" & STR$(dwError)
PRINT "RmStartSession, dwSession   =" & STR$(dwSession)
PRINT "RmStartSession, sSessionKey = " & ACODE$(sSessionKey)
PRINT

IF (dwError = %ERROR_SUCCESS) THEN
   sFile = UCODE$(sFileName & $NUL) '$NUL is needed
   psFile = STRPTR(sFile)
   dwError = RmRegisterResources(dwSession, 1, psFile, BYVAL 0, BYVAL %NULL, BYVAL 0, BYVAL %NULL)
   PRINT "RmRegisterResources, Error  =" & STR$(dwError)
   PRINT "RmRegisterResources, File   = " & ACODE$(sFile)
   PRINT
   IF (dwError = %ERROR_SUCCESS) THEN
     nProcInfo = 10
     DIM rgpi(0 TO 9) AS RM_PROCESS_INFO
     dwError = RmGetList(dwSession, nProcInfoNeeded, nProcInfo, rgpi(0), dwReason)
     PRINT "RmGetList, Error            ="  & STR$(dwError)
     IF (dwError = %ERROR_SUCCESS) THEN
       PRINT "RmGetList, ProcInfoNeeded   =" & STR$(nProcInfoNeeded)
       PRINT "RmGetList, nProcInfo        =" & STR$(nProcInfo)
       IF nProcInfo = 0 THEN
         PRINT "File not locked             = " & ACODE$(sFile)
       ELSE
         PRINT "File locked                 = " & ACODE$(sFile)
         PRINT
         FOR i = 0 TO nProcInfo - 1
           PRINT STRING$(80, "-")
           PRINT "ApplicationType" & STR$(i) & "           = (" & LTRIM$(STR$(rgpi(i).ApplicationType)) & ") ";
           SELECT CASE rgpi(i).ApplicationType
             CASE 0    : PRINT "RmUnknownApp: Application cannot be classified"
             CASE 1    : PRINT "RmMainWindow: Stand-alone process" : PRINT SPACE$(30) & "and top-level window"
             CASE 2    : PRINT "RmOtherWindow: Not stand-alone process" : PRINT SPACE$(30) & "and not top-level window"
             CASE 3    : PRINT "RmService: Application is a Windows service"
             CASE 4    : PRINT "RmExplorer: Application is Windows Explorer"
             CASE 5    : PRINT "RmConsole: Application is" : PRINT SPACE$(30) & "a stand-alone console application"
             CASE 1000 : PRINT "RmCritical: Critical process"
           END SELECT
           PRINT "strAppName     " & STR$(i) & "           = " & RTRIM$(ACODE$(rgpi(i).strAppName), ANY $SPC & $NUL)
           PRINT "dwProcessId    " & STR$(i) & "           = " & HEX$(rgpi(i).Process.dwProcessId, 8)
           hProcess = OpenProcess(%PROCESS_QUERY_LIMITED_INFORMATION, %FALSE, rgpi(i).Process.dwProcessId)
           IF hProcess THEN
             PRINT
             PRINT "hProcess                    = " & HEX$(hProcess, 8)
             IF (GetProcessTimes(hProcess, ftCreate, ftExit, ftKernel, ftUser)) AND _  'Return non-zero if success
                (CompareFileTime(rgpi(i).Process.ProcessStartTime, ftCreate) = 0) THEN 'Return zero if times are equal
               cch = SIZEOF(sz)
               IF (QueryFullProcessImageNameW(hProcess, 0, BYVAL VARPTR(sz), cch)) THEN
                 PRINT "Locking exe is              = " & ACODE$(sz)
               END IF
             END IF
             CloseHandle(hProcess)
           END IF
         NEXT
         PRINT STRING$(80, "-")
       END IF
     END IF
   END IF
   RmEndSession(dwSession)
END IF

PRINT : PRINT "Press any key or click to continue..." : MOUSE ON : MOUSE 3, UP : WAITKEY$

END FUNCTION
'______________________________________________________________________________
'

Theo Gottwald

Thanks Pierre, great you did that.

I remember that i needed such a code some years before but could not find it.
And C is like a book with a lot of seals to me.

Now that I know that you are here, I'll look for more interesting stuff to get translated.  ;D

Eros Olmi

Maybe this VBS script can help:


Domain = "---yourdomain---"
ServerName = "---yourservername---"

On Error Resume Next

Set fs = GetObject("WinNT://" & Domain & "/" & ServerName & "/LanmanServer")

For Each res In fs.Resources
   wscript.echo "_____________"
   wscript.echo "ResourceID: " & res.Name
   wscript.echo " Resource: " & res.Path
   wscript.echo " Opened by user: " & res.User
   wscript.echo " Locks: " & res.LockCount
Next
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

José Roca

Quote
DECLARE FUNCTION RmEndSession LIB "Rstrtmgr.dll" ALIAS "RmEndSession"(BYREF DWORD) AS DWORD

must be:

Quote
DECLARE FUNCTION RmEndSession LIB "Rstrtmgr.dll" ALIAS "RmEndSession"(BYVAL DWORD) AS DWORD

Pierre Bellisle

Yep, done.

The correction will have also to be made in WINAPI_II_05\RestartManager.inc

Pierre

José Roca

Yes, I have revised that file. For some reason, I had the dwSessionHandle parameter i this function and all the others below declared as BYREF instead of as BYVAL.