Click here to Skip to main content
15,887,214 members
Articles / Desktop Programming / MFC

How to programmatically use the Recycle Bin

Rate me:
Please Sign up or sign in to vote.
4.90/5 (29 votes)
19 Aug 2002CPOL7 min read 291.6K   4.3K   79  
An article on how to access the content of the RecycleBin, track its changes and deal with its functionnalities (delete-restore)
// RecycleBinDlg.cpp : implementation file
//

#include "stdafx.h"
#include "RecycleBin.h"
#include "RecycleBinDlg.h"
#include "shlobj.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRecycleBinDlg dialog

CRecycleBinDlg::CRecycleBinDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CRecycleBinDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CRecycleBinDlg)
	m_ChkFolders = FALSE;
	m_ChkRBin = FALSE;
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	m_pFolder2		= NULL;
	m_pRecycleBin	= NULL;
	m_ChkRBin		= TRUE;
	m_ChkFolders	= TRUE;

	ZeroMemory (&m_pidlDrives, sizeof (m_pidlDrives));
	ZeroMemory (&m_hNotifyDrives, sizeof (m_hNotifyDrives));

	m_hShell32 = LoadLibrary(_T("SHELL32.DLL"));
}

CRecycleBinDlg::~CRecycleBinDlg ()
{
	if (NULL != m_pFolder2)
	{
		m_pFolder2->Release ();
	}

	if (NULL != m_pRecycleBin)
	{
		m_pRecycleBin->Release ();
	}
}
void CRecycleBinDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CRecycleBinDlg)
	DDX_Control(pDX, IDC_LIST, m_List);
	DDX_Check(pDX, IDC_CHKFOLDERS, m_ChkFolders);
	DDX_Check(pDX, IDC_CHKRBIN, m_ChkRBin);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CRecycleBinDlg, CDialog)
	//{{AFX_MSG_MAP(CRecycleBinDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_UNDELETE, OnUndelete)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST, OnItemchangedList)
	ON_BN_CLICKED(IDC_UNDELETEALL, OnUndeleteall)
	ON_BN_CLICKED(IDC_PROPERTY, OnProperty)
	ON_COMMAND_RANGE (IDC_FIRSTDRIVE, IDC_LASTDRIVE, OnEmptyDrive)
	ON_NOTIFY(NM_RCLICK, IDC_LIST, OnRclickList)
	ON_BN_CLICKED(IDC_CHKRBIN, OnChkrbin)
	ON_BN_CLICKED(IDC_CHKFOLDERS, OnChkfolders)
	//}}AFX_MSG_MAP
	ON_MESSAGE (WM_SHELLNOTIFY, OnShellNotify)
	ON_MESSAGE (WM_SHELLNOTIFYRBINDIR, OnNotifyRBinDir)
	
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CRecycleBinDlg message handlers

void CRecycleBinDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CRecycleBinDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CRecycleBinDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CRecycleBinDlg::OnItemchangedList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	
	GetDlgItem (IDC_UNDELETE)->EnableWindow ((0 != m_List.GetSelectedCount ()) ? TRUE : FALSE);
	GetDlgItem (IDC_PROPERTY)->EnableWindow ((0 != m_List.GetSelectedCount ()) ? TRUE : FALSE);
	
	*pResult = 0;
}

BOOL CRecycleBinDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	
	// Add "About..." menu item to system menu.
	
	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
	
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	/* Code for letting our application to register with the Windows and receive
	* Shell Notification events 
	* As the two functions cannot be accessed directly, we have to specifically load them
	* from SHELL32.DLL
	*/
	SHFILEINFO fi;
	BOOL bReturn = FALSE;
	HIMAGELIST himl = NULL;
	
	m_List.SetExtendedStyle (LVS_EX_FULLROWSELECT);
	
	// We are gaining a Handle on the system ImageList. By doing so, we'll have
	// a direct access to the corresponding icons.
	ZeroMemory (&fi, sizeof (fi));
	himl = (HIMAGELIST)SHGetFileInfo (NULL, 0, &fi, sizeof (fi), SHGFI_ATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
	bReturn = m_ImageListSmall.Attach (himl);
	m_List.SetImageList (&m_ImageListSmall, LVSIL_SMALL);
	
	// We need to know the distance between two buttons, just to add our menu-button
	// on the right place
	CRect rect, rect2;
	long lOffset = 0;
	
	GetDlgItem (IDC_UNDELETE)->GetWindowRect(&rect);
	GetDlgItem (IDC_UNDELETEALL)->GetWindowRect(&rect2);
	ScreenToClient (&rect);
	ScreenToClient (&rect2);
	lOffset = (rect2.top - rect.bottom) + rect2.Height ();
	rect2.top += lOffset;
	rect2.bottom += lOffset;
	m_Empty.Create(_T("&Empty RBin"), WS_TABSTOP | WS_CHILD | WS_VISIBLE, rect2, this, IDC_FIRSTDRIVE);
	
	// Initialize and fill the ListCtrl
	InitInterfaces ();
	UpdateList ();
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

BOOL CRecycleBinDlg::DestroyWindow() 
{
	if (NULL != m_hShell32)
	{
		m_ChkRBin = FALSE;
		OnChkrbin ();
		m_ChkFolders = FALSE;
		OnChkfolders ();
		
		FreeLibrary(m_hShell32);
		m_hShell32 = NULL;
	}
	
	return CDialog::DestroyWindow();
}

LRESULT CRecycleBinDlg::OnShellNotify (WPARAM wParam, LPARAM lParam)
{
	LRESULT lReturn = 0;
	SHNOTIFYSTRUCT shns;
	TCHAR szBefore[MAX_PATH];
	TCHAR szAfter[MAX_PATH];
	TCHAR szMessage[MAX_PATH];
	
	memcpy((void *)&shns,(void *)wParam,sizeof(SHNOTIFYSTRUCT));

	SHGetPathFromIDList((struct _ITEMIDLIST *)shns.dwItem1, szBefore);
	SHGetPathFromIDList((struct _ITEMIDLIST *)shns.dwItem2, szAfter);

	switch (lParam)
	{
	case SHCNE_RENAMEITEM          : //0x00000001L
	case SHCNE_CREATE              : //0x00000002L
	case SHCNE_DELETE              : //0x00000004L
	case SHCNE_MKDIR               : //0x00000008L
	case SHCNE_RMDIR               : //0x00000010L
	case SHCNE_MEDIAINSERTED       : //0x00000020L
	case SHCNE_MEDIAREMOVED        : //0x00000040L
	case SHCNE_DRIVEREMOVED        : //0x00000080L
	case SHCNE_DRIVEADD            : //0x00000100L
	case SHCNE_NETSHARE            : //0x00000200L
	case SHCNE_NETUNSHARE          : //0x00000400L
	case SHCNE_ATTRIBUTES          : //0x00000800L
	case SHCNE_UPDATEDIR           : //0x00001000L
	case SHCNE_UPDATEITEM          : //0x00002000L
	case SHCNE_SERVERDISCONNECT    : //0x00004000L
	case SHCNE_UPDATEIMAGE         : //0x00008000L
	case SHCNE_DRIVEADDGUI         : //0x00010000L
	case SHCNE_RENAMEFOLDER        : //0x00020000L
	case SHCNE_FREESPACE           : //0x00040000L
		UpdateList ();
		break;
	default:
		wsprintf (szMessage, _T("EventID: %08x %d"), lParam, lParam);
		MessageBox (szMessage);;
		break;
	}

	return lReturn;
}

LRESULT CRecycleBinDlg::OnNotifyRBinDir (WPARAM wParam, LPARAM lParam)
{
	LRESULT lReturn = 0;
	SHNOTIFYSTRUCT shns;
	TCHAR szBefore[MAX_PATH];
	TCHAR szAfter[MAX_PATH];
	TCHAR szMessage[MAX_PATH];
	
	memcpy((void *)&shns,(void *)wParam,sizeof(SHNOTIFYSTRUCT));
	
	SHGetPathFromIDList((struct _ITEMIDLIST *)shns.dwItem1, szBefore);
	SHGetPathFromIDList((struct _ITEMIDLIST *)shns.dwItem2, szAfter);
	
	switch (lParam)
	{
	case SHCNE_RENAMEITEM          : //0x00000001L
	case SHCNE_CREATE              : //0x00000002L
	case SHCNE_DELETE              : //0x00000004L
	case SHCNE_MKDIR               : //0x00000008L
	case SHCNE_RMDIR               : //0x00000010L
	case SHCNE_MEDIAINSERTED       : //0x00000020L
	case SHCNE_MEDIAREMOVED        : //0x00000040L
	case SHCNE_DRIVEREMOVED        : //0x00000080L
	case SHCNE_DRIVEADD            : //0x00000100L
	case SHCNE_NETSHARE            : //0x00000200L
	case SHCNE_NETUNSHARE          : //0x00000400L
	case SHCNE_ATTRIBUTES          : //0x00000800L
	case SHCNE_UPDATEDIR           : //0x00001000L
	case SHCNE_UPDATEITEM          : //0x00002000L
	case SHCNE_SERVERDISCONNECT    : //0x00004000L
	case SHCNE_UPDATEIMAGE         : //0x00008000L
	case SHCNE_DRIVEADDGUI         : //0x00010000L
	case SHCNE_RENAMEFOLDER        : //0x00020000L
	case SHCNE_FREESPACE           : //0x00040000L
		UpdateList ();
		break;
	default:
		wsprintf (szMessage, _T("EventID: %08x %d"), lParam, lParam);
		MessageBox (szMessage);;
		break;
	}
	
	return lReturn;
}

void CRecycleBinDlg::InitInterfaces (void)
{
	if (TRUE == GetFolder2 ())
	{
		HeaderFolder2 ();
	}
	else if (TRUE == GetFolder ())
	{
		HeaderFolder ();
	}
}
void CRecycleBinDlg::UpdateList (void)
{
	DWORD			dwSize		= GetLogicalDriveStrings(0, NULL);
    LPTSTR			pszDrives	= (LPTSTR)malloc((dwSize + 2) * sizeof (TCHAR));
	LPMALLOC		pMalloc		= NULL;
	LPITEMIDLIST	pidl		= NULL;
	int				iDrive		= 0;
	int				iPos		= 0;
	int				iMax		= m_List.GetItemCount ();
	HRESULT			hr			= S_OK;
	
	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	m_Empty.RemoveAllMenuItem ();

	// If we were able to get the names of available drives, then we'll check if
	// objects are available in their local RBin. If so, we'll add their name to
	// the button's menu as an option for the user to empty them individually.
	if (NULL != pszDrives)
	{
		LPTSTR pstr = pszDrives;
		SHQUERYRBINFO qrbi;

		m_Empty.AddMenuItem (IDC_FIRSTDRIVE, _T("Empty All"), 0);
		GetLogicalDriveStrings((dwSize + 2) * sizeof (TCHAR),(LPTSTR)pszDrives);
		
		while (TCHAR ('\0') != *pstr)
		{
			ZeroMemory (&qrbi, sizeof (qrbi));
			qrbi.cbSize = sizeof (qrbi);
			hr = SHQueryRecycleBin (pstr, &qrbi);
			if (SUCCEEDED (hr))
			{
				if (0 != qrbi.i64NumItems)
				{
					iDrive ++;
					m_Empty.AddMenuItem (IDC_FIRSTDRIVE + 128 * iDrive, pstr, 0);
				}
			}
			pstr += _tcslen(pstr) + sizeof (TCHAR);
		}
		free (pszDrives);
	}
	if (0 == iDrive)
	{
		m_Empty.EnableWindow (FALSE);
	}
	
	for (iPos = 0 ; iPos < iMax ; iPos ++)
	{
		pidl = (LPITEMIDLIST)m_List.GetItemData (iPos);
		if (NULL != pidl)
		{
			pMalloc->Free (pidl);
		}
	}
	m_List.DeleteAllItems ();

	if (NULL != m_pFolder2)
	{
		FillFolder2 ();
	}
	else if (NULL != m_pRecycleBin)
	{
		FillFolder ();
	}
	
	GetDlgItem (IDC_UNDELETEALL)->EnableWindow ((0 != m_List.GetItemCount ()) ? TRUE : FALSE);
	
	pMalloc->Release();
}

void CRecycleBinDlg::GetName (STRRET str, LPTSTR lpszName)
{
	LPMALLOC		pMalloc			= NULL;
	TCHAR szPath[MAX_PATH];

	SHGetMalloc(&pMalloc); // windows memory management pointer needed later

	ZeroMemory (szPath, sizeof (szPath));
	switch (str.uType)
	{
	case STRRET_CSTR:
		_tcscpy (szPath, str.cStr);
		break;
	case STRRET_OFFSET:
		break;
	case STRRET_WSTR:
		WideCharToMultiByte (CP_ACP, 0, str.pOleStr, -1, szPath, sizeof (szPath), NULL, NULL);
		pMalloc->Free (str.pOleStr);
		break;
	}
	SetWindowText (szPath);

	if (NULL != lpszName)
	{
		_tcscpy (lpszName, szPath);
	}
	pMalloc->Release();
}

BOOL CRecycleBinDlg::GetFolder ()
{
	BOOL			bReturn			= FALSE;
	STRRET			strRet;
	LPMALLOC		pMalloc			= NULL;
	LPSHELLFOLDER	pDesktop		= NULL;
	LPITEMIDLIST	pidlRecycleBin	= NULL;
	HRESULT			hr				= S_OK;
	
	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	hr = SHGetDesktopFolder(&pDesktop);
	
	hr = SHGetSpecialFolderLocation (m_hWnd, CSIDL_BITBUCKET, &pidlRecycleBin);
	if (NULL != m_pRecycleBin)
	{
		m_pRecycleBin->Release ();
		m_pRecycleBin = NULL;
	}
	hr = pDesktop->BindToObject(pidlRecycleBin, NULL, IID_IShellFolder, (LPVOID *)&m_pRecycleBin);
	if (SUCCEEDED (hr))
	{
		bReturn = TRUE;
	}

	if (S_OK == pDesktop->GetDisplayNameOf (pidlRecycleBin, SHGDN_NORMAL, &strRet))
	{
		GetName (strRet);
	}

	pMalloc->Free (pidlRecycleBin);
	pDesktop->Release();
	pMalloc->Release();
	
	return bReturn;
}

void CRecycleBinDlg::HeaderFolder ()
{
	LPMALLOC pMalloc = NULL;
	PSHELLDETAILS pDetails = NULL;
	HRESULT hr = S_OK;
	
	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	hr = m_pRecycleBin->CreateViewObject (m_hWnd, IID_IShellDetails, (LPVOID*)&pDetails);
	if (SUCCEEDED (hr))
	{
		TCHAR szTemp[MAX_PATH];
		SHELLDETAILS sd;
		int iSubItem = 0;
		
		while (SUCCEEDED (hr))
		{
			hr = pDetails->GetDetailsOf (NULL , iSubItem, &sd);
			if (SUCCEEDED (hr))
			{
				switch (sd.str.uType)
				{
				case STRRET_CSTR:
					_tcscpy (szTemp, sd.str.cStr);
					break;
				case STRRET_OFFSET:
					break;
				case STRRET_WSTR:
					WideCharToMultiByte (CP_ACP, 0, sd.str.pOleStr, -1, szTemp, sizeof (szTemp), NULL, NULL);
					pMalloc->Free (sd.str.pOleStr);
					break;
				}
				m_List.InsertColumn (iSubItem , szTemp, LVCFMT_LEFT, 100);
				iSubItem ++;
			}
		}
	}
	if (NULL != pDetails)
	{
		pMalloc->Free (pDetails);
	}
	pMalloc->Release();
}

void CRecycleBinDlg::FillFolder ()
{
	LPMALLOC		pMalloc			= NULL;
	TCHAR			szTemp[MAX_PATH];
	LPENUMIDLIST	penumFiles		= NULL;
	LPITEMIDLIST	pidl			= NULL;
	PSHELLDETAILS	pDetails		= NULL;
	SHELLDETAILS	sd;
	int				iItem			= 0;
	int				iSubItem		= 0;
	HRESULT			hr				= S_OK;
	
	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	hr = m_pRecycleBin->CreateViewObject (m_hWnd, IID_IShellDetails, (LPVOID*)&pDetails);

	// Iterate through list
	m_pRecycleBin->EnumObjects(m_hWnd, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS| SHCONTF_INCLUDEHIDDEN, &penumFiles);
	
	if (SUCCEEDED (hr))
	{
		while (penumFiles->Next(1, &pidl, NULL) != S_FALSE)
		{
			iItem = m_List.InsertItem (iItem, _T(""));
			m_List.SetItemData (iItem, (DWORD)pidl);
			
			hr = S_OK;
			iSubItem = 0;
			
			while (SUCCEEDED (hr))
			{
				hr = pDetails->GetDetailsOf (pidl , iSubItem, &sd);
				if (SUCCEEDED (hr))
				{
					switch (sd.str.uType)
					{
					case STRRET_CSTR:
						_tcscpy (szTemp, sd.str.cStr);
						break;
					case STRRET_OFFSET:
						break;
					case STRRET_WSTR:
						WideCharToMultiByte (CP_ACP, 0, sd.str.pOleStr, -1, szTemp, sizeof (szTemp), NULL, NULL);
						pMalloc->Free (sd.str.pOleStr);
						break;
					}
					m_List.SetItemText (iItem, iSubItem , szTemp);
					iSubItem ++;
				}
			}
		}
	}
	else
	{
	}
	if (NULL != pDetails)
	{
		pMalloc->Free (pDetails);
	}

	if (NULL != penumFiles)
	{
		penumFiles->Release ();
		penumFiles = NULL;
	}
	
	pMalloc->Release();
}

BOOL CRecycleBinDlg::GetFolder2 ()
{
	BOOL			bReturn			= FALSE;
	STRRET			strRet;
	LPMALLOC		pMalloc			= NULL;
	LPSHELLFOLDER	pDesktop		= NULL;
	LPITEMIDLIST	pidlRecycleBin	= NULL;
	HRESULT			hr				= S_OK;
	
	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	if (NULL != m_pFolder2)
	{
		m_pFolder2->Release ();
		m_pFolder2 = NULL;
	}
	
	if ((SUCCEEDED (SHGetDesktopFolder(&pDesktop))) &&
		(SUCCEEDED (SHGetSpecialFolderLocation (m_hWnd, CSIDL_BITBUCKET, &pidlRecycleBin))))
	{
		if (SUCCEEDED (pDesktop->BindToObject(pidlRecycleBin, NULL, IID_IShellFolder2, (LPVOID *)&m_pFolder2)))
		{
			if (S_OK == pDesktop->GetDisplayNameOf (pidlRecycleBin, SHGDN_NORMAL, &strRet))
			{
				GetName (strRet);
			}
			
			bReturn = TRUE;
		}
	}
	
	if (NULL != pidlRecycleBin)
	{
		pMalloc->Free (pidlRecycleBin);
	}
	if (NULL != pDesktop)
	{
		pDesktop->Release();
	}
	pMalloc->Release();
	
	return bReturn;
}

void CRecycleBinDlg::HeaderFolder2 ()
{
	TCHAR szTemp[MAX_PATH];
	LPMALLOC pMalloc = NULL;
	HRESULT hr = S_OK;
	SHELLDETAILS sd;
	int iSubItem = 0;

	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	
	// We'are asking the object the list of available columns.
	// For each, we are adding them to the control in the right order.
	while (SUCCEEDED (hr))
	{
		hr = m_pFolder2->GetDetailsOf (NULL , iSubItem, &sd);
		if (SUCCEEDED (hr))
		{
			switch (sd.str.uType)
			{
			case STRRET_CSTR:
				_tcscpy (szTemp, sd.str.cStr);
				break;
			case STRRET_OFFSET:
				break;
			case STRRET_WSTR:
				WideCharToMultiByte (CP_ACP, 0, sd.str.pOleStr, -1, szTemp, sizeof (szTemp), NULL, NULL);
				pMalloc->Free (sd.str.pOleStr);
				break;
			}
			m_List.InsertColumn (iSubItem , szTemp, LVCFMT_LEFT, 100);
			iSubItem ++;
		}
	}
	pMalloc->Release();
}

void CRecycleBinDlg::FillFolder2 ()
{
	LPMALLOC		pMalloc = NULL;
	TCHAR			szTemp[MAX_PATH];
	LPENUMIDLIST	penumFiles;
	LPITEMIDLIST	pidl = NULL;
	SHELLDETAILS	sd;
	int				iItem = 0;
	int				iSubItem = 0;
	int				iIndex = -1;
	SHFILEINFO		fi;
	SFGAOF			sg = SFGAO_VALIDATE;
	HRESULT			hr = S_OK;
	
	SHGetMalloc(&pMalloc); // windows memory management pointer needed later
	
	// Get the list of available objects
	hr = m_pFolder2->EnumObjects(m_hWnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS| SHCONTF_INCLUDEHIDDEN, &penumFiles);
	if (SUCCEEDED (hr))
	{
		// Iterate through list
		while (penumFiles->Next(1, &pidl, NULL) != S_FALSE)
		{
			iItem = m_List.InsertItem (iItem, _T(""));
			m_List.SetItemData (iItem, (DWORD)pidl);

			ZeroMemory (&fi, sizeof (fi));
			hr = SHGetFileInfo ((LPCSTR)pidl, 0, &fi, sizeof (fi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_PIDL);

			if (SUCCEEDED (hr))
			{
				iIndex = fi.iIcon;
				m_List.SetItem (iItem, 0, LVIF_IMAGE, NULL, iIndex, 0, 0, 0);
			}

			// We iterate now in all the available columns.
			// Since it depends on the system, we "hope" that they are going to be as many 
			// and in the same order as when we have added the column's headers.

			hr = S_OK;
			iSubItem = 0;
			while (SUCCEEDED (hr))
			{
				hr = m_pFolder2->GetDetailsOf (pidl , iSubItem, &sd);
				if (SUCCEEDED (hr))
				{
					switch (sd.str.uType)
					{
					case STRRET_CSTR:
						_tcscpy (szTemp, sd.str.cStr);
						break;
					case STRRET_OFFSET:
						break;
					case STRRET_WSTR:
						WideCharToMultiByte (CP_ACP, 0, sd.str.pOleStr, -1, szTemp, sizeof (szTemp), NULL, NULL);
						pMalloc->Free (sd.str.pOleStr);
						break;
					}
					m_List.SetItemText (iItem, iSubItem , szTemp);
					iSubItem ++;
				}
			}
		}
	}

	if (NULL != penumFiles)
	{
		penumFiles->Release ();
		penumFiles = NULL;
	}

	pMalloc->Release();
}

BOOL CRecycleBinDlg::ExecCommand (int iItem, LPCTSTR lpszCommand)
{
	BOOL bReturn = FALSE;
	LPITEMIDLIST	pidl = NULL;
	LPCONTEXTMENU pCtxMenu = NULL;
	HRESULT hr = S_OK;

	pidl = (LPITEMIDLIST)m_List.GetItemData (iItem);

	if (NULL != m_pFolder2)
	{
		hr = m_pFolder2->GetUIObjectOf (m_hWnd, 1, (LPCITEMIDLIST *)&pidl, IID_IContextMenu, NULL, (LPVOID *)&pCtxMenu);
	}
	else
	{
		hr = m_pRecycleBin->GetUIObjectOf (m_hWnd, 1, (LPCITEMIDLIST *)&pidl, IID_IContextMenu, NULL, (LPVOID *)&pCtxMenu);
	}

	if (SUCCEEDED (hr))
	{
		UINT uiID = UINT (-1);
		UINT uiCommand = 0;
		UINT uiMenuFirst = 1;
		UINT uiMenuLast = 0x00007FFF;
		HMENU hmenuCtx;
		int iMenuPos = 0;
		int iMenuMax = 0;
		TCHAR szMenuItem[128];
		TCHAR szTrace[512];
		char verb[MAX_PATH] ;

		hmenuCtx = CreatePopupMenu();
		hr = pCtxMenu->QueryContextMenu(hmenuCtx, 0, uiMenuFirst, uiMenuLast, CMF_NORMAL);

		iMenuMax = GetMenuItemCount(hmenuCtx);
		wsprintf (szTrace, _T("Nb Items added to the menu %d\n\n"), iMenuMax);
		TRACE (szTrace);
		
		for (iMenuPos = 0 ; iMenuPos < iMenuMax; iMenuPos++)
		{
			GetMenuString(hmenuCtx, iMenuPos, szMenuItem, sizeof (szMenuItem), MF_BYPOSITION) ;
			wsprintf (szTrace, _T("Menu Entry : %s\n"), szMenuItem);
			TRACE (szTrace);
			
			uiID = GetMenuItemID(hmenuCtx, iMenuPos) ;
			
			if ((uiID == -1) || (uiID == 0))
			{
				wsprintf (szTrace, _T("No Verb found for the entry #%d \n\n"), uiID);
				TRACE (szTrace);
			}
			else
			{
				// When we'll have found the right command, we'll be obliged to perform a
				// 'uiID - 1' else the verbs are going to be be misaligned from they're
				// real ID
				hr = pCtxMenu->GetCommandString(uiID - 1, GCS_VERBA, NULL, verb, sizeof (verb));
				if (FAILED (hr))
				{
					verb[0] = TCHAR ('\0') ;
				}
				else
				{
					if (0 == _tcsicmp (verb, lpszCommand))
					{
						uiCommand = uiID - 1;
					}
				}
				wsprintf (szTrace, _T("verb %s (ret %d)\n\n"), verb, hr);
				TRACE (szTrace);
			}
		}
		
		if ((UINT)-1 != uiCommand)
		{
			CMINVOKECOMMANDINFO cmi;
			
			ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
			cmi.cbSize			= sizeof(CMINVOKECOMMANDINFO);
			cmi.fMask			= CMIC_MASK_FLAG_NO_UI;
			cmi.hwnd			= m_hWnd;
			cmi.lpParameters	= NULL;
			cmi.lpDirectory		= NULL;
			cmi.lpVerb			= MAKEINTRESOURCE (uiCommand);
			cmi.nShow			= SW_SHOWNORMAL;
			cmi.dwHotKey		= NULL;
			cmi.hIcon			= NULL;
			hr = pCtxMenu->InvokeCommand(&cmi);
			
			if (SUCCEEDED (hr))
			{
				bReturn = TRUE;
			}
		}
	}
	
	pCtxMenu->Release();
	
	return bReturn;
}

void CRecycleBinDlg::Undelete (int iItem)
{
	ExecCommand (iItem, _T("undelete"));
}

void CRecycleBinDlg::OnProperty() 
{
	POSITION pos = m_List.GetFirstSelectedItemPosition ();
	int iItem = m_List.GetNextSelectedItem (pos);
	
	ExecCommand (iItem, _T("properties"));
	m_List.SetItemState (iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED);
	m_List.SetFocus ();
}

void CRecycleBinDlg::OnUndelete() 
{
	POSITION pos = m_List.GetFirstSelectedItemPosition ();
	int iItem = m_List.GetNextSelectedItem (pos);
	
	Undelete (iItem);
}

void CRecycleBinDlg::OnUndeleteall() 
{
	int iPos = 0;
	int iMax = m_List.GetItemCount ();

	for (iPos = 0 ; iPos < iMax ; iPos ++)
	{
		Undelete (0);
	}
}

void CRecycleBinDlg::OnEmptyDrive (UINT uiID)
{
	CString strItem;

	if (TRUE == m_Empty.GetMenuItem (uiID, strItem))
	{
		HRESULT hr = S_OK;

		if (0 == strItem.Compare (_T("Empty All")))
		{
			hr = SHEmptyRecycleBin (m_hWnd, NULL, 0);
		}
		else
		{
			hr = SHEmptyRecycleBin (m_hWnd, strItem, 0);
		}
	}
}

void CRecycleBinDlg::OnRclickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
	BOOL bReturn = FALSE;
	UINT nFlag = 0;
	CPoint curPoint;
	CRect rect;
	int iItem = -1;
	
	GetDlgItem(IDC_LIST)->GetWindowRect (&rect);
	if ((FALSE != GetCursorPos(&curPoint)) &&
		(FALSE != ::ScreenToClient (pNMHDR->hwndFrom , &curPoint)))
	{
		LPITEMIDLIST	pidl = NULL;
		LPCONTEXTMENU pCtxMenu = NULL;
		HRESULT hr = S_OK;

		iItem = m_List.HitTest (curPoint, &nFlag);
		if (0 <= iItem)
		{
			pidl = (LPITEMIDLIST)m_List.GetItemData (iItem);
			
			if (NULL != m_pFolder2)
			{
				hr = m_pFolder2->GetUIObjectOf (m_hWnd, 1, (LPCITEMIDLIST *)&pidl, IID_IContextMenu, NULL, (LPVOID *)&pCtxMenu);
			}
			else
			{
				hr = m_pRecycleBin->GetUIObjectOf (m_hWnd, 1, (LPCITEMIDLIST *)&pidl, IID_IContextMenu, NULL, (LPVOID *)&pCtxMenu);
			}
			
			if (SUCCEEDED (hr))
			{
				UINT uiID = UINT (-1);
				UINT uiCommand = 0;
				UINT uiMenuFirst = 1;
				UINT uiMenuLast = 0x00007FFF;
				HMENU hmenuCtx;
				int iMenuPos = 0;
				int iMenuMax = 0;
				
				hmenuCtx = CreatePopupMenu();
				hr = pCtxMenu->QueryContextMenu(hmenuCtx, 0, uiMenuFirst, uiMenuLast, CMF_NORMAL);
				
				// Correct the coordinates to show the menu on the right place
				curPoint.x += rect.left;
				curPoint.y += rect.top;
				uiCommand = TrackPopupMenu (hmenuCtx, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RETURNCMD, curPoint.x, curPoint.y, 0, m_hWnd, NULL);
				
				// If no command was selected, the return from TrackPopupMenu will be 0
				if (0 < uiCommand)
				{
					CMINVOKECOMMANDINFO cmi;
					
					ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
					cmi.cbSize			= sizeof(CMINVOKECOMMANDINFO);
					cmi.fMask			= 0;
					cmi.hwnd			= m_hWnd;
					cmi.lpParameters	= NULL;
					cmi.lpDirectory		= NULL;
					cmi.lpVerb			= MAKEINTRESOURCE (uiCommand - 1);
					cmi.nShow			= SW_SHOWNORMAL;
					cmi.dwHotKey		= NULL;
					cmi.hIcon			= NULL;
					hr = pCtxMenu->InvokeCommand(&cmi);
					
					if (SUCCEEDED (hr))
					{
						bReturn = TRUE;
					}
				}
			}
			
			pCtxMenu->Release();
		}
	}
	
	*pResult = 0;
}


void CRecycleBinDlg::OnChkrbin() 
{
	UpdateData (TRUE);
	if (TRUE == m_ChkRBin)
	{
		LPPIDLSTRUCT stPIDL;
		LPITEMIDLIST ppidl;
		pfSHChangeNotifyRegister SHChangeNotifyRegister;
		
		SHChangeNotifyRegister = (pfSHChangeNotifyRegister)GetProcAddress (m_hShell32, MAKEINTRESOURCE(2));
		
		if (NULL != SHChangeNotifyRegister)
		{
			if(SHGetSpecialFolderLocation(GetSafeHwnd(),CSIDL_BITBUCKET, &ppidl) != NOERROR)
			{
				AfxMessageBox(_T("GetSpecialFolder problem"));
			}
			stPIDL.pidlPath = ppidl;
			stPIDL.bWatchSubtree = TRUE;
			m_hNotifyRBin = SHChangeNotifyRegister (m_hWnd, 
				SHCNF_ACCEPT_INTERRUPTS | SHCNF_ACCEPT_NON_INTERRUPTS, 
				SHCNE_ALLEVENTS, 
				WM_SHELLNOTIFY,				/* Message that would be sent by the Shell */
				1,
				&stPIDL);
			if(NULL == m_hNotifyRBin)
			{
				TRACE(_T("Change Register Failed for RecycleBin"));
			}
		}
	}
	else
	{
		pfSHChangeNotifyDeregister SHChangeNotifyDeregister = (pfSHChangeNotifyDeregister)GetProcAddress(m_hShell32, MAKEINTRESOURCE(4));

		if (NULL != SHChangeNotifyDeregister)
		{
			BOOL bDeregister = SHChangeNotifyDeregister(m_hNotifyRBin);
		}
	}
}

void CRecycleBinDlg::OnChkfolders() 
{
	UpdateData (TRUE);
	
	if (TRUE == m_ChkFolders)
	{
		LPPIDLSTRUCT stPIDL;
		LPITEMIDLIST ppidl;
		pfSHChangeNotifyRegister SHChangeNotifyRegister = (pfSHChangeNotifyRegister)GetProcAddress (m_hShell32, MAKEINTRESOURCE(2));
		pfSHSimpleIDListFromPath SHSimpleIDListFromPath = (pfSHSimpleIDListFromPath)GetProcAddress (m_hShell32, MAKEINTRESOURCE (162));
		int				iPos		= 0;
		TCHAR			szPath[MAX_PATH];
		DWORD			dwSize		= GetLogicalDriveStrings(0, NULL);
		LPTSTR			pszDrives	= (LPTSTR)malloc((dwSize + 2) * sizeof (TCHAR));
		WIN32_FIND_DATA findData;
		HANDLE			hFindData	= INVALID_HANDLE_VALUE;
		ULONG			ulParsed	= 0L;
		ULONG			ulAttr		= 0L;
		HRESULT			hr			= S_OK;
		
		if (NULL != pszDrives)
		{
			LPTSTR pstr = pszDrives;
			SHQUERYRBINFO qrbi;
			
			GetLogicalDriveStrings((dwSize + 2) * sizeof (TCHAR),(LPTSTR)pszDrives);
			
			while (TCHAR ('\0') != *pstr)
			{
				ZeroMemory (&qrbi, sizeof (qrbi));
				qrbi.cbSize = sizeof (qrbi);
				hr = SHQueryRecycleBin (pstr, &qrbi);
				if (SUCCEEDED (hr))
				{
					ZeroMemory (&findData, sizeof (findData));
					wsprintf (szPath, _T("%sRecycler"), pstr);
					hFindData = FindFirstFile (szPath, &findData);
					if (INVALID_HANDLE_VALUE != hFindData)
					{
						ppidl = SHSimpleIDListFromPath (szPath);
						stPIDL.pidlPath = ppidl;
						m_pidlDrives[iPos] = ppidl;
						m_hNotifyDrives[iPos] = SHChangeNotifyRegister (m_hWnd, 
							SHCNF_ACCEPT_INTERRUPTS | SHCNF_ACCEPT_NON_INTERRUPTS, 
							SHCNE_RMDIR | SHCNE_RENAMEFOLDER | SHCNE_DELETE | SHCNE_RENAMEITEM, 
							WM_SHELLNOTIFYRBINDIR,
							1,
							&stPIDL);
						iPos ++;
						FindClose (hFindData);
					}
					else
					{
						ZeroMemory (&findData, sizeof (findData));
						wsprintf (szPath, _T("%sRecycled"), pstr);
						hFindData = FindFirstFile (szPath, &findData);
						if (INVALID_HANDLE_VALUE != hFindData)
						{
							ppidl = SHSimpleIDListFromPath (szPath);
							stPIDL.pidlPath = ppidl;
							m_pidlDrives[iPos] = ppidl;
							m_hNotifyDrives[iPos] = SHChangeNotifyRegister (m_hWnd, 
								SHCNF_ACCEPT_INTERRUPTS | SHCNF_ACCEPT_NON_INTERRUPTS, 
								SHCNE_RMDIR | SHCNE_RENAMEFOLDER | SHCNE_DELETE | SHCNE_RENAMEITEM, 
								WM_SHELLNOTIFYRBINDIR,
								1,
								&stPIDL);
							iPos ++;
							FindClose (hFindData);
						}
					}
				}
				pstr += _tcslen(pstr) + sizeof (TCHAR);
			}
			free (pszDrives);
		}
	}
	else
	{
		pfSHChangeNotifyDeregister SHChangeNotifyDeregister;
		
		SHChangeNotifyDeregister = (pfSHChangeNotifyDeregister)GetProcAddress(m_hShell32, MAKEINTRESOURCE(4));
		if (NULL != SHChangeNotifyDeregister)
		{
			LPMALLOC		pMalloc		= NULL;
			int iPos = 0;
			
			SHGetMalloc(&pMalloc); // windows memory management pointer needed later
			while (iPos < _countof (m_pidlDrives))
			{
				if (NULL != m_hNotifyDrives[iPos])
				{
					SHChangeNotifyDeregister(m_hNotifyDrives[iPos]);
				}
				if (NULL != m_pidlDrives[iPos])
				{
					pMalloc->Free (m_pidlDrives[iPos]);
				}
				iPos ++;
			}

			ZeroMemory (&m_pidlDrives, sizeof (m_pidlDrives));
			ZeroMemory (&m_hNotifyDrives, sizeof (m_hNotifyDrives));

			pMalloc->Release ();
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
France France
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions