2013-07-23 2 views
4

Я пытаюсь написать две функции, которые добавляют и удаляют папку из IShellLibrary. Я начал с этого, но функция создает исключение в System._IntfClear:Добавить, удалить папку из IShellLibrary

Первое исключение случайности в $ 000007FEFE 168BC4. Класс исключения $ C0000005 с сообщением 'c0000005 ACCESS_VIOLATION'.

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 с сообщением 'c0000005 ACCESS_VIOLATION'. – Bill

+0

@Tlama смотрит на реализацию SHAddFolderPathToLibrary - почему '' (psiFolder: IShellItem) ._ Release() 'явно называется там? возможно, требуется вызов 'plib._Release()'? –

ответ

6

Проблема здесь состоит в том, что инженер 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; 
} 

И перевод 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; 

Проблема заключается вызов _Release. Компилятор Delphi управляет подсчетом ссылок, поэтому этот явный вызов _Release является фиктивным и его не должно быть. Поскольку компилятор организует вызов для _Release, этот дополнительный параметр просто уравновешивает подсчет ссылок. Причина, по которой _AddRef и _Release имеет префикс _, - это напоминание людям, чтобы они не вызывали их и не позволяли компилятору это делать.

Вызов Release в версии C++ является точной, потому что компиляторы C++ автоматически не вызывают Release, если вы не обернете интерфейс в интеллектуальный указатель COM. Но инженер Embarcadero слепо скопировал его, и у вас остались последствия. Очевидно, что этот код никогда не выполнялся инженерами Embarcadero.

Необходимо выполнить собственное исправление этой функции. А также любая другая ошибочно переведенная функция. Найдите _Release в блоке ShlObj и удалите их в исправленных версиях. В переводе есть и другие ошибки, поэтому следите. Например, SHLoadLibraryFromItem (и другие) объявляют локальную переменную plib: ^IShellLibrary, которая должна быть plib: IShellLibrary.

Я представил отчет о контроле качества: QC#117351.

+0

@ Дэвид. Вы говорите, что проблема с SHAddFolderPathtoLibrary является проблемой, и сейчас я должен отказаться от этого? – Bill

+0

Реализация 'SHAddFolderPathtoLibrary' в' ShlObj' неверна. Это проблема. Вам нужно будет написать свой собственный. Удалите вызов '_Release', и все это хорошо. –

+0

Я сделал именно это, но папка не добавлена ​​в библиотеки? Однако исключение прошло. – Bill

Смежные вопросы