从IShellLibrary添加,删除文件夹

Bil*_*ill 5 delphi winapi iunknown delphi-xe4

我正在尝试编写两个添加和删除文件夹的函数IShellLibrary.我从这开始,但该函数在System._IntfClear以下方面产生异常:

$ 000007FEFE 168BC4的首次机会异常.消息'c0000005 ACCESS_VIOLATION'的异常类$ C0000005.

SHAddFolderPathToLibrary是导致异常的行.

我想我需要将库名添加到函数中?

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;
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 7

这里的问题是,翻译的Embarcadero工程师SHAddFolderPathToLibrary不理解COM引用计数,以及不同编译器如何处理它.

以下SHAddFolderPathToLibrary是在C++头文件中实现的方法Shobjidl.h.它实际上是其他核心API调用的内联包装:

__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;
}
Run Code Online (Sandbox Code Playgroud)

Delphi的翻译非常忠实,确实过于忠诚:

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;
Run Code Online (Sandbox Code Playgroud)

问题是打电话给_Release.Delphi编译器管理引用计数,因此这个显式调用_Release是伪造的,不应该存在.由于编译器将安排调用_Release,这个额外的调用只会使引用计数失去平衡.之所以_AddRef_Release前缀的原因_是提醒人们不要打电话给他们并让编译器这样做.

Release对C++版本的调用是准确的,因为Release除非将接口包装在COM智能指针中,否则C++编译器不会自动为您调用.但是Embarcadero的工程师盲目地将它复制过来,你将留下后果.显然,这个代码甚至从未被Embarcadero工程师执行过.

您需要提供自己的此功能的更正实现.还有任何其他错误翻译的功能._ReleaseShlObj单元中搜索,并在更正的版本中删除它们.翻译中还有其他错误,请注意.例如,SHLoadLibraryFromItem(和其他人)声明plib: ^IShellLibrary应该是的局部变量plib: IShellLibrary.

我提交了质量控制报告:QC#117351.