Does anyone know how to alternate the color of listview rows using assembly only?
To change any non-standard option in an ActiveX control (such as the ListView), you have to subclass the control. Doing this can be quite a feat if you've never attempted it before. At its roots however, you aren't doing much more than intercepting messages send to the control's window, handling the ones you need and passing the rest on to the window's original WndProc.
1: Create the window for the ActiveX control.
2: Call GetWindowLong with GWL_WNDPROC to get the address of the old window procedure
3: Call SetWindowLong to set the address or your own WndProc
4: In your custom WndProc call CallWndProc for all messages you don't handle
5: Restore the old window procedure when you close down your app. (see step 3)
Now, that was fairly simplistic but it is a place to start. MSDN has an article titled Safe Subclassing in Win32 (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_subclas3.asp). That is a good reference.
ListView isn't an activex control.
To change color & font of common controls you can use custom draw
This is taken from Gremaf (listview.asm), a program of mine
mov ecx, pHdr
mov eax, [ecx.NMHDR].code
.elseif eax == NM_CUSTOMDRAW
mov eax, [ecx.NMCUSTOMDRAW].dwDrawStage
.if eax == CDDS_PREPAINT
mov eax, CDRF_NOTIFYITEMDRAW
ret
.elseif eax == CDDS_ITEMPREPAINT
invoke VirtualLw_PaintRow, ecx
mov eax, CDRF_NEWFONT
ret
.endif
VirtualLw_PaintRow proc private uses esi pHdr:DWORD
LOCAL buffer[256] : BYTE
mov ecx, pHdr
mov esi, [ecx.NMCUSTOMDRAW].dwItemSpec
;Calculate the value of [pGameStr][ecx->dwItemSpec]
mov eax, [ecx.NMCUSTOMDRAW].dwItemSpec ;Row number
mov edx, pGameStr ;Array base
mov esi, [edx + eax*4] ;Address of our GAME_STR structure
;Check the status
mov al, [esi.GAME_STR].StatusMask ;Load status bitmask
.if al == STATUS_GOOD
mov eax, ColorGood
.elseif al == STATUS_BEST
mov eax, ColorBest
.elseif al == STATUS_BAD
mov eax, ColorBad
.else
mov eax, ColorNot
.endif
mov esi, pHdr
mov [esi.NMLVCUSTOMDRAW].clrTextBk, eax
ret
VirtualLw_PaintRow endp
pHdr is the pointer to the NMHDR structure. The first code is the code in response to WM_NOTIFY.
This code changes the color of the row according to the value of a variable (member of a private game_str structure) but you can check if the row is even or odd
StatusGood, StatusBad, .... ColorBad, ColorNot are private variables (or private constants)
Thanks greenant,
Your solution works fine for the 1st screen, but when I scroll the screen it doesn't alternate the color. I have very little API experience, so I expect it's some simple thing I'm not yet aware of. I appreciate your help.
I don't know. Maybe a property of the listview.
Try downloading gremaf and study the listview.asm file
Hi Mr Earl
This is from one of my current projects that I use in the office - it should alternate the colours in the listview
I subclass the listview by using this in my main Proc
; ........ some code
invoke SetWindowLong,hList,GWL_WNDPROC,listViewProc
mov hOldListProc,eax
; ........ more code
and this is the subclassing code
listViewProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL lvi:LV_ITEM
mov eax,uMsg
.if eax==WM_NOTIFY
mov edi,lParam
ASSUME edi:ptr NMHDR
.if [edi].code == NM_CUSTOMDRAW
mov ecx,edi
ASSUME ecx:ptr NMLVCUSTOMDRAW
.if [ecx].nmcd.dwDrawStage == CDDS_PREPAINT
mov eax,CDRF_NOTIFYITEMDRAW
ret
.elseif [ecx].nmcd.dwDrawStage == CDDS_ITEMPREPAINT
mov eax, [ecx].nmcd.dwItemSpec
and eax, 1
dec eax
and eax, (00EEF2C8h - 00D6F8D3h) ;=(a-b)+b = a ; change these values to change colours
add eax, 00D6F8D3h ;(0)+b=b
mov [ecx].clrTextBk, eax
mov eax, CDRF_NEWFONT
ret
ASSUME ecx:nothing
.endif
; ------check for double click --------;
.elseif [edi].code == NM_DBLCLK
invoke SendMessage,hList,LVM_GETNEXTITEM,-1,LVNI_FOCUSED
mov lvi.iItem,eax
mov lvi.iSubItem,0
mov lvi.cchTextMax,60
mov lvi.pszText,offset selectedProject
mov lvi.imask,LVIF_TEXT
invoke SendMessage,hList,LVM_GETITEM,0,addr lvi
invoke DialogBoxParam, hInstance, IDD_ProjectView , hWin, addr ProjectViewProc , NULL
.else
invoke CallWindowProc, hOldListProc,hWin,uMsg,wParam,lParam ; let windows deal with rest
.endif
ASSUME edi:nothing
.else
invoke CallWindowProc, hOldListProc,hWin,uMsg,wParam,lParam ; let windows deal with rest
.endif
ret
listViewProc endp
The code may not be perfect but it works for me - and I'm still learning :)
Hope this helps
Taff
Thanks taff_e
After much juggling code I finally got it to work. The problem was my method for determining even/odd. When I took taff_e's algorithm for even/odd and put it into greenant's code it works perfectly. Subclassing wasn't needed, but thanks taff_e, your code enabled me to get it working.