I found an interesting blog
OldNewThing (http://blogs.msdn.com/b/oldnewthing/default.aspx?PageIndex=4)
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;
}
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
'______________________________________________________________________________
'
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
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
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
Yep, done.
The correction will have also to be made in WINAPI_II_05\RestartManager.inc
Pierre
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.