Автоматическая обработка ошибок

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

У всех
Типичная обработка ошибки заключается в том, чтобы обрамить блоки кода в конструкции try..except или try..finally. В общем, все по учебнику. Тем не менее, многие попросту не делают этого, так как им недосуг или обработка исключений оставляется "на потом". Когда подходит время сдачи проекта, нередко такие программисты начинают спешно латать дыры, что может дать не только положительный эффект, я имею ввиду появившуюся у программы обработку исключений, но и отрицательный. Дело в том, что обработка исключительных ситуаций тоже является частью кода, а внесение нового кода может повлечь за собой и внесение новых ошибок.

Избавиться от сложившейся ситуации не так трудно, как может показаться на первый взгляд. Почти все становится ясно, когда вспоминаешь про объект Application и его свойство OnException.

Не у всех
Как вы уже, наверное, догадались, свойство Application.OnException является глобальным обработчиком событий приложения. Перед тем как описать метод использования этого свойства, давайте договоримся, что у нас есть объект класса TgsCatcher (именно его я и описываю в данной статье), у которого есть метод TgsCatcer.Catcher, который и будет обработчиком ошибок приложения. Простейший вариант вышесказанного выглядит следующим образом:


unit gsCatcher;  
  
//**! ----------------------------------------------------------  
//**! This unit is a part of GSPackage project (Gregory Sitnin\'s  
//**! Delphi Components Package).  
//**! ----------------------------------------------------------  
//**! You may use or redistribute this unit for your purposes  
//**! while unit\'s code and this copyright notice is unchanged  
//**! and exists.  
//**! ----------------------------------------------------------  
//**! (c) Gregory Sitnin, 2001-2002. All rights reserved.  
//**! ----------------------------------------------------------  
  
{***} interface {***}  
  
uses Classes, SysUtils, JPEG;  
  
type  
  TgsCatcher = class(TComponent)  
  private  
    FEnabled: boolean;  
    FGenerateScreenshot: boolean;  
    FJPEGScreenshot: boolean;  
    FJpegQuality: TJPEGQualityRange;  
    FCollectInfo: boolean;  
    Fn: TFilename;  
    procedure SetEnabled(const Value: boolean);  
    { Private declarations }  
  protected  
    { Protected declarations }  
    procedure EnableCatcher;  
    procedure DisableCatcher;  
  public  
    { Public declarations }  
    constructor Create(AOwner: TComponent); override;  
    destructor Destroy; override;  
    procedure Catcher(Sender: TObject; E: Exception);  
  published  
    { Published declarations }  
    property Enabled: boolean read FEnabled write SetEnabled  
                      default False;  
  end;  
  
procedure Register;  
  
{***} implementation {***}  
  
uses Windows, Forms, Dialogs, Graphics;  
  
procedure Register;  
begin  
  RegisterComponents(\'Gregory Sitnin\', [TgsCatcher]);  
end;  
  
{ TgsCatcher }  
constructor TgsCatcher.Create(AOwner: TComponent);  
begin  
  inherited;  
end;  
  
destructor TgsCatcher.Destroy;  
begin  
  DisableCatcher;  
  inherited;  
end;  
  
procedure TgsCatcher.SetEnabled(const Value: boolean);  
begin  
  FEnabled := Value;  
  if Enabled then EnableCatcher else DisableCatcher;  
end;  
  
procedure TgsCatcher.DisableCatcher;  
begin  
  Application.OnException := nil;  
end;  
  
procedure TgsCatcher.EnableCatcher;  
begin  
  Application.OnException := Catcher;  
end;  
  
procedure TgsCatcher.Catcher(Sender: TObject; E: Exception);  
begin  
  {TODO: Write some exception handling code}  
end;  
  
end. 

Это компонент, который умеет подключаться и отключаться от обработчика Application.OnException при помощи установки свойства Enabled. В подключенном состоянии все возникшие в приложении исключительные ситуации перенаправляются методу TgsCatcher.Catcher, который с этими исключениями, пока, ничего не делает.

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

Реализация функций
Для начала, давайте снимем скриншот активного окна. Сделать это довольно легко. В секцию implementation подключаем модуль Graphics.
Лирическое отступление: Считается неплохим стилем, подключать модули в секцию implementation, если их информация требуется только в этой секции. Например, в секции interface я нигде не использовал ни одного класса или типа, который описан в модуле Graphics, поэтому и занес его в implementation.
После подключения вышеназванного модуля мы получили возможность работы с изображениями в формате BMP, то есть, мы можем описать объект класса TBitmap и получить в него снимок активного окна при помощи следующего вызова:

bmp := Screen.ActiveForm.GetFormImage;

Сам объект класса TBitmap создавать нет необходимости, так как он будет автоматически создан вызываемым методом GetFormImage. Теперь нам хорошо бы было полученное изображение сохранить в файл, а для этого не плохо бы было назвать файл уникальным именем. Надо заметить, что в Windows, как и во многих операционных системах есть специальный механизм создания действительно уникальных имен файлов. Однако, имена файлов на выходе этих механизмов являются, по большей части, ничего не значащими наборами символов. Но суть этой технологии в уникальности, а это она делает. Мне же хотелось, чтобы имена несли смысловую нагрузку. Было бы здорово, если бы в них было записано имя исполняемого файла, имя формы, дата и время возникновения ошибки. Решается данная задача вот таким образом (Fn - переменная строкового типа):


Fn := ExtractFilename(Application.ExeName)+\'_\'+  
Screen.ActiveForm.Name+  
FormatDateTime(\'_ddmmyyyy_hhnnss\',now)+  
\'_debug\';  

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

bmp.SaveToFile(fn+\'.bmp\'); 

Итог - любое исключение в приложении вызовет автоматическую запись скриншота в файл формата BMP. Но, такой графический формат имеет одну неприятную особенность, дельфи умеет работать только с несжатыми файлами, которые благодаря этому имеют большой объем, а мне бы хотелось посылать эти файлы автоматически по e-mail, чтобы всегда быть в курсе ошибок программы.
К счастью, фирма Borland бесплатно приложила к Delphi библиотеку работы с изображениями в формате JPEG. Поищите на компакт-диске с дельфи или на своем жестком диске в каталогах дельфи файлы, начинающиеся с букв "jpeg".
Таким образом, подключаем модуль JPEG после модуля Graphics и пишем вот такой код:

procedure TgsCatcher.DoGenerateScreenshot;  
var bmp: TBitmap;  
    jpg: TJPEGImage;  
begin  
  bmp := Screen.ActiveForm.GetFormImage;  
  begin  
    jpg := TJPEGImage.Create;  
    jpg.CompressionQuality := 100;  
    jpg.Assign(bmp);  
    jpg.SaveToFile(fn+\'.jpg\');  
    FreeAndNil(jpg);  
  end;  
  FreeAndNil(bmp);  
end;  

>Теперь из метода Catcher достаточно просто вызвать метод DoGenerateScreenshot и автоматическое сохранение скриншота в формате JPEG с качеством 100% вам обеспечено.
Теперь, я хотел бы, чтобы генерировался текстовый отчет об ошибке. Это еще проще. Давайте, к примеру, сделаем отчет, в котором будут указаны имя компьютера и имя текущего пользователя. Пишем вот такие функции и процедуры:

function TgsCatcher.CollectUserName: string;  
var  
  uname: pchar;  
  unsiz: cardinal;  
begin  
  uname := StrAlloc(255);  
  unsiz := 254;  
  GetUserName(uname,unsiz);  
  if (unsiz > 0) then  
    Result := string(uname) else  
    Result := \'n/a\';  
  StrDispose(uname);  
end;  

Эта функция запросит у системы имя пользователя при помощи функции API GetUserName, и вернет строку "n/a", если имя пользователя получить не удалось.

function TgsCatcher.CollectComputerName: string;  
var  
  cname: pchar;  
  cnsiz: cardinal;  
begin  
  cname := StrAlloc(MAX_COMPUTERNAME_LENGTH + 1);  
  cnsiz := MAX_COMPUTERNAME_LENGTH + 1;  
  GetComputerName(cname,cnsiz);  
  if (cnsiz > 0) then  
    Result := string(cname) else  
    Result := \'n/a\';  
  StrDispose(cname);  
end;  

Эта функция аналогична функции CollectUserName, только запрашивает имя компьютера.

procedure TgsCatcher.DoCollectInfo(E: Exception);  
var sl: TStringList;  
begin  
  sl := tstringlist.Create;  
  sl.add(\'--- This report is created by automated \'+  
         \'reporting system.\');  
  sl.add(\'Computer name is: [\'+ComputerName+\']\');  
  sl.add(\'User name is: [\'+UserName+\']\');  
  sl.add(\'--- End of report ----------------------\'+  
         \'-----------------\');  
  sl.SaveToFile(Fn+\'.txt\');  
end;  

Последняя процедура создает объект класса TStringList, наполняет его информацией, которую надо записать и сохраняет в файл, с именем, аналогичном имени файла со скриншотом. Остается только прописать вызов этого метода в процедуре Catcher.
Заключение
Вот, собственно и все. Что же мы получили? Мы получили невизуальный компонент, который автоматически подключается к обработчику исключительных ситуаций приложения. При этом, обработчик умеет создавать скриншот активного окна и записывать в текстовый файл интересующие нас параметры. Вроде бы неплохо.

Автор: Григорий Ситнин

Добавлено: 01 Августа 2018 07:06:04 Добавил: Андрей Ковальчук

Добавляем компонент в стандартный Message Dialog

Пример показывает стандартное диалоговое окно, которое обычно используется для подтверждения дальнейших действий в любой программе с галочкой "Don't show this message again".

Используем функцию CreateMessageDialog и добавляем любой компонент до того как будет вызвана ShowModal.

Например:


procedure TForm1.Button1Click(Sender: TObject);   
var   
  AMsgDialog: TForm;   
  ACheckBox: TCheckBox;   
begin   
  AMsgDialog := CreateMessageDialog('This is a test message.',mtWarning, [mbYes, mbNo]);   
  ACheckBox := TCheckBox.Create(AMsgDialog);   
  with AMsgDialog do   
    try   
      Caption := 'Dialog Title';   
      Height := 169;   
   
      with ACheckBox do   
      begin   
        Parent := AMsgDialog;   
        Caption := 'Don''t show me again.';   
        Top := 121;   
        Left := 8;   
      end;   
   
      case ShowModal of   
        ID_YES: ; //здесь Ваш код после того как диалог будет закрыт   
        ID_NO:  ;   
      end;   
   
      if ACheckBox.Checked then   
      begin   
        //...   
      end;   
    finally  
      ACheckBox.Free;  
      Free;  
    end;  
end;

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

Добавлено: 01 Августа 2018 07:04:33 Добавил: Андрей Ковальчук

Непонятные файлы. Откуда?

Наверняка при создании собственных программ в среде разработки delphi вы не раз замечали что помимо обычных .pas, .dpr и exe файлов в директории с программой появляется еще куча непонятных файлов. Сейчас что бы развеять все непонятки я приведу список этих файлов с их описанием:

DPR - файл проекта Delphi. Это главная программа приложения.
~DP - резервный DPR файл. Создается, если включено резервное сохранение.
PAS - исходный код модуля или формы. Главная программа находится в файле DPR.
~PA - резервный PAS файл. Создается, если включено резервное сохранение.
DFM - эти файлы связаны с файлами PAS. DFM - это двоичные файлы в которых содержатся начальные данные для компонент (это те свойства, которые Вы устанавливаете в Object Inspector). Вы не можете редактировать файл DFM текстовым редактором, но если откроете этот файл в Delphi, то увидете текстовую версию его содержимого.
~DF - резервный DFM файл. Создается, если включено резервное сохранение.
DCU - откомпилированный модуль, подобен файлу OBJ.
DSM - файл с информацией используемой внутренним отладчиком. Этот файл создается каждый раз, когда Вы компилируете проект.
OPT - опции проекта. Это настройки компилятора и компоновщика, для данного проекта. Их можно вызвать в меню Options/Project.
RES - файл ресурсов Windows. Создается Delphi автоматически и требуется для компиляции. Вы можете не пользоваться этим файлом, но удалять его не следует.
EXE - откомпилированный проект. Исполняемая Windows-программа.

На этом все!!!

Добавлено: 01 Августа 2018 07:03:49 Добавил: Андрей Ковальчук

Учимся копировать файлы в Delphi

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

Способ номер РАЗ

Для его реализации нам понадобиться создать небольшую процедуру, поэтому после ключевого слова private пишем вот такой код:


procedure MyFileCopy(Const SourceFileName, TargetFileName: String);  

Нажимаем Ctrl+Shift+C как всегда Delphi сгенерирует заготовку для нашей процедуры, посмотри что в итоге получилось у меня и допиши недостающие строчки у себя


procedure MyFileCopy(Const SourceFileName, TargetFileName: String);  
var  
A,F : TFileStream;  
begin  
A := TFileStream.Create(sourcefilename, fmOpenRead );  
try  
F := TFileStream.Create(targetfilename, fmOpenWrite or fmCreate);  
try  
F.CopyFrom(A, A.Size ) ;  
FileSetDate(F.Handle, FileGetDate(A.Handle));  
finally  
F.Free;  
end;  
finally  
A.Free;  
end;  
end;   

Копирование здесь происходит при помощи создания потока, вот пример использования данной процедуры:


Myfilecopy('D:\index.htm', 'D:\1\1.html' );  

Способ номер ДВА

Для его реализации, никаких процедур создавать не нужно, и на мой взгляд этот способ самый простой:
Пример использования:


CopyFile(Pchar('D:\index.txt'), Pchar('D:\1\1.txt'), true)   

На этом всё встретимся в следующих уроках!

Добавлено: 01 Августа 2018 07:02:47 Добавил: Андрей Ковальчук

Динамически (программно) создаем новую форму

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

Ну что поехали

Для начала создаем новый проект и кидаем на форму кнопку (button). Теперь создадим еще одну форму, жмем: File => New => Form
Сделали?.. Тогда создаем обработчик событий (OnClick) на кнопке и в нем пишем:


Form2:= TForm2.Create(Application);  
Form2.Caption:= 'Новое сообщение';  
form2.Show; 

Запускаем проект и Delphi выдает нам вот такое окно, в котором нажимаем yes. ( Если окошко по каким либо причинам не появилось то после ключевого слова implementation допиши вот такую строчку)


uses Unit2;  

динамическое создание формы delphi

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

Добавлено: 01 Августа 2018 07:01:46 Добавил: Андрей Ковальчук

Создаем круглую форму на Delphi

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


procedure CreateParams(var Params: TCreateParams); override;   

Жмем комбинацию клавиш Ctrl+Shift+C

Delphi генерирует пустую процедуру.
Посмотрите что получилось у меня и пропишите то что не хватает у вас.


procedure TForm1.CreateParams(var Params: TCreateParams);  
begin  
inherited CreateParams(Params);  
Params.Style := Params.Style or ws_popup xor ws_dlgframe;  
end; 

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

Полный листинг процедуры OnCreate:


procedure TForm1.FormCreate(Sender: TObject);  
var  
FormRgn: hRgn;  
begin  
Form1.Brush.Style := bsSolid; //bsclear;  
GetWindowRgn(Form1.Handle, FormRgn);  
DeleteObject(FormRgn);  
Form1.Height := 500;  
Form1.Width := Form1.Height;  
FormRgn := CreateRoundRectRgn(1, 1, Form1.Width - 1,  
Form1.height - 1, Form1.width, Form1.height);  
SetWindowRgn(Form1.Handle, FormRgn, TRUE);  
end; 

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

Добавлено: 01 Августа 2018 07:00:16 Добавил: Андрей Ковальчук

Учимся в delphi получать информацию о системе

Сейчас я хочу показать вам как на Delphi быстро и без использования компонентов узнать информацию о системе. Для начала создадим новую форму и бросим на неё: компонент Button (кнопка) и компонент Memo (многострочный редактор) оба с закладки Standart. После чего в обработчик кнопки вставляем следующий код:


procedure TForm1.Button1Click(Sender: TObject);  
var MemoryStatus: TMemoryStatus;  
begin  
Memo1.Lines.Clear;  
MemoryStatus.dwLength := SizeOf(MemoryStatus) ;  
GlobalMemoryStatus(MemoryStatus) ;  
with MemoryStatus  
do  
begin  
Memo1.Lines.Add(IntToStr(dwMemoryLoad) + '% использованно памяти') ;  
Memo1.Lines.Add(IntToStr(dwTotalPhys) +' Всего физической памяти (в байтах)')) ;  
Memo1.Lines.Add(IntToStr(dwAvailPhys) +' Доступно физической памяти (в байтах)')) ;  
Memo1.Lines.Add(IntToStr(dwTotalPageFile) +' Всего виртуальной памяти (в байтах)')) ;  
Memo1.Lines.Add(IntToStr(dwAvailPageFile) +' Доступно виртуальной памяти (в байтах) ')) ;  
Memo1.Lines.Add(IntToStr(dwTotalVirtual) +' Адресное виртуальное простанство текущего процесса')) ;  
Memo1.Lines.Add(IntToStr(dwAvailVirtual) +' Доступно байт виртуального адресного пространства текущего процесса')) ;  
end;  
  
  
end; 

P.S. В данном примере используется API функция GlobalMemoryStatus.

Добавлено: 01 Августа 2018 06:59:32 Добавил: Андрей Ковальчук

Запрещаем форме уезжать за пределы экрана

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

Открываем Delphi, создаем новый проект, после ключевого слова public пишем:


procedure WMMoving(var Msg: TWMMoving); message WM_MOVING;

Далее нажимаем комбинацию клавиш CTRL+SHIFT+C

Delphi создаст шаблон для нашей процедуры. Я её уже дописал, поэтому посмотрите что получилось у меня и добавьте к себе в код недостающие строки:


procedure TForm1.WMMoving(var Msg: TWMMoving);  
var  
workArea: TRect;  
begin  
workArea := Screen.WorkareaRect;  
with Msg.DragRect^ do  
begin  
if Left < workArea.Left then  
OffsetRect(Msg.DragRect^, workArea.Left - Left, 0) ;  
if Top < workArea.Top then  
OffsetRect(Msg.DragRect^, 0, workArea.Top - Top) ;  
if Right > workArea.Right then  
OffsetRect(Msg.DragRect^, workArea.Right - Right, 0) ;  
if Bottom > workArea.Bottom then  
OffsetRect(Msg.DragRect^, 0, workArea.Bottom - Bottom) ;  
end;  
inherited;  
end;  

Вот и все ! Запустите программу и попробуйте перетащить форму за пределы экрана. Если не получиться то значит, вы всё сделали верно!

Добавлено: 01 Августа 2018 06:56:59 Добавил: Андрей Ковальчук

Работаем со StringGrid, подгоняем колонку

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

Поехали..!

Запускаме Delphi и после ключевого слова public пишем


procedure AutoSizeGridColumn(Grid : TStringGrid; column : integer);  

Далее жмем уже полюбившуюся комбинацию клавиш CTRL+SHIFT+C, Delphi генерирует шаблон процедуры. А вот как должна выглядеть эта процедура полностью, посмотрите ниже и допишите то чего хватает.


procedure AutoSizeGridColumn(Grid : TStringGrid; column : integer);  
var  
i : integer;  
temp : integer;  
max : integer;  
begin  
max := 0;  
for i := 0 to (Grid.RowCount - 1) do begin  
temp := Grid.Canvas.TextWidth(grid.cells[column, i]);  
if temp > max then max := temp;  
end;  
Grid.ColWidths[column] := Max + Grid.GridLineWidth + 3;  
end;   

Теперь нам осталось кинуть на форму кнопку (button) и сам компонент StringGrid.

Сделали ... ?! Надеюсь что да !

Создаем обработчик событий на кнопке и в нем прописываем:


AutoSizeGridColumn(StringGrid1, 1);  

Вот и все, компилируем и запускаем.

Добавлено: 01 Августа 2018 06:56:07 Добавил: Андрей Ковальчук

Как проверять корректность доступа к базе данных?

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


function TBDEDirect.CheckDatabase: Boolean;  
var  
  DS: TDataSource;  
begin  
  Result := False;  
  DS := GetDataSource;  
  if DS = nil then  
    begin  
      MessageDlg('Не установлена связь с элементом-источником данных.'+  
        'Проверьте установку свойства DataSource.',  
        mtError, [mbOK], 0);  
      Exit;  
    end;  
  if DS.DataSet = nil then  
    begin  
      MessageDlg('Доступ к базе данных невозможен.', mtError,[mbOK], 0);  
      Exit;  
    end;  
  if TDBDataSet(DS.DataSet).Database = nil then  
    begin  
      MessageDlg('Доступ к базе данных невозможен.', mtError,[mbOK], 0);  
      Exit;  
    end;  
  if TDBDataSet(DS.DataSet).Database.Handle = nil then  
    begin  
      MessageDlg('Дескриптор (Handle) БД недоступен.', mtError,[mbOK], 0);  
      Exit;  
    end;  
  if DS.DataSet.Handle = nil then  
    begin  
      MessageDlg('Дескриптор курсора (Cursor-Handle) недоступен.', mtError,[mbOK], 0);  
      Exit;  
    end;  
  Result := True;  
end;  

Добавлено: 01 Августа 2018 06:55:30 Добавил: Андрей Ковальчук

Что такое #13#10?

Несомненно, вы много раз видели в Delphi-коде нечто "#13#10". Если вы не знаете, что это такое и каждый раз удивляетесь, то здесь вы узнаете ответ.

Тип данных string представляет собой совокупность одного или нескольких символов, каждый из которых записывается в виде символа "#" и числа от 0 до 255 (в десятичной или шестнадцатеричной форме) - каждая такая комбинация обозначает соответствующий ASCII-символ.

К примеру, если вы хотите сделать текст (Caption) элемента TLabel в две строки, то это можно сделать следующим образом:


Label1.Caption := 'Первая строка' + #13#10 + 'Вторая строка';  

Комбинация "#13#10" - это комбинация возврата каретки и символа новой строки. "#13" - это ASCII-эквивалент значения CR (carriage return - возврат каретки); "#10" представляет собой LF (line feed - признак новой строки).

Также наиболее интересными управляющими символами являются:
#0 - NULL-символ (нулевой);
#9 - <Tab> (символ табуляции).

Добавлено: 01 Августа 2018 06:54:54 Добавил: Андрей Ковальчук

Файловые операции с использованием стандартного диалога с анимацией Копирование Файлов

В следующем примере используется функция SHFileOperation для копирования группы файлов и показа анимированного диалога. Вы можете использовать также следующие флаги для копирования, удаления, переноса и переименования файлов. TO_COPY, FO_DELETE, FO_MOVE, FO_RENAME

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


uses ShellAPI;  
  
procedure TForm1.Button1Click(Sender: TObject);   
var   
  Fo      : TSHFileOpStruct;   
  buffer  : array[0..4096] of char;   
  p       : pchar;   
begin   
  FillChar(Buffer, sizeof(Buffer), #0);   
  p := @buffer;   
  p := StrECopy(p, 'C:\DownLoad\1.ZIP') + 1;   
  p := StrECopy(p, 'C:\DownLoad\2.ZIP') + 1;   
  p := StrECopy(p, 'C:\DownLoad\3.ZIP') + 1;   
  StrECopy(p, 'C:\DownLoad\4.ZIP');   
  FillChar(Fo, sizeof(Fo), #0);   
  Fo.Wnd    := Handle;   
  Fo.wFunc  := FO_COPY;   
  Fo.pFrom  := @Buffer;   
  Fo.pTo    := 'D:\';   
  Fo.fFlags := 0;   
  if ((SHFileOperation(Fo) <> 0) or  
    (Fo.fAnyOperationsAborted <> false)) then  
    ShowMessage('Cancelled')   
end;  

Добавлено: 01 Августа 2018 06:54:12 Добавил: Андрей Ковальчук

Проверяем соединение с интернетом

Много статей было написано, много слов было сказано, о том как узнать подключен ли компьютер к интернету или нет. На мой взгляд, самый простой способ это узнать, проверить ip адрес. Если он локальный т.е 127.0.0.1, то соединения с интернетом нет, но если ip адрес отличается от 127.0.0.1 то мы подключены к интернету. Так давайте займемся технической реализации данного метода. Открываем Delphi, создаем новый проект. На форму кидаем компонент TcpClient c закладки Internet (в принципе можно воспользоваться и TcpServer), кнопку (button) с закладки Standart и в обработчике событий OnClick кнопки пишем следующий код:


if tcpClient1.LocalHostAddr <>'127.0.0.1'  
then showmessage('Мы в Интернете!!!')  
else showmessage('Соединение с интернетом отсутствует!!!'); 

Полный листинг процедуры:


procedure TForm1.Button1Click(Sender: TObject);  
begin  
if tcpClient1.LocalHostAddr <>'127.0.0.1'  
then showmessage('Мы в Интернете!!!')  
else showmessage('Соединение с интернетом отсутствует!!!');  
end;  

Добавлено: 01 Августа 2018 06:53:43 Добавил: Андрей Ковальчук

Загружаем в BitBtn картинку формата jpg

Привет всем с вами Владимир Любаев и в этом уроке я хочу рассказать вам, как загрузить на обычную BitBtn или SpeedButton кнопку картинку формата jpg или ico

Итаку начинаем. Создаем новый проект и кидаем на форму компоненты BitBtn и Image оба с закладки Additional. Кликаем два раза по компоненту Image и загружаем в него любую картинку jpg или ico формата.

Так основные приготовления завершены, осталось самое вкусненькое, а именно код.

Создаем обработчик событий OnClick на кнопке, Delphi автоматически сгенерировал шаблон для нашей процедуры, посмотрите теперь как написано у меня и добавьте недостающие строки к себе в код.


procedure TForm1.BitBtn1Click(Sender: TObject);  
VAR  
BMP: TBitmap;  
begin  
BMP:= TBitmap.Create;  
try  
bmp.Width:= Image1.Picture.Graphic.Width;  
bmp.Height:= Image1.Picture.Graphic.Height;  
bmp.Canvas.Draw (0, 0, Image1.Picture.Graphic);  
BitBtn1.Glyph:= BMP;  
finally;  
bmp.Free;  
end;  
end;  

Вот собственно и все, запускаем проект жмем на кнопку. Вуаля.... картинка которая была ранее загруженна в image теперь отображаеться на кнопке!

Добавлено: 01 Августа 2018 06:53:06 Добавил: Андрей Ковальчук

Как создать и использовать новую форму курсора?

Для этого необходимо создать новый курсор(ы) в подходящем для этого редакторе ресурсов (например борландовский Resource Workshop). При этом надо обратить внимание на то что имена в редакторе ресурсов (особенно в том, который поставляется с Delphi) надо писать заглавными буквами. После этого "перед внутренним употреблением" (лучше всего в процедуре обработки события OnCreate главной формы) необходимо загрузить курсор(ы) из res-файла как указано ниже:


{$I CURSOR.RES}  
  
Screen.Cursors[1] := LoadCursor(hInstance, 'CURSOR_1');  
Button1.Cursor := 1; 

Обратите внимание на то, что системные курсоры в Screen.Cursors начинаются с нуля и идут в минусовом направлении. Поэтому при создании новых курсоров лучше выбирать положительные числа (лучше не слишком большие :-)).
Более удобный вариант - это объявить постоянную (равную например 12):


const  
   CUR_HAND = 12;  
  
...  
  
Screen.Cursors[CUR_HAND] := LoadCursor(hInstance, 'CURSOR_HAND');  
Button1.Cursor := CUR_HAND;  

Добавлено: 01 Августа 2018 06:52:35 Добавил: Андрей Ковальчук