Как получить дескриптор окна консольного приложения

Инструкция

Получите дескриптор окна , создав его. Произведите вызовы API-функций CreateWindow или CreateWindowEx, либо вызовите соответствующие методы-обертки (на необходимых объектах) классов используемого фреймворка или библиотеки, инкапсулирующих функционал работы с окна ми или элементами управления.Функции CreateWindow и CreateWindowEx непосредственно возвращают дескриптор окна при успешном его создании. При неудачном вызове они возвращают значение NULL. Код причины ошибки может быть запрошен при помощи API-функции GetLastError. Прототипы и подробное описание параметров функций CreateWindow и CreateWindowEx можно получить по ссылкам http://msdn.microsoft.com/en-us/library/windows/desktop/ms632679%28v=vs.85%29.aspx и http://msdn.microsoft.com/en-us/library/windows/desktop/ms632680%28v=vs.85%29.aspx .При использовании классов различных фреймворков создание объектов окон операционной системы может происходить как явно (посредством вызова метода), так и неявно (реализация стратегии RAII). Поэтому дескриптор окна лучше получать на готовом инициализированном объекте. О методах классов, возвращающих дескриптор окна , инкапсулируемый объектом, можно узнать в документации соответствующего фреймворка. Например, в MFC подобным методом является GetSafeHwnd класса CWnd.

Получите дескриптор окна путем его поиска. Используйте API-функции FindWindow и FindWindowEx или соответствующие методы-обертки объектов классов применяемого фреймворка.Функция FindWindow возвращает дескриптор окна верхнего уровня, если оно найдено или NULL при неудаче. Поиск производится по имени класса и заголовку окна . Описание параметров и аспектов работы функции находится по ссылке http://msdn.microsoft.com/en-us/library/windows/desktop/ms633499%28v=vs.85%29.aspx .Семантика работы функции FindWindowEx аналогична FindWindow с той лишь разницей, что она производит поиск дочерних окон. Документация для FindWindowEx приведена по ссылке http://msdn.microsoft.com/en-us/library/windows/desktop/ms633500%28v=vs.85%29.aspx .

Найдите дескриптор окна в процессе перечисления их множеств. Воспользуйтесь API-функциями EnumWindows, EnumChildWindows, EnumThreadWindows либо методами объектов классов используемого фреймворка.Функции EnumWindows и EnumChildWindows перечисляют окна верхнего уровня и дочерние окна соответственно. Функция EnumThreadWindows перечисляет все не дочерние окна указанного потока. Каждой из этих функций должен быть передан указатель на процедуру обратного вызова, которой в процессе работы будут передаваться дескриптор ы найденных окон в качестве параметров.Комбинируя функции перечисления, получая и анализируя свойства окон в процедуре обратного вызова, можно найти дескриптор требуемого окна . Документация для описанных функций приведена по ссылкам:- EnumWindows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633497%28v=vs.85%29.aspx ;- EnumChildWindows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633494%28v=vs.85%29.aspx ;- EnumThreadWindows: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633495%28v=vs.85%29.aspx .

Получите дескриптор окна по известным координатам. Функции WindowFromPoint, ChildWindowFromPoint, ChildWindowFromPointEx возвращают дескриптор ы окон, к областям расположения которых принадлежит заданная точка.Функция WindowFromPoint наиболее проста в использовании, но не возвращает дескриптор ы скрытых и отключенных окон. Документация по ее находится по ссылке http://msdn.microsoft.com/en-us/library/windows/desktop/ms633558%28v=vs.85%29.aspx .Функции ChildWindowFromPoint и ChildWindowFromPointEx находят дескриптор ы дочерних окон заданного родительского окна , принадлежащих заданной точке. При этом поведением ChildWindowFromPointEx можно гибко управлять с помощью дополнительного параметра. Документация для данных функций приводится по ссылкам:- ChildWindowFromPoint: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632676%28v=vs.85%29.aspx ;- ChildWindowFromPointEx: http://msdn.microsoft.com/en-us/library/windows/desktop/ms632677%28v=vs.85%29.aspx .

Видео по теме

Интерфейс прикладного программирования операционных систем семейства Windows представлен набором функций. При их вызовах могут создаваться различные объекты (файлы, процессы, потоки, объекты синхронизации, и т.д.). Для обеспечения достаточно абстрактного и унифицированного доступа к этим объектам их идентификация производится при помощи дескрипторов - «обезличенных» числовых значений.

