Распоряжайтесь окнами сами
Очень часто на всевозможных конференциях я видел вопросы, связанные с каким-либо действием над окном, закрыть окно, переместить, свернуть. Как я понял, народ очень желает получить контроль над всеми окнами и задачами, активными в данный момент в системе. Что-ж, пожалуйста; в этой статье я попробую растолковать как получать в свое распоряжение окна, задачи, приложения и т. д. чтобы дальше делать с ними все, что угодно.
Обычными способами то есть средствами Visual Basic вы можете контролировать только те окна, которые создает ваша программа, что категорически нас не устраивает. Так что бы мы делали, если бы не имели доступа к бездонным залежам функций WinAPI ?! Но это я так... Короче, использовать мы будем естесственно функции API.
Что нам надо для того, чтобы начать делать что-то с окном? Ответ - надо знать его Handle, то есть свойство окна hWnd. Запомните раз и на всегда: ключ к управлению окном - его свойство hWnd! Зная его, вы сможете вытворять с окном любые вещи. Великолепно, как же нам его узнать? Да с помощью все тех же функций API, а конкретно, функции FindWindow. Эта функция возвращает Handle окна по его свойству Caption. Вот ее определение:
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal _ lpClassName As String, ByVal lpWindowName As String) As Long
Пример использования (выдает hWnd Internet Explorer'а):
hW = FindWindow(vbNullString, "about:blank - Microsoft Internet Explorer" & Chr(0))
Однако не торопитесь прыгать от радости и хлопать в ладоши :) Вы видите, какой здоровенный caption пришлось впихать в параметр lpWindowName?! А ведь это еще только начало. Caption'ы постоянно меняются и за тем же IE невозможно все время уследить. Значит, нам надо где-то достать текущий заголовок нужного окна или процесса. Прямо у вас под пальцами есть прелестный пример :) Нажмите волшебную комбинацию CAD (Ctrl-Alt-Del) ОДИН РАЗ! Что вывалилось? Правильно, Task Manager. Если вы сейчас просматриваете эту статью в IE у меня на сайте, то вы вполне можете прочитать в списке задач такую строку: www.chat.ru/~anti_loop/vbmisc/wnd.html - Microsoft Internet Explorer. Ну или что-то в этом роде. Ну прямо бери ее и пихай в функцию FindWindow. Вот и я так подумал...
После нескольких часов поисков в ИНете, я нашел процедурку, которая вываливает полный список всех активных задач в системе. Чуть-чуть пригладив ее, я привожу ее сейчас, а затем объясню, что здесь к чему:
Sub GetTaskList() 'Получаем hWnd, который будет первым в списке 'через него, мы сможем отыскать другие задачи CurrWnd = GetWindow(Me.hwnd, GW_HWNDFIRST) 'Пока возвращаемый hWnd имеет смысл, выполняем цикл Do While CurrWnd 0 'Получаем длину имени задания по CurrW nd Length = GetWindowTextLength(CurrWnd) 'Получить имя задачи из списка ListItem = Space(Length + 1) Length = GetWindowText(CurrWnd, ListItem, Length + 1) 'Если получили имя задачи, значит добавляем ее в список найденных If Length > 0 Then List1.AddItem ListItem End If 'Переходим к следующей задаче из списка CurrWnd = GetWindow(CurrWnd, GW_HWNDNEXT) DoEvents Loop End Sub
Прежде чем опробывать процедуру, вам надо добавить на форму элемент List под именем List1,объявить необъявленные здесь переменные, а также задать константы и написать declare следующих функций:
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long Private Declare Function GetWindowTextLength Lib "user32" Alias "GetWindowTextLengthA" (ByVal hwnd As Long) As Long Const GW_HWNDFIRST = 0 Const GW_HWNDNEXT = 2
После отработки функции, в элементе List вы получите список всех имеющихся в наличие активных задач. Предупреждаю сразу: то, что вы там увидите, кардинальным образом отличается от того, что вы видите по комбинации CAD. Во-первых, задач больше в 3-4 раза, во-вторых, там есть настолько экзотические, что я о них до того, как запустил эту программу и не подозревал, например всплыло какое-то "Напоминание", а также "Индикатор батарей", которые мой Minitower, спокойно стоящий себе под столом даже во сне-то не видел. Тем не менее, задача есть и вы можете на досуге поупражняться в "снятии" различных процессов, тем более, что мы этим сейчас и займемся.
Как лично вы будете использовать полученный список задач решать уже не мне. Я же покажу все на честном и открытом способе, то-есть на том List'е, который мы так успешно сформировали.
Итак, как же снять задачу так, чтобы та даже не пискнула? Функция PostMessage очень поможет нам в этом. Дайте ей hWnd жертвы, а также укажите что ей передать и она сделает это! Хотите передать "бомбу" - передавайте. Бомба представляет собой константу WM_CLOSE, получив которую в качестве сообщение, приложение тихо себе загнется.
Добавьте к предыдущему проекту на форму еще одну кнопку Command1, а также допишите следующий код:
Const WM_CLOSE = &H10 Private Sub Command1_Click() Dim hW as Long hW=FindWindow(vbNullString,List1.Text & Chr(0)) PostMessage hW,WM_QUIT,0,0 End Sub Private Sub Form_Load() GetTaskList End Sub
Обращаю ваше внимание, что это не полная программа, а только ее фрагменты. Не забудьте объявлять переменные!
Псле запуска, выберите интересующее вас задание из списка, и нажмите на кнопку. Задание должно исчезнуть даже не пискнув.
Итак, получив hWnd окна, вы теперь можете делать с ним все, что заблагорассудится, для этого надо только уметь использовать нужные функции API.