...
...

Практическое руководство по компьютерным приколам 11

"...даже лаконичный, суровый и сухой код способен нести людям смех и веселье…"
(одно из писем на мой адрес)

Доброго дня всем любителям веселых компьютерных шуток и розыгрышей, описания которых раз за разом выходят в этих статьях. К сожалению, данный выпуск выйдет уже после 23 февраля, но еще до 8 марта, поэтому я даже не знаю, кого поздравлять: программистов или программисток:). На всякий пожарный поздравляю всех: и читателей, и читательниц (да-да, оказывается, есть и такие, что не может не радовать). Сегодняшний выпуск будет посвящен не только созданию новых шуток, но также модификации старых розыгрышей, которые были предложены читателями. Так что запускаем Borland Delphi и готовимся к сражениям на виртуальном поле боя.

1. Дрожь земли
Ну, положим, про землю я приврал чуток, а вот дрожь рабочего стола можно устроить очень даже легко. Представляете себе удивление человека, созерцающего дикую вибрацию на мониторе. А вы тем временем небрежно достаете из кармана мобильный телефон и говорите: "Трубку себе обновил. Поставил такую антенну, что небольшие помехи во время поиска сети наблюдаются". Дело остается за малым... За помехами:). Именно ими мы сейчас и займемся. Вешаем на форму два компонента: Image и Timer. Теперь дважды кликаем на форме и в обработчике FormCreate пишем:

procedure TForm1.FormCreate(Sender: TObject);
var Canvas:TCanvas;
begin
//инициализируем переменную Canvas
Canvas:=TCanvas.Create;
//получаем контекст экрана (все, что находится на мониторе)
Canvas.Handle:=GetDC(0);
//устанавливаем координаты и размер формы на весь экран
Form1.Left :=0;
Form1.Top :=0;
Form1.Width:=Screen.Width;
Form1.Height:=Screen.Height;
//устанавливаем координаты и размер Image'а на весь экран
Image1.Left:=0;
Image1.Top:=0;
Image1.Width:= Screen.Width
Image1.Height:= Screen.Height;
//копируем содержимое Canvas на Image, чтобы он содержал содержимое экрана.
Image1.Canvas.CopyRect(Image1.Canvas.ClipRect,Canvas, Canvas.ClipRect);
end;

Для тех, кто еще ничего не понял, сообщаю, что мы растянули форму и Image, содержащийся на ней, на весь экран и затем поместили в Image
содержимое экрана. Т.е. форма с Image'ем закрывает собой настоящий рабочий стол, хотя ничем от него не отличается. Теперь выставляем на таймере какое-нибудь маленькое значение (10, например) и пишем в его обработчике:

procedure TForm1.Timer1Timer(Sender: TObject);
var
Top,Left:Integer;
begin
//выбор случайного числа из диапазона (-5;5)
Top:=RandomRange(-5,5);
Left:=RandomRange(-5,5);
//изменение координат формы с Imagе'ем
Form1.Top:=Top;
Form1.Left:=Left;
end;

Для корректной работы функции RandomRange необходимо включить в раздел Uses нашей программы дополнительный модуль Math. Либо при отсутствии модуля или банальной лени можно заменить строки
Top:=RandomRange(-5,5);
Left:=RandomRange(-5,5);
на равносильные им
Top:=-5 + random(10);
Left:=-5+Random(10);

И вы мне после этого будете говорить, что ваш монитор не страдает нервным тиком? Как говорится, было бы желание, а болезнь сама найдется. С дрожью покончили, поехали дальше.

2. Не дай себя в обиду
Воистину после прошлой статьи тема "Спрятать процесс в Windows 2000/XP" получила такое бешеное развитие, что мне уже самому страшно ее
затрагивать. Куча народу предложила различные варианты (90% из которых, к сожалению, нереализуемы либо реализуемы только в Windows 98). Я уже думал начать описывать вариант с запретом на убиение процесса, весьма смутно представляя, как своими словами рассказывать про SecurityDecriptor, но тут в мой ящик пришло совершенно гениальное письмо от 15-летней девочки (если, конечно, верить подписи), где была замечательная фраза, до которой не додумался никто: "А давайте при открытии диспетчера задач наша программа его сразу закроет". Я прослезился и тут же вспомнил
замечательное: "А давайте подождем, пока басурмане сами от голода сдохнут... ну, или хотя бы ослабнут" (кто еще не посмотрел "Алеша Попович и Тугарин змей" — марш смотреть немедленно. Потом дочитаете). Действительно, Task Manager — такое же окно, как и все остальные. А следовательно, сообщения он принимает от любого приложения исправно. А если послать ему WM_DESTROY, то ничего, кроме как "сдохнуть", ему не останется. На форму вешается таймер с интервалом 10-100 (как сами захотите) и в его обработчике пишется:

procedure TForm1.Timer1Timer(Sender: TObject);
var W:HWND;
begin
//находим окно с заголовком 'Windows Task Manager' (для английской XP)
W:=FindWindow(nil,'Windows Task Manager');
//если нашли
if (W<> 0) then begin
//посылаем ему сообщение на уничтожение
SendMessage(W,wm_destroy,0,0);
end;
end;

Да, наверное, именно в такие моменты испытываешь гордость за наш народ. Народ, который всегда знает, как из ничего сделать кое-что и как в безвыходной ситуации использовать все возможности по максимуму. Достаточно навесить такой таймер на любую вашу программу, и пользователю придется здорово попотеть, убирая ее из памяти. Но это, конечно же, если у него нет программ сторонних производителей.

3. Умное выключение
Хм, мы все ближе подходим к теме искусственного интеллекта для Windows. Главное — чтобы для такого благого дела нам хватило нашего
собственного:). Сразу после выхода в свет статьи о прощальном окошке перед выключением системы пришло довольно много пожеланий выбрасывать в этом окошке надпись в зависимости от текущего времени суток. Идея абсолютно верна, да и как работать с системным временем, я еще не писал. Сейчас исправим это упущение. Для начала в обработчике FormCreate скроем форму от посторонних глаз:

procedure TForm1.FormCreate(Sender: TObject);
begin
Application.ShowMainForm:=false;
end;

Теперь поднимемся выше и добавим в класс нашей формы после директивы private процедуру WMEndSession, чтобы класс приобрел следующий вид:
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION;
{ Private declarations }
public
{ Public declarations }
end;

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

function between(count,p1,p2:integer):boolean;
begin
if (count> =p1) and (count<=p2) then between:=true
else between:=false;
end;

А сейчас можно записать модифицированную процедуру WMEndSession:

procedure TForm1.WMEndSession(var Msg: TWMEndSession);
var
//переменная для работы с временем;
DateTime:TDateTime;
h,m,sec,msec:word;
begin
//если пришло сообщение о выключении системы
f Msg.EndSession = True then
//получаем системное время
DateTime:=Time;
//декодирует время, разбивая его на часы, минуты, секунды и миллисекунды
DecodeTime(DateTime,h,m,sec,msec);
//в зависимости от часов выводит сообщение
if (between(h,6,9)) then
messagebox(0,'Еще утро, а ты уже спать ?','Microsoft Windows XP',MB_OK);
if (between(h,10,12)) then
messagebox(0,'Еще же только полдень. Мне еще работать и работать','Microsoft Windows XP',MB_OK);
if (between(h,13,18)) then
messagebox(0,'Выключаешь, а еще самое время обедать','Microsoft Windows XP',MB_OK);
if (between(h,19,23)) then
messagebox(0,'Вот-вот. Пора спать. Калыханка только что прошла','Microsoft Windows XP',MB_OK);
if (between(h,0,5))then
messagebox(0,'А? Что? Я уже сплю давно','Microsoft Windows XP',MB_OK);
inherited;
end;

Ну вот. Это уже больше похоже на правду. Вы можете создавать любое количество диапазонов и сообщений самостоятельно, так что каждый час будет не похож на предыдущий:).

На этом пока все. Пишите письма мелким почерком, ждите нового выпуска КГ!

Паша Либер aka Fireangel, Fireangel@tut.by

© Компьютерная газета

полезные ссылки
Аренда ноутбуков