获取 Excel InputBox 方法的 hwnd

Posted

技术标签:

【中文标题】获取 Excel InputBox 方法的 hwnd【英文标题】:Get hwnd of Excel InputBox Method 【发布时间】:2013-09-17 06:49:53 【问题描述】:

我想我有一个相当简单的问题。我正在寻找一种方法来获取 excel 输入框的 hwnd。我正在自动化一个过程,我注意到 8 型输入框始终位于 excel 窗口下方(如果有帮助,我正在从另一个应用程序中自动化 excel。)。显然,我希望它显示在顶部,并且我正在尝试使用 SetForegroundWindow 函数。有什么建议吗?

根据要求,我发现唯一值得尝试的方法:

Public Function GetHwnd() as Long
     GetHwnd = Excel.Application.InputBox.hwnd
End Function

【问题讨论】:

如果你的代码不能工作,那么最好包含它。 我会添加它,但它或多或少没用。我只需要一些方法来获取该输入框的 hwnd。 这个答案有帮助吗? ***.com/q/15922300/2258 @RichardMorgan 它应该回答这个问题 :) OP 将需要使用 WinAPI 中的 FindWindowFindWindowExSendMessage 函数。这些都包含在链接到问题的接受答案中。 @RichardMorgan 技术上是的,技术上不是。它让我走上了我认为我正在寻找的正确轨道,但事实证明我只需要调整隐藏和显示窗口的时间和顺序即可获得我正在寻找的效果。至于找到输入框窗口,由于代码在该行上,我不确定您是否可以在 vba 中编写代码来找到该窗口的句柄。如果这是有道理的,但我可能也不对。无论如何,我找到了解决问题的方法,感谢大家的帮助和建议! 【参考方案1】:

这不是一个简单的问题 - 答案围绕 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

' Nigel Heffernan,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 计时器的延迟回调运行

' 警告:网上发布的许多 64 位 API 声明不正确 ' 并且 none 对于指针安全的 Timer API 函数是正确的。

出错后继续下一步

SetTimer 0&, 0&, 10&, AddressOf TimerProcInputBox

InputBoxPassword = InputBox(提示, _ 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 windows under 64 bit Excel' Use LongLong and 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 上,标题为:

Asterisk the Galling: Using The VBA InputBox() For Passwords

与往常一样,请注意代码中不需要的换行符。

【讨论】:

以上是关于获取 Excel InputBox 方法的 hwnd的主要内容,如果未能解决你的问题,请参考以下文章

Application.Inputbox [LEFT] 和 [TOP] 在 Excel Vba 中不起作用。为啥?

excel将一个工作表根据条件拆分成多个工作簿,运行后,跳出类worksheet的delete方法无效

[VBA]简单的修改Excel表

c# winform 输入框

在EXCEL中 如何用VBA查找某特定单元格并返回该单元格的行和列值?

excel vba计算数学四则运算的字符串问题