вторник, 24 января 2012 г.

Путь к папке "Мои документы" содержит недопустимый символ.

Windows Installer ругался, по-видимому, из-за того, что когда-то профиль пользователя перенесли на другой диск. Вот тут сказано прошерстить реестр на предмет кривых путей до папки "Мои документы". Кривой путь нашелся в ветке реестра: HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders
Пришлось его там поправить, а потом перезапустить процесс explorer.exe

четверг, 19 января 2012 г.

Избавиться от предложения сжать сообщения Outlook Express

Попалась хорошая статья. Вкратце - обнулить параметр Compact Check Count реестра:
HKEY_CURRENT_USER\Identities\{GUID}\Software\Microsoft\Outlook Express\5.0\
(он инкрементируется при каждом закрытии почтовика и по достижении значения 100 начинает выдавать это сообщение)

вторник, 10 января 2012 г.

Как создать гаджет под Windows 7

На самом деле всё подробно расписано здесь. Я даже сподобился написать простенький таймер ^_^

Оказалось, что эти самые гаджеты в простейшем случае представляют из себя обычные приложения html. Это самое приложение зазиповано в архив (только расширение у этого архива - не .zip, а .gadget) В архиве должен быть файл gadget.xml примерно такого вида:
<?xml version="1.0" encoding="utf-8" ?>
<gadget>
<name>funTimer</name>
<namespace>CnRuFeed.Gadgets</namespace>
<version>0.0.0.1</version>
<author name="huh-muh">
<info url="huh-muh.blogspot.com" />
</author>
<copyright>&#169; 2012</copyright>
<description>Timer test</description>
<hosts>
<host name="sidebar">
<base type="HTML" apiVersion="1.0.0" src="funTimer.htm" />
<permissions>Full</permissions>
<platform minPlatformVersion="1.0" />
</host>
</hosts>
</gadget>

Соответственно, всё самое интересное заключено в файле funTimer.htm:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Fun timer</title>
</head>


<script type="text/javascript">
function resizeGadget()
{
if(System.Gadget.docked == true)
{
mainBody.style.width = 250;
mainBody.style.height = 80;
}
else
{
mainBody.style.width = 250;
mainBody.style.height = 80;
}
}

function settingsClosed(event)
{
if(event.closeAction == event.Action.commit)
{
loadSettings();
}
}

var initDate;

function loadSettings()
{
var caption = System.Gadget.Settings.read("caption");
captionLabel.innerHTML = (caption != "") ? caption : "(укажите название таймера)";

var initValue = System.Gadget.Settings.read("init");
initValue = initValue.replace(new RegExp(" ",'g'),".").replace(new RegExp(":",'g'),".");
var dateParts = initValue.split(".");
if (dateParts.length == 5)
initDate = new Date(dateParts[2], (dateParts[1] - 1), dateParts[0], dateParts[3], dateParts[4]);
else
if (dateParts.length == 3)
initDate = new Date(dateParts[2], (dateParts[1] - 1), dateParts[0]);
else
initDate = new Date();
timerLabel.innerHTML = "" + initDate;
}


var progressTimer;
function timerTick()
{
var currDate = new Date();
var dateDiff = Math.abs(currDate.getTime() - initDate.getTime()) / 1000;
var dd = Math.floor(dateDiff / (24*3600));
var hh = Math.floor( (dateDiff - dd*24*3600) / 3600 );
var mm = Math.floor( (dateDiff - dd*24*3600 - hh*3600) / 60 );
var ss = Math.floor( dateDiff - dd*24*3600 - hh*3600 - mm*60 );
timerLabel.innerHTML = "" + dd + "д " + hh + "ч " + mm + "м " + ss + "с";
progressTimer = setTimeout("timerTick()", 1000);
}


document.onreadystatechange = function()
{
if(document.readyState=="complete")
{
System.Gadget.settingsUI = "Settings.htm";
System.Gadget.onSettingsClosed = settingsClosed;
System.Gadget.onUndock = resizeGadget;
System.Gadget.onDock = resizeGadget;
loadSettings();
progressTimer = setTimeout("timerTick()", 1000);
}
}

</script>


<body id="mainBody">
<center><g:text id="captionLabel" width="100%" align="center">Loading...</g:text>
<br/>
<g:text id="timerLabel" width="100%" align="center">Loading...</g:text></center>
</body>

</html>

Для редактирования настроек программы будет использоваться файл Settings.htm:
<html xmlns="http://www.w3.org/1999/xhtml">

<script type="text/javascript">

document.onreadystatechange = function()
{
if(document.readyState=="complete")
{
mainBody.style.width = 300;
mainBody.style.height = 180;
captionBox.value = System.Gadget.Settings.read("caption");
timerBox.value = System.Gadget.Settings.read("init");
}
}

System.Gadget.onSettingsClosing = function(event)
{
if (event.closeAction == event.Action.commit)
{
System.Gadget.Settings.write("caption", captionBox.value);
System.Gadget.Settings.write("init", timerBox.value);
event.cancel = false;
}
}

</script>

<body id="mainBody">
Название таймера:
<br />
<input id="captionBox" type="text" maxlength="50" width="100%" />
<br />
Точка отсчета (дд.мм.гггг[ чч:мм]):
<br />
<input id="timerBox" type="text" maxlength="16" width="100%" />
</body>
</html>

вторник, 3 января 2012 г.

Взаимодействие PHP и MSSQL - новые веяния

Поразительный факт: подкупающие своей привычностью функции mssql_connect, mssql_query и т.п. канули в небытие начиная с версии 5.3.0, по крайней мере в варианте для windows.

Однако, как выяснилось, Microsoft в беде не оставит! Есть вполне работоспособный драйвер версии аж 2.0.1. Для него, правда, требуется нативный клиент SQL Server 2008, но его тоже легко можно скачать по ссылке вот с этой страницы (если, конечно, удастся нужную ссылку на этой странице отыскать ^_^).

Единственная тонкость: драйвер представляет из себя набор dll-ек "на все случаи жизни", и требуется выбрать из них нужную. Перебором получилось прописать в php.ini, закинув предварительно в папку расширений соответствующий файл:
extension=php_pdo_sqlsrv_53_ts_vc9.dll
что, видимо намекает на то, что PHP 5.3.1 компилировался при помощи Visual C++ 9...

В общем, минимально рабочий код оказался таким (лёгкая вариация примера из хелповника, поставляемого вместе с драйвером):
/* Указываем параметры поключения: имя сервера, логин-пароль и базу. */
$serverName = "myserver.mydomain.ru";
$connectionInfo = array( "UID"=>"uid",
"PWD"=>"pwd",
"Database"=>"AdventureWorks");

/* Подключаемся к серверу используя аутентификацию SQL Server. */
$conn = sqlsrv_connect( $serverName, $connectionInfo);
if( $conn === false )
{
echo "Unable to connect.";
die( print_r( sqlsrv_errors(), true));
}

/* Выполняем SQL-запрос. */
$tsql = "SELECT getdate()";
$stmt = sqlsrv_query( $conn, $tsql);
if( $stmt === false )
{
echo "Error in executing query.";
die( print_r( sqlsrv_errors(), true));
}

/* Получаем результаты запроса и выводим их на экран (казалось бы). */
// $row = sqlsrv_fetch_array($stmt);
// echo "Server date: ".$row[0];
// не проканало с ошибкой Object of class DateTime could not be converted to string

/* Получаем результаты запроса и выводим их на экран - а вот так проканало. */
if (sqlsrv_fetch($stmt);)
echo "Server date: ".sqlsrv_get_field( $stmt, 0, SQLSRV_PHPTYPE_STRING( SQLSRV_ENC_CHAR) );

/* Освобождаем ресурсы, выделенные для запроса и подключения. */
sqlsrv_free_stmt( $stmt);
sqlsrv_close( $conn);


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