ฉันจะปิดหน้าต่างด้วยที่จับได้อย่างไร


4

ไม่มีใครรู้ของแอปพลิเคชันที่จะปิดหน้าต่างที่ได้รับการจัดการ? บรรทัดคำสั่งเป็นสิ่งที่ดี

โปรดทราบว่าฉันไม่ต้องการฆ่าแอปพลิเคชันที่เกี่ยวข้อง แต่เป็นหน้าต่างโมดัลที่แอปพลิเคชันนั้นเป็นเจ้าของ

เหตุผล:

บางครั้งกล่องโต้ตอบเป็นกิริยาช่วยจะเปิดใต้หน้าต่างหลักในแล็ปท็อปของฉัน สิ่งนี้ไม่ได้เกิดขึ้นเพียงครั้งเดียวสำหรับ VS และ Firefox น่ารำคาญมาก

ฉันสามารถค้นหาหน้าต่างด้วย Spy ++ แต่ไม่มีวิธีฆ่ามัน

แก้ไข:

แอปพลิเคชันที่อนุญาตให้ส่งข้อความไปยังหน้าต่างใดก็ได้นั้นดีฉันเดาว่าฉันสามารถส่งบางอย่างเช่น WM_CLOSE หรืออะไรก็ได้

แก้ไข:

ฉันต้องการความเครียดที่ฉันไม่น่าสนใจในการปิดหน้าต่างที่มองเห็นได้ ประเด็นทั้งหมดคือการจัดการกับความผิดปกติที่น่าเกลียดเมื่อกล่องโต้ตอบโมดอลเปิดอยู่ใต้หน้าต่างการเป็นเจ้าของซึ่งเกิดขึ้นและไม่ใช่ครั้งเดียวสำหรับฉันในขณะที่ทำงานกับ VS และ Firefox ดังนั้นทางออกที่ต้องการคือการปิดหน้าต่างด้วยมือจับหรือถ้ามันสามารถค้นหาหน้าต่างที่ปิดบังไว้โดยเฉพาะและนำมันออกมาได้


Alt-Tab มักจะนำกล่องโต้ตอบโมดอลกลับมาอยู่ด้านบน
Remus Rusanu

ไม่ใช่ในสถานการณ์ของฉัน มันจะทำได้ก็ต่อเมื่อกล่องโต้ตอบโมดอลเปิดด้วยสไตล์หน้าต่างบางอย่าง (จำไม่ได้แน่นอน) ซึ่งทำให้ไดอะล็อกปรากฏขึ้นในแถบงาน

คำตอบ:


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
ไม่คุณบอกว่ามันเป็น "ใต้" หน้าต่างอื่น (หมายถึงตำแหน่ง y) และคุณไม่ได้พูดถึงหน้าต่างที่มองไม่เห็น มันเป็นการหยาบคายที่คุณจะต้องลงแรงหลังจากความพยายามที่ฉันทำเพื่อช่วยเหลือคุณ

ในความคิดที่สองคุณพูดถูก ฉันควรอธิบายตัวเองให้ดีกว่านี้ คุณสามารถลงคะแนนคำถามของฉันในทางกลับกันเพราะขาดความชัดเจนในนี้ฉันสมควรได้รับมันอย่างเป็นธรรม

ไม่มีเหตุผลที่จะลงคะแนนคำตอบนี้ มันเป็นความถูกต้องในการเขียนโปรแกรมคำตอบให้กับคำถามที่เกี่ยวข้องไม่ได้ดังนั้นการเขียนโปรแกรม Downvoting ซึ่งกันและกันเป็นผลแทบจะไม่
Sinan Ünür

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

ดี แต่ฉันจะไม่ติดตั้งทับทิมสำหรับ :-)

มีตัวติดตั้งในคลิกเดียวในกรณีที่คุณเปลี่ยนใจ rubyforge.org/projects/rubyinstaller
Jonas Elfström

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 ของWin32 :: GuiTest : http://www.youtube.com/watch?v=BAg7K_uwNZsของ Perl


น่ารัก แต่ฉันไม่รู้สึกเหมือนติดตั้ง Perl เพียงแค่นี้

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);
    }
}

คุณพูดถูก ฉันสงสัยว่ามีวิธีแก้ปัญหาที่ใช้งานง่ายขึ้นหรือไม่ แม้ว่าฉันได้กล่าวถึงบรรทัดคำสั่งง่าย ๆ ก็ดีพอโดยปกติแล้วใครจะคาดหวังว่าจะมี UI ที่ดีซึ่งให้คุณเลือกหน้าต่างบอกข้อมูลทุกอย่างเกี่ยวกับมัน ฯลฯ ... ณ ตอนนี้ฉันยังต้องจับคู่กับ Spy ++ . แต่คุณก็ยังถูก

การทำให้เป็น GUI จะไม่ใช้เวลามากนักยกเว้นการลงทุนเพียงเล็กน้อยในเวลา การทำงานแบบลาก - อะ - เป้าหมาย - และ - ไฮ - อา - หน้าต่างของ Spy ++ นั้นค่อนข้างง่ายที่จะทำซ้ำด้วยไอคอนและเคอร์เซอร์ที่เหมาะสม หน้าต่างไฮไลต์จะกระทำได้ง่ายด้วยฟังก์ชั่ WinAPI และGetWindowRgn FrameRgnมีฟังก์ชัน API อื่น ๆ ที่จะให้ข้อมูลเกี่ยวกับหน้าต่างที่คุณต้องการ และSetWindowPosสามารถใช้เพื่อนำไดอะล็อกเป้าหมายไปที่ด้านบนของคำสั่ง Z เพื่อให้คุณสามารถดูและโต้ตอบกับมันแทนการปิดมัน

ทุกอย่างเป็นเรื่องง่ายและทุกอย่างต้องใช้เวลาที่เราไม่มี ทำไมต้องคิดค้นล้อถ้ามันถูกประดิษฐ์ขึ้นมาแล้ว? ฉันรู้ว่ามันทำงานอย่างไรคุณพัฒนายูทิลิตี้ที่ดีเล็ก ๆ น้อย ๆ สำหรับการใช้งานด้วยตนเองจากนั้นคุณขยายมันจากนั้นคุณแก้ปัญหาเพื่อแก้ไขข้อบกพร่องและหนึ่งพบว่าตัวเองเสียเวลาสองสามวันกับสิ่งที่ทำ

คุณมีจุดดี แต่ในอีกกรณีหนึ่งเช่นนี้ฉันเชื่อว่าอาจใช้เวลามากขึ้นในการค้นหาวิธีแก้ไขปัญหาที่มีอยู่มากกว่าการสร้างโซลูชัน ไม่ใช่ทุกความต้องการที่ลึกลับได้รับความพึงพอใจจากผลิตภัณฑ์ที่มีอยู่แล้ว - ความจริงที่ฉันเป็นหนี้ความเจริญรุ่งเรืองของฉัน

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>
)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.