C#如何獲取其他程序窗口列表ListView控件中的內(nèi)容
當(dāng)前位置:點晴教程→知識管理交流
→『 技術(shù)文檔交流 』
需求:獲取其他程序中的ListView控件的文本內(nèi)容 原理:進程之間是相互隔離的,數(shù)據(jù)是不能共享的(有些特例) LVM_GETTITEMTEXT:將一個數(shù)據(jù)緩沖區(qū)提供給listview32控件,你不能把你的進程的數(shù)據(jù)緩沖提供給另外的程序,所以要用openprocess 打開“任務(wù)管理器”進程,然后在“任務(wù)管理器進程”中申請足夠長度的內(nèi)存(VirualAllocEx),將這個內(nèi)存地址提供給listview32,使用 sendmessage 發(fā)送LVM_GETTITEMTEXT消息,待sendmessage返回后,用readprocessmemory 讀取這段內(nèi)存的數(shù)據(jù),即listview控件的文本內(nèi)容。 API函數(shù):
程序演示代碼: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Runtime.InteropServices; namespace 讀取其他軟件listview控件的內(nèi)容 { public partial class Form1 : Form { int hwnd; //窗口句柄 int process;//進程句柄 int pointer; private const uint LVM_FIRST = 0x1000; private const uint LVM_GETHEADER = LVM_FIRST + 31; private const uint LVM_GETITEMCOUNT = LVM_FIRST + 4;//獲取列表行數(shù) private const uint LVM_GETITEMTEXT = LVM_FIRST + 45;//獲取列表內(nèi)的內(nèi)容 private const uint LVM_GETITEMW = LVM_FIRST + 75;
private const uint HDM_GETITEMCOUNT = 0x1200;//獲取列表列數(shù)
private const uint PROCESS_VM_OPERATION = 0x0008;//允許函數(shù)VirtualProtectEx使用此句柄修改進程的虛擬內(nèi)存 private const uint PROCESS_VM_READ = 0x0010;//允許函數(shù)訪問權(quán)限 private const uint PROCESS_VM_WRITE = 0x0020;//允許函數(shù)寫入權(quán)限
private const uint MEM_COMMIT = 0x1000;//為特定的頁面區(qū)域分配內(nèi)存中或磁盤的頁面文件中的物理存儲 private const uint MEM_RELEASE = 0x8000; private const uint MEM_RESERVE = 0x2000;//保留進程的虛擬地址空間,而不分配任何物理存儲
private const uint PAGE_READWRITE = 4;
private int LVIF_TEXT = 0x0001;
[DllImport("user32.dll")]//查找窗口 private static extern int FindWindow( string strClassName, //窗口類名 string strWindowName //窗口標(biāo)題 );
[DllImport("user32.dll")]//在窗口列表中尋找與指定條件相符的第一個子窗口 private static extern int FindWindowEx( int hwndParent, // handle to parent window int hwndChildAfter, // handle to child window string className, //窗口類名 string windowName // 窗口標(biāo)題 ); [DllImport("user32.DLL")] private static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam); [DllImport("user32.dll")]//找出某個窗口的創(chuàng)建者(線程或進程),返回創(chuàng)建者的標(biāo)志符 private static extern int GetWindowThreadProcessId(int hwnd,out int processId); [DllImport("kernel32.dll")]//打開一個已存在的進程對象,并返回進程的句柄 private static extern int OpenProcess(uint dwDesiredAccess, bool bInheritHandle,int processId); [DllImport("kernel32.dll")]//為指定的進程分配內(nèi)存地址:成功則返回分配內(nèi)存的首地址 private static extern int VirtualAllocEx(int hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll")]//從指定內(nèi)存中讀取字節(jié)集數(shù)據(jù) private static extern bool ReadProcessMemory( int hProcess, //被讀取者的進程句柄 int lpBaseAddress,//開始讀取的內(nèi)存地址 IntPtr lpBuffer, //數(shù)據(jù)存儲變量 int nSize, //要寫入多少字節(jié) ref uint vNumberOfBytesRead//讀取長度 ); [DllImport("kernel32.dll")]//將數(shù)據(jù)寫入內(nèi)存中 private static extern bool WriteProcessMemory( int hProcess,//由OpenProcess返回的進程句柄 int lpBaseAddress, //要寫的內(nèi)存首地址,再寫入之前,此函數(shù)將先檢查目標(biāo)地址是否可用,并能容納待寫入的數(shù)據(jù) IntPtr lpBuffer, //指向要寫的數(shù)據(jù)的指針 int nSize, //要寫入的字節(jié)數(shù) ref uint vNumberOfBytesRead ); [DllImport("kernel32.dll")] private static extern bool CloseHandle(int handle); [DllImport("kernel32.dll")]//在其它進程中釋放申請的虛擬內(nèi)存空間 private static extern bool VirtualFreeEx( int hProcess,//目標(biāo)進程的句柄,該句柄必須擁有PROCESS_VM_OPERATION的權(quán)限 int lpAddress,//指向要釋放的虛擬內(nèi)存空間首地址的指針 uint dwSize, uint dwFreeType//釋放類型 ); /// <summary> /// LVITEM結(jié)構(gòu)體,是列表視圖控件的一個重要的數(shù)據(jù)結(jié)構(gòu) /// 占空間:4(int)x7=28個byte /// </summary> private struct LVITEM //結(jié)構(gòu)體 { public int mask;//說明此結(jié)構(gòu)中哪些成員是有效的 public int iItem;//項目的索引值(可以視為行號)從0開始 public int iSubItem; //子項的索引值(可以視為列號)從0開始 public int state;//子項的狀態(tài) public int stateMask; //狀態(tài)有效的屏蔽位 public IntPtr pszText; //主項或子項的名稱 public int cchTextMax;//pszText所指向的緩沖區(qū)大小 }
public Form1() { InitializeComponent(); }
/// <summary> /// LV列表總行數(shù) /// </summary> private int ListView_GetItemRows(int handle) { return SendMessage(handle,LVM_GETITEMCOUNT,0,0); } /// <summary> /// LV列表總列數(shù) /// </summary> private int ListView_GetItemCols(int handle) { return SendMessage(handle, HDM_GETITEMCOUNT, 0, 0); }
private void button1_Click(object sender, EventArgs e) { int headerhwnd; //listview控件的列頭句柄 int rows,cols; //listview控件中的行列數(shù) int processId; //進程pid
hwnd = FindWindow("#32770", "Windows 任務(wù)管理器"); hwnd = FindWindowEx(hwnd, 0, "#32770",null); hwnd = FindWindowEx(hwnd, 0, "SysListView32",null);//進程界面窗口的句柄,通過SPY獲取 headerhwnd = SendMessage(hwnd, LVM_GETHEADER, 0, 0);//listview的列頭句柄
rows=ListView_GetItemRows(hwnd);//總行數(shù),即進程的數(shù)量 cols = ListView_GetItemCols(headerhwnd);//列表列數(shù) GetWindowThreadProcessId(hwnd, out processId);
//打開并插入進程 process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false,processId); //申請代碼的內(nèi)存區(qū),返回申請到的虛擬內(nèi)存首地址 pointer = VirtualAllocEx(process, IntPtr.Zero, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); string[,] tempStr;//二維數(shù)組 string[] temp = new string[cols];
tempStr=GetListViewItmeValue(rows,cols);//將要讀取的其他程序中的ListView控件中的文本內(nèi)容保存到二維數(shù)組中
listView1.Items.Clear();//清空LV控件信息 //輸出數(shù)組中保存的其他程序的LV控件信息 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols;j++ ) { temp[j]=tempStr[i,j]; } ListViewItem lvi = new ListViewItem(temp); listView1.Items.Add(lvi); } }
/// <summary> /// 從內(nèi)存中讀取指定的LV控件的文本內(nèi)容 /// </summary> /// <param name="rows">要讀取的LV控件的行數(shù)</param> /// <param name="cols">要讀取的LV控件的列數(shù)</param> /// <returns>取得的LV控件信息</returns> private string[,] GetListViewItmeValue(int rows,int cols) { string[,] tempStr = new string[rows,cols];//二維數(shù)組:保存LV控件的文本信息 for (int i = 0; i < rows;i++ ) { for (int j = 0; j < cols;j++ ) { byte[] vBuffer = new byte[256];//定義一個臨時緩沖區(qū) LVITEM[] vItem = new LVITEM[1]; vItem[0].mask = LVIF_TEXT;//說明pszText是有效的 vItem[0].iItem = i; //行號 vItem[0].iSubItem = j; //列號 vItem[0].cchTextMax = vBuffer.Length;//所能存儲的最大的文本為256字節(jié) vItem[0].pszText = (IntPtr)((int)pointer + Marshal.SizeOf(typeof(LVITEM))); uint vNumberOfBytesRead = 0;
//把數(shù)據(jù)寫到vItem中 //pointer為申請到的內(nèi)存的首地址 //UnsafeAddrOfPinnedArrayElement:獲取指定數(shù)組中指定索引處的元素的地址 WriteProcessMemory(process,pointer,Marshal.UnsafeAddrOfPinnedArrayElement(vItem,0),Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead);
//發(fā)送LVM_GETITEMW消息給hwnd,將返回的結(jié)果寫入pointer指向的內(nèi)存空間 SendMessage(hwnd, LVM_GETITEMW,i,pointer);
//從pointer指向的內(nèi)存地址開始讀取數(shù)據(jù),寫入緩沖區(qū)vBuffer中 ReadProcessMemory(process,((int)pointer + Marshal.SizeOf(typeof(LVITEM))),Marshal.UnsafeAddrOfPinnedArrayElement(vBuffer,0),vBuffer.Length, ref vNumberOfBytesRead);
string vText = Encoding.Unicode.GetString(vBuffer, 0, (int)vNumberOfBytesRead); ; tempStr[i,j] = vText; } } VirtualFreeEx(process, pointer, 0, MEM_RELEASE);//在其它進程中釋放申請的虛擬內(nèi)存空間,MEM_RELEASE方式很徹底,完全回收 CloseHandle(process);//關(guān)閉打開的進程對象 return tempStr; } } } 此代碼可以將任務(wù)管理器中的進程都抓取出來。 該文章在 2023/12/29 23:05:01 編輯過 |
關(guān)鍵字查詢
相關(guān)文章
正在查詢... |