News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests

Main Menu

LVM_GETITEMTEXT working in XP but not windows 7

Started by jimg, February 11, 2013, 04:09:57 PM

Previous topic - Next topic

jimg

Thank you Japheth, I appreciate the code.
After hours of digging through that deranged can of worms that is shell on the microsoft site, I've come to the conclusion that it is not actually what I need.  When I compare the list your code gives me to the actual desktop, it gives me four items that are not on the desktop, and misses one that is.  (It gives me two "control panel"s, a "J" (which is my user name), and a "Libraries".  It misses desktop.ini)
Ultimately, with no way to actually tie the names to the desktop listview, it doesn't help much, but still I appreciate it.

My ultimate goal is to fix my desktop icon positioner program  http://www.masmforum.com/board/index.php?topic=2704.msg21324#msg21324  to work with windows 7.  It works, I can move icons around, but without the name or icon it really is not very useful.


jj2007

Quote from: jimg on February 13, 2013, 08:59:58 AMMy ultimate goal is to fix my desktop icon positioner program  http://www.masmforum.com/board/index.php?topic=2704.msg21324#msg21324  to work with windows 7.  It works, I can move icons around, but without the name or icon it really is not very useful.

Jim,
Any chance hooking WM_NOTIFY and getting the text via the NMLVDISPINFO structure? Or is that a dead end street?

jimg

That's what I'm working on right now.  I don't know that I need to hook WM_NOTIFY, but I need to be able to send a notify to the listviews parent with a NMLVDISPINFO message.  I already have space alloted in the listviews memory, so I should be able to read the return if the parent responds properly.  Have a few more things to check out before I try it.

japheth

Quote from: jimg on February 13, 2013, 08:59:58 AM
When I compare the list your code gives me to the actual desktop, it gives me four items that are not on the desktop, and misses one that is.

Well, it's a sample, to demonstrate the basics, not a "solution". One might have to adjust the code to get exactly what you want.

jimg

Yes, thank you.  Didn't mean to seem ungrateful.  Sorry.  Reading about shell made me a little verrückt.

japheth

Just in case: on this site is a nice example about shell objects: http://wiki.winehq.org/Shell32

if you study the items and their differences you should be able to see what flags have to be set to get the items you are interested in.


jimg

Status update:

I found out the while LVM_GETITEMTEXT is not supposed to work and indeed doesn't work on a virtual listview,  LVM_GETITEM is supposed to work, but doesn't.  In fact, it looks like all the straight functions work, but those that require LVITEM or another structure be passed don't work.  I'm now thinking it has to be a 64 bit application to talk to the 64 bit desktop.  I don't have any idea how to write 64 bit apps, so it will probably be awhile before I'm back with more info.  Perhaps the LVITEM looks different for 64 bit apps?  Qwords instead of Dwords?

jj2007

Quote from: jimg on February 14, 2013, 01:41:52 PMPerhaps the LVITEM looks different for 64 bit apps?  Qwords instead of Dwords?

Possible. By the way: Does GetLastError show anything interesting?

jimg


sinsi

I converted my code to 64-bit and Lo and Behold! it gets labels, and that's using LVM_GETITEMTEXT.

japheth

Quote from: sinsi on February 14, 2013, 06:33:14 PM
I converted my code to 64-bit and Lo and Behold! it gets labels, and that's using LVM_GETITEMTEXT.

Yes, it works in 64-bit.


    option win64:3
    option frame:auto

    option casemap:none
    include windows.inc
    include commctrl.inc
    include stdio.inc

    includelib <kernel32.lib>
    includelib <user32.lib>
    includelib <comctl32.lib>
    includelib <msvcrt.lib>

CStr macro x:vararg
local xxx
    .const
xxx db x,0
    .code
    exitm <offset xxx>
endm

inv  equ INVOKE
soff equ SADD
nl   equ 13,10

.data?
    hProgMan   dq ?
    hParent    dq ? ; to get desktop listview handle
    hListView  dq ? ; desktop listview
.data
    progman      db "Progman",0
    defview      db "SHELLDLL_defVIEW", 0
    syslistview  db "SysListView32", 0

.code

Program proc frame

    inv InitCommonControls

    invoke printf, CStr("Desktop Icon Info Test",10,10)

    mov rbx, offset progman
    inv FindWindow,rbx,0 ; search for desktop listview
    or  rax,rax
    jz ErrorExit
    mov hProgMan,rax
    invoke printf, CStr("hProgman=%p",10), hProgMan
    mov rbx,offset defview
    inv FindWindowEx, hProgMan, 0, rbx, 0
    or  rax,rax
    jz ErrorExit
    mov hParent,rax
    invoke printf, CStr("  hParent=%p"), hParent
    mov rbx,offset syslistview
    inv FindWindowEx,hParent, 0, rbx, 0
    or  rax,rax
    jz ErrorExit
    mov hListView,rax
    invoke printf, CStr("  hListView=%p",10), hListView
    Call GetDesktopIconInfo ; go fill listview
    jmp @f

ErrorExit:
    inv MessageBox, 0, rbx, CStr("Unable to get"),0
@@:
;    inkey "Press any key to exit..."
    invoke ExitProcess, 0
;    exit 

Program endp

GetErrDescriptionconsole proc frame uses rbx rdi Routine:ptr BYTE
LOCAL hLocal:QWORD
.data
ErrMsgTmpl  db 10,'%s failed, Error Code %Xh',10,'%s',0
Unknown     db 'UnKnown Error',0
.code
    invoke GetLastError
    mov edi,eax
    invoke FormatMessage,FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
                         0,             ; GetItFromSystem
                         edi,0,         ; ErrNum,Default language
                         addr hLocal,   ; where to send the address of string from system
                         0,0            ; any size, no arguments
    mov rbx,offset Unknown
    .if eax!=0
        invoke LocalLock,hLocal
        mov rbx,rax
    .endif
    invoke printf, offset ErrMsgTmpl, Routine, edi, rbx
;    invoke MessageBox,0,addr Bufferx,0,0
    mov rax, offset Unknown
    .if rbx!=rax
        inv LocalFree,hLocal
    .endif
    ret
GetErrDescriptionconsole endp

GetDesktopIconInfo proc frame; get the names and positions of the desktop icons from the desktop listview
Local I:DWord,J:DWord

.data?
pid          dd ?
IconCount    dd ?
NumBytes     dq ?
hProcess1    dq ?
SharedMem1   dq ?   ; space for LV_ITEM and position data
SharedMem2   dq ?   ; space for caption or title
SharedMem3   dq ?   ; space for the position
PLen         dd ?
vmemsize     dq ?

LV_ITEMx STRUCT 8
  imask         DWORD      ?
  iItem         DWORD      ?
  iSubItem      DWORD      ?
  state         DWORD      ?
  stateMask     DWORD      ?
  pszText       QWORD      ?
  cchTextMax    DWORD      ?
  iImage        DWORD      ?
  lParam        QWORD      ?
  iIndent       DWORD      ?
  iGroupId      DWORD      ?
  puColumns     DWORD      ?
  piColFmt      DWORD      ?
  iGroup        DWORD      ?
LV_ITEMx ENDS

objItem LV_ITEMx <?>
objOut  LV_ITEMx <?>
MaxName     equ 225 ; maximum text description length for an icon  (actually, its about 212)

IconTitle        db  MaxName dup (?)

TPos    POINT   <>

.code
    inv SendMessage,hListView, LVM_GETITEMCOUNT, 0, 0   ; ask the desktop the number of icons present
    mov IconCount,eax
    or  eax,eax
    jz  Done    ; no icons???
    sub eax,1
    invoke printf, CStr("%u icons found",10), eax

    mov vmemsize,sizeof LV_ITEMx + sizeof POINT + MaxName
    mov PLen,sizeof TPos
    inv GetWindowThreadProcessId,hListView, Addr pid
    inv OpenProcess,PROCESS_VM_OPERATION Or PROCESS_VM_READ Or PROCESS_VM_WRITE, 0, pid  ; common usage
    mov hProcess1,rax
    inv VirtualAllocEx, rax, 0, vmemsize, MEM_RESERVE Or MEM_COMMIT, PAGE_READWRITE  ; get memory within desktop process
    mov SharedMem1,rax          ; save location within Desktop Listview process to write LV_ITEM
    add rax,sizeof POINT
    mov SharedMem3,rax
    add rax,sizeof LV_ITEMx     
    mov SharedMem2,rax          ; save location of text output

    mov I,0
    Loop1:      ; get length of all titles to reserve storage space
        invoke printf, CStr("#%u "), I
        mov eax, I
        inv SendMessage, hListView, LVM_GETITEMPOSITION, rax, SharedMem1   ; ask for position of Item I (send msg to explorer listview (desktop))
        mov ebx, PLen
        inv ReadProcessMemory,hProcess1, SharedMem1, addr TPos, rbx, addr NumBytes  ; read it into TPos
        .if ( !eax )
            invoke GetErrDescriptionconsole, CStr("ReadProcessMemory")
            jmp Done3
        .endif
        invoke printf, CStr("x=%u y=%u "), TPos.x, TPos.y
        mov objItem.imask, LVIF_TEXT
        mov eax, I
        mov objItem.iItem, eax
        mov objItem.iSubItem, 0
        mov rax, SharedMem2
        mov objItem.pszText, rax
        mov objItem.cchTextMax,MaxName
        inv WriteProcessMemory, hProcess1, SharedMem1, ADDR objItem, sizeof LV_ITEMx, ADDR NumBytes ;copy LV_ITEM structure to memory
        .if ( !eax )
            invoke GetErrDescriptionconsole, CStr("WriteProcessMemory")
            jmp Done3
        .endif
;************************  this is the malfunctioning call
        inv SendMessage, hListView, LVM_GETITEM, 0, SharedMem1 ; send msg to explorer listview (desktop), ask for title, returns length in eax

        inv ReadProcessMemory, hProcess1, SharedMem1, addr objItem, sizeof LV_ITEMx, addr NumBytes
        inv ReadProcessMemory, hProcess1, objItem.pszText, addr IconTitle, 40, addr NumBytes
        mov byte ptr [IconTitle+40],0  ; **** truncate long names for test
        invoke printf, CStr("Title %s",10), addr IconTitle

        inc I
        mov eax,IconCount
        cmp I,eax
        jb Loop1
    ;Loop1 ends

Done3:
    inv VirtualFreeEx, hProcess1, SharedMem1, vmemsize, MEM_RELEASE
Done2:
    inv CloseHandle,hProcess1

Done:
    ret
GetDesktopIconInfo Endp

End Program


Since it works in Win 7 64-bit, the 32-bit version should work in Win 7 32-bit as well, shouldn't it?

jj2007

Quote from: jimg on February 14, 2013, 05:54:27 PM
No errors, it thinks it worked.

I like that one :biggrin:

Have you tried LVM_GETITEMTEXTW? I know one case (with ToolTips) where only the Unicode version worked:

  .if uMsg==WM_NOTIFY
      mov ecx, lParam
      .if [ecx.NMHDR.code]==TTN_GETDISPINFO
         MsgBox 0, "Never seen!", "Hi", MB_OK
      .endif
      .if [ecx.NMHDR.code]==TTN_GETDISPINFOW
         mov eax, [ecx.NMTTDISPINFOW.lpszText]
         invoke MessageBoxW, 0, eax, 0, MB_OK
      .endif


jimg

Thank guys, at least I have a direction to go now :)  Is there an Idiots guide to 64 bit assembly programming anywhere?  This is going to be painful to convert.  I've become too dependent upon the masm32 macros. (Is there an msvcrt equivalent to inkey for pausing?)

Japheth-

I finally got JWasm 64 bit installed.  I used these options and it seemed to work, but if you have better suggestions for options to use, I'd appreciate it.

@set INCLUDE=F:\JWasm\WinInc\Include
@set path=%path%;F:\jwasm\bin
@set lib=F:\JWasm\WinInc\Lib64

Jwasm -win64 -Cp -Fo=tst.obj %1
jwlink  format win pe file tst.obj Libpath \WinInc\Lib64


also, I had to download polib to make the libraries using your batch file.  Are you working on a jwlib?

japheth

Quote from: jimg on February 15, 2013, 04:06:38 AM
I finally got JWasm 64 bit installed.  I used these options and it seemed to work, but if you have better suggestions for options to use, I'd appreciate it.

I used the standard 32-bit JWasm and the normal MS link to create the 64-bit sample - because I wanted to be able to use the 64-bit WinDbg.

Quote
also, I had to download polib to make the libraries using your batch file.  Are you working on a jwlib?

There is a jwlib, but it doesn't understand .def files as of yet.

jimg

Just to avoid confusion, I used the standard JWasm, I didn't mean to imply that a 64 bit version of JWasm even existed, I just put -win64 in the options.  But I did use the 64 bit libraries.

I just tried again using the 32bit libraries, and it assembled, but I got a lot of errors trying to link with jwlink.  eg.

Error! E2028: __imp_LocalFree is an undefined reference
Error! E2028: __imp_VirtualAllocEx is an undefined reference
Error! E2028: InitCommonControls is an undefined reference
Error! E2028: printf is an undefined reference
creating a 64-bit PE executable
file tst.obj(F:\JWasm\Progs\dip64\ec.asm): undefined symbol InitCommonControls
file tst.obj(F:\JWasm\Progs\dip64\ec.asm): undefined symbol printf
file tst.obj(F:\JWasm\Progs\dip64\ec.asm): undefined

etc.

So I obviously have a lot of learning to do yet.

What version of MS link did you use?  What were the options?