понедельник, 13 июля 2009 г.

работаем с Windows Registry

Для восстановления веток реестра в Windows существует функция RegRestoreKey. До Windows Vista ей можно было свободно пользоваться для восстановления, например, настроек по умолчанию программы. В Windows Vista это стало требовать поднятия уровня процесса(elevation) с появлением назойливого диалога UAC. Конечно, понятно, что большинство читающих эту статью живут с отключенным UAC, но подавляющее большинство обычных пользователей(по данным Microsoft) UAC не выключают. У RegRestoreKey есть ещё один недостаток — она работает с файлами в бинарном формате, который отличается для каждой новой версии ОС.

Однако, существует в Windows и программа reg.exe, которая имеет встроенный парсер REG-фалов. Да, именно тех, которые описывают ключи в обычном тектовом формате. Команды import и export этой утилиты не требуют каких либо повышенных прав. Конечно, здесь речь идет о разделах HKCU. Почему эти функции не выделили в отдельный API остается загадкой.

Ниже приведен пример использования этой утилиты в программе:
// Получаем указатель на REG файл прилинковынный в ресурсы
HRSRC hRsrc = ::FindResource( NULL, MAKEINTRESOURCE(IDR_DEFSETTINGS), L"REG" ); // IDR_DEFSETTINGS - идентификатор ресурса с файлом. Может быть другим.
HGLOBAL hGlobal = ::LoadResource( NULL, hRsrc );
LPVOID lpReg = ::LockResource( hGlobal );

// Сохраняем во временный файл
wchar_t path_buf[MAX_PATH];
SHGetFolderPath( NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT, &path_buf[0] );
const wstring temp_filename = path_buf+L"\\temp_reg.reg";
ofstream os( temp_filename.c_str(), ios_base::binary );
os.write( static_cast<char*>(lpReg), ::SizeofResource( NULL, hRsrc ) );
os.close();

// Готовим параметры reg.exe.
wstring params( L"import \"");
params += temp_filename;
params += L"\""; // Путь к файлу должен быть в кавычках на случай пробелов

// Запускаем reg.exe
SHELLEXECUTEINFO se = {0};
se.cbSize = sizeof SHELLEXECUTEINFO;
se.fMask = SEE_MASK_NOCLOSEPROCESS|SEE_MASK_UNICODE;
se.hwnd = GetSafeHwnd();
se.lpFile = L"reg.exe"; // находится в system32, поэтому путь указывать необязательно
se.lpParameters = params.c_str();
se.nShow = SW_HIDE; // Смотреть на консольку пользователю ни к чему
if ( ShellExecuteEx( &se ) ) {
WaitForSingleObject( se.hProcess, INFINITE ); // хотя тут и написано INFINITE, но в реальной жизни лучше указать таймаут
CloseHandle( se.hProcess );
} else {
// Ошибка запуска. Как-то обрабатываем эту ситуацию.
}

// Удаляем временный файл
_wremove( temp_filename.c_str() );

вторник, 7 июля 2009 г.

Windows Intenals 5-th


Наконец-то вышло пятое издание Windows Internals и уже почтальон везет его ко мне :) Книга потолстела на 250 страниц, как пишет Марк Руссинович(Mark Russinovich) у себя в блоге. Были добавлены главы посвященные Hyper-V, Kernel Transaction Manager, Code Integrity, Thread Pools, Mandatory Integrity Controls, Windows Driver Framework и ещё немного об утилитах SysInternals. До конца года обещается 6-е издание, которое пополнеет ещё на 100 страниц и будет содержать информацию специфичную для Windows 7 и Windows Server 2008 R2.

четверг, 2 июля 2009 г.

hex to long

Как думаете, чем конвертировать шестнадцатиричную строку в 32-х битное знаковое целое? Порывшись в стандарной библиотеке можно найти функцию strtol. И все работает обычно... до тех пор пока входные данные беззнаковые. Попробуйте конвертировать -1 (0xFFFFFFFF) и ничего не выйдет. strtol решит, что было переполнение и вернет MAX_LONG. Чтобы обойти эту особенность, следует использовать функцию strtoul. Она конвертит строку в беззнаковое целое, а уж потом можно его приравнять к long и старший бит укажет знак.

Пример:
#include <cstdlib>
#include <iostream>
using namespace std;

int main() {
string s = "FFFFFFFF";
char * p;
long n = strtoul( s.c_str(), &p, 16 );
// overflow when using long n = strtol( s.c_str(), &p, 16 );
if ( * p != 0 ) {
cout << "not a number" << endl;
} else {
cout << n << endl; // prints -1
}
}