WaitForMultipleObjects & Shell COM потоки
От: edton  
Дата: 14.12.19 11:29
Оценка:
Привет,
есть такой нагугленный код, который архивирует файлы используя shell com api.
вызов pToFolder->CopyHere, который и архивирует файлы, сразу возвращает управление, создавая поток(и)
Код между // **************** с помощью toolhelp функций перечисляет потоки кроме текущего и ждет их завершения.
Всё работает, но WaitForMultipleObjects возвращает управление стабильно через ~минуту после того как архив создан.
Почему такая задержка

BOOL ZIPFiles(LPTSTR lpszFolder, LPTSTR lpszZIPFilePath)
{
    if(!lpszFolder || !lpszZIPFilePath) return FALSE;

    // Create Zip file
    BYTE startBuffer[] = {80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    FILE *f = _wfopen(lpszZIPFilePath, TEXT("wb"));
    fwrite(startBuffer,sizeof(startBuffer),1,f);
    fclose(f);

    BSTR source = lpszFolder;
    BSTR dest = lpszZIPFilePath;
        
    HRESULT        hResult;
    IShellDispatch *pISD;
    Folder         *pToFolder = NULL;
    VARIANT        vDir, vFile, vOpt;

    CoInitialize(NULL);

    hResult = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void **)&pISD);

    if  (SUCCEEDED(hResult))
    {
        VariantInit(&vDir);
        vDir.vt = VT_BSTR;
        vDir.bstrVal = dest;
        hResult = pISD->NameSpace(vDir, &pToFolder);

        if (SUCCEEDED(hResult))
        {
            // Now copy source file(s) to the zip
            VariantInit(&vFile);
            vFile.vt = VT_BSTR;
            vFile.bstrVal = source;
            VariantInit(&vOpt);
            vOpt.vt = VT_I4;
            vOpt.lVal = FOF_NO_UI;

            // Copying and compressing the source files to our zip
            hResult = pToFolder->CopyHere(vFile, vOpt);
            // *************************************************************************************
            HANDLE hThrd[5]; 
                       HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPALL ,0);  //TH32CS_SNAPMODULE, 0);
                    DWORD NUM_THREADS = 0;
            if (h != INVALID_HANDLE_VALUE) {
                        THREADENTRY32 te;
                        te.dwSize = sizeof(te);
                        if (Thread32First(h, &te)) {
                            do {
                                if (te.dwSize >= (FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID)) ) {
                                    //only enumerate threads that are called by this process and not the main thread
                                    if((te.th32OwnerProcessID == GetCurrentProcessId()) && (te.th32ThreadID != GetCurrentThreadId()) ){
                                        //printf("Process 0x%04x Thread 0x%04x\n", te.th32OwnerProcessID, te.th32ThreadID);
                                        hThrd[NUM_THREADS] = OpenThread(SYNCHRONIZE/*THREAD_ALL_ACCESS*/, FALSE, te.th32ThreadID);
                                        NUM_THREADS++;
                                    }
                                }
                                te.dwSize = sizeof(te);
                            } while (Thread32Next(h, &te));
                        }
                        CloseHandle(h);
    
            //Wait for all threads to exit
                    WaitForMultipleObjects(NUM_THREADS, hThrd , TRUE , INFINITE);
    
                    //Close All handles
                    for ( DWORD i = 0; i < NUM_THREADS ; i++ ){
                           CloseHandle( hThrd[i] );
                    }
                } //if invalid handle
        // **********************************************************************************
            pToFolder->Release();
        }
        pISD->Release();
    }
    CoUninitialize();
    return TRUE;
}
Re: WaitForMultipleObjects & Shell COM потоки
От: ononim  
Дата: 15.12.19 08:14
Оценка: +1
E>Всё работает, но WaitForMultipleObjects возвращает управление стабильно через ~минуту после того как архив создан.
E>Почему такая задержка
Очевидно потому что COM или шелл или кто там заведует этим паковщиком зипов юзает не простые потоки, а пул, потоки которого живут после завершения задачи сколько им заблагорассудиться. И вообще вам никто не обещал ни факт создания новых потоков (а не процессов, например) ни то что они будут выходить после.
Юзайте minizip, не надо извращаться.
Как много веселых ребят, и все делают велосипед...
Re[2]: WaitForMultipleObjects & Shell COM потоки
От: edton  
Дата: 15.12.19 09:02
Оценка:
Здравствуйте, ononim, Вы писали:

O>Юзайте minizip, не надо извращаться.


Это для крошечной консольной утилитки для собственных нужд, поэтому и выбрал самое простое решение.
То, что ничего не гарантируется это понятно, просто интересна логика ожидания, равная одному и тому же интервалу.
Интересно, что заменив параметр bWaitAll в WaitForMultipleObjects с TRUE на FALSE (т.е. ждать завершения одного из потоков (всего их создается 3)), ф. быстро возвращает управление после создания архива
Re[3]: WaitForMultipleObjects & Shell COM потоки
От: EreTIk EreTIk's Box
Дата: 16.12.19 09:13
Оценка:
Здравствуйте, edton, Вы писали:
E>Интересно, что заменив параметр bWaitAll в WaitForMultipleObjects с TRUE на FALSE (т.е. ждать завершения одного из потоков (всего их создается 3)), ф. быстро возвращает управление после создания архива
А убрав вызов WaitForMultipleObjects функция вообще мгновенно будет отрабатывать

А если какой-нибудь антивирус/вирус/автоматизатор/криптомайнер создаст thread в вашем процессе? Будете его вечно ждать?

Страшно представить что будет, если тредов будет десяток... (спойлер: порча стека)
Re[4]: WaitForMultipleObjects & Shell COM потоки
От: edton  
Дата: 16.12.19 10:55
Оценка:
Здравствуйте, EreTIk, Вы писали:

ETI>А убрав вызов WaitForMultipleObjects функция вообще мгновенно будет отрабатывать


В таком случае или вообще не доходит до архивации (первичный поток завершается быстрее чем, создаются потоки-архиваторы). Видел примеры с ф. Sleep или выход из функции архивации когда архив еще создается.

ETI>А если какой-нибудь антивирус/вирус/автоматизатор/криптомайнер создаст thread в вашем процессе? Будете его вечно ждать?

Да, все верно. Но можно например создать снэпшот потоков до pToFolder->CopyHere и после и ждать только потоки-архиваторы

Мне вот просто интересно — ну создали вот это интерфейс, ну должен же быть человеческий метод его использования, без этих костылей. Может кто знает
Re[5]: WaitForMultipleObjects & Shell COM потоки
От: Aniskin  
Дата: 16.12.19 15:43
Оценка: +1
Здравствуйте, edton, Вы писали:

E>Мне вот просто интересно — ну создали вот это интерфейс, ну должен же быть человеческий метод его использования, без этих костылей.


Отпишусь со стороны разработчика архиватора, внедряющегося в виндовый шелл Все, что делает CopyHere — это вызывает IShellFolder.CreateViewObject(IDropTarget), а затем вызывает IDropTarget.DragEnter и IDropTarget.Drop. А уж как будет происходить обработка этого дропа — лично дело namespace extension, и CopyHere тут никак это не может контролировать.

И закладываться на конкретную виндовую реализацию упаковки imho сомнительная затея. Предустановленный обработчик zip файлов может быть замен на стороннюю реализацию, что, например, делаю я в своем архиваторе. На одной машине будет предустановленный обработчик, на второй машине, возможно, будет установлена моя программа, на третьей — третья программа. А всех не перетестируешь.
Re[3]: WaitForMultipleObjects & Shell COM потоки
От: ononim  
Дата: 16.12.19 19:28
Оценка:
Здесь обсуждается более корректный способ, правда судя по обсуждению он работает не очень
https://social.msdn.microsoft.com/Forums/vstudio/en-US/82cef352-487d-4e6c-a5bf-4dc02af7cdb1/unzip-with-shell32-api?forum=vcgeneral
Как много веселых ребят, и все делают велосипед...
Отредактировано 16.12.2019 19:32 ononim . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.