Delphi не загружается dll

Обновлено: 01.07.2024

Я загружаю DLL, используя LoadLibrary из моего проекта Delphi, вот так:

Каталог, в котором находится DLL, включен в переменную окружения Windows PATH. Когда я выполняю этот проект из Delphi, DLL не загружается. Однако, когда тот же самый код выполняется непосредственно из Windows, DLL загружается идеально.

Что я здесь упускаю? Я пытался явно указать Delphi посмотреть в каталоге DLL путем добавления каталога в Инструменты->Параметры параметры->среда Delphi параметры->библиотека - с Win32->Library путь. (Это похоже на полное PEBKAC. Я предвижу смущение для себя в ближайшем будущем :) . )

1 ответ

Мне нужно написать DLL (используя Delphi), который динамически загружается в delphi приложений и делает RTTI запроса (типичная операция-получение строковых значений для свойств управления). Классическая проблема заключается в том, что передача строк (и объектов) между приложением и DLL.

Я построил dll в Delphi 2010 году, и он потребляется в моем приложении delphi 7. Я знаю о unicode AnsiString / string matter, и, согласно моим тестам, все работает нормально до того момента, когда мое delphi 2010 dll не вызывает никаких исключений. Дело в том, есть ли какое-либо.

В большинстве случаев, когда у меня возникает аналогичная проблема(работает с windows, а не с отладчиком), это происходит из-за "user overrides"

(Меню"Проект->Параметры", "Отладчик->Блок среды")

Возможно, у вас есть переопределение пользователя для "Windows Path", поэтому он не работает при запуске из отладчика.

Похожие вопросы:

Во-первых, простите меня, если это вопрос школьника :) У нас есть несколько приложений, которые пользователь Delphi dbxpress получает доступ к серверу MySQL 5. Все эти приложения были написаны на.

Мне нужно написать DLL (используя Delphi), который динамически загружается в delphi приложений и делает RTTI запроса (типичная операция-получение строковых значений для свойств управления).

Я построил dll в Delphi 2010 году, и он потребляется в моем приложении delphi 7. Я знаю о unicode AnsiString / string matter, и, согласно моим тестам, все работает нормально до того момента, когда.

На работе я уже несколько лет использую Delphi 6 & 7 Enterprise. Несколько лет назад я купил личный экземпляр Turbo Delphi Professional. Из-за этого я имею право на профессиональное обновление.

Мое приложение скомпилировано с Delphi 2010. Это приложение загружает Delphi 7 compiled DLL, который загружает Delphi 2010 compiled DLL. D2010 app LOADS D7 DLL LOADS D2010 DLL Экспортированные.

Мое программное обеспечение, разработанное под Delphi 7.0, было обновлено и разработано под Delphi 2010 RAD Studio XE. Он также сохраняет или записывает пользовательские настройки в двоичные файлы.

Я пытаюсь создать геккона 2.0-compatible DLL в Delphi. Ранее (до Gecko 2.0) DLL требовалось экспортировать функцию NSGetModule(). Это сработало безупречно. Начиная с Firefox 4, Мой DLL загружается.

Я пытаюсь вызвать DLL, построенный с Delphi 7 (до поддержки unicode), используя Delphi XE2. Код такой: function Foo(Param1: PChar; Var Param2: DWORD; Var Param3: DWORD): PChar; stdcall; external.

Пожалуйста, выделяйте текст программы тегом [сode=pas] . [/сode] . Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Windows 7 x32. Delphi 2010

Добавлено 02.07.11, 17:09
SysErrorMessage(GetLastError)

Выдал: The handle is invalid



MAcK
Хорошо бы еще узнать что в Path? Там случайно не относительный путь? MAcK
Хорошо бы еще узнать что в Path? Там случайно не относительный путь?



пример в студию.

MyControl := TrdCobol.Create(ExtractFilePath(Application.ExeName));



если библиотека находится возле exe файла то путь не обязательный. он используется первый при поиске библиотеки.

вероятнее всего библиотеки нет там откуда ты питаешься ее загрузить. еще раз проверь где находится библиотека и куда собирает проект делфя




Поясни, пожалуйста. Хотя бы в личку. Хотя бы только "подозрения". Может мне это поможет в моей личной проблеме.



Что бы появилось окно с запросом на права админа нужно что то из:
1) Запустить с админа правами в ручную (поставить птичку в свойствах или через командную строку)
2) Написать манифест с уровнем доступа requireAdministrator
3) Создать процесс через WinApi (где то я даже находил такой примерчик. и точно помню что я его куда то себе "заныкал" а вот куда не помню)

