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

Shell编程

开发平台:

Visual C++

  1. // Folder.cpp : Implementation of CFolder
  2. #include "stdafx.h"
  3. #include "Folder.h"
  4. #include "View.h"
  5. #include "Misc.h"
  6. #include "ExtractIcon.h"
  7. #include "DropTarget.h"
  8. #include "DataObject.h"
  9. #include "ContextMenu.h"
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CComCoClass<CFolder> - COM registration
  12. BOOL CFolder::_FindAmigaDrive(LPTSTR pstrDevice)
  13. {
  14.    const int MAX_PHYSICAL_DRIVES = 6;
  15.    ATLASSERT(pstrDevice);
  16.    // Scan harddrives for an Amiga disk
  17.    // (excludes drive0 because it's likely it's the C: disk)
  18.    for( int i=1; i<MAX_PHYSICAL_DRIVES; i++ ) {
  19.       ::wsprintf(pstrDevice, _T("|H%d"), i);
  20. #ifdef _DEBUG
  21.       // DEBUG: We fake an Amiga harddisk in DEBUG mode
  22.       if( i==3 ) {
  23.          _tcscpy( pstrDevice, _T("C:\Temp\drive.adf") );
  24.          return TRUE;
  25.       }
  26. #endif
  27.       CAdfDevice dev;
  28.       if( dev.Open(pstrDevice, TRUE) ) return TRUE;
  29.    }
  30.    return FALSE;
  31. }
  32. HRESULT CFolder::_RegisterObject(CLSID clsid, UINT id, BOOL bRegister, _ATL_REGMAP_ENTRY *rm, LPCTSTR pstrDeviceName)
  33. {
  34.    HRESULT Hr;
  35.    HR( _Module.UpdateRegistryFromResource(id, bRegister, rm) );
  36.    if( !bRegister ) return S_OK;
  37.    // Uh, need to write additional attribute data to registry...
  38.    CRegKey reg;
  39.    OLECHAR szCLSID[64];
  40.    ::StringFromGUID2(clsid, szCLSID, lengthof(szCLSID));
  41.    TCHAR szSubKey[128];
  42.    LONG lResult;
  43.    
  44.    // Write DeviceName and Partition for Drive
  45.    ::wsprintf( szSubKey, _T("CLSID\%ls"), szCLSID);
  46.    lResult = reg.Open(HKEY_CLASSES_ROOT, szSubKey);
  47.    if( lResult!=ERROR_SUCCESS ) return E_FAIL;
  48.    if( (clsid==CLSID_Drive) && (pstrDeviceName!=NULL) ) {
  49.       reg.SetValue(pstrDeviceName, _T("DeviceName"));
  50.       reg.SetValue((DWORD)0L, _T("Partition"));
  51.    }
  52.    
  53.    // Write EditFlags to prevent Download Security dialog
  54. #define FTA_OpenIsSafe 0x00010000
  55.    DWORD dwFlags = FTA_OpenIsSafe;
  56.    lResult = ::RegSetValueEx(reg,
  57.                   _T("EditFlags"),
  58.                   0,
  59.                   REG_BINARY,
  60.                   (LPBYTE)&dwFlags,
  61.                   sizeof(dwFlags));
  62.    // Write ShellFolder attributes
  63.    ::wsprintf(szSubKey, _T("CLSID\%ls\ShellFolder"), szCLSID);
  64.    lResult = reg.Open(HKEY_CLASSES_ROOT, szSubKey);
  65.    if( lResult!=ERROR_SUCCESS ) return E_FAIL;
  66.    reg.SetValue(m_dwShellAttributes, _T("Attributes"));
  67.    return S_OK;
  68. }
  69. HRESULT WINAPI CFolder::UpdateRegistry(BOOL bRegister)
  70. {
  71.    CComBSTR bstrDescription;
  72.    CComBSTR bstrDriveDescription;
  73.    CComBSTR bstrProject;
  74.    CComBSTR bstrInfoTip;
  75.    CComBSTR bstrCLSID(CLSID_Folder);
  76.    CComBSTR bstrDriveCLSID(CLSID_Drive);
  77.    bstrDescription.LoadString(IDS_DESCRIPTION);
  78.    bstrDriveDescription.LoadString(IDS_DRIVEDESCRIPTION);
  79.    bstrProject.LoadString(IDS_PROJNAME);
  80.    bstrInfoTip.LoadString(IDS_INFOTIP);
  81.    _ATL_REGMAP_ENTRY rm[] = { 
  82.       { OLESTR("DESCRIPTION"), bstrDescription },
  83.       { OLESTR("PROJECTNAME"), bstrProject },
  84.       { OLESTR("CLSID"), bstrCLSID },
  85.       { OLESTR("INFOTIP"), bstrInfoTip },
  86.       { OLESTR("DRIVECLSID"), bstrDriveCLSID },
  87.       { OLESTR("DRIVEDESCRIPTION"), bstrDriveDescription },
  88.       { NULL,NULL } };
  89.    HRESULT Hr;
  90.    HR( _RegisterObject(CLSID_Folder, IDR_FOLDER, bRegister, rm, NULL) );
  91.    
  92.    // Process the CLSID_Drive registry entries
  93.    OSVERSIONINFO vi;
  94.    vi.dwOSVersionInfoSize = sizeof(vi);
  95.    ::GetVersionEx(&vi);
  96.    if( bRegister && (vi.dwPlatformId==VER_PLATFORM_WIN32_NT) ) {
  97.       // Register on >= WinNT: we can add a native drive if found
  98.       TCHAR szDevice[MAX_PATH];
  99.       if( _FindAmigaDrive(szDevice) ) {
  100.          HR( _RegisterObject(CLSID_Drive, IDR_DRIVE, bRegister, rm, szDevice) );
  101.       }
  102.   }
  103.    else if( !bRegister ) {
  104.       // Unregister - straight ahead
  105.       HR( _RegisterObject(CLSID_Drive, IDR_DRIVE, bRegister, rm, NULL) );
  106.    }
  107.    return S_OK;
  108. }
  109. /////////////////////////////////////////////////////////////////////////////
  110. // CFolder
  111. HRESULT CFolder::FinalConstruct()
  112. {
  113.    ATLTRACE(_T("CFolder::FinalConstructn"));
  114.    
  115.    // Get a unique folder ID
  116.    SYSTEMTIME st;
  117.    ::GetSystemTime(&st);   
  118.    m_dwFolderID = (st.wMilliseconds<<16) | (st.wSecond<<8) | (st.wMinute); 
  119.    // BUG: This is not unique. And it doesn't reflect the actual path!
  120.    m_bErrorShown = false;
  121.    
  122.    return S_OK;
  123. }
  124. void CFolder::FinalRelease()
  125. {
  126.    ATLTRACE(_T("CFolder::FinalReleasen"));
  127. }
  128. /////////////////////////////////////////////////////////////////////////////
  129. // Implementation
  130. // This helper function creates the actual PIDL entry
  131. // from the supplied arguments.
  132. LPITEMIDLIST CFolder::_CreateItem(
  133.                          LPCTSTR pstrName, 
  134.                          LPCTSTR pstrComment,
  135.                          PIDLTYPE pidlType, 
  136.                          int DosType,
  137.                          DWORD dwSize, 
  138.                          SYSTEMTIME ftTime,
  139.                          DWORD dwAccess,
  140.                          DWORD dwEntryFlags)
  141. {
  142.    ATLTRACE(_T("CFolder::_CreateItem '%s'n"), pstrName);
  143.    ATLASSERT(pstrName);
  144.    ATLASSERT(pidlType==PT_FOLDER || pidlType==PT_FILE);
  145.    UINT TypeID;
  146.    switch(pidlType) {
  147.    case PT_FOLDER: TypeID = IDS_FOLDER; break;
  148.    case PT_FILE: TypeID = IDS_FILE; break;
  149.    default: TypeID = IDS_UNKNOWN; break;
  150.    }
  151.    if( CAdfFile::_IsLink(DosType) ) TypeID = IDS_LINK;
  152.    if( dwEntryFlags & EF_DELETED ) TypeID = IDS_DELETEDENTRY;
  153.    PIDLDATA data = { 0 };
  154.    _tcsncpy(data.szName, pstrName, lengthof(data.szName)-1);
  155.    _tcsncpy(data.szComment, pstrComment==NULL ? _T("") : pstrComment, lengthof(data.szComment)-1);
  156.    data.type = pidlType;
  157.    data.iDosType = DosType;
  158.    ::LoadString(_Module.GetResourceInstance(), TypeID, data.szType, lengthof(data.szType)-1);
  159.    data.ftTime = ftTime;
  160.    data.dwSize = dwSize;
  161.    data.dwAccess = dwAccess;
  162.    data.dwEntryFlags = dwEntryFlags;
  163.    // Add PIDL
  164.    BYTE buf[ sizeof(PIDLDATA) + sizeof(ITEMIDLIST) ]; 
  165.    LPPIDLDATA pci = reinterpret_cast<LPPIDLDATA>(buf);
  166.    ::CopyMemory(pci, &data, sizeof(PIDLDATA));   
  167.    pci->cb = (WORD)sizeof(PIDLDATA);
  168.    pci->tag = PIDL_TAG;
  169.    // Terminate the IDList 
  170.    *(WORD *)(((LPBYTE)pci)+pci->cb) = 0;  
  171.    return CPidl::_Copy( (LPITEMIDLIST)pci ); 
  172. }
  173. SYSTEMTIME CFolder::_ConvertEntryTime(Entry *p)
  174. {
  175.    ATLASSERT(p);
  176.    SYSTEMTIME st;
  177.    st.wYear = (WORD)p->year;
  178.    st.wMonth = (WORD)p->month;
  179.    st.wDay = (WORD)p->days;
  180.    st.wHour = (WORD)p->hour;
  181.    st.wMinute = (WORD)p->mins;
  182.    st.wSecond = (WORD)p->secs;
  183.    st.wMilliseconds = 0;
  184.    st.wDayOfWeek = 0;
  185.    return st;
  186. }
  187. HRESULT CFolder::_CreateShellFolderView(LPVOID *ppvObj)
  188. {
  189.    ATLTRACE(_T("CFolder::_CreateShellFolderViewn"));
  190.    VALIDATE_OUT_POINTER(ppvObj);
  191.    HRESULT Hr;
  192.    CComObject<CView> *obj;
  193.    HR( CComObject<CView>::CreateInstance(&obj) );
  194.    HR( obj->_Init(this) );
  195.    return obj->QueryInterface(IID_IShellView, ppvObj);
  196. }
  197. // Bind To Parent.
  198. // Actually the W2K Shell supplies the ::SHBindToParent() function,
  199. // but we need it for other platforms too.
  200. HRESULT CFolder::_BindToParent(CComObject<CFolder> **pFolder)
  201. {
  202.    VALIDATE_OUT_POINTER(pFolder);
  203.    // Create the PIDL for the parent
  204.    CPidl pidl;
  205.    pidl.Copy(m_pidlPath);
  206.    pidl.RemoveLast();
  207.    // Bind it.
  208.    return _BindToObject(pidl, pFolder);
  209. }
  210. // Internal version of IShellFolder::BindToObject().
  211. // It allows us to bind to any folder.
  212. // The 'pidl' argument is a full PIDL path relative to the root (not desktop)!
  213. // Because we return a CComObject<CFolder> take good care to check reference count.
  214. HRESULT CFolder::_BindToObject(LPCITEMIDLIST pidl, CComObject<CFolder> **pFolder)
  215. {
  216.    ATLTRACE(_T("CFolder::_BindToObject '%s'n"), DbgGetPidlPath(pidl));
  217.    ATLASSERT(pFolder);
  218.    HRESULT Hr;
  219.    HR( CComObject<CFolder>::CreateInstance(pFolder) );
  220.    (*pFolder)->Initialize(m_pidl);  
  221.    (*pFolder)->m_pidlPath.Copy(pidl);
  222.    return S_OK;
  223. }
  224. short CFolder::_CompareItems(short iColumn, LPCPIDLDATA pData1, LPCPIDLDATA pData2)
  225. {
  226. #define COMPARE_INT(a,b) if(a!=b) return a>b ? (short)1 : (short)-1
  227.    // If data missing, default...
  228.    BOOL bIsEmpty1 = CPidl::_IsEmpty((LPCITEMIDLIST)pData1);
  229.    BOOL bIsEmpty2 = CPidl::_IsEmpty((LPCITEMIDLIST)pData2);
  230.    if( bIsEmpty1 && bIsEmpty2 ) return 0;
  231.    if( bIsEmpty1 ) return -1;
  232.    if( bIsEmpty2 ) return 1;
  233.    // Validate
  234.    ATLASSERT(pData1->tag==pData2->tag);
  235.    // Folders always come before files
  236.    if( pData1->type==PT_FOLDER && pData2->type==PT_FILE ) return -1;
  237.    if( pData1->type==PT_FILE && pData2->type==PT_FOLDER ) return 1;
  238.    // Compare item data (if data is equal, use filename to determine sort
  239.    // order).
  240.    switch( iColumn ) {
  241.    case COL_SIZE:
  242.       COMPARE_INT(pData1->dwSize, pData2->dwSize);
  243.       break;
  244.    case COL_TYPE:
  245.       return (short)_tcscmp(pData1->szType, pData2->szType);
  246.    case COL_TIME:
  247.       COMPARE_INT(pData1->ftTime.wYear, pData2->ftTime.wYear);
  248.       COMPARE_INT(pData1->ftTime.wMonth, pData2->ftTime.wMonth);
  249.       COMPARE_INT(pData1->ftTime.wDay, pData2->ftTime.wDay);
  250.       COMPARE_INT(pData1->ftTime.wHour, pData2->ftTime.wHour);
  251.       COMPARE_INT(pData1->ftTime.wMinute, pData2->ftTime.wMinute);
  252.       COMPARE_INT(pData1->ftTime.wSecond, pData2->ftTime.wSecond);
  253.       break;
  254.    case COL_ATTRIBS:
  255.       COMPARE_INT(pData1->dwAccess, pData2->dwAccess);
  256.       break;
  257.    }
  258.    return (short)_tcsicmp(pData1->szName, pData2->szName);
  259. #undef COMPARE_INT
  260. }
  261. /////////////////////////////////////////////////////////////////////////////
  262. // IShellFolder
  263. STDMETHODIMP CFolder::CreateViewObject(HWND hWnd, REFIID riid, LPVOID* ppRetVal)
  264. {
  265.    ATLTRACE(_T("CFolder::CreateViewObject %sn"), DbgGetIID(riid));
  266.    VALIDATE_OUT_POINTER(ppRetVal);
  267.    HRESULT Hr;
  268.    if( riid == IID_IDropTarget ) {
  269.       CComObject<CDropTarget> *pDropTarget;
  270.       HR( CComObject<CDropTarget>::CreateInstance(&pDropTarget) );
  271.       HR( pDropTarget->_Init(this, hWnd) );
  272.       return pDropTarget->QueryInterface(IID_IDropTarget, ppRetVal);
  273.    }
  274.    if( riid == IID_IContextMenu ) {
  275.       CComObject<CContextMenu> *pContextMenu;
  276.       HR( CComObject<CContextMenu>::CreateInstance(&pContextMenu) );
  277.       HR( pContextMenu->_Init(this, hWnd, NULL) );
  278.       return pContextMenu->QueryInterface(IID_IContextMenu, ppRetVal);
  279.    }
  280.    if( riid == IID_IShellView ) {
  281.       return _CreateShellFolderView(ppRetVal);
  282.    }
  283.    
  284.    return E_NOINTERFACE;
  285. }
  286. // Adds entries in a directory list to the PIDL list.
  287. void CFolder::_AddFolderToEnum(CPidl &pidl, List *cell, DWORD dwFlags, DWORD dwEntryFlags)
  288. {
  289.    while( cell!=NULL ) {
  290.       Entry *entry = (Entry *)cell->content;
  291.       
  292.       PIDLTYPE pidlType = PT_UNKNOWN;
  293.       switch( entry->type ) {
  294.       case ST_DIR:
  295.       case ST_LDIR:
  296.          if( dwFlags & SHCONTF_FOLDERS ) pidlType = PT_FOLDER;
  297.          break;
  298.       case ST_FILE:
  299.       case ST_LFILE:
  300.          if( dwFlags & SHCONTF_NONFOLDERS ) pidlType = PT_FILE;
  301.          break;
  302.       }
  303.       if( pidlType!=PT_UNKNOWN ) {
  304.          SYSTEMTIME st = _ConvertEntryTime(entry);
  305.          pidl.Concatenate( _CreateItem(
  306.             A2CT(entry->name), 
  307.             A2CT(entry->comment), 
  308.             pidlType, 
  309.             entry->type, 
  310.             entry->size, 
  311.             st,
  312.             entry->access,
  313.             dwEntryFlags) );
  314.       }
  315.       cell = cell->next;
  316.    }
  317. }
  318. // Adds entries in a deleted files list to the PIDL list.
  319. void CFolder::_AddDeletedToEnum(CPidl &pidl, List *cell, SECTNUM nDirSector, DWORD dwFlags, DWORD dwEntryFlags)
  320. {
  321.    while( cell!=NULL ) {
  322.       GenBlock *entry = (GenBlock *)cell->content;
  323.       cell = cell->next;
  324.       if( entry->parent != nDirSector ) continue;
  325.       PIDLTYPE pidlType = PT_UNKNOWN;
  326.       switch( entry->secType ) {
  327.       case ST_DIR:
  328.          if( dwFlags & SHCONTF_FOLDERS ) pidlType = PT_FOLDER;
  329.          break;
  330.       case ST_FILE:
  331.          if( dwFlags & SHCONTF_NONFOLDERS ) pidlType = PT_FILE;
  332.          break;
  333.       }
  334.       if( pidlType!=PT_UNKNOWN ) {
  335.          SYSTEMTIME st;
  336.          ::GetSystemTime(&st);
  337.          pidl.Concatenate( _CreateItem(
  338.             A2CT(entry->name), 
  339.             NULL, 
  340.             pidlType, 
  341.             entry->type, 
  342.             0,  // don't know the size yet
  343.             st,
  344.             0,
  345.             dwEntryFlags) );
  346.       }
  347.    }
  348. }
  349. STDMETHODIMP CFolder::EnumObjects(HWND hWnd, DWORD dwFlags, LPENUMIDLIST* ppRetVal)
  350. {
  351.    ATLTRACE(_T("CFolder::EnumObjectsn"));
  352.    VALIDATE_OUT_POINTER(ppRetVal);
  353.    // Open Amiga device.
  354.    // This is actually the first time we attempt to open the volume
  355.    // if the folder was just created.
  356.    HRESULT Hr;
  357.    CAdfDevice dev;
  358.    CAdfVolume vol;
  359.    Hr = _OpenAmigaDevice(m_pidl, TRUE, m_pidlPath, dev, vol);
  360.    if( FAILED(Hr) ) {
  361.       CResString<200> sText(IDS_DISKERROR);
  362.       CResString<64> sCaption(IDS_ERROR);
  363.       if( !m_bErrorShown ) ::MessageBox(hWnd, sText, sCaption, MB_OK|MB_ICONWARNING|MB_TASKMODAL);
  364.       m_bErrorShown = true;
  365.       return Hr;
  366.    }
  367.    CPidl pidl;
  368.    // Gather files from current directory
  369.    CAdfDirList list;
  370.    if( vol.GetCurrentDirctory(list)==FALSE ) return E_FAIL;
  371.    _AddFolderToEnum(pidl, list, dwFlags, 0);
  372.    // Check if we need to display 'deleted' files too
  373.    if( dwFlags & SHCONTF_INCLUDEDELETED ) {
  374.       // So add 'deleted' files to the list
  375.       CAdfDelList list;
  376.       if( vol.GetDeletedEntries(list)==FALSE ) return E_FAIL;
  377.       _AddDeletedToEnum(pidl, list, vol.GetDirectoryPtr(), dwFlags, EF_DELETED);
  378.    }
  379.    CComObject<CPidlEnum> *pEnum;
  380.    HR( CComObject<CPidlEnum>::CreateInstance(&pEnum) );
  381.    HR( pEnum->_Init( pidl, pidl.GetCount() ) );
  382.    HR( pEnum->QueryInterface(IID_IEnumIDList, (LPVOID *)ppRetVal) );
  383.    return S_OK;
  384. }
  385. STDMETHODIMP CFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  386. {
  387. #ifdef _DEBUG
  388.    TCHAR szName1[MAX_PATH];
  389.    TCHAR szName2[MAX_PATH];
  390.    _tcscpy( szName1, DbgGetPidlPath(pidl1) );
  391.    _tcscpy( szName2, DbgGetPidlPath(pidl2) );
  392.    ATLTRACE(_T("CFolder::CompareIDs (%d) '%s'<-->'%s'n"), lParam, szName1, szName2);
  393. #endif
  394.    // The lParam is used to determine whether to compare items or sub-items.
  395.    // We must compare the complete ITEMIDLIST.
  396.    while( pidl1!=NULL || pidl2!=NULL ) {
  397.       short lCmd = _CompareItems((short)lParam, (LPPIDLDATA)pidl1, (LPPIDLDATA)pidl2);
  398.       if( lCmd<0 ) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(-1));
  399.       if( lCmd>0 ) return MAKE_HRESULT(SEVERITY_SUCCESS, 0, USHORT(1));
  400.       pidl1 = CPidl::_GetNextItem(pidl1);
  401.       pidl2 = CPidl::_GetNextItem(pidl2);
  402.       if( CPidl::_IsEmpty(pidl1) ) pidl1=NULL;
  403.       if( CPidl::_IsEmpty(pidl2) ) pidl2=NULL;
  404.    }
  405.    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
  406. }
  407. STDMETHODIMP CFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  408. {
  409.    ATLTRACE(_T("CFolder::GetDisplayNameOf (%d) '%s'n"), uFlags, DbgGetPidlPath(pidl));
  410.    ATLASSERT(CPidl::_GetCount(pidl)==1);
  411.    LPCPIDLDATA pData = pidl_cast(pidl);
  412.    LPCTSTR pstrFileName = pData->szName;
  413. #ifdef _UNICODE
  414.    USES_CONVERSION;
  415.    // Allocate the wide character string 
  416.    int cchOleStr = ::lstrlen(pstrFileName) + 1;  
  417.    lpName->pOleStr = (LPWSTR)_Module.m_Allocator.Alloc(cchOleStr * sizeof(OLECHAR)); 
  418.    if( lpName->pOleStr==NULL ) return E_OUTOFMEMORY;  
  419.    lpName->uType = STRRET_WSTR;
  420.    ocscpy( lpName->pOleStr, T2CW(pstrFileName));
  421. #else
  422.    lpName->uType = STRRET_CSTR;
  423.    _tcscpy( lpName->cStr, pstrFileName);
  424. #endif
  425.    return S_OK;
  426. }
  427. STDMETHODIMP CFolder::GetAttributesOf(UINT nCount, LPCITEMIDLIST pidls[], LPDWORD rgfInOut)
  428. {
  429.    ATLTRACE(_T("CFolder::GetAttributesOf #%d, '%s'...n"), nCount, DbgGetPidlPath(pidls==NULL ? NULL : pidls[0]));
  430.    ATLASSERT(rgfInOut);
  431.    // Parse over all pidls and OR together attributes
  432.    DWORD dwAttr = 0;
  433.    if( nCount==0 ) {
  434.       // Can happen on Win95. Queries the view folder.
  435.      dwAttr |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE | SFGAO_DROPTARGET;
  436.    }
  437.    for( UINT i=0; i<nCount; i++ ) {
  438.       LPCPIDLDATA pData = pidl_cast(pidls[i]);
  439.       switch( pData->type ) {
  440.       case PT_FOLDER:
  441.          dwAttr |= SFGAO_FOLDER;
  442.          if( pData->dwEntryFlags & EF_DELETED ) {
  443.             dwAttr |= SFGAO_GHOSTED;
  444.          }
  445.          else {
  446.             dwAttr |= SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE | SFGAO_DROPTARGET | 
  447.                       SFGAO_HASPROPSHEET |
  448.                       SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME;
  449.             if( hasW(pData->dwAccess) ) dwAttr |= SFGAO_READONLY;
  450.             if( pData->iDosType==ST_LDIR ) dwAttr |= SFGAO_LINK;
  451.          }
  452.          break;
  453.       case PT_FILE:
  454.          if( pData->dwEntryFlags & EF_DELETED ) {
  455.             dwAttr |= SFGAO_GHOSTED;
  456.          }
  457.          else {
  458.             dwAttr |= SFGAO_HASPROPSHEET |
  459.                       SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME;
  460.             if( hasW(pData->dwAccess) ) dwAttr |= SFGAO_READONLY;
  461.             if( pData->iDosType==ST_LFILE ) dwAttr |= SFGAO_LINK;
  462.          }
  463.          break;
  464.       }
  465.    }
  466.    *rgfInOut = dwAttr & (*rgfInOut);
  467.    return S_OK;
  468. }
  469. STDMETHODIMP CFolder::SetNameOf(HWND, LPCITEMIDLIST pidl, LPCOLESTR pstrName, DWORD, LPITEMIDLIST *ppidlOut)
  470. {
  471.    ATLTRACE(_T("CFolder::SetNameOf '%s'n"), DbgGetPidlPath(pidl));
  472.    ATLASSERT(pidl);
  473.    ATLASSERT(pstrName);
  474.    USES_CONVERSION;
  475.    if( ppidlOut!=NULL ) *ppidlOut=NULL;
  476.    DWORD dwAttr = SFGAO_CANRENAME;
  477.    GetAttributesOf(1, &pidl, &dwAttr);
  478.    if( (dwAttr & SFGAO_CANRENAME)==0 ) return E_FAIL;
  479.    TCHAR szNewName[MAXNAMELEN+1];
  480.    if( wcslen(pstrName)>MAXNAMELEN ) return E_FAIL;
  481.    _tcscpy( szNewName, OLE2CT(pstrName));
  482.  
  483.    LPCPIDLDATA pOldData = pidl_cast(pidl);
  484.    CPidl pidlNew;
  485.    pidlNew.Attach( _CreateItem(
  486.       szNewName, 
  487.       pOldData->szComment, 
  488.       pOldData->type, 
  489.       pOldData->iDosType, 
  490.       pOldData->dwSize,
  491.       pOldData->ftTime,
  492.       pOldData->dwAccess,
  493.       pOldData->dwEntryFlags) );
  494.    HRESULT Hr;
  495.    HR( _RenameFile(pidl, pidlNew) );
  496.    if( ppidlOut!=NULL ) *ppidlOut = pidlNew.Detach();
  497.    return S_OK;
  498. }
  499. STDMETHODIMP CFolder::BindToObject(LPCITEMIDLIST pidl, LPBC, REFIID riid, LPVOID* ppRetVal)
  500. {
  501.    ATLTRACE(_T("CFolder::BindToObject '%s' %sn"), DbgGetPidlPath(pidl), DbgGetIID(riid));
  502.    VALIDATE_OUT_POINTER(ppRetVal);
  503.    
  504.    if( riid != IID_IShellFolder ) return E_NOINTERFACE;
  505.    CPidl pidlFull;
  506.    pidlFull.Copy(m_pidlPath);
  507.    pidlFull.Concatenate(pidl);
  508.    HRESULT Hr;
  509.    CComObject<CFolder> *pObj;
  510.    HR( _BindToObject(pidlFull, &pObj) );
  511.    return pObj->QueryInterface(riid, ppRetVal);
  512. }
  513. STDMETHODIMP CFolder::GetUIObjectOf(HWND hWnd, UINT nCount, LPCITEMIDLIST* pidls, REFIID riid, LPUINT, LPVOID* ppRetVal)
  514. {
  515.    ATLTRACE(_T("CFolder::GetUIObjectOf %s, #%d, '%s'...n"), DbgGetIID(riid), nCount, DbgGetPidlPath(pidls==NULL ? NULL : pidls[0]));
  516.    VALIDATE_OUT_POINTER(ppRetVal);
  517.    ATLASSERT(nCount>0);
  518.    if( nCount==0 ) return E_INVALIDARG;
  519.    HRESULT Hr;
  520.    if( riid == IID_IExtractIcon ) {
  521.       CComObject< CExtractIcon<const PIDLDATA> > *pExtractIcon;
  522.       HR( CComObject< CExtractIcon<const PIDLDATA> >::CreateInstance(&pExtractIcon) );
  523.       HR( pExtractIcon->_Init(*pidls) );
  524.       return pExtractIcon->QueryInterface(IID_IExtractIcon, ppRetVal);
  525.    }
  526.    if( riid == IID_IDropTarget ) {
  527.       if( nCount!=1 ) return E_FAIL;
  528.       // Need to create a IShellFolder for the subfolder
  529.       CComObject<CFolder> *pFolder;
  530.       CPidl pidl;
  531.       pidl.Copy(m_pidlPath);
  532.       pidl.Concatenate(pidls[0]);
  533.       HR( _BindToObject(pidl, &pFolder) );
  534.       // Do the bungy
  535.       CComObject<CDropTarget> *pDropTarget;
  536.       HR( CComObject<CDropTarget>::CreateInstance(&pDropTarget) );
  537.       HR( pDropTarget->_Init(pFolder, hWnd) );
  538.       return pDropTarget->QueryInterface(IID_IDropTarget, ppRetVal);
  539.    }
  540.    if( riid == IID_IContextMenu ) {
  541.       if( nCount!=1 ) return E_FAIL;
  542.       CComObject<CContextMenu> *pContextMenu;
  543.       HR( CComObject<CContextMenu>::CreateInstance(&pContextMenu) );
  544.       HR( pContextMenu->_Init(this, hWnd, pidls[0]) );
  545.       return pContextMenu->QueryInterface(IID_IContextMenu, ppRetVal);
  546.    }
  547.    if( riid == IID_IDataObject ) {
  548.       CComObject<CDataObject> *pDataObject;
  549.       HR( CComObject<CDataObject>::CreateInstance(&pDataObject) );
  550.       HR( pDataObject->_Init(this, hWnd, pidls, nCount) );
  551.       return pDataObject->QueryInterface(IID_IDataObject, ppRetVal);
  552.    }
  553.    return E_NOINTERFACE;
  554. }
  555. /////////////////////////////////////////////////////////////////////////////
  556. // IQueryInfo
  557. STDMETHODIMP CFolder::GetInfoFlags(DWORD *pdwFlags)
  558. {
  559.    VALIDATE_OUT_POINTER(pdwFlags);
  560.    *pdwFlags = 0;
  561.    return S_OK;
  562. }
  563. STDMETHODIMP CFolder::GetInfoTip(DWORD, LPWSTR *ppwszTip)
  564. {
  565.    VALIDATE_OUT_POINTER(ppwszTip);
  566.    CComBSTR bstr;
  567.    bstr.LoadString(IDS_INFOTIP);
  568.    *ppwszTip = (LPWSTR)_Module.m_Allocator.Alloc((bstr.Length()+1) * sizeof(WCHAR)); 
  569.    if( *ppwszTip==NULL ) return E_OUTOFMEMORY;  
  570.    USES_CONVERSION;
  571.    wcscpy(*ppwszTip, bstr);
  572.    return S_OK;
  573. }