View.cpp
上传用户:hy_wanghao
上传日期:2007-01-08
资源大小:279k
文件大小:36k
源码类别:

Shell编程

开发平台:

Visual C++

  1. // View.cpp : Implementation of CView
  2. #include "stdafx.h"
  3. #include "View.h"
  4. #include "Misc.h"
  5. #include "DropSource.h"
  6. #include "DataObject.h"
  7. #include "PropDlg.h"
  8. /////////////////////////////////////////////////////////////////////////////
  9. // CView
  10. HRESULT CView::FinalConstruct()
  11. {
  12.    ATLTRACE(_T("CView::FinalConstructn"));
  13.    // Win95 requires us to call ::OleInitialize() on the View because we use
  14.    // ::OleSetClipboard() and ::DoDragDrop() ???
  15.    // But we've already called it! The 2nd call is ignored on other platforms.
  16.    ::OleInitialize(NULL);
  17.    // Reset variables
  18.    m_pFolder = NULL;
  19.    m_hAccels = ::LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ACCELERATOR));
  20.    m_hMenu = NULL;
  21.    m_bInEdit = false;
  22.    m_bShowDeletedFiles = false;
  23.    m_dwListViewStyle = WS_TABSTOP | 
  24.                        WS_VISIBLE |
  25.                        WS_CHILD | 
  26.                        WS_BORDER | 
  27.                        LVS_REPORT |
  28.                        LVS_AUTOARRANGE |
  29.                        LVS_EDITLABELS |
  30.                        LVS_SHOWSELALWAYS |
  31.                        LVS_SHAREIMAGELISTS;
  32.    return S_OK;
  33. }
  34. void CView::FinalRelease()
  35. {
  36.    ATLASSERT(m_pFolder);
  37.    m_pFolder->Release();
  38.    ::OleUninitialize();
  39. }
  40. /////////////////////////////////////////////////////////////////////////////
  41. // IShellView
  42. STDMETHODIMP CView::CreateViewWindow(
  43.    IShellView *lpPrevView,
  44.    LPCFOLDERSETTINGS lpFS, 
  45.    IShellBrowser *pSB,
  46.    RECT *prcView, 
  47.    HWND *phWnd)
  48. {
  49.    ATLTRACE("CView::CreateViewWindown");
  50.    ATLASSERT(m_pFolder);
  51.    HRESULT Hr;
  52.    HR( IShellViewImpl<CView>::CreateViewWindow(lpPrevView, lpFS, pSB, prcView, phWnd) );
  53.    // Register view as drop target
  54.    LPDROPTARGET pDropTarget = NULL;
  55.    HR( m_pFolder->CreateViewObject(m_hWnd, IID_IDropTarget, (LPVOID *)&pDropTarget) );
  56.    HR( ::RegisterDragDrop(m_hwndList, pDropTarget) );
  57.    return S_OK;
  58. }
  59. STDMETHODIMP CView::DestroyViewWindow(void)
  60. {
  61.    ATLTRACE("CView::DestroyViewWindown");
  62.    ATLASSERT(::IsWindow(m_hwndList));
  63.    ::RevokeDragDrop(m_hwndList);
  64.    return IShellViewImpl<CView>::DestroyViewWindow();
  65. }
  66. STDMETHODIMP CView::GetItemObject(UINT uItem, REFIID riid, LPVOID *ppRetVal)
  67. {
  68.    ATLTRACE(_T("CView::GetItemObject %s (%d)n"), DbgGetIID(riid), uItem);
  69.    VALIDATE_OUT_POINTER(ppRetVal);
  70.    switch( uItem ) {
  71.    case SVGIO_BACKGROUND:
  72.       {
  73.          HRESULT Hr;
  74.          Hr = m_pFolder->CreateViewObject(NULL, riid, ppRetVal);
  75.          if( FAILED(Hr) ) Hr = m_pFolder->QueryInterface(riid, ppRetVal);
  76.          return Hr;
  77.       }
  78.    case SVGIO_SELECTION:
  79.       {
  80.          CPidlList pidls(m_hwndList);
  81.          return m_pFolder->GetUIObjectOf(m_hWnd, pidls.GetCount(), pidls, riid, NULL, ppRetVal);
  82.       }
  83.    case SVGIO_ALLVIEW:
  84.       {
  85.          CPidlList pidls(m_hwndList, LVNI_ALL);
  86.          return m_pFolder->GetUIObjectOf(m_hWnd, pidls.GetCount(), pidls, riid, NULL, ppRetVal);
  87.       }
  88.    default:
  89.       ATLASSERT(false);
  90.       return E_NOINTERFACE;
  91.    }
  92. }
  93. STDMETHODIMP CView::TranslateAccelerator(LPMSG pmsg)
  94. {
  95.    ATLASSERT(pmsg);
  96.    if( m_bInEdit ) {
  97.       if( (pmsg->message >= WM_KEYFIRST) && (pmsg->message <= WM_KEYLAST) ) {
  98.          ::TranslateMessage(pmsg);
  99.          ::DispatchMessage(pmsg);
  100.          return S_OK;
  101.       }
  102.    }
  103.    else {
  104.       if( ::TranslateAccelerator(m_hWnd, m_hAccels, pmsg) ) return S_OK;
  105.    }
  106.    return S_FALSE;
  107. }
  108. /////////////////////////////////////////////////////////////////////////////
  109. // Implementation
  110. HRESULT CView::_Init(CFolder *pFolder)
  111. {
  112.    ATLTRACE("CView::_Initn");
  113.    ATLASSERT(pFolder);
  114.    m_pFolder = pFolder;
  115.    m_pFolder->AddRef();
  116.    return S_OK;
  117. }
  118. // Sort List View item callback function.
  119. int CALLBACK CView::_ListViewSortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  120. {
  121.    LPCPIDLDATA pData1 = (LPCPIDLDATA)CPidl::_GetLastItem((LPCITEMIDLIST)lParam1);
  122.    LPCPIDLDATA pData2 = (LPCPIDLDATA)CPidl::_GetLastItem((LPCITEMIDLIST)lParam2);
  123.    return CFolder::_CompareItems((short)lParamSort, pData1, pData2);
  124. }
  125. // Setup ListView control
  126. // Adds column headers and clears all items.
  127. BOOL CView::_InitListView()
  128. {
  129.    ATLTRACE("CView::_InitListViewn");
  130.    // Empty the list
  131.    ListView_DeleteAllItems(m_hwndList);
  132.    // Initialize the columns
  133.    LV_COLUMN lvColumn;
  134.    CResString<64> str;
  135.    lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  136.    lvColumn.fmt = LVCFMT_LEFT;
  137.    lvColumn.pszText = str; // We reuse same buffer for all columns
  138.    str.LoadString(IDS_COL_NAME);
  139.    lvColumn.cx = 210;
  140.    ListView_InsertColumn(m_hwndList, COL_NAME, &lvColumn);
  141.    str.LoadString(IDS_COL_SIZE);
  142.    lvColumn.cx = 70;
  143.    lvColumn.fmt = LVCFMT_RIGHT;
  144.    ListView_InsertColumn(m_hwndList, COL_SIZE, &lvColumn);
  145.    str.LoadString(IDS_COL_TYPE);
  146.    lvColumn.cx = 80;
  147.    lvColumn.fmt = LVCFMT_LEFT;
  148.    ListView_InsertColumn(m_hwndList, COL_TYPE, &lvColumn);
  149.    str.LoadString(IDS_COL_MODIFIED);
  150.    lvColumn.cx = 130;
  151.    ListView_InsertColumn(m_hwndList, COL_TIME, &lvColumn);
  152.    if( m_ShellFlags.fShowAttribCol ) {
  153.       str.LoadString(IDS_COL_ATTR);
  154.       lvColumn.cx = 60;
  155.       lvColumn.fmt = LVCFMT_RIGHT;
  156.       ListView_InsertColumn(m_hwndList, COL_ATTRIBS, &lvColumn);
  157.    }
  158.    ListView_SetImageList(m_hwndList, _Module.m_ImageLists.m_hImageListLarge, LVSIL_NORMAL);
  159.    ListView_SetImageList(m_hwndList, _Module.m_ImageLists.m_hImageListSmall, LVSIL_SMALL);
  160.    return TRUE;
  161. }
  162. BOOL CView::_FillListView()
  163. {
  164.    ATLTRACE(_T("CView::_FillListViewn"));
  165.    DWORD dwFlags = SHCONTF_NONFOLDERS | SHCONTF_FOLDERS;
  166.    if( m_bShowDeletedFiles ) dwFlags |= SHCONTF_INCLUDEDELETED;
  167.    LPENUMIDLIST pEnumIDList;
  168.    if (SUCCEEDED(m_pFolder->EnumObjects(m_hWnd, dwFlags, &pEnumIDList) ) ) {
  169.       // Turn the listview's redrawing off
  170.       ::SendMessage(m_hwndList, WM_SETREDRAW, FALSE, 0L);
  171.       
  172.       DWORD dwFetched = 0;
  173.       LPITEMIDLIST pidl = NULL;
  174.       int iItem = 0;
  175.       while( (S_OK == pEnumIDList->Next(1, &pidl, &dwFetched)) && (dwFetched!=0) ) {
  176.          LPCPIDLDATA pData = pidl_cast(pidl);
  177.          LV_ITEM lvi = { 0 };
  178.          lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_PARAM;
  179.          lvi.pszText = LPSTR_TEXTCALLBACK;
  180.          lvi.iImage = I_IMAGECALLBACK;
  181.          lvi.iItem = iItem++;
  182.          lvi.state = 0;
  183.          if( pData->dwEntryFlags & EF_DELETED ) lvi.state |= LVIS_CUT;
  184.          lvi.stateMask = (UINT)-1;
  185.          lvi.lParam = (LPARAM)CPidl::_Copy(pidl);
  186.          ListView_InsertItem(m_hwndList, &lvi);
  187.       }
  188.       pEnumIDList->Release();
  189.       ListView_SortItems(m_hwndList, _ListViewSortFunc, 0);
  190.       // Turn the listview's redrawing back on and force it to draw
  191.       ::SendMessage(m_hwndList, WM_SETREDRAW, TRUE, 0L);
  192.       ::InvalidateRect(m_hwndList, NULL, TRUE);
  193.       ::UpdateWindow(m_hwndList);
  194.    }
  195.    return TRUE;
  196. }
  197. // Merge the toolbar
  198. BOOL CView::_MergeToolbar(UINT uState)
  199. {
  200.    ATLTRACE(_T("CView::_MergeToolbarn"));
  201.    ATLASSERT(m_pShellBrowser);
  202.    static NS_TOOLBUTTONINFO ToolBarItems[] =
  203.    {
  204.       TBI_STD, { STD_CUT,        ID_EDIT_CUT,        0, TBSTYLE_BUTTON, 0, 0 },
  205.       TBI_STD, { STD_COPY,       ID_EDIT_COPY,       0, TBSTYLE_BUTTON, 0, 0 },
  206.       TBI_STD, { STD_PASTE,      ID_EDIT_PASTE,      0, TBSTYLE_BUTTON, 0, 0 },
  207.       TBI_STD, { 0,              0,                  0, TBSTYLE_SEP,    0, 0 },
  208.       TBI_STD, { STD_DELETE,     ID_EDIT_DELETE,     0, TBSTYLE_BUTTON, 0, 0 },
  209.       TBI_STD, { STD_PROPERTIES, ID_EDIT_PROPERTIES, 0, TBSTYLE_BUTTON, 0, 0 },
  210.    };
  211.    // Don't unmerge toolbar; Shell will do it.
  212.    if( uState==SVUIA_DEACTIVATE ) return TRUE;
  213.    HRESULT Hr;
  214.    LRESULT lOffsetFile = 0;
  215.    LRESULT lOffsetView = 0;
  216.    LRESULT lOffsetCustom = 0;
  217.    Hr = m_pShellBrowser->SetToolbarItems(NULL, 0, FCT_MERGE);
  218.    // Add the toolbar bitmaps (use standard COMCTRL bitmaps)
  219.    TBADDBITMAP tbab;
  220.    tbab.hInst = HINST_COMMCTRL;
  221.    tbab.nID = IDB_STD_SMALL_COLOR;
  222.    Hr = m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 0, (LPARAM)&tbab, &lOffsetFile);
  223.    tbab.hInst = HINST_COMMCTRL;
  224.    tbab.nID = IDB_VIEW_SMALL_COLOR;
  225.    Hr = m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ADDBITMAP, 0, (LPARAM)&tbab, &lOffsetView);
  226.    // Add the buttons
  227.    BOOL res = _AppendToolbarItems(ToolBarItems, lengthof(ToolBarItems), 
  228.                                   lOffsetFile,lOffsetView,lOffsetCustom);
  229.    if( !res ) return FALSE;
  230.    _UpdateToolbar();
  231.    return TRUE;
  232. }
  233. // Updates the toolbar.
  234. BOOL CView::_UpdateToolbar()
  235. {   
  236.    ATLTRACE(_T("CView::_UpdateToolbarn"));
  237.    ATLASSERT(m_pShellBrowser);
  238.    ATLASSERT(::IsWindow(m_hwndList));
  239.    LPARAM lResult;
  240.    UINT nCount = ListView_GetSelectedCount(m_hwndList);
  241.    m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, ID_EDIT_COPY, MAKELPARAM(nCount!=0, 0), &lResult);
  242.    m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, ID_EDIT_CUT, MAKELPARAM(nCount!=0, 0), &lResult);
  243.    m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, ID_EDIT_PROPERTIES, MAKELPARAM(nCount==1, 0), &lResult);
  244.    m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, ID_EDIT_DELETE, MAKELPARAM(nCount!=0, 0), &lResult);
  245.    BOOL bClipboardCopy = _HasClipDataReady();
  246.    m_pShellBrowser->SendControlMsg(FCW_TOOLBAR, TB_ENABLEBUTTON, ID_EDIT_PASTE, MAKELPARAM(bClipboardCopy, 0), &lResult);
  247.    return TRUE;
  248. }
  249. // Merge our own menus into the Shell.
  250. // The 'uState' argument is called with SVUIA_DEACTIVATE
  251. // when the menus should be destroyed rather than created.
  252. BOOL CView::_MergeMenus(UINT uState)
  253. {
  254.    ATLTRACE(_T("CView::_MergeMenus (%d)n"), uState);
  255.    ATLASSERT(m_pShellBrowser);
  256.    typedef enum {
  257.       MENU_INDEX_FILE = 0,
  258.       MENU_INDEX_EDIT = 1,
  259.       MENU_INDEX_VIEW = 2,
  260.       MENU_INDEX_HELP = 3,
  261.    } MENUINDEX;
  262.    if( uState!=SVUIA_DEACTIVATE ) {
  263.       // Create the menu
  264.       // Some undocumented behaviour allows us to tell when the
  265.       // menu is merge when browsing solely in the folder tree or
  266.       // when to merge the view menu. There's a difference because
  267.       // the Explorer adds the "Delete", "Rename" etc items when
  268.       // you browse in the folder tree.
  269.       // We must look at the "uState": SVUIA_ACTIVATE_FOCUS means
  270.       // the view menu should be merged, SVUIA_ACTIVATE_NOFOCUS
  271.       // is the folder tree menu.
  272.       ATLASSERT(m_hMenu==NULL); // Don't merge twice without unmerge
  273.       if( m_hMenu!=NULL ) return FALSE;
  274.       // Load the menu we build the Shell menu from.
  275.       HMENU hSharedMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_MENU));
  276.       ATLASSERT(hSharedMenu);
  277.       // Merge the menus
  278.       m_hMenu = ::CreateMenu();
  279.       ATLASSERT(m_hMenu);
  280.       if( m_hMenu==NULL ) return FALSE;
  281.       OLEMENUGROUPWIDTHS omw = {0, 0, 0, 0, 0, 0};
  282.       m_pShellBrowser->InsertMenusSB(m_hMenu, &omw);
  283.       // Add top level sub-menus...
  284.       MENUITEMINFO mii = { 0 };
  285.       mii.cbSize = sizeof(mii);
  286.       mii.fMask = MIIM_SUBMENU;     
  287.       // Merge our items into the File menu
  288.       if( uState==SVUIA_ACTIVATE_FOCUS ) { 
  289.          if( ::GetMenuItemInfo(m_hMenu, FCIDM_MENU_FILE, FALSE, &mii)) {
  290.             HMENU hMenuPopup = ::GetSubMenu(hSharedMenu, MENU_INDEX_FILE);
  291.             _AppendMenu(mii.hSubMenu, hMenuPopup, 0);
  292.          }
  293.       }
  294.       // Merge our items into the Edit menu
  295.       if( uState==SVUIA_ACTIVATE_FOCUS ) {
  296.          if( ::GetMenuItemInfo(m_hMenu, FCIDM_MENU_EDIT, FALSE, &mii)) {
  297.             // Merge our menu
  298.             HMENU hMenuPopup = ::GetSubMenu(hSharedMenu, MENU_INDEX_EDIT);
  299.             _AppendMenu(mii.hSubMenu, hMenuPopup, 0);
  300.          }
  301.       }
  302.       // Merge our items into the View menu
  303.       if( ::GetMenuItemInfo(m_hMenu, FCIDM_MENU_VIEW, FALSE, &mii)) {
  304.          // Find the position of the Seperator
  305.          UINT nPos = _GetMenuPosFromID(mii.hSubMenu, FCIDM_MENU_VIEW_SEP_OPTIONS);
  306.          // and merge...
  307.          HMENU hMenuPopup = ::GetSubMenu(hSharedMenu, MENU_INDEX_VIEW);
  308.          _AppendMenu(mii.hSubMenu, hMenuPopup, nPos+1);
  309.       }
  310.       // Merge our items into the Help menu
  311.       if( ::GetMenuItemInfo(m_hMenu, FCIDM_MENU_HELP, FALSE, &mii)) {
  312.          // Merge our menu
  313.          HMENU hMenuPopup = ::GetSubMenu(hSharedMenu, MENU_INDEX_HELP);
  314.          _AppendMenu(mii.hSubMenu, hMenuPopup, 0);
  315.       }
  316.       m_pShellBrowser->SetMenuSB(m_hMenu, NULL, m_hWnd);
  317.       ::DestroyMenu(hSharedMenu);
  318.    }
  319.    else {
  320.       // Dismantle menu
  321.       m_pShellBrowser->SetMenuSB(NULL, NULL, NULL);
  322.       if( m_hMenu!=NULL ) {
  323.          ATLASSERT(::IsMenu(m_hMenu));
  324.          m_pShellBrowser->RemoveMenusSB(m_hMenu);
  325.          ::DestroyMenu(m_hMenu);
  326.          m_hMenu = NULL;
  327.       }
  328.    }
  329.    return TRUE;
  330. }
  331. // Updates the menu.
  332. // This function is usually called when the user opens one of the
  333. // Shell menus. The HMENU argument is the handled to the opened menu.
  334. BOOL CView::_UpdateMenu(HMENU hMenu)
  335. {
  336.    ATLTRACE(_T("CView::_UpdateMenun"));
  337.    if( !::IsMenu(hMenu) ) return FALSE; // Gets called with our own File sub-menu popups?
  338.    // Deselect some menuitems if there are too many/few ListView items selected
  339.    UINT nCount = ListView_GetSelectedCount(m_hwndList);
  340.    ::EnableMenuItem(hMenu, ID_FILE_OPEN, nCount==1 ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  341.    ::EnableMenuItem(hMenu, ID_FILE_RENAME, nCount==1 ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  342.    ::EnableMenuItem(hMenu, ID_EDIT_PROPERTIES, nCount<=1 ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  343.    ::EnableMenuItem(hMenu, ID_EDIT_COPY, nCount!=0 ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  344.    ::EnableMenuItem(hMenu, ID_EDIT_CUT, nCount!=0 ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  345.    ::EnableMenuItem(hMenu, ID_EDIT_DELETE, nCount!=0 ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  346.    ::CheckMenuItem(hMenu, ID_VIEW_DELETEDFILES, m_bShowDeletedFiles ? MF_CHECKED | MF_BYCOMMAND : MF_UNCHECKED | MF_BYCOMMAND);
  347.    // Check the "View" menu
  348.    UINT idMenu = ID_VIEW_REPORT;
  349.    switch( m_FolderSettings.ViewMode ) {
  350.    case FVM_ICON:
  351.       idMenu = ID_VIEW_LARGEICONS;
  352.       break;
  353.    case FVM_SMALLICON:
  354.       idMenu = ID_VIEW_SMALLICONS;
  355.       break;
  356.    case FVM_LIST:
  357.       idMenu = ID_VIEW_LIST;
  358.       break;
  359.    case FVM_DETAILS:
  360.       idMenu = ID_VIEW_REPORT;
  361.       break;
  362.    }
  363.    ATLASSERT(ID_VIEW_LARGEICONS<ID_VIEW_REPORT);
  364.    ::CheckMenuRadioItem(hMenu, ID_VIEW_LARGEICONS, ID_VIEW_REPORT, idMenu, MF_BYCOMMAND);
  365.    BOOL bClipboardCopy = _HasClipDataReady();
  366.    ::EnableMenuItem(hMenu, ID_EDIT_PASTE, bClipboardCopy ? MF_ENABLED | MF_BYCOMMAND : MF_GRAYED | MF_BYCOMMAND);
  367.    return TRUE;
  368. }
  369. // Check that data exists on the clipboard for paste
  370. BOOL CView::_HasClipDataReady()
  371. {
  372.    BOOL bClipboardCopy = FALSE;
  373.    CComPtr<IDataObject> spDataObject;
  374.    if( SUCCEEDED( ::OleGetClipboard(&spDataObject) ) ) {
  375.       if( !bClipboardCopy ) {
  376.          FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  377.          if( SUCCEEDED( spDataObject->QueryGetData(&fe) ) ) {
  378.             bClipboardCopy = TRUE;
  379.          }
  380.       }
  381.       if( !bClipboardCopy ) {
  382.          FORMATETC fe = { _Module.m_CFSTR_FILEDESCRIPTOR, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  383.          if( SUCCEEDED( spDataObject->QueryGetData(&fe) ) ) {
  384.             bClipboardCopy = TRUE;
  385.          }
  386.       }
  387.       if( bClipboardCopy ) {
  388.          if( m_pFolder->_IsDroppedPathSame(spDataObject) ) bClipboardCopy = FALSE; 
  389.       }
  390.    }
  391.    return bClipboardCopy;
  392. }
  393. // This method handles both "Copy/Cut" menu-items and drag'n'drop
  394. // operations. In both cases we need to create an IDataObject object
  395. // and pass it to Windows.
  396. HRESULT CView::_DoCopyOperation(bool bDragDrop, bool bCut)
  397. {
  398.    ATLTRACE(_T("CView::_DoCopyOperationn"));
  399.    
  400.    // Get list from selected ListView items
  401.    CPidlList pidls(m_hwndList);
  402.    pidls.Filter(m_pFolder, bCut ? SFGAO_CANMOVE : SFGAO_CANCOPY);
  403.    if( pidls.GetCount()==0 ) return E_FAIL;
  404.    // Update the ListView to reflect the possible CUT operation.
  405.    // Remove all previous CUT items.
  406.    if( !bDragDrop ) ListView_SetItemState(m_hwndList, -1, 0, LVIS_CUT);
  407.    if( bCut ) {
  408.       // Now mark all selected items as CUT
  409.       int nItem = -1;
  410.       while( (nItem = ListView_GetNextItem(m_hwndList, nItem, LVNI_SELECTED)) != -1 ) {
  411.          ListView_SetItemState(m_hwndList, nItem, LVIS_CUT, LVIS_CUT);
  412.       }
  413.    }
  414.    // Create a IDataObject and let the system handle operation...
  415.    HRESULT Hr;
  416.    CComPtr<IDataObject> spDataObject;
  417.    Hr = m_pFolder->GetUIObjectOf(m_hWnd, 
  418.                                  pidls.GetCount(), 
  419.                                  pidls,
  420.                                  IID_IDataObject, 
  421.                                  NULL, 
  422.                                  (LPVOID*)&spDataObject);
  423.    if( SUCCEEDED(Hr) && (spDataObject!=NULL) ) {
  424.       if( bCut ) {
  425.          // If we're doing 'cut' in copy/cut/paste, we need
  426.          // to notify the IDataObject about our intention
  427.          DataObj_SetDWORD(spDataObject, _Module.m_CFSTR_PREFERREDDROPEFFECT, DROPEFFECT_MOVE);
  428.       }
  429.       if( bDragDrop ) {
  430.          // If we're dragging then call Window's DoDragDrop()
  431.          // method with a freshly created IDropSource object
  432.          CComObject<CDropSource> *pDropSource;
  433.          HR( CComObject<CDropSource>::CreateInstance(&pDropSource) );
  434.          pDropSource->AddRef();
  435.          DWORD dwEffect = 0;
  436.          Hr = ::DoDragDrop(spDataObject, 
  437.                            pDropSource, 
  438.                            DROPEFFECT_COPY | DROPEFFECT_MOVE, 
  439.                            &dwEffect);
  440.          // If the drag drop turned out to be a move operation, we should
  441.          // delete the files
  442.          if( (Hr==DRAGDROP_S_DROP) && (dwEffect & DROPEFFECT_MOVE) ) {
  443.             CPidlList pidls(m_hwndList);
  444.             m_pFolder->_DeleteFiles(pidls, pidls.GetCount());
  445.             ::OleSetClipboard(NULL);
  446.             Refresh();
  447.          }
  448.          pDropSource->Release();
  449.       }
  450.       else {
  451.          // In case of regular copy/cut/paste operatons, we
  452.          // simply need to put the IDataObject on the clipboard.
  453.          // The auto-ptr will release our reference on function
  454.          // exit.
  455.          ::OleSetClipboard(spDataObject);
  456.       }
  457.    }
  458.    _UpdateToolbar();
  459.    return S_OK;
  460. }
  461. /////////////////////////////////////////////////////////////////////////////
  462. // Message Handlers
  463. LRESULT CView::OnNotifyDispInfo(UINT /*CtlID*/, LPNMHDR lpnmh, BOOL& /*bHandled*/)
  464. {
  465.    USES_CONVERSION;
  466.    LV_DISPINFO *lpdi = (LV_DISPINFO *)lpnmh;
  467.    LPITEMIDLIST pidl = (LPITEMIDLIST)lpdi->item.lParam;
  468.    ATLASSERT(pidl);
  469.    lpdi->item.mask |= LVIF_DI_SETITEM;   // dont ask us again
  470.    if( lpdi->item.iSubItem>0 ) {  
  471.       // Sub-item information being requested.
  472.       // Is the text being requested?
  473.       if(lpdi->item.mask & LVIF_TEXT) {
  474.          
  475.          TCHAR szTemp[MAX_PATH];
  476.          LPCPIDLDATA pData = pidl_cast(pidl);
  477.          switch( lpdi->item.iSubItem ) {
  478.          case COL_SIZE:
  479.             if( pData->type==PT_FILE ) {
  480.                WCHAR szwTemp[32];
  481.                if( pData->dwEntryFlags & EF_DELETED ) {
  482.                   szwTemp[0] = L'';
  483.                }
  484.                else {
  485.                   LONGLONG longlong = pData->dwSize;
  486.                   ::StrFormatByteSizeW(longlong, szwTemp, lengthof(szwTemp));
  487.                }
  488.                _tcsncpy(lpdi->item.pszText, W2CT(szwTemp), lpdi->item.cchTextMax);
  489.             }
  490.             break;
  491.          case COL_TYPE:
  492.             _tcsncpy(lpdi->item.pszText, pData->szType, lpdi->item.cchTextMax);
  493.             break;
  494.          case COL_TIME:
  495.             {
  496.               TCHAR szDate[32];
  497.               TCHAR szTime[32];
  498.               ::GetDateFormat( LOCALE_USER_DEFAULT, DATE_SHORTDATE, &pData->ftTime, NULL, szDate, lengthof(szDate) );
  499.               ::GetTimeFormat( LOCALE_USER_DEFAULT, 0, &pData->ftTime, NULL, szTime, lengthof(szTime) );
  500.               ::wsprintf(szTemp, _T("%s %s"), szDate, szTime);
  501.               _tcsncpy(lpdi->item.pszText, szTemp, lpdi->item.cchTextMax);
  502.             };
  503.             break;
  504.          case COL_ATTRIBS:
  505.             {
  506.                // Construct attribute string
  507.                CAdfFile::ConvertAccess(pData->dwAccess, szTemp);
  508.                _tcsncpy(lpdi->item.pszText, szTemp, lpdi->item.cchTextMax);
  509.             };
  510.             break;
  511.          }
  512.       }
  513.    }
  514.    else {  
  515.       // The main item information is being requested
  516.       if( lpdi->item.mask & LVIF_TEXT ) {
  517.          STRRET str;
  518.          if(SUCCEEDED(m_pFolder->GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &str))) {
  519.             switch( str.uType ) {
  520.             case STRRET_WSTR:
  521.                _tcsncpy(lpdi->item.pszText, OLE2CT(str.pOleStr), lpdi->item.cchTextMax);               
  522.                _Module.m_Allocator.Free(str.pOleStr); // Delete the string
  523.                break;
  524.             case STRRET_CSTR:
  525.                _tcsncpy(lpdi->item.pszText, A2CT(str.cStr), lpdi->item.cchTextMax);
  526.                break;
  527.             default:
  528.                ATLASSERT(false);
  529.             }
  530.          }
  531.       }
  532.       if( lpdi->item.mask & LVIF_IMAGE ) {
  533.          IExtractIcon *pEI;
  534.          if( SUCCEEDED(m_pFolder->GetUIObjectOf(m_hWnd, 
  535.                                                 1, 
  536.                                                 (LPCITEMIDLIST *)&pidl, 
  537.                                                 IID_IExtractIcon, 
  538.                                                 NULL, 
  539.                                                 (LPVOID*)&pEI)) ) 
  540.          {
  541.             // GetIconLoaction will give us the index into our image list
  542.             UINT uFlags;
  543.             pEI->GetIconLocation(GIL_FORSHELL, NULL, 0, &lpdi->item.iImage, &uFlags);
  544.             ATLASSERT(uFlags & GIL_NOTFILENAME);
  545.             pEI->Release();
  546.          }
  547.       }
  548.    }
  549.    return 0;
  550. }
  551. LRESULT CView::OnHeaderClick(UINT /*CtlID*/, LPNMHDR lpnmh, BOOL& /*bHandled*/)
  552. {
  553.    ATLTRACE(_T("CView::OnHeaderClickn"));
  554.    NMHEADER *pnmh = (NMHEADER *)lpnmh; 
  555.    // Handle left-click only 
  556.    if( pnmh->iButton==0 ) { 
  557.       // Sort the list by the column that was clicked 
  558.       ListView_SortItems(m_hwndList, _ListViewSortFunc, pnmh->iItem);
  559.    } 
  560.    return 0;
  561. }
  562. LRESULT CView::OnDeleteItem(UINT /*CtlID*/, LPNMHDR lpnmh, BOOL& /*bHandled*/)
  563. {
  564.    // Delete the pidl because we made a copy of it
  565.    NM_LISTVIEW *lpnmlv = (NM_LISTVIEW *)lpnmh;
  566.    CPidl::_Delete((LPITEMIDLIST)lpnmlv->lParam);
  567.    return 0;
  568. }
  569. // Bring up Context Menu.
  570. LRESULT CView::OnContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  571. {
  572.    ATLTRACE(_T("CView::OnContextMenun"));
  573.    CPidl pidl;
  574.    UINT nCount = ListView_GetSelectedCount(m_hwndList);
  575.    if( nCount==0 ) {
  576.       // Nothing selected? Use the View menu then (see code below).
  577.    }
  578.    else {
  579.       // We don't support merging of menus when more than one item
  580.       // is selected, so the menu for the first item is shown.
  581.       CPidlList pidls(m_hwndList);
  582.       pidl.Copy(pidls[0]);
  583.    }
  584.    UINT resMenu = 0;
  585.    if( pidl.IsEmpty() ) {
  586.       resMenu = IDM_POPUP_VIEW;
  587.    }
  588.    else {
  589.       LPCPIDLDATA pData = pidl_cast((LPCITEMIDLIST)pidl);
  590.       if( pData->dwEntryFlags & EF_DELETED ) {
  591.          resMenu = IDM_POPUP_DELETED;
  592.       }
  593.       else {
  594.          switch( pData->type ) {
  595.          case PT_FOLDER:
  596.             resMenu = IDM_POPUP_FOLDER;
  597.             break;
  598.          case PT_FILE:
  599.             resMenu = IDM_POPUP_FILE;
  600.             break;
  601.          default:
  602.             ATLASSERT(""=="Invalid menu type");
  603.          }
  604.       }
  605.    }
  606.    // Prepare menu
  607.    POINT pt = { LOWORD(lParam), HIWORD(lParam) };
  608.    if( lParam==-1 ) {
  609.       // Windows sends -1 as lParam when using SHIFT+F10 to activate context menu
  610.       RECT rc;
  611.       ListView_GetItemRect(m_hwndList, ListView_GetNextItem(m_hwndList, -1, LVNI_SELECTED), &rc, LVIR_ICON);
  612.       pt.x = rc.left + ((rc.right-rc.left)/2);
  613.       pt.y = rc.top + ((rc.bottom-rc.top)/2);
  614.       ::ClientToScreen(m_hwndList, &pt);
  615.    }
  616.    HMENU hMenu = ::LoadMenu(_Module.GetResourceInstance(), MAKEINTRESOURCE(resMenu));
  617.    ATLASSERT(::IsMenu(hMenu));
  618.    HMENU hSubMenu = ::GetSubMenu(hMenu,0);
  619.    // Let generic menu-updater handle popup too...
  620.    _UpdateMenu(hSubMenu);
  621.    // Show popup menu
  622.    ::SetMenuDefaultItem(hSubMenu, ID_FILE_OPEN, FALSE);
  623.    ::SetForegroundWindow(m_hWnd);
  624.    ::TrackPopupMenu(hSubMenu,
  625.                     TPM_LEFTALIGN|TPM_LEFTBUTTON,
  626.                     pt.x, pt.y,
  627.                     0,
  628.                     m_hWnd,
  629.                     NULL);
  630.    ::DestroyMenu(hMenu);
  631.    // Reset statusbar
  632.    OnItemChanged(0,NULL,bHandled);
  633.    return 0;
  634. }
  635. LRESULT CView::OnItemActivated(UINT /*CtlID*/, LPNMHDR /*lpnmh*/, BOOL& bHandled)
  636. {
  637.    ATLTRACE(_T("CView::OnItemActivatedn"));
  638.    return OnFileOpen(0,0,0,bHandled);
  639. }
  640. LRESULT CView::OnLabelEditBegin(UINT /*CtlID*/, LPNMHDR lpnmh, BOOL& /*bHandled*/)
  641. {
  642.    ATLTRACE(_T("CView::OnLabelEditBeginn"));
  643.    NMLVDISPINFO *lpdi = (NMLVDISPINFO*)lpnmh;
  644.    DWORD dwAttr = SFGAO_CANRENAME;
  645.    m_pFolder->GetAttributesOf(1, (LPCITEMIDLIST*)&lpdi->item.lParam, &dwAttr);
  646.    if( (dwAttr & SFGAO_CANRENAME)==0 ) return TRUE;
  647.    m_bInEdit = true;
  648.    return FALSE; // Allow edit!
  649. }
  650. LRESULT CView::OnLabelEditEnd(UINT /*CtlID*/, LPNMHDR lpnmh, BOOL& /*bHandled*/)
  651. {
  652.    ATLTRACE(_T("CView::OnLabelEditEndn"));
  653.    NMLVDISPINFO *lpdi = (NMLVDISPINFO*)lpnmh;
  654.    m_bInEdit = false;
  655.    if( lpdi->item.pszText==NULL ) return FALSE; // User cancelled editing
  656.    LVITEM lvItem = { 0 };
  657.    lvItem.mask = LVIF_PARAM;
  658.    lvItem.iItem = lpdi->item.iItem;
  659.    ListView_GetItem(m_hwndList, &lvItem);
  660.    LPITEMIDLIST pidlOldItem = (LPITEMIDLIST)lvItem.lParam;
  661.    // The IShellFolder handles the actual rename...
  662.    USES_CONVERSION;
  663.    LPCWSTR pwstr = T2CW(lpdi->item.pszText);
  664.    LPITEMIDLIST pidlNewItem = NULL;
  665.    HRESULT Hr = m_pFolder->SetNameOf(NULL, pidlOldItem, pwstr, 0, &pidlNewItem);
  666.    if( FAILED(Hr) || (pidlNewItem==NULL) ) {
  667.       ::MessageBeep(MB_ICONEXCLAMATION);
  668.       return FALSE;
  669.    }
  670.    // Set the new PIDL structure
  671.    lvItem.mask = LVIF_PARAM;
  672.    lvItem.lParam = (LPARAM)pidlNewItem;
  673.    ListView_SetItem(m_hwndList, &lvItem);
  674.    CPidl::_Delete(pidlOldItem);
  675.    return TRUE; // Accept rename
  676. }
  677. LRESULT CView::OnBeginDrag(UINT /*CtlID*/, LPNMHDR /*lpnmh*/, BOOL& /*bHandled*/)
  678. {
  679.    ATLTRACE(_T("CView::OnBeginDragn"));
  680.    _DoCopyOperation(true, false);
  681.    return TRUE;
  682. }
  683. LRESULT CView::OnItemChanged(UINT /*CtlID*/, LPNMHDR /*lpnmh*/, BOOL& /*bHandled*/)
  684. {
  685.    ATLTRACE(_T("CView::OnItemChangedn"));
  686.    ATLASSERT(m_pShellBrowser);
  687.    // Set the status bar text
  688.    TCHAR szText[64] = { 0 };
  689.    UINT nCount = ListView_GetSelectedCount(m_hwndList);
  690.    if( nCount>0 ) {
  691.       // Show "x object(s) selected" message
  692.       CResString<64> sFormat(IDS_OBJECTSELECTED);
  693.       ::wsprintf(szText, sFormat, nCount);
  694.    }
  695.    USES_CONVERSION;
  696.    m_pShellBrowser->SetStatusTextSB(T2CW(szText));
  697.    _UpdateToolbar();
  698.    return TRUE;
  699. }
  700. LRESULT CView::OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  701. {
  702.    ATLTRACE(_T("CView::OnMenuSelectn"));
  703.    ATLASSERT(m_pShellBrowser);
  704.    WORD wFlags = HIWORD(wParam);
  705.    if( wFlags==0xFFFF && lParam==NULL ) {
  706.       bHandled = FALSE;
  707.       return 1; // Menu closing!
  708.    }
  709.    CResString<80> sText(LOWORD(wParam));
  710.    if( _tcslen(sText)==0 ) {
  711.       bHandled = FALSE;
  712.       return 1; // No text. Not processed!
  713.    }
  714.    LRESULT lResult;
  715.    m_pShellBrowser->SendControlMsg(FCW_STATUS, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)(LPCTSTR)sText, &lResult);
  716.    return 0;
  717. }
  718. /////////////////////////////////////////////////////////////////////////////
  719. // Message Command Handlers
  720. LRESULT CView::OnNewFolder(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  721. {
  722.    // Create a new folder right away
  723.    CResString<MAXNAMELEN> sName(IDS_NEWFOLDER);
  724.    DWORD dwFileOpFlags = CFolder::FILEOP_UNIQUENAME;
  725.    if( FAILED( m_pFolder->_CreateFolder(sName, &dwFileOpFlags) ) ) return 0;
  726.    Refresh();
  727.    // Get new PIDL structure
  728.    LVFINDINFO fi = { 0 };
  729.    fi.flags = LVFI_STRING;
  730.    fi.psz = sName;
  731.    int iItem = ListView_FindItem(m_hwndList, -1, &fi);
  732.    ATLASSERT(iItem!=-1);
  733.    LVITEM lvItem = { 0 };
  734.    lvItem.mask = LVIF_PARAM;
  735.    lvItem.iItem = iItem;
  736.    ListView_GetItem(m_hwndList, &lvItem);
  737.    // Notify Shell so it can create the folder in the Explorer tree
  738.    CPidl pidl;
  739.    pidl.Copy(m_pFolder->m_pidl);
  740.    pidl.Concatenate(m_pFolder->m_pidlPath);
  741.    pidl.Concatenate((LPCITEMIDLIST)lvItem.lParam);
  742.    ::SHChangeNotify(SHCNE_MKDIR, SHCNF_IDLIST | SHCNF_FLUSH, pidl, NULL);
  743.    // Put ListView item in edit mode...
  744.    ::SetFocus(m_hwndList);
  745.    ListView_EditLabel(m_hwndList, iItem);
  746.    return 0;
  747. }
  748. LRESULT CView::OnFileOpen(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  749. {
  750.    ATLASSERT(m_pShellBrowser);
  751.    CPidlList pidls(m_hwndList);
  752.    pidls.Filter(m_pFolder, SFGAO_BROWSABLE);
  753.    if( pidls.GetCount()==0 ) return 0;
  754.    CPidl pidl;
  755.    pidl.Copy( m_pFolder->m_pidl );
  756.    pidl.Concatenate( m_pFolder->m_pidlPath );
  757.    pidl.Concatenate( pidls[0] );
  758.    m_pShellBrowser->BrowseObject(pidl, SBSP_DEFBROWSER | SBSP_ABSOLUTE);
  759.    return 0;
  760. }
  761. LRESULT CView::OnFileRename(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  762. {
  763.    UINT nCount = ListView_GetSelectedCount(m_hwndList);
  764.    if( nCount!=1 ) return 0;
  765.    // Put the ListView into edit mode
  766.    ::SetFocus(m_hwndList);
  767.    int nItem;
  768.    if( (nItem = ListView_GetNextItem(m_hwndList, -1, LVNI_SELECTED)) != -1 ) {
  769.       ListView_EditLabel(m_hwndList, nItem);
  770.    }
  771.    return 0;
  772. }
  773. LRESULT CView::OnFileUndelete(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  774. {
  775.    CPidlList pidls(m_hwndList);
  776.    pidls.Filter(m_pFolder, SFGAO_GHOSTED);
  777.    if( pidls.GetCount()==0 ) return 0;
  778.    m_pFolder->_UnDeleteFiles(pidls, pidls.GetCount());
  779.    Refresh();
  780.    return 0;
  781. }
  782. LRESULT CView::OnGoUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  783. {
  784.    ATLASSERT(m_pShellBrowser);
  785.    m_pShellBrowser->BrowseObject(NULL, SBSP_SAMEBROWSER | SBSP_PARENT);
  786.    return 0;
  787. }
  788. LRESULT CView::OnViewDeletedFiles(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  789. {
  790.    m_bShowDeletedFiles = !m_bShowDeletedFiles;
  791.    Refresh();
  792.    return 0;
  793. }
  794. LRESULT CView::OnViewChange(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  795. {
  796.    int dwListStyle = LVS_REPORT;
  797.    int dwViewMode = FVM_DETAILS;
  798.    switch( wID ) {
  799.    case ID_VIEW_REPORT:
  800.       dwListStyle = LVS_REPORT;
  801.       dwViewMode = FVM_DETAILS;
  802.       break;
  803.    case ID_VIEW_LARGEICONS:
  804.       dwListStyle = LVS_ICON;
  805.       dwViewMode = FVM_ICON;
  806.       break;
  807.    case ID_VIEW_SMALLICONS:
  808.       dwListStyle = LVS_SMALLICON;
  809.       dwViewMode = FVM_SMALLICON;
  810.       break;
  811.    case ID_VIEW_LIST:
  812.       dwListStyle = LVS_LIST;
  813.       dwViewMode = FVM_LIST;
  814.       break;
  815.    }
  816.    // Change the FolderSettings and change ListView control
  817.    m_FolderSettings.ViewMode = dwViewMode;
  818.    DWORD dwStyle = ::GetWindowLong(m_hwndList, GWL_STYLE);
  819.    dwStyle &= ~LVS_TYPEMASK;
  820.    dwStyle |= dwListStyle;
  821.    ::SetWindowLong(m_hwndList, GWL_STYLE, dwStyle);
  822.    // Need to update toolbar as well
  823.    _UpdateToolbar();
  824.    return 0;
  825. }
  826. LRESULT CView::OnShowHelp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  827. {
  828.    TCHAR szFileName[MAX_PATH];
  829.    ::GetModuleFileName(_Module.GetModuleInstance(), szFileName, lengthof(szFileName));
  830.    ::PathRemoveExtension(szFileName);
  831.    ::PathAddExtension(szFileName, _T(".hlp"));
  832.    ::WinHelp(m_hWnd, szFileName, HELP_CONTENTS, 0);
  833.    return 0;
  834. }
  835. LRESULT CView::OnRefresh(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  836. {
  837.    Refresh();
  838.    return 0;
  839. }
  840. LRESULT CView::OnFileProperties(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  841. {
  842.    UINT nCount = ListView_GetSelectedCount(m_hwndList);
  843.    if( nCount==0 ) {
  844.       // Show the View's Properties
  845.       if( m_pFolder->m_pidlPath.IsEmpty() ) {
  846.          // Show properties for root!
  847.          // We basically bring up the standard Property Pages for the ADF file.
  848.          SHELLEXECUTEINFO sei = { 0 };
  849.          sei.cbSize = sizeof(sei);
  850.          sei.hwnd = m_hWnd;
  851.          sei.fMask = SEE_MASK_IDLIST | SEE_MASK_INVOKEIDLIST;
  852.          sei.lpIDList = m_pFolder->m_pidl;
  853.          sei.lpVerb = _T("properties");
  854.          sei.nShow = SW_SHOWNORMAL;
  855.          ::ShellExecuteEx(&sei);
  856.       }
  857.       else {
  858.          // Show properties for active folder
  859.          CPropertiesDlg dlg;
  860.          if( SUCCEEDED(dlg._Init(m_pFolder, NULL)) ) {
  861.             if( dlg.DoModal()==IDOK ) {
  862.                Refresh();
  863.             }
  864.          }
  865.       }
  866.    }
  867.    else {
  868.       CPidlList pidls(m_hwndList);
  869.       pidls.Filter(m_pFolder, SFGAO_HASPROPSHEET);
  870.       if( pidls.GetCount()==0 ) return 0;
  871.       // Show the Folder/File Properties
  872.       switch( PidlGetType(pidls[0]) ) {
  873.       case PT_FOLDER:
  874.       case PT_FILE:
  875.          {
  876.             CPropertiesDlg dlg;
  877.             if( SUCCEEDED( dlg._Init(m_pFolder, pidls[0])) ) {;
  878.                if( dlg.DoModal()==IDOK ) {
  879.                   Refresh();
  880.                }
  881.             }
  882.          }
  883.          break;
  884.       default:
  885.          ATLASSERT(""=="Invalid property page request");
  886.       }
  887.    }
  888.    return 0;
  889. }
  890. LRESULT CView::OnFileDelete(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  891. {
  892.    ATLASSERT(m_pFolder);
  893.    CPidlList pidls(m_hwndList);
  894.    pidls.Filter(m_pFolder, SFGAO_CANDELETE);
  895.    if( pidls.GetCount()==0 ) return 0;
  896.    // Complex task of putting up a confirmation dialog...
  897.    if( m_ShellFlags.fNoConfirmRecycle==0 ) {
  898.       DWORD dwFlags = 0;
  899.       if( m_pFolder->_ConfirmDelete(pidls, pidls.GetCount(), &dwFlags)==IDNO ) return 0;
  900.    }
  901.    m_pFolder->_DeleteFiles(pidls, pidls.GetCount());
  902.    Refresh();
  903.    ::SetFocus(m_hwndList);
  904.    return 0;
  905. }
  906. LRESULT CView::OnCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  907. {
  908.    _DoCopyOperation(false,false);
  909.    return 0;
  910. }
  911. LRESULT CView::OnCut(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  912. {
  913.    _DoCopyOperation(false,true);
  914.    return 0;
  915. }
  916. LRESULT CView::OnPaste(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  917. {
  918.    CComPtr<IDataObject> spDataObject;    
  919.    if( SUCCEEDED( ::OleGetClipboard(&spDataObject) ) ) {     
  920.       
  921.       // We attempt to do an "non-optimized move".
  922.       // The formal communication when doing the paste, is to let the
  923.       // IDataObject know about the success of the paste operation.
  924.       // MSDN explains the procedures...
  925.       FORMATETC fe = { _Module.m_CFSTR_PREFERREDDROPEFFECT, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  926.       STGMEDIUM med;
  927.       HRESULT HrHadData = spDataObject->GetData(&fe, &med);
  928.       if( SUCCEEDED(HrHadData) ) {
  929.          fe.cfFormat = _Module.m_CFSTR_PERFORMEDDROPEFFECT;
  930.          spDataObject->SetData(&fe,&med,FALSE);
  931.       }
  932.       // Handle drop
  933.       HRESULT Hr;
  934.       Hr = m_pFolder->_DoDrop(spDataObject, DROPEFFECT_COPY);
  935.       // Tell the IDataObject if we succeeded
  936.       if( Hr==S_OK ) {
  937.          // We ask the IDataObject to delete the items (if we're moving files)
  938.          if( SUCCEEDED(HrHadData) ) {
  939.             fe.cfFormat = _Module.m_CFSTR_PASTESUCCEEDED;
  940.             spDataObject->SetData(&fe,&med,FALSE);
  941.          }
  942.       }
  943.       else if( Hr==S_FALSE ) {
  944.          // Do something! Anything!
  945.       }
  946.       else {         
  947.          ::MessageBeep(MB_ICONEXCLAMATION);
  948.       }
  949.       if( SUCCEEDED(HrHadData) ) ::ReleaseStgMedium(&med);
  950.       Refresh();
  951.    }
  952.    return 0;
  953. }
  954. LRESULT CView::OnSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  955. {
  956.    ::SetFocus(m_hwndList);
  957.    ListView_SetItemState(m_hwndList, -1, LVIS_SELECTED, LVIS_SELECTED);
  958.    return 0;
  959. }
  960. LRESULT CView::OnInvertSelection(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
  961. {
  962.    ::SetFocus(m_hwndList);
  963.    int nItem = -1;
  964.    while( (nItem = ListView_GetNextItem(m_hwndList, nItem, LVNI_ALL)) != -1 ) {
  965.       UINT state = ListView_GetItemState(m_hwndList, nItem, LVIS_SELECTED);
  966.       ListView_SetItemState(m_hwndList, nItem, (state ^ LVIS_SELECTED), LVIS_SELECTED);
  967.    }
  968.    return 0;
  969. }