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

Вниз

Как возвратить строку из dll без ShareMem?   Найти похожие ветки 

 
AMW   (2007-03-04 21:34) [0]

Мне нужно возвратить строку из процедуры/функции dll, как это сделать не подключая ShareMem?
Заранее спасибо!


 
Palladin ©   (2007-03-04 21:53) [1]

использовать PChar


 
Loginov Dmitry ©   (2007-03-04 23:27) [2]

Очень просто. Резервируешь заранее место под строку необходимого размера, затем вызваешь функцию из DLL и передаешь в нее адрес строки в виде PChar.


 
AMW   (2007-03-05 00:17) [3]

Написал так:
// DLL

library Project2;

uses
 SysUtils, Windows;

procedure TestProc(var buf: PChar); stdcall
var
 s: string;
begin
 s := "Test";
 Move(s[1],buf^,Length(s));
end;

exports
 TestProc Name "TestProc";
end.

// В программе:
procedure TestProc(var buf: PChar); stdcall; external "Project2.dll";

procedure TForm1.Button2Click(Sender: TObject);
var
 buf: PChar;
begin
 GetMem(buf,10);
 TestProc(buf);
 Edit1.Text := buf;
 FreeMem(buf);
end;

В Edit записывается строка "Test&#240;<". Что это за символы "&#240;<"?


 
TRUNK ©   (2007-03-05 00:41) [4]

procedure TestProc(buf: PChar); stdcall
var
s: string;
begin
s := "Test";
Move(s[1],buf,Length(s));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
buf: array[0..9] of Char;
begin
FillChar(buf,SizeOf(buf),0);
TestProc(buf);
Edit1.Text := buf;
end;


 
TRUNK ©   (2007-03-05 00:43) [5]

> TRUNK ©  [4]
Ошибочка вышла :(

TestProc(@buf);


 
TRUNK ©   (2007-03-05 00:49) [6]

> TRUNK ©  [4]
Ещё одна ошибка :((

Move(s[1],buf^,Length(s));
или
MoveMemory(@s[1],buf,Length(s));


 
Loginov Dmitry ©   (2007-03-05 07:54) [7]

procedure TestProc(buf: PChar); stdcall
var
  s: string;
begin
  s := "Test";
  MoveMemory(Pointer(s), buf, Length(s));
  buf[Length(s)] := #0;
end;


 
begin...end ©   (2007-03-05 08:52) [8]

procedure TestProc(var buf: PChar); stdcall;
var
 s: string;
begin
 s := "Test";
 Move(s[1], buf^, Length(s) + 1)
end


 
SlymRO ©   (2007-03-05 09:54) [9]

аля WinApi
function TestProc(buf:PChar;bufSize:integer):integer; stdcall;
var s: string;
begin
 s := "Test";
 result:=Length(s)+1;
 if bufSize=0 then exit;
 if result>bufSize then
   result:=bufSize;
 StrLCopy(buf,PChar(s),result-1);
end;


 
Аноним   (2007-03-05 10:36) [10]

Самый простой способ (если не хватает опыта разрулиться с указателями и выделениями памяти) - вместо String использовать WideString


 
SlymRO ©   (2007-03-05 11:13) [11]

Аноним   (05.03.07 10:36) [10]
Самый простой способ: это стандартизация соглашений о вызове процедур и о порядке освобождения ресурсов.
а то что WideString values are not reference-counted еще не выход


 
Leonid Troyanovsky ©   (2007-03-05 11:22) [12]


> SlymRO ©   (05.03.07 11:13) [11]

> а то что WideString values are not reference-counted еще  не выход

Там дело в том, что оные строки распределяются не
дельфийским менеджером, а, скажем так, через COM.

--
Regards, LVT.


 
SlymRO ©   (2007-03-05 11:22) [13]

пример панацеи widestring:
program Project2;

{$APPTYPE CONSOLE}

uses SysUtils;

const TestStr="hello world";

function TestProc:PWidestring;
var temp:widestring;
begin
 temp:=TestStr;
 result:=@temp;
end;

var temp:widestring;
begin
 temp:=TestProc()^;
 if temp<>teststr then
   writeln("Not EQ")
 else
   writeln("EQ!");
end.


 
Leonid Troyanovsky ©   (2007-03-05 11:28) [14]


> SlymRO ©   (05.03.07 11:22) [13]

> пример панацеи widestring:

Чего-то мутно.
Да и не должны мы в subject константы разбирать.

--
Regards, LVT.


 
SlymRO ©   (2007-03-05 11:43) [15]

Leonid Troyanovsky ©   (05.03.07 11:28) [14]
Чего-то мутно

А чего мутного? По идее должнобыть EQ!, но нет...
Leonid Troyanovsky ©   (05.03.07 11:28) [14]
константы разбирать

Тоже без констант:
program Project2;

{$APPTYPE CONSOLE}

uses SysUtils;

const TestStr1="hello ";
const TestStr2="world";

function TestProc:PWidestring;
var temp:widestring;
begin
temp:=TestStr1+TestStr2;
result:=@temp;
end;

var temp1,temp2:widestring;
begin
temp1:=TestProc()^;
temp2:=TestStr1+TestStr2;
if temp1<>temp2 then
  writeln("Not EQ")
else
  writeln("EQ!");
end.


 
Alexandr Bydantcev ©   (2007-03-05 11:45) [16]

Function PrgName: Integer; stdcall;
Begin
 S := "Контроль заявок";
 Result := Integer(@S);
end;

Exports PrgName name "PrgName";


 
SlymRO ©   (2007-03-05 11:50) [17]

Alexandr Bydantcev ©   (05.03.07 11:45) [16]
Integer(@S);

И что? Работает? Сам то проверял?


 
Alexandr Bydantcev ©   (2007-03-05 12:02) [18]

2 SlymRo

Можешь не верить, но работает

Извиняюсь, не указал процесс получения

var
 Lib : THandle;

Procedure GetInfo(var Value: String; ProcName: String);

var
 Proc : TFarProc;

begin
 Int := GetProcAddress(Lib, PChar(ProcName));
 Value := Copy(String(Pointer(Int)^), 0, Length(String(Pointer(Int)^)));
end


 
Аноним   (2007-03-05 12:04) [19]


> SlymRO ©   (05.03.07 11:13) [11]
> Аноним   (05.03.07 10:36) [10]
> Самый простой способ: это стандартизация соглашений о вызове
> процедур и о порядке освобождения ресурсов.
> а то что WideString values are not reference-counted еще
> не выход


По твоему это более простой способ?
Отнюдь.
Может быть, он более грамотный, более правильный, но не более простой


 
SlymRO ©   (2007-03-06 07:22) [20]

Alexandr Bydantcev ©   (05.03.07 12:02) [18]
Value := Copy(String(Pointer(Int)^), 0, Length(String(Pointer(Int)^)));

!Ё маё... Ацес виолатионы часто ловишь? и еще: дважды вызвал процедуру (хватило бы одного раза)
Alexandr Bydantcev ©   (05.03.07 11:45) [16]
Function PrgName: Integer; stdcall;
Begin
S := "Контроль заявок";
Result := Integer(@S);
end;

После выхода из функции string отсутствует, остается указатель на память, которая может содержать все что угодно... в твоем случае повезло
В однопоточном проекте в 100 строчек это может работать... В большом многопоточном приложении будут возникать ацесвиолатины случайным образом, что чревато сложностями в отладке...
И поэтому именно проще все стандартизировать и не изкать в 2 тыс. строках один нерегулярный баг


 
Loginov Dmitry ©   (2007-03-06 07:55) [21]

> Int := GetProcAddress(Lib, PChar(ProcName));
> Value := Copy(String(Pointer(Int)^), 0, Length(String(Pointer(Int)^)));


Гы! Мощная травка!


 
begin...end ©   (2007-03-06 14:41) [22]

> SlymRO ©   (06.03.07 07:22) [20]

> После выхода из функции string отсутствует

В данном случае после выхода из функции string присутствует. Потому как строковая константа.


 
SlymRO ©   (2007-03-07 10:04) [23]

begin...end ©   (06.03.07 14:41) [22]
Потому как строковая константа

остается указатель на память - строковой константы и то смотря как сделать...
Это работает:
var s:string;
Function PrgName: Integer; stdcall;
Begin
 S := "Контроль заявок";
 Result := Integer(@S);
end;

А это не работает:
Function PrgName: Integer; stdcall;
var s:string;
Begin
 S := "Контроль заявок";
 Result := Integer(@S);
end;


 
Loginov Dmitry ©   (2007-03-07 11:04) [24]

> А это не работает:


Ты вообще бред какой-то написал. Нужно не так

Result := Integer(@S);

а так

Result := Integer(S);

Тады будет работать.


 
SlymRO ©   (2007-03-07 12:56) [25]

Loginov Dmitry ©   (07.03.07 11:04) [24]
Ты вообще бред какой-то написал

Ээ... Зачэм обижаещь? Это нэ я писаль а Alexandr Bydantcev ©   (05.03.07 11:45) [16]
Я просто S задекларировалъ
Loginov Dmitry ©   (07.03.07 11:04) [24]
Result := Integer(S);

Э таварищь нэ чэстно патсказыват... Одын фиг в LStrClr попадает...


 
SlymRO ©   (2007-03-07 12:59) [26]

Loginov Dmitry ©   (07.03.07 11:04) [24]
Тады будет работать.

На те поддых:
Function PrgName: Integer; stdcall;
var s:string;
Begin
S := "Контроль заявок"#0"Fuck";
Result := Integer(S);
end;


 
begin...end ©   (2007-03-07 16:54) [27]

> SlymRO ©   (07.03.07 10:04) [23]
> остается указатель на память - строковой константы

Остаётся. Причём остаётся действительный указатель.

> SlymRO ©   (07.03.07 12:56) [25]
> Одын фиг в LStrClr попадает...

Попадает. Но память, естественно, не освобождается.

> SlymRO ©   (07.03.07 12:59) [26]

И чё?


 
Loginov Dmitry ©   (2007-03-07 18:40) [28]

> Ээ... Зачэм обижаещь?


Кого это я обижал?


 
Amoeba ©   (2007-03-07 18:48) [29]

Как альтернатива ShareMem - FastMM (http://sourceforge.net/projects/fastmm). Тоже самое, но без DLL.


 
GrayFace ©   (2007-03-07 20:40) [30]

begin...end ©   (07.03.07 16:54) [27]
> SlymRO ©   (07.03.07 10:04) [23]
> остается указатель на память - строковой константы

Остаётся. Причём остаётся действительный указатель.


Во втором случае возвращается указатель на нечто в стеке, SlymRO прав. А первый - относительная редкость.


 
begin...end ©   (2007-03-07 20:52) [31]

> GrayFace ©   (07.03.07 20:40) [30]
> SlymRO прав.

В чём? В том, что "После выхода из функции string отсутствует"? Нет, здесь он не прав. Тело строки как существовало до выхода из функции, так и существует. А указатель... да, разумеется, возвращается не указатель на тело (вопреки тому, что утверждается в [23]: "остается указатель на память - строковой константы"), а адрес адреса. С этим я и не спорил, вообще-то.


 
SlymRO ©   (2007-03-09 12:32) [32]

begin...end ©   (07.03.07 20:52) [31]
Нет, здесь он не прав

Для меня string прежде всего структура с валидными полями refcount,size а уж потом "Тело строки"... а память, она и в африке память пока никто не затрет она действительна...
а операция String(PChar(PrgName)) не приведение типа! а восстановление типа, с пересчетом поля size по символу #0


 
begin...end ©   (2007-03-09 13:19) [33]

> SlymRO ©   (09.03.07 12:32) [32]

> Для меня string прежде всего структура с валидными полями
> refcount,size

Пусть так. У строковой константы тоже есть поля счётчика ссылок (правда, этот счётчик для неё всегда равен -1) и размера. Но это ничего не меняет. После выхода из подпрограммы ни тело строковой константы, ни её служебные поля не изменятся.


 
SlymRO ©   (2007-03-12 10:34) [34]

begin...end ©   (09.03.07 13:19) [33]
Из правила всегда есть исключение. В данном контексте строковая константа... Но при динамической загрузке/выгрузке dll могут возникнуть грабли с указателем на константу в адресах выгруженной dll :):
var r:integer;
begin
Lib:=LoadLibrary("lib.dll");
Int := GetProcAddress(Lib, PChar(ProcName));
r:=Int;
FreeLibrary(Lib);//Имею право выгрузить...
Value := Copy(String(Pointer(r)^), 0,Length(String(Pointer(r)^)));
end;


ни её служебные поля не изменятся
тогда и нужно ими пользоваться во избежания [26]:
var
 r:integer;
 s:string;
begin
 r:=PrgName;
 SetString(s,PChar(r),PInteger(r-4)^);
 Caption:=s;
end;



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

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

Наверх





Память: 0.53 MB
Время: 0.042 c
11-1150844501
parovoZZ
2006-06-21 03:01
2007.04.01
Бросил на GRushPanel KolLabel...


3-1168691845
SerJaNT
2007-01-13 15:37
2007.04.01
Can not open a result set


15-1173259611
Kok
2007-03-07 12:26
2007.04.01
8 марта близко, близко....


2-1173854080
JohnKorsh
2007-03-14 09:34
2007.04.01
Ищу RxLib для D7.


1-1170236837
SH@RK
2007-01-31 12:47
2007.04.01
Динамические массивы vs Статические массивы





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