// Recycle.h #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 #ifndef Recycleh #define Recycleh /* In C++ there seem to be many ways to open files, copy them, delete them... Sometimes certain ways don't work and you end up wondering why - then it turns out to be a problem with long file names or something else ridiculous. But Windows itself uses a nice little dialog that gives a (random?) "time left estimate" and a progress bar. It can delete Directory Trees, Read only folders and files, and delete to the recycle bin.... So shouldn't we all be using this? Here's a little class that wraps the Windows Shell magic. To delete a File or Folder (which doesn't need to be empty): CRecycle::Delete("Test"); If you had a list of Directory Trees to delete, use a string of strings (double null terminator): CRecycle::Delete(CString("Test")+'\0'+"Test2"+'\0'); If you give the full path, CRecycle will delete to the Recycle Bin (unless you say: CRecycle::Delete("Test\0Test2\0",false); The following code gets the full path for a file: CString Path; DWORD Length=GetFullPathName(Path,0,0,0); // Make relative paths absolute: GetFullPathName(Path, Length, Path.GetBufferSetLength(Length), 0); Path.ReleaseBuffer(); This also uses Move and Copy lists of files giving the standard Windows Move/Copy Progress Bar Dialog. Since my implementation is meant for an Application to use, there is no user feedback with regard to Read-Only files etc. Everything that can be Moved, Deleted or Copied will be. For example, Copy("C:\\a.txt\0C:\\b.txt\0","C:\\c.txt\0C:\\d.txt\0"); copies a.txt to c.txt and b.txt to d.txt The shell uses the double null terminator to identify the end of the source/destination lists. The trailing double nulls are added by these routines, so you don't have to. So you can copy a single file as you'd expect to: Copy("C:\\a.txt","C:\\b.txt"); */ class __declspec(novtable) CRecycle { CRecycle() {} // Private Constructor: you shouldn't create one of these. enum ActionType {aCopy,aMove,aDelete,aRecycle}; static bool File(const CString& src, const CString& dst, ActionType Action) { if(!*src) return false; SHFILEOPSTRUCT FIO; memset(&FIO, 0, sizeof SHFILEOPSTRUCT); FIO.fFlags=FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR; switch(Action) { case aRecycle: FIO.fFlags |= FOF_ALLOWUNDO; // ..send to Recycle Bin case aDelete: FIO.wFunc=FO_DELETE; break; case aCopy: FIO.wFunc=FO_COPY; break; case aMove: FIO.wFunc=FO_MOVE; break; } if(src.Find('\0')!=src.GetLength()) FIO.fFlags|=FOF_MULTIDESTFILES; FIO.pFrom=&*src; if(ActionPath.GetLength()) return OK; // Point to next Path } return OK; } }; /* The old way -single file copy: static bool Copy(const CString& src, const CString& dst) { DWORD Length=GetFullPathName(src,0,0,0); //Make relative paths absolute: GetFullPathName(src, Length, src.GetBufferSetLength(Length), 0); src.ReleaseBuffer(); Length=GetFullPathName(dst,0,0,0); GetFullPathName(dst, Length, dst.GetBufferSetLength(Length), 0); dst.ReleaseBuffer(); HANDLE iFile=CreateFile(src, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(!iFile) return false; HANDLE oFile=CreateFile(dst, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(!oFile) { CloseHandle(iFile); return false; } DWORD iBytes,oBytes; char Buffer[4096]; do { ReadFile (iFile, Buffer, sizeof Buffer, &iBytes, NULL); WriteFile(oFile, Buffer, iBytes , &oBytes, NULL); if(iBytes!=oBytes) { CloseHandle(iFile); CloseHandle(oFile); return false; } }while(iBytes); BY_HANDLE_FILE_INFORMATION Info; GetFileInformationByHandle(iFile,&Info); SetFileTime(oFile,&Info.ftCreationTime,&Info.ftLastAccessTime,&Info.ftLastWriteTime); CloseHandle(iFile); CloseHandle(oFile); SetFileAttributes(dst,Info.dwFileAttributes); FlushDrive(*dst); return true; } // GetLongPathName exists only from Win98/NT5 onwards. // We can do it with IShellFolder::ParseDisplayName instead. // Jim Barry, Thermoteknix Systems Ltd., Cambridge, UK. static DWORD ShortToLongPathName(LPCTSTR ShortPath, LPTSTR LongPath, DWORD Buffer) { USES_CONVERSION; // Get the Desktop Folder CComPtr pDesktop; SHGetDesktopFolder(&pDesktop); if(!pDesktop) return 0; // Get the ID list for the short pathname ULONG eaten=0; LPITEMIDLIST item=NULL; pDesktop->ParseDisplayName(NULL, NULL, T2W(ShortPath), &eaten, &item, NULL); if(!item) { SetLastError(ERROR_FILE_NOT_FOUND); return 0; } // Get the long path of the item TCHAR szBuffer[_MAX_PATH]={0}; SHGetPathFromIDList(item, szBuffer); // Free the pidl! CComPtr pMalloc; SHGetMalloc(&pMalloc); if(pMalloc) pMalloc->Free(item); // Do what GetLongPathName does lstrcpyn(LongPath, szBuffer, Buffer); return lstrlen(szBuffer); } */ #endif //ndef Recycleh