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

Shell编程

开发平台:

Visual C++

  1. // DragDrop.cpp : Implementation of CFolder's drag'n'drop functions
  2. #include "stdafx.h"
  3. #include "Folder.h"
  4. #include "Misc.h"
  5. #include "DataObject.h"
  6. /////////////////////////////////////////////////////////////////////////////
  7. // CFolder
  8. // Check if the Window handle belongs to a CView view.
  9. // We can do this because we know the Windows classname of the view window.
  10. BOOL CFolder::_IsViewWindow(HWND hWnd)
  11. {
  12.    if( !::IsWindow(hWnd) ) return FALSE;
  13.    CResString<64> sViewClassName(IDS_CLASSNAME);
  14.    TCHAR szClassName[64];
  15.    ::GetClassName(hWnd, szClassName, lengthof(szClassName));
  16.    return( _tcsicmp(szClassName, sViewClassName)==0 );
  17. }
  18. // Sends a Windows message to a possible CView window.
  19. // The method doesn't guarantee that the message is sent if the passed
  20. // HWND handle is not a CView window.
  21. // Returns:
  22. //   TRUE   - the message was successfully sent
  23. //   FALSE  - the window was not a CView window. Message not sent.
  24. BOOL CFolder::_SendViewMessage(HWND hWnd, UINT iMsg, WPARAM wParam/*=0*/, LPARAM lParam/*=0*/)
  25. {
  26.    if( !_IsViewWindow(hWnd) ) return FALSE;
  27.    ::SendMessage(hWnd, iMsg, wParam, lParam);
  28.    return TRUE;
  29. }
  30. // Check if the IDataObject originates from this folder.
  31. // We use the internal ADFID clipboard format to determine this.
  32. BOOL CFolder::_IsDroppedPathSame(LPDATAOBJECT pDataObj)
  33. {
  34.    ATLASSERT(pDataObj);
  35.    // Query the IDataObject for the private clipboard format "AdfID".
  36.    // Only folders from "ADF View" will know about it and return a
  37.    // folder ID...
  38.    DWORD dwFolderID;
  39.    HRESULT Hr = DataObj_GetDWORD(pDataObj, _Module.m_CFSTR_ADFID, &dwFolderID);
  40.    if( FAILED(Hr) ) return FALSE;
  41.    return dwFolderID==m_dwFolderID; // Same ID? Then same CFolder...
  42. }
  43. // We support two kinds of clipboard formats for drops.
  44. // The standard HDROP and also CFSTR_FILEDESCRIPTOR. The latter
  45. // is also used internally by ADF View to copy Amiga files.
  46. // Returns:
  47. //   S_OK         - all files were successfully copied/moved
  48. //   S_FALSE      - one or more file operations were cancelled
  49. //   E_FAIL       - an error occured
  50. //   E_INVALIDARG - no good clipformat was available
  51. HRESULT CFolder::_DoDrop(LPDATAOBJECT pDataObj, DWORD dwDropEffect)
  52. {
  53.    VALIDATE_POINTER(pDataObj);
  54.    // Are we trying to paste to same folder? Not allowed in this Shell Extension.
  55.    if( _IsDroppedPathSame(pDataObj) ) return E_FAIL; 
  56.    HRESULT Hr = E_INVALIDARG;
  57.    STGMEDIUM stgmed;
  58.    // Check for HDROP
  59.    FORMATETC fe1 = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  60.    if( SUCCEEDED( pDataObj->GetData(&fe1, &stgmed) ) ) {
  61.       Hr = _DoDrop_HDROP(stgmed.hGlobal, dwDropEffect);
  62.       ::ReleaseStgMedium(&stgmed);
  63.       return Hr;
  64.    }
  65.    // Check for CFSTR_FILEDESCRIPTOR
  66.    FORMATETC fe2 = { _Module.m_CFSTR_FILEDESCRIPTOR, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
  67.    if( SUCCEEDED( pDataObj->GetData(&fe2, &stgmed) ) ) {
  68.       Hr = _DoDrop_FILEDESCRIPTOR(stgmed.hGlobal, pDataObj, dwDropEffect);
  69.       ::ReleaseStgMedium(&stgmed);
  70.       return Hr;
  71.    }
  72.    return Hr;
  73. }
  74. HRESULT CFolder::_DoDrop_HDROP(HGLOBAL hMem, DWORD dwDropEffect)
  75. {
  76.    VALIDATE_POINTER(hMem);
  77.    HRESULT HrRes = S_OK;
  78.    HRESULT Hr;
  79.    // Get target path
  80.    CShellPidlPath szPath(m_pidl);
  81.    DWORD dwFileOpFlags = 0;
  82.    // Iterate over HDROP information
  83.    HDROP hDrop = (HDROP)::GlobalLock(hMem);
  84.    if( hDrop==NULL ) return E_OUTOFMEMORY;
  85.    UINT nFiles = ::DragQueryFile(hDrop, (UINT)-1, NULL, 0);
  86.    for( UINT i=0; i<nFiles; i++ ) {
  87.       // Get dragged filename
  88.       TCHAR szFileName[MAX_PATH];
  89.       if( ::DragQueryFile(hDrop, i, szFileName, MAX_PATH)==0 ) return E_FAIL;
  90.       if( ::PathIsDirectory(szFileName) ) {
  91.          //
  92.          // Handle Directory
  93.          //
  94.          TCHAR szStrippedFileName[MAX_PATH];
  95.          _tcscpy( szStrippedFileName, szFileName );
  96.          ::PathStripPath(szStrippedFileName);
  97.          HR( _CreateFolder(szStrippedFileName, &dwFileOpFlags) );
  98.          if( dwDropEffect==DROPEFFECT_MOVE ) ::RemoveDirectory(szFileName); // BUG: Will/cannot not recursive delete
  99.       }
  100.       else {
  101.          //
  102.          // Handle File
  103.          //
  104.          TCHAR szTargetName[MAX_PATH];
  105.          _tcscpy(szTargetName, szFileName);
  106.          ::PathStripPath(szTargetName);
  107.          // Move or Copy file...
  108.          if( dwDropEffect==DROPEFFECT_MOVE ) {
  109.             Hr = _MoveFile(szFileName, szPath, szTargetName, &dwFileOpFlags);
  110.          }
  111.          else {
  112.             Hr = _CopyFile(szFileName, szPath, szTargetName, &dwFileOpFlags);
  113.          }
  114.       }
  115.       if( Hr!=S_OK ) HrRes = Hr;
  116.       // If CANCEL was chosen, exit now...
  117.       if( dwFileOpFlags & FILEOP_CANCEL ) break;
  118.    }
  119.    ::GlobalUnlock(hDrop);
  120.    return HrRes;
  121. }
  122. HRESULT CFolder::_DoDrop_FILEDESCRIPTOR(HGLOBAL hMem, IDataObject *pDataObj, DWORD dwDropEffect)
  123. {
  124.    VALIDATE_POINTER(hMem);
  125.    VALIDATE_POINTER(pDataObj);
  126.    dwDropEffect;
  127.    HRESULT HrRes = S_OK;
  128.    HRESULT Hr;
  129.    CShellPidlPath szPath(m_pidl);
  130.    FILEGROUPDESCRIPTOR *pFGD = (FILEGROUPDESCRIPTOR *)::GlobalLock(hMem);
  131.    if( pFGD==NULL ) return E_OUTOFMEMORY;
  132.    DWORD dwFileOpFlags = 0;
  133.    for( UINT i=0; i<pFGD->cItems; i++ ) {
  134.       FILEDESCRIPTOR fd = pFGD->fgd[i];
  135.       
  136.       DWORD dwFlags = FILE_ATTRIBUTE_NORMAL;
  137.       if( fd.dwFlags & FD_ATTRIBUTES ) dwFlags = fd.dwFileAttributes;
  138.       if( dwFlags & FILE_ATTRIBUTE_DIRECTORY ) {
  139.          // 
  140.          // Handle directory
  141.          //
  142.          HR( _CreateFolder(fd.cFileName, &dwFileOpFlags) );
  143.       }
  144.       else {
  145.          //
  146.          // Copy file contents
  147.          //
  148.          FORMATETC fe = { _Module.m_CFSTR_FILECONTENTS, NULL, DVASPECT_CONTENT, i, TYMED_ISTREAM };
  149.          STGMEDIUM stgmed;
  150.          HR( pDataObj->GetData(&fe, &stgmed) );
  151.          // This drag operation gives us an IStream back. To be able to reuse the
  152.          // copy/move code, we write the IStream contents to a file and pass
  153.          // it on. When the temporary file has been copied to the Amiga file system,
  154.          // we delete it again.
  155.          CComQIPtr<IStream> spStream( stgmed.pstm );
  156.          if( spStream==NULL ) return E_POINTER;
  157.          CTemporaryFile f;
  158.          TCHAR szFileName[MAX_PATH];
  159.          if( f.Create(szFileName, MAX_PATH)==FALSE ) return E_FAIL;
  160.          BYTE buf[512];
  161.          DWORD dwRead;
  162.          while( spStream->Read(&buf, sizeof(buf), &dwRead), dwRead!=0 ) {
  163.             f.Write(buf, dwRead);
  164.          }
  165.          f.Close();
  166.          // Set new file's attributes
  167.          ::SetFileAttributes(szFileName, dwFlags);
  168.          // Copy the new temporary file to the Amiga disk
  169.          // (Use _CopyFile() and do the delete ourselves, because _MoveFile() may be
  170.          //  cancelled and might not delete the file)
  171.          Hr = _CopyFile(szFileName, szPath, fd.cFileName, &dwFileOpFlags);
  172.          // Be sure we can delete the temporary file again.
  173.          // (Note the file is deleted when CTemporaryFile goes out of scope)
  174.          ::SetFileAttributes(szFileName, FILE_ATTRIBUTE_NORMAL);
  175.       }
  176.       if( Hr!=S_OK ) HrRes = Hr;
  177.       // If CANCEL was chosen, exit now...
  178.       if( dwFileOpFlags & FILEOP_CANCEL ) break;
  179.    }
  180.    ::GlobalUnlock(hMem);
  181.    return HrRes;
  182. }