Тема: Копирование файла
Пример показывает копирование файла, путь которого указан в верхнем поле ввода, в директорию, указанную в нижнем поле ввода.
При необходимости файловый путь можно выбрать, нажав кнопку "Browse".
▼Исходный код
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 Кб, 50 скачиваний с 2022-02-15
CopyFile.kex 1.86 Кб, 58 скачиваний с 2022-02-15