Đánh giá chủ đề:
  • 0 Votes - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Ms Access VBA và Google drive, một vài ý tưởng trong chia sẻ và đồng bộ số liệu...
#1
Bản demo đã có nhiều sửa đổi để các cụ Test thử nhé...
Bản demo tôi cung cấp ở đây là trích từ ứng dụng đang làm dở nên có nhiều chỗ tôi comment bằng tiếng Anh, các cụ thông cảm nhé
Bản demo của tôi hiện đã có thêm chức năng tải file lên GoogleDrive.

Tôi đang dùng 1 account thử nghiệm để test, các bác có thể dùng xem sao...
============================================
Phương pháp sử dụng GoogleDrive với VBA
Đặt vấn đề:
Tôi cần ứng dụng của tôi tương tác với dịch vụ lưu trữ trên mạng: ở đây sử dụng Google Drive (do họ cung cấp miễn phí đến 15GB với sự ổn định khá cao)
Ứng dụng của tôi viết trên nền VBA và tôi cần các file của tôi có thể tải lên và tải xuống khi cần.

Phân tích:
Hiện tại Google Drive cung cấp phương thức truy nhập ổ đĩa GoogleDrive cho người dùng tuy nhiên đối với người dùng VB/VBA cổ điển thì việc thao tác với googleDrive còn nhiều phiên toái, cụ thể như sau:
+ Làm thế nào để Truy nhập vào tài khoản người dùng một cách tiện lợi?
+ Làm thế nào để sử dụng các câu lệnh GoogleAPI khi tải tập tin lên, đặc biệt là việc vượt qua cơ chế xác thực người dùng ...vv

Sau thời gian nghiên cứu các phương án thực hiện với sự tham khảo một số tài liệu trên mạng, tôi sử dụng phương án sau đây:
Công việc 1: Tạo dự án để sử dụng các dịch vụ của Google
Công việc 2: Tạo ứng dụng và các mã xác thực để sau đó có thể sử dụng dịch vụ GoogleDrive

1. Làm rõ cơ chế xác thực người dùng và thiết lập các thông tin ban đầu
Bước 1: Khi truy nhập tài khoản Google, người ta phải cung cấp tên người dùng, mật khẩu
Bước 2: Google sẽ cung cấp mã xác thực (AuthCode), người dùng sau đó phải nhấn Accept/Chấp nhận trên hộp thoại UserConsent
Bước 3: Google sẽ cung cấp Khóa truy cập (Token) và người dùng sẽ sử dụng khóa này để thao tác với các dịch vụ của Google.
Bước 4: Vào https://console.developers.google.com/project để tạo ra một dự án sử dụng các dịch vụ của google như Google Drive chẳng hạn
+ Nhấn nút Create Project
+ Chọn tên dự án, ví dụ ở đây tôi tạo PublicStorage
Sau khi đợi một lúc, ta chọn dự án PublicStorage từ hộp chọn
Bước 5: Tạo các mã xác thực
+ Nhấn APIs & auth
+ Nhấn Credentials
+ Nhấn Create new Client ID
+ Chọn Installed Application
+ Nhấn Configure consent screen
+ Mục product name ta chọn một tên thân thiện cho ứng dụng của mình, chẳng hạn ở đây tôi chọn publicdata
+ Nhấn Save
+ Chọn Installed Application, trong mục Installed application type chọn Other
+ Nhấn Create Client ID
Sau khi xong, nhấn APIs, chọn GoogleDrive rồi nhấn Enable API.

Chúng ta sẽ nhận được màn hình kết quả với các thông số trong mục Client ID for native application như sau:
Client ID: [Thay bằng mã của bạn]
Client secret: [b][Thay bằng mã của bạn][/b]
Redirect URIs: urn:ietf:wg:oauth:2.0:oob http://localhost

Hãy lưu ý Client IDClient secret, đây là những cái chúng ta cần sau này.

Đến đây bước khởi tao ban đầu của chúng ta đã hoàn tất.
Bây giờ hãy chuyển sang phần coding/ viết mã.

2. Viết mã, phân tích cơ chế.
Đáng tiếc là Google chưa xây dựng các cơ chế sử dụng dịch vụ cho ứng dụng viết bằng VBA/VB cổ điển nên chúng ta đành phải mượn công cụ của bên ngoài để thực hiện các chuỗi lệnh thao tác với GoogleDrive. Ở đây tôi đã chọn công cụ rclone viết bằng ngôn ngữ GO (công cụ lập trình của Google) và thao tác bằng dòng lệnh.

a. Truy nhập vào Google qua cơ chế xác thực OAuth
Thật may mắn là Google sử dụng cơ chế xác thực người dùng OAuth theo đó, một khi người dùng:
+ Truy nhập vào tài khoản với tên tài khoản và mật khẩu;
+ Cung cấp mã Client_ID, Client_Secret
+ Chấp nhận cho phép sử dụng ứng dụng.
Google sẽ cho phép bất kỳ ứng dụng nào với các thông tin đã cung cấp khai thác tài nguyên gắn với tài khoản người dùng thông qua một mã gọi là Token. Mỗi máy tính sẽ có một mã Token riêng.

Vậy trước tiên, chúng ta sẽ thiết kế một mô đun cho phép xác thực với OAuth. Thật may mắn, Tim Halls đã viết giúp chúng ta một Class để thực hiện việc xác thực này, tôi dùng bộ thư viện này với một số sửa đổi trong đó có mấy thủ tục chính bao gồm AuthCode để lấy Code xác thực trên trình duyệt, BrowserComplete để đánh giá khi nào trình duyệt hoàn thành việc lấy thông tin, WaitUntilLoaded để kiểm tra trạng thái của trình duyệt, InitClientCredentials để khai báo các thông tin truy cập, InitEndPoints để thiết lập các địa chỉ truy cập dịch vụ xác thực của google.

Với class này, tôi chỉ cần viết thêm một đoạn thủ tục sau đây để lấy mã

Mã:
Private Function GetAuthCode() As String
    Dim myClass As New gAuth2, client_id As String, client_secret As String
    client_id = "mã client_id của bạn"
    client_secret = "clien_secret của bạn"
    With myClass
        .LogOnGoogle "email của bạn", "mật khẩu của bạn"
        .InitClientCredentials client_id, client_secret
        .InitEndPoints
        GetAuthCode = .AuthCode
    End With
End Function


Bước 1 đã xong. Tiếp theo chúng ta sẽ phải thiết lập được phương thức cấu hình cho rclone. Ứng dụng này không thể tự động chạy mà bạn phải tự cấu hình bằng dòng lệnh thông qua thủ tục chạy rclone config và sau đó là khai báo các thông tin khác nhau cho ứng dụng. Đáng tiếc nó lại chạy giống như trong môi trường DOS (command prompt) vì thế sẽ khá khó khăn để người dùng thông thường phải làm việc này bằng tay với các dòng lệnh khô khan.
Vì ứng dụng của tôi sử dụng 1 tài khoản cho mọi người dùng vì thế tôi bắt buộc phải thiết kế để ứng dụng làm được điều này với sự can thiệp ít nhất của người dùng (Chỉ là nhấn nút đồng ý cho phép thao tác với Google Drive qua màn hình User Consent đã nói ở trên).
Như thế ta cần một cơ chế có thể truyền tham số cho rclone theo một nhóm trình tự nào đó. Đến đây ta có 2 cách tiếp cận: sử dụng SendKeys và sử dụng Shell để truyền thông tin.
Cách dùng SendKeys không tốt do nó đòi hỏi màn hình Console (ở đây là DOS) luôn phải kích hoạt. Vì thế tôi lựa chọn cách dùng Shell và giấu màn hình CMD đi rồi truyền tham số. Thủ tục thực hiện đơn giản như sau:

 ' 2 phase 2 - send to console

Mã:
Set objShell = CreateObject("WScript.Shell") ' Tạo một phiên làm việc Shell
Set oExec = objShell.Exec("CMD /K") ' mở giao diện DOS
Call HideWindow(oExec.ProcessID) ' Giấu giao diện DOS

Sau đó đến tiết mục truyền tham số cho giao diện DOS thông qua nhóm lệnh sau đây:

Mã:
With oExec
DoEvents
For i = LBound(cmdList) To UBound(cmdList)
   .StdIn.WriteLine CStr(cmdList(i)) ' truyền từng tham số vào và đợi
Next
Do Until .StdOut.AtEndOfStream
   strResults = strResults & vbCrLf & .StdOut.ReadLine ' lấy phản hồi từ giao diện
   DoEvents
Loop
End With

Toàn bộ thủ tục này như sau:


Mã:
Private Sub WriteConsole(Optional CreateNew As Boolean = False)
    ' This will try to set up google new token
    Dim objShell As Object
    Dim oExec As Object
    Dim strResults As String
    
    ' 1. Pha 1, truy nhập và lấy mã xác thực
    Dim i As Long, client_id As String, client_secret As String, ReturnValue As Long
    Dim cmdList As Variant, theCode As String
    
    client_id = "456200380740-dr4nihc6u5fslh7larcoiqi6o189liqo.apps.googleusercontent.com"
    client_secret = "duo0jfm-IhRWffLCCtpCJY48"
    
    theCode = GetAuthCode
    If CreateNew Then
        cmdList = Array(rcPath & "rclone.exe config", "n", "gdrive", "6", client_id, client_secret, theCode, "y", "q", "exit")
    Else
        cmdList = Array(rcPath & "rclone.exe config", "e", "1", "", "", "", "", "y", theCode, "y", "q", "exit")
    End If
    DoEvents
    ' 2 phase 2 - send to console
    Set objShell = CreateObject("WScript.Shell")
    Set oExec = objShell.Exec("CMD /K")
    Call HideWindow(oExec.ProcessID)

    With oExec
        ' find a way to get stick to the windows and parse data..
        DoEvents
        For i = LBound(cmdList) To UBound(cmdList)
            .StdIn.WriteLine CStr(cmdList(i)) 
            Sleep 1000 ' wait for the message to be completed
        Next
' tiếp nhận kết quả
        Do Until .StdOut.AtEndOfStream
            strResults = strResults & vbCrLf & .StdOut.ReadLine
            DoEvents
        Loop
    End With
    Set oExec = Nothing
    ' in kết quả
    Me.rtbOutput = strResults
End Sub


Thủ tục này thực hiện 2 chế đô: tạo mới cấu hình hoặc lấy token mới từ các mã hiện tại.
Trong ví dụ này, ta dùng call WriteConsole(true)
Hãy chú ý mảng
cmdList = Array(rcPath & "rclone.exe config", "n", "gdrive", "6", client_id, client_secret, theCode, "y", "q", "exit")
nó quy định thứ tự các lệnh sẽ thực hiện bao gồm từ việc tải ra chế độ cấu hình rclone cho đến khi nhập các thống số cấu hình và kết thúc.

Cú pháp
Mã:
.StdIn.WriteLine CStr(cmdList(i)) 
chịu trách nhiệm gửi lệnh
và phần sau đó sẽ ghi lại lệnh và gửi ra báo cáo.
Với việc chạy nhóm thủ tục này, chúng ta sẽ hoàn thành phần cấu hình cho rclone. Thủ tục này chỉ chạy một lần duy nhân khi chạy ứng dụng ban đầu.

Sau khi đã cài đặt xong, chúng ta chỉ cần sử dụng các dòng lệnh của rclone để thực hiện công việc tạo thư mục, sao chép, tải file lên ...vv
Nếu các bạn muốn thử, hãy dùng chính account email của mình và theo hướng dẫn sẽ có được kết quả như ý muốn.

Ứng dụng demo ở sau đây nhé, có nhiều thứ cop nhặt, có gì các bạn cứ hỏi
http://www.sfdp.net/thuthuataccess/demo/...ects=0&d=1

Trong file ví dụ của tôi có một số đặc điểm sau:
+ tbRef để lưu trứ 2 tập tin là zlib.dll và rclone.zip (bản nén của rclone).
+ Một số thủ tục giải nén/ dãn nén bằng zlib
+ Một số thủ tục lưu tập tin thư viện vào bảng tbref và bung nó từ bảng này...

Ứng dụng chạy như sau:
1. Chạy form frmUpload
Khi chạy nó sẽ kiểm tra xem đã có 2 tập tin zlib.dll và rclone.exe trong thư mục chạy hay chưa?
Nếu không có thì sẽ lấy từ trong bảng tbRef ra.

