الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

[ تمت الإجابة ]ListeView وبعض الأسئلة

بدأه aderfiad في 29 نوفمبر 2009 · 17 رد · 1,672 مشاهدة · في أرشيف قسم الـــ Assembly
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم

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

المهم لدي سؤال بسيط

كيف يمكنني جلب السطر الدي عليه المؤشر في ListeView

كمتال لدينا ListeView بها البروسيسات المفتوحة وزر Kill

عند الضغط على الزر يقوم بتحديد البروسيس الدي عليه التضليل يعني حدده المستعمل تم بعدها تطبيق عليه كود الاغلاق

وسؤال اخر في نفس الاطار

متلا نريد اغلاق بروسيس معين من ListeView علينا اولا جلب ID هدا البروسيس والـID في ListeView عبارة عن ارقام ( يعني قمت بتحوليه عن طريق الدالة wsprintf مع كود التحويل %lu )

يعني حتى لو جلبت ID من الـListeView لا اضن انه سيغلقه باستعمال الدالة OpenProcess تم TerminateProcess لانه يلزمه الـID قبل تحوليه الى ارقام Decimal

----

ما اعرف هو ان الاحدات الخاصة بالمكوانت متل الـListeView تكون عبارة عن رسالة WM_NOTIFY

ارجو من الاخوة توضيح الامرين وشكرا لكم

تم تعديل هذه المشاركة بواسطة aderfiad في 29 نوفمبر 2009 في 03:48

#2
aderfiad كتب:

كيف يمكنني جلب السطر الدي عليه المؤشر في ListeView

كمتال لدينا ListeView بها البروسيسات المفتوحة وزر Kill

عند الضغط على الزر يقوم بتحديد البروسيس الدي عليه التضليل يعني حدده المستعمل تم بعدها تطبيق عليه كود الاغلاق

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

بخصوص ما تسأل عنه، راجع آخر مقالة Iczelion التي تتكلم عن ListView

http://win32assembly.online.fr/tut31.html

نهايتها تماماً.

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

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#3

السلام عليكم

لقد قرأت المقال سابقا ومنه تعلمت التعامل مع ListeView

لكن عندما وصلت الى هدا الامر لم افهمه لاني لا اتقن فهم الاجنليزية

ارجو ان تشرح لي الامر اخي Xacker فقد بحت في النت باكمله ولم اجد شيئا

سورس الاخ GM لم افهم فيه الامر

وصلت الى هنا وتوقفت

elseif uMsg == WM_NOTIFY

 	push edx
	mov edx,lParam
	assume edx:ptr NMHDR
	mov eax,[edx].hwndFrom
	.if eax == hlistev
 	.if [edx]. code == LVN_COLUMNCLICK
 	assume edx:ptr NM_LISTVIEW 
 	.if [edx].iSubItem==1

الى هنا الامر مفهوم

#4

لم أفهم بالضبط هل الكود أعلاه مفهوم وتسأل عما يليه أم أنك توقفت عنده وتريد فهمه..

بكل الاحوال سأشرحه بسرعة،

iczelion يتكلم عن ترتيب عناصر column في listview عند النقر على ترويسة العمود column header، (كما تفعل عندما تريد ترتيب أسماء الملفات تصاعدياً أو تنازلياً في مجلد مثلاً)، الحدث المرسل في هذه الحالة يكون WM_NOTIFY إذاً علينا التقاطه

.elseif uMsg == WM_NOTIFY

عندما يتم استقبال حدث WM_NOTIFY فإن lParam ستكون مؤشر إلى كتلة NMHDR

typedef struct tagNMHDR {

HWND hwndFrom; //A window handle to the control sending the message.

UINT_PTR idFrom;

UINT code; //A notification code. This member can be one of the common notification codes or it can be a control-specific notification code.

} NMHDR;

سنقوم بحفظ قيمة edi (يبدو أنها تحمل قيمة مهمة ويجب الاحتفاظ بها واستعادتها لاحقاً).

ثم سنقوم بنقل عنوان المؤشر lParam إلى edi

والآن سنخبر الأسمبلر أن يتعامل مع edi باعتبارها مؤشر لكتلة محددة مسبقاً حتى يكون بإمكاننا الوصول إلى عناصرها بسهولة أكبر

mov edi,lParam
assume edi:ptr NMHDR

سنتحقق أن الحدث حصل بسبب النقر على الـ column وهذا يمكن أن يتم من خلال معرفة قيمة المتغير hwndFrom التابع للكتلة NMHDR الذي يكون عبارة عن handle للعنصر المختص بحدث التنبيه WM_NOTIFY هذا، بالتالي..

mov eax,[edi].hwndFrom
.if eax==hList

