Pemrograman struktur plug-in memerlukan wadah plug-in untuk mengontrol pengoperasian setiap DLL, dan mengatur setiap subsistem yang terbagi ke dalam file perpustakaan DLL. Untuk setiap program DLL, fungsi antarmuka perlu dicadangkan untuk wadahnya. Umumnya, fungsi antarmuka meliputi: fungsi yang memulai memanggil perpustakaan DLL dan fungsi yang menutup perpustakaan DLL. Melalui fungsi antarmuka, wadah plug-in dapat meneruskan parameter ke modul DLL untuk mencapai kontrol dinamis. Saya akan menjelaskan detail implementasi spesifik dan memberikan kode respons di bawah.
Anda mungkin perlu memahami terlebih dahulu struktur UNIT dan struktur proyek di DELPHI. Artikel ini tidak membahas rincian teoritis pemrograman DLL secara mendalam, tetapi hanya menunjukkan beberapa kode praktis. Saya sedang mempelajari buku "DELPHI In- depth Programming" oleh Liu Yi.
Saya juga dalam tahap pengenalan DELPHI. Saya hanya merasa ada beberapa hal yang perlu dibahas dalam pengembangan DLL ini, jadi saya menulis artikel ini. Saya harap Anda dapat memberikan saran yang murah hati tentang apa yang saya kurang lakukan.
Pengantar program sampel
Untuk memudahkan pembacaan, saya akan menggunakan bagian dari kode program sistem MIS untuk mendemonstrasikan beberapa metode pemrograman plug-in. Program sampel adalah aplikasi DBMS struktur C/S yang khas. Fokus kami adalah pada pernyataan kontrol program kerangka kerja (selanjutnya disebut Hall) dan kontrol respons dari program plug-in dll.
1. Struktur program
Aula kontainer plug-in dibuat menggunakan proyek independen. Jendela utama Aula setara dengan bentuk wadah MDI dalam program MDI. Fungsi antarmuka di Dll akan dipanggil secara eksplisit di Aula.
Setiap program plug-in menggunakan proyeknya sendiri secara independen. Berbeda dari proyek biasa, proyek DLL membuat Dll Wizard, dan file yang dihasilkan oleh kompilasi terkait memiliki akhiran DLL.
=550) window.open('/upload/20080315181507424.jpg');" src="http://files.VeVB.COM/upload/20080315181507424.jpg" onload="if(ini.lebar>'550')ini.lebar='550';if(ini.tinggi>'1000')ini.tinggi='1000';" perbatasan=0>
2. Desain antarmuka
Dalam contoh program Narcissus, kami mencadangkan dua fungsi antarmuka:
TampilkanDLLForm
Fungsi ini meneruskan pegangan aplikasi ke jendela anak DLL, dan program DLL secara dinamis akan membuat instance formulir DLL. Anda juga dapat meneruskan beberapa logika bisnis ke subjendela DLL dalam bentuk parameter, seperti nama formulir, nama pengguna yang sedang login, dll. Gunakan fungsi ini untuk membuat instance formulir DLL saat dipanggil pertama kali.
GratisDLLForm
Fungsi ini akan menampilkan pelepasan instance jendela DLL, dan memanggil metode FreeDLLForm dari setiap formulir DLL untuk melepaskan instance yang dibuat saat keluar dari aplikasi, jika tidak maka akan menyebabkan kesalahan hanya baca memori. Demikian pula, Anda juga dapat meneruskan beberapa logika bisnis yang perlu dilakukan saat melepaskan formulir ke formulir DLL dalam bentuk parameter.
3. Metode debug
Program formulir DLL tidak dapat dijalankan secara langsung dan memerlukan wadah plug-in untuk memanggilnya. Oleh karena itu, pertama-tama kita perlu mengimplementasikan program Hall dasar, lalu menyimpan Hall.exe di direktori tetap. Buat pengaturan berikut untuk setiap proyek DLL:
1) Buka proyek DLL
2) Pilih menu Jalankan Parameter
3) Jelajahi wadah kami Hall.exe di jendela pop-up
Dengan cara ini, program Hall akan dipanggil secara otomatis saat men-debug program DLL, dan program DLL akan di-debug menggunakan antarmuka panggilan yang disediakan di Hall.
Implementasi dasar program plug-in
Metode desain program DLL tidak jauh berbeda dengan WINAPP biasa, hanya saja semua jendela disimpan di perpustakaan DLL sebagai "sumber daya" khusus dan perlu dipanggil secara manual, tidak seperti di WINAPP di mana proyek dibuat secara otomatis. Metode mendeklarasikan fungsi antarmuka sangat sederhana
1) Mendeklarasikan fungsi pada bagian Implementasi Unit
2) Tambahkan tanda stdcall di akhir pernyataan deklarasi fungsi
3) Sebelum pernyataan awal kode proyek (Sumber Tampilan Proyek), gunakan pernyataan ekspor untuk mendeklarasikan antarmuka fungsi
Untuk membuat kodenya ringkas, saya pribadi ingin menambahkan unit Unit (File Baru -- Unit) secara independen dalam proyek, dan kemudian mendefinisikan semua badan fungsi yang akan dikeluarkan dalam unit ini Satuan formulir yang dirujuk. Saya menamai unit ini UnitEntrance, menginisialisasi jendela untuk ditampilkan dalam fungsi ShowDLLForm dan memanggil metode Show untuk menampilkannya. HALL akan meneruskan nama pengguna yang login sebagai parameter. Setelah mendapatkan nama pengguna, beberapa kontrol izin dapat dilakukan, yaitu tercermin dalam inisialisasi antarmuka superior.
Kodenya adalah sebagai berikut
unit UnitKantorPintu Masuk;
antarmuka
kegunaan
Windows, Pesan, SysUtils, Varian, Kelas, Grafik, Kontrol, Formulir;
fungsi ShowDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;stdcall;
fungsi FreeDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;stdcall;
pelaksanaan
menggunakan UnitOfficialMainForm; //Ubah ke unit MAINFORM
var
DLL_Form:TFormOfficialMain; //Ubah ke nama MAINFORM
//--------------------------
//Nama: TampilkanDLLForm
//Func: Plug-in DLL memanggil fungsi entri
//Para: AMenangani pegangan program terlampir; ACaption judul formulir ini
//Rtrn: T/A
//Otentikasi: CST
//Tanggal: 2005-6-3
//--------------------------
fungsi ShowDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;
mulai
hasil:=benar;
mencoba
Application.Handle:=AHandle; //Dipasang ke wadah program utama
DLL_Form:=TFormOfficialMain.Create(Aplikasi); //Ubah ke NAMA MAINFORM
mencoba
dengan DLL_Form lakukan
mulai
Keterangan := ACaption;
StatusBar.Panel.Item[0].Teks := AUserID;
//Konfigurasi UI
Menunjukkan ;
akhir;
kecuali
di e: pengecualian lakukan
mulai
dll_form.Gratis;
akhir;
akhir;
kecuali
hasil:=salah;
akhir;
akhir;
//--------------------------
//Nama: FreeDLLForm
//Func: Plug-in DLL memanggil fungsi ekspor
//Para: Menangani pegangan program terlampir
//Rtrn: benar/salah
//Otentikasi: CST
//Tanggal: 2005-6-11
//--------------------------
fungsi FreeDLLForm(AHandle: THandle; ACaption: string; AUserID: string):boolean;
mulai
Application.Handle:=AHandle; //Dipasang ke wadah program utama
if DLL_Form.Showing kemudian DLL_Form.Close; //Jika jendela dibuka dan ditutup terlebih dahulu, memicu FORM.CLOSEQUERY dapat membatalkan proses penutupan
jika tidak DLL_Form.Showing kemudian
mulai
DLL_Form.Gratis;
hasil:=benar;
end //Masih terbuka, menunjukkan CLOSEQUERY.CANCLOSE=FALSE
kalau tidak
mulai
hasil:=salah;
akhir;
akhir;
akhir.
Kode file proyek DLL adalah sebagai berikut:
Petugas perpustakaan;
{ Catatan penting tentang manajemen memori DLL: ShareMem harus menjadi
unit pertama dalam klausa USES perpustakaan Anda DAN proyek Anda (pilih
Project-View Source) klausa USES jika DLL Anda mengekspor prosedur atau
fungsi yang melewatkan string sebagai parameter atau hasil fungsi
berlaku untuk semua string yang diteruskan ke dan dari DLL Anda--bahkan yang itu
bersarang di catatan dan kelas. ShareMem adalah unit antarmuka
manajer memori bersama BORLNDMM.DLL, yang harus digunakan bersama
dengan DLL Anda. Untuk menghindari penggunaan BORLNDMM.DLL, berikan informasi string
menggunakan parameter PChar atau ShortString }
kegunaan
sistemUtils,
Kelas,
UnitOfficialDetailForm di 'UnitOfficialDetailForm.pas' {FormOfficialDetail},
UnitOfficialMainForm di 'UnitOfficialMainForm.pas' {FormOfficialMain},
UnitOfficeEntrance di 'UnitOfficeEntrance.pas',
UnitOfficialClass di '../../Public/Library/UnitOfficialClass.pas',
UnitMyDataAdatper di '../../Public/Library/UnitMyDataAdatper.pas',
UnitMyHeaders di '../../Public/Library/UnitMyHeaders.pas';
{$R *.res}
ekspor ShowDLLForm,FreeDLLForm; //fungsi antarmuka
mulai
akhir.
Setelah program plug-in memanggil jendela DLL, instance jendela akan tetap berada di atas jendela HALL, jadi tidak perlu khawatir tentang oklusi.
Implementasi program kontainer
1. Pengenalan fungsi antarmuka
Ada dua cara untuk memanggil fungsi di perpustakaan DLL: eksplisit dan implisit. Panggilan eksplisit lebih fleksibel, jadi kami menggunakan panggilan eksplisit. Di Delphi, Anda perlu mendeklarasikan tipe fungsi untuk fungsi antarmuka, dan kemudian membuat instance dari tipe fungsi tersebut. Instance tersebut sebenarnya adalah penunjuk ke fungsi tersebut. Melalui penunjuk, kita dapat mengakses fungsi, meneruskan parameter, dan memperoleh nilai kembaliannya. Tambahkan deklarasi kelas fungsi di bagian Antarmuka pada file unit:
jenis
//Tentukan jenis fungsi antarmuka, fungsi antarmuka berasal dari antarmuka DLL
TShowDLLForm = Fungsi(AHandle:THandle; ACaption: String; AUserID:string):Boolean;stdcall;
TFreeDLLForm = Fungsi(AHandle:THandle; ACaption: String; AUserID:string):boolean;stdcall;
Fungsi perpustakaan panggilan tampilan memerlukan langkah-langkah berikut:
1) Muat file perpustakaan DLL
2) Dapatkan alamat fungsi
3) Jalankan fungsi
4) Lepaskan perpustakaan DLL
Selanjutnya kita akan membahas langkah-langkah tersebut secara detail.
2. Muat file perpustakaan DLL
Pustaka DLL dapat dimuat ke dalam memori dengan memanggil fungsi API LoadLibrary. Kami tidak akan membahas dampak DLL pada manajemen memori di sini. Parameter LoadLibrary adalah jalur alamat file DLL. Jika pemuatan berhasil, variabel tipe CARDINAL akan dikembalikan sebagai pegangan perpustakaan DLL jika file target tidak ada atau alasan lain menyebabkan pemuatan DLL file gagal, 0 akan dikembalikan.
3. Membuat instance fungsi antarmuka
Fungsi API untuk mendapatkan penunjuk fungsi antarmuka adalah GetProcAddress (pegangan file perpustakaan, nama fungsi). Jika fungsi ditemukan, penunjuk fungsi akan dikembalikan. Jika gagal, NIL akan dikembalikan.
Tentukan variabel penunjuk fungsi menggunakan tipe fungsi yang ditentukan di atas, lalu gunakan operator @ untuk mendapatkan alamat fungsi, sehingga Anda dapat menggunakan variabel penunjuk untuk mengakses fungsi tersebut. Kode utamanya adalah sebagai berikut:
…
var
ShowDLLForm: TShowDLLForm; //contoh fungsi antarmuka DLL
Formulir DLL Gratis: TFreeDLLForm;
mulai
mencoba
mulai
APlugin.ProcAddr := LoadLibrary(PChar(sPath));
APlugin.FuncFreeAddr := GetProcAddress(APlugin.ProcAddr,'FreeDLLForm');
APlugin.FuncAddr := GetProcAddress(APlugin.ProcAddr ,'ShowDLLForm');
@ShowDLLForm:=APlugin.FuncAddr;
@FreeDLLForm:=APlugin.FuncFreeAddr;
jika ShowDllForm(Self.Handle, APlugin.Caption, APlugin.UserID) maka
Hasil:=Benar
…
4. Metode pelaksanaan yang spesifik
Untuk mengelola plug-in secara terstruktur dan memfasilitasi perluasan sistem di masa depan, kita dapat menggabungkan informasi DLL yang tersedia yang tercatat dalam database, dan kemudian secara dinamis mengakses program DLL dengan menanyakan catatan database.
1) Desain tabel modul sistem
Untuk sistem MIS, Anda dapat menggunakan kondisi DBS yang ada untuk membuat tabel modul sistem untuk mencatat file DLL dan informasi terkait yang dipetakan ke modul sistem.
Jenis peran nama bidang
Indeks AutoIDINT
modul modAlias alias VARCHAR
nama modul modName VARCHAR
modWndClass membentuk pengidentifikasi unik VARCHAR
modFile jalur DLL VARCHAR
modMemo catatan TEKS
・Alias modul digunakan untuk menyatukan aturan penamaan selama fase desain pemrograman, terutama untuk referensi anggota tim selama pengembangan tim.
・Nama modul akan diteruskan sebagai parameter ACAPTION ke fungsi SHOWDLLFORM sebagai judul jendela DLL.
・Pengidentifikasi unik formulir adalah NAMA KELAS jendela utama di submodul DLL, yang digunakan untuk menentukan jendela yang akan dikontrol saat runtime.
・Jalur DLL menyimpan nama file DLL, yang akan diubah menjadi jalur absolut dalam program.
2) Struktur data informasi plug-in
Mendefinisikan antarmuka data yang mencatat informasi terkait plug-in dapat mengontrol plug-in DLL secara terpusat. Tambahkan kode berikut ke bagian Antarmuka:
jenis
//Tentukan kelas informasi plug-in
TMyPlugins = kelas
Keterangan:String; //Judul formulir DLL
NamaFile Dll:String; //jalur berkas DLL
WndClass:String; //Identifikasi formulir
ID Pengguna:string; //Nama Pengguna
ProcAddr:THandle; //Pegangan perpustakaan dimuat oleh LOADLIBRARY
FuncAddr:Penunjuk; //TAMPILKANFORM penunjuk fungsi
FuncFreeAddr:Penunjuk; //Penunjuk fungsi FREEEDLLFORM
akhir;
…
Buat sebuah instance TMyPlugins untuk setiap plug-in. Metode inisialisasi untuk instance ini akan dibahas di bawah.
3) Fungsi pemuatan plug-in
Dalam contoh ini, jendela DLL dimuat dan ditampilkan jika terjadi peristiwa yang memicu pembukaan jendela anak di HALL. Setelah peristiwa tombol dipicu, pertama-tama tentukan apakah DLL telah dimuat sesuai dengan contoh struktur plug-in. Jika telah dimuat, kendalikan tampilan atau penutupan jendela jika tidak dimuat, akses tabel data dan tetapkan bidang ke struktur plug-in, lalu jalankan pemuatan.
Kode parsialnya adalah sebagai berikut
…
//--------------------------
//Nama: OpenPlugin
//Fungsi: Proses kontrol informasi plug-in: Inisialisasi==》Setel izin==》Muat jendela DLL
//Para: APlugin-TMyPlugins; sAlias alias;
//Rtrn: T/A
//Otentikasi: CST
//Tanggal: 2-6-2005
//--------------------------
procedure TFormHall.OpenPlugin(AFromActn: TAction ;APlugin:TMyPlugins; sAlias:string; sUserID:string);
var hWndPlugin:HWnd;
mulai
//Tentukan apakah jendela plug-in telah dimuat hWndPlugin:=FindWindow(PChar(APlugin.WndClass),nil);
jika hWndPlugin <> 0 maka //Jendela plug-in telah dimuat
mulai
jika bukan IsWindowVisible(hWndPlugin) maka
mulai
AFromActn.Diperiksa := Benar;
ShowWindow(hWndPlugin,SW_SHOWDEFAULT); //Tampilan
akhir
kalau tidak
mulai
AFromActn.diperiksa := Salah;
ShowWindow(hWndPlugin,SW_HIDE);
akhir;
Keluar; //Tinggalkan proses pembuatan plugin
akhir;
//Inisialisasi instance kelas plug-in
jika tidak InitializeMyPlugins(APlugin,sAlias) maka
mulai
showmessage('Kesalahan menginisialisasi kelas plug-in.');
KELUAR;
akhir;
//Dapatkan nilai izin saat ini
APlugin.UserID := sUserID;
//Muat jendela DLL
jika bukan LoadShowPluginForm(APlugin) maka
mulai
showmessage('Kesalahan saat memuat plugin pusat.');
KELUAR;
akhir;
akhir;
//--------------------------
//Nama: InisialisasiPlugin Saya
// Fungsi: Inisialisasi instance MYPLUGIN (Caption | DllFileName | IsLoaded)
//Para: APlugin-TMyPlugins
//Rtrn: T/A
//Otentikasi: CST
//Tanggal: 2-6-2005
//--------------------------
fungsi TFormHall.InitializeMyPlugins(APlugin:TMyPlugins; sAlias:String):Boolean;
var
strSQL:string;
myDA:TMyDataAdapter;
mulai
Hasil:=Salah;
myDA:=TMyDataAdapter.Buat;
strSQL:='PILIH * DARI SystemModuleList WHERE modAlias='+QuotedStr(sAlias);
mencoba
myDA.RetrieveData(strSQL);
kecuali
di E: Pengecualian lakukan
mulai
hasil:=salah;
myDA.Gratis;
KELUAR;
akhir;
akhir;
mencoba
mulai
dengan myDA.MyDataSet lakukan
mulai
jika Bukan Kosong maka
mulai
APlugin.Caption:= FieldByName('modName').Nilai;
APlugin.DllFileName := FieldByName('modFile').Nilai;
APlugin.WndClass := FieldByName('modWndClass').Nilai;
hasil:=Benar;
akhir;
Menutup;
akhir; //akhir dengan...lakukan...
akhir; //akhir percobaan
kecuali
di E: Pengecualian lakukan
mulai
Hasil:=Salah;
myDA.Gratis;
KELUAR;
akhir; //akhir pengecualian
akhir; //akhir percobaan...kecuali
myDA.Gratis;
akhir;
//--------------------------
//Nama: LoadShowPluginForm
// Fungsi: Memuat plug-in DLL dan menampilkan jendela
//Para: APlugin-TMyPlugins
//Rtrn: true berhasil dibuat
//Otentikasi: CST
//Tanggal: 2-6-2005
//--------------------------
fungsi TFormHall.LoadShowPluginForm (const APlugin:TMyPlugins):boolean;
var
ShowDLLForm: TShowDLLForm; //contoh fungsi antarmuka DLL
Formulir DLL Gratis: TFreeDLLForm;
sPath:string; //Jalur lengkap file DLL
mulai
mencoba
mulai
sPath:=ExtractFilepath(Application.ExeName)+ 'plugins/' + APlugin.DllFileName;
APlugin.ProcAddr := LoadLibrary(PChar(sPath));
APlugin.FuncFreeAddr := GetProcAddress(APlugin.ProcAddr,'FreeDLLForm');
APlugin.FuncAddr := GetProcAddress(APlugin.ProcAddr ,'ShowDLLForm');
@ShowDLLForm:=APlugin.FuncAddr;
@FreeDLLForm:=APlugin.FuncFreeAddr;
jika ShowDllForm(Self.Handle, APlugin.Caption, APlugin.UserID) maka
Hasil:=Benar
kalau tidak
Hasil:=Salah;
akhir;
kecuali
di E: Pengecualian lakukan
mulai
Hasil:=Salah;
ShowMessage('Kesalahan saat memuat modul plug-in, harap periksa apakah file di direktori PLUGINS sudah lengkap.');
akhir;
akhir;
akhir;
…
4) Kontrol jendela DLL
Seperti yang diilustrasikan oleh kode di 3), pembukaan dan penutupan jendela DLL hanya pada lapisan presentasi. Menutup jendela tidak benar-benar melepaskan jendela DLL. Ini hanya memanggil fungsi API FindWindow untuk mendapatkan pegangan formulir sesuai dengan jendela pengidentifikasi (yaitu, Form.name). Gunakan Parameter nCmdShow dari fungsi SHOWWINDOW mengontrol tampilan/penyembunyian jendela.
Sebenarnya ini adalah titik lemah dalam implementasi program saya. Jika metode Self.close digunakan di jendela DLL, itu akan menyebabkan kesalahan memori pilihan terakhir. Oleh karena itu, tombol tutup jendela utama setiap program DLL harus disembunyikan. :-P
5) Rilis perpustakaan DLL
Ketika program keluar, perpustakaan DLL harus dirilis satu per satu sesuai dengan contoh informasi plug-in. Fungsi untuk melepaskan perpustakaan DLL adalah sebagai berikut:
prosedur TFormHall.ClosePlugin(aPLG:TMyPlugins);
var
Formulir DLL Gratis: Formulir DLL Gratis;
mulai
jika aPLG.ProcAddr = 0 maka keluar;
jika aPLG.FuncFreeAddr = nihil lalu keluar;
@FreeDLLForm:=aPLG.FuncFreeAddr;
jika bukan FreeDLLForm(Application.Handle,'','') maka
showMessage('err');
akhir;
ringkasan
Efek yang dijalankan dari program contoh ini adalah sebagai berikut:
=550) window.open('/upload/20080315181507979.jpg');" src="http://files.VeVB.COM/upload/20080315181507979.jpg" onload="if(ini.lebar>'550')ini.lebar='550';if(ini.tinggi>'1000')ini.tinggi='1000';" perbatasan=0>
Di antara cara-cara di atas, karena masih banyak masalah yang belum terselesaikan karena keterbatasan kemampuan, saya telah mengadopsi beberapa cara menutup-nutupi yang tampaknya tidak masuk akal. Saya berharap semua orang dapat merancang solusi yang lebih baik setelah mencoba sedikit cara yang bagus untuk mempelajari lebih lanjut.