Закрыть окно подсказки по окончанию программы

С помощью API-функции SendMessage можно задать поля в Memo-компоненте.

Если необходимо, например, сделать отступ в 20 пикселей слева то можно это сделать следующим образом:


var Rect: TRect;  
begin  
  SendMessage( Memo1.Handle, EM_GETRECT, 0, LongInt(@Rect));  
  Rect.Left:= 20;  
  SendMessage(Memo1.Handle, EM_SETRECT, 0, LongInt(@Rect));  
  Memo1.Refresh;  
end;  

Добавлено: 31 Июля 2018 21:21:55 Добавил: Андрей Ковальчук

Как выдать текст под наклоном?

Чтобы вывести под любым углом текст необходимо использовать TrueType Fonts (например "Arial"). Например:


var   
  LogFont : TLogFont;  
...  
  GetObject(Canvas.Font.Handle, SizeOf(TLogFont), @LogFont);  
  { Вывести текст 1/10 градуса против часовой стрелки }  
  LogFont.lfEscapement := Angle*10;   
  Canvas.Font.Handle := CreateFontIndirect(LogFont);

Добавлено: 31 Июля 2018 21:20:16 Добавил: Андрей Ковальчук

Как выяснить дату последнего изменения файла?

Для выяснения даты последнего изменения файла можно воспользоваться следующей функцией:


function GetFileDate(FileName: string): string;  
var  
  FHandle: Integer;  
begin  
  FHandle := FileOpen(FileName, 0);  
  try  
    Result := DateTimeToStr(FileDateToDateTime(FileGetDate(FHandle)));  
  finally  
    FileClose(FHandle);  
  end;  
end;  

Добавлено: 31 Июля 2018 21:19:41 Добавил: Андрей Ковальчук

Как сделать отступ в Memo?

С помощью API-функции SendMessage можно задать поля в Memo-компоненте. Если необходимо, например, сделать отступ в 20 пикселей слева то можно это сделать следующим образом:


var Rect: TRect;  
begin  
  SendMessage( Memo1.Handle, EM_GETRECT, 0, LongInt(@Rect));  
  Rect.Left:= 20;  
  SendMessage(Memo1.Handle, EM_SETRECT, 0, LongInt(@Rect));  
  Memo1.Refresh;  
end; 

Добавлено: 31 Июля 2018 21:18:57 Добавил: Андрей Ковальчук

Как закрыть окно подсказки если пользователь закончил приложение?

В следующем примере показано как закрыть окно помощи если пользователь закончил приложение.


procedure TMainForm.FormClose(Sender: TObject;   
          var Action: TCloseAction);  
begin  
  Winhelp(Handle, 'WINHELP.HLP', HELP_QUIT, 0);  
  Action := caFree;  
end;  

Добавлено: 31 Июля 2018 21:15:31 Добавил: Андрей Ковальчук

Как через индекс обратиться к нескольким компонентам?

Чтобы найти и сделать видимыми, например, компоненты с именами от "Label1" и до "Label5" можно использовать следующий вариант:


for t := 1 to 5 do  
  FindComponent('Label' + IntToStr(t)).Visible := TRUE;  

Добавлено: 31 Июля 2018 19:35:56 Добавил: Андрей Ковальчук

Порядок, в котором обрабатываются события при загрузке формы

1. OnCreate
2. OnShow
3. OnPaint
4. OnActivate
5. OnResize
6. OnPaint

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

Добавлено: 31 Июля 2018 08:42:13 Добавил: Андрей Ковальчук

Как вызвать подсказку к подсказке?

В Delphi-приложении можно вызвать помощь в пользовании системой помощи следующим образом:


Application.HelpCommand(Help_HelpOnHelp, 0); 

Добавлено: 31 Июля 2018 08:39:10 Добавил: Андрей Ковальчук

RTTI в действии

Бывает, что надо всем контpолам на форме поменять OnMouseMove Event. Или же нужно сбросить свойство Hint у всех элементов, у которых это свойство есть. Контpолы могут быть самые pазные TEdit, TLabel, TListView и т.п. Такие возможности в Delphi есть, более того, на них построена вся среда визуальной разработки IDE Delphi.

для справки

Run-time type information (RTTI) - это специальный механизм определения типа объекта во время выполнения. Чаще всего это актуально для определения типа объекта по указателю. Многие каркасные библиотеки самостоятельно поддерживают этот механизм. В том числе и VCL.

Приведем пример использования данного механизма в Delphi. Для начала рассмотрим работу с методами, а затем - со свойствами.
Следующий пример устанавливает у всех компонентов на форме обработчик OnMouseMove на собственную процедуру.


unit Unit1;  
  
interface  
  
uses  
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
  StdCtrls;  
  
type  
  TForm1 = class(TForm)  
  
    procedure FormCreate(Sender: TObject);  
  
//...эта ф-ия обязательно должна быть описана здесь, а не в одном из   
//   следующих pазделов, иначе MethodAddress() ее не видит.  
  
    procedure CommonMouseMove (Sender: TObject; Shift: TShiftState;  
                               X,Y:Integer);  
  private  
  public  
    procedure SetEventMethodToAllComponentsInForm( FormX: TForm );  
  end;  
  
var  
  Form1: TForm1;  
  
implementation  
uses TypInfo;  
{$R *.DFM}  
  
procedure TForm1.SetEventMethodToAllComponentsInForm( FormX: TForm );  
var  
  PropInfo: PPropInfo;  
  i: integer;  
  CommonMethod: TMethod;  
begin  
  for i:=0 to FormX.ComponentCount-1 do  
  begin  
    PropInfo := GetPropInfo( FormX.Components[i].ClassInfo, 'OnMouseMove');  
    if PropInfo <> nil then  
    begin  
      CommonMethod.Data := FormX.Components[i];  
      CommonMethod.Code := Form1.MethodAddress('CommonMouseMove');  
      SetMethodProp( FormX.Components[i], PropInfo, CommonMethod );  
    end;  
  end;  
end;  
  
procedure TForm1.CommonMouseMove (Sender: TObject; Shift: TShiftState; X,Y:  
Integer);  
begin  
  ShowMessage('olala');  
end;  
  
procedure TForm1.FormCreate(Sender: TObject);  
begin  
  //...пеpедадим для пpобы ссылку на эту же фоpму  
  SetEventMethodToAllComponentsInForm( self );  
end;  

Это что касается методов. Свойства тоже не обделены такими возможностями. Для из изменения нужно использовать пpоцедуpу procedure SetOrdProp(Instance: TObject; PropInfo: PPropInfo; Value: Longint);


// procedure SetOrdProp(Instance: TObject; PropInfo: PPropInfo; Value: Longint);  
  
//  Hапpимеp следующий код устанавливает свойство Color у всех компонентов фоpмы,  
//котоpые этим свойством pасполагают:  
  
  for i:=0 to FormX.ComponentCount-1 do  
  begin  
    PropInfo := GetPropInfo( FormX.Components[i].ClassInfo, 'Color');  
    if PropInfo <> nil then  
      SetOrdProp( FormX.Components[i], PropInfo, clGreen );  
  end;  

Обратите внимание, что используемые здесь процедуры для работы с RTTI определены в стандартном модуле TypInfo.

Добавлено: 31 Июля 2018 08:37:30 Добавил: Андрей Ковальчук

PGPSDK - легкий путь к шифрованию

Иногда бывает нужно прикрутить к своей программе какое-нибудь шифрование. Для этих целей разработаны кучи алгоритмов шифрования, дешифрования, электронной подписи и т.п., основанных на различных математических аппаратах. Мало того – необходимо реализовать этот алгоритм. Но мы как кульные программеры не будем этого делать – а возьмем готовую библиотеку PGPsdk. Я не буду повторять классиков [2], что для реальных приложений использовать самодельные шифры не рекомендуется, если вы не являетесь экспертом и не уверены на 100 процентов в том, что делаете. Отговаривать же Вас от разработки собственных шифров или реализации какого-либо стандарта тоже не суть этой статьи, здесь пойдет речь о том, как быстро и правильно реализовать в своих приложениях защиту от посторонних глаз и, самое главное - не обмануться.

В моем приложении уже использовалось шифрование от PGP, ДОСовская, работало через командные файлы (*.bat), что явилось весомым аргументом для выбора средства шифрования, все работало, но меня это не устраивало – ДОСовская версия PGP (5.0) затрудняло инсталляцию программы, поддержку и не имеет некоторых полезных вещей, нужных для расширения системы в будущем. Еще чем привлекала PGP – бесплатная для некоммерческих программ, генерация произвольного количества ключей и то что пакет PGP очень популярен и им пользуются большое количество людей, и Вам легко будет решить проблему защиты информации от посторонних глаз в своих приложениях и по моему защита с помощью PGP дает большое преимущество.

Небольшая справка по PGP:

Pretty Good Privacy (PGP) выпущено фирмой Phil's Pretty Good Software и является криптографической системой с высокой степенью секретности для операционных систем MS-DOS, Unix, VAX/VMS и других. PGP позволяет пользователям обмениваться файлами или сообщениями с использованием функций секретности, установлением подлинности, и высокой степенью удобства. Секретность означает, что прочесть сообщение сможет только тот, кому оно адресовано. Установление подлинности позволяет установить, что сообщение, полученное от какого-либо человека было послано именно им. Нет необходимости использовать секретные каналы связи, что делает PGP простым в использовании программным обеспечением. Это связано с тем, что PGP базируется на мощной новой технологии, которая называется шифрованием с "открытым ключом".

Поддерживаемые алгоритмы

Deiffie-Hellman
CAST
IDEA
3DES
DSS
MD5
SHA1
RIPEMD-160

Реализуемые функции

Шифрование и аунтефикация (с использованием перечисленных алгоритмов);
Управление ключами (создание, сертификация, добавление/удаление из связки, проверка действительности, определения уровня надежности);
Интерфейс с сервером открытых ключей (запрос, подгрузка, удаление и отзыв ключа с удаленного сервера);
Случайные числа (генерация криптографически стойких псевдослучайных чисел и случайных чисел, базируясь на внешних источниках);
Поддержка PGP/MIME;
Вспомогательные функции.
Обзор существующих библиотек

Первое что я сделал – сходил на torry.ru и был удивлен обилием библиотек и функций для разного рода шифрования. Функциональность их я проверять не стал, а остановился на PGP-пишных компонентах.

PGPComp - ДОСовская, работает по принципу запуска внешнего exe-файла, сразу отпала по той причине - что нужно будет устанавливать MSDOS версию PGP (Кроме того библиотека только под 1 и 2 Delphi). Вспомнил что в моей любимой почтовой программе The Bat встроена поддержка PGP, зашел на их сайт - скачал библиотеку dklib.dll, любезно предоставленную ими, но почему то у меня не один из примеров не пошел, а за отсутствием исходников, я не мог понять почему. Пробовал обраться к автору - в ответ тишина, уже больше года не отвечает он. А неплохая библиотека, по крайней мере по тому что написано в документации присутствует тот необходимый минимум функций для шифрования-дешифрования, проверки ключа и сама библиотека весит не очень много – 184'832 Байт.

Т.е. меня не устроили эти библиотеки и я пошел на http://www.pgpi.org, в поисках истины. Нашел там упоминание про библиотеку для разработчиков – PGPsdk.

Собственно сам PGPsdk

28 октября 1997 г. PGP, Inc. объявила о поставке PGPsdk сторонним производителям программного обеспечения. PGPsdk - это средство разработки для программистов на С, позволяющее разработчикам программного обеспечения встраивать в него стойкие криптографические функции. Можно сказать что в PGPsdk реализованы все функции пакета PGP, мало того - версия PGP начиная с 5.0 хранит криптографические функции в динамических библиотеках – dll (о том насколько это не безопасно – вопрос к Крису Касперски, я лишь скажу что насколько я силен в математике).

PGPsdk - это динамическая библиотека, состоящая из трех файлов [табл. 1], поддерживающая базовые алгоритмы криптования (перечислены выше), гибкое управление ключами, сетевой интерфейс и др. (можно использовать одну библиотеку - PGP_sdk.dll, если Вы не будите использовать фирменный интерфейс пользователя от NAI и сетевую библиотеку).

Установка

Скачайте архив с PGPsdk [9], на момент написания статьи доступна версия 1.7.2 (должен заметить что архив занимает 3 с лишним мегабайт), необходимо его разархивировать и из каталога \Libraries\DLL\Release взять следующие файлы - табл. 1

Табл.1
PGP_SDK.dll для криптования, управление ключами и т.д.
PGPsdkUI.dll (UI= user interface) интерфейсные штучки, если Вам нужно будет только шифровать/расшифровывать, то этот файл необязателен. Но очень полезен для ввода пароля, выбора получателей сообщений, генерации ключей и другое.
PGPsdkNL.dll (NL= network library) сетевая библиотека для работы с сервером ключей или для transport layer security. Ее мы рассматривать не будем, но в ближайшем будущем я попытаюсь ее описать.

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

Переходим к делу.

Для работы система предоставляет ряд низкоуровневых PGP API (Application Programmig Interface) функций. Заголовки (хеадеры, описания) этих функций поставляются вместе с пакетом на Ц и лежат в каталоге Headers. Если Вы как и я пишите на Delphi, можете сами сконвертировать их, а можете взять готовые тут [10]. Это проект по переводу Ц-ных хеадеров на любимый мною язык программирования. Занимается всем этим делом Стивен Хейлер (Steven R. Heller ).

Описатели переведены на Delphi по принципу как это сделано для Ц - разбросаны на кучи модулей (листинг 1). Все названия модулей аналогичны Ц-ным заголовкам, за исключением pgpEncode - переименовано в pgpEncodePas, из-за особенностей объявления в Delphi (нельзя чтоб имя процедуры совпадало с названием модуля).

Листинг 1. Объявление используемых библиотек.


uses  
  // PGPsdk  
  pgpEncodePas, pgpOptionList, pgpBase, pgpPubTypes,  
  pgpUtilities, pgpKeys, pgpErrors,  
  // always last  
  pgpSdk;  

Единственная трудность, которая возникает на пути включения криптования в Ваше приложение - это использование слишком уж низкоуровневых PGP API функций. Для того что бы сделать какую-нибудь операцию - будь то подсчет публичных ключей в связке или просто зашифровать файл - необходимо создавать контекст, указать где находятся ключи, создать фильтр ключей, подготовить файловые дескрипторы, если с памятью - выделить ее (в случае шифрования-/-расшифрования), затем все это в обратном порядке освободить (если контекст неправильно освобождается - файлы с резервными ключиками не удалятся). И все это при том что в системном каталоге WINDOWS создается файл, в котором содержится информация где находятся файлы с публичными и секретными ключами (о нем будет подробно сказано ниже). Для сравнения работы через PGP API предоставлен листинг2.

Листинг 2. Пример использования PGPsdk через PGP API


var  
  context: pPGPContext;  
  keyFileRef: pPGPKeySet;  
  defaultKeyRing: pPGPKeySet;  
  foundUserKeys: pPGPKeySet;  
  filter: pPGPFilter;  
  countKeys: PGPUInt32;  
  keyFileName: PChar;  
  userID: PChar;  
  inFileRef,  
    outFileRef: pPGPFileSpec;  
  inFileName,  
    outFileName: PChar;  
begin  
  // Init от C++  
  context := nil;  
  keyFileName := 'pubring.pgp';  
  userID := '';  
  inFileName := 'myInFile.txt';  
  outFileName := 'myOutFile.txt.asc';  
  
  // Begin  
  PGPCheckResult('sdkInit', PGPsdkInit);  
  
  PGPCheckResult('PGPNewContext',  
    PGPNewContext(  
    kPGPsdkAPIVersion,  
    context  
    ));  
  
  PGPCheckResult('PGPNewFileSpecFromFullPath',  
    PGPNewFileSpecFromFullPath(  
    context,  
    keyFileName,  
    keyFileRef  
    ));  
  
  PGPCheckResult('PGPOpenKeyRing',  
    PGPOpenKeyRing(  
    context,  
    kPGPKeyRingOpenFlags_None,  
    keyFileRef,  
    defaultKeyRing  
    ));  
  
  PGPCheckResult('PGPNewUserIDStringFilter',  
    PGPNewUserIDStringFilter(context, userID, kPGPMatchSubString, filter));  
  
  PGPCheckResult('PGPFilterKeySet',  
    PGPFilterKeySet(defaultKeyRing, filter, foundUserKeys));  
  
  // Открываем файловые манипуляторы  
  PGPCheckResult('PGPNewFileSpecFromFullPath',  
    PGPNewFileSpecFromFullPath(context, inFileName, inFileRef));  
  
  PGPCheckResult('PGPNewFileSpecFromFullPath',  
    PGPNewFileSpecFromFullPath(context, outFileName, outFileRef));  
  
  //  
  // А вот здесь уже идет кодирование.  
  //  
  PGPCheckResult('PGPEncode',  
    PGPEncode(  
    context,  
    [  
    PGPOEncryptToKeySet(context, foundUserKeys),  
      PGPOInputFile(context, inFileRef),  
      PGPOOutputFile(context, outFileRef),  
      PGPOArmorOutput(context, 1),  
      PGPOCommentString(context, PChar('Comments')),  
      PGPOVersionString(context,  
        PChar('Version 5.0 assembly by Evgeny Dadgoff')),  
      PGPOLastOption(context)  
      ]  
      ));  
  
  //  
  // Освобождаем занимаемые ресурсы и контекст PGP  
  //  
  if (inFileRef <> nil) then  
    PGPFreeFileSpec(inFileRef);  
  if (outFileRef <> nil) then  
    PGPFreeFileSpec(outFileRef);  
  if (filter <> nil) then  
    PGPFreeFilter(filter);  
  if (foundUserKeys <> nil) then  
    PGPFreeKeySet(foundUserKeys);  
  if (defaultKeyRing <> nil) then  
    PGPFreeKeySet(defaultKeyRing);  
  if (keyFileRef <> nil) then  
    PGPFreeKeySet(keyFileRef);  
  if (context <> nil) then  
    PGPFreeContext(context);  
  PGPsdkCleanup;  
end;  

Здесь реализован пример из [9] со страницы 39. Функция PGPCheckResult позаимствована у Стивена из его примеров - принимает два параметра - строковую и код выполнения функции PGP API, если была ошибка - генерируется исключение и на экран выводится описание ошибки с именем функции (Очень помогает для ловли ошибок, а при вызове dll-библиотеки, тем более написанной на другом языке – помогает избавиться от Access violation).

Листинг 3. Функция PGPCheckResult.


procedure PGPCheckResult(const ErrorContext: shortstring; const TheError:  
  PGPError);  
var  
  s: array[0..1024] of Char;  
begin  
  if (TheError <> kPGPError_NoError) then  
  begin  
    PGPGetErrorString(TheError, 1024, s);  
    if (PGPGetErrorString(TheError, 1024, s) = kPGPError_NoError) then  
      raise exception.create(ErrorContext + ' [' + IntToStr(theError) + '] : ' +  
        StrPas(s))  
    else  
      raise exception.create(ErrorContext +  
        ': Error retrieving error description');  
  end;  
end;  

Там же у Стивена я нашел еще один проект - написанная на Delphi библиотека для VB, проект под названием SimplePGP (SPGP). Дело в том, что VB не может использовать библиотеку PGPsdk из-за ограничения импортирования библиотек dll [9, раздел FAQ]. Сам Стивен предложил мне добавить к проекту еще одну dll, тем самым забыть про PGP API, и использовать облегченную модель вызова функций криптований.

Сам интерфейс к доступу функциям выполнен не плохо, продуманно и вызов их не должен вызвать затруднений у Вас.

Открыв ее я подумал - а не убрать ли мне все эти "stdcall;export;" и просто присоединить библиотеку к ехе-файлу (ну не устраивает меня хитросплетение dll). Сказано сделано.

Итак, поехали!

Создадим подкаталог для объявления функций PGPsdk, скопировав туда файлики DELPHI PGP API - pgp*.pas и spgp*.pas. Удалим в файлах spgp*.pas - "stdcall;export;"(уже полученные в итоге заголовочные файлы можно взять тут [12]). Теперь к Вашему проекту нужно приписать использование библиотек (это там где uses):


uses  
  // PGPsdk  
  pgpEncodePas, pgpOptionList, pgpBase, pgpPubTypes,  
  pgpUtilities, pgpKeys, pgpErrors,  
  // SPGP  
  spgpGlobals, spgpEncrypt, spgpKeyUtil, spgpUtil, spgpKeyMan,  
  spgpPreferences, spgpKeyProp, spgpKeyIO, spgpKeyGen, spgpMisc,  
  spgpUIDialogs,  
  // always last  
  pgpSdk;  

Можно использовать только необходимые модули.

Первое что мы попробуем сделать - это зашифровать и подписать произвольный файл и получить зашифрованный в текстовом виде (ASC). Здесь следует отметить что PGPsdk может работать не только с файлами, но и с памятью, а также комбинировать - память - файл, файл - память.


PGPCheckResult  
(  
  'Ошибка при шифровании файла',  
  spgpencodefile(  
  PChar(edtFileIn.Text),  
  PChar(edtFileOut.Text),  
  1, // Encrypt.Value  
  1, // Sign.Value  
  kPGPHashAlgorithm_MD5,  
  0,  
  kPGPCipherAlgorithm_CAST5,  
  1,  
  0,  
  0,  
  'Steven R. Heller', // Кто может расшифровать  
  'Evgeny Dadgoff', // Чем подписывать  
  'MyPassPhrase', // Хех, это пароль  
  '',  
  PChar(edtComment.Text)  
  )  
);  

Сравним что получится если переделать пример [9,стр. 18] на Delphi - на чистом API.

Лично для меня проще было использовать spgp-модель чем тяжелые PGPAPI вызовы.

Про преференс

Для работы библиотеке необходимо знать где лежат файлы с ключиками (pubring.prk и secring.prk). PGP API позволяет сохранять свои настройки в файле PGPsdk.dat (почему то он всегда сохраняется в каталоге с виндами). Для работы с этим файлом предназначены следующие функции:


spgpgetpreferences(Prefs: pPreferenceRec; Flags: Longint):LongInt;
spgpsetpreferences(Prefs: pPreferenceRec; Flags: Longint):LongInt;
Соответственно для получения преференса и установки его (кстати ключики могут лежать не только в файлах). Замечу что это не единственный способ – PGP API позволяет напрямую указывать где расположены ключи, но тогда Вам придется отказаться от SPGP, или поправлять SPGP под себя.

Как получить список всех имеющихся ключей

Здесь я покажу как получить список всех ключей - заполнение LVKeys:TListView именами ключей и шестнадцатеричными ID-значениями ключей, используя SPGP-модель.


var  
  P: TPreferenceRec;  
  Flags: LongInt;  
  outBuf: array[1..30000] of Char;  
  i, KeyCount: Integer;  
  TempStr, StrKeys: AnsiString;  
begin  
  LVKeys.Items.Clear;  
  FillChar(P, 1024, 0);  
  FillChar(outbuf, 30000, 0);  
  Flags := PGPPrefsFlag_PublicKeyring or  
    PGPPrefsFlag_PrivateKeyring or  
    PGPPrefsFlag_RandomSeedFile;  
  if (spgpGetPreferences(@P, Flags) <> 0) then  
    ShowEvent('Error!', 1);  
  // GetWindowsDirectory  
  if (LowerCase(WinDir + 'pubring.pkr') = LowerCase(StrPas(P.PublicKeyring))) or  
    not (FileExists(StrPas(P.PublicKeyring))) then  
  begin  
    StrPCopy(P.PublicKeyring, ExtractFilePath(Application.ExeName) +  
      'KEYS\pubring.pgp');  
    StrPCopy(P.PrivateKeyring, ExtractFilePath(Application.ExeName) +  
      'KEYS\secring.pgp');  
    StrPCopy(P.RandomSeedFile, ExtractFilePath(Application.ExeName) +  
      'KEYS\randseed.bin');  
    if (CreateDir(ExtractFilePath(Application.ExeName) + 'KEYS')) then  
      ShowEvent('Каталог ключей ' + ExtractFilePath(Application.ExeName) + 'KEYS'  
        +  
        ' -- не существует, Будет создан заново... ', 0);  
    spgpSetPreferences(@P, Flags);  
  
    //Создать файлы с ключами - такой хитрый прием.  
    spgpSubKeyGenerate('mmmh', 'sssl', 'ssss', 1, 1024, 0, 0, 0, 0);  
  end;  
  btnPubKeys.Caption := StrPas(P.PublicKeyring);  
  btnSecKeys.Caption := StrPas(P.PrivateKeyring);  
  btnRndBin.Caption := StrPas(P.RandomSeedFile);  
  PGPCheckResult('Ошибка при инициализации PGP-SDK, убедитесь что все DLL  
    установленны правильно', Init(FContext, PubKey, false, false));  
  spgpKeyRingID(@outBuf, 30000);  
  KeyCount := spgpkeyringcount;  
  StrKeys := StrPas(@outBuf);  
  for i := 1 to KeyCount do  
  begin  
    TempStr := Copy(StrKeys, 1, Pos(#13 + #10, StrKeys));  
    Delete(StrKeys, 1, Pos(#13 + #10, StrKeys) + 1);  
    with (LVKeys.Items.Add) do  
    begin  
      Caption := Copy(TempStr, 14, Length(TempStr) - 14);  
      SubItems.Add(TempStr[1]);  
      SubItems.Add(Copy(TempStr, 3, 10));  
    end;  
  end;  
  QuitIt(FContext, PubKey);  
end;  

Про то, как вычисляется размер зашифрованного текста.

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


outBufLen := inBufLen * 5;  
if (outBufLen < 10000) then  
  outBufLen := 10000;  
outBufRef := StrAlloc(outBufLen);  

Временные ключики

В процессе работы программы появляются резервные файлы ключей, имеющие следующий вид - (pub|sec)ring-bak-##.pgp – предусмотрен откат от изменений. В принципе, если Вы правильно используете контекст и правильно его закрываете, этот файл корректно удаляется при освобождение контекста. Но на всякий случай можно его удалять следующим образом (повесить можно на закрытие формы или вызывать принудительно):


procedure DeleteBakPGPFiles;  
var  
  P: TPreferenceRec;  
  FileSearch: string;  
  SearchRec: TSearchRec;  
begin  
  spgpGetPreferences(@P, PGPPrefsFlag_PublicKeyring or  
    PGPPrefsFlag_PrivateKeyring);  
  FileSearch := P.PublicKeyring;  
  Insert('-bak-*', FileSearch, Pos('.', FileSearch));  
  FindFirst(FileSearch, faAnyFile, SearchRec);  
  if (SearchRec.Name <> '') then  
    if not (DeleteFile(ExtractFilePath(FileSearch) + SearchRec.Name)) then  
      ShowEvent('Not delete file::' +  
        ExtractFilePath(FileSearch) + SearchRec.Name, 0);  
  while (FindNext(SearchRec) = 0) do  
    if not (DeleteFile(ExtractFilePath(FileSearch) + SearchRec.Name)) then  
      ShowEvent('Not delete file::' +  
        ExtractFilePath(FileSearch) + SearchRec.Name, 0);  
  FindClose(SearchRec);  
end;  

Интерфейс пользователя

PGP_sdkUI.dll – это библиотека пользовательских интерфейсов, фирменные штучки от Network Associates, использовав их у Вас будут диалоги такие же как у фирменного пакета PGP. Вам уже не нужно будет строить диалоги самому:

Для Генерации ключей;
При выборе получателей сообщений;
При запросе пароля и т.п.
Вывод:

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

Перечень функций SPGP


{ spgpDecrypt - decryption & signature verification functions            }  
function spgpdecode(BufferIn, BufferOut: PChar; BufferOutLen: LongInt; Pass,  
  SigProps: PChar): LongInt;  
function spgpdecodefile(FileIn, FileOut, Pass, SigProps: PChar): LongInt;  
function spgpdetachedsigverify(SigFile, SignedFile, SigProps: PChar):LongInt;  
  
{ spgpEncrypt - encryption & signing functions                           }  
function spgpencode(BufferIn, BufferOut: PChar; BufferOutLen: LongInt;  
         Encrypt, Sign, SignAlg, ConventionalEncrypt, ConventionalAlg, Armor,  
         TextMode, Clear: LongInt; CryptKeyID, SignKeyID, SignKeyPass,  
         ConventionalPass, Comment: PChar): LongInt;  
function spgpencodefile(FileIn, FileOut: PChar; Encrypt, Sign, SignAlg,  
         ConventionalEncrypt, ConventionalAlg, Armor, TextMode,  
         Clear: LongInt; CryptKeyID, SignKeyID, SignKeyPass, ConventionalPass,  
         Comment: PChar): LongInt;  
  
{ spgpFeatures - functions to determine PGPsdk version and availability  }  
{ of PGPsdk features                                                     }  
function spgpsdkapiversion: Longint;  
function spgppgpinfo(Info: pPGPInfoRec): LongInt;  
function countkeyalgs: LongInt;  
function countcipheralgs: LongInt;  
  
{ spgpKeyGen - key-generation functions                                  }  
function spgpkeygenerate(UserID, PassPhrase, NewKeyHexID: PChar;  
         KeyAlg, CipherAlg, Size, ExpiresIn, FastGeneration, FailWithoutEntropy,  
         WinHandle: Longint): LongInt;   
function spgpsubkeygenerate(MasterKeyHexID, MasterKeyPass, NewSubKeyHexID: PChar;  
         KeyAlg, Size: Longint; ExpiresIn, FastGeneration, FailWithoutEntropy,  
         WinHandle: Longint): LongInt;  
  
{ spgpKeyIO - Key import/export functions                                }  
function spgpkeyexport(pKeyID,BufferOut: PChar;BufferOutLen,ExportPrivate,  
  ExportCompatible: LongInt):LongInt;  
function spgpkeyexportfile(pKeyID,FileOut: PChar; ExportPrivate,ExportCompatible:  
  LongInt):LongInt;  
function spgpkeyimport(BufferIn,KeyProps: PChar; KeyPropsLen: LongInt):LongInt;  
function spgpkeyimportfile(FileIn,KeyProps: PChar; KeyPropsLen: LongInt):LongInt;  

Автор: Евгений Дадыков

Добавлено: 31 Июля 2018 08:36:39 Добавил: Андрей Ковальчук

Math - математика, статистика, финансы. Краткий справочник по функциям в Delphi

Тригонгометрические функции:

function ArcCos(X: Extended): Extended;  
function ArcSin(X: Extended): Extended;  
function ArcTan2(Y, X: Extended): Extended; // Арктангенс X/Y возвращает угол в квадранте  
procedure SinCos(Theta: Extended; var Sin, Cos: Extended) register; // возвращает сразу и синус и косинус, вычисления в 2 раза быстрее чем Sin, Cos по отдельности  
function Tan(X: Extended): Extended;  
function Cotan(X: Extended): Extended;  

function Hypot(X, Y: Extended): Extended; // Возвращает значение гипотенузы по катетам
Конвертация углов

function DegToRad(Degrees: Extended): Extended;  
function RadToDeg(Radians: Extended): Extended;  
function GradToRad(Grads: Extended): Extended;  
function RadToGrad(Radians: Extended): Extended;  
function CycleToRad(Cycles: Extended): Extended;  
function RadToCycle(Radians: Extended): Extended;   

Гиперболические функции

function Cosh(X: Extended): Extended;  
function Sinh(X: Extended): Extended;  
function Tanh(X: Extended): Extended;  
function ArcCosh(X: Extended): Extended;  
function ArcSinh(X: Extended): Extended;  
function ArcTanh(X: Extended): Extended;   

Логарифмы, экспоненты и возведение в степень

function LnXP1(X: Extended): Extended; // натуральный логариф x+1 (для более высокой точности при x близких к нулю)  
function Log10(X: Extended): Extended; // десятичный логарифм  
function Log2(X: Extended): Extended; // логарифм по основанию 2  
function LogN(Base, X: Extended): Extended; // логарифм по произвольному основанию  
function IntPower(Base: Extended; Exponent: Integer): Extended register;  
function Power(Base, Exponent: Extended): Extended;   

Разные функции

procedure Frexp(X: Extended; var Mantissa: Extended; var Exponent: Integer) register; // возвращает мантису и экспоненту  
function Ldexp(X: Extended; P: Integer): Extended register; // возвращает X*2**P  
function Ceil(X: Extended):Integer; // округляет до ближайшего большего целого  
function Floor(X: Extended): Integer; // округляет до ближайшего меньшего целого  
function Poly(X: Extended; const Coefficients: array of Double): Extended; // вычисление полинома 

Статистические функции

function Mean(const Data: array of Double): Extended; // среднее арифметическое  
function Sum(const Data: array of Double): Extended register; // сумма ряда  
function SumInt(const Data: array of Integer): Integer register; // сумма ряда целых чисел  
function SumOfSquares(const Data: array of Double): Extended; // сумма квадратов  
procedure SumsAndSquares(const Data: array of Double; var Sum, SumOfSquares: Extended) register; // сумма и сумма квадратов одной функцией  
function MinValue(const Data: array of Double): Double; // минимальное значение в ряду  
function MinIntValue(const Data: array of Integer): Integer; // минимальное значение в ряду целых  
function Min(A,B) минимальное значение из 2х чисел (overload функции для Integer, Int64, Single, Double, Extended)  
function MaxValue(const Data: array of Double): Double;  
function MaxIntValue(const Data: array of Integer): Integer;  
function Max(A,B);  
function StdDev(const Data: array of Double): Extended; // стандартное отклонение  
procedure MeanAndStdDev(const Data: array of Double; var Mean, StdDev: Extended); // среднее арифметическое и стандартное отклонение  
function PopnStdDev(const Data: array of Double): Extended; // распределение стандартного отклонения (Population Standard Deviation)  
function Variance(const Data: array of Double): Extended;  
function PopnVariance(const Data: array of Double): Extended; (Population Variance)  
function TotalVariance(const Data: array of Double): Extended;  
function Norm(const Data: array of Double): Extended; // среднее квадратичное (Sqrt(SumOfSquares))  
procedure MomentSkewKurtosis(const Data: array of Double;  
var M1, M2, M3, M4, Skew, Kurtosis: Extended); // основные статистические моменты  
function RandG(Mean, StdDev: Extended): Extended; // случайные числа с Гауссовским распределением

Финансовые функции

function DoubleDecliningBalance(Cost, Salvage: Extended; Life, Period: Integer): Extended;  
function FutureValue(Rate: Extended; NPeriods: Integer; Payment, PresentValue: Extended; PaymentTime: TPaymentTime): Extended;  
function InterestPayment(Rate: Extended; Period, NPeriods: Integer; PresentValue,  
FutureValue: Extended; PaymentTime: TPaymentTime): Extended;  
function InterestRate(NPeriods: Integer;  
Payment, PresentValue, FutureValue: Extended; PaymentTime: TPaymentTime): Extended;  
function InternalRateOfReturn(Guess: Extended;  
const CashFlows: array of Double): Extended;  
function NumberOfPeriods(Rate, Payment, PresentValue, FutureValue: Extended;  
PaymentTime: TPaymentTime): Extended;  
function NetPresentValue(Rate: Extended; const CashFlows: array of Double;  
PaymentTime: TPaymentTime): Extended;  
function Payment(Rate: Extended; NPeriods: Integer;  
PresentValue, FutureValue: Extended; PaymentTime: TPaymentTime): Extended;  
function PeriodPayment(Rate: Extended; Period, NPeriods: Integer;  
PresentValue, FutureValue: Extended; PaymentTime: TPaymentTime): Extended;   
function PresentValue(Rate: Extended; NPeriods: Integer;  
Payment, FutureValue: Extended; PaymentTime: TPaymentTime): Extended;  
function SLNDepreciation(Cost, Salvage: Extended; Life: Integer): Extended;  
function SYDDepreciation(Cost, Salvage: Extended; Life, Period: Integer): Extended;  

Добавлено: 31 Июля 2018 08:34:10 Добавил: Андрей Ковальчук

Ini-файл в директории программы


function ReadIni(ASection, AString : String) : String;  
var  
   sIniFile: TIniFile;  
   sPath : String[60];  
const  
   S = 'xyz';   
begin  
   GetDir(0,sPath);  
   sIniFile := TIniFile.Create(sPath + '\Name.INI');  
   Result := sIniFile.ReadString(ASection, AString, S); { [Section] String=Value }  
   sIniFile.Free;  
end;  
  
procedure WriteIni(ASection, AString, AValue : String);  
var  
   sIniFile: TIniFile;  
   sPath : String[60];  
begin  
   GetDir(0,sPath);  
   sIniFile := TIniFile.Create(sPath + '\Name.INI');  
   sIniFile.WriteString(ASection, AString, AValue);; { [Section] String=Value }  
   sIniFile.Free;  
end;

Добавлено: 31 Июля 2018 08:31:42 Добавил: Андрей Ковальчук

Drag&amp;Drop, учимся перетаскивать картинку по форме

В этом уроке будем учиться с помощью мышки перетаскивать по форме компонент Image.

Создаем новый проект на форму кидаем компонент Image с закладки Additional. Сразу загрузите в image какую ни будь картинку!
Для начала давайте определимся с тем каким образом пользователь будет перемещать объект по форме. Я предлагаю сделать так: если нажата кнопка мышки и удерживается клавиша Ctrl то можем перетаскивать. Для этого на компоненте Image создаем обработчик событий OnMouseDown, в котором пропишем вот такую строку

if ssCtrl in Shift then Image1.BeginDrag(True) ; 

Т.Е при нажатии кнопки мышки проверяем условие: если нажата клавиша CTRL то можем перетаскивать

Во время перетаскивания компонента Image над формой, а также при отпускании кнопки, у Формы возникает событие:
OnDragOver - В котором мы должны сказать форме примет ли она данный элемент(В нашем случае Image)

Итак, создадим на форме обработчик событий OnDragOver и в нем пропишем вот такую строку


Accept:= (Source is TImage) ; // Разрешаем принимать компонент Image  

Теперь нам осталось лишь сообщить программе что нужно делать, когда пользователь отпустил кнопку т.е завершил перетаскивание. Для этих целей существует событие OnDragDrop В обработчик этого события передаются параметры Source (объект-источник) и X и Y координаты курсора. В общем создаем обработчик событий OnDragDrop на форме и между begin .. end пишем:

if Source is TImage then // Если перетаскиваем компонент Image то  
begin  
TImage(Source).Left := X; //Переместить компонент Image в координаты //курсора по X  
TImage(Source).Top := Y; //Переместить компонент Image в координаты //курсора по Y  
end;  

Вот и все можите запускаться!!!

P.S. Полный код примера:


procedure TForm1.FormDragDrop(Sender, Source: TObject; X, Y: Integer);
begin  
if Source is TImage then  
begin  
TImage(Source).Left := X;  
TImage(Source).Top := Y;  
end;  
end;  
  
procedure TForm1.FormDragOver(Sender, Source: TObject; X, Y: Integer;  
State: TDragState; var Accept: Boolean);  
begin  
Accept := (Source is TImage) ;  
end;  
  
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;  
Shift: TShiftState; X, Y: Integer);  
begin  
if ssCtrl in Shift then Image1.BeginDrag(True) ;  
end;  

Добавлено: 31 Июля 2018 08:30:46 Добавил: Андрей Ковальчук