VBA 中的 UTF-8 字符 Shell_NotifyIconW [英] UTF-8 Characters Shell_NotifyIconW in VBA
问题描述
Shell_NotifyIcon Windows API 向任务栏的状态区域发送消息.
Shell_NotifyIcon Windows API sends a message to the taskbar's status area.
我正在寻找一种方法,让 Windows 通知 API 可以使用 UTF-8 字符.
I'm looking a way to make Windows notification API works with UTF-8 characters.
下面的代码运行良好,但仅限于 ANSI 字符.
The code below works well, but only with ANSI characters.
UTF-8 字符显示为??".
The UTF-8 Characters are displayed as "??".
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 并不能解决问题.
Simply changing the A to W in windows API declaration doesn't fix it.
有人有使用 Shell_NotifyIconW 处理 UTF-8 字符的经验吗?
Anyone have experience using Shell_NotifyIconW for UTF-8 charachters?
我已经尝试过下面的代码,但它不起作用.
I've tried with the code below, but it doesn't work.
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).一种是概念,另一种是坚持该概念的方式.
Unicode and UTF-8 are not interchangeable terms (please see https://www.joelonsoftware.com/articles/Unicode.html). One is a concept, and the other is a way of persisting that concept.
W
函数以 UTF-16 的形式使用 Unicode,因此您希望以这种方式向它们提供 Unicode.
W
functions in Windows use Unicode in the form of UTF-16, so you want to provide Unicode to them in that fashion.
您的 A
和 W
版本都没有正确声明,您想先修复它.
然后,对于 W
函数,您必须避免 隐式字符串转换 VB 执行,对于您需要将固定长度的字符串声明为字节数组.因为 VB 字符串已经是 UTF-16 中的 Unicode,这是 W
函数所期望的,您只需要将这些字符串中的字节复制到这些字节数组中.不需要转换,但您需要小心将每个字符串中的最后两个字节留为零.
Both your A
and W
versions are not declared correctly, you want to fix that first.
Then, for the W
function, you have to avoid the implicit string conversion VB performs, for which you need to declare the fixed length strings as byte arrays. Because VB strings are already Unicode in UTF-16, which is what W
functions expect, you simply need to copy the bytes from these strings into these byte arrays. No conversion is necessary, but you need to be careful to leave the last two bytes as zeroes in each string.
请注意,与 A
函数不同,W
函数要求您同时提供标题和信息(即 在文档中提到).如果您只提供一个,则不会显示.
Note that unlike the A
function, the W
function requires you to provide both the title and the info (which is called out in the documentation). If you only provide one, it won't show.
另请注意,不幸的是,VBA 没有为 64 位结构成员提供正确的填充,这严重破坏了 code>LongPtr,所以你需要自己提供.
Also note that unfortunately VBA does not provide correct padding for structure members in 64 bits which heavily undermines the usefulness of LongPtr
, so you would need to provide that yourself.
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)
这篇关于VBA 中的 UTF-8 字符 Shell_NotifyIconW的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!