vc++

vc++ 다른프로세스 listview item 가져오기

우유빛 2009. 6. 22. 16:37

일반적으로 자기자신의 프로세스에 속한 리스트 뷰의 경우는 간단하게 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();
}
}