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

I have a very strange problem with the IShellDispatch COM interface, more specifically with the FolderItemVerbs object that turns me on!

A call to FolderItemVerbs :: Release (), followed by CoUninitialze (), will fail. It is clearly reproducible, but only once out of 10 times.

Error - error "0xC0000005: access violation". Running the problem code in a 100% cycle sooner or later leads to a failure: - (

See an example program:

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

Please download the full sample code here: http://pastie.org/private/0xsnajpia9lsmgnlf2afa

Also note that I have explicitly tracked it to failure before FolderItemVerbs , because if I never create a FolderItemVerbs object, the crash will disappear immediately.

Also, if I never call "pVerbs-> Release ()" before CoUninitialize (), the failure will also disappear, but this will lead to a massive memleak, obviously.

Another strange thing: a crash will not happen if I run the program under Debugger! But I can run the program, wait for the crash, and then let the debugger deal with the failure.

Unfortunately, the stack trace I get doesn't help much: http://pastie.org/private/cuwunlun2t5dc5lembpw

I do not think that I am doing something wrong. I have been checking the code again and again over the past two days. So all this seems to be a mistake in FolderItemVerbs!

Has anyone come across this before and / or can confirm that this is a bug in FolderItemVerbs? Also, is there a workaround?

Thanks in advance!

+4
source share
1 answer

Thanks everyone!

Here is the "fixed" code that performs explicit message scheduling:

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

Failed to reproduce a crash with this code :-)

0
source

Source: https://habr.com/ru/post/1441369/


All Articles