Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.04.11;
Скачать: CL | DM;

Вниз

Как вывести строку из DLL   Найти похожие ветки 

 
Marina   (2004-03-24 17:35) [0]

Ребята, подскажите, мне нужно сформировать строку в DLL. Когда я указываю:  

Result := PChar("Hello, world!");

то строка из DLL выводится нормально. Если формирую строку

s := "Hello, ";
s := s + "world!";
Result := PChar(s);

то выскакивает ошибка. В чем проблема? Целый день ломаю голову.


 
panov ©   (2004-03-24 17:38) [1]

Как обычно, ошибка в 17-й строке.


 
Юрий Зотов ©   (2004-03-24 17:53) [2]

Марина, прочтите здоровенный комментарий в начале DLL. Он-то Вам и нужен.


 
Romkin ©   (2004-03-24 18:08) [3]

Даже не столько он. Просто понимание, что при преобразовании типа программист сам отвечает за это :)

function blablabla: PChar;
var
 S: string;
begin
 //формируем в s строку
 Result := PChar(S);
end;

Что получается? Память, выделенная для строки S, отслеживается компилятором, и освобождается при выходе переменной из области видимости (на end, она локальная). PChar - это указатель, и при преобразовании типа никакого размножения строк не происходит, он просто указывает на первый символ строки S. Вот и получается, что результат функции использовать нельзя, он указывает на освобожденную уже память.
Приводит это к очень неприятным последствиям, AV возникает не всегда, и не всегда при использовании результата. Блок памяти не сразу отдается системе, а просто помечается как свободный.

А вот Result := StrAlloc(length(s)+1); StrCopy(Result, PChar(S)) имеет полное право на существование, вот только память надо будет освободить (StrDispose) после использования результата функции :))


 
Soft ©   (2004-03-24 20:21) [4]

>>Marina   (24.03.04 17:35)  

Если вы передаете строку как result то могу порекомендовать два пути (мне их же недавно подсказали, при чем самый простой я не знал:).

1) Выделяет область памяти под переменную в программе, которая вызывает DLL и передаете указатель на эту область памяти в DLL. Далее функция уже загоняет данные в эту область памяти и все довольны. Так работаю все WinAPI функции с передачей строк и массивов. Но не всегда такое возможно по разным причинам, иногда непрофессионализм сотрудника.

2) Определить строку как глобальную переменную в DLL:
var HexStrOfBinFile:string;
Function BinFileToHexStr(BinFileName:PChar):Pchar;stdcall;
Function HexStrToBinFile(HexStr:PChar;BinFileName:PChar):longint;stdcall;


Причина этого, String, определенный как локальная переменная, после отработки процедуры в dll очищается(счетчик ссылок на него уменьшается до 0 и Delphi автоматически освобождает память), что приводит к тому, что вы возвращаете указатель на Nil. Определив строку как глобальную переменную, очистка значения произойдет уже только при следующем вызове процедуры, которая и использует эту строку. Так что данные метод не подходит для многопоточных приложений(где функция может быть вызвана одновременно несколькими потоками).

ЗЫ
Может в чате как-то пообщаемся?


 
Marina   (2004-03-24 21:01) [5]


> Юрий Зотов ©  
> Марина, прочтите здоровенный комментарий в начале DLL. Он-то
> Вам и нужен.


Подскажите, пожалуйста, где находится начало DLL? У меня под рукой только "Руководство разработчика" Стива Тейксейра. Там по строкам из DLL ничего нет.


> Romkin
> А вот Result := StrAlloc(length(s)+1); StrCopy(Result, PChar(S))
> имеет полное право на существование, вот только память надо
> будет освободить (StrDispose) после использования результата
> функции :))


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

Функция формирования строки в DLL:


library Test;

uses
 Windows,
 SysUtils,
 Classes;

function TestStr(): PChar; stdcall;
var
 s: string;
begin
 s := "Hello, ";
 s := s + "world!";
 Result := StrAlloc(length(s)+1);
 StrDispose(Result);
end;

exports
 TestStr;
begin

end.


Вызов функции из программы:


implementation

{$R *.DFM}

function TestStr(): PChar; stdcall external "TEST.DLL";

...

procedure TForm1.Button1Click(Sender: TObject);
var
 s: string;
begin
 s := TestStr();
 ShowMessage(s);
end;


Может, я что-то делаю не так?

P.S. Извините, из-за Dialup только сейчас смогла выйти в Интернет.


 
Fredericco ©   (2004-03-24 21:06) [6]

2 Marina   (24.03.04 21:01) [5]

> В программе выводится только пустая строка.



> вот только память надо будет освободить (StrDispose) после
> использования результата функции :))

Здесь иеется ввиду, освобождать память в вызывающей программе.


 
Soft ©   (2004-03-24 22:20) [7]

>>Marina   (24.03.04 21:01) [5]
перепишите так:

library Test;

uses
Windows,
SysUtils,
Classes;

var mystring:string;

function TestStr(): PChar; stdcall;
begin
mystring := "Hello, ";
mystring := mystring + "world!";
Result := Pchar(mystring);
end;

exports
TestStr;
begin

end.


 
Petr V. Abramov ©   (2004-03-25 00:32) [8]

> Marina   (24.03.04 21:01) [5]
 Я не Зотов и не Юрий :), но Project -> View Source Вам поможет.


 
Гаврила   (2004-03-25 00:37) [9]

Если лень возиться с выделением \ освобождением памяти, а также думать о том, чей именно менеджер памяти занимается выделением, возвращайте результатом WideString
никакого подсчета ссылок компилятором в этом случае не ведется. при присвоении производится полное копирование содержимого


 
Юрий Зотов ©   (2004-03-25 06:10) [10]

> Marina   (24.03.04 21:01) [5]

> Подскажите, пожалуйста, где находится начало DLL?

Хорошо, подскажу - но только Вам и по большому секрету. Конечно, догадаться очень сложно, но имелось в виду начало исходного кода DLL. Находится оно, как это ни странно, именно в начале исходного кода DLL. В Вашем случае - после строки library Test.

Когда Вы создали DLL, Delphi вставила в это самое пресловутое начало DLL здоровенный комментарий. Она сделала это для того, данный комментарий был ПРОЧТЕН, а не выброшен сразу же. И если бы Вы его прочли, то не имели бы сейчас совершенно никаких проблем. Причем дописав к программе всего 2 слова и абсолютно не заморачиваясь никакими PChar и проблемами выделения-освобождения памяти.

В общем, очень советую нажать в Delphi File-New-DLL и все же прочесть этот комментарий. Не пожалеете.

> У меня под рукой только "Руководство разработчика" Стива
> Тейксейра. Там по строкам из DLL ничего нет.

Ох, лукавите, Мариночка, ох, лукавите. Вот как раз там-то и есть, как раз там я и сам читал когда-то. И про управляемое время жизни там есть, и про область видимости, и про счетчик ссылок, и про сборку мусора, и про передачу в/из DLL - в общем, про все что народ Вам тут написал.

Правильно написал народ, конечно. Но если Вам нужно именно "вывести строку из DLL", как Вы написали в вопросе - то прочтите все же комментарий.


 
Marina   (2004-03-25 08:54) [11]


> Soft ©   (24.03.04 22:20) [7]


Получилось! Большое вам спасибо!!!


 
Marina   (2004-03-25 09:23) [12]


> Юрий Зотов ©  
> Хорошо, подскажу - но только Вам и по большому секрету.
> Конечно, догадаться очень сложно, но имелось в виду начало
> исходного кода DLL. Находится оно, как это ни странно, именно
> в начале исходного кода DLL. В Вашем случае - после строки
> library Test.
>
> Когда Вы создали DLL, Delphi вставила в это самое пресловутое
> начало DLL здоровенный комментарий. Она сделала это для
> того, данный комментарий был ПРОЧТЕН, а не выброшен сразу
> же. И если бы Вы его прочли, то не имели бы сейчас совершенно
> никаких проблем. Причем дописав к программе всего 2 слова
> и абсолютно не заморачиваясь никакими PChar и проблемами
> выделения-освобождения памяти


И вам, Юрий, спасибо. К сожалению, с моим общешкольным немецким много не прочитаешь. У Тейксейры написано, что первым элементом после uses должен быть ShareMem, который является модулем интерфейса для диспетчера памяти Borlandmn.dll. Дальше он пишет, чтобы обойтись без использования Borlandmn.dll можно передавать строки с помощью PChar и ShortString. И предупреждает, что ShareMem можно применять только к библиотекам Delphi/BCB DLL, нельзя передавать строки приложениям написанным не на Delphi.

Вообщем, проблему я решила. Спасибо всем! Хорошо, когда есть к кому обратиться!



Страницы: 1 вся ветка

Текущий архив: 2004.04.11;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.034 c
3-1079356027
Floppy
2004-03-15 16:07
2004.04.11
Версии MDAC?


11-1060108839
Юджин
2003-08-05 22:40
2004.04.11
Народ нужна помощь, проблема с установкой и работой компонентов


4-1079892982
Yuri Btr
2004-03-21 21:16
2004.04.11
Оконная функция нового контрола


1-1079958830
RodAM
2004-03-22 15:33
2004.04.11
Переход D5 - D7


1-1080145525
Larry Laffer
2004-03-24 19:25
2004.04.11
Main Menu