お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"パッケージを動的にロードする"





Delphi3以降で使えるパッケージ機能を使うと,実行時に追加のパッケージを
ロードして機能を増やすことが出来ます.

○ 機能を分割する単位でパッケージを作る.下段はcontains
 Project1.dpr/exe    母艦的役割のアプリケーション
    Unit1.pas
 Extpkg1.dpk/dpl     追加機能その1(フォームを追加)
    Unit2.pas
  Extpkg2.dpk/dpl     追加機能その2(カスタムコンポの追加)
    Unit3.pas
  pkgcommon.dpk/dpl   共通に参照されるパッケージ
    RegPkg.pas

○ Extpkg1,Extpkg2に含まれるユニットの中では,exeに含まれるユニットをuses
 しないほうがよい.参照して良いのはpkgcommonに含まれるものだけ

○ exeやpkgcommon内のunitからExtpkg1,Extpkg2のユニットをusesしてはいけない

○ Extpkg1, Extpkg2は相互に参照しないほうがよい.でないと個別にロードできる
利点を失ってしまうから.しかし同時にロードする組み合わせを考えておけば
うまいこといくようにも作れる.

○ exeのオプションでは実行時パッケージを使うにし,使用するパッケージとして
pkgcommon.dplを追加しておく.

○ 使うパッケージ,DLL等はexeのあるフォルダに全部放り込んで置く

<Extpkg1の内容>
 新しいフォームを作って表示できるようにする

<Extpkg2の内容>
 新しいコンポーネントを追加して,exeや他のパッケージが持っている
フォームに貼り付けられるようにする
# これで気分はコンポーネントパレット状態(^^;

○ exeを実行し,ボタンをクリックする

○ パッケージが他のパッケージをrequireしている場合は,そいつも自動で
ロードする.その過程で,再帰呼出の中でコールバックを使うことになるため,
自前のスタックStack:TListに一時変数を取っている.リエントラントにはならん.

-------------- Unit1(exeのメインフォーム)抜粋 ------------------
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    ListBox1: TListBox;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure ListBox1DblClick(Sender: TObject);
  public
    HPkg: HMODULE;
    Next: integer;
  end;

// 追加フォームの表示
procedure TForm1.Button1Click(Sender: TObject);
begin
  // フォームパッケージをロード
  HPkg := LoadExtPackage(GetModuleFileNamePath + 'Extpkg1');
  Screen.Forms[Screen.FormCount-1].ShowModal;
  UnLoadPackage(HPkg);
end;

// 追加コンポクラスを取り込み
procedure TForm1.Button2Click(Sender: TObject);
var  Count: integer;
begin
  // コンポーネントパッケージをロード
  HPkg := LoadExtPackage(GetModuleFileNamePath + 'Extpkg2');
  Count := ListBox1.Items.Count;
  while Count < ExtControlClassList.Count do begin
    ListBox1.Items.AddObject(
        TControlClass(ExtControlClassList[Count]).ClassName,
        ExtControlClassList[Count] );
    inc(Count);
  end;
end;

// カスタムコンポを張り付け
procedure TForm1.ListBox1DblClick(Sender: TObject);
var i: integer; Control: TControl;
begin
  i := ListBox1.ItemIndex;
  if i < 0 then Exit;
  Control := TControlClass(ListBox1.Items.Objects[i]).Create(Self);
  Control.Parent := Self;
  Control.Top := Next;
  inc(Next, Control.Height);
end;

------------------ Unit2 抜粋 タダのフォーム ---------------------
uses RegPkg;

initialization
  RegisterExtForm(TForm2, Form2);

finalization
  UnRegisterExtForm(TForm2);

