1 Востаннє редагувалося pika1989 (14.05.2016 12:43:54)

Тема: WinAPI Під'єднання ProgressBar до процесу копіювання

Задача: Створити програму для копіювання файлів,
програма повинна міcтити діалогове вікно з кнопкою Open,
що відкриває стандартний діалог вибору файлів та кнопкою SaveAs,
що відкриває стандартний діалог збереження файлу.
Після чого повинно запускатись копіювання файлу в окремому потоці.

Додатково. Відображати процес копіювання кожного файлу на окремому індикаторі процесу.
Передбачити неможливість повторного копіювання файлу, що вже копіюється.

Ось те, що я зробила:

Прихований текст

#include <windows.h>
#include <tchar.h>
#include <CommCtrl.h>
#include "resource.h"
#pragma warning (disable:4996)

HWND hNoModeless;
HWND hProgressBar;

struct CopyFileName
{
    wchar_t first_file[MAX_PATH];
    wchar_t second_file[MAX_PATH];
};

DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER liTotalFileSize,
                                   LARGE_INTEGER liTotalBytesTransferred,
                                   LARGE_INTEGER liStreamSize,
                                   LARGE_INTEGER liStreamBytesTransferred,
                                   DWORD dwStreamNumber,
                                   DWORD dwCallbackReason,
                                   HANDLE hSourceFile,
                                   HANDLE hDestinationFile,
                                   LPVOID lpvData)
{
    HWND lpProgressCtrl = (HWND)lpvData;

    SendMessage(lpProgressCtrl, PBM_SETPOS, (liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100), 0);
    SendMessage(lpProgressCtrl, PBM_STEPIT, 0, 0);
    return PROGRESS_CONTINUE;
}

BOOL CALLBACK ModelessDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_INITDIALOG:
        hProgressBar = CreateWindow(PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE | PBS_SMOOTH, 100, 20, 300, 30, hNoModeless, NULL, GetModuleHandle(NULL), NULL);
        SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
        SendMessage(hProgressBar, PBM_SETSTEP, 1, 0);
        SendMessage(hProgressBar, PBM_SETPOS, 0, 0);
        return 1;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        hNoModeless = nullptr;
        hProgressBar = nullptr;
        return 1;
    }
    return 0;
}

DWORD WINAPI CopyThread(PVOID pvParam)
{
    CopyFileName* temp_files = (CopyFileName*)pvParam;

    hNoModeless = CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DIALOG2), NULL, ModelessDlgProc);
    ShowWindow(hNoModeless, SW_SHOW);
        
    CopyFileEx(temp_files->first_file, temp_files->second_file, CopyProgressRoutine, &hProgressBar, FALSE, COPY_FILE_FAIL_IF_EXISTS);
    
    return 0;
}

BOOL CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static OPENFILENAME ofn;
    static wchar_t file[MAX_PATH] = L"\0";
    static wchar_t buff[MAX_PATH] = L"\0";
    static DWORD dwFileSize = 0, bytesToRead = 0, bytesRead = 0;
    CopyFileName* files_name = new CopyFileName;

    switch (uMsg)
    {
    case WM_INITDIALOG:
        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hWnd;
        ofn.lpstrFile = file;
        ofn.lpstrFilter = L"All\0*.*\0";
        ofn.nFilterIndex = 1;
        ofn.nMaxFile = MAX_PATH;

        return 1;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDC_OPEN:
            if (GetOpenFileName(&ofn))
            {
                if (lstrcmp(ofn.lpstrFile, buff) == 0)
                    MessageBox(NULL, L"This file is copying", L"Error", MB_OK|MB_ICONERROR);
                else
                    lstrcpy(buff, ofn.lpstrFile);
                break;
            }

        case IDC_SAVE_AS:
            if (GetSaveFileName(&ofn))
            {
                lstrcpy(files_name->second_file, ofn.lpstrFile);
                lstrcpy(files_name->first_file, buff);
                CreateThread(NULL, 0, CopyThread, files_name, NULL, NULL);
                break;
            }
        }
        return 1;

    case WM_CLOSE:
        EndDialog(hWnd, 0);
        return 1;
    }
    delete files_name;
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nCmd, int nCmdShow)
{
    INITCOMMONCONTROLSEX cc;
    cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
    cc.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&cc);
    
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
    return 0;
}

Програма виконує копіювання файлів будь-якого типу (з цим я довго розбиралась, але вийшло :) ), але в мене виникла проблема з під'єднанням ProgressBar до процесу копіювання:
1. Взагалі не вдається відобразити його.

2. Потрібно окремий ProgressBar для кожного потоку. Це я намагаюсь зробити через немодальне вікно: врезультаті вікно з'являється - ProgressBar нема)), але саме вікно видно, поки триває процес копіювання.

Підкажіть як правильно з ним (ProgressBar) працювати, і що я не так роблю.

2

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Мені вдалось зробити, щоб було видно ProgressBar, але тепер вікно постійно відкрите і ProgressBar не заповнюється.

Прихований текст

/*Завдання 1. Створити програму для копіювання файлів,
програма повинна міcтити діалогове вікно з кнопкою Open,
що відкриває стандартний діалог вибору файлів та кнопкою SaveAs,
що відкриває стандартний діалог збереження файлу.
Після чого повинно запускатись копіювання файлу в окремому потоці.

Додатково. Відображати процес копіювання кожного файлу на окремому індикаторі процесу.
Передбачити неможливість повторного копіювання файлу, що вже копіюється.
*/

#include <windows.h>
#include <tchar.h>
#include <CommCtrl.h>
#include "resource.h"
#pragma warning (disable:4996)

struct CopyFileName
{
    wchar_t first_file[MAX_PATH];
    wchar_t second_file[MAX_PATH];
};

HWND hNoModeless;
HWND hProgressBar;

DWORD CALLBACK CopyProgressRoutine(LARGE_INTEGER liTotalFileSize,
                                   LARGE_INTEGER liTotalBytesTransferred,
                                   LARGE_INTEGER liStreamSize,
                                   LARGE_INTEGER liStreamBytesTransferred,
                                   DWORD dwStreamNumber,
                                   DWORD dwCallbackReason,
                                   HANDLE hSourceFile,
                                   HANDLE hDestinationFile,
                                   LPVOID lpvData)
{
    HWND lpProgressCtrl = (HWND)lpvData;

    SendMessage(lpProgressCtrl, PBM_SETPOS, (liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100), 0);
    SendMessage(lpProgressCtrl, PBM_STEPIT, 0, 0);

    MSG msg;

    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!IsDialogMessage(hNoModeless, &msg))
        {
            //TranslateMessage(&msg); - обробка даних від клавіатури
            DispatchMessage(&msg);
        }
    }

    return PROGRESS_CONTINUE;
}

BOOL CALLBACK ModelessDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_INITDIALOG:
        /*hProgressBar = CreateWindow(PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE, 20, 60, 350, 30, hWnd, NULL, GetModuleHandle(NULL), NULL);
        SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
        SendMessage(hProgressBar, PBM_SETSTEP, 1, 0);
        SendMessage(hProgressBar, PBM_SETPOS, 0, 0);*/
        ShowWindow(hProgressBar, SW_SHOW);
        return 1;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        hNoModeless = nullptr;
        hProgressBar = nullptr;
        return 1;
    }

    return 0;
}

DWORD WINAPI CopyThread(PVOID pvParam)
{
    CopyFileName* temp_files = (CopyFileName*)pvParam;

    //Create modeless dialog
    hNoModeless = CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_DIALOG2), GetDlgItem(NULL, IDD_DIALOG1), ModelessDlgProc);
    ShowWindow(hNoModeless, SW_SHOW);
    //--------------------
    
    //Init ProgressBar
    hProgressBar = CreateWindow(PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE, 20, 60, 350, 30, hNoModeless, NULL, GetModuleHandle(NULL), NULL);
    SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
    SendMessage(hProgressBar, PBM_SETSTEP, 1, 0);
    SendMessage(hProgressBar, PBM_SETPOS, 0, 0);
    //--------------------

    CopyFileEx(temp_files->first_file, temp_files->second_file, CopyProgressRoutine, &hProgressBar, FALSE, COPY_FILE_FAIL_IF_EXISTS);
    
    return 0;
}

BOOL CALLBACK DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static OPENFILENAME ofn;
    static wchar_t file[MAX_PATH] = L"\0";
    static wchar_t buff[MAX_PATH] = L"\0";
    static DWORD dwFileSize = 0, bytesToRead = 0, bytesRead = 0;
    CopyFileName* files_name = new CopyFileName;

    switch (uMsg)
    {
    case WM_INITDIALOG:

        ofn.lStructSize = sizeof(OPENFILENAME);
        ofn.hwndOwner = hWnd;
        ofn.lpstrFile = file;
        ofn.lpstrFilter = L"All\0*.*\0";
        ofn.nFilterIndex = 1;
        ofn.nMaxFile = MAX_PATH;

        return 1;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDC_OPEN:
            if (GetOpenFileName(&ofn))
            {
                if (lstrcmp(ofn.lpstrFile, buff) == 0)
                    MessageBox(NULL, L"This file is copying", L"Error", MB_OK|MB_ICONERROR);
                else
                    lstrcpy(buff, ofn.lpstrFile);
                break;
            }

        case IDC_SAVE_AS:
            if (GetSaveFileName(&ofn))
            {
                lstrcpy(files_name->second_file, ofn.lpstrFile);
                lstrcpy(files_name->first_file, buff);
                CreateThread(NULL, 0, CopyThread, files_name, NULL, NULL);
                break;
            }
        }
        return 1;

    case WM_CLOSE:
        EndDialog(hWnd, 0);
        return 1;
    }
    delete files_name;
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR nCmd, int nCmdShow)
{
    INITCOMMONCONTROLSEX cc;
    cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
    cc.dwICC = ICC_WIN95_CLASSES;
    InitCommonControlsEx(&cc);
    
    DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);

    return 0;
}

3 Востаннє редагувалося Yola (14.05.2016 17:09:43)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Навіщо ви передаєте у CopyFileEx &hProgressBar якщо ця змінна глобальна? Виходить, що всі функції працюють з один ProgressBar?

Вам би допомогло використання std::list, i додавати туди кожен новий прогрес бар. А вказівник на нього передавати у функцію.

Також перевіряючи кількість елементів у списку ви могли б позиціонувати кожен новий прогрес бар у новому місці.

ukrainian.stackexchange.com - це питання-відповіді з української мови

4

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Я вже зробила його не глобальним, але від цього моя проблема не вирішилась: ProgressBar все рівно не заповнюється і вікно, де знаходиться ProgressBar, вісить, поки не натисну хрестик.

5

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

...ех, молодь:

http://ipic.su/img/img7/fs/ezgif-1563517958.1463241181.gif

Білоруський журнал «Радиолюбитель»
Lead Radar systems engineer & Software developer of industrial automation
Мої розробки та відеоблог

6

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

raxp, я Вам дякую, але як створювати ProgressBar, я вже розібрала, основна моя проблема в тому, що невдається поєднати процес копіювання та заповнення ProgressBar.

7 Востаннє редагувалося Yola (14.05.2016 20:02:48)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Викладіть свій resource.h, щоб можна було запуститись.

Також можна спробувати, в lpData передавати хендл вікна, а не прогрес бара. І з CopyProgressRoutine посилати користувацьке повідомлення цьому вікну з (liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100) у WPARAM. І вже в діалозі обробляти це повідомлення.

ukrainian.stackexchange.com - це питання-відповіді з української мови

8

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Прихований текст

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by WinAPI_home_work_7_(8_05_16).rc
//
#define IDD_DIALOG1                     101
#define IDD_DIALOG2                     102
#define IDC_OPEN                        1001
#define IDC_SAVE_AS                     1002

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        103
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1003
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

9 Востаннє редагувалося raxp (14.05.2016 20:48:49)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

pika1989 написав:

raxp, я Вам дякую, але як створювати ProgressBar, я вже розібрала, основна моя проблема в тому, що невдається поєднати процес копіювання та заповнення ProgressBar.

та невже? А це хто пише постом ранiше "ProgressBar все рівно не заповнюється"? )

Узрiть його заповнення та як треба передавати параметр. У вас float.

Білоруський журнал «Радиолюбитель»
Lead Radar systems engineer & Software developer of industrial automation
Мої розробки та відеоблог
Подякували: Yola1

10 Востаннє редагувалося Yola (14.05.2016 23:41:42)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

:o

raxp написав:

У вас float.

Де там float?
Мабуть треба

((float)liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100)

Також можна закривати діалог наприкінці CopyThread.

ukrainian.stackexchange.com - це питання-відповіді з української мови

11 Востаннє редагувалося Yola (15.05.2016 10:23:20)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Запустився. У вас виходить нескінченний while цикл отримання повідомлень.

Закоментуйте його і спробуйте знов.

----------------------------------------------------

загалом ось, не знаю що це я зробив, але можна так:

Вставте це у CopyProgressRoutine

    SendDlgItemMessage(hNoModeless, IDC_PROGRESSBAR, PBM_SETPOS, (liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100), 0);

це у ваш у відповідний діалог *.rc

    CONTROL         "", IDC_PROGRESSBAR, "msctls_progress32", PBS_SMOOTH | WS_BORDER, 19, 44, 156, 20

і замініть GetMessage на

PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)

ukrainian.stackexchange.com - це питання-відповіді з української мови
Подякували: pika19891

12

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Де там float?
Мабуть треба

не пишiть дурню. Там треба (int), бо пiсля операцiй дiлення та множення буде float, а position приймає беззнакове ціле.

Білоруський журнал «Радиолюбитель»
Lead Radar systems engineer & Software developer of industrial automation
Мої розробки та відеоблог

13

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Коли я коментую цикл у мене взагалі ProgressBar не видно :(

14 Востаннє редагувалося Yola (15.05.2016 10:31:06)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Та, і не забудьте про цю дурню (float), бо 99/100 це 0.

З тими змінами, що я вам запропонував у мене запрацювало.

ukrainian.stackexchange.com - це питання-відповіді з української мови
Подякували: pika19891

15

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Гаразд, я зараз спробую

Yola написав:

Та, і не забудьте про цю дурню (float), бо 99/100 це 0.

За це я теж читала, що має бути так)

16 Востаннє редагувалося pika1989 (15.05.2016 11:09:41)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

У мене заповняється не поступово, а лише вкінці копіювання
Але дуже Вам дякую

І виходить, що це не зовсім динамічний прогрес бар)

17

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

не поступово, а лише вкінці копіювання

Ви взагалi читаэте, що у посту #5, 9 та 12?

Білоруський журнал «Радиолюбитель»
Lead Radar systems engineer & Software developer of industrial automation
Мої розробки та відеоблог

18 Востаннє редагувалося Yola (15.05.2016 13:28:35)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

pika1989 написав:

У мене заповняється не поступово, а лише вкінці копіювання
Але дуже Вам дякую

І виходить, що це не зовсім динамічний прогрес бар)

Може ви все ж забули про приведення до float? Треба якось так:

    int percent = (float)liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100;
    SendDlgItemMessage(hNoModeless, IDC_PROGRESSBAR, PBM_SETPOS, percent, 0);

або так:

    SendDlgItemMessage(hNoModeless, IDC_PROGRESSBAR, PBM_SETPOS, (float)liTotalBytesTransferred.QuadPart / liTotalFileSize.QuadPart * 100, 0);

Обидва варіанти підходять, лише перший зручніший для зневадження.

Дайте, будь ласка, код.

ukrainian.stackexchange.com - це питання-відповіді з української мови
Подякували: pika19891

19 Востаннє редагувалося pika1989 (15.05.2016 15:50:04)

Re: WinAPI Під'єднання ProgressBar до процесу копіювання

Yola написав:
pika1989 написав:

У мене заповняється не поступово, а лише вкінці копіювання
Але дуже Вам дякую

І виходить, що це не зовсім динамічний прогрес бар)

Може ви все ж забули про приведення до float?

Я справді забула про це :[
Все вийшло, дуже-дуже Вам дякую

Подякували: Yola1