كل برنامج أو Process يعمل في الويندوز قد يحتوي على مهمة واحدة أو أكثر تعمل في نفس الوقت . هذه المهمات تسمي ب Threads .. كل Thread يمثل سير للتعليمات التي يجب تنفيذها .. راجع الدرس الثالث في الفيجوال سي++ ( http://arabteam.nicmatic.com/atassi/vc_lessons ) للتفهم أكثر عن المسطلحات Process و Thread ..
يوجد تابعين في الويندوز هما SuspendThread و ResumeThread مهمتها إيقاف عمل Thread ما وتشغيله . هذه التوابع تقبل بارمتر واحد هو مقبض هذا ال Thread أو ال Handle . وهذا المقبض وحيد بين جميع ال Handle Threads في الويندوز . هذا يعني بالحصول على هذا المقبض يمكن تجميد عمل الThread لبرنامج ما .
وبما أن الرنامج أو ال Process قد يحتوي على أكثر من Thread واحد يعملون في نفس الوقت . فمثلا ال MSN Messenger يملك أكثر من عشرة Threads تعمل في نفس الوقت . وبالتالي من أجل تجميد البرنامج يجب تجميد جميع ال Threads التي يملكها .
المشكلة هي من أين نحصل على مقبض ال Thread . في حالة تم تشغيل البرنامج باستخدام التابع CreateProcess فإنه يعطينا مقبض ال Thread الأساسي للبرنامج الذي شغلناه . ولكن ماذا لو نريد إيقاف عمل برنامج هو أساسا في وضعية التنفيذ . التابع GetWindowThreadProcessId يمكن من خلاله معرفة ال ThreadID الذي قام ببناء نافذة ما بمعرفة مقبضها . بعد معرفة ال ThreadID يمكن أخذ ال Handle بيعه عن طريق التابع OpenThread وهذا التابع لايعمل سوى في Win2000 . وبعد معرفة المقبض يمكن استخدام التوابع السابقة في تجميد المهمة الأساية للبرنامج .
ولكن ماذا لو لم يكن للبرنامج نافذة ، أو يمكلك البرنامج مهام أخرى (Threads) غير المهمة الأساسية ؟ فإن الطريقة السابقة سوف تجمد نصف البرنامج وتترك القسم الآخر يتنفذ وهذا ما قد يؤدي إلى مشاكل وينهار البرنامج . إذا يجب أن توجد طريقة من أحل الحصول على جميع ال Processes التي تعمل في الويندوز وأيضا الحصول على جميع ال Threads التي يملكها كل Process وبالتالي يمكن تجميد جميع المهام مرة واحدة ..
تعرفت على توابع تقوم بارجاع جميع ال Processes أو ال Threads وهي
CreateToolhelp32Snapshot
Process32First
Process32Next
Thread32First
Thread32First
قمت بعمل برنامج يطبق الطريقة الأخيرة . هذا البرنامج يتم اعطائه اسم الملف التنفيذي مثل (msmsgs.exe) وهو برنامج ال MSN Messenger . ويقوم بعرض جميع ال Threads التابعة للبرنامج ويمكن أن تختار أي Thread تريد تجميده أو فك تجميده ... البرنامج أثناء العمل موضح بالصورة التالية :
[note]
صورة برنامج المشروع
[/note]
كما هو ظاهر يتم كتابة اسم البرنامج ومن ثم الضعط على Open Process وبعد ذلك يتم عرض ال Threads ID التابعة لل Process وعند هذه النقطة يمكنك اختيار أي منها تريد تجميده وتضغط على الزر "Suspend Selected Threads" من أجل التجميد و "Resume selected threads" من أجل فك التجميد .
قمت بعمل برنامج آخر للتجريب وهو برنامج يقوم برسم مربعات بشكل عشوائي في Dialog ولكن كود رسم المربعات موجود في Thread ثاني أي بشكل اجمالي البرنامج يحتوي على Two Threads الأولى هي التي قامت ييناء النافذة وتحتوي على ال Message Pump التي تقوم بتنفيذ الرسائل الواصلة ، والثاني هو الذي يقوم برسم المربعات .. قمت بفصل الثريدين من أجل التوضيح . صورة البرنامج الثاني هي :
صورة برنامج التجارب
للفائدة : تلاحظ أنه حين الكبس على Start فإنه يمكنك تحريك النافذة بكل سهولة وذلك بسبب أن روتين رسم المربعات هو في Thread منفصل ..
بتفكير بسيط يجب أن تستنتج أنه عند إيقاف ال Thread الأساسي فإن نافذة البرنامج سوف تجمد أي لا يمكن إيقاف البرنامج أو اغلاقه ، ولكن سوف تبقى عملية رسم المربعات شغالة . أما عند إيقاف الثريد الثاني فقط فإن عملية الرسم تجمد مع بقاء امكانية تحريك النافذة . وفي حالة ايقاف الثريدين معا باختيارهم من القائمة يتم ايقاف المربعات ويتم تجميد النافذة .
يجب أن تنتبه إلى أنه عند إيقاف أي Thread مرتين فأنت تحتاج إلى أن تعمل Resume مرتين أيضا وذلك بسبب أنه يوجد عداد في كل ثريد يدل على حالة ال Resume وعندما يكون هذا العداد 0 فإن الثريد في حالة عمل ..
البرنامج الاساسي مع التجربة موجودون في الوصلة : (السورس مع الملف التنفيذي)
http://arabteam.nicmatic.com/atassi/Suspen...spendThread.zip
ومن أجل التجريب قم بالخطوات التالية :
- شغل البرنامجين .
- اكتب testprog.exe داخل برنامج SuspendThread .
- اضغط على Open Process . وعندها سوف تحصل على سطر واحد في ال List ، يمثل الThread الأساسي .
- اضغط على Start في برنامج TestProg وعندها سوف يتم انشاء Thread آخر الذي يقوم برسم المربعات.
- اضغط Open Process من جديد وسوف تجد أنه أصبح لدينا سطرين في ال List . حيث تمت اضافة الثريد الثاني .
- قم باختيار أحد ال IDs وجمدها بالضغط على Suspend selected threads ولاحظ تأثيرها على برنامج ال TestProg . ولكن بعد كل عملية لا تنسى أن تفك تجميد ما قمت بتجميده .
هذا كل شي