LVM_GETCOLUMN returns 无结果
LVM_GETCOLUMN returns no result
我试图监视一个 syslistview32
元素。阅读内容效果很好,但我无法获取列 headers 的文本。
这是"my"代码(我不想用借来的羽毛来装饰自己-大部分代码来自https://konradn.wordpress.com/2012/02/21/read-listviewitem-content-from-another-process/):
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct LV_COLUMN
{
public System.Int32 mask;
public System.Int32 fmt;
public System.Int32 cx;
public System.IntPtr pszText;
public System.Int32 cchTextMax;
public System.Int32 iSubItem;
public System.Int32 iImage;
public System.Int32 iOrder;
}
public static string GetListViewColumn(System.IntPtr hwnd, uint processId, int Column)
{
const int dwBufferSize = 2048;
const int LVM_FIRST = 0x1000;
const int LVM_GETCOLUMNA = LVM_FIRST + 25;
const int LVM_GETCOLUMNW = LVM_FIRST + 95;
const int LVCF_FMT = 0x00000001;
int bytesWrittenOrRead = 0;
LV_COLUMN lvCol;
string retval;
bool bSuccess;
System.IntPtr hProcess = System.IntPtr.Zero;
System.IntPtr lpRemoteBuffer = System.IntPtr.Zero;
System.IntPtr lpLocalBuffer = System.IntPtr.Zero;
try
{
lvCol = new LV_COLUMN();
lpLocalBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(dwBufferSize);
hProcess = OpenProcess(Win32ProcessAccessType.AllAccess, false, processId);
if (hProcess == System.IntPtr.Zero)
throw new System.ApplicationException("Failed to access process!");
lpRemoteBuffer = VirtualAllocEx(hProcess, System.IntPtr.Zero, dwBufferSize, Win32AllocationTypes.MEM_COMMIT, Win32MemoryProtection.PAGE_READWRITE);
if (lpRemoteBuffer == System.IntPtr.Zero)
throw new System.SystemException("Failed to allocate memory in remote process");
lvCol.mask = LVCF_FMT;
lvCol.pszText = (System.IntPtr)(lpRemoteBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN)));
lvCol.cchTextMax = 500;
lvCol.iOrder = Column;
bSuccess = WriteProcessMemoryGETCOLUMN(hProcess, lpRemoteBuffer, ref lvCol, (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN)), out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to write to process memory");
SendMessage(hwnd, LVM_GETCOLUMNA, System.IntPtr.Zero, lpRemoteBuffer);
bSuccess = ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, dwBufferSize, out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to read from process memory");
retval = System.Runtime.InteropServices.Marshal.PtrToStringUni((System.IntPtr)(lpLocalBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN))));
}
finally
{
if (lpLocalBuffer != System.IntPtr.Zero)
System.Runtime.InteropServices.Marshal.FreeHGlobal(lpLocalBuffer);
if (lpRemoteBuffer != System.IntPtr.Zero)
VirtualFreeEx(hProcess, lpRemoteBuffer, 0, Win32AllocationTypes.MEM_RELEASE);
if (hProcess != System.IntPtr.Zero)
CloseHandle(hProcess);
}
return retval;
}
无论我为列提供哪个值,结果总是string.Empty
。
获取列表视图内容的函数非常好用,非常相似:
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct LV_ITEM
{
public System.Int32 mask;
public System.Int32 iItem;
public System.Int32 iSubItem;
public System.Int32 state;
public System.Int32 stateMask;
public System.IntPtr pszText;
public System.Int32 cchTextMax;
public System.Int32 iImage;
public System.Int32 lParam;
public System.Int32 iIndent;
}
public static string GetListViewItem(System.IntPtr hwnd, uint processId, int item, int subItem, out bool Valid)
{
const int dwBufferSize = 2048;
const int LVM_FIRST = 0x1000;
const int LVM_GETITEMW = LVM_FIRST + 75;
const int LVM_GETITEM = LVM_FIRST + 5;
const int LVIF_TEXT = 0x00000001;
int bytesWrittenOrRead = 0;
LV_ITEM lvItem;
string retval;
bool bSuccess;
System.IntPtr hProcess = System.IntPtr.Zero;
System.IntPtr lpRemoteBuffer = System.IntPtr.Zero;
System.IntPtr lpLocalBuffer = System.IntPtr.Zero;
try
{
lvItem = new LV_ITEM();
lpLocalBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(dwBufferSize);
hProcess = OpenProcess(Win32ProcessAccessType.AllAccess, false, processId);
if (hProcess == System.IntPtr.Zero)
throw new System.ApplicationException("Failed to access process!");
lpRemoteBuffer = VirtualAllocEx(hProcess, System.IntPtr.Zero, dwBufferSize, Win32AllocationTypes.MEM_COMMIT, Win32MemoryProtection.PAGE_READWRITE);
if (lpRemoteBuffer == System.IntPtr.Zero)
throw new System.SystemException("Failed to allocate memory in remote process");
lvItem.mask = LVIF_TEXT;
lvItem.iItem = item;
lvItem.iSubItem = subItem;
lvItem.pszText = (System.IntPtr)(lpRemoteBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_ITEM)));
lvItem.cchTextMax = 500;
bSuccess = WriteProcessMemoryGETITEM(hProcess, lpRemoteBuffer, ref lvItem, (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_ITEM)), out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to write to process memory");
SendMessage(hwnd, LVM_GETITEMW, System.IntPtr.Zero, lpRemoteBuffer);
int Result = (int)SendMessage(hwnd, LVM_GETITEM, System.IntPtr.Zero, lpLocalBuffer);
if(Result == 0) { Valid = false; }else { Valid = true; }
bSuccess = ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, dwBufferSize, out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to read from process memory");
retval = System.Runtime.InteropServices.Marshal.PtrToStringUni((System.IntPtr)(lpLocalBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_ITEM))));
}
finally
{
if (lpLocalBuffer != System.IntPtr.Zero)
System.Runtime.InteropServices.Marshal.FreeHGlobal(lpLocalBuffer);
if (lpRemoteBuffer != System.IntPtr.Zero)
VirtualFreeEx(hProcess, lpRemoteBuffer, 0, Win32AllocationTypes.MEM_RELEASE);
if (hProcess != System.IntPtr.Zero)
CloseHandle(hProcess);
}
return retval;
}
有没有人知道我做错了什么。
非常感谢您的帮助。
此致,
一月
Ps.: 我知道UI Automation
,我喜欢UI Automation
,我知道UI Automation
可以解决这个问题,但是我不想用在这种情况下。
你只是要求 LVCF_FMT
,你需要在掩码中包含 LVCF_TEXT
并设置 iSubItem
成员。
我试图监视一个 syslistview32
元素。阅读内容效果很好,但我无法获取列 headers 的文本。
这是"my"代码(我不想用借来的羽毛来装饰自己-大部分代码来自https://konradn.wordpress.com/2012/02/21/read-listviewitem-content-from-another-process/):
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct LV_COLUMN
{
public System.Int32 mask;
public System.Int32 fmt;
public System.Int32 cx;
public System.IntPtr pszText;
public System.Int32 cchTextMax;
public System.Int32 iSubItem;
public System.Int32 iImage;
public System.Int32 iOrder;
}
public static string GetListViewColumn(System.IntPtr hwnd, uint processId, int Column)
{
const int dwBufferSize = 2048;
const int LVM_FIRST = 0x1000;
const int LVM_GETCOLUMNA = LVM_FIRST + 25;
const int LVM_GETCOLUMNW = LVM_FIRST + 95;
const int LVCF_FMT = 0x00000001;
int bytesWrittenOrRead = 0;
LV_COLUMN lvCol;
string retval;
bool bSuccess;
System.IntPtr hProcess = System.IntPtr.Zero;
System.IntPtr lpRemoteBuffer = System.IntPtr.Zero;
System.IntPtr lpLocalBuffer = System.IntPtr.Zero;
try
{
lvCol = new LV_COLUMN();
lpLocalBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(dwBufferSize);
hProcess = OpenProcess(Win32ProcessAccessType.AllAccess, false, processId);
if (hProcess == System.IntPtr.Zero)
throw new System.ApplicationException("Failed to access process!");
lpRemoteBuffer = VirtualAllocEx(hProcess, System.IntPtr.Zero, dwBufferSize, Win32AllocationTypes.MEM_COMMIT, Win32MemoryProtection.PAGE_READWRITE);
if (lpRemoteBuffer == System.IntPtr.Zero)
throw new System.SystemException("Failed to allocate memory in remote process");
lvCol.mask = LVCF_FMT;
lvCol.pszText = (System.IntPtr)(lpRemoteBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN)));
lvCol.cchTextMax = 500;
lvCol.iOrder = Column;
bSuccess = WriteProcessMemoryGETCOLUMN(hProcess, lpRemoteBuffer, ref lvCol, (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN)), out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to write to process memory");
SendMessage(hwnd, LVM_GETCOLUMNA, System.IntPtr.Zero, lpRemoteBuffer);
bSuccess = ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, dwBufferSize, out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to read from process memory");
retval = System.Runtime.InteropServices.Marshal.PtrToStringUni((System.IntPtr)(lpLocalBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_COLUMN))));
}
finally
{
if (lpLocalBuffer != System.IntPtr.Zero)
System.Runtime.InteropServices.Marshal.FreeHGlobal(lpLocalBuffer);
if (lpRemoteBuffer != System.IntPtr.Zero)
VirtualFreeEx(hProcess, lpRemoteBuffer, 0, Win32AllocationTypes.MEM_RELEASE);
if (hProcess != System.IntPtr.Zero)
CloseHandle(hProcess);
}
return retval;
}
无论我为列提供哪个值,结果总是string.Empty
。
获取列表视图内容的函数非常好用,非常相似:
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
struct LV_ITEM
{
public System.Int32 mask;
public System.Int32 iItem;
public System.Int32 iSubItem;
public System.Int32 state;
public System.Int32 stateMask;
public System.IntPtr pszText;
public System.Int32 cchTextMax;
public System.Int32 iImage;
public System.Int32 lParam;
public System.Int32 iIndent;
}
public static string GetListViewItem(System.IntPtr hwnd, uint processId, int item, int subItem, out bool Valid)
{
const int dwBufferSize = 2048;
const int LVM_FIRST = 0x1000;
const int LVM_GETITEMW = LVM_FIRST + 75;
const int LVM_GETITEM = LVM_FIRST + 5;
const int LVIF_TEXT = 0x00000001;
int bytesWrittenOrRead = 0;
LV_ITEM lvItem;
string retval;
bool bSuccess;
System.IntPtr hProcess = System.IntPtr.Zero;
System.IntPtr lpRemoteBuffer = System.IntPtr.Zero;
System.IntPtr lpLocalBuffer = System.IntPtr.Zero;
try
{
lvItem = new LV_ITEM();
lpLocalBuffer = System.Runtime.InteropServices.Marshal.AllocHGlobal(dwBufferSize);
hProcess = OpenProcess(Win32ProcessAccessType.AllAccess, false, processId);
if (hProcess == System.IntPtr.Zero)
throw new System.ApplicationException("Failed to access process!");
lpRemoteBuffer = VirtualAllocEx(hProcess, System.IntPtr.Zero, dwBufferSize, Win32AllocationTypes.MEM_COMMIT, Win32MemoryProtection.PAGE_READWRITE);
if (lpRemoteBuffer == System.IntPtr.Zero)
throw new System.SystemException("Failed to allocate memory in remote process");
lvItem.mask = LVIF_TEXT;
lvItem.iItem = item;
lvItem.iSubItem = subItem;
lvItem.pszText = (System.IntPtr)(lpRemoteBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_ITEM)));
lvItem.cchTextMax = 500;
bSuccess = WriteProcessMemoryGETITEM(hProcess, lpRemoteBuffer, ref lvItem, (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_ITEM)), out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to write to process memory");
SendMessage(hwnd, LVM_GETITEMW, System.IntPtr.Zero, lpRemoteBuffer);
int Result = (int)SendMessage(hwnd, LVM_GETITEM, System.IntPtr.Zero, lpLocalBuffer);
if(Result == 0) { Valid = false; }else { Valid = true; }
bSuccess = ReadProcessMemory(hProcess, lpRemoteBuffer, lpLocalBuffer, dwBufferSize, out bytesWrittenOrRead);
if (!bSuccess)
throw new System.SystemException("Failed to read from process memory");
retval = System.Runtime.InteropServices.Marshal.PtrToStringUni((System.IntPtr)(lpLocalBuffer.ToInt32() + System.Runtime.InteropServices.Marshal.SizeOf(typeof(LV_ITEM))));
}
finally
{
if (lpLocalBuffer != System.IntPtr.Zero)
System.Runtime.InteropServices.Marshal.FreeHGlobal(lpLocalBuffer);
if (lpRemoteBuffer != System.IntPtr.Zero)
VirtualFreeEx(hProcess, lpRemoteBuffer, 0, Win32AllocationTypes.MEM_RELEASE);
if (hProcess != System.IntPtr.Zero)
CloseHandle(hProcess);
}
return retval;
}
有没有人知道我做错了什么。
非常感谢您的帮助。
此致, 一月
Ps.: 我知道UI Automation
,我喜欢UI Automation
,我知道UI Automation
可以解决这个问题,但是我不想用在这种情况下。
你只是要求 LVCF_FMT
,你需要在掩码中包含 LVCF_TEXT
并设置 iSubItem
成员。