Разработчики, использующие Delphi для создания многопоточных приложений, могут столкнуться с ошибкой 87, когда пытаются загрузить библиотеку DLL в нескольких потоках. Эта проблема связана с неправильным управлением ресурсами и неправильной обработкой возвращаемых значений функций WinAPI. Давайте рассмотрим, как можно решить эту проблему.
Пример кода, вызывающего ошибку 87
В примере кода, предоставленном пользователем, есть несколько моментов, которые могут привести к ошибке 87. Например, функция загрузки DLL вызывается в каждом потоке отдельно, что может привести к конфликтам, если DLL уже загружена в адресном пространстве процесса.
procedure TWorker.LoadDll;
begin
FDLLHandle := LoadLibraryA(PChar(FPathApp + 'MyCalcFor32.dll'));
if GetLastError <> 0 then
begin
NotifyTerminateThread;
end
else
begin
FEvalProcAddress := GetProcAddress(FDLLHandle, PChar('EVal'));
if GetLastError <> 0 then
begin
NotifyTerminateThread;
end;
end;
end;
Анализ проблемы
Проблема заключается в том, что GetLastError может возвращать устаревшую ошибку, которая не связана с последним выполненным действием. Кроме того, не все успешные вызовы функций сбрасывают GetLastError в 0. Необходимо проверять возвращаемые значения функций, а не GetLastError.
Решение проблемы
Загрузка DLL один раз - загрузите DLL в основном потоке, а затем передайте дескриптор модуля в другие потоки.
Проверка возвращаемых значений - проверяйте возвращаемые значения функций LoadLibrary и GetProcAddress, а не используйте GetLastError для определения успеха вызова.
Пример исправленного кода
procedure TfrmMain.FormCreate(Sender: TObject);
begin
// Создание потоков без загрузки DLL
end;
procedure TfrmMain.btnExecuteThreadsClick(Sender: TObject);
begin
// Загрузка DLL в основном потоке
FDLLHandle := LoadLibraryA(PChar(FPathApp + 'MyCalcFor32.dll'));
if FDLLHandle = 0 then
begin
// Обработка ошибки
ShowMessage('Не удалось загрузить DLL');
Exit;
end;
FEvalProcAddress := GetProcAddress(FDLLHandle, PChar('EVal'));
if FEvalProcAddress = nil then
begin
// Обработка ошибки
FreeLibrary(FDLLHandle);
ShowMessage('Не удалось получить адрес функции');
Exit;
end;
// Передача информации о DLL в потоки
for I := 0 to High(Threads) do
Threads[I].DLLHandle := FDLLHandle;
Threads[I].FEvalProcAddress := FEvalProcAddress;
// Запуск потоков
for I := 0 to High(Threads) do
Threads[I].Resume;
end;
procedure TWorker.Execute;
begin
// Использование переданных адресов функции
Ret := FEvalProcAddress(FEValValue);
end;
procedure TWorker.Finalize;
begin
if Assigned(FDLLHandle) then
FreeLibrary(FDLLHandle);
end;
Заключение
При работе с многопоточными приложениями и загрузке DLL важно правильно управлять ресурсами и обрабатывать возвращаемые значения функций. Следуя приведенным рекомендациям, можно избежать ошибки 87 и других подобных проблем.
Разработчики в Delphi сталкиваются с ошибкой 87 при попытке загрузки DLL в многопоточной среде из-за неправильного управления ресурсами и обработки возвращаемых значений функций WinAPI.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.