المساعدة - البحث - قائمة الأعضاء - التقويم
نسخة كاملة: فكرة عن ال Subclassing
برمجة - شبكات - كمبيوتر - منتديات الفريق العربي للبرمجة > منتديات لغات البرمجة العام > منتدى مبرمجي لغة Microsoft Visual Basic 6 وما قبلها من إصدارات > قسم الدروس والمواضيع الهامة
AboSaker
فكرة عن ال Subclassing :
من خلال البحث و القراءة تمكنت من فهم الكثير عن ال Subclassing و أردت أن أفيد المنتدى بما تعلمته
رسائل ويندوز Windows Messages :
عند حدوث أي حدث (مثلا تحريك مؤشر الماوس ) فإن ويندوز يحدد النافذة التي وقع عليها الحدث إعتمادا على
خصائص النوافذ (مثلا المواقع و الأبعاد , التمكين , النوافذ المخفية , النافذة التي في المقدمة , ...إلخ) ومن ثم
يرسل الرسالة الى تلك النافذة . تتضمن أي رسالة المعلومات التالية :
hwnd مقبض النافذة الهدف
wMsg الرسالة (الحدث الذي وقع)
wParam, lParam وسيطان يعتمدان على الرسالة قد يكونا خاليان (كما في الحدث click ) أو أحدهما خالي
والأخر يحتوي على معلومات (الحدث MouseMove ) او كلاهما يحتويان معلومات.
وهذا يذكرنا بنحو التابع SendMessage :
Public Declare Function SendMessage Lib "user32" Alias "SendMessageA"
(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
إجراء النافذة الإفتراضي Windows Default Procedure :
لكل نافذة إجراء مرتبط بها يتم إستدعائه لحظة إنشائها , هذا الإجراء يتكفل بتلقي جميع الرسائل التي يتم إرسالها
للنافذة , يقوم ببعض العمليات و من ثم يتم إطلاق الحدث الموافق . فمثلا يتلقى الرسالة WM_PAINT , يقوم
بالتعاون مع مكتبات ويندوز برسم الفورم ومن ثم يطلق الحدث Paint .
و بطبيعة الحال فإن إجراء النافذة الإفتراضي يتوقع رسالة ذات أربعة وسائط.
Subclassing :إن مبدأ ال Subclassing بسيط : وذلك بإنشاء إجراء عام في ال Module و تطلب من ويندوز أن يستدعي
إجرائك بدلا من إجراء النافذة الإفتراضي (عن طريق التابع SetWindowLong ) و بذلك يتلقى إجراؤك الرسالة
قبل النافذة (بشكل أدق قبل إجراء النافذة الإفتراضي لأنك ستستدعيه لاحقا ) , ومن ثم استقصاء الرسائل و وسطائها
لتفعل ما تريد , و في النهاية إستدعاء إجراء النافذة ( عن طريق التابع CallWindowProc ).
وهذه الخطوة الأخيرة ضرورية جدا لأنك إن لم تقم بها رح تشوف العجايب لأن إجراء النافذة الإفتراضي لا تقتصر
مهمته على رفع الأحداث فحسب , وإنما يتداخل بأمور أخرى (رسم النافذة مثلا ).
و الآن شرح بسيط عن التابعين السابقين فيما يخص هذا المضمار
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
يغير هذا التابع العديد من الأمور الخاصة بالنوافذ يحددها الوسيط الثاني (كما هو واضح الوسيط الأول مقبض النافذة)
أما الوسيط الثالث القيمة الجديدة للشيء الذي حدد بالوسيط الثاني . ما يهمنا منها هو GWL_WNDPROC=nIndex
فالوسيط الثالث في هذه الحالة يخب أن يكون عنوان (AddressOf) إجراءك الذي صنعته , أما القيمة المعادة لهذا التابع فهي
عنوان إجراء النافذة الحالي(الإفتراضي ) و هذة القيمة مهمة جدا وعليك أن تحتفظ بها في متحول عمومي

Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
الوسيط الأول هو عنوان إجراء النافذة الإفتراضي والذي من المفترض أنك حفظته في متحول أما باقي الوسطاء فهي
وسطاء الرسالة .
و الآن إليكم الكود :

كود
في مستوى الموديول :
Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hwnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Public Declare Function IsWindow Lib "user32" (ByVal hwnd As Long) As Long
Public Const GWL_WNDPROC = (-4)
Public Const WM_MOVE = &H3     مثلا ' رسالة تحرك الفورم

Dim saveHWnd As Long        ' متحول سيمسك مقبض النافذة
Dim oldProcAddr As Long     ' المتحول الذي سيمسك عنوان إجراء النافذة الإفتراضي
Sub StartSubclassing(ByVal hwnd As Long)
   If IsWindow(hwnd) = 0 Then Exit Sub
   If saveHWnd Then StopSubclassing
   saveHWnd = hwnd
   oldProcAddr = SetWindowLong(hwnd, GWL_WNDPROC, AddressOf WndProc)
   'هو الذي سيتلقاها WndProc وبذلك فإن أي رسالة ترسل للنافذة فإن إجراءك
   'وسيتم تنفيذ هذا الإجراء
End Sub

Sub StopSubclassing()
   ' إعادة السيطرة لإجراء النافذة الإفتراضي
   SetWindowLong saveHWnd, GWL_WNDPROC, oldProcAddr
End Sub

Function WndProc(ByVal hwnd As Long, ByVal uMsg As Long, _
   ByVal wParam As Long, ByVal lParam As Long) As Long
   ' سيتم تنفيذ هذا الإجراء في كل مرة ترسل رسالة للنافذة
   
   ' إن ويندوز يتوقع قيمة مرجعة من إجراء النافذة
   ' ولما حل إجراؤك مكان إجراء النافذة فعلى إجرائك أن
   ' يرجع قيمة وخير طريقة لإرجاع القيمة الصحيحة هي إرجاع
   ' القيمة المعادة من عملية إستدعاء إجراء النافذة
   WndProc = CallWindowProc(oldProcAddr, hwnd, uMsg, wParam, lParam)
   ' و الآن يمكنك بالجمل الشرطية إختبار الرسالة وتنفيذ ما تريد
   ' API Text viewer  ثوابت الرسائل وقيمها تجدها في
   If uMsg = WM_MOVE Then
      MsgBox "النافذة تحركت"
   End If

End Function

في مستوى الفورم :

Private Sub Form_Load()
StartSubclassing Me.hwnd
End Sub

Private Sub Form_Unload(Cancel As Integer)
StopSubclassing
' Stop لا تنسى أبدا هذه الخطوة و لا تغلق البرنامج من الزر
' و انما من الضرب
End Sub

ما فائدة ال Subclassing :
1- يمكنك من خلالها قنص العديد من الرسائل التي لا يوجد لها حدث مقابل(يأكلها إجراء النافذة)
مثلا متى تحركت الفورم ؟ أو متى فقد التطبيق الدخل؟
على كل فإن .NET قد حل هذه المشكلة حيث يوجد لجميع الرسائل التي ترسل للنافذة حدث مقابل
2- يمكنك أن تتلقى الرسالة قبل أن تصل إلى النافذة ومن ثم تفعل ما تريد حسب رغبتك أو حتى
نغير فحوى الرسالة نفسها.
ولا تحاول السيطرة على فورم من خارج تطبيقك لأن هذا -على ما يبدو- يفوق قدرة الفيجوال بيسك

إن ال Subclassing تقنية رائعة تمكنك بالفعل من بناء برامج قوية ولكنها من دون أدنى شك
واحدة من أكثر الأشياء خطورة , هذا وإن ويندوز لن يغفر لك أي خطأ في هذا المضمار وسوف
يتم إغلاق فيجوال بيسك فورا دون أية رسالة لذا عليك حفظ مشروعك قبل تشغيل البرنامج.

وقد قمت بتصميم مكتبة DLL للقيام بهذه العملية فمن يريد الكود فاليضغط هنا
حجم الملف حوالي 4 كيلو
Night Coder
رائع و لعلك تخفف عنا رحيل الاستاذ عبد القادر حجار اتذكر انه قد تكلم عن نفس الموضوع من قبل
بن حسن
جزاك الله خيرا يا أخي على شرحك الرائع

لكن هل يوجد مرجع لتلك الرسائل ليشرح وظائفها ؟
عبد الله فتحي
لا أدري ولكن من خلال برنامج الـ SPY ++ المرفق مع الفيجول بإمكانك التجسس على جميع الرسائل التي ترد إلى نافذة معينة ..
وبالمحاولة يمكنك معرفة وظائف بعض هذه الرسائل ..

بالتوفيق
RbcandWbc
شكرا يا اخي على الموضوع الجيل واتممنى منك ان تكمل شرح ٍsubclassing and hooking من البداية و اوسع حتى يستطيع المبتدأين مثلي أن يتمكنوا منه
و الف شكر لك
هذه "نسخة - خفيفة" من محتويات الرئيسية للإستعراض الكامل مع المزيد من الصور والخيارات الرجاء إضغط هنا.
Invision Power Board © 2001-2009 Invision Power Services, Inc.