Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.04.11;
Скачать: [xml.tar.bz2];

Вниз

Как вывести строку из 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.047 c
14-1082402837
Gomosapin
2004-04-19 23:27
2004.04.11
Помогите решить простую задачу. Pascal


3-1081428440
Mishenka
2004-04-08 16:47
2004.04.11
Поле типа Memo?


1-1080113885
Maza_Faka
2004-03-24 10:38
2004.04.11
Dlephi8


3-1081925156
Olegka
2004-04-14 10:45
2004.04.11
Хочу работать с DB-aware компонентами


1-1082695408
Апач
2004-04-23 08:43
2004.04.11
TreeView





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский