Jump to content


Photo
* * * * * 1 votes

سلسلة دروس عربية لتعلم دوال WIN API


  • This topic is locked This topic is locked
83 replies to this topic

#1 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-16 - 01:02 PM

السلام عليكم ورحمة الله وبركاته:

باختصار
هذه سلسة من الدروس اريد ان اضعها هنا ..
ستكون عن دوال الويندوز(API)
ستكون الدروس عن الاساسيات .. اساسيات دوال WIN API
كنت اريد تأجيلها الى بداية العطلة .. لكن الجدول في العطلة مزدحم .. <_<

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

الهدف من الدروس :محاولة لانتاج بذرة .. تكون نواة لبرامج قوية تنافس مثيلاتها العالمية
محاولة بناء قاعدة صلبة لك ... تسهم في اتقاننك لدوال api ..

المطلوب من الاعضاء الكرام :التفاعل .. ما اقصده بالتفاعل ( هو طرح الاسئلة ان وجدت + تصحيح اخطائي + اضافة بعض الامور المتعلقة بالدرس ) هذا هو التفاعل

كيف تستفيد من الدروس ؟تطبق كل درس اولا باول ... (لاتؤجل عمل اليوم الى الغد :rolleyes: )
اكتب الدرس المطلوب مرة ومرتين وثلاث ..
لاتنسى المراجع الاخرى مثل :
msdn

او

ملف المساعدة الموجود في موضوع " دليلك لتعلم لغة السي+win api...."
وحجمه 5 ميقا تقريبا
http://www.arabteam2...showtopic=63917


===
قد يكون البعض مشغول بالاختبارات لكن اعتذر .. لوضعها في هذا التوقيت ..

===
الدرس الاول سيكون خلال اليومين القادمين وستطرح الدروس بشكل متوالي باذن الله ..

Edited by الشـمري, 2005-05-16 - 01:19 PM.

  • 0

#2 Eisa Ayed

Eisa Ayed

    مشرف قسم ال Java

  • المشرفين القدامى
  • PipPipPipPipPip
  • 2,074 posts
  • الجنس:ذكر
  • الدولة : :Saudia
  • اهتمامات:رعي الغنم
  • علم الدولة :

Posted 2005-05-16 - 01:37 PM

جزاك الله خيـر
  • 0

#3 eng_3llam

eng_3llam

    مشرف قسم C++/C

  • المشرفين القدامى
  • PipPipPip
  • 810 posts
  • الجنس:ذكر
  • الدولة : :Egypt-Tanta
  • اهتمامات:•Reading especially in Programming, psychology and parapsychology.<br />•Writing articles at Programming in my spare time.<br />•Hearing Music.<br />•Playing football and ping pong.<br />•Play computer games and developing simple games.<br />

Posted 2005-05-16 - 03:27 PM

بسم الله الرحمن الرحيم
السلام عليكم
أحب اشكرك دايما يعجبنى شغلك وردودكعلى الاعضاء الغلابة اللى زى:D


أحب أشكرك جدا فأنا محتاج للAPI جدا جدا حتى اكون مبرمج قوى على تطبيقات الويندوز

بس فى حاجة :(
يعنى ممكن تأخر الوقت شوية صغيرين علشان الامتحانات
حيث انى فى هذة الفترة ادخل على المنتدى كل فترة كبيــــــــــرة جدا بسبب الامتحانات
و...
بس
فاياريت تعمل SHIFT للمعاد للامام شوية علشان نستفيد كلنا


وشكرا :D
  • 0

#4 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-16 - 07:46 PM

مشكورين .
اسف اخوي لايمكن تأجيله .. انا اعرف ان اغلبكم في امتحانات .. لكن اناساضع 5 درةس تقريبا وباقي الدروس بعد ثلاث ا سابيع
ساضع الدروس الاساسية الان حتى يكون كل شخص مهيء لتعلم الدروس المتقدمة ةالتي ستكون في العطلة..
اسف
  • 0

#5 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-16 - 10:55 PM

بسم الله الرحمن الرحيم

الدرس الاول : برنامجك الاول في win api .

امر مهم للغاية : ستكون جميع الدروس مبنية على الفيجوال سي .. لذا من الممكن ان تجد اختلاف بسيط في بعض الامور ,, اذا كنت تملك مصرف اخر
يكفيك لاتقان هذه الدروس معرفت بلغة السي الام ... يعني المتغيرات والمؤشرا و STRUCTURE .. يعني مو مهم تفهم بالكائنات.


سنبدأ أولى برامجنا في عالم الويندوز .. البرنامج سيعرض رسالة ..بس

من القائمة
FILE
اختر NEW
ثم
WIN32 APPLICATION
واحذر من ان تختار CONSOLE
اكتب اسم الملف كما تحب
ثم اضغط موافق
موافق
موافق
موافق
حتى تبدا :blink:

بعدها ضع ملف سورس جديد ..لماذا ؟ حتى نكتب فيه الكود ..... يا ذكي

لصق هالكود :

#include"windows.h" 
INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE HHGG,LPSTR lpCmdLine,int nShowCmd)
{

  MessageBox(NULL,"ALSLAM ALAIKUM >>> ARABTEAM2000.COM","FIRST PROGRAM",NULL);
return 0;
}

الشرح :
اولا نستدي الملف الرأسي .. وهو
windows.h
يوجد فيه اغلب دوال الويندوز .
INT WINAPI WinMain(HINSTANCE hInstance,HINSTANCE HHGG,LPSTR lpCmdLine,int nShowCmd)
هذه الدالة هي التي ينطلق منها البرنامج .. تذكر ايام السي ... ايام hello world

وش كنا نسوي ...

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

1- HINSTANCE hInstance
بارمتر مهم .. يعني مقبض نسخة البرنامج .. عارف انك مافهمت شي لكن ستفهم اكثر لاحقا ان شاء الله .
ولاحظ الاسم الذي اخترناه hInstance
وليس شرط ان تتقيد بهذا الاسم .. اختر ماتريد .. لكن يفضل التقيد بذلك حتى تتعود ..ولان اغلب الامثلة التي ستواجهك تتقيد بهذه التسمية .. وانتبه للحروف الكبيرة والصغيرة
2- HINSTANCE HHGG هذا البارمتر لايفيدك الان لانه قديم اكتب أي كلام

3- lpCmdLine هذالبارمتر لايفيد كثيراعلى الاقل في الوقت الحالي .

4- nShowCmd متغير نستخدمه اذا اردنا اظهار النافذة واللعب بها .. يعني نصغرها ونكبرها ... ستعرف ماذا اقصد لكن بعدين .
لكن تستطيع ان تكتب اي اسم لهذه البارمترات يعني ليس شرطا التقيد بتلك الاسماء

امر اخر وهو نوعية المتغيرات .. الويندوز يستخدم بعض الانواع المعرفة مثلا
INT
وتعني
Int
وهي معرفة على الشكل التالي
typedef int                 INT;

وايضا هناك نوع اخر مثلا
LPSTR وتعني ان المتغير هو متغير نصي يعني شبيهة بـ *char
فاذا رايت هذا النوع LPSTR فاعرف على طول انه يريد منك نص مثلا
LPSTR   NAME;
تعني ان المتغير NAME متغير نصي ..

ستجد الكثير من الانواع سنذكرها في وقتها .
-=-=-=-=-=-=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=--
ندخل داخل الدالة :

MessageBox

وتعني اظهار رسالة ..

وتتطلب عدة بارمترات ساشرح المهم الان والباقي ستفهمه مع الدروس القادمة .

البارمتر الاول : مقبض النافذة وكتبنا NULL

البارمتر الثاني : النص الذي تريده ان يكون داخل الرسالة

الثالث : عنوان الرسالة

الرابع : امور اخرى تتعلق بالرسالة مثل نوعها وايقونتها ووووو ..

الان شغل البرنامج وشف ,,,,,

طلعت لك رسالة صغيرة تلقي عليك التحية

صورة البرنامج
صورة


انا اعرف ان هناك الكثير من الامور المبهمة لكن ما اريدك ان تفهمه الان هو :

1- نستدعي الملف الرأسي WINDOWS
2- الدالة WinMain هي الدالة التي ينطلق منها البرنامج .
3- الدالة MessageBox فائدتها اظهار الرسائل ...
4- لاحظ الحروف الكبيرة والضغيرة ولاحظ ان كل كلمة جديدة نضع حرفها الاول كبير مثلا
MessageBox
عبارة عن كلمتين
Message وتعني رسالة
Box وتعني صندوق ..
وهي كلمتين جمعت بكلمة واحدة ووضعوا اول حرف كبير .... اريدك ان تنتبه لتلك الملاحظة .. وانت مع مرور الوقت رح تفهم كل شي بدون معلم ....


حمل الملف المرفق ...

Attached Files


Edited by الشـمري, 2005-05-16 - 11:01 PM.

  • 1

#6 eng_3llam

eng_3llam

    مشرف قسم C++/C

  • المشرفين القدامى
  • PipPipPip
  • 810 posts
  • الجنس:ذكر
  • الدولة : :Egypt-Tanta
  • اهتمامات:•Reading especially in Programming, psychology and parapsychology.<br />•Writing articles at Programming in my spare time.<br />•Hearing Music.<br />•Playing football and ping pong.<br />•Play computer games and developing simple games.<br />

Posted 2005-05-17 - 09:49 PM

اوكى جميل ....
أنا معاك وأشكرك على التفاعل
بس فى حاجة ان الHINSTANCE
دة يعبر عن البرنامج الحالى اللى شغال دلواتى
وأيضا لية انت عملت الone pramater اللى يتم مباصتة للMessageBox عبارة عن NULL

هل ممكن ان يكون عبارة عن الinstance اللى شغال حالا

- lpCmdLine هذالبارمتر لايفيد كثيراعلى الاقل في الوقت الحالي


أحب أوضح حاجة أن الparamter دة يستخدم فى حالة الخطأ
لو حدث خطأ وانت شغال فى الinstance حالا يعمل على return للرقم دة
علشان كدة الdata type بتاع الWinMain من النوع INT
  • 0

#7 احمد غريب

احمد غريب

    مشرف قسم الأسمبلي سابقاً

  • المشرفين القدامى
  • PipPipPipPipPip
  • 2,695 posts
  • الجنس:ذكر
  • الدولة : :بلاد شمس منتصف الليل
  • اهتمامات:اسمبلى <br />وندوز API<br />علم النفس<br />تنس الطاولة
  • علم الدولة :

Posted 2005-05-17 - 11:20 PM

السلام عليكم

بعد إذن الاخ الشمرى بعض الاضافات البسيطه للشرح.


الداله WinMain هى عباره عن داله جاهزه يستدعيها نظام التشغيل مباشرتاً وتاخذ 4 عناصر.
العنصر الاول هو مقبض البرنامج ككل وإسمه hInstance ليس من الضرورى هذه التسميه ولكن برامج الوندوز تتبع طريقه معينه فى إختيار الاسماء حتى يسهل على المبرمج تعديل البرنامج لاحقاً كذلك حتى يسهل على اى مبرمج اخر فهم الشفره والتعديل فيها إذا احتاج ذلك فى المستقبل.

طيب ما هى هذه القاعده ؟؟

كما ذكرنا فإن hInstance هو من نوع مقبض لذالك يبداء بحرف h وهى إختصار لكمة handle والتى تعنى باللغه الانجليزيه مقبض, لو إتبعنا هذه القاعده نستطيع ان نستنتج منها ان كل مقبض فى برامج الوندوز تبداء بحرف h وسوف تلاحظون ذلك فى جميع برامج الوندوز.

العنصر الثانى هو ايضاً من نوع مقبض وإسمه فى الواقع هو hPrevInstance وهذه اول مره ارى التسميه التى ذكرها الاخ الشمرى HHGG, على كل حال هذا المقبض هو للتاكد ما إذا كان هناك نسخه اخرى من نفس البرنامج فى الذاكره ولكن هذا العنصر لا يستخدم ولم ارى اى برنامج يعطيه قيمه عند إستدعاء الداله WinMain وقيمته دائماً تحتوى القيمه NULL, عوضاً عنه هناك طريقه اخرى تسمى Mutex وتستخدم للتاكد من وجود البرنامج فى الذاكره وهى عباره عن ذاكره مشتركه إذا قام عنصر من البرنامج بحجزها لا يستطيع عنصر اخر ان يقلع. بمعنى اخر إذا اردت ان تمنع المستخدم من تشغيل البرنامج مرتين فى جهاز واحد تستخدم الداله CreateMutex وبهذه الطريقه تتاكد من ما إذا كان البرنامج قيد العمل ام لا, وهذه الطريقه تستخدم فى برامج عديده وربما اشهرها هو الماسنجر.

العنصر الثالث هو من نوع string ويبداء بالحرفين LP وذلك لانه من نوع long pointer وهذا العنصر هو للحصول على المعطيات التى يدخلها المستخدم فى شاشة الconsole على سبيل المثال هناك برامج تستدعى إدخال معطيات فى شاشة الكونسلى مثل برنامج xcopy للنسخ, عندما تريد نسخ ملف من مكان إلى اخر لا يكفى ان تكتب xcopy ولكن لا بد ان تدخل إسم الملف الذى تريد ان تقوم بنسخه وايضاُ المكان الذى تريد ان تنسخه إليه, فى اغلب الاحيان وخاصتاً فى برامج الوندوز لا نحتاج إلى إدخال معطيات معى إسم البرنامج لذالك هذه الداله فى الغلب تحتوى القيمه NULL.
إذاً LPSTR هى عباره عن مؤشر (pointer ) فى الذاكره يحتوى على سطر الاوامر الذى ادخله المستخدم.

العنصر الاخير للداله WinMain هى دالة الحاله, اى حالة النافذه, بهذه الداله تستطيع ان تتحكم فى إظهار النافذه او إخفائها او تصغير الحجم الخ, بما اننا لم نستخدم نافذه نستطيع التحكم فى شكله, إذاً هذه الداله لاقيمة لها فى برنامجنا هذا ولكنها مهمه فى المستقبل عندما نقوم بإنشاء نافذه كامله.


الان ننتقل إلى الداله MessageBox هذه الداله هى عباره عن نافذه جاهزه لا نستطيع بالقيام بالتحكم الكامل بها, هذه الدله تاخذ 4 عناصر.

العنصر الاول هو عباره عن مقبض لاحظ إسم الدله, إنها تبداء بحرف h

int MessageBox( HWND hWnd,    LPCTSTR lpText,    LPCTSTR lpCaption,    UINT uType);
ولكنه ليس مقبض البرنامج وإنما مقبض نافذه, لان مقبض البرنامج إسمه hInstance ونحن فى هذا البرنامج لا نملك نافذه لذالك لا نستطيع ان نعطى الدله hWin اى قيمه هنا.

العنصر الثانى ولاحظ, الاسم هنا يبداء بـLP وكما ذكرنا سابقاً فإن اسماء العناصر التى تبداء بهذه الاحرف ماهى إلا مؤشر لنص فى الذاكره, إذاً المطلوب هنا هو مؤشر من نوع char او يمكنك وضع النص داخل الداله والسى بلس بلس سيحولها إلى موشر لاحقاً. طبعاً فى لغه مثل الاسمبلى لا نضع string وإنما نحن مجبرون من وضع مؤشر من نوع char ولكن السى بلس بلس يسهل الامر ويسمح بوضع string مباشرتاً داخل الداله.

نفس الشيئ مع الداله التى تليها.

والداله الاخيره هى نوع UINT وكما نلاحظ فإن الارقام الموجبه UINT تبداء بالحرف u لتعرف المبرمج انها من ذلك النوع. هذا الرقم هو عباره عن نوع من انواع نوافذ الـMessageBox هناك عدة انواع على سبيل المثل الرساله التى تظهر بزر OK والنافذه التى تظهر بزر OK و Cancel الخ, كل واحده من هذه الرسائل لها رقم معين, ولكن للتسهيل على المبرمج قامت مايكروسفت بإعطاء هذه الرسائل اسماء ووضعت المعرف فى ملف windows.h على سبيل المثال الرساله التى تعطى معلومات ويوجد بها زر OK إسمها MB_OK يعنى يمكن ان تضع مكان الداله الرقم 0 او المعرف MB_OK وستحصل على نفس النتيجه, على فكره NULL تعنى 0 ايضاً لذلك حصل على النافذه بزر OK او موافق بالعربى, إذا اردت ان تحصل على رساله بزر OK و cancle ما عليك إلا ان تستبدل القيمه NULL بالقيمه 1 او المعرف MB_OKCANCLE.

واخيراً الداله return 0 مهمه لان البرنامج يعطى رسالة خطاء إذا لم يجد هذه الداله إعتقاداً منه ان خلل ما قد حدث, ف الداله return 0 هى عباره عن رساله للنظام التشغيل انه قد وصل إلى نهاية البرنامج بدون حدوث اخطاء.

إلى قراء كل دا وفهم انا قلت إيه يبقى جدع لانى انا شخصياً مش فاهم .


والسلام عليكم
  • 1

#8 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-17 - 11:35 PM

شكرا على الضافة يا اخوان وهذا ما اريده ..

على العموم انا لم اشرح كل شيء واعرف ذلك لان هنا بعض الامور من الصعب فهمها قبل ان د ندخل بأنشاء النافذة .. ونحو ذلك

العنصر الثانى هو ايضاً من نوع مقبض وإسمه فى الواقع هو hPrevInstance وهذه اول مره ارى التسميه التى ذكرها الاخ الشمرى HHGG

:lol:

انا تعمدت هذا الاسم لعدة اسباب منها :
1- لاثبت انك تستطيع تسميتها كما تريد ..
2- لاثبت انها ملها داعي .. فهي لانظمة 16 بت على ما اظن (( متأكد ))

-------
شرح دالة الرسالة MESSAGEBOX
ستكون بالتفصيل في الدرس الخامس ..
لكن الاخ احمد ما قصر ... من الان شرحها B)
وهذا اللي اريده ..

---

وأيضا لية انت عملت الone pramater اللى يتم مباصتة للMessageBox عبارة عن NULL


سؤال ذكي ... وعرفت جوابه قبل ايام .؟.. بعد ان قمت بتجريب الكود ... .

ساشرح السبب في الدرس الخامس((( السبب غريب ولا يخطر على بال اي واحد >>> :blink: ))

Edited by الشـمري, 2005-05-17 - 11:37 PM.

  • 0

#9 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-17 - 11:47 PM

اليوم درسنا رح يكون عن كيفية انشاء نافذة من نوع SDI
الجزء الاول

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

اقرأ مايلي حبة حبة ولاتخلي أي سي الا وتقرأه .. والا فاني غير مسؤول عن عدم اتقانك للدرس :)



ماذا تعني كلمة نافذة :

هي واجهة البرنامج والتي تكون مربعة الشكل ولها بعض الخصائص ..لايكفي هذا التعريف ..

كل ماتراه امامك نافذة ...

زر الامر نافذة

صندوق النص نافذة .

مربع الرسالة نافذة .

زر الخيار : نافذة ..........

هي عبارة عن نوافذ .. ولكن هناك انواع من النوافذ ان صح التعبير وهي :

نافذة الاب (وهي الحاضن )

نافذة الابن ........

انظر لهذه الصورة وستعرف ماذا اقصد :

صورة




طيب السؤال :: كيف يفرق نظام التشغيل بين النافذة الفلانية والنافذة الفلانية .....

جواب : بواسطة مقبض النافذة ..

ماهو مقبض النافذة ؟HWND

اولا نقول فائدته ..

النظام يعطي لكل نافذة تنشئ مقبض خاص بها هذا المقبض عبارة عن رقم ...

ومن المستحيل ان توجد نافذتين لهما نفس الرقم :::

هذه النقطة مهمة للغاية ....

===



عرفنا الان مصطلح نافذة .. ومصطلح مقبض .. وش بقى ...

الرسائل :

هذه احد اهم المفاهيم على الاطلاق ..

ماذا نقصد بالرسائل ::

نقرة الماوس... ضغطة على الكيبورد .. تحرك مؤشر الفارة .. اغلاق النافذة .. تغيير حجم النافذة ..

وووووووووووووووووووووووووووووو ... الخ الخ الخ !!!!



اعتقد انك فهمت .. لكن هناك مفهوم اخر وهو طابور الرسائل ..

اذا كان جهازك من عهد العصور الحجرية .. فلابد انه مر عليك في احد الايام ... ان جهازك هنّق .. يعني توقف عن الاستجابة .. ثم قمت باستخدام القوة .. فضغطت 22 ضغطة على الكيبورد و19 ضغطة على الماوس .. ولكن لاحياة لمن تنادي فالجهاز معلق .. وفجأة كل الاحداث التي قمت بها من ساعات قليلة ماضية جدثت ... فلقد عاد الجهاز للاستجابة .. فما السبب الذي جعل الجهاز يستجيب لرسائل قديمة .. السبب هو طابور الرسائل...

فالاحداث او الرسائل . تمسك سرا :) يعني تصف طابور تتنظر دورها الاول فالاول.. وماترجع لبرنامجك الا وقد نفذت المهمة ((( الا عند استخدام دوال معينة اخرى )))..

===

تلك كانت هي اهم المفاهيم التي يجب عليك اتقانها ... وقبل ان تتقدم خطوة الى الامام تذكر. ان تلك المفاهيم هي القلب النابض لنظام ويندوز .....

===



كيف تنشئ النافذة ؟

هناك اربع خطوات :

1- انشاء STRUCTURE يحتوي على خصائص الفئة الاساسية للنافذة .. مثلا مؤشر الماوس ولون الخلفية ..

ثم تسجل الفئة .

2- انشاء النافذة عن طريق دالة معينة .ثم تظهرها عن طريق دالة اخرى

3- تدخل برنامجك في دوامة الرسائل .. يعني في WHILE لانك تتنظر أي رسالة ترد لبرنامجك .

4- تفسر الرسائل ..يعني اذا ضغط الزر الايمن وش يصير واذا اغلق النافذة وش يصير ..



الخطوات السابقة ستنفذها في جميع برامجك ومن كثر ماتكتبها ستحفظها وتفهما عن ظهر قلب ..



انتهى الجزء الاول .. الجزء القادم سيكون كتابة اكواد بعيدا عن كثرة الكلام .. سلام

Edited by الشـمري, 2005-05-17 - 11:49 PM.

  • 0

#10 ikossan

ikossan

    مشرف أقسام الإلكترونيات

  • المشرفين القدامى
  • PipPipPip
  • 790 posts
  • الجنس:ذكر
  • الدولة : :المغرب
  • علم الدولة :

Posted 2005-05-18 - 12:44 AM

ما شاء الله عليك أخي الشـمري.
والله ما قصرت, وأظن أن كل مبتدأ في البرمجة في ويندوز يمكنه الأعتماد على بعض منصات التطوير السريع RAD مثل C++Builder لكن دون إهمال معرفة بعض دوال API في ويندوز.
لقد بدأت في سلسلة دروس بسيطة للغاية في برمجة تطبيقات ويندوز بلغة ديلفي -باسكال باستعمال دوال Api فقط دون الإعتماد على بعض المكتبات الخاصة بمصرف الشركة وهي مكتبات VCL.
البرمجة بدوال API لويندوز باستعمال لغة الديلفي-باسكال الشيئية.

أستمر وستجد كل الإخوة متابعين B) .

  • 0

#11 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-18 - 11:19 PM

انشاء نافذة من نوع SDI

الجزء الثاني:


الان انشئ مشروع جديد كما فعلنا في الدرس الاول ...

اضف هذا الكود :
#include <windows.h>
وهذا تم شرحه ..
اضف هذه الدالة ..
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
هنا نعلن عن الدالة التي نريد ان نستخدمها لاحقا ..
كما تعلم حتى نستخدم الدالة بشكل صحيح يجب الاعلان عن الدالة اولا اذا كنت تريد ان تكتب محتوياتها بعد الدالة الرئيسية WinMain

حتى لا يتشوش ذهنك تذكر مثلا

Int func();

Main()
{


}

Int func()
{
Cout<<"hello";
}
ما فعلناه مع السي العادية نفعله مع دوال الويندوز لاننا في عالم السي :blink:
-----
نعود لدالتنا .. هذه الدالة سأشرحها بعد قليل ...

الان الصق الكود التالي :
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
{
	WNDCLASS wc;
	wc.style   = 0;
	wc.lpfnWndProc  = WndProc;
	wc.cbClsExtra  = 0;
	wc.cbWndExtra  = 0;
	wc.hInstance  = hInstance;
	wc.hIcon   = LoadIcon(NULL, IDI_APPLICATION);
	wc.hCursor   = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = g_szClassName;

لاتخاف ...

اولا انشأنا تركيب جديد من نوع WNDCLASS ، واسميناه wc وتستطيع تسميته كما تريد ..
هذا التركيب هو القاعدة الاساسية للنافذة التي سننشئها بعد قليل ان شاء الله .
نستفيد من هذا التركيب في تحميل الايقونة الخاصة بنافذتنا .. التحكم بلون خلفية النافذة وغير ذلك .. ونحدد الخصائص كالتالي ..
wc.style   = 0;
الستايل العام... وضعه صفر الان ..

wc.lpfnWndProc  = WndProc;
مهم...وهواسم دالة الرسائل..الدالة التي تتحكم بالرسائل ... طبعا تسميها كما تريد
wc.cbClsExtra  = 0;
غالبا صفر
wc.cbWndExtra  = 0;
غالبا صفر
ماسبق غير مهم حاليا .. وهو خاص بذاكرة البرنامج .. هل تحجز له ذاكرة اضافية ... يعني حول هذا المعنى ..
wc.hInstance  = hInstance
اسم مقبض الفئة ( او نقول برنامجنا ) وهو مهم للغاية; لاحظ ان hInstance هو نفسه الذي اعلنا عنه في الدالة الرئيسية
WinMain(HINSTANCE hInstance,......


wc.hIcon   = LoadIcon(NULL, IDI_APPLICATION);
ايقونة البرنامج ... لكن كيف نعين الايقونة ...
عن طريق الدالة LoadIcon...
IDI_APPLICATION :: هذا يدل على نوع الايقونة تستطيع تغير نوعهاو تختار مارتريد مثلا
IDI_QUESTIONقد تسأل سؤال وتقول كيف احمل ايقونتي الخاصة بدلا من هذه الثوابت ..
ستعرف الجواب في دروس قادمة بإذن الله .
لكن لاحظ بادئة الثابت
ID
ثم اول حرف من كلمة ICON
I
ثم
_
ثم
اسم الايقونة التي تريد .....
لاحظ ان الايقونة هي معرفة كرقم
#define IDI_APPLICATION     32512
ولكن بدل من حفظ الرقم .. قام مبرمجي الويندوز بوضع ثوابت للتسهيل .

wc.hCursor   = LoadCursor(NULL, IDC_ARROW);
مؤشر الفأرة ونحصل عليه باستخدام الدالة LoadCursor
نضع اسم المؤشر وليكن
IDC_ARROWوتستطيع استخدام مؤشرات اخرى مثلا
IDC_WAITوتستطيع وضع مؤشر خاص بك ترسمه بنفسك او تستورده ... ستعرف كيف ذلك بالدروس القادمة ان شاء الله .
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
لون خلفية النافذة .. غير الرقم واحد باي رقم من واحد الى 26 على ما اعتقد .. جرب وستخرج لك الوان جديدة لكن لاتتعدى 26 ... والا ..
وهناك طريقة اخرى لتعيين لون للخلفية هكذا .
wc.hbrBackground = (HBRUSH)  GetStockObject( WHITE_BRUSH );
وهي باستخدام الدالة GetStockObject.. وغير الثابت الداخلي .. بثوابت اخرى مثلا
BLACK_BRUSH
GRAY_BRUSH
DKGRAY_BRUSH


اعرف ان هناك بعض الاشياء التي لم تفهمها مثلا HBRUSH،،،، GetStockObject ونحوها لكن ان شاء الله بالدروس الجاية رح تفهمها لانها متقدمة نوع ما ..
wc.lpszMenuName  = NULL;
هل تريد قائمة ... لان لانريد اذن وضعنا NULL
wc.lpszClassName = " arab team ";
مهم .. اسم الفئة وهو نص .. اكتب ماتريد .

خلاص .. الان انتهينا عينا الخصائص ... وبقي شي واحد وهو تسجيل الفئة لكن كيف ؟
هكذا ..
RegisterClass(&wc);
ولاحظ الدالة .. فهي تسجل الفئة وتطلب بارمتر واحد وهو الفئة ... طبعا تمرر العنوان .. لان البارمتر مؤشر .اذا نمرر له عنوان
------
هل توجد صعوبة ؟؟؟
قد يكون الكود كثير لكن مع كثرة الكتابة ستسهل ان شاء لله ..

الان خلصنا من الفئة ...

ننتقل الى النافذة ..
الصق هذا الكود

HWND hwnd;
	hwnd = CreateWindow(
  " arab team ",
  "The title of my window",
  WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
  NULL, NULL, hInstance, NULL);
الامر يحتاج الى تركيز ...
اولا انشأنا مقبض نافذة جديد وهو مهم لاننا نريد انشاء نافذة , وكما قلنا لكل نافذة مقبض .. حتى يميز النظام بين النوافذ.. لانشاء مقبض نافذة نكتب
HWND hwnd;
لاحظ حرف H
في HWND
وهو يعني مقبض أي HANDLE
وهناك انواع اخرى من المقابض مثلا ، مقبض الفرشاة .. ومقبض الصورة وغيرها ،،،،
اما WND فهي اختصار وتعني نافذة WINDOW
...
الان ننشئ النافذة عن طريق الدالة الشهيرة .. CreateWindow ولكن لاننسى اسناد مقبض النافذة بالدالة CreateWindow
حيث ان الدالة CreateWindow تنشئ النافذة وتعيد قيمة النافذة .. هذا القيمة نسندها للمقبض الذي انشأناه hwnd
هكذا

hwnd = CreateWindow(
الان ندخل الى تفاصيل الدالة :

البارمتر الاول : هو اسم التركيب الذي انشأته
wc.lpszClassName = " arab team ";
االثاني : هو اسم النافذة وهو الذي يظهر على شريط العنوان العلوي
الثالث : الستايل العام للنافذة.. الحدود زر التكبير والتصغير وغيرها .. اخترنا WS_OVERLAPPEDWINDOW
CW_USEDEFAULT, CW_USEDEFAULT, 240, 120,
هذه تعين موقع النافذة واخترنا الموقع الافتراضي "" السيني والصادي"" CW_USEDEFAULT, CW_USEDEFAULT
و 240 و 120 هي طول وعرض النافذة

بعد ذلك وضعنا NULL حيث يطلب هذا البارمتر ما يسمى بـ hWndParent
ويعني هل النافذة اب او ابنة.. وهنا نافذتنا الاب وبالتالي نضع NULL
التاسع: بم ان برنامجنا لايحتوي على قائمة وضعنا NULL
والبارمتر قبل الاخير وضعنا اسم مقبض البرنامج hInstance
والاخير NULL غالبا ..
------

الان نظهر النافذة عن طريق الدالة
ShowWindow(hwnd, nCmdShow);
لاحظ الدالة .. تريد منك بارمترين .. الاول .. مقبض النافذة التي تريد اظهارها .. الثاني تستخدم البارمتر الذي وضعته في الدالة الرئيسية ...
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
	LPSTR lpCmdLine, int nCmdShow)
ثم نحدث النافذة
UpdateWindow(hwnd);
الان انتهينا .... انشأنا الفئة ( سجلنا الفئة) ثم صنعنا نافذة .. أظهرناها وحدثناها ..
الخطوة القادمة
الخطوة الثالثة دوامة الرسائل
ماهي الرسائل
نقرة الماوس او تحريكها
ضغطة الكيبورد
تحريك النافذة او تصغيرها ونحو ذلك
وغيرها من الرسائل
---
فنحن ننتظر اي رسالة ترد الى النافذة لذا نضعها في دوامة التكرار ..
ولكن قبل ذلك نحن ننشئ فئة(او structure)
للرسائل هكذا
MSG Msg;
وسمها ماتريد..
الصق هذا الكود ..
while(GetMessage(&Msg, NULL, 0, 0) > 0)
	{
  TranslateMessage(&Msg);
  DispatchMessage(&Msg);
	}
	return Msg.wParam;
}
اولا نقول ..
مادام برنامجنا يستقبل الرسائل (( ونعرف ذلك عن طريق الدالة GetMessage)) فقم بما يأتي :
 TranslateMessage(&Msg);
تعرف يا ويندوز على الرسالة ..
ثم
DispatchMessage(&Msg);
ارسلها الى من يهمه الامر(( الى دوال تفسير الرسائل ))
تلك الصيغة تكاد تكون ثابتة الا نادرا .. وهي طريقة مفهومة على ما اعتقد ولا تحتاج المزيد من التفصيل ..

باخر الدالة الرئيسية البرنامج يعيد
return Msg.wParam;
الا نالخطوة الرابعة والاخيرة .. وهي تفسير الرسائل ..

الان ندخل بدالة فرعية وهي دالة الرسائل
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
  case WM_CLOSE:
  	DestroyWindow(hwnd);
  break;
  case WM_DESTROY:
  	PostQuitMessage(0);
  break;
  default:
  	return DefWindowProc(hwnd, msg, wParam, lParam);
	}
	return 0;
}

الشرح
LRESULT CALLBACK WndProc(HWND hwnd, 
UINT msg, 
WPARAM wParam,
 LPARAM lParam)
صيغة كتابة الدالة ولاحظ ان اسمها
WndProcوهو نفس الذي كتبناه عند تسجيل النافذة
wc.lpfnWndProc = [COLOR=red]WndProc[/COLOR];
وتتطلب اربع بارامترات .. لاتهتم كثيرا بتفاصيل الدالة كل ما عليك التركيز على اسمها فقط..
ولاننسى البارمترات.. من اهم البارامترات الثاني UINT msg وهو يعني نوع الرسالة
الحاضرة... ومعنى UINT يعني عدد من نوع unsigned int وهو عدد يبين نوع الرسالة ..

وكما قلت لاتخشى هذه الدالة..

switch(msg)

نقول له اختبر الرسالة الواردة
ولاحظ msg وهي التي في البارمترات

هل هي رسالة اغلاق النافذة
 case WM_CLOSE:
اذا اعدم النافذة :)
 	DestroyWindow(hwnd);
وننهي النافذة عن طريق الدالة DestroyWindow التي نمرر لها النافذة المطلوبة وهي هنا hwnd وهي نفسها التي كتبناها في البرارامتر الاول
WndProc(HWND hwnd, UINT msg,.....
  case WM_DESTROY:
  	PostQuitMessage(0);
اذا تم انهاء البرنامج

والا اذا كانت اي رسالة اخرى تعامل معها على كيفك ياويندوز
 default:
  	return DefWindowProc(hwnd, msg, wParam, lParam);
لاحظ الرسائل فهي تبدأ بـ WM_


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

الجزء القادم سنتحدث عن نفس هذا الدرس لكن .. فقط كتعليقات وتلميحات ... وتوسع اكثر ... ان شاء الله ..

لاتنسونا من دعائكم ..

قبل ما اخلص ... (( وش رايكم بالوان الموضوع .. احمر وازرق واخضر <_< كأنه كورنيش ))

ولاتنسون تصحيح الاخطاء واضافات من هنا وهناك السلام عليكم ..

الملف في المرفقات ..

Attached Files


Edited by الشـمري, 2005-05-18 - 11:24 PM.

  • 0

#12 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-21 - 01:40 PM

تأخرت قليلا ..
ساطرح باقي الدروس خلال الثلاث ايام القادمة . .
  • 0

#13 eng_3llam

eng_3llam

    مشرف قسم C++/C

  • المشرفين القدامى
  • PipPipPip
  • 810 posts
  • الجنس:ذكر
  • الدولة : :Egypt-Tanta
  • اهتمامات:•Reading especially in Programming, psychology and parapsychology.<br />•Writing articles at Programming in my spare time.<br />•Hearing Music.<br />•Playing football and ping pong.<br />•Play computer games and developing simple games.<br />

Posted 2005-05-22 - 08:24 PM

وأحنــــــــــــــــــــــــــــا فى أنتظارك :)
  • 0

#14 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-24 - 02:08 PM

تأخرت بالدرس صح ..


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

اكيد انكم تدرون ان هذه الدالة
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)

ينطلق منها البرنامج .. الا اننا في هذا الدرس سوف نجري بعض التغييرات حيث لن نقوم بتعريف المتغيرات في هذه الدالة يعني سيكون شكلها
INT WINAPI WinMain( HINSTANCE , HINSTANCE , LPSTR , INT )
اذا قمنا بهذا العمل .. (( كما تقوم به بعض الدروس والكتب )") .. فإنه يترتب عليه عدة امور ..
كنا في السابق نعرف hinstance جديد في بارمترات الدالة ثم ندخله بالتركيب
WNDCLASS
هكذا
wc.hInstance=hInstance;
لكن نحن لم نعرف HINSTANCE في بارمترات الدالة

اذا سيصدر المصرف خطأ يقول ..
wc.hInstance=hInstance;
غير معرف .. او غير معلن عنه ..
هذا شي طبيعي اذا مالحل ..
الحل كالتالي :
   wc.hInstance = GetModuleHandle(NULL);
الان استطعنا ان نحل المشكلة عن طريق الدلة GetModuleHandle

وايضا نفس الامر مع الدالة
    hWnd = CreateWindowEx(0, 
        "api", "api lessons", 
        WS_OVERLAPPEDWINDOW, 100,100,400,200, 
        NULL,NULL,wc.hInstance,0);
لاحظ قلنا wc.hInstance ولم نقل hInstance فقط لانها غير معرفة في بامترات الدالة الرئيسية WinMain


مشكلة اخرى ..
نعلم انه عندما اردنا اظهار النافذة استخدمنا الدالة ShowWindow
التي تطلب مقبض النافذة ومتغير من نوع int نكون قد عرفناه بالدالة الرئيسية هكذا .
ShowWindow(hwnd, ishow);
البارمتر الثاني اعلنا عنه في الدالة الرئيسية

int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
ثم نظهر النافذة

لكن لو عملت تلك الطريقة وانت لم تعلن عن المتغيرات التي تريد ي بارمترات الدالة عندها سيصدر المصرف خطأ يقول ..
لا اعرف عن المتغير ishow شي . وهذا شي طبيعي ..
مالحل ؟
الحل
هو تستخدم احدى الثوابت بدل المتغير لاظهار النافذة او القيام بأي عما اخر . هكذا
ShowWindow(hWnd,SW_SHOW);
اذا الثابت SW_SHOW يقوم باظهار النافذة ..
حلينا المشكلة ..
قد يسأل سائل مالفائدة من هذا التعقيد كله .. ليش ما نكتب دالة واحدة ونعرف مانريد ونتقيد بها الى الابد دون اي فلسفة ..
اقول
الهدف ليس تعقيد انما قد يكون اسلوب في الكتابة وايضا ينبغي عليك معرفة عدة طرق حتى تتفهم بعض الاكواد .. والدروس . اضف الى ان لكل طريقة حسنات وسيئات ..
انا افضل تعريف الدالة الرئيسية بالاسلوب الاخر ..
INT WINAPI WinMain( HINSTANCE , HINSTANCE , LPSTR , INT )
فهذا اسهل ..
واستطيع انشا مقبض نسة البرنامج .. بالدالة GetModuleHandle
واظهر النافذة بتمرير الثابت SW_SHOW
فهذا اسهل .. ولكل مبرمج طريقته ..

المزيد عن الدالة ShowWindow
هذه الدالة تستطيع تمرير عدد من الثوابت اليها لكل ثابت وظيفته ..
الثابت الاول SW_SHOW لاظهار النافذة وهناك ثوابت اخرى .. مثلا
الثابت SW_MAXIMIZE يقوم باظهار النافذة مكبرة ..
هكذا
   ShowWindow(hWnd,SW_MAXIMIZE);

وهناك ثوابت اخهرى قم بتجريبها وستعرف معناها .. منها :
1- SW_MINIMIZE
2- SW_RESTORE
3- SW_MAX
4- SW_HIDE اخفاء النافذة
5- SW_SHOWDEFAULT
.
.
.
الخ الخ الخ خخخخخخخخخخخخخخخخ .
-----
الان سنلعب بأمور اخرى ..

تعرفون ان التركيب WNDCLASS يقوم باعداد الشكل العام للنافذة .. لكن هناك تركيب اخر له نفس الاسم ولكن يزاد عليه حرفين ex هكذا .. WNDCLASSEX
وهذا يعني ان التركيب السابق هو موسع .. يعني اضيفت اليه بعض الاضافات ..
كما تعلمون التركيب WNDCLASS له 10 اعضاء وهي
    UINT    style; 
    WNDPROC lpfnWndProc; 
    int     cbClsExtra; 
    int     cbWndExtra; 
    HANDLE  hInstance; 
    HICON   hIcon; 
    HCURSOR hCursor; 
    HBRUSH  hbrBackground; 
    LPCTSTR lpszMenuName; 
    LPCTSTR lpszClassName;


بينما التركيب WNDCLASSEX له 12 عضو وهو نفس التركيب السابق لكن وسع واضيف اليه عضوين :
cbSize
وتعني حجم التركيب ونحصل عليه باستخدام sizeof المعروفة ..
   wc.cbSize = sizeof(wc);
hIconSm
ايقونة صغيرة



وعندما نريد تسجيل التركيب نستخدم الدالة الموسعة ايضا ..
RegisterClassEx هكذا
RegisterClassEx(&wc);

طبعا مع تعمقك في عالم دوال الويندوز ستلاحظ ان هنالك العديد من الدوال والتراكيب تنتهي بحرفي ex وهذا يعني انها دوال او تلراكيب موسعة ..

حيث كان مبرمجي الويندوز يستخدمون الداول العادية ومع مرور الووقت طوروها واضافوا اليها بعض التعديلات .. .
من الدوال التي وسعت ايضا دال ةصناعة اانافذة لشهيرة .. CreateWindow
اصبحت CreateWindowEx
ومن الاضافات التي اضيف اليها .. هي اضافة واحدة ...
الستايل الموسع يعني
dwExStyle
ويتحكم بالشكل العام للنافذة .. من الثوابت الممررة له هي
WS_EX_ACCEPTFILES
او
WS_EX_LEFT
او
WS_EX_TOPMOST
وهناك الكثير من الثوابت لكن راجع المراجع وستجد ماتريد .
من افضلها المرجع
win32 programmer's reference
وهو موجود في موضوع .. دليلك لتعلم السي وapi ...


اعتقد الان الامر واضح ....
----
تعديلات ..

الان سنقوم بتعديلات بخصائص النافذة والمؤشر والايقونة والالوان وووو ..
خصائص النافذة ..

بالبارمتر الرابع بالدالة CreateWindowEx
تستطيع تمرير اليه عدة ثوابت وهي تحدد الشكل العام للنافذة مثلا لو كتبت
WS_BORDER يصبح للنافذة تحديد .. او WS_HSCROLL والذي سيضع شريط تمرير افقي بالنافذة ,, وغيرها الكثير من الثوابت ومن الصعب شرحها كلها .. لكن راجع المراجع وستجد ماتريد ..

في الملف المرفق قمت بعمل بعض التأثيرات على النافذة وتغير مظهرها ..


الان دعونا نغير في البارمتر الاول ..

ضع الثابت
WS_EX_RIGHT
الثابت السابق يقوم بتغيير اتجاه النافذة من اليسار الى اليمين .. يعني مفيد لمن برامجه عربية ..
مثلا ضع الثابت
WS_EX_LEFT
الذي يجعل اتجاه النافذة الى اليسار وهو الافتراضي .. طبعا هناك لعديد من الخصائص لكن كما قلت عندك المراجع

===
بالنسبة لاحد اعضاء التركيب WNDCLASS وهو style
مرر له الثةابت التي تريد ومنها
wc.style = CS_VREDRAW|CS_HREDRAW|CS_OWNDC
وتلك الثوابت تغير خصائص عامة بالنافذة .. ومنها الثوابت السابقة ..
الثوابت كثيرة لكن جرب وابحث وستتعلم من التجريب فقط .


مؤشر الماوس :
تستطيع ان تغير المؤشر كمل كما تريد :
LoadCursor(NULL, IDC_ARROW );

غير IDC_ARROW الى :
IDC_WAIT
IDC_SIZE
IDC_SIZEWE
IDC_CROSS
طبعا هناك الكثير ..

الايقونة .
تستطيع تغيير الايقونة الى اي ايقونة تريد مثلا
IDI_QUESTION
IDI_EXCLAMATION
IDI_ASTERISK
IDI_HAND
مثال :
LoadIcon(NULL, IDI_HAND );

ونفس الامر مع الايقونة الصغير ة ..

مالفرق بين الايقونة الصغيرة والكبيرة..

الصغيرة
   wc.hIconSm = LoadIcon(NULL,  IDI_HAND );
الايقونة التي تظهر بالنافذة .. اما الكبيرة التي تظهر عندما تضغط Alt+Tab


--------
التأكد من ان كل شيء على مايرام ..
==
عندما تريد انشاء تركيب مالذي سيضمن لك ان كل شيء يسير على مايرام ..

عندما تنشىء نافذة مالذي سيضمن لك ان كل شيء سيسير على مايرام ..

تخيل صار خطأ .. وقام برنامجك بإغلاق نفسه دون سابق انذار ..
اكيد ان المستخدم سيقول "" الشرهة مو عليك يا مبرمج .. الشرهة على اللي يشتري برنامجك "" ثم يقوم بحذف برنامجك من الجهاز وهو يدعو عليك .. :(

لكن لو اظهرت رسالة لو حدث خطأ .. وقلت له يا عم .. البرنامج صار فيه خطأ ويغلق الان .. اسفين وسامحنا وحقك علينا .. عندها المستخدم على الاقل سيكون افضل حال..
خلصنا بربرة !!!

ماريد قوله هو ان تتأكد عندما تقول باستخدام بعض الدوال ان كل شي على مايرام .. هكذا ..
if(!RegisterClassEx(&wc))
	{
  MessageBox(NULL,"oooops","Arabteam",NULL);
  return 0;
    }
انت الان سجلت النافذة كالعادة .. لكن تأكدت وقلت .. اذا حدث خطأ بالبرنامج ((اظهر
رسالة واخرج من البرنامج .. (( لاحظ اننا استخدمنا ! لهذا العمل .. طبعا هذا الرمز من رموز السي راجع السي وستعرفه ..


وسنتأكد من ان النافذة انشئت على مايرام والا اظهر رسالة واخرج من البرنامج..


  if(hWnd==NULL)
    	{
  MessageBox(NULL,"OOOOPS","ARABTEAM",NULL);
  return 0;
  }

لاحظ
قلنا لو كانت قيمة المقبض NULL يعني لم يحصل على قيمة فاظهر رسالة واخرج من البرنامج ..

لكن متى لايعود بقيمة .؟؟
الدالة CreateWindowEx اذا قامت بعملها تعيد رقم هذا الرقم نساويه بمقبض النافذةHWND وبالتاتلي سيكون هذا الرقم فريد من نوعه .. عن بالقي النةوافذ لكن لو لم تعيد قيمة عندها لن تكون لـHWND اي قيمة يعني NULL وبالتالي سنخرج من البرنامج . .

طبعا الدرس يبدو غير منظم لكن .. كل ماهدفت اليه من هذا الدرس هو اعطائك مختلف المعلومات التي تجعلك مستوعب لاكبر كم من المعلومات

صورة البرنامج بعد كل هذا الكلام ..

صورة



الان حمل الملف المرفق وخذ كوب من الشاي او القهوة( العربية ) وتمتع بالمناظر الخلابة للدرس الثاني المعدل .. سلام .

Attached Files


Edited by الشـمري, 2005-05-24 - 02:09 PM.

  • 0

#15 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-25 - 11:31 AM

الدرس الثالث
اليوم درسنا سيكون باذن الله عن الرسالة ...
طبعا سبق ان وضعت هذا الدرس في منتدى برمجة الالعاب .. لكن سأعيد صياغته وسأضيف اليه عدة اضافات .. إن شاء الله .


لعمل رسالة تظهر للمستخدم نستخدم الداله التالية:
MessageBox
لاحظ الحروف الكبيرة والصغيرة...
وصيغتها
MessageBox(HWND , LPCTSTR , LPCTSTR  , UINT  );
البارمترات
1- مقبض النافذه
2-نص الرسالة
3-العنوان
4-نوع الرسالة
ملاحظة صغيرة .. LPCTSTR دائما تعني نص كانك تقول*char
فاي دالة في مربعها الاصفر الذي يظهر عندما تفتح اقواس
تطلب بارمتر معرف كـ LPCTSTR اعرف ان هذا البارمتر نص.


اولا المقبض :
المقبض له حالتان احيانا
NULL
,واحينا نكتب المقبض مثلا hwnd
لكن احد الاعضاء سأل وقال لماذا احيانا نضع NULL واحيانا نكتب اسم المقبض .

الحقيقة هذا السؤال حيرني في السابق وبحث عن جواب له في الكتب فلم أجد .. لكن قمت بالتجريب في الكود واكتشفت السبب ..

اذا وضعت NULL يعني هكذا
MessageBox(NULL,"ALSLAM \n\n ALAIKUM","FIRST", MB_OKCANCEL );
في هذه الحالة ستظهر الرسالة لكن تستطيع ان تصل الى النافذة التي تحوي هذه الرسالة ... فتستطيع تضغيرها ةوتكبيرها وحتى تحريكها ..

لكن لو كتبت اسم المقبض هكذا مثلا
MessageBox(hwnd,"ALSLAM \n\n ALAIKUM","FIRST", MB_OKCANCEL );
عندها لن تستطيع الوصول الى النافذة hwnd الا بعد ان تغلق الرسالة ..
فلاتستطيع تحريكها ولا حتى النقر عليها ..

الم تلاحظ ذلك في بعض البرامج ... هذا هو السبب لاحظ هذه الصورة ..

صورة

صورة


ثانيا : نص الرسالة
نص الرسالة معروف ,وهو الذي يظهر داخل الرسالة

ثالثا :
عنوان الرسالة معروف وهو الذي يظهر على الشريط العلوي للرسالة

4-نوع الراسالة

انواع الرسالة..وهي تعني الازرار التي تظهر على الرسالة فاحيانا تشاهد زر واحيانا اكثر
،،،،
MB_OKزر اوكي بس
MB_OKCANCELاوكي وكنسل
MB_ABORTRETRYIGNOREهنا اذا كتبنا هذا الثابت تظهر رسالة فيها ثلاث خيارات جربها وشف
MB_YESNOCANCELأو
MB_YESNOأو
MB_RETRYCANCELأو
MB_CANCELTRYCONTINUEأو
MB_HELP

#include"windows.h"


int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR sd,int s)
{
MessageBox(NULL,"ALSLAM \n\n ALAIKUM","FIRST", MB_OKCANCEL );
return 0;

}

لاحظ عند تشغيل المثال السابق يظهر زرين احدهما
defult
يعني اذا ضغطت انتر كانك ضاغط على موافق
فكيف يمكنني ان اجعل الزر الاخر هو defult
بسيطة نحط احد هذه
MB_DEFBUTTON1الزر الاول الافتراضي
====
MB_DEFBUTTON2الثاني
MB_DEFBUTTON3الثالث
MB_DEFBUTTON4الرابع
----------------------
مثال يجعل الزر الافتراضي كنسل(الثاني)

#include"windows.h"

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE,LPSTR  ,int  )
{
MessageBox(NULL,"ALSLAM ALAIKUM","FIRST", MB_OKCANCEL | MB_DEFBUTTON2 );
return 0;

}
لاحض عند الجمع بين خاصيتين نستخد المؤثر
OR
أو
|

بجانب عدد الازرار هناك انواع الايقونات التي تظهر مع الرسالة فاحيانا تظهر ايقونة تعجب او تحذير او استفهام وغيره فكيف نعمل ذلك بسيطة
في البرامتر الاخير نكتب احد هالأنواع
MB_ICONEXCLAMATION أو MB_ICONWARNING نفس الشي وتعطي علامة صفراء تخذير للمستخدم

MB_ICONINFORMATION أو MB_ICONASTERISKتعطي علامة تعجب زرقاء تدل على معلومة
MB_ICONQUESTION
علامة استفهام

MB_ICONSTOP أو MB_ICONERROR أو MB_ICONHAND علامة خطأ

مثال على استخدام لأيقونة

[/CODE]

وأخيرا ممكن تكون الرسالة كذا
MessageBox(NULL, NULL, NULL, NULL);
او

MessageBox(NULL, "I am just trying my wedding dress", NULL, NULL);
انت تشاهد بعض البرامج تعرض عليك رسالة وتقول :
هل تريد الخروج من البرنامج :
نعم .... لا

اذا اخترت نعم خرجت واذا اخترت لا لم تخرج..
فكيف نعمل مثل هذه الطريقة .. في امر نريد ان نأخذ رأي المستخدم فيه ..

الجواب :

تقول :

uf(MessageBox(NULL" THE QS " ,NULL,MB_YESNO)==IDYES)
EXIT
else
STAY

طبع البرنامج توضيحي ..
طبعا المثال توضيحي فقط..
لاحظ قلنا
==IDYES
يعني اذا كانت قيمة الرسالة IDYES
اخرج من البرنامج
والا
لاتخرج .

طبعا ينطبق الامر على باقي الازرار...
مثلا لو كان عندك زرين ok و cancel
تقول
==IDOK
او
==IDCANCEL

وهكذا مع باقي الازرار
#define IDOK                1
#define IDCANCEL            2
#define IDABORT             3
#define IDRETRY             4
#define IDIGNORE            5
#define IDYES               6
#define IDNO                7
 #define IDCLOSE         8
#define IDHELP          9


:ما تلاحظ هي فقط عبارة عن ارقام .. يعني ثوابت .. لها قيم ..
فكأننا نقول . اذا كانت قيمة الرسالة ==1 او ==2 ...

لان الحاسب لايفقه شيء الا لغة الارقام ...
==

هناك ثوابت اخرى تستطيع اضافتها الى البارمتر الاخير .. رجع المراجع لتجد ماتريد ..لكن سنستعرض معا الاهم

MB_HELPيعرض زر .. تعليمات .. للمستخدم مثلا
MessageBox(NULL," ","  api",MB_OK|MB_HELP);
MB_RIGHT
تستطيع عن طريق هذا الثابت ان تجعل نص + عنوان الرسالة يتجه من اليسر الى اليمين ..
MessageBox(NULL,"HI","  api",MB_YESNO	|MB_RIGHT );

MB_RTLREADINGهذا الثابت الرائع يقوم بتغيير اتجاه الازرار من السار الى اليمين وهذا مهم لنا .. لانه مفيد لبرامج العربية .. لكن هذا الثابت لايقوم بتغيير اتجاه النص من اليسار الى اليمين .. فهذا كانت مهمة الثابت السابق MB_RIGHT .. اذا انت قم بالجمع بين الثابتين

MessageBox(NULL," HI","  api",MB_YESNO	|MB_RTLREADING|MB_RIGHT );

MB_TASKMODALثابت ممتاز ..
لايسمح لك بالرجوع الى ناذة برنمجك الا بعد ان تغلق الرسالة ..
سواء كان البارمتر الاول NULL او يحوي اسم المقبض مثلا hWnd
ففي كل الحالات لاتستطيع الوصول الى برنامج الا بعد اغلاق الرسالة ..

وتعرف انك تستطيع عمل نفس الامر اذا مررت للبارمتر الاول مقبض النافذة . كما قلنا في اول الدرس .. ولكن الجديد مع الثابت MB_TASKMODAL
هو انه يجعل الرسالة تظهر على شريط المهام مع الايقونة .. ولايسمح لك بالوصول للنافذة
لكن اذا مررت فقك مقبض النافذة فانه يعتبر الرسالة جزء من النافذة ولاتظهر ايقونتها في شريط المهامن.. ولكن ايضا لايسمح لك بالوصول للنافذة ..
الامر واضح .. ولكن فقط جرب في الكود ..
MessageBox(NULL," HI","  api",MB_YESNO	|MB_TASKMODAL );

هنا انتهينا ..

حمل المرفقات ..

Attached Files


  • 0

#16 GHOST2010

GHOST2010

    مشرف قسم Visual Basic.Net

  • المشرفين القدامى
  • PipPipPipPipPip
  • 4,754 posts
  • الجنس:ذكر
  • الدولة : :شبين القناطر-القليوبية-مصر
  • اهتمامات:KILL KILL KILL
  • علم الدولة :

Posted 2005-05-25 - 02:53 PM

شكراً على الدروس الرائعة دى يا شمرى والله هاتفيدنى كتير :rolleyes:
  • 0

#17 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-26 - 02:11 PM

مشكور على مرورك
الدرس الرابع :التعامل مع الرسائل..

الجزء الاول :أحداث لوحة المفاتيح :

اهم احداث لوحةالمفاتيح
----------------------------
1-WM_KEYDOWNاذا ضغط على احدى المفاتيح
2-WM_KEYUPبعد الضغط على احدى المفاتيح

الان لاستخدام احد الرسائل السابقة لابد ان نبين ماهو المفتاح الذي انضغط ..ولكن كيف؟؟
لاحظ
case WM_KEYDOWN:
       switch(wParam) 
          {
           case VK_F1:
اولا لاحظ :
case WM_KEYDOWN:
نقول اذا كان ضغط على الكيبورد .. ولكن اي مفتاح .. هل ضغط على مسافة او على F1 او على ENTER
كيف نعرف ..
هكذا ..
switch(wParam) 
          {
           case VK_F1
اذ نقول .. اختبر الزر المضغوط ... wParam
فاذا كان VK_F1 عندها اعمل العمل الفلاني ..
هذه الصيغة الاساسية ..........

VK_F1 تعني المفتاح :F1 وهو ثابت من الثوابت .. وتستطيع اختيار اي مفتاح ..
واذا اردت معرفة باقي الثوابت فقم بالنقر بالزر الايمن على VK_F1 في الكومبايلر(الفيجوال سي بلس بلس )
واضغط الزر الايمن وتظهر قائمة اختر منها GO TO difinition of VK_F1
سيظهر حول الثابت عدد من الثوابت المشابهة مثل:
#define VK_SUBTRACT 0x6D
#define VK_DECIMAL 0x6E
#define VK_DIVIDE 0x6F
#define VK_F1 0x70
#define VK_F2 0x71
#define VK_F3 0x72
#define VK_F4 0x73
#define VK_DOWN 0x28
#define VK_SELECT 0x29
#define VK_PRINT 0x2A

والعديد من الثوابت... كل زر له ثابت(وهو رقم )

او ابحث في احد المراجع .
في المثال المرفق وضعت مثال بسيط عن درس اليوم والجديد فيه .

case WM_KEYDOWN:// FIRST 
  switch (wParam)
  {

  case VK_F1 : 
    MessageBox(NULL,"YOU ARE PRESSING ''F1'' NOW   ","API LESSON ",MB_OK|MB_RIGHT);
       break;
  case VK_SPACE :
  	MessageBox(NULL,"YOU ARE PRESSING   ''space'' NOW  ","API LESSON ",MB_OK|MB_RIGHT);
    break;  
    
  }
  break;  
  
  case WM_KEYUP:
  	switch (wParam)
  {
    case VK_F2 : 
    MessageBox(NULL,"YOU PRESSED ''F2''  ","API LESSON ",MB_OK|MB_RIGHT);
       break;
    case VK_UP :
    MessageBox(NULL,"YOU PRESSED ''UP''  ","API LESSON ",MB_OK|MB_RIGHT);
     break;  
  }
  	break;


كما تلاحظ يوجد حدثين
WM_KEYDOWN
و
WM_KEYUP
بالنسبة لحدث WM_KEYUP لاحظ انه لايحدث الا بعد ان يرفع المستخدم يده من المفتاح ..

انتهى الدرس ..
::::::حمل المثال لتفهم أكثر ::::::

Attached Files


Edited by الشـمري, 2005-05-26 - 02:13 PM.

  • 0

#18 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-27 - 04:26 PM

الدرس الرابع : التعامل مع الرسائل
الجزء الثاني : التعامل مع احداث الماوس .

اهم احداث الفأرة
------------------------------------------------------
WM_LBUTTONDOWNعندما يتم النقر على الزر الايسر للماوس
WM_LBUTTONUPبعد النقر على الزر اليسر للماوس
WM_LBUTTONDBLCLKعندما يتم النقر مرتين متتاليتين على الزر الايسر للماوس
--
WM_RBUTTONDOWNعندما يتم النقر على الزر الايمن للماوس
WM_RBUTTONUPبعد النقر على الزر الايمن للماوس
WM_RBUTTONDBLCLKعندما يتم النقر مرتين متتاليتين على الزر الايمن للماوس
--
WM_MBUTTONDOWNعندما يتم النقر على الزر الاوسط للماوس
WM_MBUTTONUPبعد النقر على الزر الاوسط للماوس
WM_MBUTTONDBLCLKعندما يتم النقر مرتين متتاليتين على الزر الاوسط للماوس
WM_MOUSEMOVEعندما تحرك الماوس فان هذا الحدث يحدث ..
يعني لو قمت بتحريك الماوس فوق النافذة مثلا .
حقيقة واجهتني بعض المشاكل مع هذه الرسالة .. لكن ليست مشكلة كبيرة ومع الوقت سأتعلمها بالتأكيد .

طبعا هناك العديد من الرسائل الاخرى المتعلقة بالماوس لكن هذا مايهمنا

الشرح :

مثلا نأخذ مثال على الزر الايسر
هذا مثال توضيحي

CODEswitch(msg)
{
 case WM_LBUTTONDOWN:
  
  MessageBox(hwnd, "you press left button", "arab team", MB_OK | MB_ICONINFORMATION);
  

break;
اذا ضغط المستخدم الزر الايسر
case WM_LBUTTONDOWN:

اظهر له رسالة...
MessageBox(hwnd, " left button", "arab team", MB_OK | MB_ICONINFORMATION);


وطبق ذلك على باقي الاحداث..


في المثال المرفق يوجد عدد من الرسائل طبقت عليها الدرس . .

//-------------------------------|
//-------------------------------|
   
  case WM_LBUTTONDOWN:
    MessageBox(NULL,"''Left Button ''DOWN","API LESSONS " ,MB_OK|MB_RIGHT);
       break;     

  case WM_LBUTTONUP :
    MessageBox(NULL,"  ''Left Button'' UP  ","API LESSON ",MB_OK|MB_RIGHT);
     break;    	
	
  case WM_RBUTTONDOWN:
    MessageBox(NULL,"''RIGHT Button '' DOWN","API LESSONS " ,MB_OK|MB_RIGHT);
       break;   
  
  case WM_MBUTTONDOWN:
    MessageBox(NULL," ''MIDDLE Button '' DOWN","API LESSONS " ,MB_OK|MB_RIGHT);
       break;      
   
  case WM_MOUSEMOVE:
       X+=5;
     MoveWindow(hwnd,10,10,X,520,TRUE);
     break;
   
//-------------------------------|
//-------------------------------|
المثال واضح ولايحتاج المزيد من الكلام ..

لكن سأشرح الرسالة WM_MOUSEMOVE
لاهميتها ولتعقيدها بعض الشيء :)

هذه الرسالة كما قلنا تحدث اذا تم تحريك الماوس ..
حاولت البحث عن دالة تبين المطلوب ..لكن لو قلنا عندما يتحرك الماوس فاظهر رسالة .. فكم رسالة ستظهر لذا بحثت عن دالة اخرى تبين المقصود وتكون سهلة للمبتدئين فلم اجد افضل من استخدام الدالة movewindow لانها
سهلة
تبين المقصود من الرسالة wm_mousemove

الدالة movewindow تقوم بتغيير موقع النافذة وطول وعرض النافذة ..
وتطلب ست بارمترات سهلة جدا .
الاول : مقبض النافذة التي تريد تحريكها ..
الثاني الاحداثي السيني للنافذة .. وكتبنا الاحداثي الذي نريد
الثالث : الاحداثي الصادي للنافذة .. وكتبنا الاحداثي الذي نريد
الرابع : عرض النافذة ومررنا له المتغير x
الخامس : طول النافذة وكتبنا الطول الذي نريد
السادس : يقول هل تريد اعادة رسم النافذة .. قلنا نعم true وستعرف مامعنى اعادة الرسم بالدروس القادمة . ان شاء الله تعالى . . قم بتغيير البارمتر الاخير الى false
وانظر ماذا يحدث .



نحن ببساطة قلنا اذا حرك المستخدم الماوس .. قم ..
بتغيير موقع النافذة وقم بزيادة عرض النافذةالمتغير X

X+=5
ثم اجعل عرض النافذة هو قيمة X
MoveWindow(hwnd,10,10,X,520,TRUE);
وبالتالي كلما حرك المستخدم الماوس فان قيمة X تزداد وبالتالي عرض النافذة يزداد ..

ولكن هناك مشكلة اتمنى ان تناقشوها .. وهي انه حتى لو لم تتحرك الفأرة.. فان عرض النافذة يزداد .. مادام مؤشر الماوس على النافذة .. فهل هنك حل يجعل عرض النافذة لا يزداد الا اذا قام المستخد بتحريك الماوس فقط .


حمل المثالين المرفقين .. احدهما لاحداث الماوس العادية .. والاخر لحدث تحريك الفأرة
بالهنا و العافية :lol:


الدرس القادم سيكون عن الرسائل المتنوعة .. واتمنى ان اجد من يضيف على الدروس .. ويصحح الاخطاء كما فعل اخي احمد غريب . هل يوجد احد

Attached Files


Edited by الشـمري, 2005-05-27 - 04:34 PM.

  • 0

#19 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-05-29 - 01:42 PM

اعتذر عن عدم اكمال الدروس في الوقت الحالي .. الاختبارات على الابواب .


سأتوقف مدة ثلاث اسابيع اعتبارا من اليوم ..
ثم نبدا باكمال الدروس والتي ستكون بشكل يومي ان شاء الله

واتمنى من الاعضاء اضافة بعض الامور حول الدروس التي طرحت .. او تصحيح بعض الاخطاء ان وجدت .. بعيدا عن كلمة شكرا ..

ادعولي بالتوفيق .
  • 0

#20 Abdullah.Alshammeri

Abdullah.Alshammeri

    مشرف قسم برمجة الألعاب و مراقب عام سابق

  • Topic Starter
  • أعضاء الشرف
  • 6,627 posts
  • الجنس:ذكر
  • الدولة : :نجد - الرياض
  • اهتمامات:برمجة الالعاب
  • علم الدولة :

Posted 2005-06-11 - 11:43 AM

سأكمل مطلع الاسبوع القادم اذا كان مافيه لاشغل ولامشغلة ..
لكن اتمنى منكم (( لمن يريد الاستفادة )) ان يكون فاهم جميع الدروس الماضية لاني سأضيف الدروس بشكل مكثف حتى استغل الاجازة خير استغلال .. وذلك حتى نمشي مع بعض .. (( هذا اذا كان فيه احد ماشي معي :) ))
هذا للتذكير فقط ..
  • 0




Loading