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

Вниз

Работа со структурами и DLL.   Найти похожие ветки 

 
X9 ©   (2005-08-04 09:01) [0]

Здравствуйте!

Имеется задача: создать систему работа с плагинами (динамическая загрузка). Допустим, при работе с плагином необходимо передать некоторую структуру, в полях которой имеются записи типа string, HBITMAP и Word.
Как бы это сделать малой кровью? Простое присваивание, естественно, не катит.

Заранее благодарен,
 с уважением, X9.


 
TUser ©   (2005-08-04 09:07) [1]

Для Word - вполне катит. Со строками (и дин. массивами) - включи модуль ShareMem.


 
Kolan ©   (2005-08-04 09:13) [2]


> необходимо передать некоторую структуру

Работай с указателем.


 
X9 ©   (2005-08-04 09:34) [3]

2 TUser
Для Word - конечно. Модуль ShareMem включён. Но дело в том, что необходимо сразу скопировать всю структуру, а не копировать поле за полем, так как это не единственная структура, передаваемая из DLL. Думал как раз над работой с указателями, но как узнать размер передаваемой структуры, если он варьируется (string). Просто присвоением переменной указателя обойтись нельзя, так как структурой нужно будет пользоваться и после выгрузки библиотеки.


 
X9 ©   (2005-08-04 09:38) [4]

2 TUser
Для Word - конечно. Модуль ShareMem включён. Но дело в том, что необходимо сразу скопировать всю структуру, а не копировать поле за полем, так как это не единственная структура, передаваемая из DLL. Думал как раз над работой с указателями, но как узнать размер передаваемой структуры, если он варьируется (string). Просто присвоением переменной указателя обойтись нельзя, так как структурой нужно будет пользоваться и после выгрузки библиотеки.
И ещё - как проще передать из DLL BitMap, находящийся в её ресурсах? Именно передать через экспортируемую функцию, а не загружая из самого приложения. HBITMAP, возвращаемый функцией LoadBitmap - всего лишь указатель, а TResourceStream не могу использовать из-за увеличения размера DLL.


 
X9 ©   (2005-08-04 12:28) [5]

Вот полное описание задачи:

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

Вот пример такого плагина:
-------------testplugin.dpr-------------
library TestPlugin;

uses
 Classes;

type
 TPluginVersion = record
   BaseNo,
   ReleaseNo,
   BuildNo: Word;
   VersionComment: string;
 end;

 TPluginInfo = record
   Author,
   Comment,
   PluginName,
   SomeOtherString: string;
   Icon: TMemoryStream;
   ReleaseDate: TDateTime;
   Version: TPluginVersion;
 end;

function SendPluginInfo: ??? {нечто, возвращающее TPluginInfo};
var
 _Info: TPluginInfo;
 RStream: TResourceStream;
 MStream: TMemoryStream;
begin
 with _Info do
 begin
   Author := "Вася Пупкин";
   Comment := "Супер-Пупер навороченный плугин";
   PluginName := "Super-Puper Cool";
   SomeOtherString := "Some Other Value";
   RStream := TResourceStream.Create(hInstance, "PLUGIN_LOGO", "HT_BITMAP");
   MStream := TMemoryStream.Create;
   RStream.SaveToStream(MStream);
   RStream.Free;
   Icon := MStream;
   MStream.Free;
   ReleaseDate := 1.001;
   with Version do
   begin
     BaseNo := 1;
     ReleaseNo := 0;
     BuildNo := 1;
     VersionComment := "pre-alpha-beta";
   end;
 end;
 Result := ???; {нечто, передающее результату информацию _Info};
end;

exports
 SendPluginInfo name "GetPluginInfo";  


Как можно простейшим (не слишком медленным) путём сделать так, чтобы при вызове функции "GetPluginInfo" из программы, переменная типа TPluginInfo стала идентичной (по значениям полей) переменной _Info из DLL?


 
DVM ©   (2005-08-04 12:32) [6]


> полях которой имеются записи типа string, HBITMAP и Word.
> Как бы это сделать малой кровью?

а ты видел, как в WinAPI строки передаются - указатель на строку и длина - так и передавай. При получении строки от функции - первый вызов часто возвращает длину - второй вызов с указанием длины - строку.


 
nu>>   (2005-08-04 12:52) [7]

Перед вызовом SendPluginInfo создается экземпляр TPluginInfo.
первый член структуры - ее длина, заполняемый перед вызовом SendPluginInfo. Указатель на экземпляр передается в SendPluginInfo, которая может создать свой экземпляр и заполнить переданный посредством CopyMemory, либо заполнять почленно, основываясь на размере структуры.


 
Digitman ©   (2005-08-04 13:10) [8]


>    RStream := TResourceStream.Create(hInstance, "PLUGIN_LOGO",
> "HT_BITMAP");
>    MStream := TMemoryStream.Create;
>    RStream.SaveToStream(MStream);
>    RStream.Free;
>    Icon := MStream;
>    MStream.Free;


ерундища какая-то ...

прокомментируй ? каждую строчку ?

мне тайный смысл сего "магического" кода непонятен ..


 
X9 ©   (2005-08-04 14:30) [9]

2 DVM
>> а ты видел, как в WinAPI строки передаются
Видел, но это довольно хлопотно для 4 строк, я думал, что возможно сделать проще, извиняюсь за свою наивность.

2 nu>>
IMHO, в данном случае придётся передавать размер для каждой строки отдельно, а не для всё структуры разом (смотрите объявление TPluginInfo).

2 Digitman
Согласен, глупость отменная, но так я пытался вытащить из ресурсов определённый Bitmap и передать его вместе со структурой TPluginInfo.

И ещё:
Допустим, я хочу получить размер всей структуры. Имеются ли между полями "промежутки"? Понимаю, вопрос ламерский, но раньше я напрямую с памятью не работал :(


 
Джо ©   (2005-08-04 14:34) [10]


>  Имеются ли между полями "промежутки"?

Если указать packed record, то данные не будут выравниваться на границу [двойных] слов.


 
Digitman ©   (2005-08-04 14:42) [11]


> Согласен, глупость отменная


угу .. хотя бы в том что

  Icon := MStream; // зафиксировал ссылку на объект
  MStream.Free; // а сам объект тут же уничтожил

спрашивкается, КУДА будет "смотреть" возвращенная в структуре ссылка на якобы объект TMemoryStream ?  в никуда ? объекта-то уже нет - ты его своими ручками только что "прибил" ...


 
evvcom ©   (2005-08-04 15:07) [12]


> создать систему работа с плагинами

Если хочешь, чтобы твоя система была универсальной, т.е. плагины можно было бы писать не только на Delphi, но и на С, например, типа на продажу, и чтобы ею пользовались, то не используй string и выделение/освобождение памяти через New/Dispose, а используй API-функции. Тем самым к твоей программе, возможно, проявят интерес не только Дельфисты. Не используй дельфовых классов в структуре, а то ты отфильтруешь и Дельфистов, пишущих на отличных от твоей версии. Кроме того, ты еще заимеешь проблему того, что TMemoryStream в exe - это не то же самое, что TMemoryStream в dll с нехорошими последствиями, если конечно не с рантайм пакетами юзаешь.
А структура необязательно должна быть жесткой. Например:

type
TPluginVersion = record
  BaseNo,
  ReleaseNo,
  BuildNo: Word;
  VersionComment: PChar;
end;

TPluginInfo = record
  Author,
  Comment,
  PluginName,
  SomeOtherString: PChar;
  IcoSize: DWORD;
  Icon: PByte;
  ReleaseDate: TDateTime;
  Version: TPluginVersion;
end;

function GetPluginInfoSize: Longint;
procedure SendPluginInfo(var Buf; Size: Longint);

Из exe вызываешь HeapAlloc, запрашивая GetPluginInfoSize байт, потом SendPluginInfo. GetPluginInfoSize возвращает размер с учетом длины строк и места под иконку, а SendPluginInfo записывает строки и bitmap иконки следом за PluginInfo и настраивает соответствующие указатели.


 
Mx ©   (2005-08-04 15:33) [13]

Кстати, думаю здесь будет уместным спросить: много ли проигрываешь, если использовать WideString? Этот строковый тип, я так понимаю, стандартом для COM"а идет. Так если не мудохаться с PChar, а юзать WideString может проще будет? А то: в DLL выдели - в приложении освободи... напрягает.


 
Digitman ©   (2005-08-04 16:35) [14]


> Mx ©   (04.08.05 15:33) [13]


> в DLL выдели - в приложении освободи


иной раз и мелкомягкие так же поступают в своем WinAPI


 
inic ©   (2005-08-04 17:09) [15]

X9 ©   (04.08.05 9:01)

Ветку всю не осилил, так что если повторюсь извините

По сабжу можно попробовать интерфейсы.


 
X9 ©   (2005-08-04 18:38) [16]

2 evvcom
Кроме меня никто плагины для этой программы писать не будет, это точно, к тому же проект некоммерческий. Это, по сути, и не плагины вовсе - каждая из таких DLL"ок является модулем с абсолютно различной функциональностью, программа лишь обеспечивает минимум необходимых функций, общих для всех модулей и оболочку.

2 Mx
Может оно и лучше, только вот я раньше с Юникодом не работал :(. А нет ли у Вас хорошей ссылки по данному материалу?

2 inic
Каюсь, но в интерфейсах я тоже ни бум-бум. Может быть, и у Вас ссылочка завалялась?


 
X9 ©   (2005-08-04 18:38) [17]

2 evvcom
Кроме меня никто плагины для этой программы писать не будет, это точно, к тому же проект некоммерческий. Это, по сути, и не плагины вовсе - каждая из таких DLL"ок является модулем с абсолютно различной функциональностью, программа лишь обеспечивает минимум необходимых функций, общих для всех модулей и оболочку.

2 Mx
Может оно и лучше, только вот я раньше с Юникодом не работал :(. А нет ли у Вас хорошей ссылки по данному материалу?

2 inic
Каюсь, но в интерфейсах я тоже ни бум-бум. Может быть, и у Вас ссылочка завалялась?


 
Mx ©   (2005-08-04 18:45) [18]


> X9 ©   (04.08.05 18:38) [16]

Ссылок нет. WideString - тип для строк в COM (там он представлен типом BSTR). Я сам никогда не работал, потому и спросил. Как я понял с ним такой возни как с PChar (в плане выделения памяти) не требуется.

Про интерфейсы и как их реализовать для plug-in посмотри вот тут: http://interface.ru/fset.asp?Url=/borland/decom_1.htm. См. "продолжение статьи"...


 
Mx ©   (2005-08-04 18:46) [19]

На фига точка в URL забралась? Адрес:  http://interface.ru/fset.asp?Url=/borland/decom_1.htm


 
X9 ©   (2005-08-05 07:22) [20]

2 Mx
Спасибо! Буду смотреть.


 
evvcom ©   (2005-08-05 09:55) [21]


> А то: в DLL выдели - в приложении освободи... напрягает.

Чего напрягает? Ленивый что-ль? А ошибки, связанные с неправильным использованием string и ей подобных не напрягают? Когда компилятор за тебя неявно сам освобождает, как тебе казалось, нужную еще память? Может и зря я это написал? :)
А вообще более принято "где выделил, там и освобождай".


 
Mx ©   (2005-08-05 10:17) [22]


> evvcom ©   (05.08.05 09:55) [21]
> Ленивый что-ль

Ленивый, да. Бесит после вызовов функции ставить FreeMem. Если это может провернуть компилятор, то пусть он и делает.


> "где выделил, там и освобождай".

А как быть с результатом неизвестного размера? Дурацкий HRESULT и var параметры при необходимости вернуть строку ой как бесят.


 
evvcom ©   (2005-08-05 14:21) [23]


> А как быть с результатом неизвестного размера?

Реализовывать точно так же, как и пара GetWindowTextLength и GetWindowText. Конечно, не нстолько это удобно, как работать со string, но зато универсально.


 
X9 ©   (2005-08-05 15:12) [24]

Скажите пожалуйста, как правильно посчитать размер нижеописанной структуры:

type
 TMyRecord = packed) record
   StrValue1, // Длина строки 300 символов | 300 + 4 байт
   StrValue2, // -//-         310   -//-   | 310 + 4 байт
   StrValue3, // -//-         320   -//-   | 320 + 4 байт
   StrValue4: string; // -//-  330  -//-   | 330 + 4 байт
   BitmapBits: Pointer; // | 4 байта
   Version: Word; // | 2 байта
 end;


С содержимым всё ясно, но как быть с самой структурой (разделение полей и т.д.)?


 
Mx ©   (2005-08-05 15:36) [25]

Что за разделение полей? Что за размер "самой" структуры?


 
evvcom ©   (2005-08-05 16:02) [26]

Размер структуры = SizeOf(TMyRecord)


 
X9 ©   (2005-08-05 17:31) [27]

2 evvcom
>> Размер структуры = SizeOf(TMyRecord)
+ длина строк, так я понимаю? Потому что, например, SizeOf(вышеприведённая структура) возвращает 24.
Если я прав, тогда всё! :)


 
X9 ©   (2005-08-05 17:31) [28]

2 evvcom
>> Размер структуры = SizeOf(TMyRecord)
+ длина строк, так я понимаю? Потому что, например, SizeOf(вышеприведённая структура) возвращает 24.
Если я прав, тогда всё! :)


 
Mx ©   (2005-08-05 22:05) [29]


> X9 ©   (05.08.05 17:31) [28]

Никакой длины строк SizeOf не вернет. Её результат - кол-во байтов необходимых для хранения всех полей структуры. Т.к. string указатель, данные на которые он указывает не относится к полям структуры.


 
X9 ©   (2005-08-06 01:25) [30]

2 Mx
>> Никакой длины строк SizeOf не вернет.
Извините, я видимо неправильно выразился. Я имел ввиду то, что полный размер структуры = SizeOf(TMyRecord) + длина всех строк в ней.

Всё, наконец-то разобрался.

Спасибо огромное всем ответившим и модераторам за их терпение (постараюсь больше не дублировать сообщения, это всего-лишь недостатки DialUp"а).


 
Mx ©   (2005-08-06 01:37) [31]


> X9 ©   (06.08.05 01:25) [30]

У меня есть вопрос: зачем тебе вычислять такой "размер" структуры?


 
X9 ©   (2005-08-06 12:49) [32]

2 Mx
>> У меня есть вопрос: зачем тебе вычислять такой "размер" структуры?
Я думаю сделать так: получить размер всей структуры и с помощью CopyMemory просто скопировать область памяти со структурой из DLL в экземпляр структуры в программе. Это правильно?


 
Mx ©   (2005-08-06 20:21) [33]


> X9 ©   (06.08.05 12:49) [32]
> Я думаю сделать так: получить размер всей структуры и с
> помощью CopyMemory просто скопировать область памяти со
> структурой из DLL в экземпляр структуры в программе. Это
> правильно?

Не фига! Область, в которой выделена память для самих строк совершенно не обязательно прилегает к полям структуры. Ты ведь знаешь, что строки - указатели. Куда они указывают - заранее неизвестно. Потому CopyMemory здесь не подходит. Более того, если внимательно посмотреть на менеджмент строк, увидишь, что не обязательно каждой строковой переменной соответствует индивидуальный адрес строки. Две переменные могут разделать один и тот же адрес строки. Это вторая причина по которой CopyMemory неподходит. Копируй строки вручную.



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

Форум: "Основная";
Текущий архив: 2005.08.28;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.032 c
14-1123451681
uw
2005-08-08 01:54
2005.08.28
Всем кто сейчас пьет пиво.


14-1123314339
Alex Konshin
2005-08-06 11:45
2005.08.28
Электронные географические карты мира


1-1123484706
Новичёк
2005-08-08 11:05
2005.08.28
DLL и его процедуры и функции


14-1123361147
pasha_golub
2005-08-07 00:45
2005.08.28
Горю. Проблема с SP2


14-1123151892
Andy BitOff
2005-08-04 14:38
2005.08.28
Погордимся за наших.





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