如何用SetClipboardData将字符串数据放到剪贴板时避免乱码?

api函数SetClipboardData可以往剪贴板中放置数据,它的函数语法如下:

HANDLE WINAPI SetClipboardData(
  _In_     UINT   uFormat,
  _In_opt_ HANDLE hMem
);

其中参数uFormat为要放置的数据的格式,具体的可以看剪贴板的标准数据格式

hMem参数比较复杂,如果是要放置到剪贴板的数据是字符串数据,则hMem参数表示用于存放字符串数据的内存对象的句柄。

当我们往剪贴板中放置中文字符时,比如放置字符串”我和你”,用以下的代码:

Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Declare Function SetClipboardData Lib "user32" (ByVal Format As Long, ByVal hMem As Long) As Long
Declare Function CloseClipboard Lib "user32" () As Long
Declare Function EmptyClipboard Lib "user32" () As Long
Declare Function GlobalAlloc Lib "kernel32" (ByVal Flags As Long, ByVal length As Long) As Long
Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal pDest As Long, ByVal pSource As Long, ByVal length As Long)
Const CF_TEXT = 1
Const CF_UNICODETEXT = 13
Const GHND = &H42
Sub QQ1722187970()
    Dim str1 As String
    '要放到剪贴板中的字符串
    str1 = "我和你"
    Dim hMem As Long
    '内存对象的句柄
    hMem = GlobalAlloc(GHND, LenB(str1) + 2)
    Dim lHwnd As Long
    '锁定内存块,获取内存对象的第一个字节的内存地址
    lHwnd = GlobalLock(hMem)
    '将字符串至于剪贴板内存中
    CopyMemory lHwnd, StrPtr(str1), LenB(str1) + 2
    '解锁内存块
    GlobalUnlock (hMem)
    OpenClipboard (0)
    EmptyClipboard
    '关联剪贴板对象到指定的内存对象句柄
    SetClipboardData CF_TEXT, hMem
    CloseClipboard
    Debug.Print VBA.Hex(lHwnd), VBA.Hex(StrPtr(str1))
End Sub

运行以上代码后,打开excel剪贴板,会发现剪贴板中显示的是乱码字符。

原因是我们设置的剪贴板数据格式不对,因为excel中字符串都是以unicode字符存储的,所以只需要把设置的剪贴板数据格式从CF_TEXT改成CF_UNICODETEXT即可。

也就是把以上代码中的

SetClipboardData CF_TEXT, hMem 

改成

SetClipboardData CF_UNICODETEXT, hMem

即可避免乱码了,改后的代码如下:

Declare Function OpenClipboard Lib "user32" (ByVal hwnd As Long) As Long
Declare Function SetClipboardData Lib "user32" (ByVal Format As Long, ByVal hMem As Long) As Long
Declare Function CloseClipboard Lib "user32" () As Long
Declare Function EmptyClipboard Lib "user32" () As Long
Declare Function GlobalAlloc Lib "kernel32" (ByVal Flags As Long, ByVal length As Long) As Long
Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Declare Function GlobalFree Lib "kernel32" (ByVal hMem As Long) As Long
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal pDest As Long, ByVal pSource As Long, ByVal length As Long)
Const CF_TEXT = 1
Const CF_UNICODETEXT = 13
Const GHND = &H42
Sub QQ1722187970()
    Dim str1 As String
    '要放到剪贴板中的字符串
    str1 = "我和你"
    Dim hMem As Long
    '内存对象的句柄
    hMem = GlobalAlloc(GHND, LenB(str1) + 2)
    Dim lHwnd As Long
    '锁定内存块,获取内存对象的第一个字节的内存地址
    lHwnd = GlobalLock(hMem)
    '将字符串至于剪贴板内存中
    CopyMemory lHwnd, StrPtr(str1), LenB(str1) + 2
    '解锁内存块
    GlobalUnlock (hMem)
    OpenClipboard (0)
    EmptyClipboard
    '关联剪贴板对象到指定的内存句柄
    SetClipboardData CF_UNICODETEXT, hMem
    CloseClipboard
    Debug.Print VBA.Hex(lHwnd), VBA.Hex(StrPtr(str1))
End Sub
       

发表评论