Столкнулся с проблемой, с которой не получилось разобраться: необходимо реализовать периодическое получение содержимого ячеек с компонента 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).
Здравствуйте, Kirhog, Вы писали:
K>Здравствуйте,
K>Столкнулся с проблемой, с которой не получилось разобраться: необходимо реализовать периодическое получение содержимого ячеек с компонента SysListView32, у которого выставлен стиль LVS_OWNERDATA.
Раз вы столько времени занимались этой задачей, то хелп уже читали.
LVN_GETDISPINFO пробовали отсылать?
Re[2]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, saf_e, Вы писали:
_>Раз вы столько времени занимались этой задачей, то хелп уже читали.
_>LVN_GETDISPINFO пробовали отсылать?
Спасибо вам за совет, но снова безуспешно: с данным сообщением даже обычные (не виртуальные) таблицы не читаются.
Странно... первый раз с таким сталкиваюсь — задача выглядит не такой уж специфичной, тем не менее в сети нет ни одного рабочего решения, а только описание данной проблемы (некоторым сообщениям уже по 10 лет).
Re: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, Kirhog, Вы писали:
K>Здравствуйте,
K>Столкнулся с проблемой, с которой не получилось разобраться: необходимо реализовать периодическое получение содержимого ячеек с компонента SysListView32, у которого выставлен стиль LVS_OWNERDATA.
Я думаю, что вы наверняка читали в MSDN эту статью. Для SysListView32 в сочетании с LVS_OWNERDATA список является виртуальным. Это означает, что сам SysListView32 несет ответственность только за отрисовку элементов, а ответственность за обработку содержимого несет владелец SysListView32. Это оправдано для списков большого размера, и на пользователя возлагается ответственность по повышению скорости их работы, например, с помощью кэширования.
Естественно LVM_GETITEMTEXT не работает, ибо SysListView32 отрисовал и забыл. Напротив — именно SysListView32 посылает LVN_GETDISPINFO своему владельцу и именно владелец SysListView32 должен обрабатывать у себя LVN_GETDISPINFO и снабжать SysListView32 информацией для отображения, если SysListView32 требуется свои айтемы перерисовать. Я не использовал SysListView32 из WinAPI, а из MFC, и, к сожалению, это было много лет назад. Помнится, тогда для стиля LVS_OWNERDATA я наследовался от CListView, добавлял помимо всего прочего в члены класса-потомка список отображаемых элеметов и функции для загрузки из файла — выгрузки в файл, а также обработчик LVN_GETDISPINFO, который пересылался в мой класс-потомок из родительского диалога. В итоге эти функции загрузки — выгрузки вызывались исходя из логики работы программы, а не действий пользователя, и если в результате загрузки содержимое менялось, я перерисовывал CListView. Если пользователь прокручивал список, я в обработчике LVN_GETDISPINFO снабжал CListView айтемами для отображения. Больше, увы, уже не припомню. Как вы сделаете под WinApi, уже вам виднее.
Re[3]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, Kirhog, Вы писали:
K>Спасибо вам за совет, но снова безуспешно: с данным сообщением даже обычные (не виртуальные) таблицы не читаются.
Невиртуальные и не должны. Всё ли правильно делаете?
Сообщение WM_NOTIFY отсылается родителю SysListView32, а не ему самому, сам SysListView32 в параметрах сообщения
перед отправкой заполняются соответствующие поля NMLVDISPINFO
это сообщение нельзя слать из другого процесса
Русский военный корабль идёт ко дну!
Re[4]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, Alexander G, Вы писали:
AG>Невиртуальные и не должны. Всё ли правильно делаете? AG> Сообщение WM_NOTIFY отсылается родителю SysListView32, а не ему самому, сам SysListView32 в параметрах сообщения AG> перед отправкой заполняются соответствующие поля NMLVDISPINFO AG> это сообщение нельзя слать из другого процесса
Привожу код, с помощью которого я это делал.
Первые два пункта выполнил, а вот про третий не знал (в статье про LVN_GETDISPINFO на MSDN'e про это не говорится, но наверное подразумевается). Я так понимаю, что необходимо встроить свою Dll в другой процесс и посылать это сообщение из нее?
Спасибо за наводку, вечером попробую.
Здравствуйте, Kirhog, Вы писали:
K>Первые два пункта выполнил, а вот про третий не знал (в статье про LVN_GETDISPINFO на MSDN'e про это не говорится, но наверное подразумевается). Я так понимаю, что необходимо встроить свою Dll в другой процесс и посылать это сообщение из нее?
Я бы это попробовал.
дело в том, что про WM_NOTIFY пишут:
For Windows 2000 and later systems, the WM_NOTIFY message cannot be sent between processes.
Способ с выделением в чужом процессе через VirtualAllocEx и передавать эти указатели работает для сообщений, номер которых больше или равен WM_USER.
Стандартные сообщения, которые меньше WM_USER, маршалятся самой Windows.
Т.к. WM_NOTIFY меньше WM_USER, она в том диапазоне, который маршаллится Windows.
У меня подозрение, что процитированный комментарий означает, что это сообщение Windows отказывается маршалить, и просто не передаёт его между процессами.
Русский военный корабль идёт ко дну!
Re[6]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, Alexander G, Вы писали:
AG>У меня подозрение, что процитированный комментарий означает, что это сообщение Windows отказывается маршалить, и просто не передаёт его между процессами.
Что легко проверяется "на кошках"
Re[7]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, saf_e, Вы писали:
AG>>У меня подозрение, что процитированный комментарий означает, что это сообщение Windows отказывается маршалить, и просто не передаёт его между процессами.
_>Что легко проверяется "на кошках"
У меня нет под рукой кошки достаточной длины.
Русский военный корабль идёт ко дну!
Re[6]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, Alexander G, Вы писали:
AG>Я бы это попробовал.
Вы знаете? Сработало, но только с тем компонентом, который не представляет для меня интереса (он тоже LVS_OWNERDATA).
Спасибо вам! Хоть какое-то продвижение.
Какие еще могут быть сравнительно простые способы попытаться решить эту проблему?
Вот, кстати, что выдал API Monitor v2. Видно, что родительскому компоненту посылается сообщение на отрисовку элемента, потом он запрашивает данный элемент у таблицы, а после этого рисует содержимое ячеек на DC (это первое упоминание интересующего меня текста "192682093").
Я пробовал перехватывать LVM_GETITEMA сообщение, но это мне ничего не дало: текст в LVITEM структуре пустой. Или в этой структуре где-то спрятан указатель на содержимое элемента; или родительский компонент хранит их у себя, а LVM_GETITEMA запрашивает по другим причинам; или ...
Можно было бы поставить точку останова и как-то изучить содержимое памяти, но API Monitor не поддерживает для них условия, а вызовов SendMessage слишком много, чтобы добраться до нужного. Не знаете ли вы о каком-нибудь средстве, у которого была такая возможность?
). Возможно в той программе для данной таблицы реализован какой-нибудь специальный обработчик, что не получается подступиться к нему стандартными средствами.
Re[7]: Чтение данных из SysListView32 со стилем LVS_OWNERDATA
Здравствуйте, Kirhog, Вы писали:
K>Здравствуйте, Alexander G, Вы писали:
AG>>Я бы это попробовал.
K>Вы знаете? Сработало, но только с тем компонентом, который не представляет для меня интереса (он тоже LVS_OWNERDATA). K>Спасибо вам! Хоть какое-то продвижение.
K>Какие еще могут быть сравнительно простые способы попытаться решить эту проблему?
Могу вообразить что там в интересующем owner draw или custom draw какой нибудь.
Если он рисует в ответ на NM_CUSTOMDRAW, то в NMLVCUSTOMDRAW передаётся dc, на котором он рисует, вот передать свой DC.
У DRAWITEMSTRUCT для WM_DRAWITEM тоже dc есть.
Можно попробовать передать свой dc, и, если код обработчика не игнорирует этот параметр, текст будет отрисован на нём.
Дальнейшие действия в зависимости от успеха этой акции.