الآن نريد أن نحدد إن كان التنبيه حصل بسبب النقر على column header، وهذا يمكن من خلال معرفة قيمة المتغير code التابع للكتلة NMHDR أيضاً والذي سيكون إحدى قيم محددة مسبقاً، ما نريده هو القيمة LVM_COLUMNCLICK، بالتالي..

.if [edi].code == LVN_COLUMNCLICK

الآن نريد أن نعرف أي الأعمدة تم النقر على ترويسته، وهذا يمكن من خلال الكتلة الأعلى من NMHDR والتي تحويها أساساً، اسمها NM_LISTVIEW (أو NMLISTVIEW بعد تغيير اسمها لتتوافق مع معايير التسمية القياسية)

typedef struct tagNMLISTVIEW {

NMHDR hdr; //NMHDR structure that contains information about this notification message.

int iItem;

int iSubItem; //Identifies the subitem, or zero if none.

UINT uNewState;

UINT uOldState;

UINT uChanged;

POINT ptAction;

LPARAM lParam;

} NMLISTVIEW, *LPNMLISTVIEW;

لذلك سنخبر الأسمبلر أن يعتبر قيمة edi مؤشر لكتلة NM_LISTVIEW

assume edi:ptr NM_LISTVIEW

يمكن الآن بكل بساطة تحديد العمود من خلال معرفة قيمة المتغير iSubItem التابع للكتلة NM_LISTVIEW، القيمة الخاصة بالتابع هي بكل بساطة رقم العمود (بدءاً من الـ 0 للعمود الأول وهكذا..)

.if [edi].iSubItem == 1

وهو المطلوب.

أما بخصوص سؤالك الأساسي في الموضوع، ما تريده موجود أسفل المقال، ناحية الحديث عن العنصر الذي يملك الـ focus.

تم تعديل هذه المشاركة بواسطة Xacker في 30 نوفمبر 2009 في 21:19

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#5

شكرا لك على الشرح اخي

لكن كل ما شرحته فوق فهمته من المقال وهو ما كتبته في ردي

توقفت عند هده النقطة . تم التعرف على ListeView تم العمود

والباقي هو ما لم افهمه , كيف ستجلب العلومة المكتوبة في خانة من خانات ListeView وتضعها في متغير

من هنا بدأت الامور تصعب في الفهم

ابتداء من هده النقطة لم افهم شيئا

.if SizeSortOrder==0 || SizeSortOrder==2

invoke SendMessage,hList,LVM_SORTITEMS,1,addr CompareFunc

تم تعديل هذه المشاركة بواسطة aderfiad في 30 نوفمبر 2009 في 21:17

#6
Xacker كتب:

أما بخصوص سؤالك الأساسي في الموضوع، ما تريده موجود أسفل المقال، ناحية الحديث عن العنصر الذي يملك الـ focus.

سأحاول أن ألخّصه لك.

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#7

شكرا

في الانتضار ...

#8

كما تحدثت في الأعلى عن التقاط الحدث WM_NOTIFY ومن ثم تحديد أن الحدث مرتبط بالعنصر listview نفس الأمر سيتم هنا..

حتى تقوم بتحديد السطر الذي تم اختياره في listview عليك التقاط الحدث ومن ثم ربطه بـ listview

.if uMsg == WM_NOTIFY
	push    edi
	mov		edi,lParam
	assume	edi:ptr NMHDR
	mov		eax,[edi].hwndFrom
	.if (eax == hList)
	     code here is explained next...
	.endif
	pop		edi
.endif

خلافاً لما ورد في الأعلى، ما نحتاجه الآن هو معرفة إن كان التنبيه حصل بسبب النقر (اختيار) سطر ما من listview، والتنبيه المرتبط بهذا هو القيمة NM_CLICK التي ستكون موجودة ضمن المتغير code من NMHDR، قد يكون التنبيه أيضاً حصل بسبب النقر المضاعف على السطر، ربما نود أن نعامله ذات المعاملة بالتالي نراقب أيضاً NM_DBLCLK، بالتالي..

.if uMsg == WM_NOTIFY
	push    edi
	mov		edi,lParam
	assume	edi:ptr NMHDR
	mov		eax,[edi].hwndFrom
	.if (eax == hList)
		.if (([edi].code == NM_CLICK) || ([edi].code == NM_DBLCLK))
			; code here is explained next...
		.endif
	.endif
	pop		edi
.endif

الآن سنقوم بجلب قيمة لافتة السطر (label) - الأمر يتم من خلال معرفة أي سطر حصل على التركيز focus وهذا ممكن من خلال إرسال رسالة LVM_GETNEXTITEM والتي تملك وسيطين wParam و lParam، wParam يحدد index السطر نضع فيه القيمة -1 التي تعني (ابحث في كل العناصر)، lParam يحدد حالة السطر التي نريدها وهي LVNI_FOCUSED، بالتالي..

.if uMsg == WM_NOTIFY
	push    edi
	mov		edi,lParam
	assume	edi:ptr NMHDR
	mov		eax,[edi].hwndFrom
	.if (eax == hList)
		.if (([edi].code == NM_CLICK) || ([edi].code == NM_DBLCLK))
			invoke    SendMessage,hList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED ; return item index in EAX
			; code here is explained next...
		.endif
	.endif
	pop		edi
.endif

index السطر المطلوب يتم إعادته في EAX، جميل، كل ما علينا الآن هو أن نطلب لافتة هذا السطر بإرسال رسالة LVM_GETITEM مع تحدد الـ index، بالتالي..

LOCAL    lvi			:LV_ITEM
LOCAL    buffer[256]	:BYTE

.if uMsg == WM_NOTIFY
	push    edi
	mov		edi,lParam
	assume	edi:ptr NMHDR
	mov		eax,[edi].hwndFrom
	.if (eax == hList)
		.if (([edi].code == NM_CLICK) || ([edi].code == NM_DBLCLK))
			invoke    SendMessage,hList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED ; return item index in EAX
			mov        lvi.iItem,eax
			mov        lvi.iSubItem,0
			mov        lvi.imask,LVIF_TEXT
			lea        eax,buffer
			mov        lvi.pszText,eax
			mov        lvi.cchTextMax,256
			invoke    SendMessage,hList,LVM_GETITEM,0,addr lvi
			; and we display a message box with the label
			invoke    MessageBox,0,addr buffer,NULL,MB_OK
		.endif
	.endif
	pop		edi
.endif

كما ترى فقد قمت بحجز متغير محلي في المكدس باسم lvi هو عبارة عن الكتلة LV_ITEM التي تحدد صفات السطر الخاص بـ listview، وحجزت متغير محلي آخر هو عبارة عن مخزن buffer لاستعادة النص فيه.

تذكر، الكود الأخير لا يشكل proc متكامل، أي أنك يجب أن تدخله ضمن proc بالشكل المناسب حتى تستطيع تنفيذه. جرب استخدامه، فلم أكتبه ضمن برنامج يحوي listview واختبرته ربما أخطأت في شئ ما.

تم تعديل هذه المشاركة بواسطة Xacker في 30 نوفمبر 2009 في 22:36

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#9

شكرا لك اخي شرح مفهوم 100/100

ساقوم بالتطبيق ولي عودة بادن الله

#10

تمام اخي الكريم 10/10

عملت كما شرحت واشتغلت تمام

بالنسبة للسؤال التاني ساعيد البحت في كود برنامج Process Detective

ولي عودة

#11

وجدت الكود المسؤول عن هدا العمل هدا ما فهمت منه

.if 	wParam == IDM_KILL		; -> Terminate Process
					invoke OpenProcess,PROCESS_TERMINATE,FALSE,FUNC(GetSelectedPID)

هنا الامر واضح قام بفتح البروسيس في حالة PROCESS_TERMINATE و في الـID استعمل هده الـPROC

SelectedPID				proc	
	invoke SendMessage,hPList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED
	invoke GetItemText,hPList,eax,1

	mov esi, eax
	xor eax,eax
	xor ecx, ecx
	xor edx, edx
	mov al, [esi]
	inc esi
	.while (al)
		sub al, "0"
		lea ecx, dword ptr [ecx+4*ecx]
		lea ecx, dword ptr [eax+2*ecx]
		mov al, byte ptr [esi]
		inc esi
	.endw
	lea eax, dword ptr [edx+ecx]
	xor eax, edx

	ret
GetSelectedPID endp

السطرين الاولين هما لجلب الـID من ListeView على شكل ارقام

لكن كود التحويل صعبة الفهم

تم تعديل هذه المشاركة بواسطة aderfiad في 30 نوفمبر 2009 في 23:53

#12

ليس هناك صعوبة في الأمر، العمليات رياضية بسيطة جداً..

الهدف هو تحويل نص ASCII يمثل رقم مهما كان طوله (الهدف من استخدام حلقة تستخدم AL كمتغير) إلى رقم صحيح.

لنفرض لدينا الرقم 7531 يمثل PID لكنه موجود في الذاكرة بترميز ASCII أي سيظهر بالشكل:

37 35 33 31

ونحن نريده بصيغة عدد صحيح عشري 7531 (أو hex حسبما يتم التعامل معه في المسجّلات)

لاحظ أولاً أن بطرح 30h من كل byte من السلسلة السابقة تحصل على

07 05 03 01

هذا تقريباً ما نريد لكنه ما زال في 4 بايتات منفصلة. وهو ما يقوم به السطر

sub al,"0"

الآن لدينا

lea ecx, dword ptr [ecx+4*ecx]
lea ecx, dword ptr [eax+2*ecx]

ضعها في سطر واحد كمعادلة رياضية

eax + 2*( ecx + 4*ecx) = eax + 10*ecx

قيمة eax هي الأرقام 07,05,03,01,00 التي تشحن على الترتيب (من اليسار إلى اليمين)

ecx مسجل يحمل قيمة ابتدائية 0، وفي كل خطوه يتم شحنه بناتج العملية الرياضية أعلاه.

لاحظ الرقم 00 الذي ذكرته في نهاية السلسلة، ما هذا؟ هو بكل بساطة الـ null terminator في نهاية الحلقة والذي ينتفي عنده الشرط ويتم الخروج منها.

لنطبق ما ذكرناه على الرقم المطروح كمثال

eax + 10*ecx

eax = 7, ecx = 0 therefore ecx = 7 + 10*0 = 7

eax = 5, ecx = 7 therefore ecx = 5 + 10*7 = 75

eax = 3, ecx = 75 therefore ecx = 3 + 10*75 = 753

eax = 1, ecx = 753 therefore ecx = 1 + 10*753 = 7531 (tada!)

طبعاً الاختلاف الوحيد أني في الشرح أتعامل مع الأرقام كقيم عشرية، والعمليات ستعطي نتائج ست عشرية.. وهو المطلوب لتستخدمه مع OpenProcess

تم تعديل هذه المشاركة بواسطة Xacker في 1 ديسمبر 2009 في 00:56

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#13

اولا شكرا لك على الشرح

لكن مع كامل الاسف لم استطع فهمه

قرأته مرات ومرات ولم افهمه

#14

انظر الى هذا

mimetex.cgi?7531 = 7000+500+30+1 = 7*10^

هذه طريقة أخرى للتحويل، لكنها تتطلب مسجّلات أكثر من الطريقة التي شرحتها أعلاه.

AL هي قيمة البايت الذي يتم انتزاعه من [esi] بالسطر

mov al,[esi]

10 هي قيمة ثابتة تستطيع وضعها في BL.

i هو متحول ينتقل من 0 إلى n-1=3 حيث n=4 هي عدد مراتب العدد 7531.

سيكون عليك في هذه الحالة حساب mimetex.cgi?10^i ويمكنك أن تطبق هذا من خلال حلقة أخرى فمثلاً mimetex.cgi?10^3=10*10*10، يمكنك أن تجعل CL=i وتنفذ عملية الضرب لتحصل على الناتج النهائي.

بعدها يصبح من السهل ضرب القيمة بـ AL (انتبه إلى أنه في حال كانت i تبدأ بـ 0 باتجاه 3 فعندها AL الأولى ستكون 1 وليست 7 والعكس صحيح)

والناتج النهائي للتحويل هو المجموع.

الطريقتين المذكورتين هذه والسابقة لهما نفس الفكرة تقريباً.. لكن كما ترى العملية السابقة أسهل في التنفيذ.

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#15

لم تفهم قصدي اخي

ليس الشرح هو الغير مفهوم

بل الامر من اساسه غير مفهوم

لاوضح الامر متلا قمنا بجلب الـID من ListeView وهو متلا 456

ادا مررناه هكدا الى الدالة OpenProcess فلن تتعرف عليه

السؤال هو ما هي الصيغة التي يجب ان نحول لها هدا العدد كي تقرئها الدالة OpenProcess

انت قلت الداكرة

ما فهمت هو ان الصيغة هي صيغة هدا الرقم في الداكرة

لكن حسب ما اعلم ان صيغ الارقام في الداكرة تكون بالهكس

#16
aderfiad كتب:

السؤال هو ما هي الصيغة التي يجب ان نحول لها هدا العدد كي تقرئها الدالة OpenProcess

الرقم ذاته لكن بالهكس

aderfiad كتب:
انت قلت الداكرة

ما فهمت هو ان الصيغة هي صيغة هدا الرقم في الداكرة

لكن حسب ما اعلم ان صيغ الارقام في الداكرة تكون بالهكس

انت تستعيد نص من listview يا أخي

نعم القيمة في الذاكرة hex، لكن انت تستعيد نص لذلك قيمته في الذاكرة نص أسكي مكتوب بشكل هكس وهو ما مثلته لك بالشكل 37353331 (37 هو الهكس للرقم 7 في أسكي!)

Do as I say, not as I do

We are Anonymous. We are Legion. We don't forgive. We don't forget

#17

شكرا لك

بدأت افهم الان

الوقت متأخر الان سأدهب ولي عودة غدا بادن الله لاعادة التركيز في الشرح اعلاه وتطبيقه

#18

السلام عليكم

فهمت الامر الان

بارك الله فيك

مواضيع مشابهة