일반적으로 자기자신의 프로세스에 속한 리스트 뷰의 경우는 간단하게 AllocHGlobal을 통해서도 얻어 올수 있습니다만
전에 Spy++같은 것을 만든다고 하셨으니 다른 프로세스의 리스트뷰일 겁니다.
좀 어려우시더라도 이방법 말고는 없을 겁니다.
소스 들어 갑니다.
//선언부
const int LVM_FIRST = 0x1000;
const int LVM_GETITEMCOUNT = LVM_FIRST + 4;
const int LVM_GETITEM = LVM_FIRST + 75;
const int LVIF_TEXT = 0x0001;
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
[DllImport("user32.dll")]
static extern int SendMessage(IntPtr window, int message, int wParam, IntPtr lParam);
[StructLayoutAttribute(LayoutKind.Sequential)]
struct LV_ITEM
{
public UInt32 mask;
public Int32 iItem;
public Int32 iSubItem;
public UInt32 state;
public UInt32 stateMask;
public IntPtr pszText;
public Int32 cchTextMax;
public Int32 iImage;
public IntPtr lParam;
}
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr OpenProcess(UInt32 dwDesiredAccess, Int32 bInheritHandle, UInt32 dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint dwFreeType);
[DllImport("kernel32.dll")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int nSize, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out()] IntPtr lpBuffer, int dwSize, int lpNumberOfBytesRead);
//메서드
private string GetItemText(IntPtr handle, int index, int subIndex)
{
uint pid;
//핸들을 이용하여 프로세스 id를 얻어 온다.
GetWindowThreadProcessId(handle, out pid);
//해당 프로세스의 핸들을 얻어 옵니다.
IntPtr hProcess = OpenProcess(0x0008 | 0x0010 | 0x0020 | 0x0400, 0, pid);
//해당 프로세스 영역에 메모리를 할당 합니다.
IntPtr vPtr = VirtualAllocEx(hProcess, IntPtr.Zero, Marshal.SizeOf(typeof(LV_ITEM)), 0x1000, 0x04);
//우리가 원하는 리스트뷰의 항목 구조체를 할당 합니다.
LV_ITEM item = new LV_ITEM();
//텍스트를 얻어오겠다는 마스크 입니다.
item.mask = LVIF_TEXT;
//텍스트의 최대 크기를 지정 합니다.
item.cchTextMax = 512;
//원하는 항목의 인덱스 입니다.
item.iItem = index;
//원하는 서브 항목의 인덱스 입니다.
item.iSubItem = subIndex;
//이부분에 항목문자열이 저장 됩니다. 역시 해당 프로세스 영역에 할당 합니다.
item.pszText = VirtualAllocEx(hProcess, IntPtr.Zero, 512, 0x1000, 0x04);
//방금만든 구조체를 비관리 영역에 할당 합니다.
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LV_ITEM)));
//할당한 포인터에 복사 합니다.
Marshal.StructureToPtr(item, ptr, true);
//비관리 영역에 할당한 포인터를 프로세스 영역에 할당한 포인터에 씁니다.
WriteProcessMemory(hProcess, vPtr, ptr, Marshal.SizeOf(typeof(LV_ITEM)), 0);
//쓰고나면 포인터는 해제 합니다.
Marshal.FreeHGlobal(ptr);
//항목 포인터를 얻어 옵니다.
SendMessage(handle, LVM_GETITEM, 0, vPtr);
//얻어온 항목은 프로세스 영역에 할당되어 있기 때문에 읽거나 쓸 수 없습니다.
//다시 비관리 영역으로 읽어 들여야 합니다. 이를위해 다시 할당 합니다.
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(LV_ITEM)));
//해당 프로세스 영역에서 비관리 영역으로 읽어 들입니다.
ReadProcessMemory(hProcess, vPtr, ptr, Marshal.SizeOf(typeof(LV_ITEM)), 0);
//읽어들인 포인터를 구조체로 변환 합니다.
item = (LV_ITEM)Marshal.PtrToStructure(ptr, typeof(LV_ITEM));
//쓰고난 포인터 해제
Marshal.FreeHGlobal(ptr);
//이제 다왔습니다. 문자열을 얻어오기 위한 작업 입니다. 위의 작업과 거의 동일하니 주석 생략 합니다.
ptr = Marshal.AllocHGlobal(512);
ReadProcessMemory(hProcess, item.pszText, ptr, 512, 0);
string text = Marshal.PtrToStringUni(ptr);
Marshal.FreeHGlobal(ptr);
//메모리 해제
VirtualFreeEx(hProcess, item.pszText, 0, 0x8000);
VirtualFreeEx(hProcess, ptr, 0, 0x8000);
return text;
}
//이런식으로 호출을 하면 됩니다.
int count = SendMessage(handle, LVM_GETITEMCOUNT, 0, 0);
for(int i=0; i<count; i++)
MessageBox.Show(GetItemText(handle, i, 0));
수고하세요
===============================================================
public class URLGrabber
{
[DllImport("user32.dll",EntryPoint="SendMessage")]
private static extern int SendMessage(int _WindowHandler, int _WM_USER, int _data, int _bufPtr );
[DllImport("user32.dll",EntryPoint="FindWindow")]
private static extern int FindWindow(string _ClassName, string _WindowName);
[DllImport("user32.dll",EntryPoint="FindWindowEx")]
private static extern int FindWindowEx(int _Parent, int _ChildAfter, string _ClassName, string _WindowName);
public const int WM_GETTEXTLENGTH = 0x000E;
public const int WM_GETTEXT = 0x000D;
public string GetURL()
{
int ie = FindWindow( "IEFrame" , null);
int worker = FindWindowEx( ie,0,"WorkerW",null );
int toolbar = FindWindowEx( worker,0,"rebarwindow32",null );
int comboboxex = FindWindowEx( toolbar, 0, "comboboxex32", null );
int combo = FindWindowEx( comboboxex,0,"ComboBox",null );
int edit = FindWindowEx( combo,0,"Edit",null );
int length;
length = SendMessage( edit, WM_GETTEXTLENGTH, 0 , 0 );
Console.WriteLine("len : " + length );
unsafe
{
int* buffer = stackalloc int[ length + 1 ];
SendMessage( edit, WM_GETTEXT, length + 1 , *buffer ) ;
Console.WriteLine( "Dodo 2 : " + (char) (*buffer) );
}
return null;
}
public static void Main(string[] args)
{
URLGrabber ug = new URLGrabber();
ug.GetURL();
}
}