需求:獲取其他程式中的ListView控制元件的文字內容
原理:程式之間是相互隔離的,資料是不能共享的(有些特例)
LVM_GETTITEMTEXT:將一個資料緩衝區提供給listview32控制元件,你不能把你的程式的資料緩衝提供給另外的程式,所以要用openprocess 開啟“工作管理員”程式, 然後 在“工作管理員程式”中申請足夠長度的記憶體(VirualAllocEx),將這個記憶體地址提供給listview32,使用 sendmessage 傳送LVM_GETTITEMTEXT訊息,待sendmessage返 回後,用readprocessmemory 讀取這段記憶體的資料,即listview控制元件的文字內容
API函式:
- FindWindow //查詢視窗
- FindWindowEx ////在視窗列表中尋找與指定條件相符的第一個子視窗
- SendMessage
- GetWindowThreadProcessId//找出某個視窗的建立者(執行緒或程式),返回建立者的標誌符
- OpenProcess //開啟一個已存在的程式物件,並返回程式的控制程式碼
- VirtualAllocEx //為指定的程式分配記憶體地址:成功則返回分配記憶體的首地址
- ReadProcessMemory //從指定記憶體中讀取位元組集資料
- WriteProcessMemory //將資料寫入記憶體中
- CloseHandle
- VirtualFreeEx //在其它程式中釋放申請的虛擬記憶體空間
程式演示:
程式碼:
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控制元件的內容
{
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;//獲取列表行數
private const uint LVM_GETITEMTEXT = LVM_FIRST + 45;//獲取列表內的內容
private const uint LVM_GETITEMW = LVM_FIRST + 75;
private const uint HDM_GETITEMCOUNT = 0x1200;//獲取列表列數
private const uint PROCESS_VM_OPERATION = 0x0008;//允許函式VirtualProtectEx使用此控制程式碼修改程式的虛擬記憶體
private const uint PROCESS_VM_READ = 0x0010;//允許函式訪問許可權
private const uint PROCESS_VM_WRITE = 0x0020;//允許函式寫入許可權
private const uint MEM_COMMIT = 0x1000;//為特定的頁面區域分配記憶體中或磁碟的頁面檔案中的物理儲存
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 //視窗標題
);
[DllImport("user32.dll")]//在視窗列表中尋找與指定條件相符的第一個子視窗
private static extern int FindWindowEx(
int hwndParent, // handle to parent window
int hwndChildAfter, // handle to child window
string className, //視窗類名
string windowName // 視窗標題
);
[DllImport("user32.DLL")]
private static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll")]//找出某個視窗的建立者(執行緒或程式),返回建立者的標誌符
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")]//為指定的程式分配記憶體地址:成功則返回分配記憶體的首地址
private static extern int VirtualAllocEx(int hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll")]//從指定記憶體中讀取位元組集資料
private static extern bool ReadProcessMemory(
int hProcess, //被讀取者的程式控制程式碼
int lpBaseAddress,//開始讀取的記憶體地址
IntPtr lpBuffer, //資料儲存變數
int nSize, //要寫入多少位元組
ref uint vNumberOfBytesRead//讀取長度
);
[DllImport("kernel32.dll")]//將資料寫入記憶體中
private static extern bool WriteProcessMemory(
int hProcess,//由OpenProcess返回的程式控制程式碼
int lpBaseAddress, //要寫的記憶體首地址,再寫入之前,此函式將先檢查目標地址是否可用,並能容納待寫入的資料
IntPtr lpBuffer, //指向要寫的資料的指標
int nSize, //要寫入的位元組數
ref uint vNumberOfBytesRead
);
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(int handle);
[DllImport("kernel32.dll")]//在其它程式中釋放申請的虛擬記憶體空間
private static extern bool VirtualFreeEx(
int hProcess,//目標程式的控制程式碼,該控制程式碼必須擁有PROCESS_VM_OPERATION的許可權
int lpAddress,//指向要釋放的虛擬記憶體空間首地址的指標
uint dwSize,
uint dwFreeType//釋放型別
);
/// <summary>
/// LVITEM結構體,是列表檢視控制元件的一個重要的資料結構
/// 佔空間:4(int)x7=28個byte
/// </summary>
private struct LVITEM //結構體
{
public int mask;//說明此結構中哪些成員是有效的
public int iItem;//專案的索引值(可以視為行號)從0開始
public int iSubItem; //子項的索引值(可以視為列號)從0開始
public int state;//子項的狀態
public int stateMask; //狀態有效的遮蔽位
public IntPtr pszText; //主項或子項的名稱
public int cchTextMax;//pszText所指向的緩衝區大小
}
public Form1()
{
InitializeComponent();
}
/// <summary>
/// LV列表總行數
/// </summary>
private int ListView_GetItemRows(int handle)
{
return SendMessage(handle,LVM_GETITEMCOUNT,0,0);
}
/// <summary>
/// LV列表總列數
/// </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控制元件中的行列數
int processId; //程式pid
hwnd = FindWindow("#32770", "Windows 工作管理員");
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);//總行數,即程式的數量
cols = ListView_GetItemCols(headerhwnd);//列表列數
GetWindowThreadProcessId(hwnd, out processId);
//開啟並插入程式
process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE, false,processId);
//申請程式碼的記憶體區,返回申請到的虛擬記憶體首地址
pointer = VirtualAllocEx(process, IntPtr.Zero, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
string[,] tempStr;//二維陣列
string[] temp = new string[cols];
tempStr=GetListViewItmeValue(rows,cols);//將要讀取的其他程式中的ListView控制元件中的文字內容儲存到二維陣列中
listView1.Items.Clear();//清空LV控制元件資訊
//輸出陣列中儲存的其他程式的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>
/// 從記憶體中讀取指定的LV控制元件的文字內容
/// </summary>
/// <param name="rows">要讀取的LV控制元件的行數</param>
/// <param name="cols">要讀取的LV控制元件的列數</param>
/// <returns>取得的LV控制元件資訊</returns>
private string[,] GetListViewItmeValue(int rows,int cols)
{
string[,] tempStr = new string[rows,cols];//二維陣列:儲存LV控制元件的文字資訊
for (int i = 0; i < rows;i++ )
{
for (int j = 0; j < cols;j++ )
{
byte[] vBuffer = new byte[256];//定義一個臨時緩衝區
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位元組
vItem[0].pszText = (IntPtr)((int)pointer + Marshal.SizeOf(typeof(LVITEM)));
uint vNumberOfBytesRead = 0;
//把資料寫到vItem中
//pointer為申請到的記憶體的首地址
//UnsafeAddrOfPinnedArrayElement:獲取指定陣列中指定索引處的元素的地址
WriteProcessMemory(process,pointer,Marshal.UnsafeAddrOfPinnedArrayElement(vItem,0),Marshal.SizeOf(typeof(LVITEM)), ref vNumberOfBytesRead);
//傳送LVM_GETITEMW訊息給hwnd,將返回的結果寫入pointer指向的記憶體空間
SendMessage(hwnd, LVM_GETITEMW,i,pointer);
//從pointer指向的記憶體地址開始讀取資料,寫入緩衝區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);//在其它程式中釋放申請的虛擬記憶體空間,MEM_RELEASE方式很徹底,完全回收
CloseHandle(process);//關閉開啟的程式物件
return tempStr;
}
}
}
相關文章
- 設定獲取div元素中的文字內容程式碼例項
- 獲取html標籤包裹的文字內容HTML
- js獲取select選中項的值和文字內容JS
- Android中ListView控制元件onItemClick事件中獲取listView傳遞的資料AndroidView控制元件事件
- 獲取或者設定textarea文字域的內容
- C#如何獲取ListView控制元件選中項的值C#View控制元件
- 獲取網頁中的密碼和文字輸入框的內容 (轉)網頁密碼
- javascript 獲取iframe中內容JavaScript
- PHP獲取目錄中的全部內容RecursiveDirectoryIteratorPHP
- js如何獲取文字框內被選中的字串JS字串
- jquery cheerio 獲取元素文字內容,不包括後代jQuery
- 日常筆記一:擷取富文字編輯器中的文字內容筆記
- js獲取點選單元格中的內容程式碼例項JS
- listview 後天獲取選中項的值View
- Espresso 如何獲取控制元件的實時文字?Espresso控制元件
- 【Javascript】獲取選中的文字JavaScript
- jquery實現的獲取select下拉選單value和文字內容jQuery
- PHP獲取HTTP body內容的方法PHPHTTP
- jquery獲取具有指定內容的元素jQuery
- js如何獲取網頁尾本程式碼的內容JS網頁
- ListView新增事件並獲取選中項的值View事件
- Listview獲取選中行的值View
- 使用SendMessage函式滾動文字框控制元件中的內容 (轉)函式控制元件
- android listview獲取選中項AndroidView
- Android在ListView的onTouch事件中獲取選中項的值AndroidView事件
- android如何獲取listview中的任意行資料AndroidView
- Android ListView中獲取選中行資料的方法AndroidView
- JavaScript讀取文字檔案內容程式碼例項JavaScript
- jQuery獲取元素內部元素和獲取內容的區別、獲得輸入框value的方法jQuery
- JavaScript 獲取網頁尾本程式碼內容JavaScript網頁
- javascript獲取li元素內容程式碼例項JavaScript
- 09 獲取需求的方法
- js獲取內容中的url連結,並設定a標籤JS
- css input文字框中的內容居中效果CSS
- ueditor文字框初始化如何顯示預設內容,以及文字框獲取焦點後清空預設內容
- Flutter冷知識 | 獲取dart的print內容FlutterDart
- php獲取網頁內容的三種方法PHP網頁
- android開發中如何動態獲取listview中的item的值AndroidView