2013-07-23 5 views
4

IShellLibrary에서 폴더를 추가하고 제거하는 두 가지 함수를 작성하려고합니다. 나는이 시작되지만 기능은 System._IntfClear에서 예외를 생성합니다IShellLibrary에서 폴더 추가, 제거

첫 번째 예외를 $ 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; 
+0

@Ken : 내 편집을 참조하십시오. – Bill

+0

$ 000007FEFE 168BC4의 첫 번째 기회 예외. 'c0000005 ACCESS_VIOLATION'메시지가있는 예외 클래스 $ C0000005. – Bill

+0

@Tlama가 SHAddFolderPathToLibrary 구현을보고 있습니다 - 왜'(psiFolder : IShellItem) ._ Release()'가 명시 적으로 호출 되었습니까? 어쩌면'plib._Release()'호출도 필요합니까? –

답변

6

문제는 그 COM 참조 카운팅을 이해하지 못하는 SHAddFolderPathToLibrary을 번역하고는 다른 컴파일러에 의해 처리하는 방법 엠바 카데로 엔지니어.

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

그리고 델파이 번역은 참으로 너무 충실, 매우 충실 :

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; 

문제는 _Release에 대한 호출입니다. 델파이 컴파일러는 참조 카운팅을 관리하므로 _Release에 대한이 명시적인 호출은 가짜이며 거기에 있으면 안됩니다. 컴파일러가 _Release에 대한 호출을 준비 할 것이기 때문에이 여분의 하나는 단순히 참조 카운팅의 불균형을 초래합니다. _AddRef_Release의 접두어가 _ 인 이유는 사람들에게 전화하지 말고 컴파일러가 그렇게하도록 상기시키는 것입니다. 당신이 COM 스마트 포인터의 인터페이스를 마무리하지 않는 한 C++ 컴파일러는 자동으로 Release를 호출하지 않기 때문에

는 C++ 버전 Release에 대한 호출은 정확합니다. 그러나 엠바 카데로 엔지니어는 맹목적으로 그것을 빗나갔습니다. 분명히이 코드는 엠바 카데로 엔지니어들에 의해 실행 된 적도 없습니다.

이 기능의 수정 된 구현을 제공해야합니다. 또한 다른 번역 된 기능도 있습니다. ShlObj 단위에서 _Release을 검색하여 수정 된 버전에서 제거하십시오. 번역에 다른 버그가 있으므로 조심하십시오. 예를 들어 SHLoadLibraryFromItem (및 기타)은 로컬 변수 plib: ^IShellLibraryplib: IShellLibrary이어야한다고 선언합니다.

QC 보고서 (QC#117351)를 제출했습니다.

+0

@ David - SHAddFolderPathtoLibrary가 문제라고 말하고 있으며 지금 당장이를 포기해야합니까? – Bill

+0

ShlObj에서 'SHAddFolderPathtoLibrary'의 구현이 잘못되었습니다. 그것이 문제이다. 직접 작성해야합니다. '_Release'에 대한 호출을 제거하면 모든 것이 잘됩니다. –

+0

그랬지만 폴더가 라이브러리에 추가되지 않았습니까? 그러나 예외는 사라졌습니다. – Bill