المقالات العلمية

مقالات الشبكة العربية لمطوري الألعاب

Windows و الرسائل:

هذه المقالة محمية ضمن الحقوق الفكرية لشركة In|Framez Technology Corp.، ومرخصة للعرض فقط ضمن الشبكة العربية لمطوري الألعاب مع الموافقة الصريحة من المؤلف وشركة In|Framez Technology Corp.. لا يسمح بإعادة نشر هذه المقالة أو تعديلها دون الرجوع للمؤلف. يمنع النسخ والاقتباس دون ذكر المصدر والموافقة من المؤلف.


ولكن أين صندوق البريد (Procedure) لهذه الرسائل (Messages) هذا ما توضّحه المقالة. فأرجو أن تكمل قراءتها حتى النهاية و أن تأخذ الفائدة المرجوة منها. يعتبر المثال المرافق للمقالة عبارة عن شرح وليس برنامجاً كاملاً يحقق نتيجة ما، فاستخدمه كمساعد و لا تحكم على الـ Win32 API عبره (لإنشاء برنامج مثله عليك أن تختار من لائحة أنواع التطبيقات في Visual C++ Wizard أن البرنامج من نوع Win32 API ). بسم الله مسراها...

 

النقاط التي سنتحدث عنها اليوم

  • الإطلاع على كيفية إنشاء نافذة (window) من البداية و حتى الـ Message Loop.
  • ما هو صندوق البريد الـ Procedure و ما هي الـ Messages.
  • تعريف بأهم الرسائل التي يمكن أن تستخدمها.

النوافذ windows

في هذا المقال، لن أقوم بتعريب أغلب المفردات (لعدم إقتناعي بالكلمات المعربة) فإذا أردت ترجمة المفردات الإنجليزية يمكنك الإستعانة بقاموسي الشخصي أسفل الصفحة، أو بإمكانك الإستعانة بمصادر أخرى. إنشاء النافذة هو بسهولة استدعاء للإجراء CreateWindow هذا هو كل شيء، طبعاً إذا كنت قد سجلت هذه النافذه باستدعاء آخر صغير للإجراء RegisterClass و مما يتضح من اسم الإجراء فإنك بحاجة إلى ما يسمى بصف النافذة Window Class، و طبعاً إذا أردت أن تنفذ النافذة ما تأمر به فستحتاج إلى الـ Message Loop (يبدو أن إنشاء النافذة لم يعد سهلاً بعد الآن) ولكن لنبدأ الآن بالإجراء الرئيسي الذي سيحتوي كل ما ذكرته الا و هو WinMain.

قد يكون لهذا الإجراء أصداء عند من يعملون على لغة C تحت DOS حيث الإجراء الرئيسي هناك هو main إلا أن الإجراء WinMain (الذي يوحي بأنه مصمم للنوافذ) أعقد بقليل من سابقه. إليك صيغته (التي لست مجبراً بها فقد ترغب مثلاً بتغيير أسماء المتغيرات) و لك المقارنة:

   1: int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)

و الآن دعني أفصفص (أدقق) هذا الإجراء، بدأً مع القيمة المعادة ألا و هي int (أعتقد أن هذا لا يحتاج لشرح) تتبع هذه العبارة عبارة WINAPI و المعرّفة في windows.h على أنها sdtcall__. حيث يجب أن توجد هذه العبارة (أو أحد معرفاتها، طبعاً) قبل كل إجراء من إجراءات Win32 API أي الإجراءات التي يتعامل فيها Windows مع التطبيق مباشرة.

hInstance المعامل الأول و الذي هو Handle to Instance الذي يمكن بأن تعتبره "هوية للتطبيق" التي يتعرف فيها Windows عليه و تحتاج إلى الـ Handle حتى تتمكن من تمريره كمعامل لبعض الإجراءات و في إنشاء الموارد كالقوائم و الإيقونات...

المعامل الثاني هو hPrevInstance و الذي أيضاً هو Handle to Instance ولكن ليس ليس للتطبيق الحالي بذاته، هذا المعامل يستخدم ليكشف البرنامج ما إذا كان هناك Handle لنفس Instance الذي يملكه التطبيق فيوفر كثيراً من الوقت و الكتابة في أخذ المعلومات منه ،مرة أخرى، معلومات مثل الموارد كالقوائم و الإيقونات...

الآن في Win32 لا يُستخدم هذا المعامل بل يُتجاهل و يكون ببساطة NULL حيث يسبب ذلك أن يعتبر كل تطبيق فريداً من نوعه في النظام حتى و إن كان هناك مئات التطبيقات المشابهة. ولكن و مع ذلك بعض التطبيقات بحاجة إلى معرفة ما إذا كان هناك نفس التطبيق في العمل لتبادل المعلومات، أو أكثر عموماً، لمنع تضارب الـ Instances لكل تطبيق.

المعامل الثالث هو szCmdLine و الذي كما يوحي اسمه هو Command Line أي أنه عبارة عن نص لبيان مسار التطبيق متضمناً اسمه، تستخدمه بعض التطبيقات في تحميل نفسها في الذاكرة، و للحصول على هذا المسار مع اسمه عليك باستخدام الإجراء ()GetCommandLine و الذي يرجع المسار كقيمة معادة. ثم بإمكانك أن تعرف ما إذا أدخل المستخدم أحرفاً زائدة على اسم الملف بعد مسافة بينهما(نفس التقنية (و ليس المتغير) تستخدم في الأمر Format لمعرفة السواقة و ما إذا كان الـ Format سريعاً أو كاملاً...).

المعامل الرابع و الأخير هو iCmdShow و الذي يحدد كيف سيتم عرض التطبيق مبدئياً فيما لو كان عادياً أو مكبراً أو مصغراً على شريط المهام TaskBar.

والآن لننتقل لما يسمى بالـ Window Class و الذي هو عبارة عن structure يسمى WNDCLASS و الذي يضم عشرة بنود أذكرها فيما يلي مع قيمها الأكثر استخداماً:

   1: WNDCLASS wndclass;
   2: wndclass.style = CS_HREDRAW | CS_VREDRAW;
   3: wndclass.lpfnWndProc = WndProc;
   4: wndclass.cbClsExtra = 0;
   5: wndclass.cbWndExtra = 0;
   6: wndclass.hInstance = hInstance;
   7: wndclass.hIcon = LoadIcon (NULL، IDI_APPLICATION);
   8: wndclass.hCursor = LoadCursor (NULL، IDC_ARROW);
   9: wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
  10: wndclass.lpszMenuName = NULL;
  11: wndclass.lpszClassName = szAppName;

لنبدأ بالبند الأول style: هو طبعاً عن صفات النافذة و هي عبارة عن معرفات تبدأ بالحرفين _CS من Class Style يمكن أن تجد جدولاً بها في الـ MSDN (كما كل المعرفات التي ذكرتها و سأذكرها في هذه المقالة)، و لكن دعنا نرى: جُمعت في هذا البند الخاصتان CS_HREDRAW و CS_VREDRAW بالمعامل | ولكن ماذا تعنيان؟

أفترض أنك عرفت عملهما من قرائتهما، شأنهما شأن كل معرفات ++C و هما Vertical REDRAW و Horizintal REDRAW أي إعادة رسم عمودية و أفقية حيث أنك بإضافة هاتين الخاصيتين سوف تجبر التطبيق على توليد رسالة WM_PAINT (التي سأشرحها بعد قليل) لكامل مساحة العمل Client Area عند تغيير حجم النافذة أفقياً أو عمودياً و ذلك حتى تتمكن من إعادة (رسمها).

البند الثاني lpfnWndProc و الذي يحدد الـ Procedure أو ما سميته بصندوق البريد (الذي سأشرحه بعد قليل)

البند الثالث و الرابع يستخدمان لحجز بعض البايتات الإضافية في الـ Window Class التي قد يستخدمها التطبيق داخلياً.

البند الخامس هو أحد استخدامات الـ Handle to Instance (أحد معاملات WinMain).

البند السادس و السابع يستخدمان لتحديد أيقونة و شكل المؤشر المبدئيان للنافذة باستخدام الإجراءان LoadIcon و LoadCursor على التوالي و كما هو واضح فقد حُدد في النافذة الأيقونة الإفتراضية IDI_APPLICATION و التي تظهر على شكل مربع أبيض. و شكل المؤشر الإفتراضي IDC_ARROW و هو شكل المؤشر العادي.

البند الثامن hbrBackground هو فرشاة الدهّان Brush التي يستخدمها Windows في طلي مساحة العمل Client Area (النافذة عدا شريط العنوان، الإطار، شريط القوائم، شريط الأدوات، شريط التمرير، شريط الحالة) التي قد تكون لوناً كما في المثال: حيث اعتمدت على فرشاة لون أبيض جاهزة باستخدام الإجراء GetStockObject بعد تحويلها إلى HBRUSH التي هي Handle to Brsuh باستخدام الـ Type Casting و إن كنت لا تعلم ما أتكلم عنه فأنصحك بقراءة المقالة " تحويل أنواع المتغيرات في ++C ، سلاح ذو حدين (type casting)" لــ وســام البهنسي.

كما و قد تكون (الفرشاة) عبارة عن صورة صغيرة يستخدمها Windows في (طلي) مساحة العمل فيكررها عمودياً و أفقياً.

البند التاسع و كما يوحي اسمه هو لتحديد شريط القوائم الذي سيعلو مساحة العمل ولكن و بما أنه ليس هناك شريط قوائم فقد أُعطي القيمة NULL.

البند العاشر و الأخير هو اسم الـ Window Class حيث أن لكل واحد اسم يتفرد به عن غيره لكي تمرره إلى الإجراء الذي سينشئ النافذة على أساسه.

 

هل تذكر ذلك الإجراء الصغير الذي حدثتك عنه أول المقالة RegisterClass الآن حان دوره: و هو إجراء لتسجيل الـ Window Class و هو يأخذ معاملاً واحد هو wndclass& أعني مؤشراً لـ Window Class.

إلى الآن أنا لم أحصل على الزبدة (النافذة) أنا فقط وضغت بعض مقاديرها و مكوناتها (Window Class) و الآن يجب أن أطلب من العامل (Windows) أن يصنع (Create) لي واحدة على أساس هذه المكونات (Window Class ) مع صفات إضافية.

إذا جمعت كلمات هذه الأحجية سوف تحصل على صيغة الإجراء الذي يستخدم لإنشاء النافذة على أساس الـ Window Class. أُورد صيغته مع أشهر قيم لمعاملاته:

   1: hwnd = CreateWindow (szAppName,    // window class name
   2:         TEXT ("The Hello Program"),// window caption
   3:         WS_OVERLAPPEDWINDOW,       // window style
   4:         CW_USEDEFAULT,             // initial x position
   5:         CW_USEDEFAULT,             // initial y position
   6:         CW_USEDEFAULT,             // initial x size
   7:         CW_USEDEFAULT,             // initial y size
   8:         NULL,                      // parent window handle
   9:         NULL,                      // window menu handle
  10:         hInstancem                 // program instance handle
  11:         NULL) ;                    // creation parameters

مرة أخرى لنبدأ من جديد: أولاً يعيد الإجراء CreateWindow المسؤول عن صنع الزبدة أ..أ..أقصد النافذة قيمة من نوع HWND التي هي عبارة عن Handle to Window و التي أستطيع أن أصل للـ Window عبرها، أي أنها أيضاً بطاقة هوية للـ Window. و الآن لنرى: المعامل الأول szAppName أليس هذا هو نفس المتغير الذي منح للـ Window Class اسمه؟ أجل في هذا المعامل يحدد اسم الـ Window Class الذي ستبنى النافذة على أساسه.

في المعامل الثاني يُحدد النص الذي سيظهر في شريط العنوان. و في الثالث أحدد تلك الخصائص الإضافية التي سأطلب من الصانع أن يصنع لي نافذة على أساسها، في هذا المثال هناك خاصة و احدة هي WS_OVERLAPPEDWINDOW (حيث _WS هي الحرفان الأولان من Window Style) و الذي يعني أن النافذة ستكون بخصائص عامة أي أنها ستملك شريط عنوان، زر إغلاق و تكبير و تصغير، زر قائمة النظام في الزاوية العليا اليسرى من النافذة و إطار رفيع.

المعاملات الرابع و الخامس و السادس و السابع تحدد الإحداثيات المبدئية للزاوية العليا اليسرى و حجم النافذة المبدئي على التوالي و قد حُددوا بـ CW_USEDEFAULT (حيث _CW هي الحرفان الأولان من Create Window) و التي هي القيمة الإفتراضية لـ Windows.

المعامل التالي هو اسم النافذة الأب Parent Window إذا كانت النافذة التي تنشأ هي نافذة إبن Child Window (ولكن أين بقيّة العائلة؟!!) على أية حال سوف أرجئ الحديث عن هكذا نوافذ لمقالات أخرى. المعامل التاسع هو Handle to a Menu لكن انتظر قليلاً ألم نحددها في الـ Window Class؟ حسناً كما أسلفت ذكراً يمكن إنشاء عدة نوافذ على أساس Window Class واحد ولكن ماذا لو أردت تحديد القائمة في أحد النوافذ و عدم تحديدها في أخرى منشأتان بالإستناد إلى نفس الـ Window Class؟ هذه هي أحد الطرق.

المعامل العاشر هو Handle to Instance الذي حددناه في الـ Window Class و هو أحد معاملات WinMain. و المعامل الأخير يشبه البندان الثالث و الرابع في Window Class.

 

و الآن هل بإمكاني الحصول على الزبدة (النافذة)؟ لا، ليس قبل أن تطلب من الصانع إحضارها (Show) و كشف الغطاء عنها (Update) أو ببساطة أن تضيف نداءً للإجراء ShowWindow مع Handle to Window أو hwnd كمعامل أول و الطريقة التي تريد أن تعرض بها النافذة، سواء كانت مكبرة أو مصغرة أو عادية كمعامل ثانٍ، أو يمكنك ببساطة أن تمرر له المتغير iCmdShow أي المعامل الأخير لـ WinMain. و بعد ذلك يجب عليك أن تضيف نداءً للإجراء UpdateWindow مع Handle to Window أو hwnd كمعامل وحيد.

 

يمكنك الآن أن تحصل على النافذة أمامك بخلفية بيضاء فارغة و شريط عنوان... على أية حال لن تستطيع أن تفعل أي شيء بهذه النافذة ما لم تخبرها بأن تستجيب لأوامرك و ذلك عبر عنصرين هما حلقة الرسائل Message Loop و الـ Procedure. فأما الـ Message Loop فهي حلقة (Loop) تقوم بها باستلام الرسائل (GetMessage) و ترجمتها (TranslateMessage) ثم إرسالها إلى الـ Procedure أي (DispatchMessage) و ذلك بالصيغة التالية:

   1: while (GetMessage (&msg، NULL، 0، 0))
   2: {
   3:      TranslateMessage (&msg) ;
   4:      DispatchMessage (&msg) ;
   5: }
   6: return msg.Wparam;

مرة أخرى هذه ليست قاعدة ولكن هذا هو الشكل العام (حيث يمكن إضافة إجراءات أخرى). كما يوضح اسم الإجراء فإنه يجلب الرسائل (التي هي عبارة عن تفاعل المستخدم مع الماوس و لوحة المفاتيح و الرسائل التي يرسلها Windows بنفسه إلى البرنامج) ولكن من أين؟

يحجز Windows لكل تطبيق يعمل تحته ما يسمى بـ Message Queue الذي تخزن فيه الرسائل التي ترد إلى التطبيق حسب أولويتها و ليس حسب زمن ورودها. كما ترى يأخذ الإجراء أربع معاملات. الثلاثة الأخيرة تعطى كلها بـ 0 و NULL حتى نخبر الإجراء بأننا نريد جميع الرسائل مهما كان نوعها. أما الأول فهو عبارة عن مؤشر لـ structure من نوع MSG فيه ست بنود. و يعرف هذا الـ structure في winuser.h كما يلي:

   1: typedef struct tagMSG
   2: {
   3:     HWND hwnd ;
   4:     UINT message ;
   5:     WPARAM wParam ;
   6:     LPARAM lParam ;
   7:     DWORD time ;
   8:     POINT pt ;
   9: }

كما هو واضح فإن أول بند في هذا الـ structure هو Handle to Window، و الثاني هو UINT أو بالإنجليزي الصريح unsigned int و الذي يعبر عن قيمة الرسالة العددية التي يجلبها، البند الثالث و الرابع هما عبارة عن معلومات متعلقة بالرسالة سوف ترسل فيما بعد إلى الـ Procedure، البند الخامس هو الوقت الذي حدثت فيه الرسالة بالميلي ثانية، و أخيراً البند الأخير هو عبارة عن structure فيه بندان x، y يحددان النقطة التي كان المؤشر موجوداً فيها بالنسبة للزاوية العليا اليسرى للشاشة عند حدوث الرسالة. الآن عندما أستدعي الإجراء GetMessage فأنه يملئ لي هذه البنود بالمعلومات المطلوبة عن الرسالة التالية في الـ Message Queue، ثم يعيد أي قيمة عدا الـ 0 إلا إذا كانت الرسالة WM_QUIT، التي و بكل وضوح تحدث عندما ينهي المستخدم التطبيق، عندها يتم الخروج من الحلقة و تنفذ العبارة التي بعدها ;return msg.Wparam التي أضيفت لضمان أن يعود WinMain بقيمة ما، كما هو مطلوب منه. ثم ينتهي البرنامج. عدا ذلك يُنفذ الإجراء TranslateMessage (و ذلك لإرسال الرسالة مرة أخرى إلى Windows لترجمة بعض الرسائل الصادرة من لوحة المفاتيح) مع معامل وحيد هو مؤشر لـ structure من نوع MSG الذي ملئت بنوده بنداء للإجراء GetMessage. ثم يٌنفذ الإجراء DispatchMessage (و ذلك لإرسال الرسالة مرة أخرى إلى Windows لكي يحدد الـ Procedure المناسب لها عن طريق البند hwnd من الـ structure من نوع MSG) مع معامل وحيد هو مؤشر لـ structure من نوع MSG.

أما بالنسبة للعنصر الثاني الـ Procedure فهو إجراء WinAPI أي يجب أن يسبق بالعبارة CALLBACK المعرفة في windows.h على أنها مساوية لـ stdcall__ و ذلك طبعاً لأن إجراء الـ Procedure يتواصل مع Windows مباشرة. و له الصيغة العامة التالية:

   1: LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

تذكر أنه بإمكانك تغيير اسم الإجراء على أن تغير أيضاً بند الـ lpfnWndProc في الـ Window Class. أولاً يعود الإجراء بقيمة من نوع LRESULT المعرفة على أنها signed int و يأخذ اربعة عوامل أفترض أنها أصبحت مفهومة الآن: الأول هو Handle to Window و الثاني هو القيمة العددية للرسالة، و الثالث و الرابع هي المعلومات الإضافية لكل رسالة التي قام الإجراء GetMessage بملئهما في الـ structure من نوع MSG.

و الآن كل شيء جاهز بقي علينا فقط كتابة الشيفرة (code) للـ Procedure حتى يتصرف يالشكل المناسب تجاه أي رسالة يتلقّاه. و فيما يلي أهم الرسائل التي سوف تصادفك.

 

بعض أهم الرسائل

أولاً دعنا نرى كيف يكون الشكل العام للـ Procedure مع بعض أهم الرسائل:

   1: //[defining some variables]
   2: switch (message)
   3: {
   4:     case WM_CREATE :
   5:          [process WM_CREATE message]
   6:          return 0 ;
   7:               
   8:     case WM_PAINT :
   9:          [process WM_PAINT message]
  10:          return 0 ;
  11:               
  12:     case WM_DESTROY :
  13:          [process WM_DESTROY message]
  14:          return 0 ;
  15: }
  16: return DefWindowProc (hwnd, iMsg, wParam, lParam);

يستخدم الـ Procedure عادة ما يسمى بالـ switch and case Construction أي حلقة على أساس switch و case. حيث يختبر قيمة message العددية للرسالة فيقارنها بالمعرفات العددية في windows.h. و يظهر هنا ثلاث رسائل أساسية هي WM_CREATE (حيث أن _WM هي من Window Message) و التي تنشئ عند تنفيذ الإجراء CreateWindow. و WM_PAINT و التي تنشئ عند تنفيذ الإجراء ()UpdateWindow أو عندما تلوح النافذة أو جزء منها إلى النظر أي عندما تكون (invalid) و تحتاج إلى تحديث أو إعادة (رسم) (update) . و WM_DESTROY و التي تحدث عند (تدمير) النافذة.

و لاحظ أيضاً آخر سطر في الشيفرة. يعيد هذا السطر القيمة المعادة من الإجراء DefWindowProc. من اسم هذا الإجراء نلاحظ أنه الـ Procedure الإفتراضي للنافذة و الذي يجب على كل رسالة لا يقوم التطبيق بمعالجتها أن تمر بهذا الإجراء و أحياناً حتى الرسائل التي يعالجها التطبيق.

لا يوجد الكثير في WM_CREATE فقط يجب عليك أن تعلم أن أي عمليات تريد القيام بها في أول ظهور للتطبيق يمكنك القيام بها هنا. أما WM_DESTROY فيجب عليك معالجتها (الرسالة) و القيام بعمليات الحذف و التنظيف في نهاية البرنامج ثم و أخيراً يجب إضافة السطر:

   1: PostQuitMessage (0) ;

التي تضيف رسالة WM_QUIT إلى الـ Message Queue الخاص بالتطبيق. لن تصل هذه الرسالة إلى الـ Procedure، لأنه و كما أسلفت ذكراً عندما تصل إلى الإجراء GetMessage في الـ MessageLoop في WinMain فإنه يعود بالقيمة 0 و بالتالي تنتهي الـ Message Loop و تنفذ العبارة التي بعدها و هي ;return msg.wParam (و التي غالباً ستكون 0) عندها ينتهي WinMain و بالتالي البرنامج.

أكثر اللعب سيكون في الرسالة WM_PAINT كما توحي الرسالة فهي (لرسم) النافذة و أكثر تحديداً مساحة العمل، يجب أن تكون معالجة الرسالة بالشكل التالي:

   1: case WM_PAINT:
   2:     hdc = BeginPaint(hwnd, &ps);    
   3:     // [process WM_PAINT message]
   4:     EndPaint(hwnd, &ps);
   5:  
   6: return 0 ;

(لا تحاول أن تعالج الرسالة WM_PAINT دون هاذين الإجرائين. إذا لم ترد إضافتهما فالأحرى بك أن تترك معالجة هذه الرسالة لـ DefWindowProc) كما تلاحظ تبدأ معالجة الرسالة بتنفيذ الإجراء BeginPaint لإعلان البدء بالرسم مع hwnd أو Handle to Window كمعامل أول و مؤشر لـ structure من نوع PAINTSTRUCT الذي سمي في المثال ps، و تنتتهي بتنفيذ الإجراء EndPaint لإعلان الإنتهاء من الرسم مع نفس المعاملات. القيمة المعادة من الأخير دائماً موجبة تماماً. أما الأول فإن نجح كانت القيمة المعادة من نوع HDC (Handle to Device Context) .لن أتفانى في شرح الـ DC الآن (مع أهميته) بل سأرجئه مع PAINTSTRUCT إلى مقالة أخرى ولكن إذا أحببت أن تأخذ تعريفاً أولياً فاتجه إلى أسفل الصفحة.

و الآن سأختم مقالتي بمثال على استخدام الـ hdc الذي حصلنا عليه، و ليكن في عرض نص ما باستخدام الإجراء TextOut الذي له الصيغة التالية:

   1: BOOL TextOut( HDC hdc,  // handle to DC
   2:     int nXStart,        // x-coordinate of starting position
   3:     int nYStart,        // y-coordinate of starting position
   4:     LPCTSTR lpString,   // character string
   5:     int cbString        // number of characters
   6: );

لنر الآن: أولاً Handle to Device Context (إذا لم تكن قد قرأت ترجمته أسفل الصفحة فعليك فعل ذلك الآن)، و ثانياً و ثالثاً نقطة التي تحدد الزاوية العليا اليسرى من النص، و رابعاً النص نفسه، و أخيراً عدد حروف ذلك النص (بإمكانك استخدام الإجراء lstrlen).

 

متطلبات النظام

  • Win32 API
  • Microsoft Visual Studio .NET

بإمكانك الإستعانة بالمصادر المذكورة في الأسفل إذا أردت أن تتوسع في هذا الموضوع (و هذا ما أنصح به)

 

لمزيد من المعلومات

المصطلحات المستخدمة

المصطلح معناه
Procedure و هو الإجراء المسؤول عن معالجة كافة الرسائل التي ترد إلى النافذة، يتولى Windows بنفسه إرسال هذه الرسائل إلى الـ Message Queue ثم يقوم التطبيق بنفسه باستلام الرسائل و إرسالها إلى الـ Procedure. و ذلك بعد تحديده في الـ Window Class.
Message الرسالة: ليس في ظرف و إنما في الـ Message Queue وهي قيمة عددية معرفة في windows.h بمعرفات كلمية. وهي تعبر عن الشيء الذي حدث في Windows أو أُحدِث من قبل المستخدم حتى يتمكن الـ Procedure من معالجتها بالشكل المناسب.
Message Loop عبارة عن حلقة for في WinMain. يقوم التطبيق فيها باستلام الرسائل من الـ Message Queue، القيام ببعض الترجمة لرسائل لوحة المفاتيح، ثم ارسالها إلى الـ Procedure. و ذلك عبر سلسة من الإجراءات.
API الأحرف الأولى من (Application Programming Interface) و هي عبارة عن مجموعة من الإجراءات للعمل مع المكونات، التطبيقات أو أنظمة التشغيل. وهي مكونة من مجموعة من ملفات الـ DLL التي تدعم بعض الوظائف و الـ Win32 API هي الـ API التي تتمم Windows.
Handle تستطيع أن تعتبره هوية لأي عنصر في الذاكرة. و هو عبارة عن قيمة يفهمها Windows للوصول إلى ذلك العنصر.
structure من اللغة الأصل C. فكر فيه على أنه صندوق يحوي مجموعة من المتغيرات، فإذا أردت أحدها: طلبت من Windows أن يذهب إلى الصندوق أولاً ثم إلى المتغير المطلوب. حيث يعتبره Windows متغيراً أيضاً.
Client Area توجد في النافذة (window) و هي مساحة العمل أي المساحة التي تستطيع أن ترسم، تكتب أو ترى النتائج فيها. و هي كامل النافذة عدا شريط العنوان، الإطار، شريط القوائم، شريط الأدوات، شريط التمرير، شريط الحالة.
Message Queue جزء يحجزه Windows في الذاكرة لكل تطبيق يعمل تحته ليخزن الرسائل الموجهة إلى نوافذ التطبيق فيه حسب أولويتها و ليس حسب زمن ورودها. مع إمكانية وجود أكثر من Message Queue واحد للتطبيق الواحد في ما يسمى بالـ Multi Tasking.
invalid مصطلح يطلق على مساحة عمل النافذة أو جزء منها للتعبير على أنها في حاجة لإعادة (رسم) وذلك عند أول التطبيق و عندما تختفي النافذة وراء أي شيء ثم تظهر ثانيةً.

 

بسم الله مرساها.

أضف تعليقاً

Loading