Если UAC отключен то естественно окна не будет.
Если процесс запускается от процесса у которого уже есть админ права то окна не будет, при этом админ права ему будут предоставлены в не зависимости нужны они ему или нет. исключение если при создании процесса позаботится что бы они ему не передавались.

вероятнее всего библиотеки нет там откуда ты питаешься ее загрузить. еще раз проверь где находится библиотека и куда собирает проект делфя

Проверял и не раз. Если ту же ехе(где собрал её делфи) запустить, то всё ок, даже без прав админа.

Репутация: нет
Всего: нет

загружаю дллку в мой файл. Потом эта длл таким же образом пытается загрузить ещё одну длл, но DLLI:=0, почему такое происходит, и как загрузить из длл другую длл?

Путь до дллки 100% верный.

Репутация: нет
Всего: нет

попробуй получить хендл файла через CreateFile
если не сможеш, то что-то у него с путем или правами у тебя

Репутация: нет
Всего: нет

Если его загружать не из dll, то он загружается.
То есть если делать так
exe загружает dll2
то всё ОК, а если так:
exe загружает dll1, dll1 загружает dll2
то dll2 просто не загружается

Репутация: нет
Всего: нет

какой путь передается dll1 для загрузки dll2?

Добавлено через 1 минуту и 10 секунд
хендл файла получается при вызове CreateFile?

Репутация: нет
Всего: нет

хендл длл DLLI:=LoadLibrary(name);

exe загружает dll2 - длл загружена, Работает!
exe загружает dll1, dll1 загружает dll2 - длл НЕ загружена, НЕ работает.

Репутация: нет
Всего: нет

exe загружает dll1, dll1 читает данные из файла dll2 - данные прочитаны?
с помощью CreateFile, ReadFile

Репутация: 18
Всего: 88

GetLastError что возвращает?
Уж не в dllmain ли ты загружаешь другую длл? Этого делать нельзя.

Репутация: нет
Всего: нет

я не читаю данные другой длл, мне нужно загрузить в длл другую длл, так же как это делает loadlibrary

Репутация: 18
Всего: 88

Да читаешь или нет это без разницы. все точки входа в длл выстраиваются системой друг за другом (в пределах процесса), поэтому когда одна длл находится в dllmain (в дельфи это основной блок begin-end длл а также все секции инициализации юнитов), не может быть вызвана dllmain другой длл. А значит она не может быть загружена (потому что чтобы LoadLibrary успешно отработала dllmain должна вернуть успех, в дельфи это значение переменной ExitCode)
можно загрузить только as data file, но тогда ты получишь хендл, но вызывать функции из длл не сможешь

Репутация: нет
Всего: нет

Репутация: 18
Всего: 88

Загружать в подходящем для этого месте. Либо связать с первой длл статически

Репутация: нет
Всего: нет

Репутация: 18
Всего: 88

импортировать оттуда функцию с помощью ключевого слова external при объявлении функции. Длл будет загружена "одновременно" с твоей

Репутация: нет
Всего: нет

Цитата

импортировать оттуда функцию с помощью ключевого слова external при объявлении функции.
Цитата

Длл будет загружена "одновременно" с твоей

Вторая длл на момент запуска первой может и не существовать, и появится значительно позже первой.
например я загружаю первую длл. Через час появляется вторая длл(и первая узнаёт её имя), и первой нужно воспользоваться функциями второй

и ещё один момент, в длл2 есть функции которые используют Глобальные переменные этой длл, и есть поток. То есть работает поток, меняет значения переменных, а фукции при вызове получают значения этих переменных, делают некоторые действия с ними, и возвращают результат.
Сомневаюсь что external мне поможет.
Какие есть ещё варианты?

Репутация: 12
Всего: 20

Вторая длл на момент запуска первой может и не существовать, и появится значительно позже первой.
например я загружаю первую длл. Через час появляется вторая длл(и первая узнаёт её имя), и первой нужно воспользоваться функциями второй

Вы уже столько напустили туману, что и ответить сложно. Ибо самой задачи вашей мы не знаем.
Но например. Почему бы вам не загружать обе dll в саму вашу программу? Они обе загружались бы в АП вашего процесса и можно было бы как-то организовать взаимодействие между ними.
Ну и вдобавок. Но строго имхо. Технология DLL разрабатывалась как технология ориентированная на экспорт, а импорт только подразумевался. Статический.

Но только лошади летают вдохновенно.
Иначе лошади разбились бы мгновенно!

Репутация: нет
Всего: нет

Репутация: 18
Всего: 88

в отдельном потоке загрузка второй длл должна работать, потому что поток начнет работу уже после выхода из dllmain. проблема в чем-то другом.
Что возвращает GetLastError?

Репутация: нет
Всего: нет

Самое странное то, что если код длл поместить в exe, то есть прописать вместо library program, то всё работает.
Но суть задачи в том, чтобы заставить этот код работать именно так, как я описал выше.
То есть заставить выполняться код второй длл при загрузке из первой.

Репутация: нет
Всего: нет

Всё дело в аспаке. длл2 запакована аспаком. Без аспака работает, с ним нет.
Но если без первой, сразу грузить вторую то и аспак не помеха. В чём дело? Почему так?

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

[ Время генерации скрипта: 0.1448 ] [ Использовано запросов: 21 ] [ GZIP включён ]

что первую часть статьи они могут посмотреть в архиве рассылки, выпуск номер 13.

Прежде чем начать использование какой-либо процедуры или функции, находящейся в динамической библиотеке,

вам необходимо загрузить DLL в оперативную память. Загрузка библиотеки может быть осуществлена

одним из двух способов: статическая загрузка и динамическая загрузка.

Оба метода имеют как преимущества, так и недостатки.

Статическая загрузка означает, что динамическая библиотека загружается автоматически

при запуске на выполнение использующего ее приложения. Для того чтобы использовать такой способ загрузки,

вам необходимо воспользоваться ключевым словом external при описании экспортируемой из

динамической библиотеки функции или процедуры. DLL автоматически загружается при старте программы,

и Вы сможете использовать любые экспортируемые из нее подпрограммы точно так же,

как если бы они были описаны внутри модулей приложения.

Это наиболее легкий способ использования кода, помещенного в DLL .

Недостаток метода заключается в том, что если файл библиотеки, на который

имеется ссылка в приложении, отсутствует, программа откажется загружаться.

Смысл динамического метода заключается в том, что вы загружаете библиотеку не при старте приложения,

а в тот момент, когда вам это действительно необходимо. Сами посудите, ведь если функция, описанная

в динамической библиотеке, используется только при 10% запусков программы, то совершенно нет

смысла использовать статический метод загрузки. Выгрузка библиотеки из памяти в данном случае

также осуществляется под вашим контролем. Еще одно преимущества такого способа

загрузки DLL - это уменьшение (по понятным причинам) времени старта вашего приложения.

А какие же у этого способа имеются недостатки? Основной, как мне кажется, - это то, что использование

данного метода является более хлопотным, чем рассмотренная выше статическая загрузка.

Сначала вам необходимо воспользоваться функцией Windows API LoadLibrary .

Для получения указателя на экспортируемой процедуры или функции должна

использоваться функция GetProcAddress. После завершения использования библиотеки DLL

должна быть выгружена с применением FreeLibrary.

Вызов процедур и функций, загруженных из DLL.

Способ вызова процедур и функций зависит от того, каким образом вы загрузили динамическую библиотеку,

в которой эти подпрограммы находятся.

Вызов функций и процедур из статически загруженных DLL достаточно прост. Первоначально в приложении

должно содержаться описание экспортируемой функции (процедуры). После этого вы можете их использовать

точно так же, как если бы они были описаны в одном из модулей вашего приложения.

Для импорта функции или процедуры, содержащейся в DLL , необходимо использовать

модификатор external в их объявлении. К примеру, для рассмотренной нами выше процедуры HelloWorld

в вызывающем приложении должна быть помещена следующая строка:

procedure SayHello(AForm : TForm); external myfirstdll.dll';

Ключевое слово external сообщает компилятору, что данная процедура может быть найдена в

динамической библиотеке (в нашем случае - myfirstdll.dll).

Далее вызов этой процедуры выглядит следующим образом:

При импорте функции и процедур будьте особенно внимательны при написании их имен и интерфейсов!

Дело в том, что в процессе компиляции приложения не производится проверки на правильность имен объектов,

экспортируемых из DLL, осуществляться не будет, и если вы неправильно описали какую-нибудь функцию,

то исключение будет сгенерировано только на этапе выполнения приложения.

Импорт из DLL может проводиться по имени процедуры (функции), порядковому номеру или

с присвоением другого имени.

