Is there anything in the Windows c++ API to give me a list of processes that have a handle to a given file?
-
What did your research in the documentation reveal so far? – Lightness Races in Orbit Aug 03 '11 at 19:18
-
In linux there is fuser for this. Apparently the windows equivalent is called Handle (found just by searning windows fuser). It is a command not an api call, but might help your search – frankc Aug 03 '11 at 19:50
-
the only idea i have now is to invoke handle.exe with the filename and that would give me the details. I did not want to go about starting a process for this if there is an existing api that does this. – Sriram Subramanian Aug 03 '11 at 19:52
-
@sriram again I don't know much about windows, but in unix if i wanted to know what system calls fuser was using, i would use strace to see the system calls as they happen. Apparently windows has an equivalent called process monitor: http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx I would try that on handle.exe to see what it is doing – frankc Aug 03 '11 at 20:02
2 Answers
From Microsoft's blog: How do I find out which process has a file open?
Enter the Restart Manager.
The official goal of the Restart Manager is to help make it possible to shut down and restart applications which are using a file you want to update. In order to do that, it needs to keep track of which processes are holding references to which files. And it’s that database that is of use here. (Why is the kernel keeping track of which processes have a file open? Because it’s the converse of the principle of not keeping track of information you don’t need: Now it needs the information!)
Here’s a simple program which takes a file name on the command line and shows which processes have the file open.
#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; }
This article explains it pretty good. It uses NtQuerySystemInformation to get the handles.
http://msdn.microsoft.com/en-us/library/ms724509(VS.85).aspx