NEWS

[C#] Giới thiệu thư viện Pinvoke.NET demo ứng dụng Copy File with progress bar

[C#] Giới thiệu thư viện Pinvoke.NET demo ứng dụng Copy File with progress bar
Đăng bởi: Thảo Meo - Lượt xem: 5327 10:13:05, 26/02/2020C#   In bài viết

Xin chào các bạn, bài viết hôm nay mình sẽ tiếp tục hướng dẫn đến các bạn thư viện Pinvoke.NET trong lập trình C# winform.

[C#] How to use library Pinvoke.NET

Pinvoke.NET là gì?

Pinvoke.NET là một website giống như cuốn từ điển, cho phép chúng ta tìm kiếm các hàm sử dụng thư viện Win32 để tích hợp vào trong ứng dụng lập trình .NET.

Ở website Pinvoke này, cung cấp cho chúng ta code cả hai ngôn ngữ (VB.NET và C#).

API (Application Programming Interface) là cách thức dùng để gọi hàm bên trong thư viện liên kết động DLL.

Thực hiện các tác vụ Windows như tạo và huỷ các cửa sổ ứng dụng, các control và menu; truy xuất các dịch vụ hệ thống màn hình, bàn phím và chuột, máy in và nhiều chức năng khác.

Các hàm API thường được viết bằng C++

Các bạn có thể truy cập vào website: pinvoke.net để tham khảo nhé.

intro_pinvoke

Và bài viết dưới đây, mình sẽ demo sử dụng Pinvoke.NET và viết ứng dụng nhỏ Copy File với Progress bar sử dụng thư viện Win32.

Trong .NET framework, có cung cấp cho chúng ta hàm File.Copy(source, dest, override) nằm trong thư viện System.IO (thư viện này không hỗ trợ trả về cho chúng ta progress bar phần trăm hoàn thành).

Nếu trong Net muốn lấy phần trăm progress, chúng ta phải sử dụng Stream và read byte để tính toán phần trăm.

Các bạn có thể tham khảo bài viết Copy File with Progressbar C# tại đây

HƯỚNG DẪN COPY FILE SỬ DỤNG PINVOKE

Các bạn truy cập vào website Pinvoke.net và gõ ở ô tìm kiếm với keyworks: copy file, các bạn sẽ được hình ảnh bên dưới.

copyfile_pinvoke

Giao diện demo ứng dụng copy File Win32 C#:

copyfile_win32

Đầu tiên các bạn tạo cho mình một class XCopy.cs 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Pinvoke_Copyfile
{
    class XCopy
    {
        public static void Copy(string source, string destination, bool overwrite, bool nobuffering)
        {
            new XCopy().CopyInternal(source, destination, overwrite, nobuffering, null);
        }

        public static void Copy(string source, string destination, bool overwrite, bool nobuffering, EventHandler<ProgressChangedEventArgs> handler)
        {
            new XCopy().CopyInternal(source, destination, overwrite, nobuffering, handler);
        }

        private event EventHandler Completed;
        private event EventHandler<ProgressChangedEventArgs> ProgressChanged;

        private int IsCancelled;
        private int FilePercentCompleted;
        private string Source;
        private string Destination;

        private XCopy()
        {
            IsCancelled = 0;
        }

        private void CopyInternal(string source, string destination, bool overwrite, bool nobuffering, EventHandler<ProgressChangedEventArgs> handler)
        {
            try
            {
                CopyFileFlags copyFileFlags = CopyFileFlags.COPY_FILE_RESTARTABLE;
                if (!overwrite)
                    copyFileFlags |= CopyFileFlags.COPY_FILE_FAIL_IF_EXISTS;

                if (nobuffering)
                    copyFileFlags |= CopyFileFlags.COPY_FILE_NO_BUFFERING;

                Source = source;
                Destination = destination;

                if (handler != null)
                    ProgressChanged += handler;

                bool result = CopyFileEx(Source, Destination, new CopyProgressRoutine(CopyProgressHandler), IntPtr.Zero, ref IsCancelled, copyFileFlags);
                if (!result)
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            catch (Exception)
            {
                if (handler != null)
                    ProgressChanged -= handler;

                throw;
            }
        }

        private void OnProgressChanged(double percent)
        {
            // only raise an event when progress has changed
            if ((int)percent > FilePercentCompleted)
            {
                FilePercentCompleted = (int)percent;

                var handler = ProgressChanged;
                if (handler != null)
                    handler(this, new ProgressChangedEventArgs((int)FilePercentCompleted, null));
            }
        }

        private void OnCompleted()
        {
            var handler = Completed;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }

        #region PInvoke

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel, CopyFileFlags dwCopyFlags);

        private delegate CopyProgressResult CopyProgressRoutine(long TotalFileSize, long TotalBytesTransferred, long StreamSize, long StreamBytesTransferred, uint dwStreamNumber, CopyProgressCallbackReason dwCallbackReason,
                                                        IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);

        private enum CopyProgressResult : uint
        {
            PROGRESS_CONTINUE = 0,
            PROGRESS_CANCEL = 1,
            PROGRESS_STOP = 2,
            PROGRESS_QUIET = 3
        }

        private enum CopyProgressCallbackReason : uint
        {
            CALLBACK_CHUNK_FINISHED = 0x00000000,
            CALLBACK_STREAM_SWITCH = 0x00000001
        }

        [Flags]
        private enum CopyFileFlags : uint
        {
            COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
            COPY_FILE_NO_BUFFERING = 0x00001000,
            COPY_FILE_RESTARTABLE = 0x00000002,
            COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
            COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
        }

        private CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long streamByteTrans, uint dwStreamNumber,
                                                       CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
        {
            if (reason == CopyProgressCallbackReason.CALLBACK_CHUNK_FINISHED)
                OnProgressChanged((transferred / (double)total) * 100.0);

            if (transferred >= total)
                OnCompleted();

            return CopyProgressResult.PROGRESS_CONTINUE;
        }

        #endregion

    }

}

Và tiếp theo là code c# cho form chính copy file:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Pinvoke_Copyfile
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private async void btn_Copy_Click(object sender, EventArgs e)
        {
            var source = txtSource.Text;
            var dest = txtDest.Text;

            var progress = new Progress<int>(percent =>
            {
                progressBar1.Value = percent;
                lbl_percent.Text = percent + "%";

            });

            await Task.Run(() => TaskCopy(source, dest, progress));
        }

        public void TaskCopy(string source, string dest, IProgress<int> progress)
        {
            XCopy.Copy(source, dest, true, true, (o, pce) =>
            {                
                progress.Report(pce.ProgressPercentage);
            });
        }
    }
}

Thanks for watching!

DOWNLOAD SOURCE

THÔNG TIN TÁC GIẢ

BÀI VIẾT LIÊN QUAN

[C#] Giới thiệu thư viện Pinvoke.NET demo ứng dụng Copy File with progress bar
Đăng bởi: Thảo Meo - Lượt xem: 5327 10:13:05, 26/02/2020C#   In bài viết

CÁC BÀI CÙNG CHỦ ĐỀ

Đọc tiếp
.