Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Работа со структурами и DLL.


Страницы:   1 2

X9 ©   (2005-08-04 09:01:00) 

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

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

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


Mx   (2005-08-04 15:33:00) [21]

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


evvcom   (2005-08-04 15:07:00) [22]


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

Если хочешь, чтобы твоя система была универсальной, т.е. плагины можно было бы писать не только на 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 и настраивает соответствующие указатели.


Digitman   (2005-08-04 14:42:00) [23]


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


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

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

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


Джо   (2005-08-04 14:34:00) [24]


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

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


X9   (2005-08-04 14:30:00) [25]

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

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

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

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


Digitman   (2005-08-04 13:10:00) [26]


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


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

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

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


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

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


DVM   (2005-08-04 12:32:00) [28]


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

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


X9   (2005-08-04 12:28:00) [29]

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

Имеется программа, которая должна поддерживать возможность подключения дополнительных модулей (плагинов). Плагины реализованы в виде 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?


X9   (2005-08-04 09:38:00) [30]

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


X9   (2005-08-04 09:34:00) [31]

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


Kolan   (2005-08-04 09:13:00) [32]


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

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


TUser   (2005-08-04 09:07:00) [33]

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо