Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.02.12;
Скачать: [xml.tar.bz2];

Вниз

Информация о ходе копирования файлов   Найти похожие ветки 

 
Goast   (2006-01-17 14:53) [0]

Здравствуйте мастера!!!!  У меня программа должна ОДНОВРЕМЕННО копировать на несколько компьютеров один и тот же файл. Адреса компьютеров у меня находятся в StringGrid. В принципе я уже это реализовал:
type
tmythread1=class(tthread)
 private
   { Private declarations }
 protected
 procedure execute; override;
end;

var
t1:tmythread1;

procedure tmythread2.execute;
begin

    CopyFileEx(pchar(otkyda),pchar(kyda),@Progress,nil,nil,0);
end;

Нажимаем на кнопочку!!!!!

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
t1:=tmythread1.Create(false);
t1.Priority:=tplowest;
end;

все работает файлы ОДНОВРЕМЕННО копируются на все компы по списку .ИИИИИИИ наконец вопрос!!!!…:) Как мне сделать так что бы напротив компьютера(в stringGrid) писалось бы сколько процентов скопировано???????????? Спасибо всем!!!!


 
Goast   (2006-01-17 15:39) [1]

я не понятно обьяснил что или??? или просто вопрос глупый???? только честно....;)


 
begin...end ©   (2006-01-17 15:48) [2]

Вы же указали callback-функцию Progress в качестве параметра CopyFileEx. Внутри неё и обрабатывайте информацию о том, какая часть файла уже скопирована.

Функция должна быть объявлена так:

function Progress(
 TotalFileSize: Int64,
 TotalBytesTransferred: Int64,
 StreamSize: Int64,
 StreamBytesTransferred: Int64,
 dwStreamNumber: Cardinal,
 dwCallbackReason: Cardinal,
 hSourceFile: Cardinal,
 hDestinationFile: Cardinal,
 lpData: Pointer
): Cardinal; stdcall;

TotalFileSize -- общий размер файла (в байтах), TotalBytesTransferred -- количество скопированных байтов. Делим второе на первое, и получаем проценты.


 
Goast   (2006-01-17 15:52) [3]


> begin...end ©   (17.01.06 15:48) [2]

да да до этого я только что дошел..но новая проблема!!!!
form1.Tb.stringGrid[1,???????????]:=inttostr(Round((TotalBytesTransferred.QuadPart/TotalFileSize.QuadPart)*100));
вот так он показывает сколько он скопировал но как мне узнать в какую ячейку мне это записывать т.е. при выполнении этой функции какой именно файл он скопировал....я надеюсь вы меня поняли....


 
Zeqfreed ©   (2006-01-17 15:59) [4]

Goast   (17.01.06 15:52) [3]
Последний аргумент lpData предназначен как раз для передачи необходимых данных в ф-цию обратного вызова.


 
Goast   (2006-01-17 16:08) [5]


> Zeqfreed ©   (17.01.06 15:59) [4]
> Goast   (17.01.06 15:52) [3]
> Последний аргумент lpData предназначен как раз для передачи
> необходимых данных в ф-цию обратного вызова.

ну друзья...я еще такой зеленый в delphi....можно конкретный пример как использовать это параметр...плз


 
Zeqfreed ©   (2006-01-17 17:03) [6]

Goast   (17.01.06 16:08) [5]

type
 TAnyData = record
  Row, Col : Cardinal;
 end;

 TCopyThread = class(TThread)
 private
  FSrc, FDst : String;
  FData : TAnyData;
 public
  constructor Create(CreateSuspended : Boolean; const Row, Col : Cardinal; const Src, Dst : String);
  procedure Execute; override;
 end;

. . .

function UpdateProgress(TotalFileSize, TotalBytesTransferred, StreamSize, StreamBytesTransferred: Int64;
                              dwStreamNumber, dwCallbackReason, hSourceFile, hDestinationFile : Cardinal; lpData: Pointer) : Cardinal; stdcall;
begin
 Form1.Memo1.Lines.Add(Format("A portion of file copied. Row: %d; Col: %d", [TAnyData(lpData^).Row, TAnyData(lpData^).Col]));
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 TCopyThread.Create(false, 2, 4, "C:\1.jpg", "C:\2.jpg");
 TCopyThread.Create(false, 3, 4, "C:\1.jpg", "C:\3.jpg");
 TCopyThread.Create(false, 4, 4, "C:\1.jpg", "C:\4.jpg");
end;

{ TCopyThread }

constructor TCopyThread.Create(CreateSuspended : Boolean; const Row, Col : Cardinal; const Src, Dst : String);
begin
 inherited Create(CreateSuspended);

 FData.Row := Row;
 FData.Col := Col;

 FSrc := Src;
 FDst := Dst;
end;

procedure TCopyThread.Execute;
begin
 FreeOnTerminate := true;
 CopyFileEx(PChar(FSrc), PChar(FDst), @UpdateProgress, @FData, nil, COPY_FILE_FAIL_IF_EXISTS);
end;


Примерно так. Думаю, разберетесь :)


 
Goast   (2006-01-17 17:13) [7]

блин....:( теперь я точно запутался....я думал вы мне про аргумент lpData расскажите и все...а тут такой текст....:( ну попробую разобраться конечно


 
Zeqfreed ©   (2006-01-17 17:38) [8]

Goast   (17.01.06 17:13) [7]

> я думал вы мне про аргумент lpData расскажите и все

Я решил, что памагать — так по полной :)
Хорошо, рассказываю как оно все работает.


> TAnyData = record
>  Row, Col : Cardinal;
>  end;

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


>TCopyThread = class(TThread)
> private
>  FSrc, FDst : String;
>  FData : TAnyData;
> public
>   constructor Create(CreateSuspended : Boolean; const
>Row, Col : Cardinal; const Src, Dst : String);
>  procedure Execute; override;
>  end;

Описываем класс-наследник TThread, который, собственно выполняет копирование файла в потоке. В классе присутствуют три поля: имя файла-источника (FSrc), имя файла-приемника (FDst) и те данные, которые нам потребуются для индентификации ячейки. Таким образом для каждого потока, а, соответственно, для каждого копируемого файла, мы сможем указать отдельную ячейку. Конструктор класса позволяет задать все эти поля необходимыми значениями, все как обычно.


> function UpdateProgress(...

Наша ф-ция обратного вызова. Вызывается системой, когда та скопирует часть файла (данные о скопированной части передаются в параметрах ф-ции). Одним из параметров ф-ции (lpData) мы получим указатель на те данные, которые сами укажем при вызове CopyFileEx.


>procedure TCopyThread.Execute;

Здесь мы передаем ранее заполненную (в TCopyThread.Create) запись в качестве параметра CopyFileEx и затем получим эти же данные (точнее, указатель на них) в ф-ции обратного вызова.

Вроде, все понятно объяснил :)


 
Defunct ©   (2006-01-18 02:36) [9]

> Zeqfreed ©   (17.01.06 17:38) [8]

Вместо указателя на TAnyData лучше задавать указатель на поле, в которое требуется занести "процент выполнения", чтобы OnDrawCell оставалось только пробежаться по требуемым полям и вывести результат.

Imho, ваш пример хороший, но возможно будет работать с ошибками если вместо memo взять хотя бы canvas, т.к. UpdateProgress, если я не ошибаюсь, работает в контексте того потока который вызвал CreateFileEx.


 
Goast   (2006-01-18 11:03) [10]


> Defunct ©   (18.01.06 02:36) [9]
> > Zeqfreed ©   (17.01.06 17:38) [8]
>
> Вместо указателя на TAnyData лучше задавать указатель на
> поле, в которое требуется занести "процент выполнения",
> чтобы OnDrawCell оставалось только пробежаться по требуемым
> полям и вывести результат.
>
> Imho, ваш пример хороший, но возможно будет работать с ошибками
> если вместо memo взять хотя бы canvas, т.к. UpdateProgress,
>  если я не ошибаюсь, работает в контексте того потока который
> вызвал CreateFileEx.

блин ну нечего не понимаю....:((((((( ну если вам не трудно можно пример что надо написать именно для моего кода который я выложел в начале.....
з.ы. только не глумится надо мной....:)


 
Zeqfreed ©   (2006-01-18 11:41) [11]

Defunct ©   (18.01.06 2:36) [9]

> Вместо указателя на TAnyData лучше задавать указатель
> на поле, в которое требуется занести "процент
> выполнения", чтобы OnDrawCell оставалось только
> пробежаться по требуемым полям и вывести результат.

Да, пожалуй, так было бы удобней.

> Imho, ваш пример хороший, но возможно будет работать с
> ошибками если вместо memo взять хотя бы canvas, т.к.
> UpdateProgress, если я не ошибаюсь, работает в
> контексте того потока который вызвал CreateFileEx.

Действительно, результаты теста показали, что callback-функция выполняется в контексте того потока, в котором была вызвана CopyFileEx. Лучше, наверное, будет поместить участок обновления прогресса в критическую секцию. А пример мой хорошим назвать трудно, хотя бы потому, что в UpdateProgress я забыл вернуть значение и ф-ция возвращает мусор :)

Goast   (18.01.06 11:03) [10]
Лучше, скажите, что конкретно не понятно. Попытайтесь составить свой код для своей ситуации по предложенному примеру и опубликуйте здесь. Думаю, Вам помогут разобраться.


 
KA_ ©   (2006-01-18 15:14) [12]


> Лучше, наверное, будет поместить участок обновления прогресса
> в критическую секцию.


Для этого предусмотрем метод TThread.Synchronize


 
Zeqfreed ©   (2006-01-18 17:44) [13]

KA_ ©   (18.01.06 15:14) [12]
Метод Synchronize предусмотрен для выполнения какого-либо метода в контексте основного потока. Таким образом, если выполнить CopyFileEx через метод Synchronize, то возможность единовременного копирования файлов и целесообразность использования потоков пропадет. Заставить же систему вызвать ф-цию обратного вызова в контексте основного потока невозможно, насколько я понимаю. Да и вовсе не нужно.


 
KA_ ©   (2006-01-19 15:20) [14]


> Метод Synchronize предусмотрен для выполнения какого-либо
> метода в контексте основного потока.


Я так поня, что Form1 находится в основном потоке. Поэтому участок обновления прогресса лучше вызывать через Synchronize.


>Таким образом, если
> выполнить CopyFileEx через метод Synchronize, то возможность
> единовременного копирования файлов и целесообразность использования
> потоков пропадет.


Скорость копирования упадет - т.к. время будет теряться при синхронизации с главным потоком.


>Заставить же систему вызвать ф-цию обратного
> вызова в контексте основного потока невозможно, насколько
> я понимаю. Да и вовсе не нужно.


Очень даже можно - для этого есть метод Synchronize :)


 
Zeqfreed ©   (2006-01-19 17:25) [15]

KA_ ©   (19.01.06 15:20) [14]

> Я так поня, что Form1 находится в основном потоке.
> Поэтому участок обновления прогресса лучше вызывать
> через Synchronize.

Ф-ция обратного вызова вызывается системой в контексте того процесса, в котором была вызвана CopyFileEx. Если вызывать CopyFileEx через Synchronize, то копирование файлов будет происходить последовательно, так как будет проходить по сути в одном потоке (основном).


> Скорость копирования упадет - т.к. время будет
> теряться при синхронизации с главным потоком.

Скорость копирования упадет, потому что копирование файлов будет происходить последовательно, так как будет проходить по сути в одном потоке (основном).


> Очень даже можно - для этого есть метод Synchronize :)

Ф-ция обратного вызова вызывается системой, а не пользователем и вызвать её через Synchronize, разумеется, нельзя.


 
KA_ ©   (2006-01-20 12:13) [16]

Наверное, я коряво объяснил свою мысль.
Я имел в виду, что компоненты VCL не являются потокобезопасными.
Поэтому для обращения к ним из других потоков желательно использовать метод TThread.Synchronize. При этом для синхронизации потоков используется критическая секция и событие.

Callback должен обновить компоненты на форме, соотвественно сделать он должен это в контексте главного потока (т.к. форма с компонентами в главном потоке).
Конечно, callback вызывается в контектсе потока, запустившего копирование. Но внутри callback"а мы должны будем синхронизировать этот поток с главным. Для этого и используется метод Synchronize, хотя никто нам не может запретить использовать свои средства синхронизации.

Естественно, копирование будет происходить последовательно, т.к. каждый поток будет синхронизироваться с главным и обновлять в нем компоненты.
Копипрование не будет происходить в главном потоке - в нем только обновление компонентов.


 
Zeqfreed ©   (2006-01-20 15:41) [17]

KA_ ©   (20.01.06 12:13) [16]
Кажется я понял, что Вы имеете в виду. Вы предлагаете вызывать Synchronize уже из самой ф-ции обратного вызова? Тогда да, это можно использовать для синхронизации.


 
KA_ ©   (2006-01-23 09:54) [18]

Абсолютно верно.



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.02.12;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.51 MB
Время: 0.036 c
3-1134387258
Wolferio
2005-12-12 14:34
2006.02.12
Управление базами


15-1137658991
RDA
2006-01-19 11:23
2006.02.12
AutomatedQA.AQTime


15-1136730093
Kerk
2006-01-08 17:21
2006.02.12
Видел только что НЛО.


15-1137929437
Хинт
2006-01-22 14:30
2006.02.12
Экспортируемые dll функции


15-1137596780
Джо
2006-01-18 18:06
2006.02.12
Цитата





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский