1

Тема: Копирование файла

Пример показывает копирование файла, путь которого указан в верхнем поле ввода, в директорию, указанную в нижнем поле ввода.
При необходимости файловый путь можно выбрать, нажав кнопку "Browse".
misc.php?action=pun_attachment&item=153&download=0

Исходный код
program CopyFile;

uses
  KolibriOS;

const
  WINDOW_BORDER_SIZE = 5;

// Frame flags
  FR_CAPTION = 1;
  FR_DOUBLE  = 0;
  FR_RAISED  = 2;
  FR_SUNKEN  = 4;
  FR_ETCHED  = 6;
  FR_RIDGED  = 8;
  FR_FILLED  = 16;

// Frame text position
  FR_TEXT_POS_BOTTOM = 1;
  FR_TEXT_POS_TOP    = 0;

type
  TProgressBar = packed record
    Value:         LongWord;
    Left:          LongInt;
    Top:           LongInt;
    Width:         LongWord;
    Height:        LongWord;
    Style:         LongWord;
    Min:           LongWord;
    Max:           LongWord;
    BackColor:     LongWord;
    ProgressColor: LongWord;
    FrameColor:    LongWord;
  end;

  TFrame = packed record
    Style:        LongWord;
    Width:        Word;
    Left:         SmallInt;
    Height:       Word;
    Top:          SmallInt;
    OuterColor:   LongWord;
    InnerColor:   LongWord;
    Flags:        LongWord;
    Text:         PAnsiChar;
    TextPosition: LongWord;
    Font:         LongWord;
    FontHeight:   LongWord;
    ForeColor:    LongWord;
    BackColor:    LongWord;
  end;

  // SizeOf(TEditBoxFlags) must be equal 4 bytes(currently all right),
  // otherwise flags field in edit_box structure will be incorrect
  TEditBoxFlags = set of (edfPassword, edfFocus, edfShift, edfShiftOn, edfShiftBac,
    edfLeft, edfOffset, edfInsert, edfMouse, edfCtrl, edfAlt, edfDisabled,
    edfReserved1, edfReserved2, edfAlwaysFocus, edfNumeric, edfReserved3);

  PEditBox = ^TEditBox;
  TEditBox = packed record
    width:              LongInt;
    left:               LongInt;
    top:                LongInt;
    color:              LongInt;
    shift_color:        LongInt;
    focus_border_color: LongInt;
    blur_border_color:  LongInt;
    text_color:         LongInt;
    max:                LongInt;
    text:               PAnsiChar;
    mouse_variable:     Pointer;
    flags:              TEditBoxFlags;
    size:               LongInt;
    pos:                LongInt;
    offset:             LongInt;
    cl_curs_x:          SmallInt;
    cl_curs_y:          SmallInt;
    shift:              SmallInt;
    shift_old:          SmallInt;
    height:             LongInt;
    char_width:         LongInt;
  end;

var
  BrowseFileFrame: TFrame = (
    Style: 0;
    Width: 297;
    Left: 8;
    Height: 57;
    Top: 13;
    Flags: FR_ETCHED + FR_CAPTION + FR_FILLED;
    Text: 'File path';
    TextPosition: FR_TEXT_POS_TOP;
    Font: 1;
    FontHeight: 16;
  );

  BrowseDirFrame: TFrame = (
    Style: 0;
    Width: 297;
    Left: 8;
    Height: 57;
    Top: 82;
    Flags: FR_ETCHED + FR_CAPTION + FR_FILLED;
    Text: 'Copy to';
    TextPosition: FR_TEXT_POS_TOP;
    Font: 1;
    FontHeight: 16;
  );

  ProgressBar: TProgressBar = (
    Value: 0;
    Left: 8;
    Top: 153;
    Width: 201;
    Height: 16;
    Style: 0;
    Min: 0;
    BackColor: $00FFFFFF;
    ProgressColor: $0000C000;
  );

  Edit1TextBuffer: array [0..4095] of AnsiChar;

  Edit1: TEditBox = (
    width: 209;
    left: 16;
    top: 31;
    color: $00FFFFFF;
    shift_color: $00A4C4E4;
    text_color: 0 + DT_CP866_8X16;
    max: SizeOf(Edit1TextBuffer) - 2);

  Edit2TextBuffer: array [0..4095] of AnsiChar;

  Edit2: TEditBox = (
    width: 209;
    left: 16;
    top: 100;
    color: $00FFFFFF;
    shift_color: $00A4C4E4;
    text_color: 0 + DT_CP866_8X16;
    max: SizeOf(Edit2TextBuffer) - 2);

  EditMV: LongWord;

procedure On_Redraw; forward;

const
// OpenDialog.Mode constants
  ODM_OPEN = 0;
  ODM_SAVE = 1;
  ODM_DIR  = 2;

// OpenDialog.Status constants
  ODS_CANCEL = 0;
  ODS_OK     = 1;
  ODS_ALTER  = 2;

type
// actually structure is:
//   first four bytes - size of this structure
//   and next are zero separated string values
  TOpenDialogFilter = packed record
    Size: LongWord;
    Text: array [0..SizeOf(ShortString) - 1] of AnsiChar;
  end;

  TOpenDialog = packed record
    Mode:           LongWord;
    ProcInfo:       Pointer;
    ComAreaName:    PAnsiChar;
    ComArea:        Pointer;
    OpenDirPath:    PAnsiChar;
    DirDefaultPath: PAnsiChar;
    StartPath:      PAnsiChar;
    DrawWindow:     procedure;
    Status:         LongWord;
    OpenFilePath:   PAnsiChar;
    FileNameArea:   PAnsiChar;
    FilterArea:     ^TOpenDialogFilter;
    XSize:          Word;     // at least 350
    XStart:         SmallInt;
    YSize:          Word;     // at least 250
    YStart:         SmallInt;
  end;

const
  PROC_INFO_BUFFER_SIZE      = SizeOf(TThreadInfo);
  OPEN_FILE_PATH_BUFFER_SIZE = 4096;
  FILE_NAME_AREA_BUFFER_SIZE = 1024;
  OPEN_DIR_PATH_BUFFER_SIZE  = OPEN_FILE_PATH_BUFFER_SIZE - FILE_NAME_AREA_BUFFER_SIZE;

var
  ProcLib: Pointer;
  OpenDialogInit: procedure(var OpenDialog: TOpenDialog); stdcall;
  OpenDialogStart: procedure(var OpenDialog: TOpenDialog); stdcall;

  OpenDialogFilter: TOpenDialogFilter;

  FileNameAreaBuffer: array [0..FILE_NAME_AREA_BUFFER_SIZE - 1] of AnsiChar;
  OpenFilePathBuffer: array [0..OPEN_FILE_PATH_BUFFER_SIZE - 1] of AnsiChar;
  OpenDirPathBuffer: array [0..OPEN_DIR_PATH_BUFFER_SIZE - 1] of AnsiChar;
  ProcInfoBuffer: array [0..PROC_INFO_BUFFER_SIZE - 1] of Byte;

  OpenDialog: TOpenDialog = (
    Mode: ODM_OPEN;
    ProcInfo: @ProcInfoBuffer;
    ComAreaName: 'FFFFFFFF_open_dialog';
    OpenDirPath: @OpenDirPathBuffer[0];
    DirDefaultPath: '/sys';
    StartPath: '/sys/File managers/opendial';
    DrawWindow: On_Redraw;
    OpenFilePath: @OpenFilePathBuffer[0];
    FileNameArea: @FileNameAreaBuffer[0];
    FilterArea: @OpenDialogFilter;
    XSize: 400;
    YSize: 480);

// copy comma separated string values from Filter
// to OpenDialogFilter and replace commas with zeroes
// 'txt,png,bmp' -> 'txt'#0'png'#0'bmp'#0
procedure OpenDialogSetFilter(Filter: PAnsiChar);
var
  i: LongWord;
begin
  i := 0;
  with OpenDialogFilter do
  begin
    Text[High(Text)] := #0;
    repeat
      if Filter[i] = ',' then
        Text[i] := #0
      else
        Text[i] := Filter[i];
      Inc(i);
    until (Filter[i - 1] = #0) or (i = High(Text));
    Size := i + SizeOf(Size);
  end;
end;

var
  BoxLib: Pointer;

  edit_box_draw:     procedure(var EditBox: TEditBox); stdcall;
  edit_box_key:      procedure(var EditBox: TEditBox); stdcall;
  edit_box_mouse:    procedure(var EditBox: TEditBox); stdcall;
  edit_box_set_text: procedure(var EditBox: TEditBox; Text: PAnsiChar); stdcall;
  progressbar_draw:  procedure(var ProgressBar: TProgressBar); stdcall;
  frame_draw:        procedure(var Frame: TFrame); stdcall;

const
// button identifiers
  BUTTON_BROWSE_FILE = 100;
  BUTTON_BROWSE_DIR  = 200;
  BUTTON_START_COPY  = 300;

// status of copying
  COPY_STATUS_EXST = 'File already exist!      ';
  COPY_STATUS_GOOD = 'File copied successfully.';
  COPY_STATUS_COPY = 'Copying...               ';
  COPY_STATUS_FAIL = 'File copying error!      ';

var
  WndLeft, WndTop: LongInt;
  WndWidth: LongWord = 312 + WINDOW_BORDER_SIZE * 2;
  WndHeight: LongWord;
  Key: TKeyboardInput;
  SC: TStandardColors;
  ThreadInfo: TThreadInfo;
  CopyStatus: PAnsiChar = '';

procedure EditBoxKey(var EditBox: TEditBox; Key: TKeyboardInput);
begin
  asm mov eax, Key end;
  edit_box_key(EditBox);
end;

procedure BrowseFile;
begin
  OpenDialog.Mode := ODM_OPEN;
  OpenDialogStart(OpenDialog);
  if OpenDialog.Status = ODS_OK then
  begin
    edit_box_set_text(Edit1, OpenDialog.OpenFilePath);
    edit_box_draw(Edit1);
  end;
end;

procedure BrowseDir;
begin
  OpenDialog.Mode := ODM_DIR;
  OpenDialogStart(OpenDialog);
  if OpenDialog.Status = ODS_OK then
  begin
    edit_box_set_text(Edit2, OpenDialog.OpenFilePath);
    edit_box_draw(Edit2);
  end;
end;

procedure StartCopy;
const
  LOG2_BUFFER_SIZE = 16; // 2^16 = 64K; work with (shl\shr power of 2) is more handy
var
  NumRead, NumWritten: LongWord;
  FilePos: Int64;
  BufferSize, Err: LongInt;
  CopyBuffer: Pointer;
  FileAttributes: TFileAttributes;
  FileName: PAnsiChar;
  IsEOF: Boolean;
begin
  Edit1.flags := Edit1.flags + [edfDisabled];
  Edit2.flags := Edit2.flags + [edfDisabled];
  edit_box_draw(Edit1);
  edit_box_draw(Edit2);
  // get just FileName of whole FilePath
  FileName := Edit1.Text;
  while FileName^ <> #0 do Inc(FileName);
  while FileName^ <> '/' do Dec(FileName);
  Inc(FileName);
  // calculate ProgressBar.Max
  GetFileAttributes(Edit1.Text, FileAttributes);
  ProgressBar.Max := FileAttributes.Size shr LOG2_BUFFER_SIZE + 1;
  ProgressBar.Value := 0;
  progressbar_draw(ProgressBar);
  // goto Directory entered in Edit2.Text
  SetCurrentDirectory(Edit2.Text);
  if GetFileAttributes(FileName, FileAttributes) <> 0 then // if not file already exist
  begin
    CopyStatus := COPY_STATUS_COPY;
    DrawText(8, 172, CopyStatus, SC.WorkText, SC.Work, DT_CP866_8X16 + DT_FILL_OPAQUE + DT_ZSTRING, 0);
    // try to create new file
    if CreateFile(FileName) = 0 then
    begin
      FilePos := 0;
      BufferSize := 1 shl LOG2_BUFFER_SIZE;
      // allocate memory for copy buffer
      CopyBuffer := HeapAllocate(BufferSize);
      IsEOF := False;
      // read\write loop
      repeat
        // try to read part of file
        Err := ReadFile(Edit1.Text, CopyBuffer^, BufferSize, FilePos, NumRead);
        IsEOF := Err = 6{EOF};
        if (Err = 0) or IsEOF then
          // try to write part of file
          Err := WriteFile(FileName, CopyBuffer^, NumRead, FilePos, NumWritten);
        // handle possible redraw and button close event
        case CheckEvent of
          REDRAW_EVENT:
            On_Redraw;
          BUTTON_EVENT:
            if GetButton.ID = 1 then
              TerminateThread;
        end;
        // size of source file can be changed while copying! rare case, but...
        // therefore recalculate ProgressBar.Max
        GetFileAttributes(Edit1.Text, FileAttributes);
        ProgressBar.Max := FileAttributes.Size shr LOG2_BUFFER_SIZE + 1;
        ProgressBar.Value := FilePos shr LOG2_BUFFER_SIZE;
        progressbar_draw(ProgressBar);
        // change position in file
        Inc(FilePos, BufferSize);
      until IsEOF or (Err <> 0) or (NumRead = 0) or (NumWritten <> NumRead);
      // check errors, note that EOF is normal loop ending
      if (Err = 0) and IsEOF then
      begin
        CopyStatus := COPY_STATUS_GOOD;
        ProgressBar.Value := ProgressBar.Max;
        progressbar_draw(ProgressBar);
      end
      else
        CopyStatus := COPY_STATUS_FAIL;
      // free memory for copy buffer
      HeapFree(CopyBuffer);
    end
    else
      CopyStatus := COPY_STATUS_FAIL;
  end
  else
    CopyStatus := COPY_STATUS_EXST;
  Edit1.flags := Edit1.flags - [edfDisabled];
  Edit2.flags := Edit2.flags - [edfDisabled];
  edit_box_draw(Edit1);
  edit_box_draw(Edit2);
  DrawText(8, 172, CopyStatus, SC.WorkText, SC.Work, DT_CP866_8X16 + DT_FILL_OPAQUE + DT_ZSTRING, 0);
end;

procedure On_Redraw;
begin
  BeginDraw;
  GetStandardColors(SC, SizeOf(TStandardColors));
  GetThreadInfo($FFFFFFFF, ThreadInfo);
  WndHeight := 187 + GetSkinHeight + WINDOW_BORDER_SIZE;
  DrawWindow(WndLeft, WndTop, WndWidth, WndHeight, 'Copy file', SC.Work,
    WS_SKINNED_FIXED + WS_CLIENT_COORDS + WS_CAPTION, CAPTION_MOVABLE);
  BrowseFileFrame.BackColor := SC.Work;
  BrowseDirFrame.BackColor := SC.Work;
  BrowseFileFrame.ForeColor := SC.WorkText;
  BrowseDirFrame.ForeColor := SC.WorkText;
  BrowseFileFrame.OuterColor := SC.Work3DLight;
  BrowseDirFrame.OuterColor := SC.Work3DLight;
  BrowseFileFrame.InnerColor := SC.Work3DDark;
  BrowseDirFrame.InnerColor := SC.Work3DDark;
  frame_draw(BrowseFileFrame);
  frame_draw(BrowseDirFrame);
  DrawButton(232, 25, 65, 33, SC.WorkButton, 0, BUTTON_BROWSE_FILE);
  DrawText(242, 35, 'Browse', SC.WorkButtonText, 0, DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
  DrawButton(232, 94, 65, 33, SC.WorkButton, 0, BUTTON_BROWSE_DIR);
  DrawText(242, 104, 'Browse', SC.WorkButtonText, 0, DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
  DrawButton(216, 144, 89, 33, SC.WorkButton, 0, BUTTON_START_COPY);
  DrawText(221, 154, 'Start copy', SC.WorkButtonText, 0, DT_CP866_8X16 + DT_TRANSPARENT_FILL + DT_ZSTRING, 0);
  DrawText(8, 172, CopyStatus, SC.WorkText, SC.Work, DT_CP866_8X16 + DT_FILL_OPAQUE + DT_ZSTRING, 0);
  Edit1.blur_border_color := SC.Work xor $FF000000;
  Edit1.focus_border_color := SC.WorkGraph;
  Edit2.blur_border_color := SC.Work xor $FF000000;
  Edit2.focus_border_color := SC.WorkGraph;
  edit_box_draw(Edit1);
  edit_box_draw(Edit2);
  ProgressBar.FrameColor := SC.WorkGraph;
  progressbar_draw(ProgressBar);
  EndDraw;
end;

begin
  ProcLib := LoadLibrary('/sys/lib/proc_lib.obj');
  BoxLib  := LoadLibrary('/sys/lib/box_lib.obj');

  OpenDialogInit    := GetProcAddress(proclib, 'OpenDialog_init');
  OpenDialogStart   := GetProcAddress(proclib, 'OpenDialog_start');
  frame_draw        := GetProcAddress(BoxLib, 'frame_draw');
  progressbar_draw  := GetProcAddress(BoxLib, 'progressbar_draw');
  edit_box_draw     := GetProcAddress(BoxLib, 'edit_box');
  edit_box_key      := GetProcAddress(BoxLib, 'edit_box_key');
  edit_box_mouse    := GetProcAddress(BoxLib, 'edit_box_mouse');
  edit_box_set_text := GetProcAddress(BoxLib, 'edit_box_set_text');

  OpenDialogInit(OpenDialog);
  // it is possible to set file extensions if you want
  //OpenDialogSetFilter('txt,png,dat');

  with GetScreenSize do
  begin
    WndHeight := 187 + GetSkinHeight + WINDOW_BORDER_SIZE;
    WndLeft := (Width - WndWidth) div 2;
    WndTop := (Height - WndHeight) div 2;
  end;

  Edit1.text := Edit1TextBuffer;
  Edit2.text := Edit2TextBuffer;
  Edit1.mouse_variable := @EditMV;
  Edit2.mouse_variable := @EditMV;

  SetEventMask(EM_REDRAW + EM_KEY + EM_BUTTON + EM_MOUSE);

  while True do
    case WaitEvent of
      REDRAW_EVENT:
        On_Redraw;
      KEY_EVENT:
        begin
          Key := GetKey;
          EditBoxKey(Edit1, Key);
          EditBoxKey(Edit2, Key);
        end;
      MOUSE_EVENT:
        if GetActiveWindow = GetSlotById(ThreadInfo.Identifier) then
        begin
          edit_box_mouse(Edit1);
          edit_box_mouse(Edit2);
        end;
      BUTTON_EVENT:
        case GetButton.ID of
          BUTTON_BROWSE_FILE:
            BrowseFile;
          BUTTON_BROWSE_DIR:
            BrowseDir;
          BUTTON_START_COPY:
            StartCopy;
        else
          Break;
        end;
    end;
end.

Также прикладываю скомпилированное приложение CopyFile.kex

Post's attachments

CopyFile_Copying.PNG, 5.85 Кб, 323 x 217
CopyFile_Copying.PNG 5.85 Кб, 50 скачиваний с 2022-02-15 

Иконка вложений CopyFile.kex 1.86 Кб, 58 скачиваний с 2022-02-15