Вам понадобится

  • - транслятор с языка программирования, допускающего использование Windows API;
  • - возможно, Windows Platform SDK.

Инструкция

Получите дескрипторы окон. Это можно сделать очень многими путями. Конкретный способ зависит от конечной цели.

Используйте API-функции CreateWindow или CreateWindowEx для создания окна. Они возвращают дескриптор в случае успеха и NULL в случае неудачи.

Произведите поиск окон верхнего уровня и дочерних окон по различным параметрам с использованием функций FindWindow и FindWindowEx соответственно. При успешном поиске будет получен дескриптор окна.

Перечисляйте окна функциями EnumWindows, EnumChildWindows, EnumThreadWindows. Дескрипторы найденных окон будут передаваться в качестве параметра функции обратного вызова.

Найдите дескриптор окна, расположенного в определенной позиции на экране. Произведите вызов одной из функций: WindowFromPoint, ChildWindowFromPoint или ChildWindowFromPointEx.

Получите дескрипторы процессов. Создайте новый процесс при помощи вызова API-функций CreateProcess, CreateProcessAsUser, CreateProcessWithTokenW или CreateProcessWithLogonW. Все они возвращают дескриптор нового процесса в поле hProcess структуры типа PROCESS_INFORMATION, указатель на которую должен передаваться им последним параметром.

Найдите дескриптор процесса по его известному идентификатору. Используйте вызов OpenProcess. Идентификаторы всех запущенных процессов могут быть получены, например, при помощи функций CreateToolhelp32Snapshot, Process32First и Process32Next библиотеки Tool Help.

Извлеките псевдо-дескриптор текущего процесса, используя функцию GetCurrentProcess.

Получите дескрипторы потоков. Функции CreateThread и CreateRemoteThread создают потоки в своем и чужом процессе, соответственно, возвращая их дескрипторы. Открыть существующий поток с использованием его идентификатора, получив соответствующий дескриптор, можно при помощи функции OpenThread. Псевдо-дескриптор текущего подтока возвращается при вызове GetCurrentThread.

Возможности языков семейства Си по истине безграничны, однако, в этой свободе кроются и недостатки: всегда нужно программисту держать ухо востро и контроллировать "переполнение буфера", чтобы потом программа не вылетала в "синий экран" на массе разнообразных версий Windows и железа у пользователей. Те же крэкеры и реверсеры специально ищут в коде программ на Си уязвимости, куда можно подсадить любой вирусный код, об этом более подробно автор рассказывал в своём видеокурсе . Я там многое узнал и теперь мой код стал значительно более безопасный.

Как получить дескриптор консольного окна (HWND)

Иногда необходимо производить какие-нибудь действия с окном, связанным с консольным приложением. Win32 API не предоставлят прямых методов получения дескриптора окна, связанного с консольным приложением. Однако, дескритор (handle) окна можно получить вызвав FindWindow(). Эта функция отыскивает дескриптор окна, основанный на имени класса либо имени окна.

Чтобы определить текущий заголовок консоли, вызывается GetConsoleTitle(). Затем этот заголовок указывается в функции FindWindow().

Так как несколько окошек могут иметь одинаковый заголовок, то Вам прийдётся изменить заголовок текущего консольного окна на уникальный. Это поможет защититься от получения неправильного дескриптора окна. Для изменения заголовка текущего консольного окна используется SetConsoleTitle(). Вот как это делается:

  1. Вызываем GetConsoleTitle() чтобы сохранить заголовок текущего консольного окна.
  2. Вызываем SetConsoleTitle() чтобы изменить заголовок на уникальный (неповторимы).
  3. Вызываем Sleep(40) чтобы дать время заголовку измениться.
  4. Вызываем FindWindow(NULL, uniquetitle), для получения HWND. Этот запрос возвратит HWND либо NULL в случае неудачи.
  5. Вызываем SetConsoleTitle() со значением, полученным в шаге 1, для восстановления изначального заголовка окна.

Необходимо проверить полученный HWND. Например, можно проверить, соответствует ли полученный HWND текущего процесса, вызвав для него GetWindowText() с этим HWND и сравнив его с результатом, полученным при помощи GetConsoleTitle().

Нет гарантии, что полученный HWND подойдёт для всех возможных операций с дескриптором окна.

Пример кода

Следующая функция возвращает дескриптор текущего окна консольного приложения (HWND). Если функция выполнена удачно, то возвращённое значение будет являться дескриптором консольного окна, иначе, вслучае ошибки будет возвращён NULL. Для краткости, некоторые проверки возможных ошибок убраны.

HWND GetConsoleHwnd(void) { #define MY_BUFSIZE 1024 // Размер буфера для заголовка консольного окна. HWND hwndFound; // Это то, что будет возвращено. char pszNewWindowTitle; // Уникальный заголовок окна. char pszOldWindowTitle; // Изначальный заголовок окна. // Выбираем текущий заголовок окна. GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE); // Формируем "уникальный" NewWindowTitle. wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId()); // Изменяем текущий заголовок окна. SetConsoleTitle(pszNewWindowTitle); // даём время заголовку, чтобы измениться. Sleep(40); // Ищем NewWindowTitle. hwndFound=FindWindow(NULL, pszNewWindowTitle); // Восстанавливаем изначальный заголовок окна. SetConsoleTitle(pszOldWindowTitle); return(hwndFound); }

В общих чертах, дескрипторы — это некие атрибуты объектов, для которых определено соответствующее поведение. При доступе к ним происходит получение, установка или удаление указанных атрибутов из словаря. Говоря простым языком, это особые ключевые слова, определяющие поведение объекта, его свойства или структуру. В статье будет рассмотрено несколько вариантов дескрипторов. Это позволит более точно понять их суть и предназначение.

HTML

В языке разметки гипертекста, который применяется для создания статичных веб-страниц, дескрипторы — это не что иное, как тэги. В этой среде они выполняют роль меток, благодаря которым текст, размещённый между ними, отображается определенным способом. Таким образом и формируется дизайн и расположение элементов на странице.

Как правило, специфика языка определяет наличие открывающего дескриптора и закрывающего. Все, что между ними, подвержено изменению.

Дескриптор может иметь атрибуты, то есть определённые свойства. Их синтаксис выглядит так: имя атрибута = его значение.

Подчиняясь общей логике, дескрипторы в HTML представляют собой идентификационные метки объектов. С их помощью можно управлять внешним видом, взаимодействовать со страницей и присваивать ей особые значения.

Архитектура х86

В процессорах дескрипторы — это особая структура, с помощью которой совершаются различные переходы. Её строение выглядит так:

  • Смещение. Может сдвинуть процедуру кода.
  • Селектор. Отражает своего рода метку, куда должна перейти процедура.
  • Количество параметров.
  • Права доступа.

Java

В Java EE имеется понятие дескриптора развёртывания. Он определяет то, каким образом будет развёрнут сервлет. По сути, это конфигурационный файл, содержащий настройки, свойства и требования к аппаратной части.

В веб-приложениях такой файл по правилам должен называться web.xml и располагаться в определённой папке.

Файловые дескрипторы

В операционных системах для работы с файлами к ним сначала нужно получить доступ. Это можно осуществить через файловый дескриптор. В данном примере он выполняет роль своего рода метки, которой обозначается процесс, создавший поток ввода-вывода.

Операционная система Windows позволяет обратиться к дескриптору с помощью функции CreateFile. Его можно в дальнейшем использовать при работе с требуемым файлом.

В Unix системах для файлового дескриптора используется цифровые обозначения. 0 — стандартный ввод процесса терминала, 1 — его вывод, 2 — поток диагностики. Помимо числовых представлений можно использовать символические константы, определённые спецификацией.

Дескриптор окна

После того как в системе создаётся любое окно, ему присваивается определённый дескриптор. Типы данных применяемых в нем — HWND. Программисту, при создании приложения, нужно правильно использовать их для обращения к

Программа может получить дескриптор, обратившись к помощи функции FindWindow. Она по имени класса или объекта окна сможет его найти и вернуть значение дескриптора.

Чтобы проверить, правильно ли прошла идентификация, стоит использовать функцию IsWindow.

Ошибка номер 1400

Данная проблема часто встречается в семействе операционных систем Windows. При её появлении вместе с ней может быть и краткое описание — недопустимый дескриптор окна. А может встречаться и такая формулировка - «Error_invalid_window_handle» или 0х578.

Как бороться и что значит неверный дескриптор? В зависимости от контекста объекта, нужно принимать разные меры.

В любом случае стоит сразу же пройтись по стандартным мерам, принимаемым ко всем проблемам с системой:

  • запуск и сканирование ошибки с помощью утилиты проверки целостности системных файлов;
  • проверить компьютер на вирусы.
  • Если базовые шаги не помогли, то, возможно, стоит удалить и снова установить приложение, которое вызывает сбой.

    Ещё один надёжный способ быстро восстановить работоспособность системы — сделать её откат с помощью стандартных инструментов. После использования «Восстановления системы», она вернётся к последней действующей резервной копии, при условии что она была ранее создана.

    Когда может возникнуть ошибка

    В большинстве случаев ошибка неверного дескриптора вызывается из-за недоработок в установленном программном обеспечении. Поэтому стоит внимательно следить за тем, что из софта появляется на компьютере. Также необходимо периодически обновлять все имеющееся программное обеспечение и следить за его состоянием. При этом стоит вооружиться и хорошим антивирусным ПО.

    Заключение

    В статье были представлены общие принципы работы дескрипторов в различных языках программирования и операционных системах, их функции, свойства и виды. Как правило, данный термин в основном используется программистами и разработчиками для идентификации объектов и элементов для последующего обращения к ним и управления.

    А также стало ясно, что это — неверный дескриптор. Как оказалось, это распространённая проблема в среде Windows, в большинстве случаев решаемая простыми манипуляциями.

    Вот надежный способ сделать это:

    Static extern bool AttachConsole(uint dwProcessId); static extern IntPtr GetConsoleWindow(); static extern bool FreeConsole();

    • Для консоли, к которой подключен текущий процесс, достаточно просто GetConsoleWindow()
    • Для консоли подключен другой процесс, подключаемый к нему также с помощью AttachConsole , вызывайте GetConsoleWindow , они сразу же отсоединяются от FreeConsole .

    Для дополнительной осторожности зарегистрируйте обработчик событий консоли перед тем, как присоединить (и отменить регистрацию после отсоединения), чтобы вы случайно не закончили, если событие консоли произойдет в крошечном временном интервале, который вы подключили к консоли:

    Static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add); delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType); enum CtrlTypes: uint { CTRL_C_EVENT = 0, CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT = 5, CTRL_SHUTDOWN_EVENT } bool is_attached=false; ConsoleCtrlDelegate ConsoleCtrlDelegateDetach = delegate(CtrlType) { if (is_attached = !FreeConsole()) Trace.Error("FreeConsole on " + CtrlType + ": " + new Win32Exception()); return true; };

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

    Информация о ReadProcessMemory консоли находится внутри и управляется csrss.exe (или множеством из них, по одному для каждого сеанса, начиная с Vista), поэтому его нельзя получить с помощью ReadProcessMemory . Все, что предоставляет csrss это API CSRSS LPC . Там только одна соответствующая функция в полном списке API, SrvGetConsoleWindow . И он не принимает PID, но определяет, что вызывающей стороны рассматривается в или разборки функции в winsrv.dll .

    Попробуйте следующее:

    Public static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName); … Console.Title = "Test"; … IntPtr handle = FindWindowByCaption(IntPtr.Zero, Console.Title);

    Я только что решил эту проблему для себя (к сожалению, прежде чем увидеть ответ Томаса , который намного быстрее). Ну, вот еще один способ для тех, кто не удовлетворен его ответом. Я пишу этот ответ, потому что хочу предоставить другой ответ + лучший способ создать класс Program , если вы рассматриваете консоль как окно. Начнем с этого дизайна:

    Я изменил стиль по умолчанию класса Program . Я действительно превратил его в класс, в котором есть программа, а не только один метод, который представляет его, и использует другие классы для контента. (Если вы не знаете, что я имею в виду, не важно).

    Причина, по которой я должен был это сделать, - это то, что я хотел написать следующий обработчик событий:

    Private void CatchUnhandled(Object sender, UnhandledExceptionEventArgs e) { var exception = e.ExceptionObject as Exception; MessageBox.Show(this, exception.Message, "Error"); // Check out 1st arg. }

    Поскольку консоль не реализует IWin32Window , я должен был реализовать ее сам, конечно, чтобы просто позвонить this в аргументе 1 st .

    Вот его реализация и все остальное:

    Примечание: этот код скопирован из моего приложения, вы можете свободно изменять модификаторы доступа

    Program Декларация класса:

    Internal class Program: IWin32Window { ... }