ISHELLDISPTACH:为什么folderitemverbs :: Release() counitializ

IShellDisptach: Why does FolderItemVerbs::Release() + CoUninitialize() crash?

本文关键字:counitializ folderitemverbs 为什么 ISHELLDISPTACH Release      更新时间:2023-10-16

我在 ishellDisPatch com接口方面遇到一个非常奇怪的问题,更具体地说是 folderitemverbs 对象,它使我发疯!

调用 folderitemverbs :: Release(),其次是 couninitialze()将导致崩溃。这显然是可重复的,但仅发生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 对象,崩溃就会立即消失。

另外,如果我从未在 counitialize()之前称呼" pverbs-> repares()",崩溃也消失了,但这显然会导致大量的memleak。

另一个奇怪的事情是,如果我在调试器下运行程序,崩溃将不会发生!但是我可以运行程序,等待崩溃,然后让调试器处理崩溃。

不幸的是,我得到的堆栈跟踪无济于事:http://pastie.org/private/cuwunlun2t5dc5lembpw

我认为我在这里做错了什么。在过去的两天中,我一遍又一遍地检查了代码。因此,这一切似乎都是folderitemverbs中的错误!

有人在以前遇到过这个问题吗?/或可以确认这是文件列表中的错误?另外,是否有解决问题的解决方法?

预先感谢!!!

谢谢大家!

这是执行明确消息的"更正"代码:

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;
}

到目前为止无法用重现崩溃: - )