المؤلف: زو فاي
البريد الإلكتروني: [email protected]
الصفحة الرئيسية: http://www.atechsoft.com/people/zouf/ أثناء استخدام دلفي، ستواجه حتمًا العديد من المشكلات الغريبة، كما أن توثيق دلفي قليل أيضًا بشكل مدهش، لذا لا يمكنني تلخيصه إلا ببطء بنفسي ، إذن هناك (نظرًا لأنها مجرد تفاصيل متناثرة، لم أبذل الكثير من الجهد في كتابتها، فقد تكون فوضوية بعض الشيء، ولكن يجب أن تكون مفهومة؛-)). إذا: 1. إذا كان لديك حل أفضل للمشكلة التالية، فيرجى إخباري وأصدقائي على csdn 2. إذا كانت لديك أسئلة أخرى، فيرجى إدراج المشكلات وإجاباتك وإخباري أنا وأصدقائي على csdn. التواصل يخلق كل شيء!
النص: س: إذا كان النموذج الذي تم إنشاؤه في Delphi DLL هو ShowModal في Exe، فسوف يظهر أيقونتان على شريط المهام، لماذا؟ كيفية حل هذه المشكلة؟ ج: ما يلي هو أسلوب نموذجي لوضع نموذج في ملف DLL: DLL: function ShowFrm: TModalResult; وظيفة ShowFrm: TModalResult؛ stdcall؛ 'TestDLL.dll';...begin...ShowFrm;...end. النموذج الموجود في DLL الذي تم إنشاؤه بهذه الطريقة سيعرض رمزًا آخر مع التطبيق الرئيسي والسبب هو أنه سيتم إنشاء تطبيق آخر لـ DLL في دلفي سيعرض التطبيق أيقونة شريط المهام. الحل: قم بتمرير تطبيق EXE الرئيسي إلى ملف DLL في التطبيق الرئيسي، كما يلي: DLL: function ShowFrm(app: TApplication): TModalResult; = TForm1.Create(Nil);tryForm1.ShowModal;finallyForm1.Free;end;Application := oldApp;end;Main EXE: الوظيفة ShowFrm(app: TApplication): TModalResult; stdcall; خارجي 'TestDLL.dll';...begin...ShowFrm(Application);...end ملاحظة: التطبيق في DLL والتطبيق في EXE موجودان لا تزال هناك بعض الاختلافات، انظر إلى الكود في Forms.pas: المُنشئ TApplication.Create(AOwner: TComponent);begin...إذا لم يكن IsLibrary ثم CreateHandle;...end;يمكن معرفة أن التطبيق في DLL لا يحتوي على مقبض، لذلك لن يتم تنفيذ معالجة حلقة الرسالة، وهو صحيح أيضًا. س: غالبًا ما تحدث مشكلات مع ملفات DLL في دلفي! ج: سبب حدوث المشكلة هو آلية إدارة الذاكرة الخاصة بشركة دلفي. على سبيل المثال: قم بإنشاء كائن في ملف DLL: x := TClass.Create(Application); في هذا الوقت، ستقوم دلفي تلقائيًا بتحرير مساحة العنوان (ستكون أنظمة التشغيل المختلفة مختلفة)، لذا سيتم تنفيذ عملية تحرير x يسبب استثناء. مثال آخر: قم بإنشاء كائن في EXE، وقم بتمرير DLL كمتغير محلي في DLL عندما يتم تدمير DLL، ستقوم دلفي تلقائيًا بتحرير كافة المتغيرات التي تقع خارج النطاق، لذلك إذا استخدمت هذا في كائن EXE مرة أخرى، فسيتم حذفه. سيتم طرح الاستثناء. بشكل عام، ترجع المشكلة إلى آلية إدارة الذاكرة لمترجم دلفي "الذكي" وآلية إضافة/إلغاء تحميل DLL لنظام Windows، مما يؤدي إلى تعارض الوصول إلى الذاكرة في DLL وEXE. الحل: (معظم المشاكل يمكن تجنبها بشرط اتباع المبادئ التالية) 1. بين DLL وEXE، حاول عدم استخدام آلية إدارة الذاكرة التلقائية في دلفي، فالمبرمج مسؤول عن دورة حياة الكائن على سبيل المثال: بالنسبة إلى x := TClass.Create(Application); TClass.Create(nil); بهذه الطريقة، لن يقوم التطبيق بتحريره بعد الآن. وبطبيعة الحال، يجب على المبرمج أن يحررها بنفسه. 2. حاول تجنب وجود مؤشرات مختلفة تشير إلى نفس الكائن بين ملف DLL وملف EXE. على سبيل المثال، في DLL، يشير x إلى كائن TClass، وفي EXE، يشير y إلى كائن TClass. وبهذه الطريقة، سيؤدي تحرير الذاكرة على أي من الجانبين إلى جعل الذاكرة الموجودة على الجانب الآخر غير صالحة. 3. أخرى... س: يحتاج الخيط الذي يقوم بمهام دورية إلى التوقف مؤقتًا للحظة ثم متابعة التشغيل، ولكن ماذا لو كان الخيط بحاجة إلى التوقف في هذا الوقت (على سبيل المثال، انتهت العملية)؟ ج: الحل 1: إجراء حلقات دورية خلال وضع السكون في سلسلة المحادثات. (إذا تم إيقاف الخيط مؤقتًا خلال وضع السكون، فلا يمكن إحياء الخيط من خلال الاستئناف والطرق الأخرى.) قم بإنهاء الخيط من خلال KillThread. هذه هي الطريقة الأبسط، ولكنها بدائية للغاية وقد تسبب مشاكل (KillThread عبارة عن واجهة برمجة تطبيقات غير موصى بها لنظام التشغيل Windows) الحل 2: تعليق سلسلة الرسائل، وتمرير مؤقت خارج سلسلة المحادثات، واستئنافها من حين لآخر. الكود كما يلي: // ThreadPRocedure Execute;beginwhile not Terminated dobegin... // كود المعالجة Suspend;end;end;// خارج // إجراء المؤقت OnTimer(Sender: Tobject);beginthd.Resume;end;// لإنهاء الموضوع Place...thd.Resume;thd.Terminate;thd.WaitFor //; بشكل عام، بعد إنهاء الموضوع، يجب عليك استخدام WaitFor للتأكد من أن الموضوع قد انتهى بالفعل. ...المشكلة: الاقتران بين الخيط والخارج قوي جدًا، وحتى دورة تشغيل الخيط يجب تحديدها من خلال مؤقت خارجي. الحل الثالث (هذه هي أفضل طريقة فكرت بها): توقف مؤقتًا في الخيط من خلال الإشارة. // ThreadTMyThread = class(TThread) حدث خاص: TEvent; تنفيذ الإجراء المحمي; إنشاء المُنشئ العام (loginInfo: TLoginInfo); destructor override;end;{ TMyThread }constructor (loginInfo: TLoginInfo);بدء الحدث := TEvent.Create(nil, True, True, 'EventName');end;destructor TMyThread.Destroy;begin Event.Free;end;procedure TMyThread.Execute;begin inherited; end;end;procedure TMyThread.SetEvent;begin Event.SetEvent;end;بالنسبة للبرامج التي تحتاج إلى مقاطعة سلاسل الرسائل، يكفي التعليمة البرمجية التالية فقط: البدء …thd.Terminate;thd.SetEvent;thd.WaitFor;…end;