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

مشاهدة النسخة كاملة : تعلم برمجة الوندوز بلأسمبلر


chik
12-09-2003, 05:50 PM
السلام عليكم,
سأقترح هنا بعض الملومات للدين يهتمون بلأسمبلر 32 بايت ولديهم معلومات عن س++ . الأدوات الضرورية Masm32 و VC++6 .
سأعطي في هذه البداية مثالا بسيطا يبرز لنا نافذة من نوع MessageBox من س++ والأسمبلر حتى نرى نقط التشابه وكيف نستعمل APIفي هاذين النوعين.

في الملف المرفق تجدون المشروعين كاملين.

سأبدأ بتحليل س++ :
1 #include <windows.h>
هنا نزيد الملف المذكور وهو يحتووي على جميع ما سنحتاجه في عملنا هذا
2LPSTR Caption=
في هذين السطرين ندرج معطياتنا وهنا نعني عنوان ومحتووى MessageBox
3 int WINAPI WinMain(
هذه تدل أين يبدأ برنامجنا وهي تعادل main هنا لا نحتاج Parametrs وسنرجع إليهم حين نأخذهم بعين الإعتبار ووهنا نقلتها كما هي من MSDN .
4 هنا نبدأ ب MessageBox وإذا أطللنا على MSDN نرى ما يلي
int MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box );
نرى أنها تحتاج 4 Parametrs
hWwnd وهو هاندل النافذة وووسنعطيها صفر كاعتبار أنه ليس لها نافذة أم
lpText و lpCaption هو العنوان والمحتوى
والأخير هو نوع النافذة التي نريد انظروا MSDN لتروا مختلف الأنواع

