Автор
|
Тема: Процессы, сообщения и указатели
|
One |
опубликован 25-01-2002 17:43 MSK
Хотелось бы продолжить начатую тему, т.к. я так и осталься в недоумении.ADK писал: >>Естественно, с указателями проблемы будут. А Вы что хотели? comctl32.dll грузится в каждый процесс и даёт указатели на адресное пространство родного процесса. А вот если дело в хуке происходит, то можно отследить, когда он выполняется в нужном процессе. Вот как я понимаю работу виндов: при запуске процесса в него подгружаются все модули, процедуры и функции которых он использует (user32.dll, kernel32.dll и тп., в том числе и comctl32.dll, если его исползовать). В этом легко убедится с помощью ToolHelp32, просмотрев список модулей, запещенных процессом. Теперь рассмотрим банальную ситуацию: берем произвольное окно либо контрол (кнопку, листбокс и тд.), не обязательно принадлежащее нашему процессу и посылаем ему WM_GETTEXT, предварительно выделив память под буффер для получения текста (нужно заметить, что память выделяется в адресном пространстве нашего процесса). В итоге получаем название окна либо контрола. фактически же в этом окне происходит вызов DefWindowProc, т.к. вряд ли оно переопределяет обработку сообщения WM_GETTEXT. Фактически, такую обработку можно прописать в своей процедуре обработки сообщений, причем достаточно просто, и нужно заметить, никаких проблем с занесение текста в адресное пространство другого процесса не возникает. Однако, лично я сталкнулся вот с чем: берем не родной LisView, и посылаем ему LVM_GETITEMTEXT, и сразу получаем ошибку, причем ошибку получаем не в нашем процессе, а в том, к которому мы обращались. Вопрос, почему? Ведь скорее всего, сообщение обрабатывается все той же DefWindowProc. Естественно, M$ не когда не выдаст секретов DefWindowProc, иначе ситуция с ОС M$ будет напоминать ситуцию с Linux. Однако, может быть кто-то имеет малейшее представление, что и почему там происходит, и попытается объяснить это мне. Буду благодарен.
|
Glite
|
опубликован 26-01-2002 04:38 MSK
Поробую обяснить. Когда запускается процесс ось выделяет ему 4 гига виртуального адресного пространства, 2 из которых берёт под свои нужды. Два разных процесса работают в изолированных адресных пространствах. И, приложение не может выполнить физическую адресацию памяти в адресном пространстве другого процесса. Какой бы адресс оно не задало он всегда будет соответствовать одной из его собственных страниц. Т.е. адрес из одного процесса в другом ссылается совершенно на другой участок памяти. Когда ты пытаешься передать указатель в другой процесс, то оно обращается к памяти в своём адресном пространстве, а что там - одному чорту известно. Отсюда и ругань вся. А, дллелины здесь вообще не при делах. Обмен данными между процессами можно осуществить разными способами - socket, файлы отображаемые на память, dde. |
frostbitten
|
опубликован 26-01-2002 06:50 MSK
Удивительного в том, что WM_GETTEXT работает, а LVM_GETITEMTEXT - нет - нет :).Message Quеuе находиться под полным контролем USER, там же находятся и окна. Не сложно предположить, что USER знает о возможности меж процессного WM_GETTEXT поэтому услужливо делает грамотный мост - такой же как WM_COPYDATA, только в др. сторону... Не сложно проверить, что адресс строки, кот ты указаваешь в LPARAM для WM_GETTEXT и тот, что получает обработчик (WndProc) _НЕ_ совпадают - его по пути следования подменил USER, а вот о существовании LVM_GETITEMTEXT USER как бы не знает :)... и передает указатель как ты его прописал - и ты получаешь пятый ексепшон. :)... Бороться так как тебе посоветовали - хуками... В нём делать то, что USER делает с WM_GETTEXT... только более изощренно ты же не USER! :) P.S. К стати, по ходу WM_GETTEXT попадает в мою копилку изощренных средств IPC... Честно говоря не знал о такой возможности :) Напр. можно у окна запрорсить закие-нить данные как: ::SendMessage( hwnd , WM_GETTEXT , (WPARAM)(1000 +ID_PARAM_TO_RETRIEVE_x), (LPARAM)s.GetBufferSetLength(...)); s.ReleaseBuffer(); А в обработчике соответственно возвращать заначение параметра ((int)wParam -1000)... :))))))... |
DenizK
|
опубликован 26-01-2002 09:06 MSK
Если я не ошибаюсь, то WM_GETTEXT так работает для совместимости с Win16. |
One
|
опубликован 28-01-2002 16:01 MSK
2 Glite:Извини, конечно, ты и прав... и не прав. Именно в этом весь вопрос: почему одни функции могут передавать указатели между потоками, а другие - нет? Тут я склонен согласиться с frostbitten, может быть действительно они как-то подменяются. Вопрос, как? Почему я не могу их подменить (или не знаю как это сделать ;)). Хотя я вот что подумал - окна обычно создаются с пользовательским классом, а для таких вещей как кнопки, ListView и другие контролы классы ужу определены системой. А процедура обработки сообщений задается именно там. Т.е. либо M$ не стала развивать для стандартных контролов способность межпотокового обмена "памятью", либо одно из двух. 2 DenizK: Ты ошибаешься. GetWindowText именно через WM_GETTEXT и работает. |
Flex Ferrum
|
опубликован 28-01-2002 16:22 MSK
Причина тут наверное вот в чем. В случае использования GetWindowText все определенно - возвращается текстовая строка изветсного размера. Маршаллинг для такой операции выполнить несложно. А вот с ListView, TreeView и т. п. все несколько сложнее. Между процессами необходимо передавать структуру целиком, со всеми внутренними указателями, объектами и т. д. и т. п. И если с хендлами все более-менее понятно, то вот с данными пользователя - гораздо сложней. По сему, ИМХО, ребята из Microsoft решили не заморачиваться и, если тебе нужно решить такую вот специфическую задачу, как манипуляция с ListView чужого процесса, решай ее сам с использованием хуков. Кстати, здается мне, что если перегрузить обработчик WM_GETTEXT, то все это дело может милейшим образом рухнуть (в том смысле, что результат GetWindowText для такого окна из чужого процесса будет неопределенным). |
One
|
опубликован 28-01-2002 16:53 MSK
2 Flex Ferrum:Да, я согласен, что ребята из M$ решили не заморачиваться, но позволь не согласиться вот с этим: >> Причина тут наверное вот в чем. В случае использования GetWindowText все определенно - возвращается текстовая строка изветсного размера. Маршаллинг для такой операции выполнить несложно. А вот с ListView, TreeView и т. п. все несколько сложнее. Между процессами необходимо передавать структуру целиком, со всеми внутренними указателями, объектами и т. д. и т. п. И вот почему: отправляем сообщение LVM_GETITEMTEXT с одним указателем на строку и ее размером соответственно. Получаем exception. Хотя опять - операция не сложная. Никаких структур с из загонами. Второе - если "перегрузить" значит переписать обработчик, то нет, я пробовал, все работает, никаких проблемм не возникает, в заголовоке окошка показывается тот текст, который мы возвращаем в ответ на WM_GETTEXT (т.е. винды при перерисовке окна вызывают GetWindowText). |
Flex Ferrum
|
опубликован 28-01-2002 17:00 MSK
Не известно, что они там в нутрях намудрили. Предположим, что у тебя текст хранится не в структуре, а возвращается по LVN_GETDISPINFO... Вообщем, я думаю, что они просто решили не заморачиваться. |
x
|
опубликован 29-01-2002 11:29 MSK
а я думаю вы оба неправы дело скорре в том что comctl32 надстройка на GUIuser32 не смотря на то что вызывается через DLL скорее всего по традиции вин16 имеет доступ ко всем элементам=так проще всего и надежнее и быстрее=переклюцение колец защиты далеко не быстрая операция=а элементов согласитесь много comctl был написан много позднее и скорее всего создает конторолы с монопольным доступом каждого процесса тогда вопрос сам собой отпадает |
One
|
опубликован 29-01-2002 16:21 MSK
2 x: Вся проблемма в том, что нет там никакого монопольного доступа, т.к. любое сообщение, отпревленное данному контролу из другого потока, но не связанное с указателями, нормально обрабатывается (так, для ListView можно получать номерь выбранного Item'а, двигать иконки, если не стоит AutoArrange и т.п.) |
frostbitten
|
опубликован 29-01-2002 18:24 MSK
Да не заморачивались они - это backward compatibility называется. И вопрос только в ней.2Flex Ferrum: Перегрузить WM_GETTEXT очень хорошо получается - у меня получилось то о чем я говорил - IPC такой хитрый. 2One: "в заголовоке окошка показывается тот текст, который мы возвращаем в ответ на WM_GETTEXT (т.е. винды при перерисовке окна вызывают GetWindowText)." Это не всегда так - пусти Spy++ и посмотри капшон окошка, для кот. ты переопределил WM_GETTEXT, а на обработчик поставь брикпоинт... так вот он не вызовется... |
x
|
опубликован 29-01-2002 20:52 MSK
слухай сюдыты когда регаешь окошко RegisterClass() указываешь процесс угу? стандартные классы окон уже зареганы by user i think а через какой процесс зареганы ListView и т.п. ? чуешь к чему клоню да? |