Perl для системного администрирования

       

Использование модуля 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, что очень полезно во множестве задач системного администрирования.



Содержание раздела