¿Alguien conoce una aplicación que cierre una ventana según su identificador? La línea de comando es buena.
Tenga en cuenta que no deseo eliminar la aplicación respectiva, sino una ventana modal propiedad de esa aplicación.
Razón fundamental:
En algún momento, se abre un cuadro de diálogo modal debajo de la ventana principal de mi computadora portátil. Esto sucedió más de una vez para VS y Firefox. Muy molesto.
Puedo localizar la ventana con Spy++, pero no tengo forma de cerrarla.
EDITAR:
Una aplicación que permite enviar mensajes a una ventana arbitraria también es buena, supongo que luego puedo enviar algo como WM_CLOSE o lo que sea.
EDITAR:
Deseo recalcar que no me interesa cerrar una ventana visible. El objetivo es lidiar con anomalías desagradables cuando se abre un cuadro de diálogo modal debajo de la ventana propietaria, lo que sucedió y ni una sola vez mientras trabajaba con VS y Firefox. Entonces, la solución deseada es cerrar una ventana por su manija o, si se puede, ubicar específicamente las ventanas oscurecidas y sacarlas a la luz.
Respuesta1
Bien, creé una pequeña aplicación que funciona.
Puedes descargarloaquí.
Uso:
- Iniciar el programa
- Mantenga el mouse sobre la ventana que desea cerrar (no haga clic en ella)
- Presione eliminar.
Envía un wm_close a la ventana debajo del cursor del mouse.
Código Delphi a continuación...
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.
Respuesta2
Tomé esto como excusa para probar Win32API para Ruby.
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
Usando esto puedes cerrar un bloc de notas nuevo con
> ruby closewindow.rb "Untitled - Notepad"
o si conoces el mango
> ruby closewindow.rb 15794730
Respuesta3
Aquí hay un script en Perl para hacer eso:
#!/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}");
}
Y aquí hay algo de entretenimiento usando dicho script (por favor, no lo consideren spam, solo estoy tratando de ilustrar el uso de Perl).Win32::GuiTest:http://www.youtube.com/watch?v=BAg7K_uwNZs
Respuesta4
Entonces esta respuesta implica descargar un script runner gratuitoLINQPadpara ejecutar el script y luego ejecutarlo. ejecútelo y le pedirá que coloque el cursor sobre la ventana que desea cerrar. Interroga esa ventana en busca del título, se la muestra y luego le pregunta si desea cerrarla.
// 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>
)