특정 폴더를 한번에 삭제하기(폴더안 파일까지 포함) [펌]
2015. 9. 18. 11:53ㆍIT-개발/winapi 및 MFC
반응형
[출처 : http://yamoe.tistory.com]
윈도우에서 폴더 삭제시 비어있는 폴더가 아닌 경우
일일히 폴더 안의 파일을 삭제해줘야 하는데 (DeleteFile후에 RemoveDirectory)
쉘을 사용할 경우 한번에 삭제할 수 있다.
(어떤 사람들은 system("삭제명령")을 쓰라는 얘기도 있는데 이건 너무한 것 같다.)
이 쉘 함수가 SHFileOperation()으로 파일 및 폴더의 삭제, 복사, 리네임 등 flag에 따라 많은 일을 해준다.
(옵션에 따라 휴지통에 지울 수 도 있다.)
문제는 Vista 이후 부터는 IFileOperation 를 사용하길 권장하고 있으며
실제로 Windows 7에서 SHFileOperation()을 사용할 경우 삭제시 파일을 못찾겠다는 둥 오동작을 한다.
결국 여러 WIndows OS 버전을 만족 시킬려면 윈도우 버전에 따라 SHFileOperation()를 사용할지
IFileOperation()를 사용할지 선택적으로 동작하도록 해줘야 한다.
Vista 전의 OS에선 SHFileOperation()을 통해 Recursive한 디렉토리 삭제 샘플
123456789101112131415161718192021222324252627282930313233bool
CCommonUtil::RemoveUseShellUnderVista(_tstring& filename,
bool
useRecycleBin =
true
)
{
// 파일명 끝에 \0\0 이 있어야 정상동작.
// 그렇지 않은 경우 SHFileOperation()는 1026을 돌려준다.
_tstring from = filename;
from.resize(filename.size() + 2);
from += _T(
"\0\0"
);
SHFILEOPSTRUCT shFileOpStruct = {0,};
shFileOpStruct.hwnd = NULL;
shFileOpStruct.wFunc = FO_DELETE;
shFileOpStruct.pFrom = from.c_str();
shFileOpStruct.pTo = NULL;
shFileOpStruct.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI;
shFileOpStruct.fAnyOperationsAborted = FALSE;
shFileOpStruct.hNameMappings = NULL;
shFileOpStruct.lpszProgressTitle = NULL;
if
( useRecycleBin )
// 휴지통에 넣기
{
shFileOpStruct.fFlags |= FOF_ALLOWUNDO;
}
int
ret = SHFileOperation(&shFileOpStruct);
if
( ret == 0 )
{
return
true
;
}
else
{
printf
(
"FAILED SHFileOperation[%d]\n"
, ret);
return
false
;
}
}
Vista 부터 이후 OS에선 IFileOperation()을 통해 Recursive한 디렉토리 삭제 샘플
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758#include "Shobjidl.h"
bool
CCommonUtil::RemoveUseShellSinceVista(_tstring& filename,
bool
useRecycleBin =
true
)
{
bool
ret =
false
;
const
TCHAR
* pFrom = NULL;
#ifdef UNICODE
pFrom = filename.c_str();
#else
USES_CONVERSION;
pFrom = A2W(filename.c_str());
#endif
IFileOperation* pfo;
HRESULT
hr;
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if
(SUCCEEDED(hr))
{
HRESULT
hr = CoCreateInstance(CLSID_FileOperation, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pfo));
if
(SUCCEEDED(hr))
{
DWORD
flags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI;
if
( useRecycleBin ) { flags |= FOF_ALLOWUNDO; }
// 휴지통에 넣기
hr = pfo->SetOperationFlags(flags);
if
(SUCCEEDED(hr))
{
IShellItem *psiFrom = NULL;
hr = SHCreateItemFromParsingName(pFrom, NULL, IID_PPV_ARGS(&psiFrom));
if
(SUCCEEDED(hr))
{
if
(SUCCEEDED(hr))
{
hr = pfo->DeleteItem(psiFrom, NULL);
if
(SUCCEEDED(hr))
printf
(
"success\n"
);
else
printf
(
"fail\n"
);
}
psiFrom->Release();
}
if
(SUCCEEDED(hr))
{
hr = pfo->PerformOperations();
if
(SUCCEEDED(hr))
{
ret =
true
;
}
}
}
pfo->Release();
}
}
CoUninitialize();
return
ret;
}
주의 1. XP에서 SHFileOperation와 IFileOperation가 모두 구현된 상태에서 실행할 경우
만약, 두 함수를 구현한 후 XP에서 실행시
"프로시저 시작 지점 SHCreateItemFromParsingName을(를) DLL SHELL32.dll에서 찾을 수 없습니다."
에러가 발생한다.
해당 함수가 Vista 이후의 shell32.dll 부터 있는 것이기 때문인데
현재 "프로젝트 속성 > 링커 > 입력 > 지연 로드된 DLL" 에 shell32.dll 를 등록하면 된다.
주의 2. 휴지통에 넣는 기능은 네트워크 드라이브에 있는 파일을 지울땐 적용되지 않는다.
일단 확인한것은 네트워크 드라이브로 연결된 하드의 파일/폴더 삭제시엔 휴지통으로 들어가지 않는다.
로컬 파일이 아니기 때문에 복원문제가 복잡하고 보장할 수 없기 때문으로 생각되기 때문에 당연한 듯 하다.
이런 경우도 복원이 보장되야 한다면 휴지통 기능을 직접 구현해야 하겠다.
추가로..
부록 1. 현재 어떤 윈도우 버전(타입)인지 구하는 함수
해당 함수가 Vista 이후의 shell32.dll 부터 있는 것이기 때문인데
현재 "프로젝트 속성 > 링커 > 입력 > 지연 로드된 DLL" 에 shell32.dll 를 등록하면 된다.
주의 2. 휴지통에 넣는 기능은 네트워크 드라이브에 있는 파일을 지울땐 적용되지 않는다.
일단 확인한것은 네트워크 드라이브로 연결된 하드의 파일/폴더 삭제시엔 휴지통으로 들어가지 않는다.
로컬 파일이 아니기 때문에 복원문제가 복잡하고 보장할 수 없기 때문으로 생각되기 때문에 당연한 듯 하다.
이런 경우도 복원이 보장되야 한다면 휴지통 기능을 직접 구현해야 하겠다.
추가로..
부록 1. 현재 어떤 윈도우 버전(타입)인지 구하는 함수
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081int
GetWindowsType(
void
)
{
/*
return value :
-1 : 버전얻기 실패
1 : Windows 95,
2 : Windows 98,
3 : Windows ME,
4 : Windows NT,
5 : Windows 2000,
6 : Windows XP,
7 : Windows 2003,
8 : Windows Vista, 2008
9 : Windows 7, 2008 R2
*/
int
nVersion= -1;
OSVERSIONINFOEX osvi = {0,};
BOOL
version_ex_flag = 0;
osvi.dwOSVersionInfoSize =
sizeof
(OSVERSIONINFOEX);
if
( !(version_ex_flag = GetVersionEx((OSVERSIONINFO *)&osvi)) )
{
osvi.dwOSVersionInfoSize =
sizeof
(OSVERSIONINFO);
if
( !GetVersionEx((OSVERSIONINFO *)&osvi) )
return
-1;
}
switch
(osvi.dwPlatformId)
{
case
VER_PLATFORM_WIN32_WINDOWS:
// 윈도우즈 9x 기반의 운영체제인 경우
{
if
( osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0 )
{
nVersion = 1;
// Windows 95
}
else
if
(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10)
{
nVersion = 2;
// Windows 98
}
else
if
(osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90)
{
nVersion = 3;
// Windows ME
}
}
break
;
case
VER_PLATFORM_WIN32_NT:
// NT 기술 기반의 운영체제인 경우
{
if
( osvi.dwMajorVersion <= 4 )
{
nVersion = 4;
// Windows NT
}
else
if
( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0 )
{
nVersion = 5;
//Windows 2000
}
else
if
(version_ex_flag)
{
if
( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1)
{
nVersion = 6;
// Windows XP
}
else
if
( osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2)
{
nVersion = 7;
// Windows 2003
}
else
if
( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0)
{
nVersion = 8;
// Windows Vista, 2008
}
else
if
( osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 1)
{
nVersion = 9;
// WIndows7, 2008 R2
}
}
}
break
;
}
return
nVersion;
}
'IT-개발 > winapi 및 MFC' 카테고리의 다른 글
OutputDebugString - 잘쓰기 (펌) (0) | 2015.09.30 |
---|---|
DLL 만들때, 정적 라이브러리에서 MFC 사용 !!!(펌) (0) | 2015.09.24 |
CListCtrl 포커스 해제시 selection color 유지하기 (0) | 2015.08.21 |
잘못된 인수가 발견되었습니다(An invalid argument encountered) (0) | 2015.08.18 |
Kernel Object / Object Handle (펌) (0) | 2015.08.18 |