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

Вниз

Я понимаю что подобное уже не раз спрашивали, но все же...   Найти похожие ветки 

 
kull ©   (2002-10-28 18:51) [0]

Как передать строку (PChar) из Dll. Что бы вызывающее приложение могло ее кничтожить?

Я делаю так:

в dll-ке
....
function GetSubject: PChar; cdecl;
begin
Result := StrNew("subject");
end;

exports GetSubject;
....

в приложении
......

procedure TForm1.Button1Click(Sender: TObject);
var
H: HMODULE;
fn: function: PChar; cdecl;
S: PChar;
begin
H := LoadLibrary("d:\MyDLL.dll");
fn := GetProcAddress(H, "GetSubject");
S := fn;
StrDispose(S);//Вот здесь валится с сообщением "Invalid pointer operation"
end;


Помогите идиоту, что-то я под вечер совсем не соображаю.


 
LongIsland ©   (2002-10-28 19:24) [1]

ИМХО: Вы не выделили память и пытаетесь ее освбодить, если я что-то в чем-то соображаю:-)


 
kull ©   (2002-10-28 20:08) [2]

Как не выделил? А StrNew ?


 
LongIsland ©   (2002-10-28 20:18) [3]

То ли я торможу, то ли ничего не понимаю, но память выделяется для fn. S нужно прописать по адресу fn. Поправьте меня и я с радостью отправлюсь читать доки:-)


 
kull ©   (2002-10-28 20:32) [4]

Может я совсем ничего не понимаю, но если сделать следующее:

DLL:

...
procedure GetSubject(var P: Pointer); cdecl;
begin
GetMem(P, 100);
end;

exports GetSubject;



Application:
...

procedure TForm1.Button1Click(Sender: TObject);
var
H: HMODULE;
fn: procedure(var P: Pointer); cdecl;
P: Pointer;
begin
H := LoadLibrary("d:\MyDLL.dll");
fn := GetProcAddress(H, "GetSubject");
fn(P);
FreeMem(P);
end;



Возникает та же ситуация.


 
LongIsland ©   (2002-10-28 20:53) [5]

Тогда я совсем ничего не понимаю... :-(


 
panov ©   (2002-10-28 21:49) [6]

Переменную объяви глобальной в DLL...


 
kull ©   (2002-10-28 23:37) [7]


> panov © (28.10.02 21:49)
> Переменную объяви глобальной в DLL...

В каком смысле? Что-то я не понимаю...

Мне кажется что проблемма в способе выделения и освобождения памяти.
Вот если выделять с помощью VirtualAlloc, а освобождать с помощью VirtualFree, то все работает нормально.

Задача в том, чтобы DLL можно было написать на любом языке, например C++. Может еще есть способы работы с памятью в Delphi, такие чтоб стыковались с C++?


 
Юрий Зотов ©   (2002-10-28 23:57) [8]

Поступайте так же, как принято в API - выделяет и освобождает память вызывающая сторона, а вызываемая только заполняет переданный ей готовый (уже размещенный) буфер. И все будет тип-топ.


 
kull ©   (2002-10-29 01:23) [9]


> Юрий Зотов © (28.10.02 23:57)

Да так конечно лучше, но дело в том, что заранее неизвестно какой длины будет строка на выходе... А писать дополнительные функции заранее возвращающие размер этой строки в данном случае не получится. Заранее известно только имя функции и ее параметры.


 
Юрий Зотов ©   (2002-10-29 08:52) [10]

PChar - он и есть PChar, все равно в конце строки будет ноль. Так что никаких дополнительных функций не требуется - длина строки определяется автоматически.

Так же и в API. Например, никто не заставляет обязательно вызывать GetWindowTextLength перед GetWindowText. А во многих случаях функций, подобных GetWindowTextLength просто нет.


 
panov ©   (2002-10-29 09:36) [11]

>kull © (28.10.02 23:37)

Пример:

1. Модуль библиотеки:

library strutil;

uses
SysUtils;

var
tPChar: PChar;

function RetString: Pchar;stdcall;
var
i : Integer;
begin
ReAllocMem(tPChar,1024);
for i := 0 to 1022 do tPChar[i] := "$";
Result := tPChar;
end;

procedure FreeStr;stdcall;
begin
FreeMem(tPChar);
end;

exports
RetString,
FreeStr;
end.


2. Модуль для работы с библиотекой:

unit strutil;

interface
uses Windows,sysutils;

type ELibLoadError = class(Exception);
var RetString: function: Pchar;stdcall;
var FreeStr: procedure;stdcall;
var hLib: hWnd;

procedure LoadLib;
procedure UnloadLib;

implementation

procedure LoadLib;
begin
hLib := LoadLibrary(PChar("strutil.dll"));
if (hLib=0) then
begin
raise ELibLoadError.Create("


 
kull ©   (2002-10-29 11:00) [12]


> Юрий Зотов © (29.10.02 08:52)
> PChar - он и есть PChar, все равно в конце строки будет
> ноль. Так что никаких дополнительных функций не требуется
> - длина строки определяется автоматически.

Это понятно, но как вызывающая сторона определит какого размера буфер нужно выделить, когда неизвестна длина строки?


 
kull ©   (2002-10-29 11:03) [13]


>
> panov © (29.10.02 09:36)

Неплохое решение, а еще можно в вызываемую процедуру указатель на функцию которая выделяет память. Что-то типа CallBack-a... :)


 
panov ©   (2002-10-29 11:09) [14]

>kull © (29.10.02 11:03)
Угу, можно CallBack...
У меня получалось функции из DLL для методов TThread так использовать...


 
kull ©   (2002-10-29 11:32) [15]

Thanks!


 
VaS ©   (2002-10-29 12:50) [16]

panov:

for i := 0 to 1022 do tPChar[i] := "$";

проще так

FillChar(tPChar^, 1023, "$");


 
Digitman ©   (2002-10-29 13:10) [17]

Если используется единый (для вызывающего и вызываемого модулей) объект, реализующий ф-ции менеджера памяти, никаких проблем со взаимодействием модулей (по сабжу вопроса) нет и быть не должно.


 
Digitman ©   (2002-10-29 13:18) [18]

Простой и наглядный пример : механизм использования UDF в ядре IB-сервера в таких случаях требует от кода в составе UDF DLL выделения/перерераспределения блоков памяти с использованием менеджера в составе msvcrt.dll. Если UDF успешно выделила память (malloc/realloc)и возвратила ссылку на нее, то вызыв.код в составе хост-процесса IB-сервера успешно освободит ее (free), имея возвращенную ссылку и соотв.указание в декларации UDF


 
kull ©   (2002-10-29 13:38) [19]


> Digitman © (29.10.02 13:18)

Вот я и работаю с памятью с помощью VirtualAlloc и VirtualFree...


 
Digitman ©   (2002-10-29 13:50) [20]

и к чему такие сложности ?
Здесь важно понять, что менеджер памяти Delphi по-умолчанию, доступ к которому осуществляется (явно или неявно) через вызовы SysAllocMem/SysReallocMem/SysFreeMem, "живет" в модуле system.pas. Если ты не контролируешь в каждый момент, сколько экз-ров менеджера существует в твоем процессе, то и получаешь соответствующую проблему. Модули в составе DLL обращаются за выделением/перераспределением памяти к своему экземпляру, а хост-процесс - к своему, когда от него требуют освободить блок памяти по ссылке. Но ссылка, созданная одним экземпляром, ничего не значит для другого ! Разные экз-ры одного и того же менеджера ничего не знают друг о друге !


 
Le Taon   (2002-10-29 13:56) [21]

2kull ©
>Вот я и работаю с памятью с помощью VirtualAlloc и VirtualFree...

VirtualAlloc предназначена для выделения памяти большими кусками, наименьший размер выделяемой памяти - страница.
(При этом ещё резервируется 64К адресного пространства).

Не слишком ли много на одну строку???


 
Юрий Федоров ©   (2002-10-29 13:59) [22]

ИМХО, если действительно необходимо выделять память в одном месте,а освобождать в другом, решения два:
1. передача Callback
2. использование ShareMem


 
Игорь Шевченко ©   (2002-10-29 14:02) [23]

HeapAlloc, HeapFree к примеру.

ShareMem подойдет, если и приложение и DLL написано на Delphi или (не проверялось) на Delphi и C++ Builder.


 
Le Taon   (2002-10-29 14:05) [24]

Можно просто передать менеджер памяти из ЕХЕ в ДЛЛ.
(через GetMemoryManager/SetMemoryManager)
Менеджер памяти - не объект, а структура, поэтому никаких
побочных эффектов возникнуть не должно.

(А ShareMem я как-то не доверяю)


 
kull ©   (2002-10-29 14:05) [25]


> Юрий Федоров © (29.10.02 13:59)

Да мне кажется CallBack все же то что надо.


 
Digitman ©   (2002-10-29 14:09) [26]


> Вот я и работаю с памятью с помощью VirtualAlloc и VirtualFree...


Если уж на то пошло, то работать нужно не с сист.менеджером вирт.памяти непосредственно, а с менеджером кучи (см. HeapAlloc, HeapRealloc, HeapFree). Это - наипростейший базовый менджер памяти системы, специально предназначенный для манипуляций с программной памятью на уровне прикладного кода, не озадаченного всякого рода спецификой страничного режима. Для всех прикладных задач достаточно того факта, что с сответствующим процессом при его инициализации система всегда ассоциирует индивидуальный хип, хэндл которого в любой момент времени можно получить вызовом GetProcessHeap. В системный хип-менеджер же инкапсулированы ф-ции распределения ВАП процессов (те самые, но неявно вызываемые VirtualAlloc/Realloc/Free)


 
Digitman ©   (2002-10-29 14:16) [27]

>Le Taon
>>Менеджер памяти - не объект, а структура

Именно объект, а не просто структура. Ибо со структурами, создаваемыми и поддерживаемыми конкретным менеджером, всегда ассоциирован код, выполняющий преобразования подконтрольных ему структур. Иными словами - единство данных и кода (осуществляющего некие действия над этими данными) есть суть представления менеджера именно как объекта.


 
reonid ©   (2002-10-29 14:23) [28]

2Digitman ©
Я имел в виду не внутреннюю реализацию менеджера памяти,
а то, что доступ к нему производится через три глобальные функции, помещёных в структуру. Поэтому не должно быть проблем
с РТТИ и всего прочих сопутствующих явлений, связанных с
передачей объектов в ДЛЛ.


 
Digitman ©   (2002-10-29 14:30) [29]

>reonid

А где и что именно ты "имел ввиду" ? Свое возражение я, кажется, адресовал <Le Taon (29.10.02 14:05)>


> через три глобальные функции, помещёных в структуру


Ну и что ? Хост-процесс вполне может иметь свою структуру, а DLL - свою.


 
AlexKniga ©   (2002-10-29 15:46) [30]

2 Digitman
reonid = Le Taon = 195.9.0.43


 
Digitman ©   (2002-10-29 15:56) [31]

>AlexKniga

Не хватало мне еще сыщиком работать)



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

Текущий архив: 2002.11.07;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.02 c
14-21793
MaximatorVeter
2002-10-10 23:02
2002.11.07
Когнетивная психология!


7-21841
Ученик
2002-09-04 11:35
2002.11.07
Глобальные hook-и


3-21422
Radiy
2002-10-17 17:40
2002.11.07
Запуск программы с базой из автозагрузки


1-21622
Юрий Федоров
2002-10-26 13:04
2002.11.07
Проблемы с непонятно чем :)


3-21448
Kurt
2002-10-21 11:55
2002.11.07
Подскажите, как в QuickReport-е организовать печать двух групп, о