From: Heesob Park Date: 2010-07-27T12:26:16+09:00 Subject: Re: Help: How to pass a struct as a pointer to Win32API? Hi, 2010/7/27 Jing Li : >  Hi all, > > As titled, I want to read text content from a standard syslistview32 control > in an application.  And the syslistview32 control is not a pop-up but > embedded in the application, which means the control has same process ID as > the application.  In that case, I don't have to call VirtualAllocEx or > WriteProcessMemory. > > So far, I could successfully get syslistview32 control's handle, count how > many items listed.  But still can not read its content.  Could you please > tell me how to do it correctly? > > require 'Win32API' > findwin = Win32API.new('user32', 'FindWindow', 'PP', 'L') > getdlg = Win32API.new('user32', 'GetDlgItem', 'LL', 'L') > sendmsg = Win32API.new('user32', 'SendMessage', 'LLLP', 'L') > > #Some irrelevant details are ignored > #Here I've already got syslistview32 control's handle, let's assume it is > resultslist = 3739380 > > puts "Count of items = #{sendmsg.call(resultslist, 4100, 0, nil)}" > #LVM_GETITEMCOUNT = 0x1004 > puts header = getdlg.call(resultslist, 0).to_s(16).upcase > #No problem, this works > > #From here I tried to SendMessage with LVM_GETITEMTEXT parameter to get > syslistview32's content > #Solution I: define a struct as described in MSDN, but something wrong when > I tried to pack, this is due to my lack of knowledge on pack&unpack > LV_item = Struct.new(:mask, :iItem, :iSubItem, :state, :stateMask, :pszText, > :cchTextMax, :iImage, :lParam) > lv_item = LV_item.new() > puts sendmsg.call(resultslist, 4165, 1, lv_item.to_a.pack("p")) >    => return value is 1, success? > puts lv_item.inspect >    => # stateMask=nil, pszText=nil, cchTextMax=nil, iImage=nil, lParam=nil> > absolutely not succeed > #If I initiate lv_item = LV_item.new(0, 0, 0, 0, 0, "", 0, 0, ""), then > error occurs at packing: can't convert Fixnum into String (TypeError).  Can > I pack integer pointer except pack("p")? > > #Solution II: Directly pack an array and pass to SendMessage, return value > is still nil > lv_item = [0, 0, 0, 0, 0, "\000", 0, 0, "\000"] > lv_item = lv_item.pack("IiiIIpiip") > puts sendmsg.call(resultslist, 4165, 1, lv_item) >    => return value is 1, success? > lv_item = lv_item.unpack("IiiIIpiip") > puts lv_item.inspect >    => [0, 0, 0, 0, 0, "\000", 0, 0, "\000"], nothing is padded actually > > I really appreciate if you can answer my question, thanks in advance. > Here is a code using VirtualAllocEx and WriteProcessMemory for a general purpose. require 'Win32API' findwin = Win32API.new('user32', 'FindWindow', 'PP', 'L') getdlg = Win32API.new('user32', 'GetDlgItem', 'LL', 'L') sendmsg = Win32API.new('user32', 'SendMessage', 'LLLP', 'L') getWindowThreadProcessId = Win32API.new('user32', 'GetWindowThreadProcessId', 'LP', 'L') openProcess = Win32API.new('kernel32', 'OpenProcess', 'LIL', 'L') virtualAllocEx = Win32API.new('kernel32', 'VirtualAllocEx', 'LPLLL', 'L') virtualFreeEx = Win32API.new('kernel32', 'VirtualFreeEx', 'LLLL', 'L') writeProcessMemory = Win32API.new('kernel32', 'WriteProcessMemory', 'LLPLP', 'I') readProcessMemory = Win32API.new('kernel32', 'ReadProcessMemory', 'LLPLP', 'I') PROCESS_VM_OPERATION = 0x08 PROCESS_VM_READ = 0x10 PROCESS_VM_WRITE = 0x20 PROCESS_QUERY_INFORMATION = 0x400 MEM_COMMIT = 0x1000 MEM_RELEASE = 0x8000 PAGE_READWRITE = 0x04 LVM_GETITEMTEXT = 0x1000+45 LVM_GETITEMCOUNT = 0x1000+4 SIZE_OF_LVITEM = 60 resultslist = 0xB0044 ##<== start with some given handle count = sendmsg.call(resultslist,LVM_GETITEMCOUNT, 0, nil) lv_item = [0, 0, 0, 0, 0, nil, 512, 0, 0,0,0,0,0,0,0] lv_item = lv_item.pack("LiiLLpiiLiiLLLL") pid = 0.chr*4 getWindowThreadProcessId.call(resultslist, pid) pid = pid.unpack('L').first process = openProcess.call(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION,0,pid) _lvi=virtualAllocEx.call(process, nil, SIZE_OF_LVITEM,MEM_COMMIT, PAGE_READWRITE) _item=virtualAllocEx.call(process, nil, 512, MEM_COMMIT,PAGE_READWRITE) _subitem=virtualAllocEx.call(process, nil, 512, MEM_COMMIT,PAGE_READWRITE) for i in 0..count lv_item[8,4] = [0].pack('L') item = 0.chr * 512 lv_item[20,4] = [_item].pack('L') writeProcessMemory.call(process, _lvi, lv_item, SIZE_OF_LVITEM, nil) sendmsg.call(resultslist, LVM_GETITEMTEXT, i, _lvi) subitem = 0.chr * 512 lv_item[8,4] = [1].pack('L') lv_item[20,4] = [_subitem].pack('L') writeProcessMemory.call(process, _lvi, lv_item, SIZE_OF_LVITEM, nil) sendmsg.call(resultslist, LVM_GETITEMTEXT, i, _lvi) readProcessMemory.call(process, _item, item, 512, nil) readProcessMemory.call(process, _item, subitem, 512, nil) item = item.strip! subitem = subitem.strip! puts "#{item} - #{subitem}" end virtualFreeEx.call(process, _lvi, 0, MEM_RELEASE) virtualFreeEx.call(process, _item, 0, MEM_RELEASE) virtualFreeEx.call(process, _subitem, 0, MEM_RELEASE) Regards, Park Heesob