春节后第一天上班,先给大家拜年啦
顺便讨教一个头疼的问题:
我的程序调用一个别人的应用程序,弹出一个小窗体,但是此时正在做其他操作,比如编写文档.
跳出的窗体将输入焦点抢走了,很恼人... 请问各位有没有办法可以让输入正常哇~
调用代码就一句: Shell(App.path & "\popup.exe", vbNormalNoFocus)
顺便讨教一个头疼的问题:
我的程序调用一个别人的应用程序,弹出一个小窗体,但是此时正在做其他操作,比如编写文档.
跳出的窗体将输入焦点抢走了,很恼人... 请问各位有没有办法可以让输入正常哇~
调用代码就一句: Shell(App.path & "\popup.exe", vbNormalNoFocus)
ShowWindow
SetWindowPos
PostMessage
SetForegroundWindow
SetActiveWindow
SetFocus
这些都试了(可能用的不正确还是咋的),头大呀。
VbMinimizedNoFocus 6 窗口会以一个图标来显示。而当前活动的的窗口仍然保持活动。
shell参数是这么说的
在shell后面SetFocus也不行吗?
我用一个timer让它到时间运行那个exe (先用GetForegroundWindow获取到了系统中的活动窗体句柄)
shell之后,我用上面的办法想抢回焦点无果,除非我点一下鼠标.
其实那个exe上面没输入焦点,就像QQ消息那种样子.
SetFocus跟控件的句柄
Shell(App.path & "\popup.exe", vbMinimizedNoFocus)
Private Sub Command1_Click()
Shell App.Path & "\popup.exe", vbNormalNoFocus
Command1.SetFocus
End Sub不知道楼主的shell是在什么事件里执行的
我是在timer里面测试,然后点击别的应用程序(比如word),然后观察焦点
Private Declare Function ShowWindow Lib "user32" (ByVal hwnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function GetActiveWindow Lib "user32" () As Long
Private Const SW_SHOW = 5Private Sub Timer1_Timer()
Shell App.Path & "\popup.exe", vbNormalNoFocus
ShowWindow GetActiveWindow, SW_SHOW
End Sub
Private Sub Timer1_Timer()
'……
Timer1.enable=false
End Sub
晕,这样编写文档的窗口始终是顶级窗口了
#21楼 当然是一次,我用个按钮控制的,这样才好测试哇 好像矛盾timer没有焦点,GetActiveWindow 可以获得其它窗口的焦点
按钮本身可以得到焦点,点的时候肯定有焦点,GetActiveWindow得到的是VB窗口的焦点
同一个函数放的位置不一样,得到的结果是不一样的
Private Sub Command1_Click()
Timer2.Enabled = True
End SubPrivate Sub Timer2_Timer()
Dim lngActive As Long, lngActive2 As Long
Dim dblPID As Double, lngShell As Long
Dim s As String
Timer2.Enabled = False
' s = String(255, Chr(0))
lngActive = GetForegroundWindow()
' GetWindowText lngActive, s, 255
dblPID = Shell(App.path & "\popup.exe", vbNormalNoFocus)
lngShell = InstanceToWnd(CLng(dblPID)) '转换PID-->句柄
DoEvents
' lngActive2 = FindWindow(vbNullString, s)
' ShowWindow lngShell, 8' Debug.Print lngShell
SetWindowPos lngShell, -1, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOACTIVATE
SetWindowPos lngActive, 1, 0, 0, 0, 0, SWP_NOMOVE Or SWP_NOSIZE Or SWP_SHOWWINDOW
' SetWindowPos lngActive, 0, 0, 0, 0, 0, &H2& Or &H1& Or &H4& Or &H40&
' BringWindowToTop lngShell
' If GetForegroundWindow = lngShell Then SetForegroundWindow 0
' Dim lParam As Long
' lParam = MakeKeyLparam(vbKeyLButton, WM_KEYDOWN)
' PostMessage lngActive, &H201&, vbKeyLButton, 0
' DoEvents
' lParam = MakeKeyLparam(vbKeyLButton, WM_KEYUP)
' PostMessage lngActive, &H202&, vbKeyLButton, 0
' lParam = MakeKeyLparam(vbKeyTab, WM_KEYDOWN)
' PostMessage Me.hwnd, &H104&, vbKeyTab, lParam
' Sleep 50
' lParam = MakeKeyLparam(vbKeyTab, WM_KEYUP)
' PostMessage Me.hwnd, &H105&, vbKeyTab, lParam
' SetForegroundWindow lngActive
'' If lngActive2 <> 0 Then SetActiveWindow lngActive2' SetActiveWindow lngActive
' NewSetFocus lngActive' keybd_event VK_A, MapVirtualKey(VK_A, 0), 0, 0 '按下A键
' keybd_event VK_A, MapVirtualKey(VK_A, 0), KEYEVENTF_KEYUP, 0 '释放A键' SendKeys "%{TAB}"
end sub
GetCursorPos得到鼠标位置
WindowFromPointXY得到控件句柄
GetParent得到窗体句柄
事后
SetActiveWindow跟窗体的句柄
SetFocus跟控件的句柄
再不好用就没辙了
臆想的,嘿嘿,不知道有没有这样的API
2.使用FindWindow获得该程序窗口的句柄
3.使用SendMessage利用该窗口的句柄将其隐藏
hProcess As Long
hThread As Long
dwProcessId As Long
dwThreadId As Long
End Type
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Long
hStdInput As Long
hStdOutput As Long
hStdError As Long
End Type
Private Declare Function WaitForInputIdle Lib "user32.dll" (ByVal hp As Long, ByVal t As Long) As Long
Private Declare Function CreateProcessInternalW Lib "kernel32.dll" (ByVal hToken As Long, ByVal lpApplicationName As Long, ByVal lpCommandLine As Long, lpProcessAttributes As Any, lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, lpStartupInfo As Any, lpProcessInformation As PROCESS_INFORMATION, hNewToken As Long) As Long
Private Sub Timer1_Timer()
Dim SI As STARTUPINFO, PI As PROCESS_INFORMATION
SI.cb = Len(SI)
CreateProcessInternalW 0, StrPtr("popup.exe"), ByVal 0, ByVal 0, ByVal 0, ByVal 0, 0, 0, 0, SI, PI, ByVal 0
WaitForInputIdle PI.hProcess, 5000
Text1.SetFocus
End SubForm1中放一个Timer1 4秒钟一次,还放一个Text1
用了Text1.SetFocus 之后,VB本身的应用会闪,但是焦点不在文档上啊
如果你是其他控件放文档,就对那个控件SetFouces
有个现象,如果我正在文档上快速输入字符,这个popup.exe是不会影响输入的,但要是输入中稍有停顿,输入焦点就没了.
Dim hForegdWnd As Long, dwCurID As Long, dwForeID As Long
Dim hActive As Long
hForegdWnd = GetForegroundWindow()
dwForeID = Abs(GetWindowThreadProcessId(hForegdWnd, 0))
dwCurID = Abs(GetCurrentThreadId())
AttachThreadInput dwForeID, dwCurID, 1
hActive = GetFocus() '输入焦点所在控件句柄
AttachThreadInput dwForeID, dwCurID, 0
ForeWindow = hActive
end functionsetfocus 上述函数所得句柄
我是这个意思
popup.exe在运行后会把自己作为焦点
我先创建popup.exe进程,然后等待把自己作为焦点,然后再把你的文档作为焦点
如果你在他把自己作为焦点之前ForeWindow是不行的,因为等下它会把自己作为焦点
在他把自己作为焦点之后ForeWindow也不行,因为这时GetForegroundWindow和GetFocus都是他的窗口了
你应该就在WaitForInputIdle后SetFocus你的文档窗口
我的Private Function ForeWindow() As Long 只是为了取到输入焦点所在控件的句柄,
确实是在之前就取好的,如果先不取,如何"SetFocus你的文档窗口"呢,这个"你的文档窗口"句柄如何获得呢,真纠结...
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function AttachThreadInput Lib "user32" (ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
Private Declare Function GetFocus Lib "user32" () As Long
Private Declare Function NewSetFocus Lib "user32" Alias "SetFocus" (ByVal hwnd As Long) As Long
Private Declare Function GetForegroundWindow Lib "user32" () As LongPrivate Sub Command1_Click()
'点击之后切换到文本文档上打字(打字速度不要太快,或者只点一下文本文档,光标落入里面即可)
'3秒后观察光标是否消失
Timer2.Enabled = True
End Sub
Private Sub MDIForm_Load()
Timer2.Interval = 3000
Timer2.Enabled = False
End Sub
Private Sub Timer2_Timer()
Dim lngActive As Long, lngActive2 As Long
Timer2.Enabled = False
lngActive2 = ForeWindow()
Dim SI As STARTUPINFO, PI As PROCESS_INFORMATION
SI.cb = Len(SI)
CreateProcessInternalW 0, StrPtr("popup.exe"), ByVal 0, ByVal 0, ByVal 0, ByVal 0, 0, 0, 0, SI, PI, ByVal 0
WaitForInputIdle PI.hProcess, 5000
' Shell App.Path & "\popup.exe", vbMinimizedNoFocus
' AttachThead lngActive2
End Sub
Private Function ForeWindow() As Long
Dim hForegdWnd As Long, dwCurID As Long, dwForeID As Long
Dim hActive As Long
hForegdWnd = GetForegroundWindow()
dwForeID = Abs(GetWindowThreadProcessId(hForegdWnd, 0))
dwCurID = Abs(GetCurrentThreadId())
AttachThreadInput dwForeID, dwCurID, 1
hActive = GetFocus() '输入焦点所在控件句柄
AttachThreadInput dwForeID, dwCurID, 0
ForeWindow = hActive
End Function
Private Sub AttachThead(hwnd As Long)
Dim hForegdWnd As Long, dwCurID As Long, dwForeID As Long
dwCurID = GetCurrentThreadId()
dwForeID = GetWindowThreadProcessId(hwnd, 0)
AttachThreadInput hwnd, dwCurID, 1
NewSetFocus hwnd
AttachThreadInput hwnd, dwCurID, 0
End Sub
ForeWindow 就是上面47F那个 ,窗体是MDIform ,试了下普通窗体好像没问题
Dim lngActive As Long, lngActive2 As Long, h As Long
Timer2.Enabled = False
' lngActive2 = ForeWindow()
Dim SI As STARTUPINFO, PI As PROCESS_INFORMATION
SI.cb = Len(SI)
h = GetForegroundWindow
CreateProcessInternalW 0, StrPtr("popup.exe"), ByVal 0, ByVal 0, ByVal 0, ByVal 0, 0, 0, 0, SI, PI, ByVal 0
WaitForInputIdle PI.hProcess, 5000
SetForegroundWindow h
' Shell App.Path & "\popup.exe", vbMinimizedNoFocus
' AttachThead lngActive2
End Sub增加Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long我这里可以
不知道我那个在用的老程序SetForegroundWindow用了之后就是会闪烁
之前我也用这个SetForegroundWindow试了就是闪烁就没用,我再检查下
我是因为原来有CreateProcessInternalW的声明才复制来用它
你最好用CreateProcessW,CreateProcessInternalW是未公开的api
你可以要求 popup.exe 加个命令行参数,用来控制不要置顶。
它置顶后本身是没有焦点的,但原来正操作的文档上焦点也没了.
看来只能自己写个或者改下人家的那个popup.exe才好了