News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

List-view controls: two issues

Started by NoCforMe, April 21, 2012, 10:35:39 PM

Previous topic - Next topic

NoCforMe

Just learning how to use these very useful controls. (I'm using the report style, with rows and columns of text, no icons yet.)

Ran into two issues. Solved one of them but not the other.

First issue: deleting existing columns. In my app, I needed to be able to reinitialize the control and put new data into it. Getting rid of all the existing "subitems" (i.e., row contents) was super-simple:

; Delete all existing items in list-view control:
INVOKE SendMessage, ListviewHandle, LVM_DELETEALLITEMS, 0, 0


But when it came to deleting the "items" (Win32's confusing term for the columns and their header-row contents), it wasn't so easy. This didn't work:

; Delete all existing columns in list-view control:
MOV ECX, ListviewColumns
JECXZ rf30 ;In case there are no columns.
MOV colIdx, 0
dcloop: PUSH ECX
INVOKE SendMessage, ListviewHandle, LVM_DELETECOLUMN, colIdx, 0
INC colIdx
POP ECX
LOOP dcloop


You would think this would work: go through the columns, starting at the left side, and just nuke 'em. Nope.

Just on a whim, I tried starting at the last column and working backwards:

MOV ECX, ListviewColumns
JECXZ rf30 ;In case there are no columns.
LEA EAX, [ECX - 1]
MOV colIdx, EAX
dcloop: PUSH ECX
INVOKE SendMessage, ListviewHandle, LVM_DELETECOLUMN, colIdx, 0
DEC colIdx
POP ECX
LOOP dcloop

Bingo! Works fine. (MSDN documentation says nothing about this. They do, however, say that you can't delete column 0--the first header column---unless you're using Comctrl32.dll version 5 or later, which I am.)

Second issue: MSDN says about the LVM_GETITEM message:
QuoteApplications should not assume that the text will necessarily be placed in the specified buffer. The control may instead change the pszText member of the structure to point to the new text, rather than place it in the buffer.
I understand what they're saying; what I don't understand is 1) why a control would exhibit such arbitrary behavior, and 2) how you're supposed to know whether you get text returned into your buffer or a pointer to the text? (I even left a note, in the "Community Content" area on that MSDN page.)

I guess you could 1) see if any text got returned into your buffer (you'd have to clear it first). If it was, use it. If not, check the pszText pointer to see if it got changed. If it did, there's your text.

One other question: does Win32 return null text by returning a NULL pointer, or by returning a pointer to a null string (i.e, a single NULL byte)?

NoCforMe

Quote from: NoCforMe on April 21, 2012, 10:35:39 PM
Second issue: MSDN says about the LVM_GETITEM message:
QuoteApplications should not assume that the text will necessarily be placed in the specified buffer. The control may instead change the pszText member of the structure to point to the new text, rather than place it in the buffer.
I understand what they're saying; what I don't understand is 1) why a control would exhibit such arbitrary behavior, and 2) how you're supposed to know whether you get text returned into your buffer or a pointer to the text? (I even left a note, in the "Community Content" area on that MSDN page.)

I guess you could 1) see if any text got returned into your buffer (you'd have to clear it first). If it was, use it. If not, check the pszText pointer to see if it got changed. If it did, there's your text.

As Homer Simpson would say, Doh!

I just didn't parse that (MSDN) statement correctly. I just got it: the API may change the pointer (pszText) to something different from what you set it to when you sent the LVM_GETITEM message. Therefore, you'll always find the returned text correctly by using the pszText pointer, not by ASS-U-Ming that the text will be sitting in the buffer whose pointer you passed in.

Gotcha.

xandaz

   Noc. LVM_DELETECOLUMN is used to delete the column and eliminate the name from the header removed it from grid etc. Thats not how you delete items. If you're intention is to delete and item rather than a subitem, then you use  LVM_DELETEITEM. If on the other hand you want to delete a subitem. Just use lvi.iSubItem to point to the column's index and set pszText to null, or remove LVIF_TEXT for mask. I havent read so well your post. i hope i'm helping you out. Can you post some code?

xandaz

    Oh yeah.... you always should use the pointer returned is pszText when using LVM_GETITEM as you said. ty

NoCforMe

Quote from: xandaz on April 25, 2012, 10:18:49 PM
   Noc. LVM_DELETECOLUMN is used to delete the column and eliminate the name from the header removed it from grid etc. Thats not how you delete items. If you're intention is to delete and item rather than a subitem, then you use  LVM_DELETEITEM. If on the other hand you want to delete a subitem. Just use lvi.iSubItem to point to the column's index and set pszText to null, or remove LVIF_TEXT for mask. I havent read so well your post. i hope i'm helping you out. Can you post some code?

Go back and read my original post, a little more carefully this time. (And I did post code.)

I first used LVM_DELETEALLITEMS to delete all items in the control, basically everything but the columns themselves with their headings. (This is a heck of a lot easier than using LVM_DELETEITEM to delete each and every item separately.)

I then used LVM_DELETECOLUMN to delete each column. What I discovered, though, was that this only seemed to work when I went in reverse order, starting at the last (righmost) column.

Probably should have added that this is under Windows 2000 Professional, and using Comctl32.dll version 5.81.3502. Perhaps this works differently under different OS or DLL versions?