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

Вниз

Как передать текст в DLL?   Найти похожие ветки 

 
lmatveev   (2002-10-06 20:39) [0]

Мне нужно написать библиотеку для использования в системах, написанных на C, VB и т.п. Короче не на Delphi. Функция в библиотеке должна получать некий текст, его обрабатывать и возвращать обратно. Сразу скажу, что использовать borlmm.dll я не хочу. Так вот вопрос в том как принято (например в WinAPI) передавть/получать текст в/из Dll?
Сейчас я сделал следующим образом:
function ProcessText(const Source; SrcSize: integer; var Dest): integer; stdcall;
var
SrcText, DestText: string;
begin
SetString(SrcText, PChar(@Source), Size);
...
DestText := "some processed text";
Move(PChar(DestText)^, Dest, Length(DestText));
Result := Length(DestText);
end;

и вызываю я ее так:

function CallProcess(Src: string): string;
var
h: THandle;
f: function (const Source; SrcSize: integer; var Dest): integer; stdcall;
s: integer;
Buf: string;
begin
Result = "";
h := LoadLibrary("TextLib.dll");
if h = 0 then exit;
@f := GetProcAddress(h, "ProcessText");
if @f = nil then exit;
s := f(PChar(Src)^, Length(Src), Buf);
SetString(Result, @Buf, s);
end;


Но во-первых, я не уверен, что обязательно надо использовать untyped параметры (мне хотелось бы более жестко)
Во-вторых, я не уверен, что я все правильно написал (особенно в части получения результата).
И вообще чем-то мне этот код не нравиться :))
Прошу всех поделиться своими сообржениями по изложенной проблеме


 
Diamond Cat   (2002-10-06 22:51) [1]

не совсем понял длл твоя или нет если твоя то
проще всего использовать файл в памяти к примеру
hMapFile := CreateFileMapping (
$FFFFFFFF, // хендл файла памяти
nil, // этот параметр задает сикретность
Page_ReadWrite, // доступ разрешен
0, // размер занимаемый в верхней памяти
10000, // размер занимаемый в нижней памяти
MyFile"); // имя файла памяти
передаешь его параметры в длл и вперед,


 
Ihor Osov'yak   (2002-10-06 23:15) [2]

Попытаюсь ответить.


Первым делом - явная ошибка - на вызывающей стороне ты под
Buf: string; не запросил памяти (при стандартных установках компилятора string интерпритируется как AnsiString и при обьявлении оно есть nil или смотрит на глобальную пустую строчку - ньюансов уже не помню - лень запустать делфи и смотреть - но ТОЧНО там нет места для размещения результата, который ты туда суешь через

Move(PChar(DestText)^, Dest, Length(DestText));

В этом месте получишь вылет, или немного позже - что значительно хуже ...

Теперь немного философии. Для твоего сценария нужно решить, кто
выделяет память, и кто освобождает. Посколько ты планируешь работать в разнородной среде, где будут разные менеджеры памяти - то есть если память выделил борландовский менеджер, то майкрософтовский быстрее всего ее не сможет корректно освободить. И наоборот.
То есть единственный выход - принять за аксиому сценарий: кто выделяет, тот и освобождает. Естественно, это должна быть вызывающая сторона. Ибо она способна контролировать то обстоятельство, когда буффер уже можно убивать.
Другой вариант - использаовать структуры, память под которые распределяет система, а не рантайм конкретной системы программирования. К примеру widestring. Но чисто по религиозным аргументам я всегда с прохладцей отношусь ко второму варианту.

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

Немного сложнее с возвратом. Ибо вызывающая сторона должна выделить память до вызова, еще не зная нужного размера результата. Есть два варианта - выделяем с гарантированым запасом - но это то, что я называю бардачный стиль. Другой вариант - как это сделано в апи.
Должно быть три параметра - собственно указатель на буфер, размер бувера и возратное значение - сколько нужно.
Принимающая строна должна разобратся, какой размер ей передался и не выйти за пределы этого размера. И сказать через возвратное значение - сколько ей реально нужно.
На практике используют двойной вызов - первый раз вызывают с нулевым размером буфера - тогда длл говорит, сколько ей нужно. Естественно, было бы хорошо, чтобы она в этом случае никакой реальной работы не делала... Потом согласно полученому значению вызывающая сторона запрашивает память, делает "активный" вызов, получает результат, освобождает память.

Недостаток - не всегда можно определить размер результата - тогда можно работать по сценарию - выделяем память с запасом или
в итерационном процессе (если нет проблем с быстродействием)

Зы - некоторые умельцы используют для возврата строковых значений статически распределенные буферы "с запасом". Конечно,очень простое решение. Но получается очень много неразрешенных проблем при многопоточной работе и при рекурсивных вызовах (последнее можно получить при хитром использовании callback или sendmessage окнам главного приложения из кода своей функции). Хотя для простеньких случаев вполне допустимая практика. Сам иногда по причине природной лени юзаю. Главное - никаких проблем с віделением и освобождением памяти.









 
Ihor Osov'yak   (2002-10-06 23:18) [3]

2 Diamond Cat

Файлы, проецируемые в память хорошее средство для обмена между процесами. Внутри удного процесса - ну как минимум по пушкам из воробьев ... (это не оговорка - :-))


 
lmatveev   (2002-10-07 01:21) [4]

To

> Ihor Osov"yak © (06.10.02 23:15)


Большое спасибо за подробное разъяснение. У меня осталось несколько вопросов:
1. Правильно ли я понял, что если я буду передавать и возвращать параметры как WideString, то память будет выделяться автоматически?
2. Если использовать PChar, не натолкнусь ли я на проблему когда текст будет содержать "#0"?
3. Могу ли я для возврата текста использовать тот же PChar или нужен просто указатель на данные?


 
Ihor Osov'yak   (2002-10-07 09:50) [5]

1. Да. Выделением памяти под WideString и управлением их временем жизни занимается не delph, а oleaut32.dll, те виндовс.

не использовал этот механизм лишь потому, что в свое время не совсем разобрался с ним, плюс для меня были проблемы сделать поддержку widestring в тестовых приложениях на других системах программирования (не делфи).

2. Да, если использовать функции для обработки pchar. Но можно на принимающей стороне тело pchar перегнать в string тем же move,
ориентируясь на длинну входного буффера (!! см. замечание ниже) (ее, естественно, придется дополнительно передавать, в своем примере Вы так и делаете). Да, входной параметр pchar,pointer, нетипизированый var приводят к генерации одинакового машинного кода - то бышь это одно и тоже, разница только в шаманских заклинаниях исходного текста при приведении типа.

Еще одно. Если в теле входной строки может быть #0 - то хотя можно ее перегнать в string при помощи setlen+move или SetString - не нужно так делать. Ибо любой нормальный чел, видя pchar подразумевает нул_терминейт_стринг... В таком случае лучше использовать нетипизированный указатель или нетипизированый var. И хотя на уровне машинного кода это одно и тоже, первый вариант лучше, хотя бы потому, что к примеру сишный программер с элементарным знанием делфи такую конструкцию поймет, а вот нетипизированный var его быстрее всего собьет с толку... Но это уже имхо.

3. Этого вопроса я не понял. Что такое "просто указатель на данные". Если имеется ввиду нетипизированный указатель - да. См. выше по поводу еквивалентности pchar, pointer и приведения типов.







 
Ihor Osov'yak   (2002-10-07 09:59) [6]

да, для полноты ответа - то что Борланд пишет про строки в заготовке на dll по поводу ShareMem подразумевает то, что dll и основная программа ОБЕ на делфи. Ну и скромно умалчивается про необходимость таскать в таком случае за собой borlndmm.dll.

Если что-то не на делфи - забуть за ShareMem (сорри за надоедливое повторение)



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

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

Наверх





Память: 0.49 MB
Время: 0.009 c
14-59435
Сатир
2002-10-31 20:14
2002.11.18
Updates for Delphi 6


3-59006
Nemesis
2002-10-28 10:48
2002.11.18
Lock file has grown too large


1-59280
iNew
2002-11-07 17:18
2002.11.18
Как определить, что в ячейке ValueListEditor1.Cells


7-59459
Krot
2002-09-19 22:07
2002.11.18
Добавление вкладки


14-59333
netrebsky
2002-11-01 09:39
2002.11.18
Выбор языка





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