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

Вниз

PChar результат функции из Dll   Найти похожие ветки 

 
slavannnov   (2007-09-19 14:32) [0]

Из Dll библиотеки отдаю результат функции, как ссылку на запись, в которой содержится PChar.

Функция и типы примерно так:

PMyType = ^TMyType;
TMyType = record
 Pst: LongWord;
 Str: PChar;
 Bool: Boolean;
 Int: Integer;
end;

function GetResult(Data: ...): PMyType;
var
 Back: TMyType;
begin
 ...
 Back.Str := PChar("My string num = " + IntToStr(10));
 ...
 Result := @Back;


Вызываю из приложения - получаю AV. Если убрать IntToStr и возвращать просто строку, то все ок. А в случае с IntToStr, Format - всегда AV. Что тут не так?


 
Ega23 ©   (2007-09-19 14:34) [1]

var
 ss : string;

ss := "My string num = " + IntToStr(10);
Back.Str := PChar(ss);

?


 
stanislav ©   (2007-09-19 14:35) [2]

Наверное нужно создавать указатель New(), и уничтожать Dispose().
Лучше сделай процедуру
procedure GetResult(Data: ...,Var MT:PMyType)


 
Сергей М. ©   (2007-09-19 14:37) [3]


> Что тут не так?
>


Время жизни переменной Back равно времени работы ф-ции GetResult.

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


 
slavannnov   (2007-09-19 14:41) [4]

Ну хорошо, вроде понял про время жизни. Но как тогда получается, что используя просто строку - адрес памяти соответсвует уже не существующему адресу. Просто совпадаение, память не заняли под другие нужды?

Так как лучше делать: для результата New или передавать по ссылке вход. параметром?


 
stanislav ©   (2007-09-19 14:43) [5]

лучше передавать параметр, т.к. тебе ведь ее удалить нужно.


 
stanislav ©   (2007-09-19 14:45) [6]

т.е. выделяешь и освобождаешь память в приложении, а не в dll.


 
slavannnov   (2007-09-19 14:52) [7]

Попробовал все способы исправить - не помогло. Стабильно с этими же симптомами получается AV. Что я ещё мог забыть?


 
Инс ©   (2007-09-19 14:57) [8]

Проще всего будет вместо String использовать WideString, но не правильнее всего...


 
stanislav ©   (2007-09-19 15:12) [9]

Так тебе нужно и под Back.Str память выделять


 
Сергей М. ©   (2007-09-19 15:12) [10]


> как лучше делать: для результата New или передавать по ссылке
> вход. параметром?


Да как угодно, но уж точно не так как ты пытался это делать, т.е. с пом. локальной переменной.


 
evvcom ©   (2007-09-19 15:15) [11]


> Попробовал все способы исправить - не помогло.

Ну значит не все. Способ есть и не один. Показывай, что пробуешь, а то экстрасенсы в другой ветке тусуются.


 
Сергей М. ©   (2007-09-19 15:15) [12]


> slavannnov   (19.09.07 14:41) [4]


Фантазии с выделением/освобождением памяти, используемой для возврата рез-та, ограничены только одним - менеджеры памяти в вызывающем и вызываемом кодах должны быть одни и те же.


 
slavannnov   (2007-09-19 15:52) [13]

Попробовал я выделять память и передавать так:

var
RD: PMyType;
begin
New(RD);
GetResult(.., RD);
with RD^ do
  ...

Но нужно ли под PChar внутри этой записи выделять память?
DLL:
procedure GetResult(Data: ...; ReturnData: PMyType);


Но ничего не получилось, AV.

---

В результате, работает только один вариант: как выше подсказали, заменил PChar в записе, на WideString.

Передавал в случае с WideString, так:
var
RD: TMyType;
begin
GetResult(.., @RD);
with RD do
  ...


И это работает. Но мне на самом деле одной работоспособности мало. Я хочу понять почему так получается?


 
Сергей М. ©   (2007-09-19 16:05) [14]


