4

Кто-нибудь знает о приложении, которое закроет окно, учитывая его дескриптор? Командная строка хороша.

Обратите внимание, что я не хочу убивать соответствующее приложение, скорее модальное окно, принадлежащее этому приложению.

Обоснование:

Иногда модальное диалоговое окно открывается под главным окном на моем ноутбуке. Это произошло не раз для VS и Firefox. Очень надоедливый.

Я могу найти окно с помощью Spy++, но у меня нет средств его убить.

РЕДАКТИРОВАТЬ:

Приложение, позволяющее отправлять сообщения в произвольное окно, также хорошо, я думаю, что тогда я могу отправить что-то вроде WM_CLOSE или что-то еще.

РЕДАКТИРОВАТЬ:

Я хочу подчеркнуть, что мне не интересно закрывать видимое окно. Весь смысл в том, чтобы иметь дело с отвратительными отклонениями, когда модальный диалог открывается под окном-владельцем, что произошло, и не один раз для меня, работая с VS и Firefox. Таким образом, желаемое решение состоит в том, чтобы закрыть окно за его ручку или, если оно может специально найти скрытые окна и выдвинуть их.

6 ответов6

4

Хорошо, я сделал небольшое приложение, которое делает трюк.

Скриншот

Вы можете скачать его здесь.

Использование:

  1. Запустить программу
  2. Наведите курсор на окно, которое хотите закрыть (не нажимайте на него)
  3. Нажмите удалить.

Он отправляет 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.
3

Я воспринял это как предлог, чтобы попробовать Win32API для 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

Используя это, вы можете закрыть новый блокнот с

> ruby closewindow.rb "Untitled - Notepad"

или если вы знаете ручку

> ruby closewindow.rb 15794730
1

Вот скрипт 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's Win32::GuiTest: http://www.youtube.com/watch?v=BAg7K_uwNZs

1

Это было бы просто умственно приготовить для себя. Я вижу, ты отверг Perl. Какой твой любимый язык?

Вот простой пример C (не проверенный, исходя из памяти):

#include <windows.h>
#include <stdio.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow){
    HWND hWnd;

    if(!sscanf(lpCmdLine, "%i", &hWnd)){
        MessageBox(null, "Invalid argument", "Close Window", MB_OK | MB_ICONERROR);
        return 1;
    }

    PostMessage(hWnd, WM_CLOSE, 0, 0);
}

Это простой пример C # (опять же, не проверенный):

using System;
using System.Runtime.Interop;

static class Program{
    [DllImport("user32.dll", CharSet=CharSet.Auto)]
    static extern int PostMessage(int hWnd, int msg, int wParam, int lParam);

    const int WM_CLOSE = 16;

    static void Main(string[] args){
        int hWnd;
        if(args.Length == 1 && int.TryParse(args[0], out hWnd))
            PostMessage(hWnd, WM_CLOSE, 0, 0);
        else MessageBox.Show("Invalid Argument", "CloseWindow", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}
0

Нажмите Alt + Esc, чтобы отправить текущее окно переднего плана назад. Продолжайте нажимать, пока не дойдете до диалога. Это будет циклически проходить даже через окна, отсутствующие в списке Alt + Tab .

0

Таким образом, этот ответ включает в себя загрузку бесплатного 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>
)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .