السلام عليكم
عندما بدات تعلم الاسمبلى وبرمجه الAPI كانت هناك طريقة يستخدمها اغلب مبرمجى الاسمبلي فى الحصول على الجزء الادنى من الدوال امثال lParam و wParam, هذه الطريقه كانت تزعجنى جداً ولكن لقلة خبرتى فى الاسمبلى لم يكن لدى القدره على تغير الامر وكنت انصاع لهذه الطريقه لانى لا اعرف غيرها, ولكن بعد فتره وجدت مقاله كتبها شخص إسمه Ernie يوضح فيها كيفيه تغير هذه الطريقة وإستخدام طريقه افضل دعونى اضع مثال حتى تتضح الصوره.
مثال:
عندما تريد على سبيل المثال ان تقراء مدخلات الماوس من دالة lParam فإنك تقوم بالتالى:
.ELSEIF uMsg==WM_LBUTTONDOWN mov eax,lParam and eax,0ffffh mov ebx,lParam shr ebx,16
وبذلك تحصل على موقع x فى eax وموقع y فى ebx , هذه هى الطريقه التى تعلمناها وتعودنا عليها, ونستخدمها فى حالات كثيره جداً فى برمجة الAPI .
طبعاً Ernie لم تعجبه الطريقة وشكى الموضوع لhutch الرجل الذى يحمل على عاتقه تطوير مكتبات masm32 فاشار عليه بالتالى.
البديل الاول
قم باخذ المعطيات من الستاك مباشرتاً بدلاً من تقسمها بهذه الطريقه المطوله وإليك مثال يوضح ذلك:
wParamL equ <WORD PTR [ebp + 16]> wParamH equ <WORD PTR [ebp + 18]> lParamL equ <WORD PTR [ebp + 20]> lParamH equ <WORD PTR [ebp + 22]>
وبهذا تستطيع إختصار الكود الاصلى على النحو التالى:
.ELSEIF uMsg==WM_LBUTTONDOWN mov eax,lParamL mov ebx,lParamH
طيب جميل جداً ولكن المشكله ان الجزء الاول من الكود معقد جداً ولا استطيع ان اذكر مواقع الدوال فى الإٍستاك, ولنفرض اننى اردت ان استخدم دوال اخرى غير الlParam و wParam فهذه الطريقة غير مجديه, رغم انها اختصر على صطرين من الشفره.
البديل الثانى
Ernie لم يقتنع بالحل وقرر إيجاد حل اخر وهو على النحو التالى:
packedDW UNION value DWORD ? STRUCT loword WORD ? hiword WORD ? ENDS packedDW ENDS
كما تلاحظو طريقة Ernie مبنية على تحديد متغير من نوع جديد يمكننا من الوصول إلى كل word فى المتغير او نستطيع ان ناخذ DWORD ولن نستهلك الذاكره لاننا نستخدم UNION والمثال يصبح على النحو التالى:
.ELSEIF uMsg==WM_LBUTTONDOWN mov eax,lParam.loword mov ebx,lParam.hiword
فى بادء الامر اعجبت بهذه الطريقه وطورتها لاجعلها اكثر شمولاً حيث انه يمكن تقسم الDWORD إلى 4 byte على النحو التالى:
packedDW UNION value DWORD ? STRUCT loword WORD ? hiword WORD ? ENDS STRUCT llbyte byte ? lhbyte byte ? hlbyte byte ? hhbyte byte ? ENDS packedDW ENDS
وبهذا استطيع الوصول إلى كل بايت او كل word او dword بنفس الطريقه السابقه, ولكن عندما اردت تطبيق الطريقه لاحظت اننى لابد ان اغير طريقتى فى البرمجه وتغير جميع الدوال من نوع dword إلى packedDW, ليس فقط ذلك ولكن لاحظت ايضاً ان برامجى اصبحت تشبه برامج السى بلس بلس, وشعرت كانى لا اعرف هذه اللغه وقررت ان ابحث عن طريقه افضل..
البديل الثالث
فى بعض الاحيان نعقد الامور بدلاً من تبسيطها ونبحث عن حلول لتبسيط امور هى فى الاصل بسيطه, يوجد دوال فى معالج Intel يقوم بما نريد دون الحاجه لإستخدام Shitft او AND ودون الحاجه إلى تغير الدوال وذلك على النحو التالى:
movzx eax, word ptr[lParam] movzx ebx, word ptr[lParam+2]
شكل البرناج لم يتغير ولن يحدث خلل فى باقى البرنامج لان هذه العمليه هى نفس العمليه التى تعودنا عليها ولكن بطريقه مختصره وتصلح معى جميع انواع المتغيرات, يمكنك ان تجرب الطريقه على النحو التالى.
إذهب إلى ملف ICZTUTES الموجود تحت ملف masm32 ثم افتح الدرس رقم 7 فى الغالب المسار سيكون على النحو التالى إذا قمت بتنصيب برنامج masm32 بالطريقه المعتاده
C:\masm32\ICZTUTES\TUTE07
افتح ملف الاسمبلى mouse.asm وغير الجزء التالى:
.ELSEIF uMsg==WM_LBUTTONDOWN movzx eax,lParam and eax,0ffffh mov hitpoint.x,eax movzx eax,lParam shr eax,16 mov hitpoint.y,eax mov MouseClick,TRUE invoke InvalidateRect,hWnd,NULL,TRUE
بحيث يصبح على النحو التالى
.ELSEIF uMsg==WM_LBUTTONDOWN movzx eax,word ptr[lParam] mov hitpoint.x,eax movzx eax,word ptr[lParam+2] mov hitpoint.y,eax mov MouseClick,TRUE invoke InvalidateRect,hWnd,NULL,TRUE
قم بعملية كمبايل ولنك للبرنامج وسوف تلاحظ ان البرنامج يعمل وان ما قمنا به ماهو إلا تسريع للبرنامج, بالطبع لن يكون هناك فرق ملحوظ للسرعه ولكن تخيل لو كان البرنامج يقوم بهذه العمليه 1000 مره او 100000 مره عند إذا سيكون الفرق ملحوظ.
وبالتاكيد لم اضع هذا الموضوع لانى اتضايق من سرعة مثل هذا البرنامج ولكن لانى اريد ان اعود نفسى على كتابة البرامج بالطريقه الصحيحه.
إذا ارتم ان تقراؤ موضوع Ernie والذى كان السبب فى كتابتى لهذا الموضوع فهو موجود على الرابط التالى :
http://ourworld.compuserve.com/homepages/e...orld/params.htm
اسف على الاطاله
والسلام عليكم