接之前的一篇文章http://blog.youkuaiyun.com/bloonfield/article/details/6780918
在制作软件的安装卸载时,有时一些动态库被某些进程占用,不可以直接删除,需要先将占用这个动态库的进程结束。怎么才能知道动态库被哪个进程占用呢?
开始的思路是这样的,在DOS里面有这样一个命令“tasklist /m XXX.dll”这个命令会列出所有占用了XXX.dll的进程。OK,原理简单。只要能得到DOS命令的返回结果就OK了。
。。。
这种方法确实可以在XP中实现,可是在win2K的系统上就不行了,因为“taskllist”这个命令是在XP及其之后的系统上才加上的。而且如果程序本身是32位的,在64位的机器上也是不行的,需要重新编译一个64位的程序。不然用“tasklist”得到的结果是不完整的。只能说,这种方法弱爆了。
所以,最后用了另一种方法,通过进程快照。
先要遍历所有的进程,然后对每个进程遍历其占用的模块,从中查找指定的dll。OK,废话不多说,代码如下:
//结构体,用来存放进程的相关信息
typedef struct sPROCESSINFO
{
char caExeName[100]; //进程名
char caWindowName[MAX_PATH]; //对应的窗体名称
DWORD dwProcessId; //进程ID
HWND hProWinHandle; //窗体句柄
}PROCESSINFO, *LPPROCESSINFO;
void GetDllAttach(IN char * pcDllName, //指定的dll名称
OUT sPROCESSINFO * psExeInfo,//返回的进程
OUT int * piExeNum) //进程个数
{
BOOL bModule = FALSE;
BOOL bProcess = FALSE;
HANDLE hSnapPro;
PROCESSENTRY32 sPro;
MODULEENTRY32 sModule;
int iNum = 0;
WCHAR wcaDllName[0x100] = {0};
memset(&sPro, 0, sizeof(sPro));
memset(&sModule, 0, sizeof(sModule));
MultiByteToWideChar(CP_ACP, 0, pcDllName, -1, wcaDllName, sizeof(wcaDllName)); //转换到Unicode编码
//得到进程快照
hSnapPro = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
sPro.dwSize = sizeof(sPro);
sModule.dwSize = sizeof(sModule);
//得到第一个进程信息,之后遍历所有进程
bProcess = Process32First(hSnapPro, &sPro);
while (bProcess)
{ //得到当前进程的模块快照
HANDLE hSnapModule = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, sPro.th32ProcessID);
//遍历所有模块,看是否有指定名称的DLL
bModule = Module32First(hSnapModule, &sModule);
while (bModule)
{
if (memicmp((char*)sModule.szModule, (char*)wcaDllName, sizeof(wcaDllName)) == 0)
{
WideCharToMultiByte(CP_ACP, 0, sPro.szExeFile, -1, psExeInfo[iNum].caExeName, sizeof(psExeInfo[iNum].caExeName), NULL, NULL);
psExeInfo[iNum++].dwProcessId = sPro.th32ProcessID;
break;
}
bModule = Module32Next(hSnapModule, &sModule);
}
bProcess = Process32Next(hSnapPro, &sPro);
CloseHandle(hSnapModule);
}
CloseHandle(hSnapPro);
*piExeNum = iNum;
}
另外,多说一句,上面这个函数因为放在了一个定义了UNICODE的库里,所以中间有宽字符的转换,如果不用支持宽字符,可将其去掉。