В первом случае вы просто объявляете имя процедуры и библиотеку, из которой ее импортируете

(мы это рассмотрели чуть выше). Импорт по порядковому номеру требует от вас указание этого самого номера:

procedure HelloWorld(AForm : TForm); external myfirstdll.dll index 15 ;

В этом случае имя, которое вы даете процедуре при импорте не обязательно должно совпадать с тем,

которое было указано для нее в самой DLL. Т.е. приведенная выше запись означает,

что вы импортируете из динамической библиотеки myfirstdll.dll процедуру, которая в ней экспортировалась

пятнадцатой, и при этом в рамках вашего приложения этой процедуре дается имя SayHello.

Если вы по каким-то причинам не применяете описанный выше способ импорта,

но тем не менее хотите изменить имя импортируемой функции (процедуры), то можно воспользоваться третьим методом:

procedure CoolProcedure; external myfirstdll.dll name 'DoSomethingReallyCool' ;

Здесь импортируемой процедуре CoolProcedure дается имя DoSomethingReallyCool.

Вызов процедур и функций, импортируемых из динамически загружаемых библиотек

несколько более сложен, чем рассмотренный нами выше способ. В данном случае требуется объявить

указатель на функцию или процедуру, которую вы собираетесь использовать.

Помните процедуру HelloWorld? Давайте посмотрим, что необходимо сделать для того,

чтобы вызвать ее на выполнение в случае динамической загрузки DLL. Во-первых, вам

необходимо объявить тип, который описывал бы эту процедуру:

THelloWorld = procedure (AForm : TForm);

Теперь вы должны загрузить динамическую библиотеку, с помощью GetProcAddress получить

указатель на процедуру, вызвать эту процедуру на выполнение, и, наконец, выгрузить DLL из памяти.

Ниже приведен код, демонстрирующий, как это можно сделать:

DLLInstance := LoadLibrary( 'myfirstdll.dll' );

@HelloWorld := GetProcAddress(DLLInstance, 'HelloWorld' );

Как уже говорилось выше, одним из недостатков статической загрузки DLL является невозможность

продолжения работы приложения при отсутствии одной или нескольких библиотек. В случае с динамической

загрузкой у вас появляется возможность программно обрабатывать такие ситуации и не допускать, чтобы программа

вываливалась» самостоятельно. По возвращаемому функциями LoadLibrary и GetProcAddress значениям можно

определить, успешно ли прошла загрузка библиотеки и найдена ли в ней необходимая приложению процедура.

Приведенный ниже код демонстрирует это.

procedure TForm1.DynamicLoadBtnClick(Sender: TObject);

THelloWorld = procedure (AForm : TForm);

DLLInstance := LoadLibrary( 'myfirstdll.dll' );

if DLLInstance = 0 then begin

MessageDlg( 'Невозможно загрузить DLL' , mtError, [mbOK], 0 );

@HelloWorld := GetProcAddress(DLLInstance, 'HelloWorld' );

if @HelloWorld nil then

MessageDlg( 'Не найдена искомая процедура!.' , mtError, [mbOK], 0 );

В DLL можно хранить не только код, но и формы.

Причем создание и помещение форм в динамическую библиотеку не слишком сильно отличается от работы

с формами в обычном проекте. Сначала мы рассмотрим, каким образом можно написать библиотеку,

содержащую формы, а затем мы поговорим об использовании технологии MDI в DLL.

Разработку DLL, содержащую форму, я продемонстрирую на примере.

Итак, во-первых, создадим новый проект динамической библиотеки.

Для этого выберем пункт меню File|New, а затем дважды щелкнем на иконку DLL .

После этого вы увидите примерно следующий код:

Сохраните полученный проект. Назовем его DllForms.dpr.

Теперь следует создать новую форму. Это можно сделать по-разному.

Например, выбрав пункт меню File|New Form. Добавьте на форму какие-нибудь компоненты.

Назовем форму DllForm и сохраним получившийся модуль под именем DllFormUnit.pas .

Вернемся к главному модулю проекта и поместим в него функцию ShowForm, в задачу которой будет входить

создание формы и ее вывод на экран. Используйте для этого приведенный ниже код.

function ShowForm : Integer; stdcall ;

Обращаю внимание, что для того, чтобы проект был скомпилирован без ошибок, необходимо добавить в секцию uses модуль Forms .

Экспортируем нашу функцию с использованием ключевого слова exports :

Компилируем проект и получаем файл dllforms.dll. Эти простые шаги - все,

