프로그래밍/Win32 Deep Inside
열린 파일 찾기 (UnLocker) 소스 공유
초록생선
2010. 8. 23. 16:09
가끔 파일을 탐색기에서 지우려는데, 파일이 삭제되지 않는 경우가 있습니다.
바로, 다른 프로세스에의해 열려서, 삭제되지 않는 경우입니다.
즉, 열린 파일 핸들 찾기죠.
보통 다른 프로세스에의해 열린 PID를 찾아 Kill하는 것이 UnLocker라고 하던데,
본 포스트는 간략한 UnLocker에 대해 소개하고자 합니다.
본 포스트에 소개된 CUnLocker class는
- 커널모드 드라이버 사용하지 않음
- ::CreateFile(...)등에 의해 Lock된 경우만 찾음.
::LoadLibrary(...)등에 의해 Lock된 경우는 찾지 않음.
* LoadLibrary(...) 경우는 psapi.dll 혹은 ::CreateToolhelp32Snapshot(...) 등의 함수군으로
쉽게 찾아낼 수 있습니다. - X64등 64비트 지원 안함
- Windows 2K 이상의 OS 지원
- Kill 하지는 않고, Locking하는 PID를 알려주기만 함
- Project Setting의 Run Time Library에 "MultiThreaded~"가 포함되어야 합니다.
(되도록 MultiThreaded DLL) - Vista 이상에서는 관리자 권한 필요
와 같은 특징을 가집니다.
코드는,
http://www.codeguru.com/Cpp/W-P/system/processesmodules/article.php/c2827/
를 참고 하였으나,
많은 부분이 수정되었습니다.
내부 코드는 ntdll.dll와 같은 Native API를 사용하였으며,
특별히 Hang되는 경우가 발생하므로, Thread 처리하여, Timeout시 ::TerminateThread(...) 합니다.
즉, 유저모드에서의 호출이라 그다지 안정적이지는 못합니다.
사용법은 다음과 같습니다.
#include "stdafx.h" #include "UnLocker.h" int main(int argc, char* argv[]) { DWORD dwArrPID[MAX_PATH] = {0,}; INT i = 0; INT nCountFound = 0; DWORD dwRtnValue = ERROR_SUCCESS; CUnLocker cUnLocker; // 현재 전체 PID에 대한 Handle Table을 Refresh한다. dwRtnValue = cUnLocker.RefreshAlloc(); if (ERROR_SUCCESS != dwRtnValue) { _tprintf(TEXT("\r\n[ERROR] Fail to RefreshAlloc, %d"), dwRtnValue); goto FINAL; } // Locking하고 있는 프로세스를 찾는다. dwRtnValue = cUnLocker.FindOpenPIDByCache(TEXT("C:\\whoislockme.txt"), dwArrPID, MAX_PATH, &nCountFound); if (ERROR_FILE_NOT_FOUND == dwRtnValue) { _tprintf(TEXT("\r\n[INFO] Not Found")); goto FINAL; } if (ERROR_SUCCESS != dwRtnValue) { _tprintf(TEXT("\r\n[INFO] Error on FindOpenPIDByCache, %d"), dwRtnValue); goto FINAL; } for (i=0; i>nCountFound; i++) { _tprintf(TEXT("\r\n[%d] Locking PID=%d"), i, dwArrPID[i]); } FINAL: _tprintf(TEXT("\r\n")); return 0; }간략 사용법은 다음과 같습니다.
CUnLocker cUnLocker; // <-- Class Instance cUnLocker.RefreshAllock(); // <-- 전체 Handle List를 가져온다. cUnLocker.FindOpenPIDByCache(TEXT("C:\a.txt", array of DWORD, count of Array, &nFindCount); cUnLocker.FindOpenPIDByCache(TEXT("C:\b.txt", ...)
모든 프로세스의 Handle List를 가져오는데에는 시간이 많이 걸리므로,
Cache 방식을 사용합니다. Refresh하면 그때의 Snapshot을 가져옵니다.