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

Вниз

Как возвратить строку из 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;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.049 c
2-1173541157
cawwa
2007-03-10 18:39
2007.04.01
Глобальные горячие клавиши.


1-1170616649
flaxe
2007-02-04 22:17
2007.04.01
Bitmap в ICO


15-1173086533
MsGuns
2007-03-05 12:22
2007.04.01
Украинский футбол глазами европейцев


15-1173109856
xayam
2007-03-05 18:50
2007.04.01
7z


15-1173157995
eXPell
2007-03-06 08:13
2007.04.01
Подскажите софт, пожалуйста