// 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 ();
}
}
}