なぜパッケージを使用するのでしょうか?
答えは簡単です。パッケージの力のためです。設計時パッケージはカスタム コンポーネントのリリースとインストールを簡素化し、実行時パッケージは従来のプログラミングに新たな力を注入します。再利用可能なコードをランタイム ライブラリにコンパイルすると、それを複数のアプリケーション間で共有できます。すべてのアプリケーションはパッケージを通じて標準コンポーネントにアクセスでき、Delphi 自体がこれを行います。アプリケーションは実行可能ファイル内の別個のコンポーネント ライブラリをコピーする必要がないため、システム リソースとディスク領域が大幅に節約されます。さらに、パッケージを使用すると、アプリケーション固有のコードのみをコンパイルするだけで済むため、コンパイルにかかる時間が短縮されます。
パッケージを動的に使用できれば、さらに多くのメリットが得られます。パッケージは、アプリケーション開発に対する新しいモジュール式アプローチを提供します。場合によっては、オプションの HR モジュールが付属する会計システムなど、特定のモジュールをアプリケーションのオプション コンポーネントにしたい場合があります。基本アプリケーションのみをインストールする必要がある場合もあれば、追加の HR モジュールをインストールする必要がある場合もあります。このモジュール式のアプローチは、パッケージ技術を通じて簡単に実装できます。これまでは、DLL を動的にロードすることによってのみこれを実現できましたが、Delphi のパッケージング テクノロジを使用すると、アプリケーションの各モジュール タイプをバンドルに「パッケージ化」することができます。特に、パッケージから作成されたクラス オブジェクトはアプリケーションによって所有されるため、アプリケーション内のオブジェクトと対話できます。
ランタイムパッケージとアプリケーション
多くの開発者は、実際にはモジュール式アプリケーション設計でパッケージを使用できる (そしてそうすべきである) にもかかわらず、Delphi パッケージをコンポーネントを配置する場所としてのみ考えています。
パッケージを使用してアプリケーションをモジュール化する方法を示すために、例を作成してみましょう。
1. Form1 と Form2 の 2 つのフォームを持つ新しい Delphi プログラムを作成します。
2. 自動的に作成されたフォーム リストから Form2 を削除します (PROject | オプション | フォーム)。
3. Form1 にボタンを配置し、ボタンの OnClick イベント ハンドラーに次のコードを入力します。
TForm2.Create(application) を使用して行う
始める
モーダルを表示;
無料;
終わり;
4. Unit1 の uses 句に忘れずに Unit2 を追加します。
5. プロジェクトを保存して実行します。
ボタンのあるフォームを表示し、クリックすると別のフォームを作成して表示する単純なアプリケーションを作成しました。
しかし、上記の例の Form2 を再利用可能なモジュールに組み込み、正常に動作させるにはどうすればよいでしょうか?
答えは「バオ!」です。
Form2 のパッケージを作成するには、次の作業が必要です。
1. プロジェクト マネージャーを開きます ([表示] | [プロジェクト マネージャー])。
2. プロジェクト グループを右クリックし、[新しいプロジェクトの追加...] を選択します。
3. 「新規」プロジェクトリストで「パッケージ」を選択します。
4. これで、パッケージ エディターが表示されるはずです。
5. 「次を含む」項目を選択し、「追加」ボタンをクリックします。
6. 次に、[参照...] ボタンをクリックして、[Unit2.pas] を選択します。
7. パッケージには「Unit2.pas」ユニットが含まれているはずです。
8. 最後にパッケージを保存してコンパイルします。
これでパッケージが完成しました。 Project/BPL ディレクトリに「package1.bpl」という名前のファイルがあるはずです。 (BPLはBorland Package Libraryの略称、DCPはDelphi CompiledPackageの略称です。)
このパッケージは完成しました。次に、パッケージオプションのスイッチをオンにする必要があります
そして元のアプリケーションを再コンパイルします。
1. プロジェクト マネージャーで「Project1.exe」をダブルクリックしてプロジェクトを選択します。
2. 右クリックして「オプション...」を選択します (メニューからプロジェクト | オプション... を選択することもできます)。
3. 「パッケージ」オプションページを選択します。
4. [ランタイム パッケージを使用してビルドする] チェック ボックスをオンにします。
5. 「ランタイムパッケージ」編集ボックス「Vcl50;Package1」を編集し、「OK」ボタンをクリックします。
6. 注: Unit2 をアプリケーションから削除しないでください。
7. アプリケーションを保存して実行します。
アプリケーションは以前と同じように実行されますが、違いはファイル サイズに見られます。
Project1.exe のサイズは、以前は 293K でしたが、現在はわずか 14K です。リソース ブラウザを使用して EXE ファイルと BPL ファイルの内容を表示すると、Form2 DFM とコードがパッケージに保存されていることがわかります。
Delphi は、コンパイル中にパッケージの静的リンクを完了します。 (これが、EXE プロジェクトから Unit2 を削除できない理由です。)
ここから何が得られるかを考えてください。パッケージ内にデータ アクセス モジュールを作成し、データ アクセス ルールを変更するとき (BDE 接続から ADO 接続への切り替えなど)、パッケージを少し変更して再公開することができます。あるいは、「このオプションは現在のバージョンでは使用できません」というメッセージを表示するフォームを 1 つのパッケージ内に作成し、完全に機能するフォームを同じ名前の別のパッケージ内に作成することもできます。今では、手間をかけずに製品を「プロ」バージョンと「エンタープライズ」バージョンで利用できるようになりました。
パッケージの動的なロードとアンロード
ほとんどの場合、静的にリンクされた DLL または BPL で十分です。しかし、BPL をリリースしたくない場合はどうすればよいでしょうか?アプリケーションが終了する前に表示されるメッセージは、「指定されたディレクトリにダイナミック リンク ライブラリ Package1.bpl が見つかりません」というメッセージだけです。それとも、モジュール型アプリケーションでは、プラグインをいくつでも使用できますか?
実行時に BPL に動的に接続する必要があります。
DLL の場合は、LoadLibrary 関数を使用する簡単な方法があります。
関数LoadLibrary(lpLibFileName:Pchar):HMODULE;stdcall;
DLL をロードした後、GetProcAddress 関数を使用して、DLL のエクスポートされた関数とメソッドを呼び出すことができます。
関数 GetProcAddress(hModule: HMODULE; lpProcName:LPCSTR): FARPROC;
最後に、FreeLibrary を使用して DLL をアンインストールします。
関数 FreeLibrary(hLibModule: HMODULE): BOOL;stdcall;
次の例では、Microsoft の HtmlHelp ライブラリを動的にロードします。
function TForm1.ApplicationEvents1Help(コマンド: Word; データ: 整数; var CallHelp: ブール値):ブール値;
タイプ
TFNHtmlHelpA = 関数(hwndCaller: HWND; pszFile: PansiChar; uCommand: UINT;dwData: Dword): HWND;
変数
ヘルプモジュール: Hmodule;
HTMLヘルプ: TFNHtmlHelpA;
始める
結果 := False;
ヘルプモジュール := LoadLibrary('HHCTRL.OCX');
if HelpModule <> 0 then
始める
@HtmlHelp := GetProcAddress(HelpModule, 'HtmlHelpA');
@HtmlHelp <> nil の場合
結果 := HtmlHelp(Application.Handle,Pchar(Application.HelpFile), Command,Data) <> 0;
FreeLibrary(ヘルプモジュール);
終わり;
CallHelp := False;
終わり;
BPL の動的ロード
BPL にも同じ簡単な方法を使用できます。あるいは、基本的に同じ簡単な方法と言うべきでしょうか。
LoadPackage 関数を使用してパッケージを動的にロードできます。
関数LoadPackage(定数名:文字列):HMODULE;
次に、GetClass 関数を使用して、TPersistentClass 型オブジェクトを作成します。
function GetClass(const AclassName: string):TPersistentClass;
すべてが完了したら、UnLoadPackage(Module:HModule); を使用します。
元のコードにいくつかの小さな変更を加えてみましょう。
1. プロジェクト マネージャーで「Project1.exe」を選択します。
2. 右クリックして「オプション...」を選択します。
3. 「パッケージ」オプションページを選択します。
4. 「ランタイムパッケージ」編集ボックスから「Package1」を削除し、「OK」ボタンをクリックします。
5. Delphi ツールバーで、[プロジェクトからファイルを削除] ボタンをクリックします。
6. 「Unit2 | Form2」を選択し、「OK」をクリックします。
7. 「Unit1.pas」のソース コードで、uses 句から Unit2 を削除します。
8. Button1 の OnClick タイムコードを入力します。
9. HModule タイプと TPersistentClass タイプの 2 つの変数を追加します。
変数
パッケージモジュール: HModule;
Aクラス: TPersistentClass;
10. LoadPackage 関数を使用して、Packge1 パッケージをロードします。
PackageModule := LoadPackage('Package1.bpl');
11. PackageModule が 0 であるかどうかを確認します。
12. GetClass 関数を使用して永続型を作成します。
AClass := GetClass('TForm2');
13. この永続型が nil でない場合は、前の状態に戻ることができます。
このタイプのオブジェクトを同じ方法で作成して使用します。
TcustomForm と同様に TComponentClass(AClass).Create(Application) を使用
始める
モーダルを表示;
無料;
終わり;
14. 最後に、UnloadPackage プロセスを使用してパッケージをアンインストールします。
UnloadPackage(パッケージモジュール);
15. プロジェクトを保存します。
OnClick イベント ハンドラーの完全なリストは次のとおりです。
プロシージャ TForm1.Button1Click(Sender: Tobject);
変数
パッケージモジュール: HModule;
Aクラス: TPersistentClass;
始める
PackageModule := LoadPackage('Package1.bpl');
if PackageModule <> 0 then
始める
AClass := GetClass('TForm2');
AClass <> nil の場合
TcustomForm と同様に TComponentClass(AClass).Create(Application) を使用
始める
モーダルを表示;
無料;
終わり;
UnloadPackage(パッケージモジュール);
終わり;
終わり;
残念ながら、それだけではありません。
問題は、GetClass 関数が登録された型しか検索できないことです。 フォーム内で通常参照されるフォーム クラスおよびコンポーネント クラスは、フォームが読み込まれるときに自動的に登録されます。ただし、この場合、フォームを早期にロードすることはできません。では、タイプをどこに登録するのでしょうか?答えは「カバンの中に」です。パッケージ内の各ユニットは、パッケージがロードされるときに初期化され、パッケージがアンロードされるときにクリーンアップされます。
ここで例に戻ります。
1. プロジェクトマネージャーで「Package1.bpl」をダブルクリックします。
2. 「Contains」セクションの「Unit2」の横にある + 記号をクリックします。
3. 「Unit2.pas」をダブルクリックしてユニットソースコードエディタを起動します。
4. ファイルの最後に初期化セクションを追加します。
5. RegisterClass プロシージャを使用して、フォーム タイプを登録します。
RegisterClass(TForm2);
6. 終了セクションを追加します。
7. UnRegisterClass プロシージャを使用して、フォーム タイプの登録を解除します。
UnRegisterClass(TForm2);
8. 最後に、パッケージを保存してコンパイルします。
これで「Project1」を安全に実行でき、以前と同じように動作しますが、必要に応じてパッケージをロードできるようになりました。
終わり
パッケージを静的に使用するか動的に使用するかに関係なく、[プロジェクト オプション] | [ランタイム パッケージを使用してビルド] をオンにしてください。
パッケージをアンインストールする前に、必ずパッケージ内のすべてのクラス オブジェクトを破棄し、登録されているすべてのクラスを登録解除してください。次のプロセスが役立つ場合があります。
プロシージャ DoUnloadPackage(モジュール: HModule);
変数
i: 整数。
M: TMemoryBasicInformation;
始める
for i := Application.ComponentCount - 1 downto 0 do
始める
VirtualQuery(GetClass(Application.Components[i].ClassName), M, Sizeof(M));
if (モジュール = 0) または (HMODULE(M.AllocationBase) = モジュール)
Application.Components[i].Free;
終わり;
UnregisterModuleClasses(モジュール);
UnloadPackage(モジュール);
終わり;
パッケージをロードする前に、アプリケーションは登録されているすべてのクラスの名前を知っている必要があります。この状況を改善する 1 つの方法は、パッケージによって登録されたすべてのクラスの名前をアプリケーションに伝える登録メカニズムを作成することです。
例
複数のパッケージ: パッケージは循環参照をサポートしません。つまり、ユニットは、既にそのユニットを参照しているユニットを参照することはできません (へへ)。これにより、呼び出しフォームの特定の値が呼び出されたメソッドによって設定されることが困難になります。
この問題の解決策は、呼び出し側オブジェクトとパッケージ内のオブジェクトの両方によって参照される追加のパッケージを作成することです。アプリケーションをすべてのフォームの所有者にする方法を想像してみてください。変数 Application は Forms.pas に作成され、VCL50.bpl パッケージに含まれます。アプリケーションで VCL50.pas をコンパイルする必要があるだけでなく、パッケージに VCL50 も必要であることに気づいたかもしれません。
3 番目の例では、顧客情報と、オンデマンドで顧客の注文を (動的に) 表示するアプリケーションを設計します。
では、どこから始めればよいでしょうか?すべてのデータベース アプリケーションと同様に
手順は同じで、接続する必要があります。 TDataBase 接続を含むメイン データ モジュールを作成します。次に、このデータ モジュールをパッケージ (cst_main) にカプセル化します。
次に、アプリケーションで顧客フォームを作成し、DataModuleMain を参照します (VCL50 と cst_main を静的にリンクします)。
次に、顧客注文フォームを含む新しいパッケージ (cst_ordr) を作成し、cst_main を要求します。これで、アプリケーションに cst_ordr を動的にロードできるようになりました。メイン データ モジュールは動的パッケージがロードされる前にすでに存在しているため、cst_ordr はアプリケーションのメイン データ モジュール インスタンスを直接使用できます。
上の図は、このアプリケーションの機能図です。
置換可能なパッケージ: パッケージのもう 1 つの使用例は、置換可能なパッケージを作成することです。この機能の実装には、パッケージの動的読み込み機能は必要ありません。プログラムの期間限定の試用版をリリースしたいとします。これを実現するにはどうすればよいでしょうか?
まず、「スプラッシュ」フォーム (通常は「トライアル」という単語が描かれた画像) を作成し、アプリケーションの起動時に表示します。次に、アプリケーションに関する情報を提供する「About」フォームを作成します。最後に、ソフトウェアが古いかどうかをテストする関数を作成します。これら 2 つの形式とこの機能をパッケージにカプセル化し、ソフトウェアの試用版とともにリリースします。
有料バージョンでは、前の 2 つのフォームと同じクラス名を持つ「スプラッシュ」フォームと「About」フォーム、およびテスト関数 (何も実行しない) も作成し、それらを同じパッケージにカプセル化して追加します。名前。
なになに?これは便利ですか?さて、ソフトウェアの試用版を一般公開できます。顧客がアプリを購入した場合は、試用版以外のパッケージを送信するだけで済みます。これにより、インストールと登録パッケージのアップグレードが 1 回だけ必要となるため、ソフトウェア リリース プロセスが大幅に簡素化されます。
このパッケージは、Delphi および C++ Builder 開発コミュニティにモジュラー設計への新たな扉を開きます。パッケージを使用すると、ウィンドウ ハンドルを渡す必要がなく、コールバック関数や他の DLL テクノロジも必要ありません。これにより、モジュール型プログラミングの開発サイクルも短縮されます。私たちがしなければならないのは、Delphi のパッケージを機能させることだけです。