参考于:https://blog.csdn.net/u012108436/article/details/72688310
有别于我之前写的文章,这个方法对DLL貌似并不适用,猜测Windows上dll并不算是文件句柄,没办法被NtQuerySystemInformation识别到
之前的文章:https://www.cnblogs.com/suxia/p/13163094.html
底下是使用方法:
查看文件是否其他进程占用
METHOD:
主要使用BOOL FindFileHandle(LPCTSTR lpName, vector<ncFileHandle>& handles); 底下定义tstring类似于wstring,说实在我对这块不清楚,可能为了配合WINAPI才define这个数据类型,毕竟底下很多API和数据类型和枚举变量都被Windows藏起来了
PARAMETER:
LPCTSTR lpName:输入值,文件的完整地址
vector<ncFileHandle>& handles:输出值,存储着占用文件的进程详细信息的容器
RETURN:
成功为1,失败为0
WARNING:
函数要遍历所有文件句柄,找出与文件路径匹配的文件句柄,并通过文件句柄找到占用他的进程句柄,所以耗时很久,常规要一秒到两秒左右,谨慎使用
#include "stdafx.h" #include <windows.h> #include <tchar.h> #include <shlwapi.h> #include <stdio.h> #include <tchar.h> #include <atlbase.h> #include <vector> #include <map> #include <iostream> #include <string> #include <winternl.h> #include <psapi.h> #pragma comment(lib, "psapi.lib") #pragma comment(lib, "shlwapi") using namespace std; typedef std::basic_string<TCHAR, std::char_traits<TCHAR>, std::allocator<TCHAR>> tstring; #ifndef _countof #define _countof(array) (sizeof(array)/sizeof((array)[0])) #endif EXTERN_C BOOL GetFilePathFromHandleW(HANDLE hFile, LPWSTR lpszPath, UINT cchMax); EXTERN_C BOOL GetFilePathFromHandleA(HANDLE hFile, LPSTR lpszPath, UINT cchMax); #ifdef UNICODE #define GetFilePathFromHandle GetFilePathFromHandleW #else #define GetFilePathFromHandle GetFilePathFromHandleA #endif #define NT_SUCCESS(status) (status == (NTSTATUS)0x00000000L) #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) #define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L) #define SystemHandleInformation ((SYSTEM_INFORMATION_CLASS)16) // NTQUERYOBJECT typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; WCHAR NameBuffer[1]; } OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION; //winternl.h中以定义,微软未放出134的定义,需自己手动定义 typedef enum _OBJECT_INFORMATION_CLASS_SELFDEFINE { //ObjectBasicInformation, ObjectNameInformation=1, //ObjectTypeInformation, ObjectAllInformation=3, ObjectDataInformation=4 } OBJECT_INFORMATION_CLASS_SELFDEFINE, *POBJECT_INFORMATION_CLASS_SELFDEFINE; typedef NTSTATUS(WINAPI *NTQUERYOBJECT)( _In_opt_ HANDLE Handle, _In_ OBJECT_INFORMATION_CLASS_SELFDEFINE ObjectInformationClass, _Out_opt_ PVOID ObjectInformation, _In_ ULONG ObjectInformationLength, _Out_opt_ PULONG ReturnLength); // NTQUERYSYSTEMINFORMATION typedef struct _SYSTEM_HANDLE { DWORD dwProcessId; BYTE bObjectType; BYTE bFlags; WORD wValue; PVOID pAddress; DWORD GrantedAccess; } SYSTEM_HANDLE, *PSYSTEM_HANDLE; typedef struct _SYSTEM_HANDLE_INFORMATION { DWORD dwCount; SYSTEM_HANDLE Handles[1]; } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; typedef NTSTATUS(WINAPI *NTQUERYSYSTEMINFORMATION)( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL); //typedef struct _IO_STATUS_BLOCK { // LONG Status; // LONG Information; //} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; typedef struct _FILE_NAME_INFORMATION { ULONG FileNameLength; WCHAR FileName[MAX_PATH]; } FILE_NAME_INFORMATION; __declspec(dllimport) LONG __stdcall ZwQueryInformationFile( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG FileInformationLength, IN ULONG FileInformationClass ); typedef LONG(__stdcall * PFN_ZwQueryInformationFile) ( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG FileInformationLength, IN ULONG FileInformationClass ); // // NtQueryInformationFile // #define FileNameInformation ((FILE_INFORMATION_CLASS)9) // typedef struct _FILE_NAME_INFORMATION { // ULONG FileNameLength; // WCHAR FileName[1]; // } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION; typedef NTSTATUS(WINAPI *NTQUERYINFORMATIONFILE)( IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass); // typedef struct _CLIENT_ID { // HANDLE UniqueProcess; // HANDLE UniqueThread; // } CLIENT_ID, *PCLIENT_ID; // ncScopedHandle class ncScopedHandle { ncScopedHandle(const ncScopedHandle&); ncScopedHandle& operator=(const ncScopedHandle&); public: ncScopedHandle(HANDLE handle) : _handle(handle) { } ~ncScopedHandle() { if (_handle != NULL) { CloseHandle(_handle); } } operator HANDLE() const { return _handle; } PHANDLE operator& () { return &_handle; } void operator=(HANDLE handle) { if (_handle != NULL) { CloseHandle(_handle); } _handle = handle; } private: HANDLE _handle; }; // ncFileHandle struct ncFileHandle { SYSTEM_HANDLE _handle;//占用文件的进程句柄详细信息 tstring _filePath;//文件的完整路径,tstring等同于wstring tstring _path;//占用进程的程序磁盘位置 ncFileHandle(SYSTEM_HANDLE handle, const tstring& filePath, const tstring& path) : _handle(handle) , _filePath(filePath) , _path(path) { } }; //根据文件句柄获取文件所在磁盘名 EXTERN_C BOOL GetVolumeNameByHandle(HANDLE hFile, LPWSTR szVolumeName, UINT cchMax) { BOOL bResult = FALSE; WCHAR szBuf[500] = { 0 }; WCHAR * pIter = szBuf; int i = 0; BY_HANDLE_FILE_INFORMATION stFileInfo = { 0 }; do { if (FALSE == GetFileInformationByHandle(hFile, &stFileInfo)) { break; } if (0 == GetLogicalDriveStringsW(_countof(szBuf), szBuf)) { break; } for (; pIter; pIter += 4) { DWORD dwVolumeSerialNumber = 0; if (GetVolumeInformationW(pIter, NULL, 0, &dwVolumeSerialNumber, NULL, NULL, NULL, 0)) { if (dwVolumeSerialNumber == stFileInfo.dwVolumeSerialNumber) { lstrcpynW(szVolumeName, pIter, cchMax); bResult = TRUE; break; } } } } while (FALSE); return bResult; } EXTERN_C BOOL GetFilePathFromHandleW(HANDLE hFile, LPWSTR lpszPath, UINT cchMax) { BOOL bResult = FALSE; WCHAR szValue[MAX_PATH] = { 0 }; IO_STATUS_BLOCK isb = { 0 }; FILE_NAME_INFORMATION fni = { 0 }; HMODULE hNtDLL = NULL; PFN_ZwQueryInformationFile pfn_ZwQueryInformationFile = NULL; do { if (INVALID_HANDLE_VALUE == hFile || NULL == lpszPath || 0 == cchMax) { break; } hNtDLL = LoadLibraryW(L"ntdll.dll"); if (hNtDLL == NULL) { break; } pfn_ZwQueryInformationFile = (PFN_ZwQueryInformationFile)GetProcAddress(hNtDLL, "ZwQueryInformationFile"); if (NULL == pfn_ZwQueryInformationFile) { break; } // 9 == FileNameInformation if (0 != pfn_ZwQueryInformationFile(hFile, &isb, &fni, sizeof(fni), 9)) { break; } if (FALSE == GetVolumeNameByHandle(hFile, szValue, _countof(szValue))) { break; } PathAppendW(szValue, fni.FileName); lstrcpynW(lpszPath, szValue, cchMax); bResult = TRUE; } while (FALSE); return bResult; } EXTERN_C BOOL GetFilePathFromHandleA(HANDLE hFile, LPSTR lpszPath, UINT cchMax) { BOOL bResult = FALSE; WCHAR szTmep[MAX_PATH] = { 0 }; do { if (INVALID_HANDLE_VALUE == hFile || NULL == lpszPath || 0 == cchMax) { break; } if (FALSE == GetFilePathFromHandleW(hFile, szTmep, _countof(szTmep))) { break; } if (0 == WideCharToMultiByte(CP_ACP, 0, szTmep, lstrlenW(szTmep), lpszPath, cchMax, NULL, NULL)) { break; } bResult = TRUE; } while (FALSE); return bResult; } // GetDeviceDriveMap void GetDeviceDriveMap(std::map<tstring, tstring>& mapDeviceDrive) { TCHAR szDrives[512]; if (!GetLogicalDriveStrings(_countof(szDrives) - 1, szDrives)) { return; } TCHAR* lpDrives = szDrives; TCHAR szDevice[MAX_PATH]; TCHAR szDrive[3] = _T(" :"); do { *szDrive = *lpDrives; if (QueryDosDevice(szDrive, szDevice, MAX_PATH)) { mapDeviceDrive[szDevice] = szDrive; } while (*lpDrives++); } while (*lpDrives); } // DevicePathToDrivePath BOOL DevicePathToDrivePath(tstring& path) { static std::map<tstring, tstring> mapDeviceDrive; if (mapDeviceDrive.empty()) { GetDeviceDriveMap(mapDeviceDrive); } for (std::map<tstring, tstring>::const_iterator it = mapDeviceDrive.begin(); it != mapDeviceDrive.end(); ++it) { size_t nLength = it->first.length(); if (_tcsnicmp(it->first.c_str(), path.c_str(), nLength) == 0) { path.replace(0, nLength, it->second); return TRUE; } } return FALSE; } // GetHandlePath BOOL GetHandlePath(HANDLE handle, tstring& path) { static NTQUERYOBJECT fpNtQueryObject = (NTQUERYOBJECT)GetProcAddress(GetModuleHandle(_T("ntdll")), "NtQueryObject"); if (fpNtQueryObject == NULL) { return FALSE; } DWORD dwLength = 0; OBJECT_NAME_INFORMATION info; NTSTATUS status = fpNtQueryObject(handle, ObjectNameInformation, &info, sizeof(info), &dwLength); if (status != STATUS_BUFFER_OVERFLOW) { return FALSE; } POBJECT_NAME_INFORMATION pInfo = (POBJECT_NAME_INFORMATION)malloc(dwLength); while (true) { status = fpNtQueryObject(handle, ObjectNameInformation, pInfo, dwLength, &dwLength); if (status != STATUS_BUFFER_OVERFLOW) { break; } pInfo = (POBJECT_NAME_INFORMATION)realloc(pInfo, dwLength); } BOOL bRes = FALSE; if (NT_SUCCESS(status)) { path = pInfo->Name.Buffer; bRes = DevicePathToDrivePath(path); } free(pInfo); return bRes; } // GetSystemHandleInfo PSYSTEM_HANDLE_INFORMATION GetSystemHandleInfo() { static NTQUERYSYSTEMINFORMATION fpNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle(_T("ntdll")), "NtQuerySystemInformation"); if (fpNtQuerySystemInformation == NULL) { return NULL; } DWORD dwLength = 0; SYSTEM_HANDLE_INFORMATION shi; NTSTATUS status = fpNtQuerySystemInformation(SystemHandleInformation, &shi, sizeof(shi), &dwLength); if (status != STATUS_INFO_LENGTH_MISMATCH) { return NULL; } PSYSTEM_HANDLE_INFORMATION pshi = (PSYSTEM_HANDLE_INFORMATION)malloc(dwLength); while (true) { status = fpNtQuerySystemInformation(SystemHandleInformation, pshi, dwLength, &dwLength); if (status != STATUS_INFO_LENGTH_MISMATCH) { break; } pshi = (PSYSTEM_HANDLE_INFORMATION)realloc(pshi, dwLength); } if (!NT_SUCCESS(status)) { free(pshi); pshi = NULL; } return pshi; } // // 检测指定句柄是否可能导致NtQueryObject卡死: // 1.注意必须使用NtQueryInformationFile而不是NtQueryObject进行检测,否则可能导致WinXP系统 // 下进程死锁而无法结束。 // void CheckBlockThreadFunc(void* param) { static NTQUERYINFORMATIONFILE fpNtQueryInformationFile = (NTQUERYINFORMATIONFILE)GetProcAddress(GetModuleHandle(_T("ntdll")), "NtQueryInformationFile"); if (fpNtQueryInformationFile != NULL) { BYTE buf[1024]; IO_STATUS_BLOCK ioStatus; fpNtQueryInformationFile((HANDLE)param, &ioStatus, buf, 1024, FileNameInformation); } } // IsBlockingHandle BOOL IsBlockingHandle(HANDLE handle) { HANDLE hThread = (HANDLE)_beginthread(CheckBlockThreadFunc, 0, (void*)handle); if (WaitForSingleObject(hThread, 100) != WAIT_TIMEOUT) { return FALSE; } TerminateThread(hThread, 0); return TRUE; } // FindFileHandle BOOL FindFileHandle(LPCTSTR lpName, vector<ncFileHandle>& handles) { handles.clear(); if (lpName == NULL) { return FALSE; } // 打开“NUL”文件以便后续获取文件句柄类型值。 ncScopedHandle hTempFile = CreateFile(_T("NUL"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); if (hTempFile == NULL) { return FALSE; } // 获取当前系统中所有的句柄信息。 PSYSTEM_HANDLE_INFORMATION pshi = GetSystemHandleInfo(); if (pshi == NULL) { return FALSE; } // 查询当前系统的文件句柄类型值。 BYTE nFileType = 0; DWORD dwCrtPid = GetCurrentProcessId(); for (DWORD i = 0; i < pshi->dwCount; ++i) { if (pshi->Handles[i].dwProcessId == dwCrtPid && hTempFile == (HANDLE)pshi->Handles[i].wValue) { nFileType = pshi->Handles[i].bObjectType; break; } } HANDLE hCrtProc = GetCurrentProcess(); for (DWORD i = 0; i < pshi->dwCount; ++i) { // 过滤掉非文件类型的句柄。 if (pshi->Handles[i].bObjectType != nFileType) { continue; } // 将上述句柄复制到当前进程中。 ncScopedHandle handle = NULL; ncScopedHandle hProc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pshi->Handles[i].dwProcessId); if (hProc == NULL || !DuplicateHandle(hProc, (HANDLE)pshi->Handles[i].wValue, hCrtProc, &handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { continue; } // 过滤掉会导致NtQueryObject卡死的句柄(如管道等)。 if (IsBlockingHandle(handle)) { continue; } // 获取句柄对应的文件路径并进行匹配检查。 tstring filePath; if (GetHandlePath(handle, filePath) && filePath.find(lpName) != tstring::npos) { ncScopedHandle hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, pshi->Handles[i].dwProcessId); TCHAR szProcName[MAX_PATH]; GetProcessImageFileName(hProcess, szProcName, MAX_PATH); tstring path(szProcName); DevicePathToDrivePath(path); ncFileHandle fh(pshi->Handles[i], filePath, path); handles.push_back(fh); } } free(pshi); return TRUE; } // BOOL CloseHandleEx (HANDLE handle, DWORD dwPid) // { // if (GetCurrentProcessId () == dwPid) // return CloseHandle (handle); // // ncScopedHandle hProcess = OpenProcess (PROCESS_DUP_HANDLE, FALSE, dwPid); // if (hProcess == NULL) // return FALSE; // // return DuplicateHandle (hProcess, handle, GetCurrentProcess (), NULL, 0, FALSE, DUPLICATE_CLOSE_SOURCE); // } // main int _tmain(int argc, _TCHAR* argv[]) { tstring path(_T("D:\\dev\\YozoUCloud\\Debug\\x64\\YozoBridge64.dll")); vector<ncFileHandle> vecHandles; if (!FindFileHandle(path.c_str(), vecHandles)) { return -1; } else { wcout.imbue(locale("chs")); for (int i = 0; i < vecHandles.size(); i++) { wcout << vecHandles[i]._filePath.c_str() << " is in using by " << vecHandles[i]._path.c_str() << endl;; } } system("pause"); return 0; }