![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Работа со структурами и DLL.
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.