excel - VBA 中的 UTF-8 字符 Shell_NotifyIconW
问题描述
Shell_NotifyIcon Windows API 将消息发送到任务栏的状态区域。
我正在寻找一种使 Windows 通知 API 与 UTF-8 字符一起工作的方法。
下面的代码运行良好,但仅适用于 ANSI 字符。
UTF-8 字符显示为“??”。
Option Explicit
Private Declare PtrSafe Function Shell_NotifyIconA Lib "shell32.dll" (ByVal dwMessage As Long, ByRef nfIconData As NOTIFYICONDATA) As LongPtr
Public nfIconData As NOTIFYICONDATA
Private Type NOTIFYICONDATA
cbSize As Long
hwnd As LongPtr
uID As Long
uFlags As Long
uCallbackMessage As Long
hIcon As LongPtr
szTip As String * 128
dwState As Long
dwStateMask As Long
szInfo As String * 256
uTimeout As Long
szInfoTitle As String * 64
dwInfoFlags As Long
End Type
Public Function toast(Optional ByVal title As String, Optional ByVal info As String, Optional ByVal flag As Long)
With nfIconData
.dwInfoFlags = flag
.uFlags = &H10
.szInfoTitle = title
.szInfo = info
.cbSize = &H1F8
End With
Shell_NotifyIconW &H0, nfIconData
Shell_NotifyIconW &H1, nfIconData
End Function
'Flags for the balloon message..
'None = 0
'Information = 1
'Exclamation = 2
'Critical = 3
Sub TestANSI()
toast "Hi"
End Sub
Sub testUTF8()
toast ChrW(55357) & ChrW(56397)
End Sub
只需将 Windows API 声明中的 A 更改为 W 并不能解决此问题。
有人有使用 Shell_NotifyIconW 处理 UTF-8 字符的经验吗?
我已经尝试使用下面的代码,但它不起作用。
Option Explicit
Private Declare PtrSafe Function Shell_NotifyIconW Lib "shell32.dll" (ByVal dwMessage As Long, ByRef nfIconData As NOTIFYICONDATA) As LongPtr
Public nfIconData As NOTIFYICONDATA
Private Type NOTIFYICONDATA
cbSize As Long
hwnd As LongPtr
uID As Long
uFlags As Long
uCallbackMessage As Long
hIcon As LongPtr
szTip As String * 128
dwState As Long
dwStateMask As Long
szInfo As String * 256
uTimeout As Long
szInfoTitle As String * 64
dwInfoFlags As Long
End Type
Public Function toast(Optional ByVal title As String, Optional ByVal info As String, Optional ByVal flag As Long)
With nfIconData
.dwInfoFlags = flag
.uFlags = &H10
.szInfoTitle = title
.szInfo = info
.cbSize = &H1F8
End With
Shell_NotifyIconW &H0, nfIconData
Shell_NotifyIconW &H1, nfIconData
End Function
'Flags for the balloon message..
'None = 0
'Information = 1
'Exclamation = 2
'Critical = 3
Sub TestANSI()
toast "Hi"
End Sub
Sub testUTF8()
toast ChrW(55357) & ChrW(56397)
End Sub
解决方案
Unicode和UTF-8不是可互换的术语(请参阅https://www.joelonsoftware.com/articles/Unicode.html)。一个是一个概念,另一个是坚持这个概念的一种方式。
W
Windows 中的函数使用 UTF-16 形式的 Unicode,因此您希望以这种方式为它们提供 Unicode。
你的A
和W
版本都没有正确声明,你想先解决这个问题。
然后,对于W
函数,您必须避免 VB 执行的隐式字符串转换,为此您需要将固定长度的字符串声明为字节数组。因为 VB 字符串已经是 UTF-16 中的 Unicode,这是W
函数所期望的,所以您只需将这些字符串中的字节复制到这些字节数组中。不需要转换,但您需要小心将每个字符串中的最后两个字节保留为零。
请注意,与A
函数不同的是,该W
函数要求您同时提供标题和信息(在文档中已提及)。如果您只提供一个,它将不会显示。
另请注意,不幸的是,VBA没有为64 位结构成员提供正确的填充,这严重破坏了 的有用性LongPtr
,因此您需要自己提供。
Option Explicit
Private Declare PtrSafe Function Shell_NotifyIconW Lib "shell32.dll" (ByVal dwMessage As Long, ByRef nfIconData As NOTIFYICONDATAW) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Type NOTIFYICONDATAW
cbSize As Long
#If Win64 Then
padding1 As Long
#End If
hwnd As LongPtr
uID As Long
uFlags As Long
uCallbackMessage As Long
#If Win64 Then
padding2 As Long
#End If
hIcon As LongPtr
szTip(1 To 128 * 2) As Byte
dwState As Long
dwStateMask As Long
szInfo(1 To 256 * 2) As Byte
uTimeout As Long
szInfoTitle(1 To 64 * 2) As Byte
dwInfoFlags As Long
End Type
Private Const NIM_ADD As Long = &H0&
Private Const NIM_MODIFY As Long = &H1&
Private Const NIF_INFO As Long = &H10&
Private Function Min(ByVal a As Long, ByVal b As Long) As Long
If a < b Then Min = a Else Min = b
End Function
Public Sub Toast(Optional ByVal title As String, Optional ByVal info As String, Optional ByVal flag As Long)
Dim nfIconData As NOTIFYICONDATAW
With nfIconData
.cbSize = Len(nfIconData)
.uFlags = NIF_INFO
.dwInfoFlags = flag
If Len(title) > 0 Then
CopyMemory ByVal VarPtr(.szInfoTitle(LBound(.szInfoTitle))), ByVal StrPtr(title), Min(Len(title) * 2, UBound(.szInfoTitle) - LBound(.szInfoTitle) + 1 - 2)
End If
If Len(info) > 0 Then
CopyMemory ByVal VarPtr(.szInfo(LBound(.szInfo))), ByVal StrPtr(info), Min(Len(info) * 2, UBound(.szInfo) - LBound(.szInfo) + 1 - 2)
End If
End With
Shell_NotifyIconW NIM_ADD, nfIconData
Shell_NotifyIconW NIM_MODIFY, nfIconData
End Sub
Toast ChrW$(55357) & ChrW$(56397), ChrW$(55357) & ChrW$(56397)
推荐阅读
- python - 删除pandas python中的方括号将numpy数组导出到excel
- version-control - 是否可以在同一个项目中使用 Plastic SCM 和 Gluon?
- javascript - 在组件卸载之前 setTimeout 未完全取消
- python-3.x - 散景中网络节点的多个字形
- node.js - 将异步函数的行为更改为同步
- jquery - 需要 Jquery Regex 来验证字母数字空格和以下字符 [],./\
- algorithm - 确定集合是否是集合中任何成员的子集
- sql-server - 插入到具有只读主键列的表中
- c# - 我不明白 xaml 对齐方式
- bash - Bash:使用';'回显多个命令的结果