Почему мое приложение зависает при копировании большого файла? - PullRequest
1 голос
/ 26 февраля 2010

У меня есть приложение MFC. Это в основном просто копирование файлов с одного диска на другой. Когда я копирую большие файлы (более 1 ГБ) и нажимаю на окно, мое приложение зависает, но копирование продолжается в фоновом режиме. Кто-то сказал мне, что я должен использовать рабочий поток. Я использовал это, но это все еще зависает. Когда я копирую небольшие файлы, это нормально. Я не могу понять, в чем может быть проблема. Пожалуйста, помогите кому-нибудь!

Вот мой код:

void CGetFileListDlg::OnBnClickedButtonGetFileList()  
{
 //here i'm doing file list comparing
 AfxBeginThread( CopyThread, &Tstruct ); //here i call my thread and give a struct to it as a paramter, which contains, which file i have to copy
}   

UINT CopyThread( LPVOID pParam )
{
UINT uiMaxPass = 3;
UINT uiPAssCount = 0;
int i = 0;

threadstruct *Test = (threadstruct*)(pParam);
CGetFileListDlg* ptr = (CGetFileListDlg*)Test->ez ;

struct address
{
    char *from;
    char *to;
    int current;
};

struct address Address;


for ( i = 0; i < Test->diff; i++ )
    {

    TCHAR currentfile[512], file[MAX_PATH +32], successf[10], unsuccessf[10], buf[20], remainingf[20], oprog[10];
    char tmp[1024], tmp2[1024],dest[1024];
    int j,k,l;
    char ch;

    memset( tmp, 0, sizeof( tmp ) );
    memset( dest, 0, sizeof( dest ) );
    memset( tmp2, 0, sizeof( tmp2 ) );
    memset( buf, 0, sizeof( buf ) );
    memset( currentfile, 0, sizeof( currentfile ) );
    memset( file, 0, sizeof( file ) );
    memset( successf, 0, sizeof( successf ) );
    memset( unsuccessf, 0, sizeof( unsuccessf ) );
    memset( remainingf, 0, sizeof( remainingf ) );
    memset( oprog, 0, sizeof( oprog ) );
    ch = NULL;
    strcat( dest, SecondaryHDD );

    l = 1;
    for ( k = strlen( SecondaryHDD ); k < strlen( Test->difference[i].filename ); k++ )
    {
        dest[k] = Test->difference[i].filename[ l + strlen( SecondaryHDD ) - 1 ];
        l++;
    }
    dest[k]='\0';

    for ( j = strlen( Test->difference[i].filename); ch != '\\'; j-- )
    {
        ch = Test->difference[i].filename[j];
    }

    l = 0;
    for ( k = 3; k < j + 1; k++ )
    {
        tmp2[l] = Test->difference[i].filename[k];
        l++;
    }
    tmp2[l]='\0';
    strcpy( tmp, SecondaryHDD );
    strcat( tmp, tmp2);

    SHCreateDirectoryExA( NULL, tmp, NULL );

    memset( file, 0, sizeof( file ) );

    memset( tmp, 0, sizeof( tmp ) );
    strcpy(tmp, Test->difference[i].filename );

    MultiByteToWideChar(  CP_ACP, NULL, tmp, -1, file, strlen( Test->difference[i].filename ) );
    wsprintf( currentfile, _T("%s"), file );
    ptr->m_edCurrentCopy.SetWindowText( currentfile );

    Address.from = strdup(tmp);
    Address.to = strdup(dest);
    Address.current = i;

    PostMessage( (HWND)Test->hWnd , WMU_PROGRESS, (WPARAM)&Address, (LPARAM)&dest ); //calling OnProgressMsg function, which does the copy
    Sleep(100);
}

PostMessage( (HWND)Test->hWnd, WMU_COPYDONE, uiPAssCount, 0 );

return 0;
}  

LRESULT CGetFileListDlg::OnProgressMsg( WPARAM wParam, LPARAM lParam )
{ 
    TCHAR currentfile[512], file[MAX_PATH +32], successf[10], unsuccessf[10], buf[20], remainingf[20], oprog[10];
char tmp[1024], tmp2[1024],dest[1024];
int j,k,l;
char ch;
struct address
{
    char *from;
    char *to;
    int current;
};

address *Address = (address*)wParam;

//char *to = (char*)lParam;    
//char *from = (char*)wParam;    

int ret = 0;
ret = CopyFileA( Address->from, Address->to, false );
//ret = CopyFileExA( Address->from, Address->to, &MyCopyProgressRoutine, this, FALSE,FALSE);

if ( ret == 0 ) //failed
{
    wsprintf( buf, _T("Failed ( %d )"), GetLastError() );
    m_difference.SetItemText(Address->current, 2, buf);
    unsuccess++;
    wsprintf( unsuccessf, _T("%d"), unsuccess, GetLastError() );
    m_unsuccess.SetWindowText( unsuccessf );
}
else
{
    m_difference.SetItemText(Address->current, 2, L"OK!");
    success++;
    wsprintf( successf, _T("%d"), success );
    m_success.SetWindowText( successf );
}

wsprintf( remainingf, _T("%d"), ( diff - ( success + unsuccess ) ) );
m_remaining.SetWindowText( remainingf );

wsprintf( oprog, _T("%d %%"), ( (success + unsuccess ) *100 )/diff );
m_overallprog.SetWindowText( oprog );

UpdateData(FALSE);

return 0;
}

Ответы [ 2 ]

10 голосов
/ 26 февраля 2010
PostMessage( (HWND)Test->hWnd , WMU_PROGRESS, (WPARAM)&Address, (LPARAM)&dest );
//calling OnProgressMsg function, which does the copy

То есть вы создаете новую тему, которая ... отправляет сообщения в основную тему и заставляет основную тему выполнять все операции копирования?

Это , а не , как вы используете рабочие потоки. Ваш рабочий поток должен быть тем, кто выполняет копирование, и все, что OnProgressMsg должен сделать, это обновить пользовательский интерфейс.

1 голос
/ 26 февраля 2010

Я думаю, что под WorkerThread подразумевалось, что WorkerThread должен выполнять копирование. Если говорить по крайней мере в терминах Win32API, то во всех Windows, в действительности в Windows есть дескриптор hWnd, есть цикл обработки сообщений. Когда этот цикл сообщений перестает отвечать в течение достаточного периода времени, проводник Windows считает, что ваше приложение «не отвечает», потому что по сути это не так - оно не обрабатывает сообщения.

Что вам нужно сделать, это вызвать подпоток, который выполняет копирование, а затем уведомить «родительский» поток, когда это будет сделано, чтобы диалог мог быть закрыт; или уведомите родительский диалог о прогрессе, чтобы родительский диалог мог обновить индикатор выполнения или что-то в этом роде.

...