5 هنا نغادر البرنامج ب
VOID ExitProcess( UINT uExitCode // exit code for all threads );

أما فيما يخص الأسمبلر في الأول نعطي نوع Processor Instructions هنا نعطي نوع 386 ونعطي أيضا نوع الذاكرة Flat وهنا يمكن أن نأخذ كل هذا كموديل لبرامجنا ويمكن أن نقرأ عنها في ملف المساعدة ل MASM
1 مثل ما سبق ملفات Include نزيد windows.inc الذي يحوي عدة معطيات مثل MB_OK وهنا نزيد أيضا user32.inc و kernel32.inc لأن MessageBox توجد في user32 أما ExitProcess فتوجد في kernel32 كما نزيد ملفات .lib المرافقتان لهما في س++ لم نكتب كل هذا لأن الكل كان مذكور في windows.h .
2 .data هنا تبدأ منطقة المعطيات وسنعطي كالسابق العنوان والمتوى
3 .code هنا تبدأ منطقة الكود ووهي بمثابة main
4 بعد هذا عندنا
invoke MessageBox, 0,Offset Text, Offset Caption, MB_OK + MB_ICONEXCLAMATION
هنا نرى التشابه الكبير نكتب المكرو invoke وو المسج بوكس يكتب في نفس الشكل مثل س++ ونلاحض نفس الشيء فيما يخص ExitProcess . لكي نلخص إذا كانت عندنا Api باسم Func نكتبها في س++ كما يلي :
Func(a,b,c,d,e) ففي الأسمبلر نكتبها
Invoke Func,a,b,c,d,e
وفي الحقيقة فإن هذه الماكرو تفعل العمل التالي:
push e
push d
push c
push b
push a
call Func
نرى أن parameters تضع في الستاك على العكس يعني الأخير يطرح الأول وهنا ارجعو إلى مثالنا وغيروا invoke MessageBox
ب :
push MB_OK
push Offset Caption
push Offset Text
push 0
call MessageBox
وتلاحظون أنه يعطينا نفس النتيجة.
وللتجميع يمكنكم استعماا الملف make.bat وسنرجع للحديث عنه في مرة أخرى وإذا غيرنا اسم ملف chik1 يجب التغيير أيضا chik1 داخل هذا الملف.
أما int 3 هي الآن غير شغالة وسنرجع إليها حين نستعمل Debugger
نكتفي بهذا القدر اليوم وأتمنى أن أكون أعطيتكم الرغبة في هذه البرمجة وفي المرة القادمة يمكن أن نتطرق لبرمجة نافذة من نوع DialogBox ويمكنكم من الآن البدء في هدا وكما قلت هناك تشابه كبير مع س++
في انتظار آرائكم أقول لكم إلى اللقاء.

حبروش
15-09-2003, 03:20 PM
جزاك الله كل خير بنزل الملف ومشكور مقدما وسأكنب لك بعد التنفيذ

حبروش
15-09-2003, 03:41 PM
جميل جدا اخي CHIK والفرق واضح من خلا الحجم حيث ان حجم الملف بالاسمبلي اصغر عشر مرات من السي بلس بلس

chik
15-09-2003, 03:56 PM
السلام عليكم,
في المرة القادمة سأهيء على نفس المنوال مثالا لاستعمال نافدة من نوع DialogBox .
ألى دلك أنتظر آراءكم واقتراحاتكم وإلى اللقاء.

chik
16-09-2003, 01:20 PM
السلام عليكم,
هنا سأقترح مثالا لإستعمال نافدة من نوع DialogBox .
هنا سأعطي المثال ب س++ وفي المرة القادمة سأعطي نفس الشيء بالأسمبلر. ويمكنكم من الآن التفكير في هدا.
في الملف المرافق تجدون المشروع كاملا.

نشغل Visual C++ نختار File New Win32 Application نعطي الإسم والمسار ثم OK . نعطي الإسم مثلا ExpApi . بعد هذا نختار Empty Project و OK .
بعد أن نتم من المشروع نختار Project Add To Project New C++ Source File نعطي الإسم مثلا ExpApi .
بعد هدا سنضيف النافذة , نختار Insert Resource Dialog New بعد هذا تظهر لنا نافذة فيها 2 باتن نختار كل واحد منهما ونزيلهما بالضغط على Delete . بعد هذا نضيف EditBox و 2 Button . بعد هذا نسجل هذه النافذة في نفس المسار تحت اسم script1.rc . بعد هذا نختار View Id=resource symbol هذا يعطينا الأرقام التي أعطيت للنافذة ولكل ما فيها نرى مثلا IDD_DIALOG=101 هذا بالنسبة للنافذة . IDD_EDIT1=1000 ل EditBox و IDC_BUTTON= 1000 و 1001 للبقية . يمكن أن تكون عندكم أرقاما مختلفة يجب فقط أن نعرف رقم كل أداة عندنا.
بعد هذا نرجع إلى ملفنا ExpApi.cpp فهو الآن صفحة بيضاء ونبدأ البرمجة.
#include <windows.h> نضيف ملف header .
LPSTR text="a text … " نعطي ما سنكتب .
نضيف السطر الآتي وسنتحدث عنه من بعد
BOOL CALLBACK DialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
); هنا أخذتها كما هي من MSDN