2. Khi bạn nhấn Lấy Token
+ Bạn cần có các thông tin ở texbox liên quan, hiện tại tôi dùng với 1 account thử nghiệm.
+ Chạy rclone để thiết lập cấu hình lần đầu
(lần sau nó cũng vẫn chạy như thế vì tôi không đưa ra cơ chế kiểm tra xem có cấu hình của rclone chưa).
Bây giờ việc chấp thuận cũng như nhập các thông tin khác đã được tự động hóa. Gần đây có báo đưa về việc rò rỉ an ninh liên quan đến cơ chế này, hy vọng Google sẽ sơm có cách điều chỉnh mà không làm ảnh hưởng tới công cụ này!

Và bạn có thể sửa code để tải vài file ....


Và nhiều thứ linh tinh mục khác.
Có ai hỏi gì xin cứ đặt câu hỏi nhé

Chúc các bạn tuần mới đầy niềm vui!
Chữ ký của paulsteigel ====================
Quốc gia hưng vong
Thất phu hữu trách
====================
Reply
Những người đã cảm ơn maidinhdan , xuankien07 , Noname , tranthanhan1962 , MatTroiNguQuen , Che_Guevara
#2
Bài viết rất là hay, đọc thấy mê...vọc ngay thôi. 015
Chữ ký của maidinhdan * Để được hỗ trợ tốt nhất, nhấn vào link dưới đây để xem.
1. [Hướng dẫn] Kiểu file gửi lên để được giúp đỡ
2. [Hướng dẫn] Nội quy diễn đàn
3. [Hướng dẫn] Cách Đưa file và hình vào diễn đàn
4.[Hướng dẫn] Để xây dựng một ứng dụng hoàn hảo và lời cảm tạ
5. Cần tìm Demo hay ứng dụng sử dụng thanh tìm kiếm phía trên cùng, bên phải của diễn đàn.
* Nếu muốn cảm ơn, hãy nhấn nút thank, không cần viết thêm bài nào nửa.



ღღღღღTài sản của maidinhdan (View All Items) ღღღღღ
Reply
Những người đã cảm ơn
#3

Googdrive...tiếp nào
Sau thời gian nghiên cứu và mày mò, có vẻ công cụ tải file, upload file lên googdrive bằng VBA là hoàn toàn khả thi.
Hôm nay tôi xin phép giới thiệu với các bạn phần đầu của nỗ lực này nhé.
Trước hết, để tiện lợi cho việc viết bài, tôi sẽ lấy một ứng dụng mở của tôi sử dụng làm thí nghiệm.

A. Để làm việc được với Googdrive từ VBA hoặc bất cứ ứng dụng nào không phải là giao diện Web, bạn cần thỏa mãn được mấy điều kiện sau:
+ Có một Ứng dụng được tạo ra để truy cập vào các dịch vụ của Google
+ Ứng dụng này được tạo ra với các thông số tối thiểu sau
* AppID (Mã ứng dụng). Trong ví dụ của tôi là [openstore-1034]
* ClientID (Mã ứng dụng khách). Trong ví dụ của tôi là ["759747656687-rjkm22bit7ob5tufc5sbgg1gsuj48fme.apps.googleusercontent.com"]
* ClientSecret (mã bí mật của ứng dụng khách). Trong ví dụ của tôi là ["Jf5DqXlZ2G3cOtUtHIraaxvQ"]
+ Khi ứng dụng này truy cập vào bất cứ dịch vụ nào, người dùng cần phải truy cập vào tài khoản gmail sau đó phải chấp thuận cho ứng dụng sử dụng.
...
==============================================================
Do bài viết của tôi không thể đăng được, các bạn có thể đọc ở tài liệu sau đây nhé
Bài đọc chi tiết
==============================================================

Liên kết tải file ví dụ ở đây
http://www.sfdp.net/thuthuataccess/demo/...ects=0&d=1
Chúng ta có thể thấy kết quả như trong sheet1 với việc dùng Json2table nhé.
Tiếp cận với tải file lên, tải xuống, xóa ... vv sẽ làm tương tự.

Đến đây xin tạm dừng bài viết đã nhé.
Chúc các bạn vui vẻ.
Chữ ký của paulsteigel ====================
Quốc gia hưng vong
Thất phu hữu trách
====================
Reply
Những người đã cảm ơn Noname , maidinhdan , thucgia , tranthanhan1962 , Che_Guevara
#4
Tối nay về nghiên cứu phần này, thấy giới thiệu là ngon rồi, Với code này, có thể phục vụ rất rất rất rất nhiều việc.

Cảm ơn anh Ngọc!
Chữ ký của maidinhdan * Để được hỗ trợ tốt nhất, nhấn vào link dưới đây để xem.
1. [Hướng dẫn] Kiểu file gửi lên để được giúp đỡ
2. [Hướng dẫn] Nội quy diễn đàn
3. [Hướng dẫn] Cách Đưa file và hình vào diễn đàn
4.[Hướng dẫn] Để xây dựng một ứng dụng hoàn hảo và lời cảm tạ
5. Cần tìm Demo hay ứng dụng sử dụng thanh tìm kiếm phía trên cùng, bên phải của diễn đàn.
* Nếu muốn cảm ơn, hãy nhấn nút thank, không cần viết thêm bài nào nửa.



ღღღღღTài sản của maidinhdan (View All Items) ღღღღღ
Reply
Những người đã cảm ơn Noname
#5
Sau khi dành tương đối nhiều thời gian cho chủ đề GoogleDrive, tôi đã hoàn thành bước 1:
+ Liệt kê danh sách file và đối tượng thư mục trong googleDrive
+ Cho phép tải file nhỏ lên GoogleDrive.
Ứng dụng gửi kèm theo chỉ mang tính demo nhưng cơ bản thực hiện được nhiệm vụ.
Tất nhiên còn có một số điểm khác cần cân nhắc bao gồm:
+ Bẫy lỗi
+ Hoàn thiện cơ chế tải file dùng chế độ tải phân đoạn đối với các file lớn.
+ Hoàn thiện cơ chế tương tác với file/ folder.
...

Hy vọng chúng ta sẽ cùng nhau đi tiếp.
Với chế độ tải file đơn giản chỉ áp dụng đối với file nhỏ, Google cũng có một số điểm hạn chế. Tất cả các ứng dụng khác họ không dùng dạng SimpleUpload mà dùng dạng tải phân đoạn Resumable Upload.
Tuy nhiên với chế độ phân đoạn thì cần có thêm thời gian nên tôi xin tạm trình bày về chế độ tải đơn giản đã nhé.

Để tải file lên được chúng ta cần có những thủ tục sau:
+ Đọc file dưới dạng nhị phân và chuyển thành chuỗi (nhiều thủ tục đọc file nhị phân đều gặp lỗi với tên file có ký tự Unicode).
+ Chuyển tên chuỗi sang dạng Utf-8.
+ Lấy được mã Token
+ Đăng tải thông tin.

Các bạn có thể xem qua thủ tục Upload có trong Module Upload nhé.
Các thủ tục khác đang được tiếp tục hoàn thiện.
Chúc các bạn ngủ ngon
File đính kèm như trong bài trước - ở đây 
Chữ ký của paulsteigel ====================
Quốc gia hưng vong
Thất phu hữu trách
====================
Reply
Những người đã cảm ơn Noname , tranthanhan1962 , Che_Guevara
#6
Sao không cọn Access viết vậy anh? thấy Excel là bắt đầu rầu  019
Chữ ký của maidinhdan * Để được hỗ trợ tốt nhất, nhấn vào link dưới đây để xem.
1. [Hướng dẫn] Kiểu file gửi lên để được giúp đỡ
2. [Hướng dẫn] Nội quy diễn đàn
3. [Hướng dẫn] Cách Đưa file và hình vào diễn đàn
4.[Hướng dẫn] Để xây dựng một ứng dụng hoàn hảo và lời cảm tạ
5. Cần tìm Demo hay ứng dụng sử dụng thanh tìm kiếm phía trên cùng, bên phải của diễn đàn.
* Nếu muốn cảm ơn, hãy nhấn nút thank, không cần viết thêm bài nào nửa.



ღღღღღTài sản của maidinhdan (View All Items) ღღღღღ
Reply
Những người đã cảm ơn
#7
(27-08-15, 08:53 AM)maidinhdan Đã viết: Sao không cọn Access viết vậy anh? thấy Excel là bắt đầu rầu  019

Vì tớ lười lười - thôi để đóng vào cái demo vậy...
Chữ ký của paulsteigel ====================
Quốc gia hưng vong
Thất phu hữu trách
====================
Reply
Những người đã cảm ơn maidinhdan
#8
(10-08-15, 03:28 PM)paulsteigel Đã viết: Bản demo đã có nhiều sửa đổi để các cụ Test thử nhé...
Bản demo tôi cung cấp ở đây là trích từ ứng dụng đang làm dở nên có nhiều chỗ tôi comment bằng tiếng Anh, các cụ thông cảm nhé
Bản demo của tôi hiện đã có thêm chức năng tải file lên GoogleDrive.

Tôi đang dùng 1 account thử nghiệm để test, các bác có thể dùng xem sao...
============================================
Phương pháp sử dụng GoogleDrive với VBA
Đặt vấn đề:
Tôi cần ứng dụng của tôi tương tác với dịch vụ lưu trữ trên mạng: ở đây sử dụng Google Drive (do họ cung cấp miễn phí đến 15GB với sự ổn định khá cao)
Ứng dụng của tôi viết trên nền VBA và tôi cần các file của tôi có thể tải lên và tải xuống khi cần.

Phân tích:
Hiện tại Google Drive cung cấp phương thức truy nhập ổ đĩa GoogleDrive cho người dùng tuy nhiên đối với người dùng VB/VBA cổ điển thì việc thao tác với googleDrive còn nhiều phiên toái, cụ thể như sau:
+ Làm thế nào để Truy nhập vào tài khoản người dùng một cách tiện lợi?
+ Làm thế nào để sử dụng các câu lệnh GoogleAPI khi tải tập tin lên, đặc biệt là việc vượt qua cơ chế xác thực người dùng ...vv

Sau thời gian nghiên cứu các phương án thực hiện với sự tham khảo một số tài liệu trên mạng, tôi sử dụng phương án sau đây:
Công việc 1: Tạo dự án để sử dụng các dịch vụ của Google
Công việc 2: Tạo ứng dụng và các mã xác thực để sau đó có thể sử dụng dịch vụ GoogleDrive

1. Làm rõ cơ chế xác thực người dùng và thiết lập các thông tin ban đầu
Bước 1: Khi truy nhập tài khoản Google, người ta phải cung cấp tên người dùng, mật khẩu
Bước 2: Google sẽ cung cấp mã xác thực (AuthCode), người dùng sau đó phải nhấn Accept/Chấp nhận trên hộp thoại UserConsent
Bước 3: Google sẽ cung cấp Khóa truy cập (Token) và người dùng sẽ sử dụng khóa này để thao tác với các dịch vụ của Google.
Bước 4: Vào https://console.developers.google.com/project để tạo ra một dự án sử dụng các dịch vụ của google như Google Drive chẳng hạn
+ Nhấn nút Create Project
+ Chọn tên dự án, ví dụ ở đây tôi tạo PublicStorage
Sau khi đợi một lúc, ta chọn dự án PublicStorage từ hộp chọn
Bước 5: Tạo các mã xác thực
+ Nhấn APIs & auth
+ Nhấn Credentials
+ Nhấn Create new Client ID
+ Chọn Installed Application
+ Nhấn Configure consent screen
+ Mục product name ta chọn một tên thân thiện cho ứng dụng của mình, chẳng hạn ở đây tôi chọn publicdata
+ Nhấn Save
+ Chọn Installed Application, trong mục Installed application type chọn Other
+ Nhấn Create Client ID
Sau khi xong, nhấn APIs, chọn GoogleDrive rồi nhấn Enable API.

Chúng ta sẽ nhận được màn hình kết quả với các thông số trong mục Client ID for native application như sau:
Client ID: [Thay bằng mã của bạn]
Client secret: [b][Thay bằng mã của bạn][/b]
Redirect URIs: urn:ietf:wg:oauth:2.0:oob http://localhost

Hãy lưu ý Client IDClient secret, đây là những cái chúng ta cần sau này.

Đến đây bước khởi tao ban đầu của chúng ta đã hoàn tất.
Bây giờ hãy chuyển sang phần coding/ viết mã.

2. Viết mã, phân tích cơ chế.
Đáng tiếc là Google chưa xây dựng các cơ chế sử dụng dịch vụ cho ứng dụng viết bằng VBA/VB cổ điển nên chúng ta đành phải mượn công cụ của bên ngoài để thực hiện các chuỗi lệnh thao tác với GoogleDrive. Ở đây tôi đã chọn công cụ rclone viết bằng ngôn ngữ GO (công cụ lập trình của Google) và thao tác bằng dòng lệnh.

a. Truy nhập vào Google qua cơ chế xác thực OAuth
Thật may mắn là Google sử dụng cơ chế xác thực người dùng OAuth theo đó, một khi người dùng:
+ Truy nhập vào tài khoản với tên tài khoản và mật khẩu;
+ Cung cấp mã Client_ID, Client_Secret
+ Chấp nhận cho phép sử dụng ứng dụng.
Google sẽ cho phép bất kỳ ứng dụng nào với các thông tin đã cung cấp khai thác tài nguyên gắn với tài khoản người dùng thông qua một mã gọi là Token. Mỗi máy tính sẽ có một mã Token riêng.

Vậy trước tiên, chúng ta sẽ thiết kế một mô đun cho phép xác thực với OAuth. Thật may mắn, Tim Halls đã viết giúp chúng ta một Class để thực hiện việc xác thực này, tôi dùng bộ thư viện này với một số sửa đổi trong đó có mấy thủ tục chính bao gồm AuthCode để lấy Code xác thực trên trình duyệt, BrowserComplete để đánh giá khi nào trình duyệt hoàn thành việc lấy thông tin, WaitUntilLoaded để kiểm tra trạng thái của trình duyệt, InitClientCredentials để khai báo các thông tin truy cập, InitEndPoints để thiết lập các địa chỉ truy cập dịch vụ xác thực của google.

Với class này, tôi chỉ cần viết thêm một đoạn thủ tục sau đây để lấy mã

Mã:
Private Function GetAuthCode() As String
    Dim myClass As New gAuth2, client_id As String, client_secret As String
    client_id = "mã client_id của bạn"
    client_secret = "clien_secret của bạn"
    With myClass
        .LogOnGoogle "email của bạn", "mật khẩu của bạn"
        .InitClientCredentials client_id, client_secret
        .InitEndPoints
        GetAuthCode = .AuthCode
    End With
End Function


Bước 1 đã xong. Tiếp theo chúng ta sẽ phải thiết lập được phương thức cấu hình cho rclone. Ứng dụng này không thể tự động chạy mà bạn phải tự cấu hình bằng dòng lệnh thông qua thủ tục chạy rclone config và sau đó là khai báo các thông tin khác nhau cho ứng dụng. Đáng tiếc nó lại chạy giống như trong môi trường DOS (command prompt) vì thế sẽ khá khó khăn để người dùng thông thường phải làm việc này bằng tay với các dòng lệnh khô khan.
Vì ứng dụng của tôi sử dụng 1 tài khoản cho mọi người dùng vì thế tôi bắt buộc phải thiết kế để ứng dụng làm được điều này với sự can thiệp ít nhất của người dùng (Chỉ là nhấn nút đồng ý cho phép thao tác với Google Drive qua màn hình User Consent đã nói ở trên).
Như thế ta cần một cơ chế có thể truyền tham số cho rclone theo một nhóm trình tự nào đó. Đến đây ta có 2 cách tiếp cận: sử dụng SendKeys và sử dụng Shell để truyền thông tin.
Cách dùng SendKeys không tốt do nó đòi hỏi màn hình Console (ở đây là DOS) luôn phải kích hoạt. Vì thế tôi lựa chọn cách dùng Shell và giấu màn hình CMD đi rồi truyền tham số. Thủ tục thực hiện đơn giản như sau:

 ' 2 phase 2 - send to console

Mã:
Set objShell = CreateObject("WScript.Shell") ' Tạo một phiên làm việc Shell
Set oExec = objShell.Exec("CMD /K") ' mở giao diện DOS
Call HideWindow(oExec.ProcessID) ' Giấu giao diện DOS

Sau đó đến tiết mục truyền tham số cho giao diện DOS thông qua nhóm lệnh sau đây:

Mã:
With oExec
DoEvents
For i = LBound(cmdList) To UBound(cmdList)
   .StdIn.WriteLine CStr(cmdList(i)) ' truyền từng tham số vào và đợi
Next
Do Until .StdOut.AtEndOfStream
   strResults = strResults & vbCrLf & .StdOut.ReadLine ' lấy phản hồi từ giao diện
   DoEvents
Loop
End With

Toàn bộ thủ tục này như sau:


Mã:
Private Sub WriteConsole(Optional CreateNew As Boolean = False)
    ' This will try to set up google new token
    Dim objShell As Object
    Dim oExec As Object
    Dim strResults As String
    
    ' 1. Pha 1, truy nhập và lấy mã xác thực
    Dim i As Long, client_id As String, client_secret As String, ReturnValue As Long
    Dim cmdList As Variant, theCode As String
    
    client_id = "456200380740-dr4nihc6u5fslh7larcoiqi6o189liqo.apps.googleusercontent.com"
    client_secret = "duo0jfm-IhRWffLCCtpCJY48"
    
    theCode = GetAuthCode
    If CreateNew Then
        cmdList = Array(rcPath & "rclone.exe config", "n", "gdrive", "6", client_id, client_secret, theCode, "y", "q", "exit")
    Else
        cmdList = Array(rcPath & "rclone.exe config", "e", "1", "", "", "", "", "y", theCode, "y", "q", "exit")
    End If
    DoEvents
    ' 2 phase 2 - send to console
    Set objShell = CreateObject("WScript.Shell")
    Set oExec = objShell.Exec("CMD /K")
    Call HideWindow(oExec.ProcessID)

    With oExec
        ' find a way to get stick to the windows and parse data..
        DoEvents
        For i = LBound(cmdList) To UBound(cmdList)
            .StdIn.WriteLine CStr(cmdList(i)) 
            Sleep 1000 ' wait for the message to be completed
        Next
' tiếp nhận kết quả
        Do Until .StdOut.AtEndOfStream
            strResults = strResults & vbCrLf & .StdOut.ReadLine
            DoEvents
        Loop
    End With
    Set oExec = Nothing
    ' in kết quả
    Me.rtbOutput = strResults
End Sub


Thủ tục này thực hiện 2 chế đô: tạo mới cấu hình hoặc lấy token mới từ các mã hiện tại.
Trong ví dụ này, ta dùng call WriteConsole(true)
Hãy chú ý mảng
cmdList = Array(rcPath & "rclone.exe config", "n", "gdrive", "6", client_id, client_secret, theCode, "y", "q", "exit")
nó quy định thứ tự các lệnh sẽ thực hiện bao gồm từ việc tải ra chế độ cấu hình rclone cho đến khi nhập các thống số cấu hình và kết thúc.

Cú pháp
Mã:
.StdIn.WriteLine CStr(cmdList(i)) 
chịu trách nhiệm gửi lệnh
và phần sau đó sẽ ghi lại lệnh và gửi ra báo cáo.
Với việc chạy nhóm thủ tục này, chúng ta sẽ hoàn thành phần cấu hình cho rclone. Thủ tục này chỉ chạy một lần duy nhân khi chạy ứng dụng ban đầu.

Sau khi đã cài đặt xong, chúng ta chỉ cần sử dụng các dòng lệnh của rclone để thực hiện công việc tạo thư mục, sao chép, tải file lên ...vv
Nếu các bạn muốn thử, hãy dùng chính account email của mình và theo hướng dẫn sẽ có được kết quả như ý muốn.

Ứng dụng demo ở sau đây nhé, có nhiều thứ cop nhặt, có gì các bạn cứ hỏi
http://www.sfdp.net/thuthuataccess/demo/...ects=0&d=1

Trong file ví dụ của tôi có một số đặc điểm sau:
+ tbRef để lưu trứ 2 tập tin là zlib.dll và rclone.zip (bản nén của rclone).
+ Một số thủ tục giải nén/ dãn nén bằng zlib
+ Một số thủ tục lưu tập tin thư viện vào bảng tbref và bung nó từ bảng này...

Ứng dụng chạy như sau:
1. Chạy form frmUpload
Khi chạy nó sẽ kiểm tra xem đã có 2 tập tin zlib.dll và rclone.exe trong thư mục chạy hay chưa?
Nếu không có thì sẽ lấy từ trong bảng tbRef ra.

2. Khi bạn nhấn Lấy Token
+ Bạn cần có các thông tin ở texbox liên quan, hiện tại tôi dùng với 1 account thử nghiệm.
+ Chạy rclone để thiết lập cấu hình lần đầu
(lần sau nó cũng vẫn chạy như thế vì tôi không đưa ra cơ chế kiểm tra xem có cấu hình của rclone chưa).
Bây giờ việc chấp thuận cũng như nhập các thông tin khác đã được tự động hóa. Gần đây có báo đưa về việc rò rỉ an ninh liên quan đến cơ chế này, hy vọng Google sẽ sơm có cách điều chỉnh mà không làm ảnh hưởng tới công cụ này!

Và bạn có thể sửa code để tải vài file ....


Và nhiều thứ linh tinh mục khác.
Có ai hỏi gì xin cứ đặt câu hỏi nhé

Chúc các bạn tuần mới đầy niềm vui!


Bước 5: Tạo các mã xác thực
+ Nhấn APIs & auth
+ Nhấn Credentials
+ Nhấn Create new Client ID
+ Chọn Installed Application
+ Nhấn Configure consent screen
+ Mục product name ta chọn một tên thân thiện cho ứng dụng của mình, chẳng hạn ở đây tôi chọn publicdata
+ Nhấn Save
+ Chọn Installed Application, trong mục Installed application type chọn Other
+ Nhấn Create Client ID
Sau khi xong, nhấn APIs, chọn GoogleDrive rồi nhấn Enable API.

??? sao mình làm bước này không được nhỉ
không thấy các id
Chữ ký của thucgia Hix, Access quả nhiên lợi hại !!!! http://vibigaba.esy.es/
ღღღღღTài sản của thucgia (View All Items) ღღღღღ
Reply
Những người đã cảm ơn
#9
(10-08-15, 03:28 PM)paulsteigel Đã viết: Bản demo đã có nhiều sửa đổi để các cụ Test thử nhé...
Bản demo tôi cung cấp ở đây là trích từ ứng dụng đang làm dở nên có nhiều chỗ tôi comment bằng tiếng Anh, các cụ thông cảm nhé
Bản demo của tôi hiện đã có thêm chức năng tải file lên GoogleDrive.

Tôi đang dùng 1 account thử nghiệm để test, các bác có thể dùng xem sao...
============================================
Phương pháp sử dụng GoogleDrive với VBA
Đặt vấn đề:
Tôi cần ứng dụng của tôi tương tác với dịch vụ lưu trữ trên mạng: ở đây sử dụng Google Drive (do họ cung cấp miễn phí đến 15GB với sự ổn định khá cao)
Ứng dụng của tôi viết trên nền VBA và tôi cần các file của tôi có thể tải lên và tải xuống khi cần.

Phân tích:
Hiện tại Google Drive cung cấp phương thức truy nhập ổ đĩa GoogleDrive cho người dùng tuy nhiên đối với người dùng VB/VBA cổ điển thì việc thao tác với googleDrive còn nhiều phiên toái, cụ thể như sau:
+ Làm thế nào để Truy nhập vào tài khoản người dùng một cách tiện lợi?
+ Làm thế nào để sử dụng các câu lệnh GoogleAPI khi tải tập tin lên, đặc biệt là việc vượt qua cơ chế xác thực người dùng ...vv

Sau thời gian nghiên cứu các phương án thực hiện với sự tham khảo một số tài liệu trên mạng, tôi sử dụng phương án sau đây:
Công việc 1: Tạo dự án để sử dụng các dịch vụ của Google
Công việc 2: Tạo ứng dụng và các mã xác thực để sau đó có thể sử dụng dịch vụ GoogleDrive

1. Làm rõ cơ chế xác thực người dùng và thiết lập các thông tin ban đầu
Bước 1: Khi truy nhập tài khoản Google, người ta phải cung cấp tên người dùng, mật khẩu
Bước 2: Google sẽ cung cấp mã xác thực (AuthCode), người dùng sau đó phải nhấn Accept/Chấp nhận trên hộp thoại UserConsent
Bước 3: Google sẽ cung cấp Khóa truy cập (Token) và người dùng sẽ sử dụng khóa này để thao tác với các dịch vụ của Google.
Bước 4: Vào https://console.developers.google.com/project để tạo ra một dự án sử dụng các dịch vụ của google như Google Drive chẳng hạn
+ Nhấn nút Create Project
+ Chọn tên dự án, ví dụ ở đây tôi tạo PublicStorage
Sau khi đợi một lúc, ta chọn dự án PublicStorage từ hộp chọn
Bước 5: Tạo các mã xác thực
+ Nhấn APIs & auth
+ Nhấn Credentials
+ Nhấn Create new Client ID
+ Chọn Installed Application
+ Nhấn Configure consent screen
+ Mục product name ta chọn một tên thân thiện cho ứng dụng của mình, chẳng hạn ở đây tôi chọn publicdata
+ Nhấn Save
+ Chọn Installed Application, trong mục Installed application type chọn Other
+ Nhấn Create Client ID
Sau khi xong, nhấn APIs, chọn GoogleDrive rồi nhấn Enable API.

Chúng ta sẽ nhận được màn hình kết quả với các thông số trong mục Client ID for native application như sau:
Client ID: [Thay bằng mã của bạn]
Client secret: [b][Thay bằng mã của bạn][/b]
Redirect URIs: urn:ietf:wg:oauth:2.0:oob http://localhost

Hãy lưu ý Client IDClient secret, đây là những cái chúng ta cần sau này.

Đến đây bước khởi tao ban đầu của chúng ta đã hoàn tất.
Bây giờ hãy chuyển sang phần coding/ viết mã.

2. Viết mã, phân tích cơ chế.
Đáng tiếc là Google chưa xây dựng các cơ chế sử dụng dịch vụ cho ứng dụng viết bằng VBA/VB cổ điển nên chúng ta đành phải mượn công cụ của bên ngoài để thực hiện các chuỗi lệnh thao tác với GoogleDrive. Ở đây tôi đã chọn công cụ rclone viết bằng ngôn ngữ GO (công cụ lập trình của Google) và thao tác bằng dòng lệnh.

a. Truy nhập vào Google qua cơ chế xác thực OAuth
Thật may mắn là Google sử dụng cơ chế xác thực người dùng OAuth theo đó, một khi người dùng:
+ Truy nhập vào tài khoản với tên tài khoản và mật khẩu;
+ Cung cấp mã Client_ID, Client_Secret
+ Chấp nhận cho phép sử dụng ứng dụng.
Google sẽ cho phép bất kỳ ứng dụng nào với các thông tin đã cung cấp khai thác tài nguyên gắn với tài khoản người dùng thông qua một mã gọi là Token. Mỗi máy tính sẽ có một mã Token riêng.

Vậy trước tiên, chúng ta sẽ thiết kế một mô đun cho phép xác thực với OAuth. Thật may mắn, Tim Halls đã viết giúp chúng ta một Class để thực hiện việc xác thực này, tôi dùng bộ thư viện này với một số sửa đổi trong đó có mấy thủ tục chính bao gồm AuthCode để lấy Code xác thực trên trình duyệt, BrowserComplete để đánh giá khi nào trình duyệt hoàn thành việc lấy thông tin, WaitUntilLoaded để kiểm tra trạng thái của trình duyệt, InitClientCredentials để khai báo các thông tin truy cập, InitEndPoints để thiết lập các địa chỉ truy cập dịch vụ xác thực của google.

Với class này, tôi chỉ cần viết thêm một đoạn thủ tục sau đây để lấy mã

Mã:
Private Function GetAuthCode() As String
    Dim myClass As New gAuth2, client_id As String, client_secret As String
    client_id = "mã client_id của bạn"
    client_secret = "clien_secret của bạn"
    With myClass
        .LogOnGoogle "email của bạn", "mật khẩu của bạn"
        .InitClientCredentials client_id, client_secret
        .InitEndPoints
        GetAuthCode = .AuthCode
    End With
End Function


Bước 1 đã xong. Tiếp theo chúng ta sẽ phải thiết lập được phương thức cấu hình cho rclone. Ứng dụng này không thể tự động chạy mà bạn phải tự cấu hình bằng dòng lệnh thông qua thủ tục chạy rclone config và sau đó là khai báo các thông tin khác nhau cho ứng dụng. Đáng tiếc nó lại chạy giống như trong môi trường DOS (command prompt) vì thế sẽ khá khó khăn để người dùng thông thường phải làm việc này bằng tay với các dòng lệnh khô khan.
Vì ứng dụng của tôi sử dụng 1 tài khoản cho mọi người dùng vì thế tôi bắt buộc phải thiết kế để ứng dụng làm được điều này với sự can thiệp ít nhất của người dùng (Chỉ là nhấn nút đồng ý cho phép thao tác với Google Drive qua màn hình User Consent đã nói ở trên).
Như thế ta cần một cơ chế có thể truyền tham số cho rclone theo một nhóm trình tự nào đó. Đến đây ta có 2 cách tiếp cận: sử dụng SendKeys và sử dụng Shell để truyền thông tin.
Cách dùng SendKeys không tốt do nó đòi hỏi màn hình Console (ở đây là DOS) luôn phải kích hoạt. Vì thế tôi lựa chọn cách dùng Shell và giấu màn hình CMD đi rồi truyền tham số. Thủ tục thực hiện đơn giản như sau:

 ' 2 phase 2 - send to console

Mã:
Set objShell = CreateObject("WScript.Shell") ' Tạo một phiên làm việc Shell
Set oExec = objShell.Exec("CMD /K") ' mở giao diện DOS
Call HideWindow(oExec.ProcessID) ' Giấu giao diện DOS

Sau đó đến tiết mục truyền tham số cho giao diện DOS thông qua nhóm lệnh sau đây:

Mã:
With oExec
DoEvents
For i = LBound(cmdList) To UBound(cmdList)
   .StdIn.WriteLine CStr(cmdList(i)) ' truyền từng tham số vào và đợi
Next
Do Until .StdOut.AtEndOfStream
   strResults = strResults & vbCrLf & .StdOut.ReadLine ' lấy phản hồi từ giao diện
   DoEvents
Loop
End With

Toàn bộ thủ tục này như sau:


Mã:
Private Sub WriteConsole(Optional CreateNew As Boolean = False)
    ' This will try to set up google new token
    Dim objShell As Object
    Dim oExec As Object
    Dim strResults As String
    
    ' 1. Pha 1, truy nhập và lấy mã xác thực
    Dim i As Long, client_id As String, client_secret As String, ReturnValue As Long
    Dim cmdList As Variant, theCode As String
    
    client_id = "456200380740-dr4nihc6u5fslh7larcoiqi6o189liqo.apps.googleusercontent.com"
    client_secret = "duo0jfm-IhRWffLCCtpCJY48"
    
    theCode = GetAuthCode
    If CreateNew Then
        cmdList = Array(rcPath & "rclone.exe config", "n", "gdrive", "6", client_id, client_secret, theCode, "y", "q", "exit")
    Else
        cmdList = Array(rcPath & "rclone.exe config", "e", "1", "", "", "", "", "y", theCode, "y", "q", "exit")
    End If
    DoEvents
    ' 2 phase 2 - send to console
    Set objShell = CreateObject("WScript.Shell")
    Set oExec = objShell.Exec("CMD /K")
    Call HideWindow(oExec.ProcessID)

    With oExec
        ' find a way to get stick to the windows and parse data..
        DoEvents
        For i = LBound(cmdList) To UBound(cmdList)
            .StdIn.WriteLine CStr(cmdList(i)) 
            Sleep 1000 ' wait for the message to be completed
        Next
' tiếp nhận kết quả
        Do Until .StdOut.AtEndOfStream
            strResults = strResults & vbCrLf & .StdOut.ReadLine
            DoEvents
        Loop
    End With
    Set oExec = Nothing
    ' in kết quả
    Me.rtbOutput = strResults
End Sub


Thủ tục này thực hiện 2 chế đô: tạo mới cấu hình hoặc lấy token mới từ các mã hiện tại.
Trong ví dụ này, ta dùng call WriteConsole(true)
Hãy chú ý mảng
cmdList = Array(rcPath & "rclone.exe config", "n", "gdrive", "6", client_id, client_secret, theCode, "y", "q", "exit")
nó quy định thứ tự các lệnh sẽ thực hiện bao gồm từ việc tải ra chế độ cấu hình rclone cho đến khi nhập các thống số cấu hình và kết thúc.

Cú pháp
Mã:
.StdIn.WriteLine CStr(cmdList(i)) 
chịu trách nhiệm gửi lệnh
và phần sau đó sẽ ghi lại lệnh và gửi ra báo cáo.
Với việc chạy nhóm thủ tục này, chúng ta sẽ hoàn thành phần cấu hình cho rclone. Thủ tục này chỉ chạy một lần duy nhân khi chạy ứng dụng ban đầu.

Sau khi đã cài đặt xong, chúng ta chỉ cần sử dụng các dòng lệnh của rclone để thực hiện công việc tạo thư mục, sao chép, tải file lên ...vv
Nếu các bạn muốn thử, hãy dùng chính account email của mình và theo hướng dẫn sẽ có được kết quả như ý muốn.

Ứng dụng demo ở sau đây nhé, có nhiều thứ cop nhặt, có gì các bạn cứ hỏi
http://www.sfdp.net/thuthuataccess/demo/...ects=0&d=1

Trong file ví dụ của tôi có một số đặc điểm sau:
+ tbRef để lưu trứ 2 tập tin là zlib.dll và rclone.zip (bản nén của rclone).
+ Một số thủ tục giải nén/ dãn nén bằng zlib
+ Một số thủ tục lưu tập tin thư viện vào bảng tbref và bung nó từ bảng này...

Ứng dụng chạy như sau:
1. Chạy form frmUpload
Khi chạy nó sẽ kiểm tra xem đã có 2 tập tin zlib.dll và rclone.exe trong thư mục chạy hay chưa?
Nếu không có thì sẽ lấy từ trong bảng tbRef ra.

2. Khi bạn nhấn Lấy Token
+ Bạn cần có các thông tin ở texbox liên quan, hiện tại tôi dùng với 1 account thử nghiệm.
+ Chạy rclone để thiết lập cấu hình lần đầu
(lần sau nó cũng vẫn chạy như thế vì tôi không đưa ra cơ chế kiểm tra xem có cấu hình của rclone chưa).
Bây giờ việc chấp thuận cũng như nhập các thông tin khác đã được tự động hóa. Gần đây có báo đưa về việc rò rỉ an ninh liên quan đến cơ chế này, hy vọng Google sẽ sơm có cách điều chỉnh mà không làm ảnh hưởng tới công cụ này!

Và bạn có thể sửa code để tải vài file ....


Và nhiều thứ linh tinh mục khác.
Có ai hỏi gì xin cứ đặt câu hỏi nhé

Chúc các bạn tuần mới đầy niềm vui!

Hình như giao diện đường link :

https://console.developers.google.com/project

bi giờ đã được thay đổi, nên mình không thể lấy được Client ID và Client secret như bạn hướng dẫn. Hay là Google thay đổi chính sách không?

Mình tìm thấy đoạn youtube sau giống như hướng dẫn của bạn

video how to get Client ID and Client secret
Chữ ký của thucgia Hix, Access quả nhiên lợi hại !!!! http://vibigaba.esy.es/
ღღღღღTài sản của thucgia (View All Items) ღღღღღ
Reply
Những người đã cảm ơn
#10
(27-08-15, 09:05 AM)paulsteigel Đã viết:
(27-08-15, 08:53 AM)maidinhdan Đã viết: Sao không cọn Access viết vậy anh? thấy Excel là bắt đầu rầu  019

Vì tớ lười lười - thôi để đóng vào cái demo vậy...

Có bản demo cho access rồi nhé. Link ở bài đầu Dân ạ. Hoặc ở đây:
http://www.sfdp.net/thuthuataccess/demo/...ects=0&d=1
Đến tối mình sẽ trả lời bạn thugia. Giờ đang bận tí. Bạn thông cảm nhé.
Chữ ký của paulsteigel ====================
Quốc gia hưng vong
Thất phu hữu trách
====================
Reply
Những người đã cảm ơn Noname , maidinhdan , tranthanhan1962 , Che_Guevara


Có thể liên quan đến chủ đề
Chủ đề: Tác giả Trả lời: Xem: Bài mới nhất
  Cài đặt ODBC -nền tảng kết nối Access và nguồn dữ liệu khác Noname 33 19,294 01-12-16, 06:49 PM
Bài mới nhất: atula77
  Xây dựng Class Modules trong Access ( Cơ bản đến Nâng cao) maidinhdan 2 181 13-11-16, 05:32 PM
Bài mới nhất: cpucloi
  [Help] SQL lỗi khi tham chiếu trường trong Forms Phung Duc 1 71 02-11-16, 03:17 PM
Bài mới nhất: Minh Tiên
  tương tác chương trình ngoài lamvanphung 4 412 30-09-16, 02:47 AM
Bài mới nhất: maidinhdan
  Ứng dụng đổi tên file trong windows hàng loạt tranthanhan1962 7 1,211 19-09-16, 04:16 PM
Bài mới nhất: maidinhdan

Chuyển nhanh:


User(s) browsing this thread: 1 Guest(s)
Diễn Đàn Thơ Văn Thi Ẩm Lâu|Nhà Hàng Sông Thơ