> нужно ли под PChar внутри этой записи выделять память?


Если она к этому моменту не выделена тем или иным образом, то конечно же нужно.


 
evvcom ©   (2007-09-19 17:13) [15]

1 пример тоже можно переписать "без указателей":

interface
procedure GetResult(Data: ...; var ReturnData: TMyType);

implementation
...
var
 RD: TMyType;
begin
 GetResult(.., RD);

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


 
DVM ©   (2007-09-19 17:20) [16]

Кстати, а нужно ли именно PCHAR. Строка имеет какую то максимальную длину. Редко ведь когда границы бывают неизвестны. Может ее заменить на array [...] of char?


 
slavannnov   (2007-09-19 17:25) [17]

Привожу код ещё раз, первый не работает. Что забыл и что не так не понимаю.
При обращении к результату Str -- AV. Почему не работает?

PMyType = ^TMyType;
TMyType = record
Pst: LongWord;
Str: PChar;
Bool: Boolean;
Int: Integer;
end;

DLL:
procedure GetResult(InData: TOtherRecord; var OutData: TMyType);
begin
...
OutData.Str := PChar("My string num = " + IntToStr(10));
...
end;

EXE:
var
 MyData: TMyData;
begin
 // пытался тут выделать память под TMyData.str (PChar) -- но дохлый номер.
 GetResult(OtherData, MyData);
 with MyData do
 begin
   ShowMessage(StrPas(Str));


Этот же код спокойно работает. Почему? Что такого получается в WideString?

PMyType = ^TMyType;
TMyType = record
Pst: LongWord;
Str: WideString;
Bool: Boolean;
Int: Integer;
end;

DLL:
procedure GetResult(InData: TOtherRecord; OutData: PMyType);
begin
...
OutData^.Str := "My string num = " + IntToStr(10);
...
end;

EXE:
var
 MyData: TMyData;
begin
 GetResult(OtherData, @MyData);
 with MyData do
 begin
   ShowMessage(Str);


Не знаю, что и предпологать, попытаюсь избавиться от PChar.


 
Сергей М. ©   (2007-09-19 17:31) [18]


> OutData.Str := PChar("My string num = " + IntToStr(10));


> При обращении к результату Str -- AV. Почему не работает?


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


 
Сергей М. ©   (2007-09-19 17:32) [19]


> ожидаемых тобой


ожидаемому тобой (времени жизни)


 
slavannnov   (2007-09-19 17:41) [20]

Хорошо, спасибо. Но второй мой пример, все ок, казалось бы, но почему работает только с WideString, использую обычный string - получаю неприятности.

?


 
Loginov Dmitry ©   (2007-09-19 21:31) [21]

> использую обычный string - получаю неприятности.


ShareMem не забыл подключить там где надо?


 
Инс ©   (2007-09-19 21:33) [22]


> Что такого получается в WideString?

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


 
slavannnov   (2007-09-19 21:39) [23]

Ну т.е. в случае если я буду использовать WideString мне не нужно беспокоиться о ShareMem?


 
Инс ©   (2007-09-19 21:45) [24]


> [23] slavannnov   (19.09.07 21:39)

Не нужно, только процессорное время на перекодировку в юникод и обратно потеряете.


 
stanislav ©   (2007-09-20 08:45) [25]

Sharemem, нужно носить с приложением т.к. это dll Борланд. Да и dll с приложениями разработанными на других языках работать не будет.
Вот незнаю по поводу widestring, будет ли работать dll допустим  c приложениями разработанными с помощью продуктом Microsoft.


 
Однокамушкин   (2007-09-20 09:24) [26]

Здесь ситуация следующая:

1. Любая строковая константа размещается во время компиляции в сегменте кода... Когда Pchar-у присваивается константа, соответствующая переменная становится указателем на соответсвующую часть сегмента кода... Понятно, что пока не выгружена длл, этот участок памяти никуда не денется, поэтому указатель останется актуальным

2. Когда вы присваиваете PChar-у указатель на вычисленную строку, эта строка размещается в динамической памяти, а указатель на неё в неявной переменной, которая финализируется после выхода из соответствующей функции, поэтому после выхода из функции PChar указывает на память, с которой неизвестно что случилось: то ли она возвращена системе (тогда av), то ли использована для других нужд (тогда будет мусор), то ли пока там ещё осталась строка... Точное поведение зависит от многих факторов, предсказать в каждом конретном случае сложно...

3. Проблемы со string-ом возникают потому, что у программы и у длл разные менеджеры памяти, и один менеджер не может освобождать память, которую выделил другой... Поэтому нужен ShareMem, который заставляет программу и длл использовать единый менеджер памяти, реализующийся borlandmm.dll... Или в новых версиях дельфей можно использовать SimpleShareMem - он позволяет программе и длл использовать единый менеджер памяти без подключения дополнительных библиотек... Кстати, совет использовать New или StrNew для передачи PChar-ов не слушайте, потому что придётся в программе вызывать Dispose или StrDispose и снова нарываться на те же грабли, когшда один менеджер памяти пытается освободить то, что выделено другим...

4. WideString является оболочкой над системным типом BSTR, который используется в OLE, и для этого типа в системе существует свой менеджер памяти, доступный через функции SysAllicString, SysFreeString и т.п. Поэтому при работе с WideString-ом дельфийский менеджер памяти не задействуется, и никаких проблем с передачей WideString-ов между программой и длл не возникает...


 
Сергей М. ©   (2007-09-20 09:39) [27]


> 1. Любая строковая константа размещается во время компиляции
> в сегменте кода


Не в сегменте, а в секции, и не кода, а инициализированных данных.
Убедись сам, изучив соответствующий *.map-файл.


 
Однокамушкин   (2007-09-20 10:05) [28]


> Сергей М. ©   (20.09.07 09:39) [27]

Не путайте типизированные константы и литералы (константы, размещённые прямо в тексте)

Сделал такую функцию:


procedure TForm1.Button1.Click(Sender: TObject);
var
 P: PChar;
begin
 P := "Test";
 ...
end;

procedure TForm1.Button2.Click(Sender: TObject);
...


CPU Window показывает следующее:

1. Код метод Button1Click начинается с адреса 0044EB57

2. В переменную P заносится указатель 0044EB9C

3. Инструкция ret для Button1Click находится по адресу 0044EB98

4. Код метода Button2Click начинается с адреса 0044EBA4

5. Между Button1Click и Button2Click вижу "ничей" кусок кода, который содержит "Test"

Ещё комментарии нужны, или и так всё понятно?

P.S. Откомпилировал по вашему совету проект с включённой опцией Map file Detailed... Не нашёл там информации о размещении строки "Test" - может, подскажете, как искать? Зато нашёл в нём строку "Detailed map of segments" - так что использование слова "сегмент" тоже вполне оправдано...


 
Сергей М. ©   (2007-09-20 10:12) [29]


> Однокамушкин   (20.09.07 10:05) [28]
>
>


Надо было сразу уточнить, что речь у тебя идет именно о литералах, ибо из [26] это не очевидно.


> использование слова "сегмент" тоже вполне оправдано


В PE-файле как рез-те сборки модуля нет сегментов, там именно секции. И я вел речь именно об этом.



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

Форум: "Начинающим";
Текущий архив: 2007.10.14;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.53 MB
Время: 0.049 c
2-1189538649
SKIPtr
2007-09-11 23:24
2007.10.14
Удаление элементов в TStrings


3-1174626285
Amateur
2007-03-23 08:04
2007.10.14
Вывод веб странички из BLOB на WebBrowser


1-1186047147
hgd
2007-08-02 13:32
2007.10.14
WebBrowser и прокси


2-1189756196
kostyas
2007-09-14 11:49
2007.10.14
Invalid floating point operation


2-1190485834
Aser
2007-09-22 22:30
2007.10.14
Как вывести хинт (сообщение) в трэй - т.н. "baloon"





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский