这不是一个简单的问题 - 答案围绕 VBA 中的几个令人沮丧的空白。
VBA.InputBox 函数创建一个“模态对话框”,在您需要 VBA 获取窗口句柄并调用某些或其他 API 函数的确切时刻,使您的应用程序的 VBA 代码处于等待状态。
当“模态”状态被释放,允许 VBA 再次运行命令和 API 函数时,InputBox 已经消失了。
幸运的是,“manish1239”在 2003 年 10 月发现了一种解决方法,他在Xtreme Visual Basic Talk上发布了一个巧妙的 hack :他将您需要运行的代码放在围绕该等待状态运行的 VBA 函数中,使用来自API 计时器。
我使用他的代码在 VBA InputBox 中设置“PasswordChars”:这是一个需要 InputBox 窗口句柄的 API 调用,您可以根据需要调整代码
公共函数输入框密码(提示为字符串,_
可选默认为 String = vbNullString, _
可选 XPos,可选 YPos,_
可选的 HelpFile,可选的 HelpContext _
) 作为字符串
出错时继续下一步
' 复制 VBA InputBox 函数的功能,使用用户的
' 键入的输入显示为星号。对话框的“标题”参数
' 标题在此实现中被硬编码为“需要密码”。
' 需要的函数:TimerProcInputBox
' 需要的 API 声明:FindWindow、FindWindowEx、SetTimer、KillTimer
’ 奈杰尔·赫弗南,2015 年 1 月,
' **** **** **** *** 此代码在公共域中 **** **** **** ****
' 基于用户 'manish1239' 在 Xtreme Visual Basic Talk 中发布的代码
' 2003 年 10 月http://www.xtremevbtalk.com/archive/index.php/t-112708.html
' 编码说明:我们将 'Set PasswordChar' 消息发送到文本框编辑
' VBA 'InputBox' 对话框中的窗口。这不是一个简单的任务:
' InputBox 是同步的,一个离开我们应用程序的“模态对话框”
' VBA 代码在我们需要调用发送的确切时刻处于等待状态
' 消息 API 函数。所以它通过来自 API Timer 的延迟回调运行
' 警告:网上发布的许多 64 位 API 声明不正确
' 并且它们都不适合指针安全的 Timer API 函数。
出错时继续下一步
SetTimer 0&, 0&, 10&, AddressOf TimerProcInputBox
输入框密码 = 输入框(提示,_
PASSBOX_INPUT_CAPTION,_
默认, _
XPos,YPos,_
帮助文件,帮助上下文)
结束功能
#If VBA7 And Win64 Then ' 64-bit Excel under 64-bit windows ' 使用 LongLong 和 LongPtr
' 请注意 wMsg 始终是 WM_TIMER 消息,它适合 Long
公共子 TimerProcInputBox(ByVal hwnd As LongPtr, _
ByVal wMsg 只要,_
ByVal idEvent As LongPtr, _
ByVal dwTime As LongLong)
出错时继续下一步
' REQUIRED for Function InputBoxPassword
' https://msdn.microsoft.com/en-US/library/windows/desktop/ms644907(v=vs.85).aspx
KillTimer hWndIbox, idEvent
Dim hWndIbox As LongPtr ' Handle to VBA InputBox
hWndIbox = FindWindowEx(FindWindow("#32770", PASSBOX_INPUT_CAPTION), 0, "Edit", "")
If hWndIbox <> 0 Then
SendMessage hWndIbox, EM_SETPASSWORDCHAR, Asc("*"), 0&
End If
End Sub
#ElseIf VBA7 Then ' VBA7 in 32-Bit Office ' 仅使用 LongPtr
Public Sub TimerProcInputBox(ByVal hwnd As LongPtr, _
ByVal wMsg As Long, _
ByVal idEvent As LongPtr, _
ByVal dwTime As Long)
On Error Resume Next
' REQUIRED for Function InputBoxPassword
' https://msdn.microsoft.com/en-US/library/windows/desktop/ms644907(v=vs.85).aspx
Dim hWndIbox As LongPtr ' Handle to VBA InputBox
KillTimer hwnd, idEvent
hWndIbox = FindWindowEx(FindWindow("#32770", PASSBOX_INPUT_CAPTION), 0, "Edit", "")
If hWndIbox <> 0 Then
SendMessage hWndIbox, EM_SETPASSWORDCHAR, Asc("*"), 0&
End If
End Sub
#Else ' 32 位 Excel
Public Sub TimerProcInputBox(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal idEvent As Long, _
ByVal dwTime As Long)
On Error Resume Next
' REQUIRED for Function InputBoxPassword
' https://msdn.microsoft.com/en-US/library/windows/desktop/ms644907(v=vs.85).aspx
Dim hWndIbox As Long ' Handle to VBA InputBox
KillTimer hwnd, idEvent
hWndIbox = FindWindowEx(FindWindow("#32770", PASSBOX_INPUT_CAPTION), 0&, "Edit", "")
If hWndIbox <> 0 Then
SendMessage hWndIbox, EM_SETPASSWORDCHAR, Asc("*"), 0&
End If
End Sub
#万一
您将需要以下声明:
选项显式
选项专用模块
#If VBA7 And Win64 Then ' 64-bit Excel under 64-bit windows ' 使用 LongLong 和 LongPtr
Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As LongPtr, _
ByVal hWnd2 As LongPtr, _
ByVal lpsz1 As String, _
ByVal lpsz2 As String _
) As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As LongPtr, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any _
) As LongPtr
Private Declare PtrSafe Function SetTimer Lib "user32" _
(ByVal hwnd As LongPtr, _
ByVal nIDEvent As LongPtr, _
ByVal uElapse As Long, _
ByVal lpTimerFunc As LongPtr _
) As Long
Public Declare PtrSafe Function KillTimer Lib "user32" _
(ByVal hwnd As LongPtr, _
ByVal nIDEvent As LongPtr _
) As Long
#ElseIf VBA7 Then 'VBA7 in 32-Bit Office ' 仅使用 LongPtr,LongLong 不可用
Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As LongPtr, _
ByVal hWnd2 As LongPtr, _
ByVal lpsz1 As String, _
ByVal lpsz2 As String _
) As LongPtr
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As LongPtr, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any _
) As LongPtr
Private Declare PtrSafe Function SetTimer Lib "user32" _
(ByVal hwnd As LongPtr, _
ByVal nIDEvent As Long, _
ByVal uElapse As Long, _
ByVal lpTimerFunc As LongPtr) As LongPtr
Private Declare PtrSafe Function KillTimer Lib "user32" _
(ByVal hwnd As LongPtr, _
ByVal nIDEvent As Long) As Long
#Else ' 32 位 Excel
Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" _
(ByVal hWnd1 As Long, _
ByVal hWnd2 As Long, _
ByVal lpsz1 As String, _
ByVal lpsz2 As String _
) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
(ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _
(ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByRef lParam As Any _
) As Long
Private Declare Function SetTimer Lib "user32" _
(ByVal hwnd As Long, _
ByVal nIDEvent As Long, _
ByVal uElapse As Long, _
ByVal lpTimerFunc As Long) As Long
Public Declare Function KillTimer Lib "user32" _
(ByVal hwnd As Long, _
ByVal nIDEvent As Long) As Long
#万一
Private Const PASSBOX_INPUT_CAPTION As String = "需要密码"
Private Const EM_SETPASSWORDCHAR As Long = &HCC
Private Const NV_INPUTBOX 只要 = &H5000&
我将其发布在我的博客 Excellerando 上,标题为:
.
与往常一样,请注意代码中不需要的换行符。