Здравствуйте,
Столкнулся с проблемой, с которой не получилось разобраться: необходимо реализовать периодическое получение содержимого ячеек с компонента SysListView32, у которого выставлен стиль LVS_OWNERDATA.
Были испробованы различные способы:
1. Стандартное чтение через SendMessage(LVM_GETITEMTEXT). Данный способ работает в этой же программе, но только на компонентах без стиля LVS_OWNERDATA. В данном же случае возвращается пустой текст. В конце сообщения привел фрагмент моего кода, который использую для других компонент.
2. Detours (
http://research.microsoft.com/en-us/projects/detours/ ), EasyHook (
http://easyhook.codeplex.com/ ). Пытался отлавливать TextOut(A,W) и DrawText(A,W,Ex), но почему-то не работало.
3. .NET Automation
4. Очень много решений из интернета, ни одно из которых не работает.
(Возможно что-то еще, чего уже не помню — дело было два месяца назад)
В общем, после одной-двух недель экспериментов я сдался и сделал в лоб — получаю расположение компонента и делаю снимок экрана в данной области, потом распознаю. Но данное решение не очень стабильно, так как нет надежного способа вывести окно в Foreground, плюс есть и другие ограничения.
Я работаю в основном с Java'ой и в WinAPI оценил бы себя где-то на 3 (из 10), и есть большая вероятность, что где-то я пошел по неверному пути или просто допустил ошибку.
Поэтому прошу у вас совета, что еще можно предпринять? Было бы просто идеально, если вы уже сталкивались с такой проблемой и решили ее.
Заранее спасибо.
За рабочий код готов заплатить (как договоримся, но точно не меньше $100).
int GetListViewItemText(HWND handle, int row, int column, LPTSTR text, int size) {
const int SIZE = 512;
int result = 0;
LVITEM lvi, *_lvi;
TCHAR item[SIZE], subitem[SIZE];
LPTSTR itemText;
LPTSTR _subitem;
unsigned long pid;
HANDLE process;
GetWindowThreadProcessId(handle, &pid);
process = OpenProcess(
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE,
pid);
//log(string("process: ") + to_string((llong) process));
_lvi = (LVITEM*) VirtualAllocEx(process, NULL, sizeof(LVITEM), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
itemText = (LPTSTR) VirtualAllocEx(process, NULL, SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
memset(&lvi, 0, sizeof(LVITEM));
memset(item, 0, SIZE);
lvi.cchTextMax = SIZE;
lvi.mask = LVIF_TEXT;
lvi.iSubItem = column;
lvi.pszText = itemText;
lvi.cchTextMax = SIZE;
SIZE_T* bytes = new SIZE_T;
*bytes = 0;
LRESULT res = WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), bytes);
if (!res) {
DWORD error = GetLastError();
log(string("WriteProcessMemory error: ") + to_string((llong) error));
}
res = SendMessage(handle, LVM_GETITEMTEXT, (WPARAM) row, (LPARAM) _lvi);
//log(string("chars: ") + to_string((llong) res));
res = ReadProcessMemory(process, itemText, item, SIZE, bytes);
if (!res) {
DWORD error = GetLastError();
log(string("ReadProcessMemory error: ") + to_string((llong) error));
}
res = ReadProcessMemory(process, itemText, item, SIZE, bytes);
if (!res) {
DWORD error = GetLastError();
log(string("ReadProcessMemory error: ") + to_string((llong) error));
}
//log(string("item: ") + string(item));
// TODO: refactor
int i;
for (i = 0; i + 1 < size && item[i]; ++i) {
text[i] = item[i];
}
text[i] = 0;
result = wcslen(item);
VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
VirtualFreeEx(process, itemText, 0, MEM_RELEASE);
CloseHandle(process);
return result;
}