IShellDisptach: почему происходит сбой FolderItemVerbs :: Release () + CoUninitialize ()?

У меня очень странная проблема с IShellDispatch Интерфейс COM, более конкретно с FolderItemVerbs объект, который сводит меня с ума!

призвание FolderItemVerbs :: Release () с последующим CoUninitialze () приведет к аварии. Это явно воспроизводимо, но происходит только 1 из 10 раз.

Сбой — ошибка «0xC0000005: нарушение прав доступа». Запуск проблемного кода в цикле на 100% рано или поздно приводит к сбою 🙁

Пожалуйста, посмотрите пример программы:

static int TestProc(const TCHAR *pcDirectoryName, const TCHAR *pcFileName)
{
int iSuccess = 0;

IShellDispatch *pShellDispatch = NULL;
Folder *pFolder = NULL; FolderItem *pItem = NULL;
FolderItemVerbs *pVerbs = NULL;

HRESULT hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pShellDispatch);
if(FAILED(hr) || (pShellDispatch ==  NULL))
{
iSuccess = -3;
return iSuccess;
}

variant_t vaDirectory(pcDirectoryName);
hr = pShellDispatch->NameSpace(vaDirectory, &pFolder);
if(FAILED(hr) || (pFolder == NULL))
{
iSuccess = -4;
pShellDispatch->Release();
return iSuccess;
}

variant_t vaFileName(pcFileName);
hr = pFolder->ParseName(vaFileName, &pItem);
if(FAILED(hr) || (pItem == NULL))
{
iSuccess = -5;
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}

hr = pItem->Verbs(&pVerbs);
if(FAILED(hr) || (pVerbs == NULL))
{
iSuccess = -6;
pItem->Release();
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}

/* Here we would do something with the FolderItemVerbs */

pVerbs->Release(); pVerbs = NULL; //If this line is commented out, we don't get a crash, but a massive memory leak!
pItem->Release(); pItem = NULL;
pFolder->Release(); pFolder = NULL;
pShellDispatch->Release(); pShellDispatch = NULL;

iSuccess = 1;
return iSuccess;
}

//-----------------------------------------------------------------------------

static unsigned __stdcall ThreadProc(void* pArguments)
{
HRESULT hr = CoInitialize(NULL);
if((hr == S_OK) || (hr == S_FALSE))
{
threadParam_t *params = (threadParam_t*) pArguments;
params->returnValue = TestProc(params->pcDirectoryName, params->pcFileName);
CoUninitialize();
}
else
{
if(threadParam_t *params = (threadParam_t*) pArguments)
{
params->returnValue = -10;
}
}

return EXIT_SUCCESS;
}

Пожалуйста, загрузите полный Пример кода здесь:
http://pastie.org/private/0xsnajpia9lsmgnlf2afa

Обратите также внимание, что я однозначно отследил FolderItemVerbs, потому что если я никогда не создаю FolderItemVerbs объект, крах немедленно исчез.

Также, если я никогда не буду вызывать «pVerbs-> Release ()» раньше CoUninitialize () авария тоже прошла, но это, очевидно, приведет к массивной утечке памяти.

Еще одна странная вещь заключается в том, что сбой не произойдет, если я запускаю программу под отладчиком! Но я могу запустить программу, дождаться сбоя и затем позволить Отладчику обработать сбой.

К сожалению, трассировка стека, которую я получаю, не сильно помогает:
http://pastie.org/private/cuwunlun2t5dc5lembpw

Я не думаю, что я делаю что-то не так здесь. Я проверял код снова и снова в последние два дня. Так что все это, похоже, ошибка в FolderItemVerbs!

Кто-нибудь сталкивался с этим раньше и / или может подтвердить, что это ошибка в FolderItemVerbs? Кроме того, есть ли решение этой проблемы?

Заранее спасибо !!!

4

Решение

Спасибо всем!

Вот «исправленный» код, который выполняет явную диспетчеризацию сообщений:

void DispatchPendingMessages(void)
{
const DWORD uiTimeout = GetTickCount() + 10000;
const HANDLE hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
unsigned int counter = 0;
if(hEvent)
{
for(;;)
{
MSG Message;
while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
const DWORD nWaitResult = MsgWaitForMultipleObjects(1, &hEvent, FALSE, 250, QS_ALLINPUT | QS_ALLPOSTMESSAGE);
if((nWaitResult == WAIT_TIMEOUT) || (nWaitResult == WAIT_FAILED) || (GetTickCount() >= uiTimeout)) break;
}
CloseHandle(hEvent);
}
}

//-----------------------------------------------------------------------------

static int TestProc(const TCHAR *pcDirectoryName, const TCHAR *pcFileName)
{
int iSuccess = 0;

IShellDispatch *pShellDispatch = NULL;
Folder *pFolder = NULL; FolderItem *pItem = NULL;
FolderItemVerbs *pVerbs = NULL;

HRESULT hr = CoCreateInstance(CLSID_Shell, NULL, CLSCTX_INPROC_SERVER, IID_IShellDispatch, (void**)&pShellDispatch);
if(FAILED(hr) || (pShellDispatch ==  NULL))
{
iSuccess = -3;
return iSuccess;
}

variant_t vaDirectory(pcDirectoryName);
hr = pShellDispatch->NameSpace(vaDirectory, &pFolder);
if(FAILED(hr) || (pFolder == NULL))
{
iSuccess = -4;
pShellDispatch->Release();
return iSuccess;
}

variant_t vaFileName(pcFileName);
hr = pFolder->ParseName(vaFileName, &pItem);
if(FAILED(hr) || (pItem == NULL))
{
iSuccess = -5;
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}

hr = pItem->Verbs(&pVerbs);
if(FAILED(hr) || (pVerbs == NULL))
{
iSuccess = -6;
pItem->Release();
pFolder->Release();
pShellDispatch->Release();
return iSuccess;
}

/* Here we would do something with the FolderItemVerbs */

pVerbs->Release(); pVerbs = NULL;
pItem->Release(); pItem = NULL;
pFolder->Release(); pFolder = NULL;
pShellDispatch->Release(); pShellDispatch = NULL;

iSuccess = 1;
return iSuccess;
}

//-----------------------------------------------------------------------------

static unsigned __stdcall ThreadProc(void* pArguments)
{
HRESULT hr = CoInitialize(NULL);
if((hr == S_OK) || (hr == S_FALSE))
{
threadParam_t *params = (threadParam_t*) pArguments;
params->returnValue = TestProc(params->pcDirectoryName, params->pcFileName);
DispatchPendingMessages(); //This is required before CoUninitialize() to avoid crash with certain Shell Extensions !!!
CoUninitialize();
}
else
{
if(threadParam_t *params = (threadParam_t*) pArguments)
{
params->returnValue = -10;
}
}

return EXIT_SUCCESS;
}

Не удалось воспроизвести аварию с тот пока код 🙂

0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]