我們的插件外殼程序與普通應用程序之間的唯一不同就在于工程源文件中出現在uses子句中的Sharemem單元和加載插件文件的代碼。任何在自身與子DLL之間傳遞字符串參數的應用? 都需要Sharemem單元,它是DelphiMM.dll(Delphi提供該文件)的接口。要測試這個外殼,需要將DelphiMM.dll文件從Delphi/Bin目錄復制到path環境變量所包含的路徑或者應用程序所在目錄中。發布最終版本時也需要同時分發該文件。 插件通過LoadPlugins過程載入到這個測試外殼中,這個過程在主窗口的FormCreate事件中調用,見圖2。該過程使用FindFirst和FindNext函數在應用程序所在目錄中查找插件文件。找到一個文件以后,就使用圖3所示的LoadPlugins過程將其載入。 { 在應用程序目錄下查找插件文件 } PRocedure TfrmMain.LoadPlugins; var sr: TSearchRec; path: string; Found: Integer; begin path := ExtractFilePath(application.Exename); try Found := FindFirst(path + cPLUGIN_MASK, 0, sr); while Found = 0 do begin LoadPlugin(sr); Found := FindNext(sr); end; finally FindClose(sr); end; end;
{ 加載指定的插件 DLL. } procedure TfrmMain.LoadPlugin(sr: TSearchRec); var Description: string; LibHandle: Integer; DescribeProc: TPluginDescribe; begin LibHandle := LoadLibrary(Pchar(sr.Name)); if LibHandle $#@60;$#@62; 0 then begin DescribeProc := GetProcAddress(LibHandle, cPLUGIN_DESCRIBE); if Assigned(DescribeProc) then
begin DescribeProc(Description); memPlugins.Lines.Add(Description); end else begin MessageDlg(’File "’ + sr.Name +’" is not a valid plug-in.’, mtInformation, [mbOK], 0); end; end else MessageDlg(’An error occurred loading the plug-in "’ + sr.Name + ’".’, mtError, [mbOK], 0); end;
我們已經創建好了父應用程序,現在該輪到創建我們希望加載的插件了。插件文件是一個標準的Delphi DLL,所以我們從Delphi IDE中創建一個新DLL工程,保存它。由于導出的插件函數將用到字符串參數,所以要在工程的uses子句中把Sharemen單元放在最前面。圖4列出的就是我們這個簡單插件的工程源文件。 uses Sharemem, SysUtils, Classes, main in ’main.pas’;
{$E plg.}
eXPorts DescribePlugin;
begin
end.
雖然插件是一個DLL文件,但是沒有必要一定要給它一個.DLL的擴展名。實際上,一個原因就足以讓我們有理由改變擴展名:當父應用程序尋找要加載的文件時,新的擴展名可以作為特定的文件掩模。通過使用別的擴展名(我們的例子使用了*.plg),你可以在一定程度上確信應用程序只會載入相應的文件。編譯指示字$X可以實現這個改變,也可以通過Project Options對話框的Application頁來設置擴展名。 第一個例子插件的代碼是很簡單的。圖5顯示了包含在一個新單元中的代碼。注重,DescribePlugin原型與外殼應用程序中的TpluginDescribe類型相一致,使用附加的export保留字指定該過程將被導出。被導出的過程名稱也將會出現在主工程源代碼的exports段中(在圖4中列出)。 unit main;