Использование модуля Win32 Setupsup
Использование модуля Win32::Setupsup
Если упоминание о манипуляции окнами процесса, приведенное в конце предыдущего раздела, возбудило ваше любопытство, вам понравится наш следующий подход. На этот раз мы рассмотрим модуль Win32: :Setupsup Йена Хелберга (Jens Helberg). Он называется «Setup-sup», потому что первоначально был разработан для использования при установке программного обеспечения (при частом применении программы Setup.exe).
Некоторые инсталляторы можно запускать в так называемом «тихом режиме» для полной автоматизации установки. В этом режиме они не задают никаких вопросов и не просят нажимать кнопки «ОК>>, освобождая администратора от необходимости сидеть нянькой при инсталляторе. Если такой режим не поддерживается механизмом установки (а подобных случаев очень много), это сильно усложняет жизнь системного администратора. Win32: .Setupsup помогает справиться с такими трудностями. Он позволяет найти информацию о работающих процессах и работать с ними (либо завершить эти процессы, если вы того пожелаете).
Обратитесь к разделу «Информация о модулях из этой главы», чтобы узнать, как получить и установить модуль Win32: Используя Win32: :Setupsup, получить список выполняемых процессов очень просто. Вот слегка измененная версия примера, который можно увидеть в последнем разделе:
use Win32::Setupsup:
$machine = "";
получаем список на текущей ма^/не
Win32::Setupsup::GetProcessList
($machine, \@processlist. \@threaalist i a-die
"Ошибка получения списка процессов:
". Win32 :Serupsjjp: :GetLa;:: Ем^г(). ", '
pop(@processlist);
# удалить фальшивую запись, всегда
добавляемую к списку foreach Sprocesslist ((aprocesslist){
$pid = $processlist->{pid}:
$name = $processlist->{name};
write; }
format STDOUT_TOP =
Process ID Process Name
format STDOUT =
@<««« @««««««««««««««
$pid, $name
Завершение процессов тоже очень просто:
KillProcess($pid, Sexitvalule, Ssystemprocessflag) or die
"Невозможно завершить процесс:
".Win32: :Setupsup: ,GetLast.Error()
Два последних аргумента необязательны. Первый завершает процесс и, соответственно, устанавливает его код завершения (по умолчанию это 0). Второй аргумент позволяет вам завершать системные процессы (при условии, что у вас есть право Debug Prog rans).
Но все это очень скучно. Мы можем перейти на другой уровень манипулирования процессами, взаимодействуя с окнами, которые откры ты запущенным процессом. Чтобы вывести список окон, доступных на рабочем столе, применим:
Win32: :Setuosup: : EnuTiWiPdows( \awinduwiisi;) or die
Win32: :Setuosp: :GetUstError( @windowlist
теперь содержит список дескрипторов окон, которые выглядят как обычные числа, если их напечатать. Чтобы узнать больше о каждом окне, можно использовать несколько различных функций. Например, чтобы прочитать заголовки всех окон, воспользуемся функцией GetWindowText():
use Win32::Setupsup;
Win32::Setupsup::EnumWindOws(\@windowlist) or die
"Ошибка получения списка процессов:
".Win32::Setupsup::GetLastError()."\n"
foreach Swhandle (@windowlist){
if (Win32::Setupsup::GetWindowText($whandle,\$text)){
print "$whandle: $text","\n"; }
else { warn
"Невозможно получить текст для Swhandle" .
Win32::Setupsup::Get LastError()."\n"; >
}
Вот небольшой отрывок получаемых данных:
66130: chapter02 - Microsoft Word
66184: Style
194905150:
66634: setupsup - WordPad
65716: Fuel
328754: DDE Server Window
66652:
66646:
66632: OleMainThreadWndName
Как видите, у некоторых окон есть заголовки, а у некоторых их нет. Внимательные читатели могли заметить в этом отрывке еще кое-что любопытное. Окно 66130 принадлежит сеансу Microsoft Word, запущенному в настоящий момент (в нем набиралась эта глава). Окно 66184 смутно напоминает название еще одного окна, связанного с Microsoft Word. Как мы можем узнать, действительно ли эти окна взаимосвязаны?
В Win32: :Setupsup также есть функция EnumChildWindows(), которая позволяет вывести список дочерних окон для любого окна. Используем ее для вывода иерархии текущего окна:
use Win32::Setupsup:
# получаем список
Win32: : Setupsup: : FnunWindows(^.®windowlist) or
die "Ошибка получения процессов:
".Win32: 'Setiipsup: : Gf;: LastError(). "\n":
превращаем список дескрипторов окон в хэш
ЗАМЕЧАНИЕ: в результате преобразования
элементами хэиа становятся обычные числа,
а не дескрипторы окон. Некоторые функции,
например GetWindowProperties
(которую мы скоро рассмотрим),
не могут использовать эти преобразованные v/c.ra.
Будьте осторожны,
for (is>windowlist){$windowlist{$_}++;
}
и проверяем наличие дочерних окон для каждого окна
foreach $whandle (@windowlist){
(Win32: :Setupsup: : EnumChildWindows($whandIe. \ichildren)){
сохраняем отсортированный список дочерних окон
$children{$whandle} = [sort {$a <=>$b} ©children]:
tt удаляем все дочерние окна из главного хзша,
в результате всех итераций %windowlist будет
содержать только родительские окна без
соответствующих дочерних
foreach $child (@children){
delete $wir.dewlist{$child};
}
}
}
обходим в цикле список родительских окон
и тех окон, у которых нет дочерних,
и рекурсивно печатаем дескриптор каждого
окна и его дочерние окна (если они есть)
foreach my $window (sort {$a <=> $b} keys %windowlist){ &printfamily($window,0);
}
выводим дескриптор заданного окна и его дочерних окон
(рекурсивно) sub printfamily {
начальное окно, насколько глубоко мы ушли по дереву?
my($startwindow,Sievel) = @_;
выводим дескриптор окна с соответствующим отступом
print((" " х Slevel)."$startwindow\n").
return unless (exists $children{$startwindow>):
к дочерних окон не дело сделано
противном случае мы должны
roreach Schildwir.dow (@{
}
Есть еще одна функция, о которой надо сказать, перед тем как двигаться дальше: GetWindowPropertiesO. Функция GetWindowPropertiesO вмещает в себя остальные свойства окон. Например, используя GetWindowPropertiesO, можно получить идентификатор процесса, создавшего конкретное окно. Это разумно совместить с некоторыми из только что рассмотренных возможностей модуля Win32: : IProc.
В документации к модулю Win32: :Setupsup есть список свойств, и к ним можно обратиться. Используем одно из них для написания очень простой программы, которая выведет размеры окна на экране. GetWindowPropertiesO принимает три аргумента: дескриптор окна, ссылку на массив, содержащий имена запрашиваемых свойств, и ссылку на хэш, где будут храниться результаты запроса. Вот какой код мы применим для этого:
Win32: :Setupsup: :GetW:
ndowProperties($ARGV[0], ["reef, "id"], \%info);
print "\t" . $info{rect}{top} . "\n";
print $info{rect}{left} . " -" . $ARGV[0] .
"- " . $info{rect}{right} . "\n";
print "\t" , $info{rect}{bottom} . "\n";
Вывод получается несколько вычурным. Вот как выглядит вывод размеров (координат верхнего, левого, правого и нижнего края) окна с дескриптором 66180:
154
272 -66180- 903
595
GetWindowPropertiesO возвращает специальную структуру данных только для одного свойства rect. Все остальные будут представлены в хэше в виде обычных ключей и значений. Если вы не уверены в свойствах, возвращаемых Perl для конкретного окна, воспользуйтесь утилитой windowse, которую можно найти на http://greatis.virtualave.net/ products.htm.
Разве теперь, когда мы знаем, как определить различные свойства окон, не было бы логично научиться изменять некоторые из этих свойств? Например, было бы полезно изменять заголовок окна. С такими возможностями мы могли бы создавать сценарии, использующие заголовок окна в качестве индикатора состояния: "Prestidigitation In Progress ... 32% complete" Чтобы внести эти изменения, достаточно одного вызова функции:
Win32::Setupsup:SetWindow
Text($handle,Stext);
Свойство rect тоже можно установить таким образом. Следующие строки заставляют указанное окно переместиться в заданную позицию экрана:
use Win32::Setupsup;
$info{rect}{left} = 0;
$info{rect}{nght} = 600;
$info{rect}{top} = 10;
$info{rect}{bottom}= 500;
Win32::Setupsup::SetWindow
Properties($ARGV[0], \%info);
Самую впечатляющую функцию я приберег напоследок. При помощи SendKeysO можно послать произвольные комбинации клавиш любому окну на рабочем столе. Например:
use Win32::Setupsup;
$texttosend = "\\DN\\Low in trie gums";
Win32::Setupsup::SendKeys($ARGV[0],Stexttosend, '',0);
В результате, в указанное окно будет послан текст, предваряемый символом «курсор вниз». Аргументы SendKeysO очень просты: дескриптор окна, посылаемый текст, флаг, определяющий, нужно ли активизировать окно для каждого сочетания клавиш, и необязательный интервал между сочетаниями клавиш. Коды специальных символов, таких как «курсор вниз», окружаются обратными слэшами. Список допустимых кодов можно найти в документации к модулю.
С помощью этого модуля мы попадаем на иной уровень управления процессами. Теперь мы можем удаленно управлять приложениями (и частями операционной системы), не взаимодействуя явно с этими приложениями. Нам не нужна поддержка командной строки или специальных API. У нас есть возможность писать сценарии для GUI, что очень полезно во множестве задач системного администрирования.