Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Figure 1 foo.cpp
////////////////////////////////////////////////////////////////
// Simple program demonstrates why operator= returns a reference
// To compile type:
//
// cl foo.cpp
//
#include <stdio.h>
class A {
public:
int x;
A(int xx=0) { x=xx; }
A& operator=(A& a) {
x=a.x;
return *this;
}
};
int main()
{
A a,b,c(6);
(a=b) = c; // explicit grouping overrides normal right-associativity!
printf ("a=%d\n", a.x);
printf ("b=%d\n", b.x);
printf ("c=%d\n", c.x);
return 0;
}
Figure 2 SHFileOperation
////////////////////////////////////////////////////////////////
// SHFileOperation/LPSHFILEOPSTRUCT can be used to move, copy, delete
// or rename files. Below, I've only shown how I use it to move files
// to the Recycle Bin. See RecycFile.h,cpp for more. - PD
//
int SHFileOperation(LPSHFILEOPSTRUCT lpFileOp);
struct SHFILEOPSTRUCT{
HWND hwnd; // NULL (progress dialog, not
// used)
UINT wFunc; // FO_DELETE (delete operation)
LPCTSTR pFrom; // file name(s) to delete
LPCTSTR pTo; // NULL (not used for delete)
FILEOP_FLAGS fFlags; // see below
BOOL fAnyOperationsAborted; // (returned TRUE if user
// aborted) not used
LPVOID hNameMappings; // not used for delete
LPCSTR lpszProgressTitle; // not used for delete
};
// Flags used
#define FOF_SILENT 0x0004 // don't report progress
#define FOF_NOERRORUI 0x0400 // don't put up error UI
#define FOF_ALLOWUNDO 0x0040 // REQUIRED for Recycle Bin!!!
#define FOF_NOCONFIRMATION 0x0010 // Don't ask user if OK to delete
Figure 3 RecycFile
RecycFile.h
////////////////////////////////////////////////////////////////
// MSDN April 2001
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0. Runs on Windows 98 and probably Windows
// 2000 too.
//
#include <shellapi.h>
//////////////////
// CRecycleFile sends a file to the Recycle Bin.
// Note derived from SHFILEOPSTRUCT.
//
class CRecycleFile : public SHFILEOPSTRUCT {
protected:
public:
CRecycleFile();
~CRecycleFile() { }
int Recycle(LPCTSTR pszPath, BOOL bDelete=FALSE);
};
RecycFile.cpp
////////////////////////////////////////////////////////////////
// MSDN April 2001
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0. Runs on Windows 98 and probably Windows
// 2000 too.
//
#include <windows.h>
#include <tchar.h>
#include "RecycFile.h"
//////////////////
// Constructor initializes SHFILEOPSTRUCT with reasonable
// defaults. You can override if you like. Go ahead, make my day.
//
CRecycleFile::CRecycleFile()
{
memset((SHFILEOPSTRUCT*)this,0,sizeof(SHFILEOPSTRUCT));
fFlags |= FOF_SILENT; // don't report progress
fFlags |= FOF_NOERRORUI; // don't report errors
fFlags |= FOF_NOCONFIRMATION; // don't confirm delete
}
//////////////////
// Send a file to the recycle bin. Args:
// - full pathname of file.
// - bDelete: if TRUE, really delete file (no recycle bin)
//
int CRecycleFile::Recycle(LPCTSTR pszPath, BOOL bDelete)
{
// Copy pathname to double-NULL-terminated string.
//
TCHAR buf[_MAX_PATH + 1]; // allow one more character
_tcscpy(buf, pszPath); // copy caller's path name
buf[_tcslen(buf)+1]=0; // need two NULLs at end
// Set SHFILEOPSTRUCT params for delete operation
//
wFunc = FO_DELETE; // REQUIRED: delete operation
pFrom = buf; // REQUIRED: which file(s)
pTo = NULL; // MUST be NULL
if (bDelete) { // if delete requested..
fFlags &= ~FOF_ALLOWUNDO; // ..don't use Recycle Bin
} else { // otherwise..
fFlags |= FOF_ALLOWUNDO; // ..send to Recycle Bin
}
return SHFileOperation(this); // do it!
}
Figure 4 recycle.cpp
////////////////////////////////////////////////////////////////
// MSDN April 2001
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 6.0. Runs on Windows 98 and probably Windows
// 2000 too.
//
#pragma once
#pragma warning(disable:4786) // disable annoying C4786
#define VC_EXTRALEAN // Exclude rarely used stuff from
// headers
#include <windows.h>
#include <stdio.h>
#include <direct.h> // getcwd
#include <conio.h> // getche
#include <tchar.h>
#include <assert.h>
#include <string> // STL string class
#include <list> // STL list class
#include <sys/stat.h> // stat function
#include "RecycFile.h"
using namespace std; // use STL
typedef list<string> CStringList; // like MFC
// I'm really roughing it hereneed my own TRACE and ASSERT!
#define ASSERT assert
#ifdef _DEBUG
#define TRACE _tprintf
#else
#define TRACE 1 ? (void)0 : ::_tprintf
#endif
// pre-declare functions
void usage();
void help();
string GetCurrentDir();
string MakeAbsolute(const string& relname);
BOOL confirm(LPCTSTR pFileName);
LPCTSTR GetErrorMsg(int err);
// global command-line switches
BOOL bPrompt=FALSE; // prompt each file
BOOL bQuiet=FALSE; // don't display messages
BOOL bDisplayOnly=FALSE; // display results only; don't actually recycle
BOOL bZap=FALSE; // really delete (don't recycle)
// test if file exists
inline fileexists(LPCTSTR pFilename)
{
struct stat st;
return stat(pFilename, &st)==0;
}
// check for switch: / or -
inline BOOL isswitch(TCHAR c)
{
return c==L'/' || c==L'-';
}
//////////////////
// Main function expects argv already expanded for wildcards. You must
// link with setargv.obj!!
//
int main(int argc, TCHAR* argv[], TCHAR* envp[])
{
// Parse command line, building list of file names.
// Switches can come in any order.
//
CStringList files;
for (int i=1; i<argc; i++) {
if (isswitch(argv[i][0])) {
switch(tolower(argv[i][1])) {
case 'q':
bQuiet=TRUE;
break;
case 'n':
bDisplayOnly=TRUE;
break;
case 'p':
bPrompt=TRUE;
break;
case 'z':
bZap=TRUE;
break;
case '?':
help();
return 0;
default:
usage();
return 0;
}
} else {
// Got a file name. Make it absolute and add to list.
files.push_back(MakeAbsolute(argv[i]));
}
}
if (files.empty()) {
// No files specified: tell bozo user how to use this command.
usage();
return 0;
}
// Delete (recycle) all the files in the list
int nDel=0;
CStringList::iterator it;
// loop over list of files and recycle each one
for (it=files.begin(); it!=files.end(); it++) {
const string& filename = *it;
LPCTSTR pFileName = filename.c_str();
// Only recycle if file exists. If the user types a wildcardeg:
// recycle foo.* and there are no files that match "foo.*", then
// setargv passes the wildcard expression unexpandedbut obviously
// there is no such file.
//
if (fileexists(pFileName)) {
if (!bQuiet && !bPrompt) {
// tell user I'm recycling this file
_ftprintf(stderr,_T("%s %s\n"),
bZap ? _T("Deleting") : _T("Recycling"), pFileName);
}
if (!bDisplayOnly) {
if (!bPrompt || confirm(pFileName)) {
// Finally! Recycle the file. Use CRecycleFile.
CRecycleFile rf;
int err = rf.Recycle(pFileName,bZap);
if (err==0) {
nDel++;
} else {
// Can't recycle: display error message
_ftprintf(stderr,_T("Error %d: %s"), err,
GetErrorMsg(err));
}
}
}
} else {
_ftprintf(stderr,_T("File not found \"%s\"\n"), pFileName);
}
}
if (!bQuiet) {
_ftprintf(stderr,_T("%d files recycled\n"),nDel);
}
return 0;
}
////////////////
// Duh.
//
void usage()
{
_tprintf(_T("Usage: RECYCLE [/QNPZ?] file...\n"));
}
////////////////
// Ditto duh.
//
void help()
{
_tprintf(_T("Purpose: Send one or more files to the recycle bin.\n"));
_tprintf(_T("Format: RECYCLE [/Q /N /P /Z] file....\n"));
_tprintf(_T(" /Q(uiet) no messages\n"));
_tprintf(_T(" /N(othing) don't delete, just show files\n"));
_tprintf(_T(" /P(rompt) confirm each file\n"));
_tprintf(_T(" /Z(ap) really deletesame as del\n"));
}
//////////////////
// Make a file name absolute with respect to current directory.
//
string MakeAbsolute(const string& relname)
{
// Get current directory. Since cwd is static this happens only once.
static const string cwd = GetCurrentDir();
string absname;
if (relname[0] && relname[1] && relname[1]==':') {
// relname is already absolute
absname = relname;
} else if (relname[0]=='\\') {
// relname begins with \ add drive letter and colon
absname = string(cwd,0,2);
absname += relname;
} else { // file name begins with letter:
// relname begins with a letter prepend cwd
absname = cwd;
absname += relname;
}
return absname;
}
//////////////////
// Get current directory. For some reason unknown to mankind, getcwd
// returns "C:\FOO" (no \ at end) if dir is NOT root; yet it returns "C:\"
// (with \) if cwd is root. Go figure. To make the result consistent for
// appending a file name, GetCurrentDir adds the missing \ if needed.
// Result always has final \.
//
string GetCurrentDir()
{
TCHAR dir[MAX_PATH];
_tgetcwd(dir, sizeof(dir)/sizeof(TCHAR));
// Append '\' if needed
int lastchar = _tcslen(dir)-1;
if (lastchar>0 && dir[lastchar] != '\\') // if last char isn't \ ..
_tcscat(dir,_T("\\")); // ..add one
return dir; // compiler will convert to string!
}
//////////////////
// Get user confirmation to recycle/delete a file
//
BOOL confirm(LPCTSTR pFileName)
{
while (TRUE) {
_tprintf(_T("Recycle %s (Y/N/All)? "), pFileName);
char c = _getche();
if (c=='') {
_tprintf(_T("^C\n"));
exit(0);
}
_tprintf(_T("\n"));
switch (tolower(c)) {
case 'a':
bPrompt=FALSE;
// fall through
case 'y':
return TRUE;
case 'n':
return FALSE;
}
}
}
//////////////////
// Get Windows system error message
//
LPCTSTR GetErrorMsg(int err)
{
const BUFSIZE = 512;
static TCHAR buf[BUFSIZE];
buf[0]=0;
// Only Windows could have a function this confusing to get a simple
// error message.
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, // source
err, // error code
0, // language ID
buf, // buffer to receive message
BUFSIZE, // size of buf
NULL); // arguments
return buf;
}