char chFileName[MAX_PATH] = {0}; GetModuleFileNameEx = (funGetModuleFileNameExA)GetProcAddress ...
164上位机VC MFC强制删除已打开文件
功能展示
大家肯定都有想删除文件,却被提示无法删除的经历,这是因为文件正在被其他程序打开使用中,我们当前例程实现强制删除文件功能,选择强制删除可删除已经打开的文件,效果如图; 要点提示 文件的删除可以用函数DeleteFile()但如果文件已经打开就会删除失败,这时我们得强制关闭打开文件的进行;
进程的强制关闭 比较繁琐 ,主要思路为:1.列举系统运行的进程;2. 列举系统所有进程打开的全部文件句柄3.逐一获取文件句柄的文件名与要删除的文件名对比,再进行相应操作 实现功能 1.新建基于对话框的应用程序 2.拖拽一编辑框ID为IDC_EDIT1,用于显示要删除文件的路径; 拖拽按钮<选择要删除文件><删除已选择文件>,选择框控件<强制删除>ID改为IDC_CHECK1,分别实现其相应功能; 3.添加两变量private://成员变量 CList<SYSTEM_HANDLE, SYSTEM_HANDLE&>m_FileHandles;//记录文件句柄 CMap< DWORD, DWORD&, SYSTEM_PROCESS_INFORMATION*,SYSTEM_PROCESS_INFORMATION*> m_SysProcesses;//记录系统当前运行的进程信息 再添加两变量所用到的头文件与自定义结构体 - #include <afxtempl.h> typedef struct _UNICODE_STRING
- {WORD Length;WORD MaximumLength;PWSTR Buffer;
- } UNICODE_STRING;
- typedef struct _VM_COUNTERS
- {
- DWORD PeakVirtualSize;
- DWORD VirtualSize;
- DWORD PageFaultCount;
- DWORD PeakWorkingSetSize;
- DWORD WorkingSetSize;
- DWORD QuotaPeakPagedPoolUsage;
- DWORD QuotaPagedPoolUsage;
- DWORD QuotaPeakNonPagedPoolUsage;
- DWORD QuotaNonPagedPoolUsage;
- DWORD PagefileUsage;
- DWORD PeakPagefileUsage;} VM_COUNTERS;
复制代码- typedef struct _SYSTEM_THREAD
- {
- DWORD u1;
- DWORD u2;
- DWORD u3;
- DWORD u4;
- DWORD ProcessId;
- DWORD ThreadId;
- DWORD dPriority;
- DWORD dBasePriority;
- DWORD dContextSwitches;
- DWORD dThreadState; // 2=running, 5=waiting
- DWORD WaitReason;
- DWORD u5;
- DWORD u6;
- DWORD u7;
- DWORD u8;
- DWORD u9;
- } SYSTEM_THREAD;
- typedef struct _SYSTEM_PROCESS_INFORMATION
- {
- DWORD dNext;
- DWORD dThreadCount;
- DWORD dReserved01;
- DWORD dReserved02;
- DWORD dReserved03;
- DWORD dReserved04;
- DWORD dReserved05;
- DWORD dReserved06;
- LARGE_INTEGER qCreateTime;
- LARGE_INTEGER qUserTime;
- LARGE_INTEGER qKernelTime;
- UNICODE_STRING usName;
- DWORD BasePriority;
- DWORD dUniqueProcessId;
- DWORD dInheritedFromUniqueProcessId;
- DWORD dHandleCount;
- DWORD dReserved07;
- DWORD dReserved08;
- VM_COUNTERS VmCounters;
-
复制代码- DWORD dCommitCharge;
- SYSTEM_THREAD Threads[1];
- } SYSTEM_PROCESS_INFORMATION;
- typedef struct _SYSTEM_HANDLE//定义系统句柄结构
- {
- DWORD ProcessID;
- WORD HandleType;
- WORD HandleNumber;
- DWORD KernelAddress;
- DWORD Flags;
- } SYSTEM_HANDLE;
- typedef struct _SYSTEM_HANDLE_INFORMATION
- {
- DWORD Count;
- SYSTEM_HANDLE Handles[1];
- } SYSTEM_HANDLE_INFORMATION;
- 4.例程用到了外部的函数,所以得动态加载外部函自定些变量;
- 数//定义外部函数
- typedef DWORD( WINAPI *funGetModuleFileNameExA)( HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize);
- typedef DWORD (WINAPI *PNtQuerySystemInformation)( DWORD, VOID*, DWORD, ULONG* );
- typedef DWORD (WINAPI *PNtQueryObject)( HANDLE, DWORD, VOID*, DWORD, VOID* );
- 再添加这些函数的变量
- funGetModuleFileNameExA GetModuleFileNameEx;
- PNtQuerySystemInformation NtQuerySystemInformation;//外部函数
- PNtQueryObject NtQueryObject;//外部函数
- 并在初始化函数OnInitDialog()中时动态加载
- //外部函数获取
- NtQuerySystemInformation = (PNtQuerySystemInformation)GetProcAddress(GetModuleHandle(_T("ntdll.dll")),_T("NtQuerySystemInformation"));
- NtQueryObject = (PNtQueryObject)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), _T("NtQueryObject"));
- 5,添加几个成员函数,再实现两个按钮控件功能
- private://成员函数
- void EnumRunningProc();
- void EnumProcessOpenedFile();
- BOOL GetDiviceName(LPCTSTR lpDosName, CString& szDiviceName);
- BOOL CloseFileHandle(DWORD dwProcessID, HANDLE hFile);
复制代码- 5.函数实体部分过长,可下载例程观看 加载要删除的文件,及文件删除操作,这两个按钮的函数部分为
- void CGkbc8Dlg::OnChoose()
- {
- CFileDialog Dlg(TRUE, "", "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "所有文件|*.*||");
- if (Dlg.DoModal() == IDOK)
- SetDlgItemText(IDC_EDIT1,Dlg.GetPathName());
- }
- void CGkbc8Dlg::OnDelete()
- {
- CString sFileName;
- GetDlgItemText(IDC_EDIT1,sFileName);
- if(sFileName.IsEmpty()) return; //空返回;
- if (MessageBox("确实要删除文件吗?", "提示", MB_YESNO)==IDNO) return;//不删除返回;
- BOOL bDeleted = DeleteFile(sFileName);//删除文件
- if (bDeleted)
- {
- SetDlgItemText(IDC_EDIT1,"");
- MessageBox("删除成功!");
- return;
- }
-
- int nCheck = ((CButton*)GetDlgItem(IDC_CHECK1))->GetCheck();//是否选中强制删除
- if(!nCheck)//没选中强制删除
- {
- MessageBox("无法删除文件!");
- return;
- }
- //<> 强制删除部分
- EnumRunningProc();//列举运行中的进程
- EnumProcessOpenedFile();//列举进程打开的文件句柄
- BOOL bFindFile = FALSE; //发现文件标识
- DWORD dwCurProcID = GetCurrentProcessId();
- HANDLE hFile; //文件句柄
- UCHAR FileNames[MAX_PATH];
- CString sDiviceName;
- GetDiviceName(sFileName, sDiviceName);
复制代码- for (POSITION pos = m_FileHandles.GetHeadPosition(); pos != NULL;)
- {
- SYSTEM_HANDLE& fileHandle = m_FileHandles.GetNext(pos);
- SYSTEM_PROCESS_INFORMATION* pProcInfo = NULL;
- BOOL bFindRet = m_SysProcesses.Lookup(fileHandle.ProcessID, pProcInfo);//在进程中查找句柄
- if (!bFindRet) continue;
- hFile = (HANDLE)fileHandle.HandleNumber;
- if (dwCurProcID != fileHandle.ProcessID)
- {
- HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, TRUE, fileHandle.ProcessID);
- HANDLE hSysFile = (HANDLE)fileHandle.HandleNumber;
- //复制远程进程句柄到当前进程中
- DuplicateHandle(hProcess, hSysFile, GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS);
- CloseHandle(hProcess);
- }
- memset(FileNames, 0, MAX_PATH);
- NtQueryObject(hFile, 1, FileNames, MAX_PATH, NULL);
- CloseHandle(hFile);
- //判断文件是否是欲删除的文件
- //首先将DOS文件名转换为设备文件名
- UCHAR* pchData = FileNames;
- pchData += 8;
- if (wcscmp((unsigned short*)pchData, sDiviceName.AllocSysString()) == 0)
- {
- CloseFileHandle(fileHandle.ProcessID, (HANDLE)fileHandle.HandleNumber); //关闭文件句柄
- bFindFile = TRUE;
- }
- sDiviceName.ReleaseBuffer(); }
- if (bFindFile == FALSE)
- {
- for (POSITION ps = m_SysProcesses.GetStartPosition(); ps != NULL;)//判断文件是否是一个直接运行的文件
- {
- DWORD dwProcID;
- SYSTEM_PROCESS_INFORMATION* pProcInfo = NULL;
- m_SysProcesses.GetNextAssoc(ps, dwProcID, pProcInfo);
- if (pProcInfo != NULL)
- {
- HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS , TRUE, dwProcID);
- if (hProcess)
- {
复制代码- char chFileName[MAX_PATH] = {0};
- GetModuleFileNameEx = (funGetModuleFileNameExA)GetProcAddress(GetModuleHandle(_T("Psapi.dll")), "GetModuleFileNameExA");
- GetModuleFileNameEx(hProcess, NULL, chFileName, MAX_PATH);
- if (strcmp(sFileName.GetBuffer(0), chFileName) == 0)//发现系统中运行的进程
- {
- TerminateProcess(hProcess, 0);
- bFindFile = true;
- }
- CloseHandle(hProcess);
- }
- }
- }
- }
- //<>执行文件删除
- if (bFindFile == TRUE)
- {
- BOOL bDeleted = DeleteFile(sFileName);
- if (bDeleted)
- {
- SetDlgItemText(IDC_EDIT1,"");
- MessageBox("删除成功!");
- }
- else
- {
- DWORD wResult;
- wResult = GetLastError();
- }
- }
- }
复制代码我们来演示功能实现过程
|