0 / 0 / 0
Регистрация: 11.08.2010
Сообщений: 2
1

Передача строк в dll

11.08.2010, 03:08. Показов 15191. Ответов 8
Метки нет (Все метки)

Здравствуйте уважаемые знатоки, хочу задать вопрос по dll в delphi. Вернее хочу увидеть пример кода, задача сдледующая, в библиотеку передаётся строка, обрабатывается функцией и возращается результат, тоже строка, функция выполняется динамически. Казалось бы что проще, но возникает проблема доступа к памяти, поиск по интернету вернул несколько вариантов решения, во первых почитать внимательно комментарий новосозданой dll, да sharemem использовать пробывал, как советуют, строка передаётся, но при выходе из программы всё равно выскакивает ошибка, при использовании pchar, возращаются неверные данные (не имею опыта использования pchar), использовать widestring (брал по примеру на каком то форуме), даёт ошибку памяти сразу при вызове функции, вообщем ответа по различным запросам в поиске я не нашёл, кто может показать рабочий пример кода по моей задаче?
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
11.08.2010, 03:08
Ответы с готовыми решениями:

Передача строк в dll и вывод на форму
Здравствуйте! Подскажите, пожалуйста, как правильно организовать передачу строк в dll!! вот есть у...

Передача строк между Dll между Exe
Подскажите алгоритм предачи строк между динамической библиотекой и исполняемым файлом. Мне...

Передача данных в dll
Есть .dll: library dll; uses Windows, WinInet, SysUtils, TlHelp32, UrlMon, Dialogs; var ...

Передача массива в dll
Не могли бы обьяснить как реализовать сабж?(возможно ссылку на теорию) Пробовал и в тупую...

8
13084 / 5869 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
11.08.2010, 16:34 2
Лучший ответ Сообщение было отмечено как решение

Решение

Здесь проблема вот в чём. Вызывающая программа и DLL используют одно и тоже адресное пространство, поэтому в обмене данными можно применять указатели. Но вызывающую программу и DLL обслуживают два различных экземпляра менеджера памяти. И, соответственно, оба менеджера используют две раздельных "кучи" - т. е. две отдельные друг от друга области динамической памяти. Поэтому, если для некого объекта память была выделена, например, в DLL, потом указатель на него был передан в вызывающую программу, а затем, если вызывающая программа попытается осободить память из под этого объекта - то менеджер памяти вызывающей программы выполнит действия по особождению в неподконтрольном ему участке памяти - т. е. в области динамической памяти, которая обслуживается не им, а другим менеджером - связанным с DLL. Такие действия могут даже разрушить целостноть кучи, принадлежащей DLL.
---
Решать эту проблему можно поразному:
1. Использовать модуль ShareMem - этот модуль надо прописать самым первым в предложении Uses в модуле вызывающей программы и модуле DLL. Кроме этого вместе с приложением надо поставлять дополнительную DLL библиотеку: BORLNDMM.DLL. Эта библиотека, содержит альтернативный менеджер памяти Delphi.
Здесь могут быть, как раз, такие проблемы:
Цитата Сообщение от xanrias
...но при выходе из программы всё равно выскакивает ошибка...
Есть и другие альтернативные менеджеры - в инете можно поискать. Они возможно более стабильные. А может и нет.
2. Не использовать динамические типы и указатели. Это часто весьма неудобно.
---
3. Третий вариант - на мой взгляд наиболее удобный.
Идея вот в чём - те динамические объекты, которые создаёт менеджер памяти, связанный с DLL, пускай этот же менеджер памяти и уничтожает. Для этого просто в раздел экспорта поместим процедуру для удаления "собственных" объектов.
Делается, например так:
Код DLL:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
library StrServ;
 
{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }
 
uses
  SysUtils,
  Classes;
 
{$R *.res}
 
procedure ProcStr(const aPStr1 : PChar; var aPStr2 : PChar; var aSize : Longword); stdcall;
var
  Str1, Str2 : String;
begin
  if aSize = 0 then begin
    aPStr2 := nil;
    Exit;
  end;
 
  //Переносим входные данные в строку типа String.
 
  SetString(Str1, aPStr1, aSize);
  //Либо так:
  //SetLength(Str1, aSize);
  //Move(aPStr1^, Pointer(Str1)^, aSize);
 
  //Теперь использоуем Str1 в своём алгоритме.
  //...
  //...
  //...
 
  //Пускай, например:
  Str2 := AnsiUpperCase(Str1);
 
  //...
 
  //Переносим результирующие данные, которые хранятся в строке Str2
  //в буфер выходных данных, который будет возвращён в вызывающую программу.
  aSize := Length(Str2);
  aPStr2 := AllocMem(aSize);
  Move(Pointer(Str2)^, aPStr2^, aSize);
 
  //Вызывающая программа, в момент, когда данные выходного буфера ей будут уже
  //не нужны, обязана самостоятельно освободить память, выделенную для этого буфера.
  //Для освобождения этой памяти, вызывающая программа обязана применить экспортируемую
  //нашей DLL процедуру: DllFreeMem().
end;
 
//Эта процедура предназначена для освобождения из вызывающей программы той памяти,
//которая ранее была выделена в коде этой DLL.
procedure DllFreeMem(var aPStr : PChar; const aSize : Longword); stdcall;
begin
  FreeMem(aPStr, aSize);
end;
 
exports
  ProcStr, DllFreeMem;
 
begin
end.
Код вызывающей программы:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Memo2: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
//Внешняя процедура для обработки строки.
procedure ProcStr(const aPStr1 : PChar; var aPStr2 : PChar; var aSize : Longword); stdcall; external 'StrServ.dll' name 'ProcStr';
 
//Внешняя процедура для освобождения памяти из под буфера, ProcStr
procedure DllFreeMem(var aPStr1 : PChar; const aSize : Longword); stdcall; external 'StrServ.dll' name 'DllFreeMem';
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
var
  PCharRes : PChar;
  StrRes : String;
  Size : Longword;
begin
  Size := Length(Memo1.Text);
  ProcStr(PChar(Memo1.Text), PCharRes, Size);
 
  //Переносим возвращённые данные в строку типа String.
  SetString(StrRes, PCharRes, Size);
  //Либо так:
  //SetLength(StrRes, Size);
  //if Size > 0 then Move(PCharRes^, Pointer(StrRes)^, Size);
 
  //Освобождаем память, которую ранее выделил код DLL для буфера с возвращаемыми данными.
  //Для особождения памяти привлекаем менеджер памяти, связанный с этой же DLL.
  DllFreeMem(PCharRes, Size);
 
  //Теперь можно использовать строку StrRes в своём алгоритме.
  //...
  //...
  //...
 
  Memo2.Text := StrRes;
 
end;
 
end.
Здесь в ProcStr() параметр aSize имеет двойное назначение - при вызове функции через него следует передать размер входной строки, а при возвращении управления в вызывающую программу, через этот же параметр возвращается размер выходной строки.
---
Примеры приведены для случая, когда:
type String = type AnsiString;
- например, для Delphi7.
Для Delphi 2009/2010 надо скорректировать программу - там:
type String = type WideString.
Соответственно, длина строки символов и размер будут иметь различное значение. И пр.
Вложения
Тип файла: rar StrExchangeWithDll.rar (179.2 Кб, 327 просмотров)
3
1172 / 478 / 83
Регистрация: 04.03.2010
Сообщений: 1,019
11.08.2010, 16:51 3
А вот пример для слабенького уровня знаний. Dll + Программа
Вложения
Тип файла: rar Строки в Dll.rar (619.6 Кб, 811 просмотров)
2
0 / 0 / 0
Регистрация: 11.08.2010
Сообщений: 2
11.08.2010, 19:27  [ТС] 4
Огромное спасибо всем ответам, всё достаточно развёрнуто и понятно, исходники оба рабочие, единственное поменял загрузку на динамическую. Отличный форум, отличные знатоки =)
0
Enum
31.08.2012, 08:54 5
Mawrat, в сообщении от 11.08.2010 20:34 Вы описываете алгоритм программы для DLL и исполняемой программы. Пытаясь уложить в голове алгоритм, возник вопрос: процедура procedure ProcStr при вызове из исполняемой программы получает входные параметры (const aPStr1 : PChar; var aPStr2 : PChar; var aSize : Longword) и делает свою работу, но по определению ведь процедуры ничего не возвращают? У Вас же в алгоритме процедура возвращает параметры (StrRes, PCharRes, Size). Это уже должна быть как минимум функция. Почему же процедура возвращает данные? Может это и глупый вопрос, но мне он не понятен, ответьте пожалуйста, извиняюсь, я начинающий программист.
13084 / 5869 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
31.08.2012, 10:54 6
Функция возвращает значение, которое в вызывающем коде подставляется в том месте, где эта функция вызвана. Функция может быть элементом в выражении. Например:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
implementation
 
//Функция, возвращающая квадрат aX.
function F(const aX : Extebded) : Extended;
begin
  //Значение, которое присвоено встроенной переменной Result будет возвращено в вызывающий код и подставлено
  //в том месте, где выполнен вызов функции.
  Result := aX * aX;
end;
 
//Код, в котором выполняется вызов функции F().
procedure TForm1.Button1Click(Sender : TObject);
var
  S : String;
  Num : Extended;
begin
  Num := StrToFloat(Edit1.Text);
  S := FloatToStr( F(Num) );
  ShowMessage('Возведение в квадрат: ' + S);
end;
 
end.
Процедура не возвращает значение и не может участвовать в выражениях. Функции и процедуры могут иметь список параметров. Данные, переданные в подпрограмму через параметры, могут быть изменены. Изменения параметров отражаются в вызывающей программе, если эти параметры объявлены со спецификатором VAR. Таким образом, представленный выше код можно заменить на код с процедурой, в которой результат вычисления квадрата передаётся в вызывающий код через дополнительный параметр aRes:

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
implementation
 
//Процедура, вычисляющая квадрат aX. Результат вычисления возвращается через параметр aRes.
procedure F(const aX : Extebded; var aRes : Extended);
begin
  //Изменение значения aRes отразится в вызывающем коде в переменной, которая передана процедуре F в качестве
  //параметра aRes.
  aRes := aX * aX;
end;
 
//Код, в котором выполняется вызов процедуры F().
procedure TForm1.Button1Click(Sender : TObject);
var
  S : String;
  Num, Res : Extended;
begin
  Num := StrToFloat(Edit1.Text);
  F(Num, Res);
  S := FloatToStr( Res );
  ShowMessage('Возведение в квадрат: ' + S);
end;
 
end.
---
Ещё хочу вернуться к прежнему своему сообщению, где в описании способа с использованием модуля ShareMem, я написал:
Цитата Сообщение от Mawrat Посмотреть сообщение
Здесь могут быть, как раз, такие проблемы:
Цитата Сообщение от xanrias
...но при выходе из программы всё равно выскакивает ошибка...
Есть и другие альтернативные менеджеры - в инете можно поискать. Они возможно более стабильные. А может и нет.
Вот эти слова беру назад. Если всё написано правильно, то проблем с ShareMem быть не должно.
2
Enum
03.09.2012, 05:23 7
Mawrat, существует ли ограничение на количество передаваемых/принимаемых процедурой параметров? Такие тонкости к сожалению в учебниках не обсуждаются.
4148 / 1803 / 213
Регистрация: 06.10.2010
Сообщений: 4,033
03.09.2012, 08:59 8
Количество параметров ограничено размером стека (Project->Options...->Linker->Max stacksize).
1
0 / 0 / 0
Регистрация: 14.10.2015
Сообщений: 2
08.05.2016, 09:33 9
Подскажите, а можно ли отправить сообщение в dll одним приложением, а получить ответ в другом приложении?

Добавлено через 26 минут
Т.е. чтобы отправлялось сообщение из одного приложения, попадало в dll, а другое приложение забирало результат из этого dll?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.05.2016, 09:33
Помогаю со студенческими работами здесь

Передача Query из DLL в программу
Доброго времени суток ! Долго думал над вопросом,пытался его сформулировать гуглу,но так и не...

Передача с Dll в ЕХЕ файл.
проблема с dll Как месяц Delphi поставил, поэтому мало чего шарю в нем. я создал DLL с ресурсами...

Передача массива из DLL в основную программу
В DLL у меня происходят вычисления и в основную программу передается массив записей. Но, почему то...

Передача структуры данных в DLL (stdcall)
Хочу передать данные следующей структуры в DLL: Поле1: Символьный тип, длинной 15 букв (Pole_1:...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru