如题

比如我们删除某个文件中,如果文件被占用的话是删除不掉的,那么替换操作啥都不行
在这里插入图片描述

故要实现这个提前检测有哪些被占用了, 已经被哪个进程占用的.
我这个需求就是检测dll被哪个进程占用的

总结了3种解决方案

1. 通过拍进程快照,然后遍历每个进程上面dll module, 然后dll 名字匹配的形式.

这里引发了一个问题, 我这个进程是32位的,然后我的dll 有64 和32位的, 拍进程快照的方式
32位进程 只能读32位进程的dll模块信息
在这里插入图片描述
当遍历的目标进程是64位时 会lasterror 为299 我看了一下,是进程位数不匹配.

然后我看了一下 procexp_Chn.exe 这个工具我打开的是32位的 为啥电脑上的32和64位的进程模块信息都能
加载出来呢?? 我仔细看了一下 原来你打开32位的进程,它会启动个64位的后台进程把相关信息传递给32位的进程.

这是我打开的
在这里插入图片描述
这是它自己开的
在这里插入图片描述
行了 这个方案不行.

第二种方案 通过 命令行 tasklist /m dllName

这个 /m 参数就是找这个dll 被哪个进程占用了
在这里插入图片描述
这个简单啊, 但是遇到个很奇怪奇怪的问题
我通过winapi 管道的形式, QProcess 的形式,打开 cmd 执行这个命令行都会获取不到结果, system("")
也不行,会阻塞死控制台
试了很多种 都不行, 感觉不是代码层面的问题了, 别人用我的代码都能正常执行, 在我机器会出问题 卡住
我ping baidu 啥的都可以 tasklist 也可,唯独加 /m 参数出问题
折腾一下午 还是不行,要抑郁了 又找了新方案

第三种方案

看的这个 MSDN 上的 How do I find out which process has a file open?
链接如下
https://devblogs.microsoft.com/oldnewthing/?p=8283

然后改了一下 发现很好使, 代码贴一下.

#include <windows.h>
#include <RestartManager.h>
#include <stdio.h>
#pragma comment(lib, "Rstrtmgr.lib")

int test()
{
	DWORD dwSession = 0;
	WCHAR szSessionKey[CCH_RM_SESSION_KEY + 1];
	DWORD dwError = RmStartSession(&dwSession, 0, szSessionKey);
	if (dwError != ERROR_SUCCESS)
	{
		wprintf(L"RmStartSession Start Error, ErrorCode: %d\n", dwError);
		getchar();
	}
	//你的dll 绝对路径
	PCWSTR pszFile = L"C:/Users/info/AppData/Local/xxx/SWVirtualCam_x64.dll";
	dwError = RmRegisterResources(dwSession, 1, &pszFile, 0, NULL, 0, NULL);
	if (dwError != ERROR_SUCCESS)
	{
		wprintf(L"RmRegisterResources for File %ls Error, ErrorCode: %d\n", pszFile, dwError);
		getchar();
	}

	DWORD dwReason = 0;
	UINT i = 0;
	UINT nProcInfoNeeded = 0;
	UINT nProcInfo = 10;
	RM_PROCESS_INFO rgpi[10];
	memset(rgpi, 0, sizeof(rgpi));
	dwError = RmGetList(dwSession, &nProcInfoNeeded, &nProcInfo, rgpi, &dwReason);
	if (dwError != ERROR_SUCCESS)
	{
		wprintf(L"RmGetList Error, ErrorCode: %d\n", dwError);
		getchar();
	}

	if (nProcInfoNeeded == 0)
	{
		wprintf(L"This file is not in locked!");
		getchar();
	}

	for (i = 0; i < nProcInfo; i++)
	{
		wprintf(L"The locked file: %ls\n\n", pszFile);
		wprintf(L"Who lock this file:\n");
		wprintf(L"Name: \t%ls\n", rgpi[i].strAppName);
		wprintf(L"ID  : \t%d\n", rgpi[i].Process.dwProcessId);


		HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, rgpi[i].Process.dwProcessId);

		if (hProcess)
		{
			// 这个if语句是为了判断是否是某个程序的某个进程(因为一个程序可以有多个进程)
			FILETIME ftCreate, ftExit, ftKernel, ftUser;
			if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)
				&& CompareFileTime(&rgpi[i].Process.ProcessStartTime, &ftCreate) == 0)
			{
				WCHAR sz[MAX_PATH] = { 0 };
				DWORD ProcPathMaxLength = MAX_PATH;
				if (QueryFullProcessImageNameW(hProcess, 0, sz, &ProcPathMaxLength) && ProcPathMaxLength <= MAX_PATH)
				{
					wprintf(L"Path: \t%ls\n", sz);
				}
			}

			wprintf(L"\n");
			CloseHandle(hProcess);
		}
	}

	RmEndSession(dwSession);

	getchar();

	return 0;
}

这个demo 代码检测没有问题, 原理就是通过 windows 的重启管理器的 文件引用计数来的
基于demo代码 封装改一下,就满足需求了

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