Разбить одно приложение на части
Заранее благодарю за любой совет.
ЗЫ - Не хочу плодить много модальных окон. Хочется реализовать в одном главном.
Есть приложение. Приложение логически делится на некоторые части. Ради удобства, я просто сделал на нем меню с кнопочками в левой стороне окна и компонент TPageControl c правой и скрыл у него "заголовки табов". Грубо говоря, просто по щелчку кнопки меню ставлю активной соответствующую страницу TPageCotrol которая имеет свое содержимое. Так сказать свою реализацию - всяческие листы, панели, кнопки и все это со своим функционалом. Грубо говоря на вкладке Autorun содержимое соответствующих веток реестра, а на вкладке RegDLL - список зарегистрированных в системе DLL. Просто я хочу сделать так, чтобы Содержимое Каждой такой Вкладки загружалось непосредственно из DLL при переходе на вкладку и выгружалось, дабы облегчить EXEшник и пожалеть память. Но не загружалось все целиком при запуске. Вот и спрашиваю у вас, каким способом это можно сделать с адекватным сопротивлением и наибольшей грамотностью)))
Ага. А потом мы увидим сообщение о твоем убийстве разгневанными пользователями, у которых отчего-то все это поделие жутко тормозит при переключении вкладок. А экзешник ты таким способом не облегчишь ни разу, по крайней мере в Delphi, поскольку весь ее RTL придется тянуть в каждую DLL, либо класть рядом bpl-ки. Ну ежели нужно изобретение очередного кривого лисапеда, то поищи в разделе по ключевому слову "плагины". Тема уже неоднократно поднималась и были предложены абсолютно все варианты.
Наиболее грамотно будет сделать нормальное приложение и не парить себе мозг. Реализация плагинов - это уже "неадекватное сопротивление" и требуется в очень немногих случаях. Не в твоем точно. Выйгрыш от экономии памяти будет никаким, по сравнению с трудоемкостью разработки, скорости работы получившегося приложения и граблями в последующем сопровождении. Единственный плюс - так сказать, экспириенс...
Пример приложения
public
tabsStack: array of TForm;
{...}
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
UnloadPlugins();
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
LoadPlugins();
end;
procedure TForm1.LoadPlugins;
var
SearchRec: TSearchRec;
I : Integer;
begin
SetLength(tabsStack, 0);
I := FindFirst(ExtractFilePath(Application.ExeName)+'\plugins\*.dll', faAnyFile, SearchRec);
while I = 0 do
begin
LoadPlugin(SearchRec.Name);
I := FindNext(SearchRec);
end;
FindClose(SearchRec);
end;
procedure TForm1.LoadPlugin(name: string);
type
getPlugin = function(): TForm;
var
call: getPlugin;
dynamicLibrary: HMODULE;
TabSheet: TTabSheet;
begin
dynamicLibrary := LoadLibrary(PChar(ExtractFilePath(Application.ExeName)+'\plugins\'+name));
call := GetProcAddress(dynamicLibrary,PChar('getPlugin'));
if (not assigned(call)) then begin
FreeLibrary(dynamicLibrary);
end else begin
SetLength(tabsStack, Length(tabsStack)+1);
TabSheet:=TTabSheet.Create(Self);
TabSheet.DoubleBuffered:=true;
TabSheet.PageControl:=PageControl1;
tabsStack[length(tabsStack)-1]:=call();
TabSheet.Caption:=tabsStack[length(tabsStack)-1].Caption;
with tabsStack[length(tabsStack)-1] do begin
BorderStyle:=bsNone;
DoubleBuffered:=true;
Align:=alClient;
Parent:=TabSheet;
Show;
end;
end;
end;
procedure TForm1.UnloadPlugins;
var
i:integer;
begin
for i:=0 to Length(tabsStack)-1 do begin
tabsStack.Free;
end;
end;
Пример плагина
uses
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
function getPlugin(): Pointer; export;
begin
Result:=TForm2.Create(nil);
end;
exports
getPlugin name 'getPlugin';
end.
Успехов!
Ну-с, для начала: размер *.exe + размер *.dll = ?
Остальное комментировать страшно...
Если собирать с пакетами, то 4 кб на ехе/длл не так уж и много.
По поводу темы вообще - makbeth верно говорит, плюсов от такой реализации будет меньше, чем минусов, в частности, из-за мороки с отладкой и шаредными ресурсами, которые надо будет передавать из длл в ехе (это ж не просто функция, а компоненты, вполне возможно, придётся пошаманить).
(Кстати, с фреймами проблем пока не наблюдал, я бы использовал их вместо форм, они всё же полегче будут.)
Единственное, если вам действительно нужна функциональность плагинов - тогда можно использовать и такой подход. Но я бы его немного уточнил: вместо хранения каждой вкладки в DLL я бы сделал (1) возможность длл хранить несколько вкладок сразу + (2) возможность зашивать вкладки статически в саму прогу (ехе). Второй пункт делается несложно через абстракный класс для плагинов.
Первый пункт нам даст бонус в производительности/памяти (не нуно держать длл для плагинов, которые сразу много вкладок добавляют). Второй - позволит не таскать с собой длл для стандартных вкладок, плюс уменьшит размер проги в целом, т.к. это будет один ехе, а не ехе + длл. Ну, и производительность/память тут же.
Угу. Только вот сами RTL пакеты в сумме весят больше чем получилось бы одно монолитное приложение. Пакеты хороши, когда используется одновременно несколько программ. Тогда это оправданно. А так - ради одной проги - таскать с собой еще и весь RTL...:(
Ну да, естесственно. Плюс там ещё можно выбрать, какие с какими пакетами собирать, так что не обязательно всю среду тянуть.
Вообще, подход Борланда мне в этом плане нравится гораздо больше .Net'овского - там надо тягать 250 метров дистриба framework'а, плюс админские права, ежели он не установлен.
з.ы.: кстати, а в нете есть статическая линковка или какой-то аналог bpl? По моему неглубокому знакомству с VS такое я видел только для C++.
я как то ковырял это дело. мне удалось дотнетовское приложение без установленного фреймворка запустить. только дллки нужные запихнул и всё, но не знаю всё ли работает в таком виде. форма с кнопочкой запустилась :)
Все равно с пакетами общий объем проги выходит намного больше, чем та же прога в статике. Оно и понятно...
250 метров - это SDK. Реально, только фреймворк - 80-90 вроде.
"Грузите апельсины бочками" (c) Microsoft
Похожая аналогия - нафига мне куча офисных приложений, если мне нужен только Word?
Курим про ngen.