有谁知道有哪个应用程序可以根据句柄关闭窗口吗?命令行很好。
请注意,我并不想终止相应的应用程序,而是希望终止该应用程序所拥有的模态窗口。
理由:
有时,我的笔记本电脑主窗口下方会打开一个模式对话框。VS 和 Firefox 中不止一次出现过这种情况。非常烦人。
我可以使用 Spy++ 定位该窗口,但没有办法将其终止。
编辑:
允许向任意窗口发送消息的应用程序也很好,我想我可以发送像 WM_CLOSE 之类的消息。
编辑:
我想强调的是,我对关闭可见窗口不感兴趣。重点是处理当模式对话框在所属窗口下方打开时出现的丑陋异常,这种情况确实发生过,而且在我使用 VS 和 Firefox 时不止一次。因此,理想的解决方案是通过窗口句柄关闭窗口,或者如果它可以专门找到被遮挡的窗口并将它们调出。
答案1
好的,我制作了一个可以解决这个问题的小应用程序。
你可以下载这里。
用法:
- 启动程序
- 将鼠标悬停在要关闭的窗口上(不要单击它)
- 按删除键。
它向鼠标光标下的窗口发送 wm_close。
下面是 Delphi 代码...
unit uCloseWindow;
interface
uses
Windows, Forms, Messages, SysUtils, Variants, Classes, Controls;
type
TfrmMain = class(TForm)
procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
public
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure TfrmMain.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var
HandleUnderCursor:HWND;
begin
if Key=VK_DELETE then
begin
HandleUnderCursor := WindowFromPoint(Mouse.CursorPos);
SendMessage(HandleUnderCursor,WM_CLOSE,0,0)
end;
end;
end.
答案2
我以此为借口尝试了 Ruby 的 Win32API。
require 'Win32API'
WM_CLOSE = 0x0010
FindWindow = Win32API.new('user32', 'FindWindow', ["P", "P"], "L")
SendMessage = Win32API.new('user32', 'SendMessage', ["L", "L", "P", "P"], "L")
def Send_WM_CLOSE(title)
handle = FindWindow.call(nil, title)
SendMessage.call(handle, WM_CLOSE, nil, nil) if handle != 0
end
if ARGV[0].to_i==0
title=String.new(ARGV[0])
Send_WM_CLOSE(title)
else
SendMessage.call(ARGV[0].to_i, WM_CLOSE, nil, nil)
end
使用这个你可以关闭新的记事本
> ruby closewindow.rb "Untitled - Notepad"
或者如果你知道句柄
> ruby closewindow.rb 15794730
答案3
这是一个执行此操作的 Perl 脚本:
#!/usr/bin/perl
use strict;
use warnings;
use Win32::GuiTest qw(FindWindowLike SendKeys SetForegroundWindow);
die "Need pattern to match against window titles\n" unless @ARGV;
my ($windowtitle) = @ARGV;
my ($myhandle) = FindWindowLike(0, qr/winclose\.pl/);
my @windows = FindWindowLike(0, qr/\Q$windowtitle\E/i);
for my $handle ( @windows ) {
next if $handle == $myhandle;
SetForegroundWindow($handle);
SendKeys("%{F4}");
}
下面是使用此类脚本的一些娱乐内容(请不要认为这是垃圾邮件,我只是想说明 Perl 的Win32::Gui 测试:http://www.youtube.com/watch?v=BAg7K_uwNZs
答案4
因此,这个答案涉及下载一个免费的脚本运行器LINQPad运行脚本然后运行它。运行它,它会要求您将光标放在要关闭的窗口上。它会询问该窗口的标题,向您显示它,然后询问您是否要关闭它。
// close an app's foremost window - will try to just close whatever window the mouse is over first, see if that does the trick
// close works when linqpad runs as administrator. Used to close a modal in linqpad that was stuck
open System.Drawing
module PInvoke =
type WindowHandle = nativeint
module Native =
open System.Drawing
open System.Runtime.InteropServices
//http://pinvoke.net/default.aspx/user32.SendMessage
// IntPtr would be fine here, nativeint is more idiomatic
[<DllImport("User32", SetLastError=true)>]
extern nativeint private SendMessage(WindowHandle hWnd, int Msg, nativeint wParam, nativeint lParam)
[<DllImport("User32", EntryPoint="WindowFromPoint", ExactSpelling = true)>]
extern WindowHandle private WindowFromPoint (Point point)
// https://stackoverflow.com/questions/18184654/find-process-id-by-windows-handle
//https://stackoverflow.com/a/18184700/57883
[<DllImport("User32", SetLastError=true)>]
extern int private GetWindowThreadProcessId(WindowHandle hWnd, int& processId)
// https://stackoverflow.com/questions/1316681/getting-mouse-position-in-c-sharp
[<DllImport("User32", SetLastError=true)>]
extern bool private GetCursorPos(Point& lpPoint);
//https://stackoverflow.com/questions/647236/moving-mouse-cursor-programmatically
// claims sendInput is better than send messages for clicking
[<DllImport("User32", SetLastError=true)>]
extern System.Int64 SetCursorPos(int x, int y);
// let dll = DllImportAttribute("")
// But, if you need to get text from a control in another process, GetWindowText() won't work. Use WM_GETTEXT instead.
// another mapping for StringBuilder out
// you might need to get the string length from another call before calling this: https://www.pinvoke.net/default.aspx/user32.getwindowtext
[<DllImport("User32",CharSet=CharSet.Auto,EntryPoint="SendMessage")>]
extern nativeint SendWMText(WindowHandle hWnd, int msg, nativeint wParam, StringBuilder sb);
open Native
type SendMessageRaw = {hWnd:nativeint; msg:int; wParam:nativeint; lParam:nativeint}
type Message<'t> =
| Close of windowHandle:nativeint
| GetText of windowHandle:nativeint * withReturn :(string -> unit)
| [<Obsolete("Use only for testing, don't leave things unmapped")>]
Raw of SendMessageRaw
let ptToParam (pt:System.Drawing.Point) = nativeint (pt.Y <<< 16 ||| pt.X)
let sendMessage message =
let sendMessage a b c d = SendMessage(a,b,c,d)
match message with
| Close hwnd ->
let WM_CLOSE = 0x0010
printfn "Attempting close"
sendMessage hwnd WM_CLOSE IntPtr.Zero IntPtr.Zero
| GetText (hWnd,f) ->
let WM_GETTEXTLENGTH = 0x000E
printfn "Getting text length"
let length: int =int<|SendMessage(hWnd,WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero)
printfn "Got text length: %i " length
let mutable sb = StringBuilder(length + 1)
let WM_GETTEXT = 0x000D
let result = SendWMText(hWnd,WM_GETTEXT,nativeint (length + 1),sb)
printfn "Text returned is length %i" sb.Length
sb.ToString()
|> f
result
| Raw x -> SendMessage(x.hWnd, x.msg, x.wParam, x.lParam)
let windowFromPoint(pt:Point) =
let mutable pt = pt
let hwnd = WindowFromPoint(pt)
if hwnd <> IntPtr.Zero then
Some hwnd
else None
let getCursorPos() =
let mutable pt = Point()
match GetCursorPos(&pt) with
| true -> Some pt
| false -> None
let getWindowThreadProcessId hwnd =
let mutable pId = 0
let result = GetWindowThreadProcessId(hwnd, &pId)
if pId <> 0 then
Some pId
else None
type WindowInfo = {PId:int;MainWindowHandle:nativeint; ProcessName:string}
let getWindowInfo hwnd =
hwnd
|> PInvoke.getWindowThreadProcessId
|> Option.map (Process.GetProcessById)
|> Option.map (fun p ->
{PId=p.Id; MainWindowHandle=p.MainWindowHandle; ProcessName=p.ProcessName}
)
Util.ReadLine("Put the cursor of the desired window") |> ignore
let currentPt = PInvoke.getCursorPos()
printfn "Current Pos is %A" currentPt
currentPt
|> Option.bind(fun pt ->
PInvoke.windowFromPoint pt
)
|> Option.map(fun hWnd ->
printfn "Current hWnd is %A" hWnd
let wi = getWindowInfo hWnd
printfn "CurrentWindowInfo is %A" wi
wi.Dump()
let pid = PInvoke.getWindowThreadProcessId hWnd
printfn "With pId = %A" pid
hWnd
)
|> Option.iter(fun hWnd ->
let text =
let mutable text:string = null
let r = PInvoke.sendMessage <| PInvoke.GetText(hWnd,
(fun s ->
printfn " got text?"
text <- s))
text
printfn "Window text:%s" text
if Util.ReadLine<bool>("Attempt close?") then
PInvoke.sendMessage (PInvoke.Message.Close( hWnd))
|> ignore<nativeint>
)