Alle offenen Handles einer Datei herausfinden



  • Gegeben ist ein Dateiname (z.B. "c:\x.txt"). Nun möchte ich alle Handles herausfinden die diese Datei gerade geöffnet haben.
    Im zweiten Schritt bräuchte ich dann noch das Handle des Prozesses der die Datei geöffnet hat.

    Geht sowas?

    Das Programm darf ausdrücklich mit Administarationsrechten laufen.



  • Nein, das geht nicht. Man kann sowas für "lokale" Prozess z.B. mit dem Prozess-Explorer machen. Wenn die Datei aber via Netzwerkshare geöffnet ist, hilft Dir das nicht viel weiter...

    WAS willst Du denn genau? bzw. WARUM?



  • Manchmal "blockiert" irgendein Programm / Thread eine Datei, und behindert diese am geschrieben werden oder am löschen.

    Ich möchte nun ein Programm schrieben welches mir anzeigt, welches Programm der Verursacher ist.



  • Dann schau am besten mit dem Prozess Explorer nach... solche Funktion in Dein eigenes Programm einzubauen, würde ich nicht machen... ch vermute eher, Du vergisst selber das Dateihandle zu schliessen...



  • das geht mit der nativen NT API. hab ich mal gemacht. über normale winapi geht es nicht.



  • ich kann dir nachher mal meinen code geben, wenn du ihn dan nnoch brauchst.



  • Mein Programm öffnet (bisher) keine Handels. Es soll extra für diesen Zweck ein Programm sein.

    @hack0r
    Am Codebeispiel bin ich interressiert.



  • so, bitte schön

    openfiles.c

    #include "openfiles.h"
    
    /*
     * GetNumOpenFiles - Returns the number of open files for a process.
     *
     * The function returns the number of open file handles for the specified
     *	process.
     *
     * @pid
     *	Identifier of the process to retrieve the number of open files for.
     *
     * @return
     *	The number of open files on success, -1 on error.
     *
     */
    int GetNumOpenFiles( DWORD pid ) {
    	ULONG *p, n, i, count = 0;
    	PSYSTEM_HANDLE_INFORMATION h;
    	HANDLE hProcess;
    	PFN_NtQuerySystemInformation NtQuerySystemInformation =
    		(PFN_NtQuerySystemInformation) GetProcAddress(LoadLibrary("NTDLL"),
    		"NtQuerySystemInformation");
    	PFN_NtQueryObject NtQueryObject = (PFN_NtQueryObject)
    		GetProcAddress(LoadLibrary("NTDLL"), "NtQueryObject");
    	if(!NtQuerySystemInformation || !NtQueryObject)
    		return -1;
    
    	if(!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid)))
    		return -1;
    
    	n = 0x1000;
    	p = malloc(sizeof(ULONG) * n);
    
    	while(NtQuerySystemInformation(SystemHandleInformation, p, n * sizeof(*p),
    		0) == STATUS_INFO_LENGTH_MISMATCH) {
    		free(p);
    		n = n * 2;
    		p = malloc(sizeof(ULONG) * n);
    	}
    
    	h = (PSYSTEM_HANDLE_INFORMATION)(p + 1);
    	for(i = 0; i < *p; i++) {
    		/* handle belongs to target process */
    		if(h[i].ProcessId == pid)
    			count++;
    	}
    	CloseHandle(hProcess);
    	free(p);
    	return count;
    }
    
    /*
     * GetOpenFiles - Retrieves a list of open files for a process.
     *
     * The function retrieves a list of files opened by the specified
     *	process.
     *
     * @pid
     *	Identifier of the process to retrieve the list of files for.
     *
     * @pFiles
     *	Pointer to an array of POPENFILE_T structures that will receive the
     *	information on the opened files.
     *
     * @pNumFiles
     *	Maximum number of files to retrieve.
     *
     * @return
     *	The function returns the number of entries in pFiles on success,
     *		-1 on failure.
     *
     */
    int GetOpenFiles( DWORD pid, POPENFILE_T pFiles, DWORD dwNumFiles ) {
    	ULONG *p, n, i, count = 0;
    	PSYSTEM_HANDLE_INFORMATION h;
    	HANDLE hProcess;
    	PFN_NtQuerySystemInformation NtQuerySystemInformation =
    		(PFN_NtQuerySystemInformation) GetProcAddress(LoadLibrary("NTDLL"),
    		"NtQuerySystemInformation");
    	PFN_NtQueryObject NtQueryObject = (PFN_NtQueryObject)
    		GetProcAddress(LoadLibrary("NTDLL"), "NtQueryObject");
    	if(!NtQuerySystemInformation || !NtQueryObject)
    		return -1;
    
    	if(!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid)))
    		return -1;
    
    	n = 0x1000;
    	p = malloc(sizeof(ULONG) * n);
    
    	while(NtQuerySystemInformation(SystemHandleInformation, p, n * sizeof(*p),
    		0) == STATUS_INFO_LENGTH_MISMATCH) {
    		free(p);
    		n = n * 2;
    		p = malloc(sizeof(ULONG) * n);
    	}
    
    	h = (PSYSTEM_HANDLE_INFORMATION)(p + 1);
    	for(i = 0; i < *p; i++) {
    		if(count >= dwNumFiles)
    			break;
    
    		/* handle belongs to target process */
    		if(h[i].ProcessId == pid) {
    			HANDLE hObject;
    			OBJECT_BASIC_INFORMATION obi;
    			OBJECT_NAME_INFORMATION *poni;
    
    			if(!DuplicateHandle(hProcess, (HANDLE)h[i].Handle, GetCurrentProcess(),
    				&hObject, 0, 0, DUPLICATE_SAME_ATTRIBUTES))
    				continue;
    
    			NtQueryObject(hObject, ObjectBasicInformation, &obi, sizeof(obi), NULL);
    
    			n = obi.NameInformationLength == 0 ? MAX_PATH * sizeof(WCHAR) :
    					obi.NameInformationLength;
    			poni = (POBJECT_NAME_INFORMATION)malloc(n);
    
    			NtQueryObject(hObject, ObjectNameInformation, poni, n, NULL);
    			/* convert from something like \Device\Harddisk0\some_file to dos drive
    				letter path */
    			if(DeviceToDosPath(poni->Name.Buffer, pFiles[count].szFileName,
    				sizeof(pFiles[count].szFileName))) {
    				pFiles[count].dwFlags = h[i].GrantedAccess;
    				count++;
    			}
    
    			CloseHandle(hObject);
    		}
    	}
    	CloseHandle(hProcess);
    	free(p);
    
    	return count;
    }
    
    /*
     * GetPIDsFromFile - Returns process identifiers of all processes that have
     *			currently opened target file.
     *
     * @lpFileName
     *	Name of the file to look up.
     *
     * @lpPIDs
     *	Pointer to an array of DWORDs that will receive the process identifiers.
     *
     * @dwNumPIDs
     *	Maximum number of entries to store in the buffer pointed to by lpPIDs.
     *
     * @return
     *	The function returns the actual number of entries in lpPIDs on success,
     *		-1 on failure.
     *
     */
    int GetPIDsFromFile( PTCHAR lpFileName, PDWORD lpPIDs, DWORD dwNumPIDs ) {
    	ULONG *p, n, i, count = 0;
    	PSYSTEM_HANDLE_INFORMATION h;
    	HANDLE hProcess;
    	PFN_NtQuerySystemInformation NtQuerySystemInformation =
    		(PFN_NtQuerySystemInformation) GetProcAddress(LoadLibrary("NTDLL"),
    		"NtQuerySystemInformation");
    	PFN_NtQueryObject NtQueryObject = (PFN_NtQueryObject)
    		GetProcAddress(LoadLibrary("NTDLL"), "NtQueryObject");
    	if(!NtQuerySystemInformation || !NtQueryObject)
    		return -1;
    
    	n = 0x1000;
    	p = malloc(sizeof(ULONG) * n);
    
    	while(NtQuerySystemInformation(SystemHandleInformation, p, n * sizeof(*p),
    		0) == STATUS_INFO_LENGTH_MISMATCH) {
    		free(p);
    		n = n * 2;
    		p = malloc(sizeof(ULONG) * n);
    	}
    
    	h = (PSYSTEM_HANDLE_INFORMATION)(p + 1);
    	for(i = 0; i < *p; i++) {
    		HANDLE hObject;
    		OBJECT_BASIC_INFORMATION obi;
    		OBJECT_NAME_INFORMATION *poni;
    		TCHAR szFileName[MAX_PATH];
    
    		if(count >= dwNumPIDs)
    			break;
    
    		if(!(hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, h[i].ProcessId)))
    			continue;
    
    		if(!DuplicateHandle(hProcess, (HANDLE)h[i].Handle, GetCurrentProcess(),
    			&hObject, 0, 0, DUPLICATE_SAME_ATTRIBUTES)) {
    			CloseHandle(hProcess);
    			continue;
    		}
    
    		CloseHandle(hProcess);
    		NtQueryObject(hObject, ObjectBasicInformation, &obi, sizeof(obi), NULL);
    
    		n = obi.NameInformationLength == 0 ? MAX_PATH * sizeof(WCHAR) :
    				obi.NameInformationLength;
    		poni = (POBJECT_NAME_INFORMATION)malloc(n);
    
    		NtQueryObject(hObject, ObjectNameInformation, poni, n, NULL);
    		if(DeviceToDosPath(poni->Name.Buffer, szFileName, sizeof(szFileName))) {
    			if(!_tcscmp(lpFileName, szFileName))
    				lpPIDs[count++] = h[i].ProcessId;
    		}
    
    		CloseHandle(hObject);
    	}
    
    	free(p);
    	return count;
    }
    
    /*
     * DeviceToDosPath - Converts Device Path to Dos Path.
     *
     */
    int DeviceToDosPath( PWCHAR lpDevice, PTCHAR lpDosPath, INT nSize ) {
    	int i;
    	DWORD dwDrives;
    	WCHAR szDev[MAX_PATH] = {0}, szRet[MAX_PATH], *p;
    
    	if(!lpDevice)
    		return 0;
    
    	/* extract device path */
    	if(wcsncmp(lpDevice, L"\\Device\\", wcslen(L"\\Device\\")))
    		return 0;
    
    	p = lpDevice + wcslen(L"\\Device\\");
    	while(*p != '\\') {
    		if(*p == 0)
    			return 0;
    		p++;
    	}
    	wcsncpy(szDev, lpDevice, p - lpDevice);
    
    	dwDrives = GetLogicalDrives();
    	for(i = 0; i < 32; i++) {
    		if((dwDrives >> i) & 0x01) {
    			WCHAR szDosDevice[MAX_PATH], szDrive[3] = L"A:";
    
    			szDrive[0] = 'A' + i;
    			QueryDosDeviceW(szDrive, szDosDevice, sizeof(szDosDevice));
    			if(!wcscmp(szDev, szDosDevice)) {
    				wcscpy(szRet, szDrive);
    				wcsncat(szRet, p, nSize);
    #ifndef _UNICODE
    				/* convert to single byte */
    				WideCharToMultiByte(CP_ACP, 0, szRet, wcslen(szRet) * sizeof(WCHAR),
    					lpDosPath, nSize, NULL, NULL);
    #else
    				wcscpy(lpDosPath, szRet);
    #endif
    			}
    		}
    	}
    	return 1;
    }
    
    /* example */
    #if 0
    int main(int argc, char *argv[]) {
    	DWORD dwPIDs[10];
    	/* open some file */
    	HANDLE hFile = CreateFile("C:\\WINDOWS\\win.ini", GENERIC_EXECUTE, 0, NULL,
    		OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    	/* get number of open files for this process */
    	DWORD dwNum = GetNumOpenFiles(GetCurrentProcessId()), i;
    	POPENFILE_T pFiles;
    
    	if(hFile == INVALID_HANDLE_VALUE) {
    		printf("Could not open C:\\WINDOWS\\win.ini\n");
    		return 0;
    	}
    
    	/* get a list of all files this process has currently opened */
    	pFiles = (POPENFILE_T)malloc(sizeof(OPENFILE_T) * dwNum);
    	dwNum = GetOpenFiles(GetCurrentProcessId(), pFiles, dwNum);
    
    	printf("Process %i has handles for following files:\n\n", GetCurrentProcessId());
    	for(i = 0; i < dwNum; i++)
    		printf("%s\n", pFiles[i].szFileName);
    	printf("\n");
    
    	/* get a list of processes that have currently opened C:\WINDOWS\win.ini */
    	dwNum = GetPIDsFromFile( _T("C:\\WINDOWS\\win.ini"), dwPIDs, sizeof(dwPIDs) / sizeof(dwPIDs[0]) );
    	printf("%i processes have currently opened \"C:\\WINDOWS\\win.ini\" :\n\n", dwNum);
    	for(i = 0; i < dwNum; i++)
    		printf("- %i\n", dwPIDs[i]);
    
    	free(pFiles);
    	CloseHandle(hFile);
    	return 0;
    }
    #endif
    

    openfiles.h

    #ifndef _OPENFILES_H_
    #define _OPENFILES_H_
    
    #include <Windows.h>
    #include <tchar.h>
    
    /************** public interface **************/
    
    typedef struct OPENFILE_S {
    	TCHAR szFileName[MAX_PATH];
    	DWORD dwFlags;
    } OPENFILE_T, *POPENFILE_T;
    
    /*
     * GetNumOpenFiles - Returns the number of open files for a process.
     *
     * The function returns the number of open file handles for the specified
     *	process.
     *
     * @pid
     *	Identifier of the process to retrieve the number of open files for.
     *
     * @return
     *	The number of open files on success, -1 on error.
     *
     */
    int GetNumOpenFiles( DWORD pid );
    
    /*
     * GetOpenFiles - Retrieves a list of open files for a process.
     *
     * The function retrieves a list of files opened by the specified process.
     *
     * @pid
     *	Identifier of the process to retrieve the list of files for.
     *
     * @pFiles
     *	Pointer to an array of POPENFILE_T structures that will receive the
     *	information on the opened files.
     *
     * @pNumFiles
     *	Maximum number of files to retrieve.
     *
     * @return
     *	The function returns 1 on success, -1 on failure.
     *
     */
    int GetOpenFiles( DWORD pid, POPENFILE_T pFiles, DWORD dwNumFiles );
    
    /*
     * GetPIDsFromFile - Returns process identifiers of all processes that have
     *			currently opened target file.
     *
     * @lpFileName
     *	Name of the file to look up.
     *
     * @lpPIDs
     *	Pointer to an array of DWORDs that will receive the process identifiers.
     *
     * @dwNumPIDs
     *	Maximum number of entries to store in the buffer pointed to by lpPIDs.
     *
     * @return
     *	The function returns the actual number of entries in lpPIDs on success,
     *		-1 on failure.
     *
     */
    int GetPIDsFromFile( PTCHAR lpFileName, PDWORD lpPIDs, DWORD dwNumPIDs );
    
    /************** private interface **************/
    #define NTSTATUS					DWORD
    #define SYSTEM_INFORMATION_CLASS	DWORD
    #define OBJECT_INFORMATION_CLASS	DWORD
    #define STATUS_INFO_LENGTH_MISMATCH 0xC0000004
    #define DUPLICATE_SAME_ATTRIBUTES	0x00000004
    
    #define SystemHandleInformation		0x10
    #define ObjectBasicInformation		0x00
    #define ObjectNameInformation		0x01
    #define ObjectTypeInformation		0x02
    
    typedef struct _UNICODE_STRING {
    	USHORT	Length;
    	USHORT	MaximumLength;
    	PWSTR	Buffer;
    } UNICODE_STRING, *PUNICODE_STRING;
    
    typedef struct _SYSTEM_HANDLE_INFORMATION {
    	ULONG		ProcessId;
    	UCHAR		ObjectTypeNumber;
    	UCHAR		Flags;
    	USHORT		Handle;
    	PVOID		Object;
    	ACCESS_MASK	GrantedAccess;
    } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
    
    typedef struct _OBJECT_BASIC_INFORMATION {
    	ULONG			Attributes;
    	ACCESS_MASK		DesiredAccess;
    	ULONG			HandleCount;
    	ULONG			ReferenceCount;
    	ULONG			PagedPoolUsage;
    	ULONG			NonPagedPoolUsage;
    	ULONG			Reserved[3];
    	ULONG			NameInformationLength;
    	ULONG			TypeInformationLength;
    	ULONG			SecurityDescriptorLength;
    	LARGE_INTEGER	CreationTime;
    } OBJECT_BASIC_INFORMATION, *POBJECT_BASIC_INFORMATION;
    
    typedef struct _OBJECT_TYPE_INFORMATION {
    	UNICODE_STRING	TypeName;
    	ULONG			TotalNumberOfHandles;
    	ULONG			TotalNumberOfObjects;
    	WCHAR			Unused1[8];
    	ULONG			HighWaterNumberOfHandles;
    	ULONG			HighWaterNumberOfObjects;
    	WCHAR			Unused2[8];
    	ACCESS_MASK		InvalidAttributes;
    	GENERIC_MAPPING GenericMapping;
    	ACCESS_MASK		ValidAttributes;
    	BOOLEAN			SecurityRequired;
    	BOOLEAN			MaintainHandleCount;
    	USHORT			MaintainTypeList;
    	DWORD			PoolType;
    	ULONG			DefaultPagedPoolCharge;
    	ULONG			DefaultNonPagedPoolCharge;
    } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;
    
    typedef struct _OBJECT_NAME_INFORMATION {
    	UNICODE_STRING	Name;
    	WCHAR			NameBuffer[0];
    } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
    
    typedef NTSTATUS (WINAPI *PFN_NtQuerySystemInformation)( SYSTEM_INFORMATION_CLASS,
    														PVOID, ULONG, PULONG );
    typedef NTSTATUS (WINAPI *PFN_NtQueryObject)( HANDLE, OBJECT_INFORMATION_CLASS, PVOID,
    									  ULONG, PULONG);
    int DeviceToDosPath( PWCHAR lpDevice, PTCHAR lpDosPath, INT nSize );
    #endif /* _OPENFILES_H_ */
    


  • Erst mal danke für ein so ausführiches Codebeispiel.

    Mir ist es gelungen die Funktionen in ein BCB Projekt einzubetten.

    Leider Bekomme ich "nur" diese Ausgaben:

    Process xxx has handles for following files:
    0 processes have currently opened C:\test.txt

    und das obwohl mein Programm mehrere Dateien offen hat.
    Öffne ich die test-Datei in meinem Programm (oder in einem anderen) dann scheitert der Aufruf mit "Could not open..."

    Gibt es da noch einen Lösungsweg?


Anmelden zum Antworten