что необходимо сделать для сОбратите внимание, что функция ShowForm объявлена с использованием ключевого слова stdcall .

Оно сигнализирует компилятору использовать при экспорте функции соглашение

по стандартному вызову (standard call calling convention). Экспорт функции таким образом создает

возможность использования разработанной DLL не только в приложениях, созданных в Delphi.

Соглашение по вызову (Calling conventions) определяет, каким образом передаются аргументы при вызове функции.

Существует пять основных соглашений: stdcall, cdecl, pascal, register и safecall.

Подробнее об этом можно узнать, посмотрев раздел " Calling Conventions " в файле помощи Delphi.

Также обратите внимание, что значение, возвращаемое функцией ShowForm ,

соответствует значению ShowModal. Таким образом вы можете передавать некоторую информацию

о состоянии формы вызывающему приложению.

Ниже представлено два листинга, первый из которых содержит полный код файла

проекта DLL (модуль с формой здесь не приводится), а второй - модуль вызывающего приложения,

в котором используется только что разработанная нами библиотека.

DllFormUnit in 'DllFormUnit.pas' ;

function ShowForm : Integer; stdcall ;

Windows, Messages, SysUtils, Classes, Graphics,

Controls, Forms, Dialogs, StdCtrls;

TForm1 = class (TForm)

procedure Button1Click(Sender: TObject);

function ShowForm : Integer; stdcall ;

procedure TForm1.Button1Click(Sender: TObject);

Прошу заметить, что при экспорте функции также было использовано ключевое слово stdcall.

Следует обратить особое внимание на работу с дочерними формами в DLL. Если, к примеру,

в вызывающем приложении главная форма имеет значение свойства FormStyle, равным MDIForm,

в котором будет говориться, что нет ни одной активной MDI-формы.

В тот момент, когда вы пытаетесь показать ваше дочернее окно, VCL проверяет корректность

свойства FormStyle главной формы приложения. Однако в нашем случае все вроде бы верно.

Так в чем же дело? Проблема в том, что при проведении такой проверки, рассматривается объект Application,

принадлежащий не вызывающему приложению, а собственно динамической библиотеке.

Ну, и естественно, поскольку в DLL нет главной формы, проверка выдает ошибку.

Для того чтобы избежать такой ситуации, надо назначить объекту Application динамической библиотеки

объект Application вызывающего приложения. Естественно, это заработает только в том случае,

когда вызывающая программа - VCL-приложение. Кроме того, перед выгрузкой библиотеки из памяти

необходимо вернуть значение объекта Application библиотеки в первоначальное состояние.

Это позволит менеджеру памяти очистить оперативную память, занимаемую библиотекой.

Следовательно, вам нужно сохранить указатель на «родной» для библиотеки объект Application

в глобальной переменной, которая может быть использована при восстановлении его значения.

Итак, вернемся немного назад и перечислим шаги, необходимые нам для работы с помещенным

в DLL MDIChild-формами.

В динамической библиотеке создаем глобальную переменную типа TApplication.

Сохраняем указатель на объект Application DLL в глобальной переменной.

Объекту Application динамической библиотеки ставим в соответствие указатель на Application

Создаем MDIChild-форму и работаем с ней.

Возвращаем в первоначальное состояние значение объекта Application динамической библиотеки

и выгружаем DLL из памяти.

Первый шаг прост. Просто помещаем следующий код в верхней части модуля DLL:

Затем создаем процедуру, которая будет изменять значение объекта Application и создавать дочернюю форму.

Процедура может выглядеть примерно так:

procedure ShowMDIChild(MainApp : TApplication);

if not Assigned(DllApp) then begin

Все, что нам теперь необходимо сделать, - это предусмотреть возвращение значения объекта Application

в исходное состояние. Делаем это с помощью процедуры MyDllProc:

procedure MyDLLProc(Reason: Integer);

if Reason = DLL_PROCESS_DETACH then

if Assigned(DllApp) then

Использование динамически подключаемых библиотек не так сложно, как это может показаться на первый взгляд.

DLL предоставляют широчайшие возможности для оптимизации работы приложений,

а также работы самих программистов. Используйте DLL и, возможно, ваша жизнь станет легче!

Использование динамически подключаемых библиотек не так сложно, как это может показаться на первый взгляд.

DLL предоставляют широчайшие возможности для оптимизации работы приложений,

а также работы самих программистов. Используйте DLL и, возможно, ваша жизнь станет легче!

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

Читайте также: