Форум: "Основная";
Текущий архив: 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.045 c