Привет,
есть такой нагугленный код, который архивирует файлы используя 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;
}
E>Всё работает, но WaitForMultipleObjects возвращает управление стабильно через ~минуту после того как архив создан.
E>Почему такая задержка
Очевидно потому что COM или шелл или кто там заведует этим паковщиком зипов юзает не простые потоки, а пул, потоки которого живут после завершения задачи сколько им заблагорассудиться. И вообще вам никто не обещал ни факт создания новых потоков (а не процессов, например) ни то что они будут выходить после.
Юзайте
minizip, не надо извращаться.
Здравствуйте, ononim, Вы писали:
O>Юзайте minizip, не надо извращаться.
Это для крошечной консольной утилитки для собственных нужд, поэтому и выбрал самое простое решение.
То, что ничего не гарантируется это понятно, просто интересна логика ожидания, равная одному и тому же интервалу.
Интересно, что заменив параметр bWaitAll в WaitForMultipleObjects с TRUE на FALSE (т.е. ждать завершения одного из потоков (всего их создается 3)), ф. быстро возвращает управление после создания архива
Здравствуйте, edton, Вы писали:
E>Интересно, что заменив параметр bWaitAll в WaitForMultipleObjects с TRUE на FALSE (т.е. ждать завершения одного из потоков (всего их создается 3)), ф. быстро возвращает управление после создания архива
А убрав вызов WaitForMultipleObjects функция вообще мгновенно будет отрабатывать
А если какой-нибудь антивирус/вирус/автоматизатор/криптомайнер создаст thread в вашем процессе? Будете его вечно ждать?
Страшно представить что будет, если тредов будет десяток... (спойлер: порча стека)
Здравствуйте, EreTIk, Вы писали:
ETI>А убрав вызов WaitForMultipleObjects функция вообще мгновенно будет отрабатывать
В таком случае или вообще не доходит до архивации (первичный поток завершается быстрее чем, создаются потоки-архиваторы). Видел примеры с ф. Sleep
или выход из функции архивации когда архив еще создается.
ETI>А если какой-нибудь антивирус/вирус/автоматизатор/криптомайнер создаст thread в вашем процессе? Будете его вечно ждать?
Да, все верно. Но можно например создать снэпшот потоков до pToFolder->CopyHere и после и ждать только потоки-архиваторы
Мне вот просто интересно — ну создали вот это интерфейс, ну должен же быть человеческий метод его использования, без этих костылей. Может кто знает
Здравствуйте, edton, Вы писали:
E>Мне вот просто интересно — ну создали вот это интерфейс, ну должен же быть человеческий метод его использования, без этих костылей.
Отпишусь со стороны разработчика архиватора, внедряющегося в виндовый шелл
Все, что делает CopyHere — это вызывает IShellFolder.CreateViewObject(IDropTarget), а затем вызывает IDropTarget.DragEnter и IDropTarget.Drop. А уж как будет происходить обработка этого дропа — лично дело namespace extension, и CopyHere тут никак это не может контролировать.
И закладываться на конкретную виндовую реализацию упаковки imho сомнительная затея. Предустановленный обработчик zip файлов может быть замен на стороннюю реализацию, что, например, делаю я в своем архиваторе. На одной машине будет предустановленный обработчик, на второй машине, возможно, будет установлена моя программа, на третьей — третья программа. А всех не перетестируешь.