คำนำ
ในช่วงสองสามสัปดาห์ที่ผ่านมาของการทำงาน ฉันประสบปัญหาปวดหัว นั่นคือตัวควบคุม ActiveX ที่เขียนใน VB6 มีปัญหาแปลก ๆ มากมายในสภาพแวดล้อม Delphi หลังจากพลิกผันหลายครั้ง ในที่สุดฉันก็ค้นหาฟอรัมและข้อมูลเกือบทั้งหมด พบวิธีแก้ไขปัญหาที่เกิดขึ้นใน Delphi เวอร์ชันต่างๆ
หนึ่งในข้อยกเว้นร้ายแรงที่อธิบายไม่ได้ใน Delphi5
ก่อนอื่น เรามาดูพฤติกรรมแปลกๆ ของตัวควบคุม ActiveX ที่เขียนใน VB ภายใต้ Delphi5 กันก่อน
ตัวอย่างเช่น เราใช้ VB เพื่อเขียนการควบคุม UserTest (เพื่อความง่าย เราจะส่งออกเพียงคลาสเดียว การควบคุมผู้ใช้) คุณสมบัติ TestName และวิธี TestMethod จากนั้นคอมไพล์ลงในตัวควบคุม ActiveX ลงทะเบียนและนำเข้าในสภาพแวดล้อมการพัฒนา Delphi5 (หากมีสิ่งใดที่ไม่ชัดเจนเกี่ยวกับขั้นตอนข้างต้น โปรดตรวจสอบเอกสารอ้างอิงต่างๆ จะต้องมีคำตอบมาตรฐาน) จนถึงตอนนี้ทุกอย่างดูเหมือนจะเป็นปกติ
จากนั้นเราคุ้นเคยกับการลากและวางตัวควบคุมลงในแบบฟอร์ม ปรับขนาด และกำหนดค่าให้กับคุณสมบัติในหน้าต่างคุณสมบัติหรือเหมือนกันในโค้ด ซึ่งเป็นเรื่องปกติและใช้งานง่ายมาก อย่างไรก็ตาม ปัญหาเกิดขึ้น หากคุณเรียก TestMethod ด้วยความกระตือรือร้น คุณจะได้รับข้อยกเว้นแปลกๆ "OleError800a01a9" จากนั้นโปรแกรมจะออก น่าเสียดาย คุณจะไม่สามารถติดตามข้อยกเว้นนี้ได้ ใน VB แน่นอน ถ้าคุณเก่งเรื่องการประกอบ คุณสามารถทำตามหน้าต่างการแก้ไขข้อบกพร่องของ Delphi ทีละขั้นตอน...
เมื่อฉันพบปัญหานี้ครั้งแรก ฉันเกือบจะโกรธเพราะทั้ง Microsoft และ Borland ไม่มีคำอธิบายใด ๆ เกี่ยวกับข้อผิดพลาดหรือข้อมูลใด ๆ ที่ต้องค้นหา ฉันต้องไปที่ฟอรัมหลายแห่งที่ฉันแวะเวียนไป แน่นอนว่าฟอรัมที่สำคัญที่สุดคือ CSDN และค้นหาคำถามที่คล้ายกันในเวอร์ชัน VB และเวอร์ชัน Delphi น่าเสียดายที่มีเพียงคำถามที่คล้ายกันแต่ไม่มีคำตอบ ลูกค้ารายใหญ่ที่ใช้การพัฒนานี้ หลังจากทดสอบเครื่องมือการพัฒนาและสภาพแวดล้อมการพัฒนาเกือบทั้งหมดบน Windows (รวมถึงเดสก์ท็อปและเว็บ) ฉันลืม Delphi ไปได้เลย
ในช่วงสองวันที่เหลือ ฉันเกือบจะวิ่งไปทั่วโลก และถามว่าผู้เชี่ยวชาญของ Delphi รู้เกี่ยวกับสถานการณ์นี้หรือไม่ ในที่สุดฉันก็พบลิงก์จาก Google น่าเสียดาย ตอนนี้ฉันลืมตำแหน่งที่แน่นอนของลิงก์นั้นแล้ว แต่ฉันมีวิธีที่เกือบจะเป็นเวทย์มนตร์ (นั่นคือสิ่งที่ผู้ค้นพบเรียกมันว่า):
วิธีการปรับเปลี่ยนไลบรารีประเภทพร็อกซี XXX_TLB.PAS ด้วยตนเอง (โดยที่ XXX อ้างอิงถึงชื่อคลาสของตัวควบคุม) ที่สร้างโดย Delphi หลังจากการนำเข้าตัวควบคุม VBActiveX สามารถแก้ไขปัญหานี้ได้ ตัวอย่าง:
มีการควบคุม UserControl1 เขียนใน VB หลังจากนำเข้าใน Delphi แล้ว สองไฟล์จะถูกสร้างขึ้น หนึ่งในนั้น UserControl1_TLB.PAS คือไฟล์ที่เราต้องการแก้ไข
ค้นหาสิ่งนี้ในไฟล์
FintF:_UserControl1;
FunctionGetControlอินเทอร์เฟซ:_UserControl1;
และ
PROpertyControlInterface: _UserControl1readGetControlInterface;
รับการควบคุมอินเทอร์เฟซ;
เช่นเดียวกับ
ขั้นตอน TUserControl1.CreateControl;
ขั้นตอนการสร้าง;
เริ่ม
Finf:=IUnknown(OleObject)as_UserControl1;
จบ;
เริ่ม
IfFinf=nilthenDoCreate;
จบ;
ฟังก์ชั่นTUserControl1.GetControl1อินเทอร์เฟซ:_UserControl1;
เริ่ม
สร้างการควบคุม;
ผลลัพธ์:=ฟินเฟิล;
จบ;
โปรดทราบ: _UserControl1 ทั้งหมดที่ทำเครื่องหมายด้วยสีแดงที่นี่จะต้องถูกแทนที่ด้วย _UserControl1Disp หากการคอมไพล์ไม่สำเร็จ โปรดแทนที่ _UserControl1 ทั้งหมดที่รายงานในคำเตือนการคอมไพล์ด้วย _UserControl1Disp และคอมไพล์ด้วยวิธีนี้เมื่อเรียกวิธีการควบคุม ข้อผิดพลาดร้ายแรงข้างต้นจะไม่เกิดขึ้น เกิดขึ้น.
ขอบคุณสำหรับการค้นพบที่ยิ่งใหญ่นี้ ฉันสามารถอธิบายได้แบบนี้เท่านั้น ไม่เช่นนั้นฉันอาจจะยังคงติดอยู่ในวงกลมนี้ หรือฉันจะต้องใช้เครื่องมืออื่นเพื่อพัฒนาการควบคุมนี้ใหม่ (ฉันนึกภาพไม่ออกว่างานนี้จะขนาดไหน) และหรืออาจมีปัญหาความเข้ากันได้อื่นๆ)
Delphi5 ข้อยกเว้นร้ายแรงที่อธิบายไม่ได้ 2
อย่างไรก็ตาม Delphi ไม่ยอมปล่อยฉันไปหลังจากที่ฉันหลีกเลี่ยงข้อจำกัดนี้ ในไม่ช้า ลูกค้าก็ค้นพบปัญหาที่ยุ่งยากอีกประการหนึ่ง ในสภาพแวดล้อมการพัฒนา ข้อยกเว้นจะปรากฏขึ้นทุกครั้งที่ปิดแบบฟอร์มที่มีการควบคุมขณะเกิดข้อผิดพลาด แต่จะเป็นเช่นนั้น ไม่เกิดขึ้นในแอปพลิเคชันที่คอมไพล์แล้ว แม้ว่าจะไม่ส่งผลกระทบต่อการใช้งานของผู้ใช้ปลายทาง แต่ก็เป็นปัญหาใหญ่สำหรับนักพัฒนา จากนั้นฉันก็ลองใช้ตัวอย่างข้างต้นแล้วพบว่ามันไม่ได้เกิดขึ้น (ตอนนั้นฉันคลั่งไคล้มาก นี่อาจเกิดจากการใช้โค้ดบางอย่างที่เข้ากันไม่ได้ มันน่ากลัวอย่างยิ่งที่จะพบว่าโค้ดหลายหมื่นบรรทัดเป็นเรื่องปกติในหนึ่งวันหรือไม่) ด้วยความโมโห ฉันจึงบล็อก การควบคุมในการควบคุมของฉัน โค้ดทั้งหมด เหลือเพียงส่วนต่อประสานกับผู้ใช้เท่านั้น แล้วมีสิ่งแปลก ๆ เกิดขึ้น ฉันไม่ได้เขียนโค้ดใด ๆ แต่ ข้อผิดพลาดนี้ยังคงเกิดขึ้นเมื่อโหลดการควบคุมของฉัน ซึ่งทำให้ฉันมีความสุขและแปลกใจ สิ่งที่น่ายินดีก็คือปัญหานี้ไม่เกี่ยวข้องกับโค้ดของฉัน ดังนั้นการค้นหาจะง่ายกว่ามาก การลดมาตรฐานบางอย่างใน VB จริง ๆ แล้วการควบคุมสามารถทำให้เกิดข้อผิดพลาดที่น่ากลัวเช่นนั้นได้ ความขัดแย้งระหว่าง Delphi5 และ VB6 นั้นไม่ได้ลึกขนาดนั้น ในอีก 2 ชั่วโมงข้างหน้า ฉันยังคงลบการควบคุมบนอินเทอร์เฟซต่อไปเพื่อทดสอบว่าใครทำให้เกิดข้อยกเว้นร้ายแรงนี้
หลังจากผ่านไป 2 ชั่วโมง ฉันถอนหายใจด้วยความโล่งอกและพบปัญหาพื้นฐานคือ:
หากคุณใช้คอนเทนเนอร์คอนโทรล เช่น Frame และ PictureBox (ซึ่งสามารถมีคอนโทรลอื่นๆ อยู่ข้างใน) ในคอนโทรลผู้ใช้ VB คุณจะไม่สามารถเพิ่มคอนโทรล windowLess เช่น Label, Line และ Image ให้กับคอนโทรลเหล่านี้ได้ (นั่นคือ ไม่มีคอนโทรล Window, พวกมันถูกวาดโดย VB แบบเรียลไทม์ระหว่างรันไทม์) มิฉะนั้น คุณจะได้รับรายงานข้อผิดพลาดเหมือนที่กล่าวข้างต้น
ตัวควบคุม ActiveX ที่ซ่อนอยู่ใน Delphi6 และ 7
เนื่องจากประสบการณ์อันเลวร้ายภายใต้ Delphi5 ฉันจึงพบว่ายังคงจำเป็นต้องทดสอบว่าปัญหาเดียวกันนี้มีอยู่ใน Delphi6 และ 7 หรือไม่ (เวอร์ชันก่อนหน้านี้ไม่จำเป็นอีกต่อไปเนื่องจากมีผู้ใช้น้อยมาก และ Delphi8 ยังไม่ได้เปิดตัวอย่างเป็นทางการ ดังนั้น ไม่สามารถใช้ได้ในขณะนี้) ผลลัพธ์ก็คือ: ...ไม่ว่าฉันจะโหลดมันกี่ครั้ง ฉันก็ไม่เคยพบไอคอนเล็กๆ ที่รอคอยมานานบนแถบ ActiveX เลย ผลลัพธ์นี้ตลกมากจริงๆ ฉันไม่สามารถโหลดได้ ไม่ต้องพูดถึงว่าการทดสอบจะปกติหรือไม่
ในทำนองเดียวกัน ฉันค้นหาฟอรัมและเว็บไซต์ต่างๆ และพบว่ามีคนถามคำถามที่คล้ายกันใน CSDN มากขึ้น แต่คำตอบยังคงเป็นศูนย์ ด้วยความสิ้นหวัง ฉันจึงต้องปรับตัวเลือกใน Delphi6 และ 7...
หลังจากผ่านไป 3 ชั่วโมง 15 นาที 54 วินาที ฉันพบสาเหตุหรือวิธีแก้ปัญหาของปัญหาเวรนี้ (โปรดยกโทษให้ฉันที่เรียกแบบนั้น ฉันทนไม่ได้) ซึ่งจริงๆ แล้วง่ายมาก
ตอนนี้โปรดติดตามฉัน: คลิกเมนู Tools->EnvironmentOptions->TypeLibrary เราควรค้นหารายการ: IgnorespecialCoClassFlagsWhenImporting เลือกรายการนั้น จากนั้นเลือกรายการ CanCreate ดังนั้นตอนนี้เรามาลองนำเข้าตัวควบคุม ActiveX ที่แย่นั้น (ควรจะเป็น โปรดทราบว่าหากคุณนำเข้าครั้งเดียว โปรดลบไฟล์ที่สร้างขึ้นสองไฟล์ ได้แก่ ไฟล์ .dcr และ .pas ไม่เช่นนั้นไฟล์จะไม่รีเฟรช) ถ้าคราวนี้ยังหา control ในคอลัมน์ ActiveX ไม่เจอ ก็ต้องโทรไป Microsoft หรือ Borland แล้วถามว่าจะแต่งงานได้เมื่อไหร่ 555!
(นอกจากนี้ ไม่พบข้อผิดพลาดข้างต้นที่ปรากฏใน Delphi5 ใน Delphi6 และ 7)
สภาพแวดล้อมการทดสอบของฉันคือ:
Win2K
Delphi5อัปเดต1
Delphi6Update2
เดลฟี7