zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    微软推出的免费新书《Introducing Microsoft SQL Server 2012》
    关于Installshield中Ie8\Ie9\SQL Server 2008 R2 Native Client等Prq文件在线下载地址
    PowerDesigner批量生成日期型、中文字符型、数字型测试数据
    在服务器上使用第三方独立组件对Word/Excel进行编程
    文明源自谎言
    中文写程序,何陋之有?
    在线网摘收藏?让Google来吧!
    下载文件时根据MIME类型自动判断保存文件的扩展名
    谨慎注意WebBrowser控件的DocumentCompleted事件
    你的命运谁攥着?
  • 原文地址:https://www.cnblogs.com/suxia/p/13220337.html
Copyright © 2011-2022 走看看