=================================================================================
下面处理WM_LBUTTONDOWN。
0000:00404E79 loc_404E79:
0000:00404E79 movzx eax, [ebp+lParam]
//取lParam的低16位,注意它用的是movzx,和下面不同。
//开始静态分析没有看出来差别,还是debug了一下才明白。
0000:00404E7D mov [ebp+pt.x], eax
0000:00404E80 mov eax, dword ptr [ebp+lParam]
0000:00404E83 call sub_403C6C
//这个call实际是取eax的高16位
0000:00404E88 movzx eax, ax
//截掉废的bit
0000:00404E8B mov [ebp+pt.y], eax
0000:00404E8E push [ebp+pt.y]
0000:00404E91 push [ebp+pt.x] ; pt
0000:00404E94 push offset sRect ; lprc
0000:00404E99 call PtInRect
//这个API有点意思,一般API传结构都是传地址,比如sRect,但是它
//传Point就直接传值了。以前还真没有看到这样的API。
0000:00404E9E test eax, eax
0000:00404EA0 jz loc_404F8F
//返回True才继续
0000:00404EA6 push 0 ; lParam
0000:00404EA8 push 2 ; wParam
0000:00404EAA push 0A1h ; '? ; Msg
//碰到这种Msg,应该查出它的名称。当然直接用值也可以,但是不利于理解
//上面还有2个参数,虽然查到意思,还是不很明白。
0000:00404EAF mov eax, [ebp+hWnd]
0000:00404EB2 push eax ; hWnd
0000:00404EB3 call PostMessageA
0000:00404EB8 jmp loc_404F8F
0000:00403C6C sub_403C6C proc near
0000:00403C6C
0000:00403C6C shr eax, 10h
0000:00403C6F retn
0000:00403C6F sub_403C6C endp
OK,下面就是WM_LBUTTONDOWN的代码了:
WM_LBUTTONDOWN:
Begin
sPoint.x:=lParam AND $FFFF;
sPoint.y:=lParam SHR 16;
//这里就不能用Hi和Lo了
If PtInRect(sRect,sPoint) Then
Begin
PostMessage(hDlg,WM_NCLBUTTONDOWN,2,0);
End;
End;
运行一下,效果出来了。虽然还是没有看到标题栏,但是那个地方点上去已经可以
拖了。
好,还有2个WM。大概看看,WM_DRAWITEM量比较少,而WM_PAINT写了一堆。当然先
逆WM_DRAWITEM了。
0000:00404F3F loc_404F3F:
0000:00404F3F mov eax, dword ptr [ebp+lParam]
0000:00404F42 call sub_4042AC
//拜托,又是一个公用call。参数就是lParam的值
0000:00404F47 xor ebx, ebx
0000:00404F49 jmp short loc_404F8F
0000:004042AC sub_4042AC proc near
//怎么知道它是公用的call?很简单,IDA有ref信息的。不过我贴的时候去掉了
0000:004042AC
0000:004042AC String = byte ptr -0Ch
0000:004042AC
0000:004042AC push ebx
0000:004042AD add esp, 0FFFFFFF4h
//sub esp,0CH
0000:004042B0 mov ebx, eax
//入口参数
0000:004042B2 mov eax, ds:hbr
0000:004042B7 push eax ; hbr
0000:004042B8 lea eax, [ebx+1Ch]
//有麻烦了,ebx到底是什么?还好Delphi带的SDK文档很不错,可以查到
//WM_DRAWITEM的lParam是^DRAWITEMSTRUCT
//另外,注意这里用了LEA取地址,所以eax=ebx+1ch,是一个地址
//对照Windows.pas里的定义可以看到它用的定义是const lprc: TRect。
//所以把结构的成员直接写了没有问题的,Delphi会自己转换。
//后面的调用也有这个问题,但是Delphi很不错。用汇编就要自己注意了。
0000:004042BB push eax ; lprc
0000:004042BC mov eax, [ebx+18h]
0000:004042BF push eax ; hDC
0000:004042C0 call FillRect
0000:004042C5 push 0A0A0A0h ; COLORREF
0000:004042CA mov eax, [ebx+18h]
0000:004042CD push eax ; HDC
0000:004042CE call SetTextColor
0000:004042D3 push 1 ; int
0000:004042D5 mov eax, [ebx+18h]
0000:004042D8 push eax ; HDC
0000:004042D9 call SetBkMode
0000:004042DE push 0Fh ; grfFlags
//在SDK里可以查到是一些值的组合,下面还有。
0000:004042E0 push 1 ; edge
0000:004042E2 lea eax, [ebx+1Ch]
0000:004042E5 push eax ; qrc
0000:004042E6 mov eax, [ebx+18h]
0000:004042E9 push eax ; hdc
0000:004042EA call DrawEdge
0000:004042EF push 0Ah ; nMaxCount
0000:004042F1 lea eax, [esp+10h+String]
0000:004042F5 push eax ; lpString
0000:004042F6 mov eax, [ebx+14h]
0000:004042F9 push eax ; hWnd
0000:004042FA call GetWindowTextA
0000:004042FF push 25h ; uFormat
0000:00404301 lea eax, [ebx+1Ch]
0000:00404304 push eax ; lpRect
0000:00404305 push 0FFFFFFFFh ; nCount
0000:00404307 lea eax, [esp+18h+String]
0000:0040430B push eax ; lpString
0000:0040430C mov eax, [ebx+18h]
0000:0040430F push eax ; hDC
0000:00404310 call DrawTextA
0000:00404315 test byte ptr [ebx+10h], 1
0000:00404319 jz short loc_404350
0000:0040431B push 0DDFFh ; COLORREF
0000:00404320 mov eax, [ebx+18h]
0000:00404323 push eax ; HDC
0000:00404324 call SetTextColor
0000:00404329 push 25h ; uFormat
0000:0040432B lea eax, [ebx+1Ch]
0000:0040432E push eax ; lpRect
0000:0040432F push 0FFFFFFFFh ; nCount
0000:00404331 lea eax, [esp+18h+String]
0000:00404335 push eax ; lpString
0000:00404336 mov eax, [ebx+18h]
0000:00404339 push eax ; hDC
0000:0040433A call DrawTextA
0000:0040433F push 0Fh ; grfFlags
0000:00404341 push 2 ; edge
0000:00404343 lea eax, [ebx+1Ch]
0000:00404346 push eax ; qrc
0000:00404347 mov eax, [ebx+18h]
0000:0040434A push eax ; hdc
0000:0040434B call DrawEdge
0000:00404350
0000:00404350 loc_404350:
0000:00404350 add esp, 0Ch
0000:00404353 pop ebx
0000:00404354 retn
0000:00404354 sub_4042AC endp
好的,WM_DRAWITEM和sub_4042AC出来了。
WM_DRAWITEM:
Begin
ItemDraw(PDrawItemStruct(lParam));
Result:=0;
End;
Procedure ItemDraw(lpDIS:PDrawItemStruct);
Var
Str:String;
Begin
FillRect(lpDIS^.hDC,lpDIS^.rcItem,h_Brush);
SetTextColor(lpDIS^.hDC,$A0A0A0);
SetBkMode(lpDIS^.hDC,TRANSPARENT);
DrawEdge(lpDIS^.hDC,lpDIS^.rcItem,BDR_RAISEDOUTER,BF_RECT);
GetWindowText(lpDIS^.hwndItem,PChar(Str),10);
DrawText(lpDIS^.hDC,PChar(Str),-1,lpDIS^.rcItem,DT_SINGLELINE OR DT_VCENTER OR DT_CENTER);
If lpDIS^.itemState MOD 2=1 Then
Begin
SetTextColor(lpDIS^.hDC,$DDFF);
DrawText(lpDIS^.hDC,PChar(Str),-1,lpDIS^.rcItem,DT_SINGLELINE OR DT_VCENTER OR DT_CENTER);
DrawEdge(lpDIS^.hDC,lpDIS^.rcItem,BDR_SUNKENOUTER,BF_RECT);
End;
End;
试试看,原来是画三维边框。
另外,不知道大家注意到没有,贴上来的PAS代码其实都是排好的。直接C&P就可以,
连缩进也不用做。
还有,上面的代码有个问题,至少我认为是个问题。就是在GetWindowText那里。
虽然已经限制了长度,但是Str没有初始化,这个在以前没有什么,因为都是Short的。
但是现在还有个PChar,而且和Short都对应到String类型。以前老是有人抱怨说PChar
出AccessViolation,结果最后发现是没有初始化,PChar都指到随机地址了。后来用了
SetLength就OK了。不过这里因为Str是在堆栈分配的,所以个人认为问题不大。不知老
钱怎么看这个问题,最好是请他指教一下。