Среда, 15.05.2024
Королевство Delphi
Главное меню
Статьи
Наш опрос
Нужен форум на сайте?
Всего ответов: 90
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Главная » Статьи » Система » Разное

Способы сохранения и загрузки параметров программного обеспечения

В этой статье речь пойдет о способах сохранения и загрузки параметров программного обеспечения. Из своего личного опыта я могу твердо сказать, что это не так просто, как кажется многим. Как Вы уже успели заметить, крупные программные продукты используют для хранения своих параметров исключительно системный реестр. Напротив, разработчики программного обеспечения, относящие его к Freeware, предпочитают  конфигурационные файлы с расширением "INI” (далее "ini-файлы”). Почему же дело обстоит именно так? Мы рассмотрим два этих способа более подробно, а так же поговорим о внедрении определенных средств защиты  ini-файлов.

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

Для работы с системным реестром в Borland Delphi предусмотрен модуль Registry, который содержит класс TRegistry.

Uses Registry;
…
…
Var
 R: TRegistry;
Begin
 R := Tregistry.Create;
 …
 …
 …
 R.Free;
End;

Рассмотрим принципы сохранения и загрузки данных, используя системный реестр, на небольшом примере, который будет содержать две процедуры GetCaption и SaveCaption.

procedure GetCaption;
var
 R: TRegistry;
begin
 R := TRegistry.Create;
 R.RootKey := HKEY_LOCAL_MACHINE;
 {
 Открытие ключа. Параметр True означает,
 что при отсутствии ключа он автоматически создается
 }
 R.OpenKey('Software\Test', True)
 {Записываем параметр}
 R.WriteString('FormCaption', Form1.Caption);
 {Закрываем ключ}
 R.CloseKey;
 R.Free;
end;

procedure SaveCaption;
var
 R: TRegistry;
begin
 R := TRegistry.Create;
 R.RootKey := HKEY_LOCAL_MACHINE;
 R.OpenKey('Software\Test', True)
 {
 Устанавливаем заголовок формы, используя
 ранее сохраненную строчку
 }
 Form1.Caption := R.ReadString('FormCaption');
 R.CloseKey;
 R.Free;
end;

Процедура SaveCaption сохраняет заголовок формы, а процедура GetCaption загружает из реестра ранее сохраненную строку, и устанавливает ее в качестве заголовка.

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

Стоит сказать еще о двух процедурах модуля Registry: GetKeyNames и GetValueNames. Они позволяют сканировать реестр, как обычные каталоги. При открытии ключа вы указываете начальный путь поиска, а далее процедура GetKeyNames создает список типа TStrings и записывает в него имена всех найденных ключей, а процедура GetValueNames составляет список из имен параметров, находящихся в заданном ключе.

До появления 32-х разрядных операционных систем, для хранения параметров программы использовали исключительно конфигурационные файлы с расширением "INI” (далее ini-файлы). Но вскоре, ini-файлы были забыты, и на смену им пришел системный реестр. Но до сих пор встречаются программы, которые активно используют такой способ хранения параметров. В чем же его преимущества? Прежде всего в стабильности. В отличие от системного реестра, при сбоях в операционной системе с ini-файлом ничего не случается, если только он не находится в системном каталоге. Стоит помнить, что ini-файл должен находиться в одном каталоге с программой. Кроме стабильности, важным преимуществом ini-файлов является мобильность программного кода, в чем вы можете убедиться, посмотрев пример, приведенный ниже. Что же касается недостатков, то это простота удаления. Ini-файл – это обычный файл, который можно случайно удалить.

Для работы с ini-файлами в Borland Delphi предусмотрен модуль IniFiles.

Uses IniFiles;
…
…
…
Var
 IniFile: TiniFile;
Begin
 IniFile := TiniFile.Create(‘имя файла’);
 …
 …
 …
 IniFile.Free;
End;

Принципы работы Ini-файлов и системного реестра схожи между собой. Изменим предыдущую программу, которая сохраняла и изменяла заголовок формы, используя системный реестр.

procedure SaveCaption;
var
 IniFile: TIniFile;
begin
 IniFile := TIniFile.Create(ExtractFilePath(Application.Exename) + 'Test.ini');
 IniFile.WriteString('MainOptions', 'FormCaption', Form1.Caption);
 IniFile.Free;
end;

procedure GetCaption;
var
 IniFile: TIniFile;
begin
 IniFile := TIniFile.Create(ExtractFilePath(Application.Exename) + 'Test.ini');
 Form1.Caption := IniFile.ReadString('MainOptions', 'FormCaption', '');
 IniFile.Free;
end;

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

А теперь, поговорим о средствах защиты. Операционная система предоставляет возможность закрытия доступа к определенным файлам. Но, к сожалению, закрытие доступа длится только во время работы программы. После того, как программа будет закрыта, доступ будет полностью открыт. Например, можно ограничить доступ к ini-файлу. Для реализации данной возможности, среди множества функций WinAPI существует функция OpenFile. Давайте попробуем написать программу, которая закрывала бы доступ к ini-файлу.

 var
 Form1: TForm1;
 hIniLockedFile: Cardinal;
 OfStruct : _OfStruct;
implementation
 {$R *.dfm}
procedure SaveCaption;
var
 IniFile: TIniFile;
begin
 {Отключаем защиту файла}
 CloseHandle(hIniLockedFile);
 {Резервное время для оключения}
 Sleep(1000);
 IniFile := TIniFile.Create(ExtractFilePath(Application.Exename) + 'Test.ini');
 IniFile.WriteString('MainOptions', 'FormCaption', Form1.Caption);
 IniFile.Free;
 {После сохранения, заново ставим защиту}
 hIniLockedFile := OpenFile(PChar(ExtractFileDir(Application.Exename) + 'Test.ini'), OfStruct, OF_Share_Exclusive);
end;

procedure GetCaption;
var
 IniFile: TIniFile;
begin
 IniFile := TIniFile.Create(ExtractFilePath(Application.Exename) + 'Test.ini');
 Form1.Caption := IniFile.ReadString('MainOptions', 'FormCaption', '');
 IniFile.Free;
 {Устанавливаем защиту}
 hIniLockedFile := OpenFile(PChar(ExtractFileDir(Application.Exename) + 'Test.ini'), OfStruct, OF_Share_Exclusive);
end;

При запуске программы, из ini-файла считывается информация, после чего он блокируется для последующих операций работы с ним: копирование, удаление, редактирование и т.д. При сохранении параметров, защита временно снимается, а вскоре заново возобновляется.


(Рис. 1) Ограничение доступа к файлу Test.ini

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

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

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

Я написал две простейшие процедуры кодирования и декодирования текста. На их примере мы и рассмотрим работу нашей программы.

 var
 Form1: TForm1;
 hIniLockedFile: Cardinal;
 OfStruct : _OfStruct;

const
 csCryptFirst = 20;
 csCryptSecond = 230;
 csCryptHeader = 'Crypted';

type
 ECryptError = class(Exception);

implementation

{$R *.dfm}

function CryptString(Str:String):String;
var
 I : Integer;
 Clen : Integer;
begin
 clen := Length(csCryptHeader);
 SetLength(Result, Length(Str)+clen);
 Move(csCryptHeader[1], Result[1], clen);
 For i := 1 to Length(Str) do
 begin
 if i mod 2 = 0 then
 Result[i+clen] := Chr(Ord(Str[i]) xor csCryptFirst)
 else
 Result[i+clen] := Chr(Ord(Str[i]) xor csCryptSecond);
 end;
end;

function UnCryptString(Str:String):String;
var
 I : Integer;
 Clen : Integer;
begin
 Clen := Length(csCryptHeader);
 SetLength(Result, Length(Str)-Clen);
 If Copy(Str, 1, clen) <> csCryptHeader then
 raise ECryptError.Create('Файл поврежден!');
 For i := 1 to Length(Str)-clen do
 begin
 if (i) mod 2 = 0 then
 Result[i] := Chr(Ord(Str[i+clen]) xor csCryptFirst)
 else
 Result[i] := Chr(Ord(Str[i+clen]) xor csCryptSecond);
 end;
end;

Procedure CryptIniFile;
var
 S: TStringList;
 I: Integer;
begin
 S := TStringList.Create;
 S.LoadFromFile(ExtractFileDir(Application.Exename) + 'Test.ini');
 For I := 0 to S.Count - 1 do
 S.Strings[I] := CryptString(S.Strings[I]);
 S.SaveToFile(ExtractFileDir(Application.Exename) + 'Test.ini');
end;

Procedure DecryptIniFile;
var
 S: TStringList;
 I: Integer;
begin
 if not FileExists(ExtractFileDir(Application.Exename) + 'Test.ini') then Exit;
 S := TStringList.Create;
 S.LoadFromFile(ExtractFileDir(Application.Exename) + 'Test.ini');
 For I := 0 to S.Count - 1 do
 S.Strings[I] := UnCryptString(S.Strings[I]);
 S.SaveToFile(ExtractFileDir(Application.Exename) + 'Test.ini');
end;

procedure SaveCaption;
var
 IniFile: TIniFile;
begin
 {Отключаем защиту файла}
 CloseHandle(hIniLockedFile);
 {Резервное время для оключения}
 Sleep(1000);
 IniFile := TIniFile.Create(ExtractFilePath(Application.Exename) + 'Test.ini');
 IniFile.WriteString('MainOptions', 'FormCaption', Form1.Caption);
 IniFile.Free;
 {После сохранения, заново ставим защиту}
 hIniLockedFile := OpenFile(PChar(ExtractFileDir(Application.Exename) + 'Test.ini'), OfStruct, OF_Share_Exclusive);
end;

procedure GetCaption;
var
 IniFile: TIniFile;
begin
 {Расширофка конфигурационного файла}
 DeCryptInIFile;
 Sleep(1000);
 IniFile := TIniFile.Create(ExtractFilePath(Application.Exename) + 'Test.ini');
 Form1.Caption := IniFile.ReadString('MainOptions', 'FormCaption', '');
 IniFile.Free;
 {Устанавливаем защиту}
 hIniLockedFile := OpenFile(PChar(ExtractFileDir(Application.Exename) + 'Test.ini'), OfStruct, OF_Share_Exclusive);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 GetCaption;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 SaveCaption;
 CloseHandle(hIniLockedFile);
 CryptInIFile;
end;


(Рис. 2) Файл «Test.ini» в зашифрованном виде

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

Следует сказать пару слов о самих алгоритмах кодирования  и декодирования текста. В качестве признака того, что файл уже был закодирован, используется обыкновенная текстовая строка «Crypted», которой соответствует константа csCryptHeader. Она следует вначале каждой зашифрованной строчки. Перед шифрованием, определяется длина строки csCryptHeader, после чего увеличивается длина будущей строки, которая равна длине шифруемой строки и длине строки csCryptHeader. Далее, простым перебором, происходит замена каждого символа шифруемой строки. Это осуществляется с помощью функции Chr, которая по сгенерированному программой числу возвращает соответствующий символ. При замене символов, следует учитывать определенные параметры, которые определяет логическая операция. В нашем примере, в зависимости от того, делится ли порядковый номер строки на два без остатка, используются разные параметры, что усложняет последующую дешифровку текста.

При дешифровки текста определяется его реальная длина, что достигается вычитанием из длины дешифруемой строки длины строки csCryptHeader. Для того, что бы определить, поврежден файл или нет, программа ищет в закодированной строчке заголовок, в нашем примере это «Crypted», и если он отсутствует, то дешифровка прекращается и возникает ошибка. Если же все в порядке, далее идет расшифровка текста, алгоритм которой полностью противоположен алгоритму шифрования.

Итак, все способы, освещенные в статье, были подробно разобраны и оговорены. Теперь выбор за вами. Попробуйте описанные в этой статье способы на своей практике. Импровизируйте, пытаясь создать что-то совершенное, и решение в выборе между системным реестром и ini-файлами придет к вам.

Автор: Корнейчук Михаил

Получить ссылку на материал

Категория: Разное | Добавил: Барон (16.12.2011)
Просмотров: 698 | Теги: сохранение, параметры, Загрузка | Рейтинг: 0.0/0
[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Поиск
Категории раздела
ActiveX [10]
CORBA и COM [16]
Kol и MCK [23]
WinAPI [28]
Компоненты [27]
Работа с Bluetooth [4]
Железо [8]
Текст [18]
Разное [98]
Королевство Delphi © 2010-2024
Яндекс цитирования