----------- unit3 抜粋 実行時追加型(^^;カスタムコンポの宣言 ----------
uses RegPkg;

  TMyControl1 = class(TLabel)
  public
    constructor Create(AOwner: TComponent); override;
  end;

  TMyControl2 = class(TLabel)
  public
    constructor Create(AOwner: TComponent); override;
  end;

constructor TMyControl1.Create;
begin
  inherited Create(AOwner);
  Caption := '11111111';
end;

constructor TMyControl2.Create;
begin
  inherited Create(AOwner);
  Caption := '2 2 2 2 2';
end;

initialization
  RegisterExtControlClasses([TMyControl1, TMyControl2]);

finalization
  UnRegisterExtControlClasses([TMyControl1, TMyControl2]);

---------------------- RegPkg 全文 ---------------------------------
unit RegPkg;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ActiveX;

procedure RegisterExtForm(FormClass: TFormClass; var AForm);
procedure RegisterExtControlClasses(
            ControlClasses: array of TPersistentClass);
procedure UnRegisterExtForm(FormClass: TFormClass);
procedure UnRegisterExtControlClasses(
            ControlClasses: array of TPersistentClass);

procedure SetRequiredPackageList(HPkg: HMODULE; const List: TStrings);
function  LoadExtPackage(PkgName: string): HMODULE;
function  GetModuleFileName: string;
function  GetModuleFileNamePath: string;

var
  ExtPackageList: TList;
  ExtControlClassList: TList;

implementation

procedure RegisterExtForm(FormClass: TFormClass; var AForm);
begin
  RegisterClass(FormClass);
  Application.CreateForm(FormClass, AForm);
end;

procedure RegisterExtControlClasses(
            ControlClasses: array of TPersistentClass);
var  i: integer;
begin
  RegisterClasses(ControlClasses);
  for i := 0 to High(ControlClasses) do
    ExtControlClassList.Add(ControlClasses[i]);
end;

procedure UnRegisterExtForm(FormClass: TFormClass);
var  i: integer;
begin
  with Application do begin
    for i := ComponentCount-1 downto 0 do begin
      if Components[i] is FormClass then
        Components[i].Free;
    end;
  end;
  UnRegisterClass(FormClass);
end;

procedure UnRegisterExtControlClasses(
            ControlClasses: array of TPersistentClass);
var  i: integer;
begin
  UnRegisterClasses(ControlClasses);
  for i := 0 to High(ControlClasses) do
    ExtControlClassList.Remove(ControlClasses[i]);
end;

var
  Stack: TList;

procedure InfoProc( const Name: string; NameType: TNameType;
                    Flags: Byte; Param: Pointer);
begin
  if NameType = ntRequiresPackage then
    TStringList(Stack.Last).Add( Name );
end;

procedure SetRequiredPackageList(HPkg: HMODULE; const List: TStrings);
var  Flags: Integer;
begin
  List.Clear;
  Stack.Add(List);
  try
    GetPackageInfo(HPkg, nil, Flags, InfoProc);   // callback
  finally
    Stack.Delete(Stack.Count-1);
  end;
end;


function EnumModuleFunc(HInstance: Longint; Data: Pointer): Boolean;
var  ModuleName: string;
  Indx: integer;
  List: TStringList;
  Buffer: array[0..261] of Char;
begin
  List := Stack.Last;
  SetString( ModuleName, Buffer,
          Windows.GetModuleFileName(HInstance,Buffer,SizeOf( Buffer )) );
  ModuleName := ExtractFileName(ModuleName);
  ModuleName := ChangeFileExt( ModuleName, '' );
  Indx := List.IndexOf( ModuleName );
  if Indx >= 0 then
    List.Delete(Indx);  // delete the package names already loaded
  Result := True;
end;

function LoadExtPackage(PkgName: string): HMODULE;
var i: integer;
  Path: string;
  List: TStringList;
begin
  Result := LoadLibrary(PChar(PkgName + '.dpl'));
  if (Result > -1) and (Result <= 32) then
    raise EPackageError.CreateFmt(sErrorLoadingPackage,
      [PkgName, SysErrorMessage(GetLastError)]);
  List := TStringList.Create;
  Stack.Add(List);
  try
    try
      SetRequiredPackageList(Result, List);
      Path := ExtractFilePath(PkgName);
      EnumModules( EnumModuleFunc, nil );  // callback
      for i := 0 to List.Count-1 do
        LoadExtPackage( Path + List[i] );  // recursion
      InitializePackage(Result);
      ExtPackageList.Add(Pointer(Result));
    except
      FreeLibrary(Result);
      raise;
    end;
  finally
    Stack.Delete(Stack.Count-1);
    List.Free;
  end;
end;

function  GetModuleFileName: string;
var Buffer: array[0..261] of Char;
begin
  SetString( Result, Buffer,
          Windows.GetModuleFileName(HInstance,Buffer,SizeOf( Buffer )) );
end;

function  GetModuleFileNamePath: string;
begin
  Result := ExtractFilePath(GetModuleFileName);
end;

initialization
  Stack := TList.Create;
  ExtPackageList := TList.Create;
  ExtControlClassList := TList.Create;

finalization
  ExtControlClassList.Free;
  ExtPackageList.Free;
  Stack.Free;

end.
                                                  TN(CQJ01721)

Original document by TN            氏 ID:(CQJ01721)


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum