Форум: "Основная";
Текущий архив: 2003.07.31;
Скачать: [xml.tar.bz2];
ВнизДопустимо ли такое обращение со строками в DLL? Найти похожие ветки
← →
Aleksandr (2003-07-15 15:52) [0]В dll у меня есть объект-список, имеющий функцию, возвращающую свойство всех своих элементов в виде строки (string) с разделителями #13#10. В той же библиотеке есть функция, доступная для пользователей, возвращающая PChar:
function GetNamesRus : PChar; stdcall;
var
s : string;
begin
Result:=nil;
if Assigned(NamesList) then begin
s:=NamesList.GetNamesRus;
if s<>"" then
Result:=StrNew(PChar(S))
end
end;
Вроде мне казалось, что внутри DLL должно быть до фени, пользуешься string или нет, лишь бы на выход были PChar. Однако же PChar приходит какой-то кривой (мусор всякий, хотя наблюдается нечто от нужного), и при попытке ему StrDispose ругается на invalid pointer operation. Объясните мне, что тут к чему?
← →
Skier (2003-07-15 15:54) [1]function title(n: Integer): PChar;
var
s: string;
begin
s := Format("title - %d", [n]);
Result := PChar(s); // DON"T DO THIS
end;
This example returns a pointer to string data that is freed when the title function returns.
← →
Aleksandr (2003-07-15 15:58) [2]2 Skier:
Да? А в моем понимании между
Result:=StrNew(PChar(S))
и
Result:=PChar(S)
есть глобальная разница
← →
Skier (2003-07-15 15:58) [3]Shit. Не туда ! StrNew не заметил :)
А как объявлена GetNamesRus в приложении ?
← →
Юрий Федоров (2003-07-15 15:58) [4]В данном случае не наблюдается "is freed when the title function returns."
Тут дело в другом: Если память выделена в DLL, то она и освобождена должна быть в DLL.
Иначе uses ShareMem и далее по тексту комментария.
А то, что там "мусор всякий" - это странно, тут дело не в PChar или String, а в чем-то другом, например в пресловутых соглашениях о вызовах
← →
Aleksandr (2003-07-15 15:59) [5]Понял. В приложении объявлено как:
function GetNamesRus : PChar; stdcall; external "disten.dll";
← →
Aleksandr (2003-07-15 16:01) [6]2 Юрий Федоров :
Тяжко. Не могли бы Вы привести пример, когда из dll берется PChar и в DLL он потом освобождается? Я просто этого не представляю, в смысле организации.
← →
Юрий Федоров (2003-07-15 16:04) [7]еще одну функцию в DLL - туда параметром PChar, там StrDispose
← →
Skier (2003-07-15 16:04) [8]>Aleksandr © (15.07.03 16:01)
-function GetNamesRus(Buffer : PChar; BufferSize : Integer) : Integer; stdcall;
-память под Buffer выделять и освобождать в host-приложении
-Не спасёт ?
← →
Aleksandr (2003-07-15 16:06) [9]%/ Надо попробовать...
← →
Юрий Федоров (2003-07-15 16:07) [10]>>>Skier © (15.07.03 16:04)
Вообще с моей точки зрения этот вариант наиболее предпочтительный, я всегда так и делаю (почему-то не люблю я этот самый ShareMem), тут только один недостаток - нужно заранее знать BufferSize или выделять по максимуму
← →
Skier (2003-07-15 16:08) [11]>Юрий Федоров © (15.07.03 16:04)
Не очень удачный подход, IMHO.
← →
Skier (2003-07-15 16:10) [12]>Юрий Федоров © (15.07.03 16:07)
> нужно заранее знать BufferSize или выделять по максимуму
?
> почему-то не люблю я этот самый ShareMem
Дело даже не в ShareMem. Дело в том что тип String понимают только Delphi и Builder и вот здесь может крыться угроза. :)
← →
Юрий Федоров (2003-07-15 16:11) [13]>>Skier © (15.07.03 16:08)
Вопрос философский...
Тем не менее многие функции API организованы именно так
← →
clickmaker (2003-07-15 16:11) [14]procedure GetNamesRus(var Buffer : PChar);
begin
if Assigned(NamesList) then begin
s:=NamesList.GetNamesRus;
Buffer := PChar(LocalAlloc(Length(s)+1));
StrPCopy(Buffer, s);
end;
end;
В host"e LocalFree
← →
Юрий Федоров (2003-07-15 16:12) [15]>>Skier © (15.07.03 16:10)
>>понимают только Delphi и Builder
На практике этого чаще всего достаточно :-)
← →
Skier (2003-07-15 16:13) [16]>Юрий Федоров © (15.07.03 16:11)
Дык,...поэтому я и написал "IMHO" :)
← →
Aleksandr (2003-07-15 16:14) [17]Мда, я вот над этим сейчас глубоко и задумался... То есть в функцию уже загоняется буфер с выделенным размером BufferSize, а возвращается, сколько надо? То есть программист должен выделить (кстати, сколько лучше?), получить неверный результат, освободить и выделить еще раз с возвращенным значением?
← →
Aleksandr (2003-07-15 16:16) [18]2 clickmaker :
О, Ваше сообщение не заметил сразу... Глупый вопрос: а почему процедурой, а не результатом?
← →
Юрий Федоров (2003-07-15 16:16) [19]Что думает общественность по поводу предложенного clickmaker ©
варианта LocalAlloc? Я что-то в сомнениях...
← →
clickmaker (2003-07-15 16:19) [20]Aleksandr © (15.07.03 16:16)
2 clickmaker :
О, Ваше сообщение не заметил сразу... Глупый вопрос: а почему процедурой, а не результатом?
Непринципиально. Главное, что память, захваченную LocalAlloc в DLL, можно освободить в EXE.
Юрий Федоров © (15.07.03 16:16)
Что думает общественность по поводу предложенного clickmaker ©
варианта LocalAlloc? Я что-то в сомнениях...
А зря. Это работающий пример.
← →
Skier (2003-07-15 16:19) [21]>Aleksandr
http://www.compress.ru/Temp/990/index.htm#03
← →
Толик (2003-07-15 16:21) [22]imho, хорошим тоном является правило "кто выделяет память, тот её и освобождает" (см. большинство ф-й WinAPI). Так и для понимания проще да и для отладки.
← →
Aleksandr (2003-07-15 16:32) [23]Спасибо всем... будем делать :)
← →
Aleksandr (2003-07-15 17:29) [24]О-о... не так все просто с этими локалами... Для LocalAlloc влаги какие-то надо указать, и возвращает она Хэндл памяти, а LocalFree(P) не прокатывает - дай, говорит, переменную типа кардинал. :(
Кстати, а вообще, можно ли создавать в dll классы, которые понимались бы другими программами? У меня эта строка - это переформатированные объекты с пропертями через запяточия, и разбирать ее потом на объекты обратно - тоже не подарок. Но что-то нигде я описаний не встречал такой работы, чтобы функцией получить из dll список объектов описанного в dll же типа.
← →
Юрий Федоров (2003-07-15 17:30) [25]>>Aleksandr © (15.07.03 17:29)
Может быть интерфейсы спасут отца русской демократии ?
← →
Fantasist. (2003-07-16 02:52) [26]
> Кстати, а вообще, можно ли создавать в dll классы, которые
> понимались бы другими программами?
Можно - ActiveX называется.
← →
Aleksandr (2003-07-16 17:13) [27]Скажите, а при варианте:
function GetNamesRus(Buffer : PChar; BufferSize : Integer) : Integer; stdcall;
чем память на хосте под буфер выделять, никаких ограничений нет? Например, можно ли использовать GetMem:
var
pNames : PChar;
Size : integer;
begin
Size:=GetNamesRus(nil,0); //при неназначенном буфере она просто возвращает необходимый размер
GetMem(pNames,Size);
try
if GetNamesRus(pNames,Size)=Size then ...
finally
FreeMem(pNames)
end
end
← →
Юрий Федоров (2003-07-16 17:15) [28]Можно. Не забудь про память под завершающий 0 :-)
← →
clickmaker (2003-07-16 17:35) [29]Aleksandr © (15.07.03 17:29)
О-о... не так все просто с этими локалами... Для LocalAlloc влаги какие-то надо указать
LocalAlloc(Size, LPTR), откастить к нужному указателю
← →
Aleksandr (2003-07-16 18:16) [30]Спасибо истчо раз. Постараюсь не забыть :)
← →
Fredericco (2003-07-16 19:39) [31]
implementation
var
hGlobalMemory: THandle;
.......
function ReturnString(StringIn: Pchar): Pchar ;
var
lpGlobalMemory: pointer ;
begin
lpGlobalMemory:=nil;
hGlobalMemory := Global ReAlloc(hGlobalMemory,strlen(StringIn)+1, GMEM_MOVEABLE);
if hGlobalMemory <> 0 then
begin
lpGlobalMemory := GlobalLock(hGlobalMemory);
lstrcpy(lpGlobalMemory,StringIn);
GlobalUnlock(hGlobalMemory);
end;
ReturnString := Pchar(lpGlobalMemory);
end;
.....
function GetHBusyMem:THandle;
begin
Result:=hGlobalMemory;
end;
.............
initialization
......
hGlobalMemory := GlobalAlloc(GMEM_MOVEABLE , 1);
Меня спасает при передаче строк любой длины.
Только не забудь в хост программе объявить функ. GetHBusyMem (вызывать не обязательно). Понимаю, что глупость, но без нее у меня память кушается...
← →
Fredericco (2003-07-16 19:41) [32]Совсем забыл!!!
function GetNamesRus : PChar; stdcall;
begin
.....
Result:=ReturnString(PChar(%YourString%));
end;
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2003.07.31;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.01 c