⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cshellfileop.cpp

📁 类似 windows explorer的工具
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//  operation, and "wipe the slate" for the next one.
//
//////////////////////////////////////////////////////////////////////////

void CShellFileOp::Reset()
{
    ResetInternalData();
}


//////////////////////////////////////////////////////////////////////
// The Go() function!
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
//
// Function:    CShellFileOp::Go
//
// Description:
//  Validates data and starts a file operation.
//
// Input:
//  lpbOperationStarted: [out] Pointer to a BOOL that receives TRUE if the
//                       SHFileOperation() API was called to start the
//                       operation, or FALSE if the API was not called.
//  lpnAPIReturn: [out] Pointer to an int that receives the return value from
//                SHFileOperation() if it was called.  If the API is not called,
//                the variable pointed to is not changed.
//  lpbAnyOperationsAborted: [out] Pointer to a BOOL that receives TRUE if the
//                           user aborted the file operation, or FALSE if not.
//
// Returns:
//  TRUE if and only if SHFileOperation() was called and it returned 0 (success).
//
//////////////////////////////////////////////////////////////////////////
// Updated in v1.1 - Changed the two 'new' calls to allocate BYTEs insetad
// of TCHARs.
//////////////////////////////////////////////////////////////////////////

BOOL CShellFileOp::Go ( BOOL* lpbOperationStarted,
                       int*  lpnAPIReturn /*=NULL*/,
                       BOOL* lpbAnyOperationsAborted  /*=NULL*/ )
{
    TCHAR* szzSourceFiles = NULL;
    TCHAR* szzDestFiles = NULL;
    DWORD  dwSourceBufferSize;
    DWORD  dwDestBufferSize;
    int    nAPIRet;
    
    // Validate the pointers....
    ASSERT ( AfxIsValidAddress ( lpbOperationStarted, sizeof(BOOL) ) );
    ASSERT ( lpnAPIReturn == NULL  ||
        AfxIsValidAddress ( lpnAPIReturn, sizeof(int) ) );
    ASSERT ( lpbAnyOperationsAborted == NULL  ||
        AfxIsValidAddress ( lpbAnyOperationsAborted, sizeof(BOOL) ) );
    
    
    m_bGoCalledAPI = FALSE;
    
    if ( NULL != lpbOperationStarted )
    {
        *lpbOperationStarted = FALSE;
    }
    
    // Do a bunch of validation before
    // calling the API.
    
    // 1. Did you call SetOperationFlags()?
    
    if ( ! m_bFlagsSet )
    {
        TRACE0("Go() aborting because SetOperationFlags() was not called first.\n");
        goto bailout;
    }
    
    // 2 Is the op type valid?
    
    if ( ! ( m_rFOS.wFunc == FO_COPY  ||  m_rFOS.wFunc == FO_DELETE  ||
        m_rFOS.wFunc == FO_MOVE  ||  m_rFOS.wFunc == FO_RENAME ) )
    {
        TRACE0("Go() aborting because the operation type was invalid.\n");
        goto bailout;
    }
    
    // 3 Is the source file list nonempty?
    
    if ( m_lcstrSourceFiles.IsEmpty() ) 
    {
        TRACE0("Go() aborting because the source file list is empty.\n");
        goto bailout;
    }
    
    // 4. Is the dest file list nonempty
    // if the op needs dest files?
    
    if ( m_rFOS.wFunc != FO_DELETE  &&  m_lcstrDestFiles.IsEmpty() )
    {
        TRACE0("Go() aborting because the destination file list is empty.\n");
        goto bailout;
    }
    
    // 5. Is the dest file list OK?  There
    // must either be one entry, or the same
    // number of entries as in the source
    // list.
    
    if ( m_rFOS.wFunc != FO_DELETE )
    {
        if ( m_lcstrDestFiles.GetCount() != 1  &&
            m_lcstrDestFiles.GetCount() != m_lcstrSourceFiles.GetCount() )
        {
            TRACE0("Go() aborting because the destination file list has the wrong number of strings.\n");
            goto bailout;
        }
    }
    
    
    // Everything checked out OK, so now
    // build the big double-null-terminated
    // buffers.
    
    dwSourceBufferSize = GetRequiredBufferSize ( m_lcstrSourceFiles );
    
    if ( m_rFOS.wFunc != FO_DELETE )
    {
        dwDestBufferSize = GetRequiredBufferSize ( m_lcstrDestFiles );
    }
    
    try
    {
        szzSourceFiles = (LPTSTR) new BYTE [ dwSourceBufferSize ];
        
        if ( m_rFOS.wFunc != FO_DELETE )
        {
            szzDestFiles = (LPTSTR) new BYTE [ dwDestBufferSize ];
        }
    }
    catch ( CMemoryException )
    {
        TRACE0("Memory exception in CShellFileOp::Go()!\n");
        throw;
    }
    
    FillSzzBuffer ( szzSourceFiles, m_lcstrSourceFiles );
    
    if ( m_rFOS.wFunc != FO_DELETE )
    {
        FillSzzBuffer ( szzDestFiles, m_lcstrDestFiles );
    }
    
    // and now, the moment you've all been
    // waiting for
    
    m_rFOS.pFrom = szzSourceFiles;
    m_rFOS.pTo = szzDestFiles;
    m_rFOS.lpszProgressTitle = (LPCTSTR) m_cstrProgressDlgTitle;
    
    
    // If there are 2 or more strings in
    // the destination list, set the 
    // MULTIDESTFILES flag.
    
    if ( m_lcstrDestFiles.GetCount() > 1 )
    {
        m_rFOS.fFlags |= FOF_MULTIDESTFILES;
    }
    
    
    m_bGoCalledAPI = TRUE;
    
    if ( NULL != lpbOperationStarted )
    {
        *lpbOperationStarted = TRUE;
    }
    
    // drum roll please....
    nAPIRet = SHFileOperation ( &m_rFOS );  // tah-dah!
    
    // Save the return value from the API.    
    if ( NULL != lpnAPIReturn )
    {
        *lpnAPIReturn = nAPIRet;
    }
    
    // Check if the user cancelled the
    // operation.
    
    if ( NULL != lpbAnyOperationsAborted )
    {
        *lpbAnyOperationsAborted = m_rFOS.fAnyOperationsAborted;
    }
    
bailout:
    // If we got here via one of the gotos, fire off an ASSERT.
    // If this ASSERT fires, check the debug window for a TRACE output
    // line that describes the problem.
    ASSERT ( m_bGoCalledAPI );
    
    // Free buffers.
    if ( NULL != szzSourceFiles )
    {
        delete [] szzSourceFiles;
    }
    
    if ( NULL != szzDestFiles )
    {
        delete [] szzDestFiles;
    }
    
    
    return m_bGoCalledAPI  &&  0 == nAPIRet;
}


//////////////////////////////////////////////////////////////////////
// Private helper functions
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
//
// Function:    CShellFileOp::ResetInternalData
//
// Description:
//  Clears the CShellFileOp object's member variables in preparation for a
//  new file operation.
//
// Input:
//  Nothing.
//
// Returns:
//  Nothing.
//
//////////////////////////////////////////////////////////////////////////

void CShellFileOp::ResetInternalData()
{
    // Empty the string lists
    m_lcstrSourceFiles.RemoveAll();
    m_lcstrDestFiles.RemoveAll();
    
    // Reset state variables
    m_bFlagsSet = FALSE;
    m_bGoCalledAPI = FALSE;
    
    // And clear out other stuff...
    m_cstrProgressDlgTitle.Empty();
    
    ZeroMemory ( &m_rFOS, sizeof ( m_rFOS ) );
}


//////////////////////////////////////////////////////////////////////////
//
// Function:    CShellFileOp::GetRequiredBufferSize
//
// Description:
//  Calculates the number of bytes required to hold the passed-in string
//  list in double-null-terminated character array form.
//
// Input:
//  list: [in] The string list to look at.
//
// Returns:
//  The number of bytes required.
//
//////////////////////////////////////////////////////////////////////////

DWORD CShellFileOp::GetRequiredBufferSize ( const CStringList& list )
{
    DWORD    dwRetVal = 0;
    POSITION pos;
    CString  cstr;
    
    // If this ASSERT fires, the passed-in list was empty. This ought to
    // never fire, actually, since Go() won't even call this function if
    // either list is empty.
    
    ASSERT ( !list.IsEmpty() );
    
    
    pos = list.GetHeadPosition();
    
    while ( NULL != pos )
    {
        cstr = list.GetNext ( pos );
        
        // **NOTE** The MFC docs for CString::GetLength() say that it returns
        // the number of bytes in the string, but that's wrong!!  In Unicode,
        // it returns the number of characters (which is half the number of
        // bytes).  Thus the multiplication by sizeof(TCHAR).
        
        dwRetVal += sizeof(TCHAR) * ( cstr.GetLength() + 1 );
    }
    
    return dwRetVal + sizeof(TCHAR);    // add one more for the final null
}


//////////////////////////////////////////////////////////////////////////
//
// Function:    CShellFileOp::FillSzzBuffer
//
// Description:
//  Copies a string list into a character array, making a double-null-terminated
//  list of strings.
//
// Input:
//  pBuffer: [out] The buffer that will hold the strings.
//  list: [in] The string list to read.
//
// Returns:
//  Nothing.
//
//////////////////////////////////////////////////////////////////////////

void CShellFileOp::FillSzzBuffer ( TCHAR* pBuffer, const CStringList& list )
{
    TCHAR*   pCurrPos;
    POSITION pos;
    CString  cstr;
    
    // If this ASSERT fires, the passed-in list was empty. This ought to
    // never fire, actually, since Go() won't even call this function if
    // either list is empty when it shouldn't be.
    
    ASSERT ( !list.IsEmpty() );
    
    ASSERT ( pBuffer != NULL );
    
    
    pCurrPos = pBuffer;
    
    pos = list.GetHeadPosition();
    
    while ( NULL != pos )
    {
        cstr = list.GetNext ( pos );
        
        _tcscpy ( pCurrPos, (LPCTSTR) cstr );
        
        pCurrPos = _tcsinc ( _tcschr ( pCurrPos, '\0' ) );
    }
    
    // Tack on the final null
    *pCurrPos = '\0';
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -