I have recently been writing a custom listview control as a bit of MASM practice (its my first control) and would like to get your ideas/suggestions/comments on it. Its still in a pretty basic state, I need to add in alot more stuff and expose alot more properties but to start with I wanted it to be straightforward to use and to have a range of different formatting options.

One thing I wanted to do was to keep the data handling pretty straightforward. Anytime the control needs data it will send a WM_NOTIFY message to its parent (using a DDLV_INFO structure) which is a zero based row/col structure. When it needs to draw/format a cell it will send another WM_NOTIFY message (using a DDLV_DRAW structure) to ask for formatting options (again sending zero based row/col to identify the cell). Each cell exposes the hdc of the control so for each cell you can change the font, text colour etc. and the background brush for each cell can also be supplied.

There is an example project in the zip file along with the control/include files (cdLV.lib, cdLV.inc). It shows a basic usage of the control (no exciting data) and some row highlighting/cell formatting. All the brushes are created by the calling project - so it is responsible for cleanup of the brushes/fonts etc.

At the moment it still uses the Header control, but the list is all done from scratch. When i have more time ill do a custom header.
Posted on 2003-05-15 02:38:24 by MurkyT
Haven't looked at the source, just played a bit with the exe.
Looks good so far! Got a couple suggestions though :)

- make selection happen on mouse click, not release.

- perhaps use/support callbacks instead of/in addition to notify messages?

Btw, it's pretty smooth - are you doing double buffering?
Posted on 2003-05-15 02:54:16 by f0dder
program crashes on xp when i close it. odd.
Posted on 2003-05-15 04:33:59 by xkardisx
looks very good under NT4 (SP6) ..

the handling is very fast.

What about an TreeView-Control too? CommonControl Treeviews are terribly
slow when inserting with to many items. Such a code would even be useful
for Linux-Coders, if they refuse to use shitty class libraries.

Bye Miracle
Posted on 2003-05-15 07:23:58 by miracle
Thanks for your replies!

Fodder - good suggestion for putting the selection onto the button down rather than button up. I'll have a look at how to do the callback stuff. I'm not doing any back buffering on the control at the moment. I tried to be very careful about how much of the control I updated at any one time and also tried to only write once to each pixel per paint. Seems to be working ok so far but if things start to get messy I may well go the back buffering route.

xkardisx - strange that it crashes on exit..I've tried it on XP here and it worked ok. I'll have a look to see if I've done anything silly which would cause it to crash.

miracle - good to know it works on NT - thats the one windows OS i don't have. I do have some thoughts on maybe using the Listview in combination with a treeview - ill let you know if I get there!
Posted on 2003-05-15 10:35:34 by MurkyT
murky, nice to see there's some coders left that actually care ;)
my OS is win2k btw, so that's another NT it works on. If you need help debugging on XP lemme know, I have XP machines too.
Posted on 2003-05-15 10:47:03 by f0dder
Nice work MurkyT :alright: The only thing that I would like is scrolling like a normal listview (smooth, not per-line), but that's personal preference. It did crash on exit on my XP machine too, I (shamelessly :)) took a look at the disassembly of your program and I think you got the first two API calls in the next piece of reconstructed code in the wrong order, ebx is zero (or garbage) when it enters the if case, that's why the reference to (probably your control info structure) is invalid and causes a crash:

.elseif uMsg==WM_DESTROY
invoke DeleteObject, dword ptr [ebx + 20]
invoke GetWindowLong, [hWnd], GWL_USERDATA
mov ebx, eax
invoke GetProcessHeap
invoke HeapFree, eax, 0, ebx
invoke PostQuitMessage, 0

Posted on 2003-05-15 13:03:49 by Thomas
Thanks for spotting that Thomas, the api calls were indeed the wrong way round - doh! I'll upload a new version with that fixed and a few other bits and pieces later today. I would be grateful if anyone who has it crashing on XP could test to see that it has fixed the problem. So - file to follow later!

Also, I have a question about callbacks...Fodder suggested that maybe the data could be requested by a callback function as well as by a WM_NOTIFY. I can set up the callback function - and let the developer choose which one to use, but at the moment I am passing the row and col to the callback individually. I tried to pass them as a structure but I couldn't seem to get the syntax right - can anyone tell me how to do that? (or if its worth doing that?)

This is what I have at the moment, passing the parameters individually

; ********* code from control *********
push edi ; *** col
push esi ; *** row

mov eax,[ebx].lpDataFn ;*** pointer to callback
call eax

; ******* code from test program which holds callback ****
CBFunc PROC item:DWORD,subItem:DWORD

;**** return a pointer to the data
mov eax,offset szBitofText

CBFunc endp
Posted on 2003-05-15 14:35:49 by MurkyT
If passing two parameters bother you, you could pass them as a single dword - either 64k entries with 64k subitems, or some other combination (I'd choose more bits for items and less for subitems, even though this means you have to mask instead of just movzx with words). However, passing two dwords to a function is not really a bad thing to do, and passing a struct isn't going to save you much either (possibly it would be worse than stack passing - I can elaborate more on this theory if anybody wants me to).

And well... you might as well just keept it as two dword pushes. It's not that much overhead, and it should cover all needs in the next couple of years ;P

I would suggest to keep "item" scrolling as it is, instead of "Pixel" scrolling. Pixel scrolling often annoys me :)

Btw, love the hat on your avatar pic :)
Posted on 2003-05-15 14:51:25 by f0dder
btw, you might also want to send cache hints like windows listview does. It's not much use when you store your items in an efficient-to-index data structure, but if you use a listview control to represent, say, a huge database or whatever (where fetching an item can be slow), it can be nice to get the cache message (ie, "I'll need items 100-200 soon"), since getting a batch of data is often faster than getting each data piece in response to a callback.
Posted on 2003-05-15 15:18:42 by f0dder
Not heard of cache hinting before...interesting thought. Could it be sent to the callback as a third parameter?Maybe a number perhaps (+ve if scrolling downwards, -ve if scrolling back up) which would be 2-3 times the number of rows per page? would that be a valid range? Or is there a standard way of doing it?

Gald you like the beanie lol..one of my friends found a page on aluminium beanies http://www.zapatopi.net/afdb.html and we all made one and took a pic.(it was a slow evening!)
Posted on 2003-05-15 15:33:50 by MurkyT
for regular listview controls, LVN_ODCACHEHINT in WM_NOTIFY.
I would suggest keeping this separate from the normal callback, so apps that don't need this message can easily ignore it and suffer very little overhead.
Posted on 2003-05-15 15:36:51 by f0dder
Ok - i've uploaded a new version of the test program (with new versions of the cdLV.lib and cdLV.inc)

This test has two LV's working independently of each other - first with about 100 rows, second one with 1,000,000 rows. The first LV shows the usage of two buttons to add a column on the end or add 100 rows (just to show how the messages work at the moment, DDLVM_GETNUMCOLS,DDLVM_GETCOUNT,DDLVM_SETCOUNT)

The first LV requests data via a WM_NOTIFY message.
The second LV requests via a callback - this specified in the initalizing structure, fill in the lpDataFn field with the offset of the callback

I've also changed the selection to a mouse button down rather than mouse up, hopefully the crash on exit should be fixed (thanks Thomas).

One thing I mention in the source file of the test project is that the brushes used for the background, cell backgrounds etc can be solid brushes, hatched or pattern brushes...so if you want an interesting LV you can change the brushes around :-)
Posted on 2003-05-16 01:01:23 by MurkyT

very nice... i started to write my own lv control as well a couple of months ago.
but i stopped because i had no time for such things anymore. maybe you can
get something usefull out of it (look at how you can resize the header-tables,
i think it's way better than ms's behaviour)...

every cell has it's own data-structure so different cell designs (colors, font/blabla)
are possible too...

Posted on 2003-05-16 06:42:45 by mob