Đề tài TTcopy - Chương trình tăng tốc copy

Theo Microsoft, cơ chế đọc ghi của Windows thực hiện tức thì khi đang đọc file, điều này giảm khả năng thất thoát dữ liệu nhưng cũng đồng thời làm chậm đi tốc độ ghi file. Do vậy để cải thiện tốc độ ghi file thì ta phải sử dụng buffer. Buffer là 1 mảng kiểu byte dùng làm trung gian giữa việc đọc file nguồn và ghi file đích. Việc lựa chọn kích thước của buffer rất quan trọng và nó có ảnh hưởng rất lớn tới tốc độ ghi file. Và kích thước của buffer thường được chọn dựa vào kích thước của file nguồn. Việc sử dụng buffer trong ghi file cũng giống như việc bạn chọn 1 cái “gáu” để chuyển “nước” từ “máy nước” này sang cái khác. Bạn cũng có thể chuyền “nước” trực tiếp nhưng rõ ràng có cái “gáu” sẽ tốt hơn. Và sự tương quan về kích thước của cái “gáu”, “máy nước” và “sức” của người chuyển rất quan trọng, nếu cái “gáu” quá nhỏ hay quá lớn thì cũng làm chậm việc chuyển “nước”.

doc23 trang | Chia sẻ: tuandn | Lượt xem: 1954 | Lượt tải: 3download
Bạn đang xem trước 20 trang tài liệu Đề tài TTcopy - Chương trình tăng tốc copy, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
ĐH QUỐC GIA TP.HỒ CHÍ MINH TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN Báo cáo đề tài: TTCOPY CHƯƠNG TRÌNH TĂNG TỐC COPY Môn: Lập Trình Trên Windows GVHD: Trần Trung Ngôn 08520257 Nguyễn Quang Duy Trang 08520420 Phan Văn Thông 08520392 Trần Thanh Tùng 08520456 Lê Thị Xuyến 08520 MỤC LỤC I.Giới thiệu 3 II.Kĩ thuật quan trọng 4 1. Ghi file dùng buffer 4 a. Tại sao phải dùng buffer để ghi file b. Thuật toán 2. Checksum CRC32 10 a. CRC32 là gì b. Cách tính mã CRC32 c. CRC32 trong TTCopy d. Nút Test 3. Drag và Drop 13 4. Custom Controls 17 a. Custom Progressbar b. Custom CheckBox 5. Run as admin 20 6. Integration with Ctrl+C/Ctrl+X/Ctrl+V 22 III.Kết luận và hướng phát triển 23 GIỚI THIỆU Nếu ai đó phải copy một file có “sức nặng ngàn cân” lên đến vài Gb bằng trình copy mặc định của Windows thì việc chờ đợi có lẽ là cả một cực hình. Sau khi copy file làm sao biết được file vừa copy xong có sử dụng được hay không (tức là có lổi xãy ra trong quá trình copy không)?. Việc copy “giữa đường gãy gánh” khi không đủ dung lượng trống khiến bạn điên đầu! Bạn muốn tạm dừng việc copy/move giữa chừng theo ý của bạn do phải làm việc khác... TTCopy sẽ giúp bạn giải quyết vấn đề! Vậy TTCopy có gì? Giao diện thân thiện dễ sử dụng: TTCopy copy/move file thông qua buffer, có 2 lựa chọn: + Cho phép người sử dụng tự hiệu chỉnh buffer thích hợp trong khi copy/move. Khi copy/move một lúc nhiều file dung lượng mổi file khác nhau, + Auto-buffer mode sẽ linh hoạt hiệu chỉnh buffer phù hợp trên dung lượng file đang thực thi TTCopy hổ trợ kiểm tra lỗi bằng việc so sánh mã checksum file CRC32. Nhờ vậy người dùng biết được file sau khi copy có xãy ra lổi hay không? TTCopy với các tùy chọn linh hoạt trong khi copy/move như: copy, move, pause, resume, close, shutdown when done, test, run as admin. KĨ THUẬT QUAN TRỌNG GHI FILE SỬ DỤNG BUFFER Tại sao phải sử dụng Buffer ? Theo Microsoft, cơ chế đọc ghi của Windows thực hiện tức thì khi đang đọc file, điều này giảm khả năng thất thoát dữ liệu nhưng cũng đồng thời làm chậm đi tốc độ ghi file. Do vậy để cải thiện tốc độ ghi file thì ta phải sử dụng buffer. Buffer là 1 mảng kiểu byte dùng làm trung gian giữa việc đọc file nguồn và ghi file đích. Việc lựa chọn kích thước của buffer rất quan trọng và nó có ảnh hưởng rất lớn tới tốc độ ghi file. Và kích thước của buffer thường được chọn dựa vào kích thước của file nguồn. Việc sử dụng buffer trong ghi file cũng giống như việc bạn chọn 1 cái “gáu” để chuyển “nước” từ “máy nước” này sang cái khác. Bạn cũng có thể chuyền “nước” trực tiếp nhưng rõ ràng có cái “gáu” sẽ tốt hơn. Và sự tương quan về kích thước của cái “gáu”, “máy nước” và “sức” của người chuyển rất quan trọng, nếu cái “gáu” quá nhỏ hay quá lớn thì cũng làm chậm việc chuyển “nước”. byte[] Buffer = new byte[buffer * 1024]; //Khởi tạo buffer TTCopy có 2 chế độ chỉnh kích thước buffer Autobuffer: chương trình sẽ tự động điều chỉnh kích thước buffer cho phù hợp với kích thước file nguồn. Tự chọn: người dùng có thể tự điều chỉnh kích thước buffer theo ý mình thông qua TrackBar b. Thuật toán - Bước 1: Kiểm tra + Folder rỗng + Đường dẫn file nguồn và đích trùng nhau: không làm gì | hoặc tự đổi tên + Nếu file đã tồn tại tại nơi lưu: xử lý lựa chọn Overwrite|Overwrite All, Rename|Rename All, Skip|Skip All. Code VD: //Nếu đường dẫn nguồn kết thúc là * = file ảo, không cần copy File ảo dùng để xác định folder rỗng hay không nên chỉ copy folder rỗng if (s.EndsWith("*")) return 0; //Nếu trùng đường dẫn thì không cần copy if (s == d) return 0; //Nếu file đã tồn tại if (File.Exists(d)) { xử lý lựa chọn Overwrite|Overwrite All, Rename|Rename All, Skip|Skip All. } Bước 2: + Khai báo 2 biến FileStream dùng để đọc file nguồn và ghi file đích + Lấy giá trị buffer: Auto-buffer: chương trình chọn giá trị buffer size dựa vào dung lương file đang thực thi Tự chọn: lấy giá trị từ TrackBar vào làm buffer size + Khai báo biến lấy độ dài của file nguồn và buffer Code VD: FileStream dtn, src; try { src = new FileStream(s, FileMode.Open, FileAccess.Read); //Mở đọc file gốc bằng file stream } int buffer; long mbyte; if (autobuffchk.value == true)//Nếu có tùy chọn Auto buffer { mbyte = 16;//Mặc định dùng 16MB if (src.Length < 10 * 1024 * 1024) mbyte = 1; //file dưới 10MB dùng buffer 1MB else if (src.Length < 50 * 1024 * 1024) mbyte = 2; //file dưới 50MB dùng buffer 2MB else if (src.Length < 100 * 1024 * 1024) mbyte = 4; //file dưới 100MB dùng buffer 4MB mbyte = mbyte * 1024;//Chuyển sang Byte buffer = (int)(mbyte);//Gán giá trị buffer } else//tự chọn buffer { mbyte = getbuffsize();//Lấy giá trị buffer từ trackbar buffer = (int)getbuffsize();//Gán giá trị buffer } byte[] Buffer = new byte[buffer * 1024];//Khởi tạo buffer long LengthCurrent = src.Length;//Lấy kích thước file long LengthBuffer = Buffer.Length;//Lấy kích thước buffer try { dtn = new FileStream(d, FileMode.Create, FileAccess.Write); //Mở file đích để ghi } Bước 3: Copy + File nguồn nhỏ hơn buffer size: Resize buffer bằng với file nguồn Đọc file nguồn vào buffer Ghi vào file đích từ buffer + File nguồn lớn hơn buffer: Đọc file nguồn vào buffer, ghi vào file đích từ buffer Nếu phần còn lại của file nguồn nhỏ hơn buffer size thì resize buffer bằng phần còn lại đó. Code VD: if (LengthCurrent <= LengthBuffer) //Nếu dung lượng file nhỏ hơn buffer { Array.Resize(ref Buffer, (int)LengthCurrent); src.Read(Buffer, 0, Buffer.Length); dtn.Write(Buffer, 0, Buffer.Length); } else//Nếu dung lượng file lớn hơn buffer { for (int i = 0; i < src.Length; i += Buffer.Length) { LengthCurrent -= Buffer.Length; //Giảm độ dài file chưa copy if (LengthCurrent < 0) //Nếu độ dài file còn lại nhỏ hơn buffer thì resize lại cho vừa Array.Resize(ref Buffer, (int)(LengthBuffer + LengthCurrent)); src.Read(Buffer, 0, Buffer.Length); dtn.Write(Buffer, 0, Buffer.Length); } } Đi kèm với việc ghi file bằng buffer thì ta có những giải quyết kèm theo: Thay đổi buffer lập tức khi chỉnh TrackBar (ngay cả trong lúc copy file): trong lúc copy kiểm tra xem giá trị thanh TrackBar có thay đổi không? nếu có thì resize lại buffer CodeVD: if (getbuffsize() != Buffer.Length) {//getbuffersize là hàm lấy giá trị tư TrackBar LengthBuffer = getbuffsize()*1024; Array.Resize(ref Buffer, (int)(LengthBuffer)); } Tính tốc độ copy: trong thời gian >=1s thì lấy dung lượng hiện tại trừ dung lượng lúc trước rồi chia cho khoảng thời gian đó. if (DateTime.Now.Subtract(dtStart).Seconds >= 1) { //Tính toán tốc độ copy file this.Text = "Copying - " + (((i - dtStartByte) / 1024 / 1024) / (DateTime.Now.Subtract(dtStart).Seconds)) + "MB/s"; dtStart = DateTime.Now; dtStartByte = i; } Copy thuộc tính của file (folder): trong quá trình copy file hay folder ta cũng tiến hành copy thuộc tính của chúng CodeVD: private void copy_attr(string s,string d) { DirectoryInfo sF = new DirectoryInfo(s); DirectoryInfo dF = new DirectoryInfo(d); dF.Attributes = sF.Attributes; } Pause and Resume: Trong quá trình copy/move ta có thể pause và resume lại bất cứ lúc nào. Khi pause thì tiểu trình đảm nhận công việc copy/move sẽ tạm dừng, chờ đến khi giá trị onpause=false thì tiếp tục hoặc có lệnh chờ thoát thì kết thúc tiến trình. Trạng thái pause: Resume sau khi pause: Trong quá trình copy nếu ổ đĩa thiếu dung lượng thì chương trình sẽ tự động pause và auto-resume khi ổ đĩa trống. Việc pause chỉ đơn giản sử dụng vòng lặp while, nếu kiểm tra thấy ổ cứng đã đủ dung lượng thì tiếp tục công việc. Khi copy(move) cùng ổ đĩa thì ta không dùng buffer, ta sử dụng hàm Move trong lớp File có sẵn: File.Move(s, d); Nhưng tại sao không dùng buffer? vì trong cùng phân vùng hàm File.Move thực tế là nó không move file mà chỉ sửa sector để thay đổi đường dẫn thôi, vì vậy không cần thiết phải copy và xóa file gốc để thực hiện move. KIỂM TRA LỖI CRC32 CRC32 là gì CRC32 là một loại checksum CRC. Việc tính toán checksum được thực hiện trên tinh thần của thuật toán checksum CRC cơ bản và được lưu trữ mã checksum dưới dạng số hexa (32bit) Cách tính mã CRC32 Các giá trị Giá trị của mã CRC được lưu trữ bằng một biến kiểu ulong với giá trị khởi tạo mặc định là: ulong ulCRC = 0xffffffff (8 byte =32 bit) Hằng số CRC_Polynomial constant cũng có kiểu giá trị là ulong và có giá trị: const ulong ulPolynomial = 0xEDB88320; đây là hằng số được quy định bởi thuật toán. Bảng CRC (CRC table) là một mãng giá trị kiểu ulong gồm 256 phần tử, được tính toán thông qua hằng số ulPolynomial ulong ulCRCTable = new ulong[256]; Đầu tiên ta cho một biến i chạy từ 0 à 255. Ứng với từng giá trị của i ta tiếp tục cho qua vòng lặp 8 lần: Nếu i chẵn thì dịch phải i một bit và XOR(Exclusive-OR) rồi gán lại cho i ban đầu i = ( i >> 1) ^ ulPolynomial; Nếu i lẻ thì chỉ dịch phải i một bít i = i>>1; Mục đích của việc lặp lại 8 lần là để tạo ra giá trị hexa (32bit). Code: ulong dwCrc; for (i = 0; i < 256; i++) { dwCrc = (ulong)i; for (j = 8; j > 0; j--) { if ((dwCrc & 1) == 1)//If dwCrc lẽ dwCrc = (dwCrc >> 1) ^ ulPolynomial; else dwCrc >>= 1; } ulCRCTable[i] = dwCrc; } Tính toán checksum Sau khi đã tính được bảng ulCRCTable ta tiến hành checksum. Khi đọc từng mảng byte buffer trong khi copy hay move, ta cho vào hàm CoputeCRC như sau: Code: public void ComputeCRC(ref byte[] buffer) { ulong len; len = (ulong)buffer.Length;// //Đọc từng byte của buffer for (ulong buffptr = 0; buffptr < len; buffptr++) { ulong tabPtr = ulCRC & 0xFF; tabPtr = tabPtr ^ buffer[buffptr]; ulCRC = ulCRC >> 8; ulCRC = ulCRC ^ crc32Table[tabPtr]; } } Lưu ý giá trị ulCRC sau khi qua hàm ComputeCRC chưa phải là mã checksum của file mà ta phải phủ định từng bít của nó mới tạo ra mã checksum. Ở đây ta chỉ việc XOR giá trị ulCRC với 0xffffffff Checksum CRC32 trong chương trình TTCopy Do thao tác copy, cut được thực hiện thông qua buffer nên checksum CRC32 cũng thông qua buffer. Đầu tiên ta kiểm tra dung lượng file cần kiểm tra CRC32 với giá trị của bufferSize Nếu bé hơn hoặc bằng, hạ bufferSize xuống bằng dung lượng của file đó và tiến hành đọc thông qua buffer. Sau khi đọc hoàn tất, ta chỉ việc sử dụng hàm ComputeCRC để tính giá trị ulCRC. Nếu lớn hơn, ta đọc file bằng bufferSize và tính dồn giá trị ulCRC. Đến khi nào dung lượng còn lại của file bé hơn hoặc bằng bufferSize, ta mới tiến hành điều chỉnh bufferSize bằng với số byte còn lại của file, và tiếp tục dồn giá trị cuối cùng này vào ulCRC Sau khi đã có được giá trị ulCRC, ta phủ định lại bằng cách cho biến ulCRC XOR với giá trị 0xffffffff, ta được mã checksum CRC32 của file. Nút Test Có thể Test CRC sau khi copy và move để kiểm tra trong quá trình copy hay move có xãy ra lỗi không. Đầu tiên kiểm tra dung lượng file đích và file nguồn. Nếu không bằng nhau ta không cần kiểm tra mã CRC mà kết luận ngay là “CRC not match”. Nếu dung lượng hai file bằng nhau thì ta mới tiến hành kiểm tra file đích rồi so sánh. Bạn có thể tùy chọn TestCRC trong khi copy(move) hay không để cải thiện tốc độ copy(move). TestCRC sau khi copy Chương trình tự động tính CRC32 khi đọc file (copy/move), và có thể tính CRC32 của file đích sau khi copy/move khi chọn tùy chọn Test. DRAG và DROP Chương trình TTCopy cho phép kéo và thả tập tin/thư mục vào danh sách nhằm đơn giản hóa công việc. Thay vì phải thực hiện thao tác mở bảng Open, chọn lần lượt các tập tin/thư mục cần copy (move), giờ đây mọi việc trở nên dễ dàng hơn khi dùng chuột lần lượt kéo và thả chúng vào chương trình. Danh sách các tập tin/thư mục sẽ được cập nhật ngay mà không cần phải thao tác dài dòng. Để đưa khả năng kéo thả vào chương trình, trước hết chúng ta xác định: + Thao tác kéo thả được chia ra thành hai sự kiện: “kéo” tập tin/thư mục vào trong chương trình và “thả” chúng. Kéo thả phải được sự cho phép thì mới thực hiện được. + Việc “thả” tập tin/thư mục sẽ diễn ra tại bất kì vị trí nào của chương trình. Do đó cần phải thiết lập sự kiện trên toàn thể các thành phần đang hiển thị. + Sau khi “thả” tập tin/thư mục, đường dẫn của chúng sẽ được lưu vào 1 listbox tạm. Chức năng của listbox này sẽ được nêu ở phần sau. Như vậy, chúng ta sẽ xây dựng thuộc tính drag&drop cho chương trình như sau: //Thiết lập cho phép kẻo thả tập tin/thư mục cho tất cả thành phần trên form foreach (Control c in this.Controls) { c.AllowDrop = true; c.DragDrop += new DragEventHandler(myDragDrop);//sự kiện “thả” c.DragEnter += new DragEventHandler(myDragEnter);//sự kiện “kéo” } //Thiết lập kéo thả cho form this.AllowDrop = true; this.DragEnter += new DragEventHandler(myDragEnter);//sự kiện “kéo” this.DragDrop += new DragEventHandler(myDragDrop);//sự kiện “thả” + Sau đó chúng ta xây dựng 2 sự kiện “kéo” và “thả”như sau: Kéo: private void myDragEnter(object sender, DragEventArgs e) { //Nếu không phải đang thực thi test/copy/move thì cho phép kéo thả thêm file/folder vào if (!onwork) { //Nếu kéo file/folder thì xử lý cho phép thả if (e.Data.GetDataPresent(DataFormats.FileDrop)) //Hiệu ứng chuột khi kéo e.Effect = DragDropEffects.Move; } } Thả: private void myDragDrop(object sender, DragEventArgs e) { //Nếu không phải đang thực thi test/copy/move thì cho phép kéo thả thêm file/folder vào if (!onwork) { //Lấy danh sách file, folder đưa vào listbox string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); for (int i = 0; i < files.Length; i++) tmplist.Items.Add(files[i]); //Khởi tạo thread chạy để thêm file/folder vào list tạm Thread th = new Thread(add); th.Start(); } } Listbox tạm: Để tránh việc sử dụng đệ qui làm tổn hao tài nguyên hệ thống vô ích và trì trệ việc add file, ta sử dụng list box tạm với vai trò queue để khử đệ qui. Như vậy, công việc bây giờ là xây dựng hàm phân tích thư mục và hàm thêm vào danh sách thực: Phân tích thư mục: private void addf(string folder,string root) { //Thực hiện thêm thư mục try { bool empty_folder = true; string[] f; //Lấy danh sách thư mục con f = Directory.GetDirectories(folder); for (int i = 0; i < f.Length; i++) { //Thêm thư mục vào listbox tmplist để tiếp tục add tmplist.Items.Add(f[i] + "|" + root); //Do có thư mục con nên thư mục không rỗng empty_folder = false; } //Lấy danh sách file trong thư mục f = Directory.GetFiles(folder); for (int i = 0; i < f.Length; i++) { //Nếu là file đầu tiên của thư mục thì thêm vào tùy chọn đánh dấu if (i == 0) lst_insert(f[i], getfilesize(f[i]), root, "1"); //Nếu không phải file cuối cùng thì thêm vào không có đánh dấu else lst_insert(f[i], getfilesize(f[i]), root); //Do có file trong thư mục nên thư mục không rỗng empty_folder = false; } if (empty_folder) { //Nếu là thư mục rỗng, theo vào file ảo * để đảm bảo thư mục được thực thi khi thực hiện move lst_insert(folder+"\\*", "0", root,"1"); } } catch (Exception ex) { //Gọi hàm hiển thị danh sách file khi có lỗi err_pull(); if (ex is System.UnauthorizedAccessException) { //Hỏi xem người dùng có muốn thêm file tiếp hay không nếu gặp một thư mục bị giới hạn quyền truy cập if (MessageBox.Show(this, "Can't open directory " + folder + "\nDo you want to continue?", "Alert", MessageBoxButtons.YesNo) == DialogResult.No) { //Nếu không muốn thì xóa danh sách những thư mục/file đang chờ add tmplist.Items.Clear(); } } } setStatus("Reading files"); } Thêm vào danh sách thực: - Sử dụng listview tạm tmpv để lưu tạm thời danh sách tập tin và đưa ra listview lst thật để khỏi bị thắt cổ chai và đứng chương trình. //Sau khi đã thêm hết danh sách tập tin vào listview tmpv, thực hiện copy vào listview lst là listview chính ListViewItem[] itemclone=new ListViewItem[tmpv.Items.Count]; setStatus("Reading file(s)/folder(s)"); //Tạo clone cho các mục trong listview tmpv for (int i = 0; i < tmpv.Items.Count; i++) { itemclone[i] = tmpv.Items[i].Clone() as ListViewItem; } tmpv.Items.Clear(); //Sau khi tạo clone, tiến hành chép vào listview lst setStatus("Adding file(s)/folder(s)"); lst.Items.AddRange(itemclone); ; setStatus("Waitting"); tmplist.Items.Clear(); //Xóa danh sách file trong tmplist chờ add vì đã add hết CUSTOM CONTROLS Custom Progressbar Để tiện theo dõi tiến trình copy, ta dùng 2 thanh tiến trình (progressbar) do người dùng tạo ra (usercontrol): một để theo dõi tiến trình của từng tập tin và một cho toàn bộ tiến trình. Điều khiển CustomProgressBar kế thừa lớp UserControl gồm 3 PictureBox với 3 màu khác nhau: thanh b1 màu sẫm biểu diễn dung lượng đã xử lý của một file (hoặc của toàn bộ tiến trình); thanh b2 màu nhạt biểu diễn thanh b1 cộng thêm dung lượng của một vùng đệm (buffersize) (hoặc dung lượng của file tiếp theo); thanh bgr màu trắng biểu diễn toàn bộ công việc phải xử lý tương ứng với biến max. Mỗi PictureBox được gắn với 3 Label: 3 lbl_left cho biết dung lượng (hoặc số file) đã xử lý; 3 lbl cho biết lượng công việc đã hoàn thành tính bằng phần trăm, font chữ của Label này (ForeColor) có màu sáng để dễ nhìn hơn khi thanh màu sẫm chạy qua, đây cũng là lý do ta cần đến 3 Label giống nhau cho mỗi thanh; 3 lbl_right cho biết thời gian xử lý của từng file (hoặc của toàn bộ quá trình). Mỗi bộ 3 Label này nằm cùng một vị trí. Việc cập nhật tiến trình cho điều khiển được tiến hành thông qua hàm sValue: public double svalue(double s,double r){ … } Với 2 tham số : s là dung lượng file đã xử lý và r là kích thước buffer (hoặc dung lượng file kế tiếp). 2 tham số này được truyền lần lượt cho 2 biến value và ove của lớp CustomProgressBar. Ta tiến hành kiểm tra giá trị của 2 biến này. Nếu s và r đều bằng 0, tức là giai đoạn đầu tiên của tiến trình xử lý, ta ghi nhận thời điểm này trong một biến dtStart kiểu DateTime. Giai đoạn tiếp theo s bằng 0 và r khác 0 (buffer đã được tạo ra nhưng chưa xử lý), và cuối cùng s và r đều khác 0 (đang trong tiến trình xử lý), ta xác định nội dung của Label phần trăm bằng công thức : dung lượng / tổng dung lượng * 100 + “%”; Việc xác định nội dung cho các Label lbl_left cũng khá đơn giản: dung lượng s + “MB of” + dung lượng max + “MB”, tất cả đều được tính bằng MB và làm tròn đến chữ số thập phân thứ nhất. Tương tự, việc xác định nội dung các Label lbl_right bằng cách lấy thời gian hiện tại trừ đi thời gian bắt đầu sau khi số liệu đã được xử lý bằng hàm plus(int) để thêm vào 0 nếu số thời gian chỉ có 1 chữ số (<10). Custom Checkbox Tương tự như customProgressBar, customCheckBox cũng là một UserControl nhưng đơn giản hơn rất nhiều, chỉ gồm một Label lbl, một biến Boolean value và có biến cố MouseDown được xử lý bằng sự kiện lbl_MouseDown như sau: private void lbl_MouseDown(object sender, MouseEventArgs e) { value = !value; if (value == true) lbl.ForeColor = SystemColors.WindowText; else lbl.ForeColor = SystemColors.GrayText; } Hàm này đơn giản chỉ đảo ngược trạng thái Visible và Invisible sau mỗi lần nhấn chuột bằng cách thay đổi tính năng ForeColor từ WindowText sang GrayText và ngược lại. Ngoài ra còn có các phương thức Load và sValue để khởi tạo và cập nhật giá trị cho các đối tượng của lớp customCheckBox : private void customCheckbox_Load(object sender, EventArgs e) { this.Width = lbl.Width; this.Height = lbl.Height; } public void sValue(string txt,bool val) { lbl.Text = txt; Text = txt; value=val; if(value==true) lbl.ForeColor=SystemColors.WindowText; else lbl.ForeColor=SystemColors.GrayText; this.Width = lbl.Width; this.Height = lbl.Height; } Ứng dụng của lớp customCheckBox trong dự án là xác định xem người dùng muốn làm gì sau khi quá trình xử lý dữ liệu kết thúc. Có 3 lựa chọn trong trường hợp này: AutoBuffer (tự động điều chỉnh kích thước buffer, mặc định value = true), Close (đóng chương trình, mặc định value = true), Test (chuyển sang kiểm tra CRC ngay sau khi xử lý xong, mặc định value = false). RUN as ADMIN Với sự xuất hiện của HĐH Windows Vista, chức năng

Các file đính kèm theo tài liệu này:

  • docBC.doc
  • rarSoure code.rar
  • pptxTTCopy.pptx