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

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.009 c
1-21640
Andrey.L.V.
2002-10-27 09:38
2002.11.07
---|Ветка была без названия|---


6-21716
ламо
2002-09-10 19:59
2002.11.07
сокет


1-21587
Gamar
2002-10-30 10:28
2002.11.07
Компоненты под стиль OfficeXP


6-21715
_Misha_
2002-09-10 18:18
2002.11.07
Порт связи между клиентом и сервером


1-21656
Archon
2002-10-27 17:45
2002.11.07
как интегрировать компоненту в htlm документ





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