Listview control & LVM_GETNEXTITEM

'LVM_FIRST = &H1000
'LVM_GETNEXTITEM = (LVM_FIRST + 12)
'LVM_GETSELECTEDCOUNT = (LVM_FIRST + 50)
'LVNI_SELECTED = &H2
'listhwnd = handle to the listview control

sub test()

nTotal = sendmessage(listhwnd, LVM_GETSELECTEDCOUNT, 0, 0) - this returns the correct number of selected items.

for n=0 to nTotal -1
i=-1

i=sendmessage(listhwnd, LVM_GETNEXTITEM, i, LVNI_SELECTED)

'i always return -1, why?

next n

end sub

I'm trying to find all the selected items in a listview control. The listview control is in a different process.

I do not understand why i is always -1, LVM_GETNEXTITEM should return the next selected item in the list.
SiWixAsked:
Who is Participating?
 
ArkConnect With a Mentor Commented:
Hi
First of all, you have to pass lParam ByVal:

i=sendmessage(listhwnd, LVM_GETNEXTITEM, i, ByVal LVNI_SELECTED)

Second, why do you reset i to -1 every loop? Correct code

sub test()

nTotal = sendmessage(listhwnd, LVM_GETSELECTEDCOUNT, 0, 0)' - this returns the correct number of selected items.

i=-1

for n=0 to nTotal -1

i=sendmessage(listhwnd, LVM_GETNEXTITEM, i, ByVal LVNI_SELECTED)

'Works OK
next n

end sub


And last, if your listview is in a different process, you'll have a problemm when try to pass structures (LV_ITEM, for examle, to retrive selected item text) via sendmessage. See my sample at http://www.freevbcode.com/ShowCode.Asp?ID=3290 how to pass structures via SendMessage to another processes.

Cheers
0
 
Ryan ChongCommented:
What don't use ListView built-in methods to check whether an item is selected or not?

Anyway, try find some codes useful at:
http://www.mvps.org/vbnet/code/toc/tocbytopic_l.htm#ListView

regards
0
 
SiWixAuthor Commented:
ryancys:  The listview control reside in a different process (application). I do not have a "listview1".

I refer to the listview through it's window handle (HWND), by using windows api - Sendmessage.

regards,
Stian
0
 
SiWixAuthor Commented:
That's it!!!!

It works, just as you said.

The i=-1 was misplaced in the question.

I couldn't understand why the hell it worked using C, but not VB.

I definitely need a good Win32api book. I'll have a look at your recommendation.

What problems are you referring to, with regards to LV_ITEM. I can easily get the text from the listview, but yes I do have a problem. I have to make sure that the list is scrolled to the end, otherwise the LV_ITEM returns empty for non visible items. (ie only list items that have been visible is returned)


Thanks!
0
 
ArkCommented:
Thanks for points. Glad I could help you.
About difference in C and VB - C works with pointers easy, while VB doesn't. Take a look on SendMessage declaration:
'Normal' declaration,like in Api Viewer.

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long

Look, last parameter (lParam) is passing ByRef and without Type checking (as Any). Actually, in C it'd DWORD (long) - pointer to additional message info. When you use structure as lParam, everything is OK - you pass pointer to this structure ByRef. But when you pass long variable (LVNI_SELECTED in your case), SendMessage thing that this is a pointer (memory address = 2) and try to get anything there. So, you need force passing this value ByVal (like in my sample) or use 'TypeSafe" VB declaration:


Private Declare Function SendMessageLong Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Now about possible problems with passing structures to another processes. Each process have its own memory map. It means that memory used by process is "Virtual" memory, ie. memory address in one process may be same as in another process, but these processes store different variables at these addresses. Now look at SendMessage declaration again. When you send message to another process with structure pointer:
Dim li As LV_ITEM
SendMessage hLV, LVM_GETITEM, nItem, li
actually, you send to another process a pointer to LV_ITEM structure which another process should fill with data. But this pointer belong to your process and another process know nothing about it!. Same address in another process may be already in use and you'll get GPF. So, you need smth like "Interprocess memory communication". Under w9x/Me you can use upper memory (above 2GB limit). This virtual memory area is shareable for all application. You can allocate memory in this area via FileMapping API and pass to another process this memory address. Another process have access to this area, so it can fill it with data. Then you process can copy this memory to structure via rtlMoveMemory API. As for NT/2000/XP - there isn't shareable memory. But these OS have VirtualAllocateEx API which allow your process to allocate memory in different process. So, you allocate memory in different process, that process fill this memory with data and you can read this data from your process with ReadProcessMemory API.

Regards
Ark
0
All Courses

From novice to tech pro — start learning today.