คุณเคยใช้ Adobe Photoshop หรือไม่? สำหรับฆราวาสปลั๊กอินเป็นเพียงบล็อกรหัสที่ให้กับแอปพลิเคชันจากภายนอก (ตัวอย่างเช่นใน DLL) ความแตกต่างระหว่างปลั๊กอินและ DLL ปกติคือปลั๊กอินมีความสามารถในการขยายการทำงานของแอปพลิเคชันหลัก ตัวอย่างเช่น Photoshop เองไม่มีฟังก์ชั่นการประมวลผลภาพจำนวนมาก การเพิ่มปลั๊กอินให้เอฟเฟกต์ที่ยอดเยี่ยมเช่นเบลอจุดและสไตล์อื่น ๆ ทั้งหมดและไม่มีแอปพลิเคชันหลัก
นี่เป็นสิ่งที่ดีมากสำหรับโปรแกรมการประมวลผลภาพ แต่ทำไมคุณต้องใช้ความพยายามอย่างมากในการกรอกแอพพลิเคชั่นเชิงพาณิชย์ที่รองรับปลั๊กอิน สมมติว่าให้ตัวอย่างแอปพลิเคชันของคุณจะสร้างรายงานบางอย่าง ลูกค้าของคุณจะขออัปเดตหรือเพิ่มรายงานใหม่อย่างแน่นอน คุณสามารถใช้เครื่องกำเนิดรายงานภายนอกเช่นรายงาน Smith ซึ่งเป็นโซลูชันที่ไม่เหมือนกันมากต้องมีการเผยแพร่ไฟล์เพิ่มเติมการฝึกอบรมเพิ่มเติมสำหรับผู้ใช้และอื่น ๆ นอกจากนี้คุณยังสามารถใช้ QuickReport ได้ แต่สิ่งนี้จะทำให้คุณอยู่ใน Nightmare ควบคุมเวอร์ชัน - หากคุณต้องการสร้างแอปพลิเคชันของคุณใหม่ทุกครั้งที่คุณเปลี่ยนแบบอักษร
อย่างไรก็ตามตราบใดที่คุณทำรายงานลงในปลั๊กอินคุณสามารถใช้งานได้ ต้องการรายงานใหม่หรือไม่? ไม่มีปัญหาเพียงแค่ติดตั้ง DLL แล้วคุณจะเห็นในครั้งต่อไปที่แอปพลิเคชันจะเริ่ม อีกตัวอย่างหนึ่งคือแอปพลิเคชันที่ประมวลผลข้อมูลจากอุปกรณ์ภายนอก (เช่นสแกนเนอร์บาร์โค้ด) โดยการเขียนรูทีนการประมวลผลส่วนต่อประสานของอุปกรณ์แต่ละตัวเป็นปลั๊กอินคุณสามารถบรรลุความสามารถในการปรับขนาดสูงสุดโดยไม่ต้องทำการเปลี่ยนแปลงใด ๆ กับแอปพลิเคชันหลัก
เริ่มต้น
สิ่งที่สำคัญที่สุดก่อนที่คุณจะเริ่มเขียนโค้ดคือการหาคุณสมบัติที่แอปพลิเคชันของคุณต้องการขยาย นี่เป็นเพราะปลั๊กอินโต้ตอบกับแอปพลิเคชันหลักผ่านอินเทอร์เฟซเฉพาะซึ่งจะถูกกำหนดตามความต้องการของคุณ ในบทความนี้เราจะสร้างปลั๊กอิน 3 ตัวเพื่อแสดงหลายวิธีที่ปลั๊กอินโต้ตอบกับแอปพลิเคชันหลัก
เราจะทำให้ปลั๊กอินเป็น DLL ก่อนที่จะทำสิ่งนี้เราต้องทำเชลล์เพื่อโหลดและทดสอบพวกเขา รูปที่ 1 แสดงโปรแกรมทดสอบหลังจากโหลดปลั๊กอินครั้งแรก ปลั๊กอินแรกไม่ได้ทำอะไรที่ยิ่งใหญ่และในความเป็นจริงสิ่งที่มันทำคือส่งคืนสตริงที่อธิบายตัวเอง อย่างไรก็ตามมันยืนยันจุดสำคัญ-มันจะทำงานได้อย่างถูกต้องโดยมีหรือไม่มีแอปพลิเคชันปลั๊กอิน หากไม่มีปลั๊กอินมันจะไม่ปรากฏในรายการปลั๊กอินที่ติดตั้ง แต่แอปพลิเคชันยังสามารถทำงานได้ตามปกติ
ความแตกต่างเพียงอย่างเดียวระหว่างเชลล์ปลั๊กอินของเราและแอปพลิเคชันปกติคือหน่วย Sharemem ในไฟล์แหล่งที่มาโครงการที่ปรากฏในประโยคการใช้งานและรหัสที่โหลดไฟล์ปลั๊กอิน แอปพลิเคชั่นใด ๆ ที่ผ่านพารามิเตอร์สตริงระหว่างตัวเองและ DLL ลูก? ในการทดสอบเชลล์นี้คุณจะต้องคัดลอกไฟล์ delphimm.dll จากไดเรกทอรี Delphi/bin ไปยังเส้นทางที่มีอยู่ในตัวแปรสภาพแวดล้อมเส้นทางหรือไดเรกทอรีที่แอปพลิเคชันอยู่ ไฟล์จะต้องแจกจ่ายในเวลาเดียวกันเมื่อรุ่นสุดท้ายถูกปล่อยออกมา
ปลั๊กอินถูกโหลดลงในเปลือกทดสอบนี้ผ่านกระบวนการ loadplugins ซึ่งเรียกว่าในเหตุการณ์ formcreate ในหน้าต่างหลักดูรูปที่ 2 กระบวนการนี้ใช้ฟังก์ชั่น FindFirst และ FindNext เพื่อค้นหาไฟล์ปลั๊กอินในไดเรกทอรีที่แอปพลิเคชันอยู่ หลังจากค้นหาไฟล์ให้ใช้กระบวนการ loadplugins ที่แสดงในรูปที่ 3 เพื่อโหลด
{ค้นหาไฟล์ปลั๊กอินในไดเรกทอรีแอปพลิเคชัน}
ขั้นตอน tfrmmain.loadplugins;
วาจา
SR: TsearchRec;
เส้นทาง: สตริง;
พบ: จำนวนเต็ม;
เริ่ม
PATH: = ExtractFilePath (Application.exename);
พยายาม
พบ: = findfirst (เส้นทาง + cplugin_mask, 0, sr);
ในขณะที่พบ = 0 เริ่มต้น
loadplugin (SR);
พบ: = findNext (SR);
จบ;
ในที่สุด
FindClose (SR);
จบ;
จบ;
{โหลดปลั๊กอินที่ระบุ
โพรซีเดอร์ tfrmmain.loadplugin (SR: TSEARCHREC);
วาจา
คำอธิบาย: สตริง;
libhandle: จำนวนเต็ม;
DesternEproc: tplugindescribe;
เริ่ม
libhandle: = loadlibrary (pchar (sr.name));
ถ้า libhandle $#@60; $#@62;
เริ่ม
DesternEproc: = getProcaddress (libhandle, cplugin_describe);
หากได้รับมอบหมาย (อธิบาย ณ
DescriptionProc (คำอธิบาย);
memplugins.lines.add (คำอธิบาย);
จบ
อื่น
เริ่ม
messagedlg ('ไฟล์ "' + sr.name + '" ไม่ใช่ปลั๊กอินที่ถูกต้อง'
mtinformation, [mbok], 0);
จบ;
จบ
อื่น
Messagedlg ('เกิดข้อผิดพลาดในการโหลดปลั๊กอิน "' +
sr.name + '".', mterror, [mbok], 0);
จบ;
วิธีการ loadplugin แสดงให้เห็นถึงแกนกลางของกลไกปลั๊กอิน ก่อนอื่นปลั๊กอินถูกเขียนเป็น DLL ประการที่สองมันถูกโหลดแบบไดนามิกผ่าน LoadLibrary API เมื่อโหลด DLL แล้วเราต้องการวิธีการเข้าถึงขั้นตอนและฟังก์ชั่นที่มีอยู่ API เรียก GetProcaddress ให้กลไกนี้ซึ่งส่งคืนตัวชี้ไปยังรูทีนที่ต้องการ ในการสาธิตอย่างง่ายของเราปลั๊กอินมีเพียงขั้นตอนที่เรียกว่า desctionplugin ซึ่งระบุโดย cplugin_describe คงที่ (กรณีของชื่อขั้นตอนมีความสำคัญมากและชื่อที่ส่งไปยัง getProcaddress จะต้องเหมือนกันกับชื่อรูทีนที่รวมอยู่ใน DLL) . หากไม่พบรูทีนที่ร้องขอใน DLL GetProcaddree จะส่งคืน NIL ดังนั้นคุณจะตกลงที่จะใช้ฟังก์ชั่นที่ได้รับมอบหมายเพื่อกำหนดค่าการส่งคืน
ในการจัดเก็บพอยน์เตอร์ไปยังฟังก์ชั่นในวิธีที่ใช้งานง่ายจำเป็นต้องสร้างประเภทเฉพาะสำหรับตัวแปรที่ใช้ โปรดทราบว่าค่าการส่งคืนของ getProcaddress ถูกเก็บไว้ในตัวแปรอธิบายว่าเป็นของประเภท tplugindescribe นี่คือคำสั่งของมัน:
พิมพ์
tplugindescribe = ขั้นตอน (var desc: string);
เนื่องจากขั้นตอนมีอยู่ภายใน DLL จึงรวบรวมกิจวัตรการส่งออกทั้งหมดผ่านการแปลงการโทรมาตรฐานดังนั้นจึงจำเป็นต้องมีตัวบ่งชี้ STDCALL กระบวนการนี้ใช้พารามิเตอร์ VAR ซึ่งมีคำอธิบายปลั๊กอินเมื่อกระบวนการส่งคืน
ในการเรียกกระบวนการที่คุณเพิ่งได้รับเพียงใช้ตัวแปรที่บันทึกที่อยู่เป็นชื่อกระบวนการตามด้วยพารามิเตอร์ใด ๆ ในกรณีของเราคำสั่ง:
DescriptionProc (คำอธิบาย)
กระบวนการคำอธิบายที่ได้รับในปลั๊กอินจะถูกเรียกและตัวแปรคำอธิบายจะถูกเติมด้วยสตริงที่อธิบายฟังก์ชั่นของปลั๊กอิน
ปลั๊กอินก่อสร้าง
เราได้สร้างแอปพลิเคชันหลักและถึงเวลาสร้างปลั๊กอินที่เราต้องการโหลด ไฟล์ปลั๊กอินเป็น Delphi DLL มาตรฐานดังนั้นเราจึงสร้างโครงการ DLL ใหม่จาก Delphi IDE และบันทึก เนื่องจากฟังก์ชั่นปลั๊กอินที่ส่งออกจะใช้พารามิเตอร์สตริงหน่วย Sharemen ควรวางไว้ก่อนในประโยคการใช้งานของโครงการ รูปที่ 4 แสดงรายการไฟล์แหล่งที่มาของปลั๊กอินอย่างง่ายของเรา
ใช้
Sharemem, sysutils, ชั้นเรียน,
หลักใน 'main.pas';
{$ e plg.}
การส่งออก
อธิบายถึง
เริ่ม
จบ.
แม้ว่าปลั๊กอินเป็นไฟล์ DLL แต่ก็ไม่จำเป็นต้องให้ส่วนขยาย. dll ในความเป็นจริงเหตุผลหนึ่งก็เพียงพอที่จะให้เหตุผลแก่เราในการเปลี่ยนส่วนขยาย: เมื่อแอปพลิเคชันหลักมองหาไฟล์ที่จะโหลดส่วนขยายใหม่สามารถทำหน้าที่เป็นหน้ากากไฟล์เฉพาะ ด้วยการใช้ส่วนขยายอื่น (ตัวอย่างของเราใช้ *.plg) คุณสามารถมั่นใจได้ว่าแอปพลิเคชันจะโหลดไฟล์ที่เกี่ยวข้องเท่านั้น คอมไพล์ตัวบ่งชี้ $ x สามารถบรรลุการเปลี่ยนแปลงนี้หรือคุณสามารถตั้งค่าส่วนขยายผ่านหน้าแอปพลิเคชันของกล่องโต้ตอบตัวเลือกโครงการ
รหัสสำหรับปลั๊กอินตัวอย่างแรกนั้นง่ายมาก รูปที่ 5 แสดงรหัสที่มีอยู่ในหน่วยใหม่ โปรดทราบว่าต้นแบบ desplicplugin นั้นสอดคล้องกับประเภท tplugindescribe ในแอปพลิเคชันเชลล์และใช้คำที่สงวนไว้ในการส่งออกเพิ่มเติมเพื่อระบุว่ากระบวนการจะถูกส่งออก ชื่อกระบวนการที่ส่งออกจะปรากฏในส่วนการส่งออกของซอร์สโค้ดโครงการหลัก (แสดงในรูปที่ 4)
หน่วยหลัก;
ส่วนต่อประสาน
โพรซีเดอร์อธิบาย PLUGIN (VAR DESC: String);
การส่งออก;
การดำเนินการ
โพรซีเดอร์อธิบาย PLUGIN (VAR DESC: String);
เริ่ม
desc: = 'ทดสอบปลั๊กอิน v1.00';
จบ;
จบ.
ก่อนทดสอบปลั๊กอินนี้ให้คัดลอกไปยังเส้นทางของแอปพลิเคชันหลัก วิธีที่ง่ายที่สุดคือการสร้างปลั๊กอินในไดเรกทอรีย่อยของไดเรกทอรีที่บ้านจากนั้นตั้งค่าเส้นทางเอาต์พุตไปยังเส้นทางหลัก (ไดเรกทอรี/เงื่อนไขของกล่องโต้ตอบตัวเลือกโครงการสามารถใช้สำหรับการตั้งค่านี้)
การดีบัก
ตอนนี้ให้ฉันแนะนำคุณสมบัติที่ดีกว่าใน Delphi 3: ความสามารถในการดีบัก DLLs จาก IDE ในโครงการ DLL คุณสามารถระบุโปรแกรมเป็นแอปพลิเคชันโฮสต์ผ่านกล่องโต้ตอบ Run Paramates จากนั้นคุณสามารถตั้งค่าเบรกพอยต์ในรหัส DLL ของคุณและกด F9 เพื่อเรียกใช้ - เหมือนกับที่คุณทำในแอปพลิเคชันปกติ Delphi จะเรียกใช้โปรแกรมโฮสต์ที่ระบุและโดยการรวบรวม DLL ด้วยข้อมูลการดีบักนำคุณไปยังจุดพักในรหัส DLL