الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

مشكلة في استدعاء حدث من Dll

بدأه asrocks في 9 يوليو 2008 · 9 رد · 1,079 مشاهدة · في لغة Delphi
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

حاليا أنا أعمل برنامج مستخدماً DLL بحيث استدعي الإجراء الموجود في DLL من التطبيق و تنفيذه و الطريقة نجحت .

و لكن المشكلة هي عندما أكتب إجراء في ال DLL (حدث الضغط على زر الماوس مثلا هنا) هكذا :

library DLLProject;

uses

Windows,Messages,SysUtils,Variants,Classes,Graphics,Controls,Forms,Dialogs,jpeg,

ExtCtrls,StdCtrls;

{$R *.res}

procedure mDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);

begin

showmessage('You clicked on the Form :at'+inttostr(x)+':'+inttostr(y));

end;

exports

mDown;

begin

end.

و من ثم عندما استدعي هذا الحدث (الإجراء) من تطبيقي و أطبقه على الفورم على هذا الشكل :

implementation

procedure mDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); stdcall external 'DLLProject.dll';

{$R *.dfm}

/////-----------

procedure TForm1.Button1Click(Sender: TObject);

begin

form1.OnMouseDown:=mDown;

end;

لا ينفذ و يظهر لي خطأ في عملية الإستدعاء في "Calling Convertions differ"

و أتمنى من الأخوة هنا إيجاد الحل و شكراً

#2

السلام عليكم...

هذه الرسالة تظهر عندما يكون هناك فرق في مصطلح أو أسلوب الاستدعاء (Calling convention) بين تعريف الإجراء (أو الدالة) داخل الـ DLL و تعريف الإجراء (أو الدالة) في التطبيق المستدعي (الذي يستخدم فيه الإجراء أو الدالة).

و للفائدة فإن أساليب الاستدعاء في دلفي هي: register, pascal, cdecl, stdcall, safecall، كما في الجدول التالي:

أساليب الاستدعاء
الأسلوبترتيب تمرير البارامتراتالتخلص من البارامتراتتمرير البارامترات في المسجلات
register (الافتراضي)من اليسار إلى اليمينالإجراءنعم
pascalمن اليسار إلى اليمينالإجراءلا
cdeclمن اليمين إلى اليسارالبرنامج المستدعيلا
stdcallمن اليمين إلى اليسارالإجراءلا
safecallمن اليمين إلى اليسارالإجراءلا

و إذا لم تحدد في تعريف الإجراء أو الدالة نوع أسلوب الاستدعاء فإن الأسلوب الافتراضي هو register.

وحسب الكود الموجود في المشاركة رقم 1 للأخ asrocks فإن تعريف الإجراء في التطبيق يستخدم أسلوب stdcall بينما تعريف الإجراء في الـ DLL فلا يحتوي على محدد الأسلوب، و بالتالي فهو يستخدم أسلوب register.

و بالمناسبة فإن الأسلوب register هو أكثر تلك الأساليب فعالية لأنه يتجنب إنشاء إطار ضمن المكدس (Stack frame) و يستعمل حتى 3 مسجلات (Registers) من مسجلات المعالج المركزي، أما الأساليب الأخرى فإنها تمرر البارامترات عبر المكدس (Stack).

ملاحظة مهمة: إذا كنا ننوي استعمال الـ DLL مع لغات برمجة أخرى فإنه يفضل لستعمال الأسلوب stdcall لأن بعض اللغات الأخرى قد لا تدعم استعمال المسجلات (كما هو الحال في Visual Basic).

أما بالنسبة إلى حل مشكلة الكود السابق: فإما أن نضيف الموجه stdcall إلى تعريف الإجراء في الـ DLL أو نحذف الموجه stdcall من تعريف الإجراء في التطبيق المستدعي:

  1.  
  2. // In DLL:
  3. procedure mDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); stdcall;
  4. // In Application:
  5. procedure mDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); stdcall; external 'DLLProject.dll';
  6.  

== أو ==

  1. // In DLL:
  2. procedure mDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer);
  3. // In Application:
  4. procedure mDown(Sender: TObject; Button: TMouseButton;Shift: TShiftState; X, Y: Integer); exter
    nal 'DLLProject.dll';
  5.  

نرجو الاستفادة و السلام.

وَ قُلِ اعْمَلُوا فَسَيَرَى اللهُ عَمَلَكُمْ وَ رَسُولُهُ وَ الْمُؤْمِنُونَ

صدق الله العظيم

#3

شكرا اخ najy_zl على الرد المنسق, لمزيد من المعلومات حول DLL يمكنك ايضا الاطلاع على المشاركة التالية:

سلسلة بوليسية شيقة حول DLL, لا تتردد بالدخول, كل ما تريد معرفته حول ملفات DLL

رب اجعلني مقيم الصلاة ومن ذريتي ربنا وتقبل دعاء.

لا تنسى: "العقل مثل العضلة كلما استخدمته أكثر كلما ازدادت قوته"

#4

اخواني

أولاً الله يعطيكم العافية على هذه الردود

العملية نجحت على الشكل :

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

mDown(sender,button,shift,x,y);

end;

----------

بس المشكلة في عملية اسناد هذا الإجراء (mDown) إلى حدث MouseDown للـ Form1

Form1.OnMouseDown:=mDown

الخطأ يظهر في هذه العبارة

و شكراً مرة أخرى

#5

إخواني اذا ممكن المساعدة و لكم جزيل الشكر مرة اخرى

#6

السلام عليكم...

الأخ asrocks: لم تخبرنا إذا كنت قد قمت بتعديل الأكواد بحيث يتطابق التصريح عن الإجراء mDown في البرنامج مع تعريفه في الـ DLL.

الأمر الثاني: إذا كنت قد أنشأت إجراءً لمعالجة الحدث OnMouseDown في برنامجك:

procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

فلماذا تريد أن تسند إليه الإجراء الموجود في الـ Dll؟:

Form1.OnMouseDown := mDown;

نرجو التوضيح مع ذكر رسالة الخطأ

و السلام.

وَ قُلِ اعْمَلُوا فَسَيَرَى اللهُ عَمَلَكُمْ وَ رَسُولُهُ وَ الْمُؤْمِنُونَ

صدق الله العظيم

#7

أخي najy_zl اسلوب الأستدعاء عندي كان خاطىء بين DLL و application

و الحمد لله ظبطو و صار موافق بين الأثنين.

و فكرة البرنامج هي إنشار مجموعة عناصر Timage أثناء التنفيذ

و عند ضغط زر الماوس على كل image يتم تنفذ أمر معين يختلف عن الاّخر

و بالتالي سوف أنشأ الأحداث بنفسي و من ثم أسند كل حدث إلى(حدث image) الموافق له | و العملية نجحت بالكامل |.

و لكن أريد أن أجمع هذه الأحداث التي أنشأتها في ملف DLL و من ثم من التطبيق أستدعي كل حدث و أسنده إلى (حدث image) الموافق له

---------------------------

عملية الإستدعاء نجحت و لكن تكمن المشكلة في عملية الإسناد فقط

------------

أرفقت لك المشروع باستخدام حدث mDown على الفورم لترى المشكلة.

و مشكور كتير

Project.zip

#8

المرفق موجود في الاعلى و جاهز للتحميل

#9

السلام عليكم...

الأخ asrocks... المشكلة أنه هناك اختلاف بين نوعي الإجرائين رغم تطابقهما في نوع و عدد و ترتيب البارامترات. سبب الاختلاف أن الإجراء mDown الموجود في الـ DLL هو إجراء عادي (قياسي) بينما إجراء الحدث OnMouseDown يجب أن يكون إجراءً تابعاً لكائن، بمعنى أنه في الواقع منهج (Method) لكائن (Object). لترى الفرق اختر الحدث OnMouseDown في نافذة الخصائص (Object Inspector) ثم اضغط F1 لعرض التعليمات. ستجد أن تعريف الحدث OnMouseDown كالتالي:

  1. type TMouseEvent = procedure (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y:
    Integer) of object;
  2.  
  3. property OnMouseDown: TMouseEvent;
  4.  

لاحظ وجود عبارة of object في نهاية تعريف النوع TMouseEvent، ثم تعريف الخاصية OnMouseDown بأنها من النوع TMouseEvent، و ذلك يعني أن الإجراء المسند إلى هذه الخاصية يجب أن يكون تابعاً لكائن.

و رغم أنه يمكنك إنشاء أصناف (Classes) داخل الـ DLL و تكتب لها إجراءات (ستكون تلقائياً of object لأنها معرفة داخل Class) إلا أن هذا النوع من الإجراءات لا يمكن تصديره من الـ DLL لأنه يحتاج إلى مؤشرين (2 Pointers) أحدهما للكائن و الآخر للإجراء.

لقد بحثت خلال اليومين السابقين في الإنترنت عن طريقة لتصدير مثل تلك الإجراءات لكني لم أصل إلى نتيجة، رغم أن بعضهم يتحدث عن إمكانية تصدير الأصناف (Classes) و بالتالي ربما يمكن الوصول إلى الـ Methods الخاصة بها.

آسف على الإطالة و لكن أحببت أن أوضح المسألة. أعتقد أن الحل الأمثل هو استخدام الـ Run-time Packages التي هي أيضاً ملفات DLL و لكن بامتداد bpl مع بعض المواصفات الخاصة بدلفي. إذا استعملت الـ Packages فإنه يمكنك الوصول إلى الـ Classes و الـ Objects و الـ Methods.

نرجو الاستفادة و السلام.

وَ قُلِ اعْمَلُوا فَسَيَرَى اللهُ عَمَلَكُمْ وَ رَسُولُهُ وَ الْمُؤْمِنُونَ

صدق الله العظيم

#10

مشكور أخي على مجهودك و إن شاء الله اذا وجدت الحل سأكون أول من يضعه هنا

مواضيع مشابهة