Code đưa chuỗi unicode vào clipboard

Liên hệ QC

truongvu317

Thành viên tích cực
Tham gia
15/11/10
Bài viết
942
Được thích
684
Giới tính
Nữ
Xin chào các bạn! Mình có sưu tập được một đoạn code dùng để copy chuỗi vào clipboard. Code này khi copy chuỗi là tiếng việt có dấu thì sẽ bị hiện tượng một số ký tự bị chuyển thành dấu "?". Vậy mình xin nhờ các bạn giúp mình sửa code này hoặc viết mới code cũng được, để có thể copy chuỗi tiếng việt có dấu mà không bị lỗi trên. Mình xin cảm ơn sự giúp đỡ của các bạn.



Mã:
Option Explicit


#If Mac Then
    ' ignore
#Else
    #If VBA7 Then
        Private Declare PtrSafe Function GlobalUnlock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
        Private Declare PtrSafe Function GlobalLock Lib "kernel32" (ByVal hMem As LongPtr) As LongPtr
        Private Declare PtrSafe Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, _
                                                             ByVal dwBytes As LongPtr) As LongPtr

        Private Declare PtrSafe Function CloseClipboard Lib "user32" () As Long
        Private Declare PtrSafe Function OpenClipboard Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
        Private Declare PtrSafe Function EmptyClipboard Lib "user32" () As Long

        Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, _
                                                         ByVal lpString2 As Any) As LongPtr

        Private Declare PtrSafe Function SetClipboardData Lib "user32" (ByVal wFormat _
                                                                As Long, ByVal hMem As LongPtr) As LongPtr
    #Else
        Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
        Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
        Declare Function GlobalAlloc Lib "kernel32" (ByVal wFlags As Long, _
                                                     ByVal dwBytes As Long) As Long

        Declare Function CloseClipboard Lib "user32" () As Long
        Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
        Declare Function EmptyClipboard Lib "user32" () As Long

        Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, _
                                                 ByVal lpString2 As Any) As Long

        Declare Function SetClipboardData Lib "user32" (ByVal wFormat _
                                                        As Long, ByVal hMem As Long) As Long
    #End If
#End If
Private Const GHND = &H42
Private Const CF_TEXT = 1
Private Const MAXSIZE = 4096

Sub ClipBoard_SetData(MyString As String)
    #If Mac Then
        With New MSForms.DataObject
            .SetText MyString
            .PutInClipboard
        End With
    #Else
        #If VBA7 Then
            Dim hGlobalMemory As LongPtr
            Dim hClipMemory   As LongPtr
            Dim lpGlobalMemory    As LongPtr
        #Else
            Dim hGlobalMemory As Long
            Dim hClipMemory   As Long
            Dim lpGlobalMemory    As Long
        #End If

        Dim X                 As Long

        ' Allocate moveable global memory.
        '-------------------------------------------
        hGlobalMemory = GlobalAlloc(GHND, Len(MyString) + 1)

        ' Lock the block to get a far pointer
        ' to this memory.
        lpGlobalMemory = GlobalLock(hGlobalMemory)

        ' Copy the string to this global memory.
        lpGlobalMemory = lstrcpy(lpGlobalMemory, MyString)

        ' Unlock the memory.
        If GlobalUnlock(hGlobalMemory) <> 0 Then
            MsgBox "Could not unlock memory location. Copy aborted."
            GoTo OutOfHere2
        End If

        ' Open the Clipboard to copy data to.
        If OpenClipboard(0&) = 0 Then
            MsgBox "Could not open the Clipboard. Copy aborted."
            Exit Sub
        End If

        ' Clear the Clipboard.
        X = EmptyClipboard()

        ' Copy the data to the Clipboard.
        hClipMemory = SetClipboardData(CF_TEXT, hGlobalMemory)

OutOfHere2:

        If CloseClipboard() = 0 Then
            MsgBox "Could not close Clipboard."
        End If
    #End If

End Sub
 
1. Trong phần khai báo API
sửa
Mã:
Private Declare PtrSafe Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, _
                                                         ByVal lpString2 As Any) As LongPtr
...
Declare Function lstrcpy Lib "kernel32" (ByVal lpString1 As Any, _
                                                 ByVal lpString2 As Any) As Long

thành

Mã:
Private Declare PtrSafe Function lstrcpyW Lib "kernel32" (ByVal lpString1 As Any, _
                                                         ByVal lpString2 As Any) As LongPtr
...
Private Declare Function lstrcpyW Lib "kernel32" (ByVal lpString1 As Any, _
                                                 ByVal lpString2 As Any) As Long

2. Thêm hằng số
Mã:
Private Const CF_UNICODETEXT = 13

3. Tôi viết lại Sub ClipBoard_SetData. Tôi giữ nguyên code, chỉ thay đổi những gì cần phải thay và rút gọn tên biến. Muốn biết những chỗ nào quan trọng thì so sánh code trước và code tôi đã sửa.

Mã:
Sub ClipBoard_SetData(ByVal ExcelString As String)
    #If Mac Then
        With New MSForms.DataObject
            .SetText ExcelString
            .PutInClipboard
        End With
    #Else
        #If VBA7 Then
            Dim hData As LongPtr
            Dim pData    As LongPtr
        #Else
            Dim hData As Long
            Dim pData    As Long
        #End If
       
        ExcelString = StrConv(ExcelString, vbUnicode)
        ' Allocate moveable global memory.
        '-------------------------------------------
        hData = GlobalAlloc(GHND, Len(ExcelString) + 1)

        ' Lock the block to get a far pointer
        ' to this memory.
        pData = GlobalLock(hData)

        ' Copy the string to this global memory.
        pData = lstrcpyW(pData, ExcelString)

        ' Unlock the memory.
        If GlobalUnlock(hData) <> 0 Then
            MsgBox "Could not unlock memory location. Copy aborted."
            GoTo OutOfHere2
        End If

        ' Open the Clipboard to copy data to.
        If OpenClipboard(0) = 0 Then
            MsgBox "Could not open the Clipboard. Copy aborted."
            Exit Sub
        End If

        ' Clear the Clipboard.
        EmptyClipboard

        ' Copy the data to the Clipboard.
        SetClipboardData CF_UNICODETEXT, hData

OutOfHere2:

        If CloseClipboard() = 0 Then
            MsgBox "Could not close Clipboard."
        End If
    #End If

End Sub

Giả sử trong sheet1 trong A1 có văn bản tiếng Việt. Hãy chạy code sau
Mã:
Sub test()
Dim text As String
    text = Sheet1.Range("A1").Value
    ClipBoard_SetData text
End Sub
 
Upvote 0
Bạn sửa như sau để có thể thêm mã Unicode vào Clipboard:

lstrcpy khai báo thêm Alias "lstrcpyW", nên đổi khai báo lstrcpy thành wstrcpy


Vì unicode được cấp 2 byte bộ nhớ lưu trữ nên:
hGlobalMemory = GlobalAlloc(GHND, Len(MyString) + 1)
Sang:
hGlobalMemory = GlobalAlloc(GHND, LenB(MyString) + 2)

lstrcpyW nhận đối số không phải kiểu string mà là kiểu BSTR nên cần sử dụng StrPtr:
pData = lstrcpy(pData, ExcelString)
Sang:
pData = wstrcpy(pData, StrPtr(ExcelString))

Format của Unicode là &H13 chứ không phải &H1:
SetClipboardData(13&, hGlobalMemory)
 
Upvote 0
Tôi viết lại Sub ClipBoard_SetData
Cháu thử code rùi, cơ bản là bác viết mới lại. Code đã chạy như mong muốn của cháu hihi, Có điều gì cháu cần lưu ý thêm khi dùng code này không ạ. Cháu cảm ơn bác nhiều!!!


Cảm ơn bạn! Mình có làm theo hướng dẫn thì chạy đúng rùi. Code này mình tìm trên mạng của nước ngoài, nên họ không có sài được cho unicode.
 
Upvote 0
Cháu thử code rùi, cơ bản là bác viết mới lại. Code đã chạy như mong muốn của cháu hihi, Có điều gì cháu cần lưu ý thêm khi dùng code này không ạ. Cháu cảm ơn bác nhiều!!!



Cảm ơn bạn! Mình có làm theo hướng dẫn thì chạy đúng rùi. Code này mình tìm trên mạng của nước ngoài, nên họ không có sài được cho unicode.
Tôi test code bác batman1 thấy lỗi thiếu ký tự mà bạn nói "chạy như mong muốn", + 1 khác + 2 nhé bạn, cẩn thận.
ClipBoard_SetData "chạy như mong muốn"
"Học vẹc" cách học của những người nôn nóng
 
Upvote 0
Cháu thử code rùi, cơ bản là bác viết mới lại. Code đã chạy như mong muốn của cháu hihi, Có điều gì cháu cần lưu ý thêm khi dùng code này không ạ. Cháu cảm ơn bác nhiều!!!



Cảm ơn bạn! Mình có làm theo hướng dẫn thì chạy đúng rùi. Code này mình tìm trên mạng của nước ngoài, nên họ không có sài được cho unicode.
Mình test thử thì thấy lỗi đối với các từ như thế này: "biển", "buổi", "đường" (dù +1 hay +2), bạn thử lại xem?
 
Upvote 0
Bạn sửa như sau để có thể thêm mã Unicode vào Clipboard:
Vì unicode được cấp 2 byte bộ nhớ lưu trữ nên:
hGlobalMemory = GlobalAlloc(GHND, Len(MyString) + 1)
Sang:
hGlobalMemory = GlobalAlloc(GHND, LenB(MyString) + 2)


Format của Unicode là &H13 chứ không phải &H1:
Đúng là tôi sơ ý bỏ qua chỗ này. Phải là +2

lstrcpy khai báo thêm Alias "lstrcpyW", nên đổi khai báo lstrcpy thành wstrcpy
Trong thư viện kernel32 không có cái gọi là lstrcpy mà chỉ có lstrcpyA, lstrcpyW nên có thể khai báo
lstrcpy Lib "kernel32" Alias "lstrcpyA"
lstrcpy Lib "kernel32" Alias "lstrcpyW"

Hoặc khai báo thẳng chả Alias gì cả

lstrcpyW (hoặc lstrcpyA nếu dùng ANSI). Tôi dùng kiểu này.

lstrcpyW nhận đối số không phải kiểu string mà là kiểu BSTR nên cần sử dụng StrPtr:
StrPtr hoặc StrConv như tôi dùng.

Format của Unicode là &H13 chứ không phải &H1:
Format của Unicode là &H0D. Hoặc &H0D hoặc 13 chứ làm gì có &H13.

ôi test code bác batman1 thấy lỗi thiếu ký tự mà bạn nói "chạy như mong muốn", + 1 khác + 2 nhé bạn, cẩn thận.
Sơ ý bỏ qua là chuyện thường, con người mà. Vả lại tôi đọc ban đêm, bạn đọc ban ngày. Sơ ý thôi chứ không phải là không biết, bạn làm gì mà chế diễu thế.
 
Upvote 0
+ 1 khác + 2 nhé bạn, cẩn thận.
à, cái này là mình đi nhờ code, lúc có code chạy thử thì thấy nó ra đúng kết quả nên tin tưởng là được. chứ mình mà có thầy dạy về API thì mới hiểu ý nghĩ của +1 hay +2 có nghĩa là gì. Code này mình xin về dùng trong công việc của mình, trong khi dùng nếu phát hiện chưa chuẩn thì lại lên GPE nhờ các bác bảo hành thêm.
 
Upvote 0
à, cái này là mình đi nhờ code, lúc có code chạy thử thì thấy nó ra đúng kết quả nên tin tưởng là được. chứ mình mà có thầy dạy về API thì mới hiểu ý nghĩ của +1 hay +2 có nghĩa là gì. Code này mình xin về dùng trong công việc của mình, trong khi dùng nếu phát hiện chưa chuẩn thì lại lên GPE nhờ các bác bảo hành thêm.
Code thì miễn phí nhưng bảo hành thì có phí, hehe.
 
Upvote 0
Mọi sự giúp đỡ từ siwtom, batman1 đều miễn phí. Nhiều người muốn tranh thủ GPE để kiếm chác nhưng siwtom và batman1 không bao giờ. Đã không, hiện không, và sẽ không bao giờ có số di động, MOMO hay bất cứ thứ gì. Cũng không có kiểu như nhiều người gửi tin nhắn cho người hỏi để mồi chài, để chào mời "dịch vụ" của cá nhân.
 
Upvote 0
Hù, hết hồn. Bác nói tôi sợ quá.
Tôi biết mà bác. Đùa thì có lẽ tôi hơi kém, bị bác xạc cho 1 trận rồi, chứ chuyện bác nói ở bên trên thì không thể không biết được.

Tôi xin lỗi bác về chuyện hôm trước lần nữa! Mong bác bình thường hóa quan hệ.
 
Upvote 0
Web KT

Bài viết mới nhất

Back
Top Bottom