هنا سنعطي نقطة بدء البرنامج WinMain هذه الدالة هي التي سيبدء بها برنامجنا :
int WINAPI WinMain(
HINSTANCE hInstance, // handle to current instance
HINSTANCE hPrevInstance, // handle to previous instance
LPSTR lpCmdLine, // pointer to command line
int nCmdShow // show state of window
)
لها 4 Parameters الأول هو الوحيد الذي سنحتاجه في برنامجنا هذا وهو في الحقيقة يعطينا موقع البرنامج في الذاكرة . الثاني هو كالأول لكن بالنسبة إذا كان البرنامج شغالا من قبل. الثالث هم Parameters التي يمكن أن نعطيها مع بدء البرنامج . والأخير هو يحدد كيف ستظهر النافذة كبيرة مصغرة … وإذا لم نفهم كل معنى هذا ليس مشكلا فسوف نتطرق لكل واحد حين نحتاجه في البرامج القادمة إن شاء الله.
لبرامج من النوع DialogBox سوف نحتاج الدالة DialogBoxParam .إذا أطللنا على MSDN تعطينا:
int DialogBoxParam( HINSTANCE hInstance, // handle to application instance LPCTSTR lpTemplateName, // identifies dialog box template HWND hWndParent, // handle to owner window DLGPROC lpDialogFunc, // pointer to dialog box procedure LPARAM dwInitParam // initialization value );
ونحن سنكتبها كالتالي
DialogBoxParam(hInstance,MAKEINTRESOURCE(101),NULL ,DialogProc,NULL);
البارمتر الأول هو hInstance الذي تعطيه لنا WinMain
الثاني هو رقم النافذة 101 ونستعمل الماكرو MAKEINTRESOURCE لتحول لنا الرقم إلى بارامتر مفهوم.
الثالث أعطيناه NULL لأن نافذتنا ليس لها أب أو أنها تعتبر هي الأب أو الأساسية.
الرابع وهو من نوع CALLBACK وهو عنوان الدالة التي تتكلف بتحليل ودراسة Events . مثلا حين نقوم بشيء على نافذتنا كالكليك مثلا فإن الوندوز سيبعث بإنذار إلى النافذة ليخبرها بأن شيئ حصل ويعطيها رقم Event وكل هذا سيقدم إلى هذه الدالة. ونحن قد أعطينا مفهومها في الأول لأننا نذكرها هنا ولكن سنتعامل معها من بعد. نعلم الكومبايلر بوجودها .
هذا كل ما سنضع في WinMain أما البرمجة الحقيقية فستكون في DialogProc .

BOOL CALLBACK DialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
إذن هذه هي الدالة التي ستقوم بتحليل النافذة . وهي لها 4 بارامتر :
الأول وهو hwndDlg أو ما يسمى ب هاندل النافذة والآن يمكن أن نعتبر هذا كبارامتر يمكن أن يعرف نافذة ما.
الثاني وهو رقم Event الذي وقع للنافذة وهي كثيرة ويمكن التعرف عنها في MSDN وهي تبدأ ب WM_ .
الثالث والرابع هما بارامتر إضافيان وهما يتغيران حسب Event .
هنا سنكتب if(uMsg==WM_CLOSE)
{
ExitProcess(0);
return 1;
}
حين يصل إلى دالتنا الإنذار WM_CLOSE وهذا يحصل حين نريد إقفال النافذة ننهي البرنامج ب ExitProcess .
يمكن أن نشغل البرنامج في هذا الحد ونرى أن ما يشتغل فيه هو حين ننقر علامة X لإغلاق البرنامج.
سنضيف الآن ما يتعلق بنقر Button 1 2.
if(uMsg==WM_COMMAND)
{
if(LOWORD(wParam)==1001)
{
SetDlgItemText(hwndDlg,1000,"An Example From - Chik - مثال من عند");
return 1;
}
if(LOWORD(wParam)==1002)
{
ExitProcess(0);
return 1;
}
} حين ننقر Button فإن الوندوز ترسل إنذار من نوع WM_COMMAND . وحين يتم هذا فإن البرامتر wParam يحمل في Word المنخفض (LOWORD) رقم Button الذي حصل عليه النقر
if(LOWORD(wParam)==1001) هنا نحاول أن نعرف إذا كان button1 الذي يحمل رقم 1001 وإذا كان ذلك سنرسل كتابة ما إلى EditBox والحامل للرقم 1000 .سنستعمل
SetDlgItemText(hwndDlg,1000, text);
هذه الدالة ترسل كتابة ما في text إلى الأداة رقم 1000 والكل في النافذة التي تحمل الهاندل hwndDlg وهذه ليست إلا نافذتنا.
نعمل نفس الشئ مع Button2 وهنا نخرج من البرنامج.
هذا البرنامج مكتوب على هذا النحو ليس بالأنيق ولكن فضلته هكذا ظانا أنه ربما يسهل الفهم أكثر . فيمكن مثلا أن نضيف تلملف resource.h إلى مشروعنا وبدلا من أن نكتب الأرقام نكتب IDD_DIALOG إلى غير ذلك.
وكمثال يمكنكم أن تزيدوا EditBox آخر , نكتب في هذا وحين نقوم بالنقر تنقل الكتابة في EditBox الآخر باستعمال الدالة GetDlgItemText التي تقرأ الكتابة من نافذة ما داخل DialogBox .
أتمنى أن تجدوا إفادة في هذا وفي انتظار آرائكم واقتراحاتكم أقول لكم إلى اللقاء.

حبروش
16-09-2003, 02:24 PM
رائع جدا اخي chik
بس اذا ممكن يكون الدرس على ملف وورد مرفق مع المثال او استعمال خاصيه الكود بالمنتدي عشان تسهل قراءة الكود


تحياتي والمعذره على على الاقتراح

chik
18-09-2003, 03:27 PM
السلام عليكم,
كما وعدتكم سأعطي نفس المثال السابق لكن هذه المرة بلغة الأسمبلر.
في الملف الرافق تجدون المثال وأنا أضفت ملف وورد يحتوي على هدا النص:

أولا سنحتاج إلى نافذة الديالوغ , وهنا سنصنعها من فيجوال س++ إلا أنه يمكنكم استعمال أي برنامج آخر يقوم بهذه المهمة.
نشغل فيجوال س++ ونقوم ب insert resource ثم نختار dialog new تظهر لنا نافذة فيها 2 button نزيلهما ونضيف EditBox و 2 Button . بعد هذا ننقر فوق النافذة باليمين ونغتار Propreties وحين تفتح هذه الأخيرة نبدل خانة ID حيث غالبا ما نجد فيها IDD_DIALOG… نغيرها باسم في هذا المثال سميتها CHIK " " نكتب الإسم بين الشرطتين. مثل السابق نرى الأرقام المعطية لكل أداة وذلك باختيار view id=resource symbol في حالتي هذه IDC_EDIT=1000 و IDC_BUTTON=1001 والآخر 1002 نسجل هذا في المسار الذي سنشتغل فيه ونختار تسجيله تحت ملف .res ونعطيه اسم مثلا هنا script1.res .
هنا نكون انتهينا بما يتعلق بالنافذة فلنذهب إلى البرمجة.

.386
.model flat, stdcall
option casemap :none ; case sensitive


include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc

includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
هذه كالسابق ونتأكد أن مسار masm32 هو صحيح عندنا أو نغيره .

WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
هنا ندرج الدالة المكلفة بدراسة events نفس الشيء مثل س++ .
WndProc اسم الدالة يمكن أن نعطيها أي اسم نريد.
PROTO تعني prototype.
:DWORD نوع parameter ونلاحظ أنه عندنا أربعة . رغم أنه في س++ أذنا هذه parameters من أنواع مختلفة hwnd,wparam.. وغيرها إلا أنها كلها من نوع 32 بايت أو double word.

.data
dlgname db "CHIK",0 ; إذا كنتم قد أعطيتم اسم آخر للديالوغ غيروه هنا
text db "An Example From - Chik - مثال من عند",0
hInstance dd 0
هنا نعطي المعطيات . الأول سيكون الإسم الذي أعطيناه للنافذة الثاني الكتابة التي سنبرزها والثالث هو سنحتاجه في البرنامج تذكروا hInstance في س++.

invoke GetModuleHandle, NULL
mov hInstance, eax
GetModuleHandle تعطينا ما يدل على اسمها أو بخلاصة نقول تعطينا hInstance للبرنامج . ولنوضح أكثر يجب أن نعلم أن أي API ترجع لنا نتيجة فهذه الأخيرة تكون في الجستر eax ولهذا سنقوم بوضع eax في hInstance.

invoke DialogBoxParam,hInstance,ADDR dlgname,0,ADDR WndProc,0
لا شيء يذكر فهذا مثل س++.


WndProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
هنا الدلة WndProc وسنعطي اسماء لكل parameter .
أما البقية فهي مثل س++ .
ونلاحظ أن كثير من الماكرو قد سهلت الأمور مثل .if وغيرها.

في السطر الأخير عندنا xor eax,eax و return.
نريد أن نرجع صفر لذا قمنا ب xor eax,eax فهذه العملية ستقوم بوضع 0 في eax.

لبناء البرنامج يمكنكم استعمال الملف make.bat وأنا هنا لم أضع فيه إلا اللازم حتى نتمكن من فهمه فهو يحتوي على 3 اسطر الآتية وتأكدوا من مسار mas32 :

C:\MASM32\BIN\Cvtres.exe /machine:ix86 script1.res
C:\MASM32\BIN\Ml.exe /c /coff chik2.asm
C:\MASM32\BIN\Link.exe /SUBSYSTEM:WINDOWS chik2.obj script1.obj
السطر الأول سيمكن من إعطاء ملف .obj ل resource أو النافذة.
الثاني سيجمع الملف .asm ويعطينا الملف .obj للبرنامج.
والأخير سيجمع ويلاقي جميع الملفات .obj ليعطينا الملف .exe الأخير.

أتمنى أن يفيدكم هذا المثال وتكونوا قد لاحظتم التشابه الكبير.
إلى مثال آخر سأبقى أنتظر آراءكم واقتراحاتكم.
إلى اللقاء.

chik
30-09-2003, 06:27 PM
السلام عليكم,

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


كنت أود أن أذهب تدريجيا مع هذه الدروس إلا أني لاحظت اهتمام الإخوة ببرمجة Server & Client وها أنا سأعطي مثالا لهذا كالعادة ب س++ وبالأسمبلر ورغم أن الكثير يتخوف من هذا الأخير إلا أنكم سوف تلاحظون أن هناك تشابه كبير.
أولا يجب أن نعرف أننا سنستعمل بروتوكول TCP/IP لبرنامجينا.
دعنا الآن نتكلم بعجالة ماذا يحدث حين يكون عندنا سيرفر وكلاينت.
نعرف أن في ميدان هذا النوع من الإتصالات هناك ما يسمى ب port أو البوابات وعددها إذا لم تخدعني ذاكرتي حوالي 65000 منها ما هو مسجل مثل الباب 80 يستعمل ل http المعروف أو 21 ل FTP وغير ذلك والبقية يمكن استعماله لأغراض أخرى.
السيرفر هو الذي سيبدأ العمل إذ يجب عليه أن يفتح بابا للتواصل في المثال سيفتح الباب 11111 وكما ترون فقد أخذته كما شئت. بعد فتح هذا الباب يبقى في الإستماع حتى يتصل به أحد.
الكلاينت يجب عليه أن يتصل بالسيرفر وذلك من خلال عنوانه الإيبي IP Address وفي السيرفر لم نحدد هذا ليأخذ الإيبي للكمبيوتر المتواجد عليه. كما يجب عليه أن يتصل بالباب الذي يكون قد فتحه السيرفر.
حين يتم هذا الإتصال يمكن أن يبديا الحديث بتبادل المعلومات مثل ما يحدث في التشات أو الميسنجر. وهنا أضيف أنه يمكن برمجة السيرفر لبعض COMMANDS ليعمل أشياءا أخرى كحذف ملف ما أو غير ذلك وهذه هي طريقة التروجينات. نقول مثلا لو أن الكلاينت يرسل كلمة del path\file فإن السيرفر سيمسح الملف المذكور أو نقول مثلا send path\file ليرسل إلى الكلاينت الملف المذكور إلخ…
والإتصال يكون بواسطة ما يسمى ب السوكيت SOCKETS وهذه بمثابة قناة التواصل بينهما أو الخيط الذي يكون مسؤولا عن هذا الإتصال.
ومثالنا يمكن أن نجربه على كمبيوتر واحد أو على الشبكة وأظن ان التجربة الأولى غالبا ما تكون على كمبيوتر واحد. نشغل السيرفر بعد ذلك نشغل الكلاينت هنا يجب أن نعطيه الإيبي لكمبيوترنا وإذا لم يكن عندنا أي إيبي مثلي يمكنكم الذهاب إلى الكنترول بانل ثم الشبكة واختيار TCP وهنا يمكنم إدخال أي إيبي فمثلا أنا أدخلت الرقو 1.2.3.4 إيبي عجيب أليس كذلك. ووإذا تمت الأمور كما يرام فستتم الإتصال ويمكنكم إيذاع واستقبال الكتابة بين الكلاينت والسيرفر.
وطبعا المثالين هما أبسط ما يمكن وأفترض أن كل الأمور تتم على ما يرام ولم أرد أن أختبر هل التواصل تم بنجاح أم هناك مشكل ما وذلك حتى يكون البرنامج بسيطا جدا ولكن إذا أردنا شيئا معقولا فبالطبع يجب أخذ كل الإحتمالات والإحتياطات. لكن هذا مثال أول وأتمنى أن يكون هناك متطوع يقوم بما تبقى.

هنا سنقوم بتحليل برنامج س++ للسيرفر.
مثل المثال السابق نقوم بإنشاء نافذة DialogBox اسمها "DLGSERVER" وإيقون اسمه "MYICON".لقد زدنا ملف <winsock2.h> وهو كافي إذ فيه جميع ما نحتاج وكما يجب أن نضيف ملف ws2_32.lib حتى تكون لدينا كل الأدوات لبناء برنامجنا. وكما نرى أننا زدنا 2 events خاصين WS_ACCEPT = WM_USER و
WS_REC= WM_USER + 1 وسوف نرى صلاحيتهما من بعد.
فيما يخص WinMain فلا شيئ جديد على المثال السابق وسنرى الآن الدالة المكلفة ب Events .
حين يبدأ تهيئ الديالوغ WM_INITDIALOG سنرسم الإيقون
HICON ico;
ico=LoadIcon(hins,"MYICON");
SendMessage(hwnd,WM_SETICON,(WPARAM)ICON_BIG,(LPAR AM)ico);
نأخذ الإيقون أولا بإعطائه الهاندل للبرنامج ثم الإسم الذي اخترناه للإيقون. بعد ذلك نستعمل SendMessage لتخبر النافذة أننا سنقوم برسم الإيقون بإعطائها الرسالة WM_SETICON.

WSAStartup(0x101,&wsaData);
هذه تمكننا من إخبار وندوز أننا سنستعمل السوكيت لتهيء لنا المناخ المناسب.
soc=socket(AF_INET,SOCK_STREAM,0);
هنا نقوم بخلق السوكيت التي سنسميها soc وهي التي ستبقى في الإستماع. ولها ثلاث متطلبات ويمكن في غالب الأحيان استعمال نفس الشيء. الأول هو ما يسمى بالعائلة الثاني هو النووع والأخير هو البروتوكول.
socin.sin_family=AF_INET;
socin.sin_port=htons((u_short)11111);
soccin هي من نوع struct sockaddr_in ويجب ملؤها بخاصيات السوكيت التي نريدها. نعطيها مثلا النوع البوابة والإيبي إلا أن الإيبي لن نعطيها هنا في السيرفر لكنها أساسية في الكلاينت. و htons هي دالة مرادها أن تترجم لنا رقم البوابة المعروف عندنا إلى رقم تفهمه sockaddr_in .

bind(soc,(SOCKADDR*)&socin,sizeof(socin));
هذه بخلاصة تقوم بجعل علاقة بين السوكيت soc الذي خلقناها وبين خصائصها الذي أعطيناهم من بعد. وهذه غالبا ما تستعمل من جانب السيرفر.
listen(soc,10) ;
وأخيرا ستبدأ السوكيت في الإستماع وتنتظر أي اتصال.
WSAAsyncSelect(soc,hwnd,WS_ACCEPT,FD_ACCEPT);
هذه تقوم بربط message خاص ب event خاص. وهذا ما ذكرت في البداية.
نعلم مثلا أننا حين ننقر button فإن وندوز ترسل message إلى النافذة المسؤولة هذا message هو WM_COMMAND حين تريد الكتابة ترسل WM_SETTEXT وغيرها. لكن هنا من سيدلنا مثلا أنه قد تم اتصال فيجب أن يكون عندنا event في هذا الحال هو FD_ACCEPT أو أن السيرفر قد قبل مكالمة وبين message في حالنا سميناه WS_ACCEPT وهذا إرسال خاص اخترناه نحن وللعلم هناك إرسالات خاصة بالوندوز تبتدأ من الصفر حتى 3FF بالهيكس والخاصة تبتدأ من WM_USER = 400. بخلاصة يمكن أن نقول أنه كلما قبل السيرفر أي مكالمة فإن الوندوز ترسل لنا إرسالا رقمه 400 هيكس. ونحن حين نتصل بهذا نعرف أنه قد تم قبول. وإذن فهذه الدالة تقوم بالربط بين كل هذا وهناك كما تتوقعون عدة Event قبول الإتصال استقبال معطيات إقفال مكالمة أو غير ذلك ويمكن أخذ ما نحتاجه في البرنامج.

shutdown(soc2,SD_SEND);
closesocket(soc2);
shutdown(soc,SD_SEND);
closesocket(soc);
WSACleanup();
EndDialog(hwnd,0);
حين ننهي البرنامج نعمل التنظيف بمحي وإزالة كل ما كنا قد خلقناه.
case WM_COMMAND:
if(LOWORD(wpa)==1002)
{
char ch[100];
int ll;
GetDlgItemText(hwnd,1001,ch,100);
ll=strlen(ch)+1;
send(soc2,ch,ll,0);
return 1;
}
حين ننقر زر send لإرسال الكتابة نقوم بأخذ ما كتبناه ونضعه في بافر ch نتعرف على طوله ونرسله على متن السوكيت 2 التي سنتكلم عنها لاحقا باستعمال الدالة send .
case WS_ACCEPT:
if (LOWORD(lpa)==FD_ACCEPT)
هنا حين نتوصل بإرسالنا الخاص والسطر الثاني نتأكد أن event هو فعلا قبول المكالمة .
int sz;
sz=sizeof(socin2);
soc2=accept(soc,(SOCKADDR*)&socin2,(int *)&sz);
هنا نخلق السوكيت التي سنسميها soc2 وهذه هي التي تقوم بالربط بدلا من الأولى. فمثلا يمكن للثانية أن تتبادل الكلام مع الكلاينت بينما الأولى ترجع إلى الإستماع إذا ما تمت هناك قبول اتصال مع كلاينت آخر. في هذه الحالة نخلق سوكيت ثالثة تقوم بالإتصال لترجع الأولى للإستماع.
EnableWindow(GetDlgItem(hwnd,1002),1);
SetDlgItemText(hwnd,1003,"!!! CONNEXION ESTABLISHED !!!");
send(soc2,"!!! CONNEXION ESTABLISHED !!!",30,0);
WSAAsyncSelect(soc2,hwnd,WS_REC,FD_READ|FD_CLOSE);
حين يتم القبول نكتب رسالة تنبهنا بذلك ونرسل رسالة إلى الكلاينت .
وفي السطر الأخير سنختار أرسالا خاصا مرة أخرى وفي هذه الحالة سيخبرنا بوصول كتابة ما FD_READ أو أن الإتصال قد أغلق FD_CLOSE وكل هذا يرسل لنا ارسالا خاصا اسمه WS_REC.
case WS_REC:

if(LOWORD(lpa) == FD_READ)
حين نتصل بهذا الإرسال نتأكد أننا قد توصلنا بكتابة ما.
cc=ioctlsocket(soc2,FIONREAD,&cmd);
if(cmd)
{
char ch[100];
cc=recv(soc2,ch,100,0);
SetDlgItemText(hwnd,1000,ch);

}cc=ioctlsocket(soc2,FIONREAD,&cmd);
if(cmd)
{
char ch[100];
cc=recv(soc2,ch,100,0);
SetDlgItemText(hwnd,1000,ch);

}
المهم هنا هي الدالة الأولى وهي تستعمل لعدة أغراض وهنا سنسنتعملها لقراءة الكتابة التي وصلت وأيضا طول الكتابة فهي تحتاج لمعرفة السوكيت التي تشتغل عليها البارمتر الثاني هنا FIONREAD أننا نريد القراءة والأخير يوضع فيه طول الرسالة. وحين نتصل بشيء ما نقوم باستقباله بالدالة recv مع العلم أن الدالة الأولى لا تقرا بل تقوم بإعطاء المعلومات فقط. وإذا كنا نهتم بالتروجنات هنا يمكن أن نضيف برمجة الأوامر التي يستقبلها من الكلاينت. وبعد هذا نقوم بكتابة الرسالة.
if(LOWORD(lpa) == FD_CLOSE)
{
EnableWindow(GetDlgItem(hwnd,1002),0);
SetDlgItemText(hwnd,1003,"!!! I AM WAITING !!!");
closesocket(soc2);
وفي الأخير إذا ما كسر الإتصال كمثل أننا أقفلنا السيرفر نقوم بإخبار الكلاينت بذلك.

هذا من جانب السيرفر أما من جانب الكلاينت فالأمور تقريبا متشابهة إلا في حالة accept فبالطبع الكلاينت لن يبقى في الإستماع وإنما يحاول الربط لذى فهو سيستعمل connect.
case 1001:
GetDlgItemText(hwnd,1000,ip,16);
soc=socket(AF_INET,SOCK_STREAM,0);

socin.sin_family=AF_INET;
socin.sin_port=htons((u_short)11111);
socin.sin_addr.S_un.S_addr=inet_addr(ip);
connect(soc,(sockaddr*)&socin,sizeof(socin));
WSAAsyncSelect(soc,hwnd,WS_CONNECT,FD_CONNECT);
حين ننقر connect سنأخذ IP للسيرفر نخلق السوكيت ونعطيها الخصائص وهنا نزيد الإيبي باستعمال الدالة inet_addr التي تحول إيبي معروف على النحو 1.2.3.4 إلى إيبي ل struct.بعد هذا نستعمل connect.
والبقية تلاحظون أنها متشابهة.

أما فيما يخص الأسمبلر فأظن أنه بدون تعليق كل ما قيل مسبقا يطبق على هذا الأخير ولقد حاولت أن آخذ اسماء المتغيرات نفسها حتى يبدأ الشبه كما هو.
وهنا أريد أن أعطي أو أعيد بعض المعطيات وهي أنه حين نستدعي دالة API فإذا كانت هذه الأخيرة ترجع شيئا ما فهذا يكون في eax . فعلى سبيل المثال حين نكتب في س++ :
soc=socket(AF_INET,SOCK_STREAM,0)
بما |أن الدالة socket في الرجوع تعطينا soc الذي نستخدمه فيما بعد ففي الأسمبلر نكتب كالتالي :
invoke socket,AF_INET,SOCK_STREAM,0
وبما أن الدالة ترجع في eax فإن هذا الأخير يحتوي إذن على علامة soc لذى نكتب mov soc,eax نكتب قيمة eax الناتج المرجع في soc .
وكذلك حين نستعمل الماكرو LOWORD في س++ فهذه الأخيرة تعطينا 16 بت الأولى لعدد يحتوي على 32 بت. فمثلا eax هو رجستر من 32 بت و LOWORD ل eax ليس هو إلا ax .
وفي الأخير أريد أن أظيف أنه في الأسمبلر يجب إضافة الملف ws2_32.inc وملف ws2_32.lib وهذان فيهما كل الدوال الخاصة بالسوكيت وإظافة أيضا masm32.inc و .lib لأننا استعملنا StrLen الدالة التي تعطينا طول كتابة ما.
وفي الأخير أتمنى أن يعجبكم هذا المثال وأن تكون فيه إفادة وأتمنى أن يطوره أحدكم ولم لا ربما نقوم باتصال بواسطة هذا البرنامج. فقد لاحظت أن هنا أخ مهتم بهذا كثيرا ويريد برنامجا مثل هذا مطورا إلا أنه ليس لدي الوقت الكثير لأنكب على هذا ولكن يمكنني المساعدة في أي شيء.
وإلى اللقاء.

chik
30-09-2003, 06:33 PM
السلام عليكم,

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

في انتظار آرائكم أقول لكم إلى اللقاء.

حبروش
13-10-2003, 09:40 PM
عمل رائع جدا ومميزما ادري وشلون نشكرك عليه

الجميل فى الموضوع انه جديد تماما ولايوجد اي كتب مطبوععه تتناول هالموضوع

adel_m
15-10-2003, 11:28 PM
تسلم اخوي chik
عمل رائع وجزاك الله الف خير

سفر
15-11-2003, 08:14 AM
مشكور ما قصرت

ssh777
20-01-2004, 01:59 AM
تسلم على المشاركه الحلوه0
ويعطيك العافيه0

computer50
08-02-2004, 05:15 PM
يعطيك العافية

sameh-nabel
20-02-2004, 05:55 PM
و الله انا ممتن