Почему Control.FromHandle(IntPtr) возвращает null в одном подключенном процессе и возвращает действительный объект "Form"? в другом подключенном процессе?

Я сталкиваюсь с проблемой, связанной с извлечением всех элементов управления из некоторого подключенного процесса. Мой SpyDll успешно запущен в подключенный процесс, но когда я проверяю оператор

Control control = Control.FromHandle(MainWindowHandle), он возвращает ноль в управляющий объект, где "MainWindowhandle" - это просто собственный дескриптор главного окна этого подключенного процесса, который вы всегда берете из класса.NET "Процесс" после запуска этого процесса.

Но, как ни странно, случается так, что в каком-то другом подключенном процессе, который является тем же приложением C# .NET, он возвращает действительный объект Main "WinForm".

Так почему же это не сработает в вышеуказанном случае? Существуют ли исключения для правильного использования MainWindowHandle. В моем случае оба являются отдельными.NET управляемыми процессами, запрограммированными на C#. Любая конфигурация процесса должна специально поддерживаться при создании этого процесса?

С уважением, Усман

5 ответов

Решение

1.) Имейте в виду, что может быть несколько доменов приложений, и вы можете получить только управляющие объекты текущего домена приложения в текущем процессе. Также вы должны использовать правильную версию ruuntime afaik, но я не уверен в этом.

2.) В любом случае, зачем вам дескриптор управления, гораздо удобнее работать напрямую с нативными дескрипторами, вы даже можете использовать нативные функции из другого процесса, без внедрения dll. Если вам действительно нужны управляемые управляющие объекты, тогда посмотрите на коллекцию Application.OpenForms вместо этого дескриптора поиска!

Когда вы создаете элемент управления / форму с использованием WinForms, код WinForm автоматически сохраняет запись, которая сопоставляет дескриптор собственного окна с экземпляром C#. Когда элемент управления / форма уничтожается, эта запись затем удаляется. Поэтому все, что вызывает Control.FromChildHandle, - это поиск в списке записей, чтобы узнать, имеет ли он соответствующий собственный дескриптор и, если да, возвращает связанный экземпляр C#.

Поэтому вы получите обратно записи C# только для экземпляров Control/Form, созданных из самой WinForms. Родные окна и собственный контроль от присоединения к другому процессу никогда не вернут запись. Вот почему это не работает для вас и никогда не будет, а также почему вы получаете верный класс при работе с приложением C#, которое использовало WinForms для создания окна.

Это связано с тем, что функция, которую вы вызываете "Control.FromHandle", использует хеш-таблицу для поиска экземпляра элемента управления по его дескриптору. Поэтому, когда вы вызываете этот метод для HWND, у которого нет экземпляра элемента управления, вы получите null.

Чтобы использовать HWND, вы должны использовать Win32 Messaging API через вызовы PInvoke. Например, вы можете использовать SendMessage для отправки сообщения WM_GETTEXT для запроса текста окна. Для некоторых из этих сообщений в Windows32 Windowing API существуют различные оболочки, такие как GetWindowText, которые переносят вышеупомянутое сообщение.

Вы изучали использование Control.FromChildHandle? Он будет искать цепочку элементов управления, пока не найдет элемент управления, связанный с этим дескриптором.

В вашем первом случае это может быть не прямой потомок.

Для любого данного AppDomain нестатические члены типа T живут в сущности (экземпляр T). Статические члены типа T живут в другом отдельном объекте (сам тип T). Таким образом, тип или экземпляр T в одном домене приложений отличается от типа или экземпляра T в другом домене приложений. Это означает, что Control.FromHandle имеет смысл только в том случае, если возвращаемый экземпляр находится в том же AppDomain, что и вызывающий метод, в противном случае он должен возвращать нуль.

Для работы с другим доменом приложения вам потребуется кодирование в стиле COM, что-то вроде (psuedocode):

runtimes = IClrMetaHost.EnumerateLoadedRuntimes(processHandle);
host = runtime[0].GetInterface( ICorRuntimeHost );
appdomains = host.EnumDomains();
appdomains[0].CallBack( () => dosomething(); );
Другие вопросы по тегам