المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : اجراءات API و مقدمة عن الرسائل



PaPEr Cut
21-07-2002, 02:10 PM
عودة الى موضوع اجراءات API، من المهم ان تضع في ذهنك اصدار Windows المناسب الذي تستدعي اجراءات API الخاصة به. فهنالك العديد من اجراءات API غير متوافقة مع الاصدارات المختلفة لـ Windows! احد هذه الاجراءات قد واجهته قبل عدة ايام وهو GetDiskFreeSpace والخاص بمعرفة المساحة المتوفرة في القرص المحدد. فعندما قمت بتجربته تحت Windows 2000 عمل بنجاح، لكن عندما نبهني احد الاخوان في رسالة تقتضي ان الاجراء لم يعمل بشكل صحيح تحت نظام Windows ME راجعت مكتبة MSDN وتبين لي ان هذا الاجراء متوافق مع نظم Windows NT و Windows 2000 وبعد مساعدة كريمة منه نبهني الى وجود الاجراء GetDiskFreeSpaceEx والذي يتوافق مع جميع اصدارات Windows المختلفة والذي عمل بنجاح معي. في معظم الاحوال، الاجراءات التي تنتهي بالحروف Ex تكون متوافقة مع جميع اصدارات Windows فهي اجراءت مطورة او محدثة من اجراءات سابقة لها.


تجرني القصة السابق الى الحديث عن موضوع توافقية اجراءت API لاصدارات Windows المختلفة وهي احدى المشاكل الخطيرة جدا التي تصادف مطوروا برامج Windows والذين يفرض عليهم تزامن التوافقية لبرامجهم حتى تعمل تحت اصدارات Windows المختلفة.

والحل الذي يطبق في معظم البرامج الجدية يختلف من طريقة تسويقية الى اخرى. فمثلا، يقوم بعض المبرمجين بانشاء اصدار من البرنامج خاص لـ Windows 9x واصدار اخر خاص لـ Window NT قد تكون طريقة مجدية الا انني اعتقد انها مكلفة. فمن المعروف ان كتابة الف سطر لبرنامج من الصفر خير من عملية تنقيح برنامج مكون من مائة سطر! وهي القاعدة التي يستند عليها مهندسوا البرامج Software Engineer. ويبدو ان الطريقة الافضل هي استخدام جمل الشرط عند كل عملية استدعاء اجراء من اجراءات API فقد تكتب شيئا مثل:


===============

If Windows9x Then Call Win9xAPI

Else If WindowNT Then Call WinNTAPI

===============


الذي اقصده من الخوارزم السابق، هي عملية اختبار اصدار Windows الحالي ومن ثم استدعاء اجراء API المناسب او المتوافق معه، وبهذه الطريقة ستضمن استقرار عملية تنفيذ برنامجك. فلا تغتر كثيرا اذا شاهدت برنامجك عمل بنجاح تحت اصدارات Windows المختلفة! لانك عاجلا او اجلا ستستخدم اجراءات API والتي تتطلب الحذر الشديد عندما تلعب بها، فلا تلعب بالنار - تحرء صبيعك! والي بيشتري برامجك، يرجع يبيعها لك!!!


اخيرا، اعود الى موضوع مقبض النافذة، مقبض النافذة عبارة عن قيمة عددية صحيحة حجمها 16 bit في نظم Windows 3.x و 32 bit في نظم Windows 9x و NT و 2000. اتوقع ان حجمها سيكون 64 bit في نظم Windows XP والعاملة تحت مسارات الـ 64 bit. اردت التنويه هنا حول حجمها كي تعين قيمها في انواع مناسبة للمتغيرات. فكما يعمل مبرمجوا لغة C، ان المتغيرات Int -ليس Long Int- حجمها 2 بايت، واذا قمت باسناد قيمة مقبض حجمه long int وكان حجم القيمة اكبر من int، فان قيمة المتغير ستعود الى الصفر وتزيد بمقدار الفارق مما يؤثر بشكل سلبي ليس فقط على برنامج وانما يشمل النوافذ المفتوحة في البرامج الاخرى! لا تنسى يا عسل انك قد ترسل قيمة مقبض لاداة او نافذة اخرى!




حسنا والان لنغير الموضوع قليلا ونتكلم عن موضوع مهم جدا جدا وهو الرسائل Messages...



* الرسائل - فكرة عامة


عندما يقوم شخص اسمه "عباس السريع" مثلا بفتح بريده الالكتروني في وقت من اوقات حياته، سيقرأ رسالة تخبره "لقد توفى ابوك" او "لقد فزت بالمليون". بغض النظر عن المحتوى التشاؤمي او التفاؤلي للرسالة، فهي رسالة هدفها اخباره بوقوع (((حدث))) معين. كلمة (((حدث))) حط عليها 9848923742 خط! فهي مهمة جدا جدا! اذن فالحدث Event عبارة عن رسالة تمت من مرسل ومرسل له. وهذا بالضبط الذي يحدث مع عالم برمجة Windows!!!!!!



فعندما يقوم المستخدم بالنقر باصابع يده الناعمتين على نافذة، يقوم فورا نظام التشغيل بارسال رسالة الى تلك النافذة يخبرها "بان المستخدم قد قام بالنقر عليها" وستقوم النافذة باتخاذ الاجراء اللازم للتفاعل مع تلك الرسالة.


السيناريو السابق هو ملخص مقالتي الان، فعملية وقوع الاحداث Events التي تقع على النوافذ والادوات والتي قد تكون نقرات بالفأرة او لوحة المفاتيح الخ... هي عبارة عن رسائل مرسلة من نظام التشغيل الى برنامجك.


تقنيا، يوجد نوعان من الرسائل تحت بيئة Windows. النوع الاول رسال التنبيه Notification Messages وهي عبارة عن رسائل من نظام التشغيل الى برنامجك. والنوع الثاني هي رسائل التحكم Control Message وهي عبارة عن رسائل من برنامج الى برامج اخرى!. نعم نعم فلا تعتقد ان برنامجك يستقبل رسائل -مثل عامل السنترال- فقط، بل يمكن ان يرسل رسائل -كمدراء الاقسام- الى جميع البرامج حاله كحال النظام -فكلنا سواسيه- والطريقة التي اعرفها هي باستخدام الاجراء SendMessage وهو احد اجراءات API المشهورة.


لكن يا شباب يبدو انني نسيت توضيح ماهي حقيقة الرسالة؟ هل هي رسالة صوتية مرئية ام ماذا؟؟؟ والحقيقة انها عبارة عن قيمة لا راحت ولا جت حالها كحال مقبض النافذة! فهي قيمة عددية صحيحة من نوع 16bit او 32bit على حسب الاصدار. لكن وبسبب وجود الالاف الرسائل، تجد معظم لغات البرمجة توفر قيم الرسائل للمبرمج على شكل ثوابت لها بادئة WM كـ WM_CLICK او WM_MOUSEMOVE الخ..



* برنامجي كيف يتعامل مع الرسائل؟


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


عندما تقوم بفتح نافذة فانك -انت او لغة البرمجة- قد احدثت حلقة تكرارية لا نهائية قائلة:

كلمة ولو جبر خاطر ولا سلام من بعيد

................. ولا رسالة يا هاجر بيد ساعي البريد


الكملة التي ستجبر خاطر النافذة هي الرسالة التي تريدها، وساعي البريد هو نظام التشغيل. تصوروا ان عملية انتظار الرسالة تتم في حلقة تكرارية وبالتأكيد فكر ماذا سيحدث لو وجدت 100 نافذة مفتوحة في وقت واحد وكل واحدة منها لها حلقة تكرارية طالبة رسالة من نظام التشغيل!!! فلو كان الجهاز يحتوي على ذاكرة عالية ومعالج سريع لتنفيذ جميع حلقات التكرار سيوفر نظام التشغيل جميع الرسائل الى اصحابها. اما في حالة كون الجهاز موب لهناك! فهذه النوافذ ستسبب التقليل من مصادر النظام مما يؤدي الى انهيار نظام التشغيل قائلا: احنا نصرف على مين ولا على مين!!! وستظر الشاشة الزرقاء المحبوبة "System Busy" . لا تخف تراني امزح، فهذا شئ نادر الحدوث بسبب كثرة النوافذ المفتوحة لكن المقصد من ذلك هو تبين ان المعالج يقوم بتنفيذ عشرات الالاف -ان لم يكن ملايين- من التعليمات في حلقات تكرارية للنوافذ والتي غرضها فقط انتظار الرسائل من نظام التشغيل!! هذا غير تنفيذ الاكواد التي كتبتها!


لتوضيح الفكرة اكثر، دعنا نفترض انك انشئت نافذة وتريد ان تجعلها جاهزة لاستقبال الرسائلة. فالخوارزم الذي ستتبعه سيكون مشابه لهذا:


===============




Do

{

GetMessage ( &lMsg, &lPara1, &lPara2);


switch ( lMsg )

{

case: WM_CLICK

OnWindowClick ();

case: WM_MOUSEMOVE

OnWindowMouseMove ( lPara1, lPara2);

.

.

.

}

} While ( lMsg = WM_CLOSEWINDOW )




==============


اذن، في الخوارزم السابق انشئنا حلقة تكرارية هدفها قنص رسائل النظام والموجهة الى النافذة عن طريق الاجراء GetMessage، وستنتهي الحلق اذا كانت الرسالة WM_CLOSEWINDOW والتي بكل تأكيد توضح اننا لن نحتاج الى عملية قنص الرسائل ما دام المستخدم طلب اغلاق النافذة. استخدم عبارة الشرط switch ... case لتحديد نوع الراسلة ومن ثم تنفيذ الاجراء المناسب.


اذا كان الكود السابق غريب عليك، فيبدو انك من المبرمجين حديثوا العهد بـ Windows والمعاصرين للبرمجة المرئية Visual، لكن الشئ الذي لابد من معرفته هو انه مهما كانت لغة البرمجة التي تستخدمها، فهذا الخوارزم هو الخوارزم الذي تتبعه لغة البرمجة وتشئ الاكواد المناسب له والذي يعرف في عالم لفات البرمجة المرئية بالاحداث Events والتي هي عبارة عن اجراءات قد رتبتها لك لغة البرمجة ويتم استدعاءها وفقا لنوعية الرسائل التي وصلت للنافذة من نظام التشغيل. مع ذلك، عندما تحدك الايام ستضطر الى الاكواد مماثلة للخوارزم السابق وستطبق تقنيات متقدمة في برمجة رسائل النظام Windows كالردود CallBack او التصنيف الفرعي للرسائل Subclassing Windows Messages.


بالمناسبة، اذا كنت من مبرمجي Visual Basic، فستجد مقالة حول الردود CallBack في موقع الى القمة مع Visual Basic تجدها على الرابط التالي:


http://www.vb2top.com/scripts/showar.asp?id=46