• Visual C++ 查看文件被哪个进程占用


    参考于: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;
    }
  • 相关阅读:
    WebAssembly API & MDN All In One
    Apple iPhone 14 Pro 药丸设计看不懂,药丸上面那条屏幕缝隙完全没有用处呀?
    API 调试工具 All In One
    macOS Time Machine All In One
    使用 macOS 输入多个空格,会自动添加一个点 bug All In One
    手把手的教你如何使用 Vite 搭建一个 React UI 组件库 All In One
    LeetCode 两数相加算法题解 All In One
    如何把 iPad 作为 Mac 扩展屏幕使用 All In One
    【DEMO】【C/C++】最简单的一种回调函数
    Qt中cvMat与QImage,QPixmap的转换
  • 原文地址:https://www.cnblogs.com/suxia/p/13220337.html
Copyright © 2020-2023  润新知