Чтение данных из SysListView32 со стилем LVS_OWNERDATA
От: Kirhog  
Дата: 19.12.13 12:52
Оценка:
Здравствуйте,

Столкнулся с проблемой, с которой не получилось разобраться: необходимо реализовать периодическое получение содержимого ячеек с компонента 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;
}
winapi syslistview32 lvs_ownerdata c++ с# .net
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.