Add, remove folder from IShellLibrary

I am trying to write two functions that add and remove a folder from IShellLibrary . I started with this, but the function System._IntfClear an exception in System._IntfClear :

The first random exception was $ 000007FEFE 168BC4. The exception class is $ C0000005 with the message 'c0000005 ACCESS_VIOLATION'.

SHAddFolderPathToLibrary is the string that throws the exception.

Think I need to add a library name to a function?

 function AddFolderToLibrary(AFolder: string): HRESULT; { Add AFolder to Windows 7 library. } var plib: IShellLibrary; begin Result := CoCreateInstance(CLSID_ShellLibrary, nil, CLSCTX_INPROC_SERVER, IID_IShellLibrary, plib); if SUCCEEDED(Result) then begin Result := SHAddFolderPathToLibrary(plib, PWideChar(AFolder)); end; end; function RemoveFolderFromLibrary(AFolder: string): HRESULT; { Remove AFolder from Windows 7 library. } var plib: IShellLibrary; begin Result := CoCreateInstance(CLSID_ShellLibrary, nil, CLSCTX_INPROC_SERVER, IID_IShellLibrary, plib); if SUCCEEDED(Result) then begin Result := SHRemoveFolderPathFromLibrary(plib, PWideChar(AFolder)); end; end; 
+4
source share
1 answer

The problem is that the Embarcadero engineer, who translated SHAddFolderPathToLibrary , does not understand COM reference counting and how it is handled by different compilers.

Here, SHAddFolderPathToLibrary is implemented in the C ++ header file Shobjidl.h . This is actually a built-in wrapper for other core API calls:

 __inline HRESULT SHAddFolderPathToLibrary(_In_ IShellLibrary *plib, _In_ PCWSTR pszFolderPath) { IShellItem *psiFolder; HRESULT hr = SHCreateItemFromParsingName(pszFolderPath, NULL, IID_PPV_ARGS(&psiFolder)); if (SUCCEEDED(hr)) { hr = plib->AddFolder(psiFolder); psiFolder->Release(); } return hr; } 

And the translation of Delphi is very true, and in reality too true:

 function SHAddFolderPathToLibrary(const plib: IShellLibrary; pszFolderPath: LPCWSTR): HResult; var psiFolder: IShellItem; begin Result := SHCreateItemFromParsingName(pszFolderPath, nil, IID_IShellItem, psiFolder); if Succeeded(Result) then begin Result := plib.AddFolder(psiFolder); psiFolder._Release(); end; end; 

The problem is calling _Release . The Delphi compiler controls the reference count, so this explicit call to _Release is fictitious and should not _Release . Since the compiler organizes the call to _Release , this additional parameter simply balances the reference count. The reason _AddRef and _Release has the _ prefix is ​​to remind people that they don't call them, and let the compiler do this.

Calling Release in C ++ is accurate because C ++ compilers do not automatically call Release for you unless you wrap the interface in a smart COM pointer. But the Embarcadero engineer blindly copied it, and you still have consequences. Obviously, this code was never executed by Embarcadero engineers.

You will need to execute your own patched implementation of this function. As well as any other erroneously translated function. Locate _Release in the ShlObj module and remove them in the patched versions. There are other errors in the translation, so watch out. For example, SHLoadLibraryFromItem (and others) declare a local variable plib: ^IShellLibrary , which should be plib: IShellLibrary .

I submitted a QC report: QC # 117351 .

+6
source

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


All Articles