MCP

суббота, 16 ноября 2013 г.

Windows, делаем бекап самого дорогого

Как известно, люди делятся на тех, кто ещё не делает бекапы, и тех кто уже делает. Я предпочитаю использовать для дома следующую схему: не часто, но периодически делаю полный бекап системы на случай глобального факапа, а также, гораздо чаще сохраняю важные данные (и храню большее количество версий). Под важными данными я понимаю рабочие файлы, настройки программ, базы данных. И данные бекапы также используются для восстановления случайно удалённых или изменённых файлов без полного отката системы.

Сегодня же, я хочу рассказать, как сделать бекап самого ценного для винды, а именно реестра. Дело в том, что в настоящий момент, практически всё необходимое для жизни винды хранится именно там. Вплоть до того, что если у вас есть сохранённая копия реестра, то вы можете поставить новую систему, и подменить ей реестр. И она заработает как старая, со всеми предыдущими настройками! Конечно, есть некоторые оговорки: повалятся некоторые сервисы и программы, будут проблемы с драйверами. Но эти проблемы можно уже решить в рабочем порядке. Главное — на вас не будет смотреть голая система.

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

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

Где хранится реестр?

Он хранится в нескольких файлах. Во-первых, в папке C:\Windows\System32\config\ Там находятся файлы вида SYSTEM, SOFTWARE, SAM, COMPONENTS, DRIVERS. Это соответствующие ветки реестра. Например, SYSTEM — информация о сервисах и драйверах, SOFTWARE — установленные драйвера, SAM — данные о пользователях с внутренними идентификаторами и паролями (именно данная ветка обычно хорошо так меняется при установке, из-за чего система становится "особенно другой").
Также в этой папке находится системный профиль (профиль компьютера, который с точки зрения системы почти настоящий пользователь), и всякая другая мелочёвка.
При перезагрузке системы копия реестра сохраняется в папке RegBack. Я не очень представляю, когда данные из RegBack могут использоваться автоматически, но в случае проблем можно попытаться подменить файлы реестра из данной папки, чтобы восстановить работоспособность.

Также, в папке с профилем каждого пользователя (C:\Users\username\) находится файл ntuser.dat, являющийся реестром для данного пользователя.

Собственно, эти файлы мы и будем архивировать.

Как сделать архивную копию?

Какзалось бы, просто взять и скопировать. Но не всё так просто. Дело в том, что данные файлы заблокированы системой (справедливости ради, из RegBack можно достать файлы достаточно просто, но они будут не очень свежими в случае отсутствия перезагрузок, да и реестр пользователя не архивируется самостоятельно).

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

Мы же не будем искать аварийных путей, и займёмся использованием встроенных средств Windows, а именно Volume Shadow Copy, теневой копией.

При создании теневой копии диска, создаётся снимок всей файловой системы на заданный момент времени, с неизменяемыми файлами. Который можно использовать для чтения заблокированных файлов или использовать в качестве версии файлов на определённый момент времени (так работает System Restore в Windows, она делает примерно тоже самое, в определённых случаях).

Итак, что надо сделать:
  1. Сделать теневую копию диска
  2. Подмонтировать её симлинком для удобства работы
  3. Скопировать нужные файлы
  4. Удалить копию
Всё это можно сделать из консоли, используя стандартные утилиты, я для удобства написал всё это на Powershell.

Итак по пунктам (полный скрипт в конце поста):

Делаем теневую копию и монтируем её:
Function CreateShadow($disk)
{
    # e.g. c: -> c:\
    $disk = $disk[0] + ':\';

    $shadowObj = (gwmi -List Win32_ShadowCopy).Create($disk, "ClientAccessible")
    $currentShadow = gwmi Win32_ShadowCopy | ? { $_.ID -eq $shadowObj.ShadowID }
    $shadowID = $currentShadow.ID
    $name  = $currentShadow.DeviceObject + "\"
    $dummy = cmd /c "mklink /d .\$shadowID $name"
    Write-Host $dummy
    return $shadowID
}

В данном куске скрипта мы через WMI создаём теневую копию, получаем её идентификатор, и монтируем её в качестве симлинка в текущей папке (с названием как идентификатор теневой копии).
Используя данный скрипт уже можно вручную скопировать файлы. Ну или автоматически, примерно так:
Function PerformBackup($shadowPath, $bakRoot)
{
    if ($shadowPath -like '%\')
    {
        $shadowPath = $shadowPath.SubString(0, $shadowPath.Length - 1)
    }

    if ($bakPath -like '%\')
    {
        $bakPath = $bakPath.SubString(0, $bakPath.Length - 1)
    }

    $tmpFile = "$PWD\tmpFileList.txt"

    # if script was incorrectly finished
    if (Test-Path $tmpFile)
    {
        Remove-Item $tmpFile
    }
    Get-ChildItem -Recurse "$($shadowPath)\Windows\System32\Config" -Force -ErrorAction Continue | % { $_.FullName.Remove(0, $shadowPath.Length + 1) | Out-File -FilePath $tmpFile -Encoding ascii -Append }

    Get-ChildItem "$($shadowPath)\Users\" -Directory | % { Get-ChildItem -File -Force "$($_.FullName)\ntuser.*" -ErrorAction SilentlyContinue | % { $_.FullName.Remove(0, $shadowPath.Length + 1) | Out-File -FilePath $tmpFile -Encoding ascii -Append } }

    $archName = Get-Date -Format 'yyyyMMdd'

    # if file exists, using _1, _2, ...
    $archPath = $bakRoot + '\' + $archName;
    $iterator = 1;
    while (Test-Path "$archPath.7z")
    {
        $archPath = $bakRoot + '\' + $archName + '_' + $iterator;
        $iterator++;
    }

    $curPWD = $PWD
    cd $shadowPath
    cmd /c "$($curPWD)\7z.exe a -m0=LZMA2 $archPath.7z @$tmpFile"
    cd $curPWD
    Remove-Item $tmpFile
}

В данном скрипте мы собираем список файлов для архивирования во временный файл, и передаём его архиватору 7z, чтобы он уже самостоятельно проделал всю необходимую работу.

Дальше мы удаляем лишнюю копию:
Function DropShadow($shadowID)
{
    $dummy = cmd /c "rmdir .\$shadowID"
    Write-Host $dummy
    $currentShadow = gwmi Win32_ShadowCopy | ? { $_.ID -eq $shadowID }
    $currentShadow.Delete()
}

И лишние файлы:
Function RemoveOldBackups($bakPath)
{
    dir $bakPath | ? { $_.CreationTime -le $(Get-Date).AddDays(-30) } | Remove-Item
}

Скрипт целиком можно взять тут: backup-registry.7z (вместе с 7zip). В скрипте надо будет поправить необходимые пути и настроить его на периодическое выполнение, например, раз в день (что мелочиться-то?).

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

суббота, 2 ноября 2013 г.

Как добавить клиентам радости

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

Что включает в себя комплект поставки бюджетного телефона? Сам телефон, простенькая гарнитура и зарядник, несколько бумажек. Всё. У более дорогих обычно всё тоже самое, может лишь отличие в том, что качество гарнитуры и зарядника чуть выше (да и то не всегда).

Что сделала Digma:
  • Положила в комплект симпатичный рыжий бампер, т.е. телефон сразу начинает привлекать внимание, за счёт яркого позитивного цвета, и приносит радость владельцу
  • симпатичный USB-зарядник с подсветкой порта. Мелочь, но приятно искать в темноте под столом разъём
  • Тряпочка для протирки 
  • Защитная плёнка на экран
  • При этом транспортировочная плёнка — прозрачная, без надписей. Т.е. можно для начала тестировать телефон не снимая её, не пытаясь прочесть информацию за огромными ненужными буквами
Т.е. компания потратила чуть больше денег, но впечатление от неё у покупателя осталось весьма позитивным, что с учётом толпы псевдопроизводителей телефонов на российском рынке (Keneksi, Highscreen, Texet, Explay, Fly), возможно что-то стоит. 

PS: Может показаться что статья рекламная, но тут только личные впечатления, телефон был выбран по суммарным показателям, а дополнения в коробке оказались приятным бонусом.

суббота, 12 октября 2013 г.

Впечатления от Windows 8.1

До выхода Windows 8.1 всё меньше и меньше времени, и до того момента, как на людей польётся тонна информации об "уникальных" и "удобнейших" нововведениях, хочу поделиться тем, что я увидел в этой системе нового, приятного и удобного:

НИЧЕГО!

Да, именно так. Абсолютно ничего не изменилось. Да, сломался firewall от Comodo и упорно отказывался ставиться. Заменил на другой. Да, тема из 8 Preview сломалась, починил, отвалившуюся спячку почил, неприлично долгую загрузку-как нибудь починю, остальные мелочи несущественны.

И в общем-то всё, передо мной та же самая Windows 8. Конечно, можно посмотреть в свойства системы и узнать, но это очевидно, не за этим делаются изменения.

Можете спросить про кнопку Пуск, она ведь появилась. Да, появилась, но подобное убожество я писал самостоятельно в июле прошлого года. Да, у меня менее красиво вышло, но я ведь и не рассказываю всем окружающим с помпой про мегафичу? В общем, вместо стандартного убожества из Win8.1 и ничего из Win8, у меня сейчас стоит StartIsBack, и я чувствую себя человеком.

Также теперь есть изменения в Metro Modern UI поведении. Теперь приложения при установке не попадают на главный экран. Ну что же, прорвёмся, можно открыть все программы, и найти только что скачанную игрушку. Или не находить, всё равно они скучные.

Есть какие-то копеечные изменения в стандартных Modern'овых приложениях, но это вообще-то должен быть обычный процесс разработки, не привязанный к новой версии винды.

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

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

PS: Надо отдать должное, есть 2 действительно новые фичи в Windows Server 2012 R2, но это не клиентская система, кроме того, про них уже прожужжали все уши интересующимся.

суббота, 5 октября 2013 г.

Тема из Windows 8 Release Preview в Windows 8.1

Данный пост является продолжением прошлогоднего: Смена темы в Windows 8 на тему из Release Preview. Как результат, контекст обсуждения и общие моменты по установке смотрите в прошлом посте.

Итак, совсем скоро Microsoft выпустит Windows 8.1, в которой будет 100500 улучшений, всё будет быстрее, лучше и красивее (по секрету скажу, что ничего стоящего не замечено).

Но Microsoft не был бы Microsoft'ом, если бы в новой версии что-нибудь бы не поломал. В частности, замечательная тема из Windows 8 RP, теперь выглядит гораздо хуже. Вот вам картинка для понимания процесса:



Если у кого плохо с монитором или внимательностью, то проблема в том, что вокруг заголовка появился прямоугольник слегка другого оттенка чем основной заголовок. Что не фатально, но раздражает.

После некоторого времени, потраченного на иследования я выяснил, что тут сложились два фактора:

  • Изменился рендеринг текста, стал ещё более простым (те. убрано свечение текста там, где оно не включено специально)
  • Тема от Windows 8 RP имеет в качестве цвета заголовка практически (но не полностью!) прозрачную рамку.
Т.е. получается, что из-за того что текст заголовка окна рисуется на фоне заданного в настройках персонализации цвета, а сам заголовок тем же цветом, но из-за неполной прозрачности чуть-чуть другого оттенка. И получается такая фигня.

Собственно, проблема есть, пишу решения:
Решение №1 использовать программу  Aero Glass for Windows 8, которая сама добавит свечение вокруг букв и решит проблему. Единственная проблема: заставить программу работать по-человечески, та ещё задача. 

Решение №2 поправить тему, заменив почти прозрачность на полную прозрачность, а так как мы сломаем оригинальную тему, то сломать дополнительно проверку подписи для тем.
Вторая проблема решается давно и неплохо (ибо люди любят кастомные темы).

Самый простой способ сломать проверку через UxStyle. Это небольшой сервис, котороый не меняет системные файлы, а проводит изменения в памяти. Как результат, можно подклаывать любую тему с deviantART. Единственная проблема, пока нельзя скачать программу для 8.1, ибо она была выпущена, но из-за какого-то критичного бага убрана. Так что ждём фикса бага и обновления.

Ну а саму тему из Win 8 RP, я уже поправил, и выкладываю здесь, чтобы можно было забрать и пользоваться:

А подробности по установке в прошлом посте.


суббота, 21 сентября 2013 г.

Маленький хинт для программистов

Иногда бывают ситуации, когда вам нужно что-то удалённо сделать с вашим домашним компьютером. Часто что-то стандартное, а под рукой только телефон.

С одной стороны, можно начать писать могучее приложение под телефон, которое будет общаться с компьютером (для надёжности через внешний сервис), а с другой, можно поступить по-программистски: написать самому абсолютно точное и простое решение:

  1. Поднять web-сайт на своём компьютере (IIS или node.js — не важно, что больше нравится)
  2. Выставить его в интернет (Dynamic DNS в помощь)
  3. Ограничить к нему доступ авторизацией или сертификатами
  4. Для стандартных задач сделать url'ы, выполняющие определённые команды (лучше внешние батники, чтобы их лего можно было менять)
  5. Если нужно что-то сложное, то можно уже сделать интерфейс для выбора или ввода команды вручную
  6. Открыть с телефона в браузере полученную ссылку
В общем-то и всё. Ключевое, конечно, в данном случае - ограничить доступ, иначе вы открываете огромную дыру себе в компьютер, остальное дело 10 минут. Код, выполяющий определённую команду на ASP.NET выглядит просто и банально:

var runCmd = ConfigurationManager.AppSettings["runCmd"];
var processStartInfo = new ProcessStartInfo
{
FileName = runCmd,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false
};
var process = Process.Start(processStartInfo);
var output = process.StandardOutput.ReadToEnd();
var error = process.StandardError.ReadToEnd();
process.WaitForExit();
lbOutput.Text = output + error;

При этом я уверен, что есть уже готовые внешние решения и всякие saas'ы, но ведь самому написать интереснее? 

Зачем я написал эту банальность? А дело в том, что практика показывает, что иногда простые и очевидные решения в голову приходят в самый последний момент (даже для программистов), и человек гораздо вероятнее будет гуглить computer management for android, когда у него всего-лишь одна задча: выполнить ping www.ru и поглядеть на получившийся результат. 

воскресенье, 25 августа 2013 г.

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

Сейчас стало довольно модным использовать следующую модель версий продуктов (Google первый начал, остальные подхватили):
  • Developer — фактически транк, в котором тестируются новые фичи, стабильность не гарантируется и даже декларируется что её может не быть
  • Beta — фичи заморожены, идёт багфиксинг. Стабильность повышается со временем
  • Stable — полностью стабильная версия, обновления выходят только в случае обнаружения серьёзных проблем.
Кроме этого, обычно версионирование идёт по +1, т.е. Stable имеет версию n, Beta — n+1, Developer — n+2.
Когда Beta полностью оттестирована, она переходит в Stable и все версии щелкаются на единичку.

В общем, это всё всем понятно и известно. Но хочу поговорить о таком моменте: в любой момент времени свежесть версий должна идти в этом же порядке. Т.е. даже если сейчас идёт подготовка к релизу стабильной версии, в Beta и Developer должно быть по крайней мере тоже самое. Очевидно? Вроде бы да. Но я сейчас вижу перед глазами свежую Оперу, у которой на момент написания поста самая свежая версия это Beta (Next), а Developer, гораздо древнее. Т.е. явное нарушение концепции. Я не знаю точно, почему так происходит, но могу предположить, что у них одна команда, которая сегодня занимается исследованиями, а завтра в поте лица правит баги. Ну и чего они хотели добиться, внедряя технологию, которую сами же и не смогли осилить?

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

суббота, 17 августа 2013 г.

Методы и производительность динамического создания конструкторов

В .NET достаточно развитые средства рефлексии, и как результат этим активно пользуются. При этом вариантов и способов использования достаточно много. Эти способы отличаются в зависимости от того что надо: по типу действий (создать объект, вызвать его метод, получить/изменить значение поля), по информации об объекте (мы заранее знаем сигнатуру или не знаем), по типу доступа (публичные/приватные методы), по наличию параметров.

Я как-то делал доклад по этим технологиям на YaNA, но с тех пор прошло много времени, обнился Framework, и в моей жизни количество кода с рефлексией значительно возросло, поэтому я решил обновить знания, провести тесты и поделиться результатами.

Сегодня я рассмотрю достаточно простой способ: вызов конкструктора без параметров и с известными параметрами. Это достаточно часто встречающаяся задача, например, она может использоваться для создания плагинов и модулей. При этом мы знаем, что объект имеет определённый тип (отнаследован от интерфейса, например), так что в дальнейшем мы можем вызывать методы напрямую. Но тем не менее, мы не можем напрямую создать объект, т.к. у нас есть только информация о типе (Type), но изначально мы просто не можем написать new MyObject() — данные придут позднее.

Соответственно есть несколько путей решений:

Activator.CreateInstance

Самый простой и удобный метод создания объекта:
Activator.CreateInstance(myObjectType)

Также можно передать параметры для конструктора. Всё просто и очевидно.

ConstructorInfo.Invoke

"Классический рефлекшен". 
var constructorInfo = myObjectType.GetConstructor(new Type[0]);
constructorInfo.Invoke(new object[0]);

Т.е. мы получаем объект ConstructorInfo и через рефлексию создаём объект. В данном примере нет параметров, но их легко можно передать массивом объектов

Compiled Expression

Ещё один сравнительно новый вариант создания объекта, который заключается в построении Expression'а и дальнейшей компиляции его в делегат (анонимную функцию). Способ создания без параметров выглядит так:
var d = Expression.Lambda<Func<object>>(Expression.New(constructorInfo)).Compile();

В результате у нас будет делегат, возвращающий object (можно специфицировать точнее), который мы можем вызывать как обычный метод.

Если конструктор имеет параметры и нам точно известны, какие они должны быть, мы можем использовать подобный код:
var p1 = Expression.Parameter(typeof(int));
var p2 = Expression.Parameter(typeof(string));
var newExpression = Expression.New(constructorInfo, p1, p2);
var d = Expression.Lambda<Func<int, string, object>>(newExpression, true, p1, p2).Compile();

В данном случае, мы точно знаем, что у нас есть конкструктор с двумя параметрами типа int и string, поэтому мы генерируем конкретный код, вызывающий конкструктор с нужными параметрами. В отличие от предыдущих методов, данный слегка читерский, ибо тут мы точно указываем параметры, а мы их можем и не знать, соответственно у этого метода должна быть фора.

Compiled Expression with Any Parameters

Чтобы избавиться от этой форы и рассмотреть случаи, когда мы заранее не можем знать параметры, надо сгенерировать что-то общее. Логично будет рассмотреть случай, когда у нас есть делегат, принимающий массив параметров типа object, при этом данный делегат внутри сам проводит преобразования для корректного вызова. Код будет выглядеть примерно так:

var argsExpr = Expression.Parameter(typeof(object[]));
var constructorParams = constructorInfo.GetParameters()
.Select((p, i) => Expression.Convert(Expression.ArrayAccess(argsExpr, Expression.Constant(i)), p.ParameterType));
var newExpr = Expression.New(constructorInfo, constructorParams);
var d = Expression.Lambda<Func<object[], object>>(newExpr, true, argsExpr).Compile();

Т.е. мы передаём массив, в котором находятся аргументы, потом из этого массива достаём параметры для конструктора, конвертируем к нужному типу и вызываем конструктор.

Dynamic Method

Самый сложный метод, который заключается в использовании DynamicMethod и ручной генерации MSIL'а. Поскольку решение в отличие от остальных не совсем тривиальное, детальное описание реализации оставлю для следующей статьи (будет ссылка, когда статья будет написана). Мы его также как и Expression можем сделать специфичным, или обобщённым. У обобщённого основная идея та же, что и в предыдущем методе: мы генерируем делегат, принимающий массив object'ов, внутри приводим аргументы к нужному типу и вызываем конструктор. Только делаем всё это нативно, генерируя MSIL и компилируя его.

Результаты производительности

Мерять тут можно много чего. Но я остановился на следующих условиях:
  • Только публичные конкструкторы (приватные значительно дольше, а необходимость в их использовании весьма специфичная)
  • Время подготовки нужного объекта не замеряется. Подразумевается, что если уж есть цель оптимизации, то этим временем можно пренебречь. Хотя оно может и вносить ощутимые задержки на первый вызов. Если для вас это будет существенно, наверное стоит провести замеры на ваших условиях и железе.
  • Объекты очень простые но не совершенно пустые (сложность этих объектов может сильно повлиять на расстановку сил, нивелировав или максимально усилив различия между методами
  • Проверяется Debug и Release режим, чтобы выяснить ускорение, получаемое кодом от оптимизации
  • Конкретные цифры я не покажу, ибо это сильно зависит от железа. Только отношение
  • Также для сравнения добавлен прямой вызов конструктора 

Вызов конструктора без параметров

reflection constructor performance

По графику можно сделать простой вывод: если скорость не очень критична, используйте Activator, а если объектов нужно создавать очень много, то Expression. И да, Release режим в некоторых случаях рулит. Рефлекшен через ConstructorInfo самый медленный. Если у вас есть желание, можете использовать DynamicMethod, он самый быстрый.

Вызов конструктора с параметрами

Я взял конструктор с двумя параметрами int и string, чтобы было заметно влияние боксинга. Результаты получились следующие:
reflection constructor performance

Те же графики, но без активатора, чтобы был лучше виден масштаб:
reflection constructor performance


В данном случае Activator показал дичайшие тормоза, что очень удивительно, относительно предыдущего варианта. Обобщённый экспрешшен в 2 раза медленнее специализированного (хоть на графике это плохо видно) и в 4-6 раз медленнее прямого вызова (для сравнения скорости). Т.е. вывод тут такой — используйте скомпилированные экспрешшены, по-возможности с явными типами, если нет, то с обобщёнными, потери не очень сильные. При этом обобщённый DynamicMethod быстрее обобщённого Expresssion'а, но медленнее типизированного. Т.е. если хочется максимальной скорости, придётся относительно много писать, чтобы сделать максимально типизированный и производительный DynamicMethod.