Вопрос, заданный пользователем, касается работы с массивами в Delphi в контексте использования API известных папок Windows. В частности, рассматривается функция IKnownFolderManager::GetFolderIds, которая возвращает массив идентификаторов известных папок. В Delphi для работы с такими функциями, возвращающими массив, необходимо использовать указатели, так как стандартная обработка массивов в Delphi не позволяет корректно передать адрес массива в функцию, ожидающую указатель.
Описание проблемы
Функция IKnownFolderManager::GetFolderIds в Windows API определена следующим образом:
После успешного вызова этой функции ppKFId указывает на массив идентификаторов KNOWNFOLDERID, который является массивом GUID. Эти данные выделены в куче и должны быть освобождены с помощью функции CoTaskMemFree.
В версии Delphi, представленной в модуле ShlObj.pas (Delphi Alexandria 11.2), функция GetFolderIds определена так:
function GetFolderIds(ppKFId: array of TKnownFolderID; var pCount: UINT): HRESULT; stdcall;
где TKnownFolderID соответствует типу TGUID.
Пользователь пытается определить переменную в Delphi, которая удовлетворяла бы параметру "массив из TKnownFolderID", но при этом могла бы быть освобождена с помощью CoTaskMemFree, требующего указатель.
Подходы, которые не работают
Пользователь пытался использовать различные подходы, включая определение динамического массива, преобразование массива в указатель, использование записей с условным типом и другие, но все они приводили к ошибкам компиляции или исключениям защиты.
Подтвержденный ответ
Проблемой является некорректное определение функции GetFolderIds в модуле ShlObj.pas. В Delphi для работы с массивами, возвращаемыми функцией, необходимо использовать указатели, а не открытые массивы. Правильное определение функции должно выглядеть следующим образом:
function GetFolderIds(var ppKFId: PKnownFolderID; var pCount: UINT): HRESULT; stdcall;
Использование функции с правильным определанием будет выглядеть так:
var
FolderList: PKnownFolderID;
Count: UINT;
begin
...
OleCheck(Mgr.GetFolderIds(FolderList, Count));
...
CoTaskMemFree(FolderList);
end;
Пользователь сообщил об этой ошибке в Embarcadero, и до тех пор, пока разработчики не исправят ее, вам придется скопировать определение интерфейса IKnownFolderManager в свой проект, исправить ошибку и использовать его в своем коде.
Альтернативный ответ
Если нет возможности исправить определение функции в модуле ShlObj.pas, можно использовать альтернативный подход, описанный пользователем, который заключается в преобразовании указателя на массив в переменную типа PKnownFolderID и последующем использовании этой переменной для вызова функции GetFolderIds. Этот подход позволяет корректно работать с функцией, получать список известных папок и корректно освобождать память.
Пример кода
type
PKnownFolderID = ^TKnownFolderID;
var
FolderListPointer: PKnownFolderID;
begin
pointer(FolderListPointer) := nil;
...GetFolderIds(FolderListPointer, ...);
...
CoTaskMemFree(FolderListPointer);
pointer(FolderListPointer) := nil;
end;
Обратите внимание, что данный подход не является идеальным, так как требует явного преобразования и может быть не так удобен в использовании, как исправленная версия модуля ShlObj.pas.
Вопрос связан с использованием функций Windows API для работы с известными папками в Delphi, где требуется корректно обработать возвращаемый функцией массив идентификаторов и освободить выделенную для него память.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.