Как я могу закрыть окна по их ручке?

5296
mark

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

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

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

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

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

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

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

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

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

3
Alt-Tab обычно возвращает модальное диалоговое окно вверху. Remus Rusanu 14 лет назад 0
Ну, не в моих сценариях. Это происходит только в том случае, если модальное диалоговое окно открыто с определенным стилем окна (не помню точно), которое заставляет диалоговое окно появиться на панели задач. 14 лет назад 0

6 ответов на вопрос

4
Wouter van Nifterick

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

Скриншот

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

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

  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. 
Нехорошо. Как я уже сказал, окно скрыто за другим окном. Вся цель это заняться этими безобразными делами. 14 лет назад 0
Смотрите второй РЕДАКТИРОВАТЬ в моем посте. 14 лет назад 0
Нет, вы сказали, что это "под" другим окном (подразумевается y-позиция), и вы не упомянули, что окно не было видно. Это немного грубо с вашей стороны понизить голос после того, как я приложил усилия, чтобы помочь вам. 14 лет назад 3
Если подумать, вы правы. Я должен был объяснить себя лучше. Вы можете понизить мой вопрос в ответ, потому что из-за отсутствия ясности я заслуживаю его честно. 14 лет назад 0
Нет причин для отрицания этого ответа. Это правильный * программирующий * ответ на не очень связанный с программированием вопрос. Взаимное отрицательное голосование вряд ли продуктивно. Sinan Ünür 14 лет назад 0
2
Jonas Elfström

Я воспринял это как предлог, чтобы попробовать 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 
Хорошо, но я не собираюсь устанавливать ruby ​​для этого :-) 14 лет назад 0
Установщик в один клик, если вы передумаете. http://rubyforge.org/projects/rubyinstaller/ Jonas Elfström 14 лет назад 0
1
Sinan Ünür

Вот скрипт 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("%"); } 

И вот некоторые развлечения с использованием такого скрипта (пожалуйста, не рассматривайте этот спам, я просто пытаюсь проиллюстрировать использование Perl's Win32 :: GuiTest : http://www.youtube.com/watch?v=BAg7K_uwNZs

Милый. Но я не хочу устанавливать Perl только для этого. 14 лет назад 0
1
P Daddy

Это было бы просто умственно приготовить для себя. Я вижу, ты отверг 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); } } 
Вы правы. Мне было интересно, если есть более удобные решения. Хотя, как я уже упоминал, простая командная строка достаточно хороша, обычно требуется какой-то изящный пользовательский интерфейс, который позволит вам выбрать окно, расскажет всю информацию о нем и т. Д. На данный момент мне все еще нужно связать его со Spy ++ , Но вы все равно правы. 14 лет назад 0
Превращение в GUI не потребовало бы намного больше, за исключением небольших затрат времени. Поведение Drag-a-target-and-highlight-a-window в Spy ++ легко скопировать с помощью соответствующего значка и курсора. Подсветка окна легко выполняется с помощью функций WinAPI `GetWindowRgn` и` FrameRgn`. Существуют и другие функции API, которые предоставят вам любую информацию об искомом окне. И `SetWindowPos` может использоваться, чтобы вывести целевой диалог на вершину Z-порядка, чтобы вы могли видеть его и взаимодействовать с ним, а не просто закрывать его. 14 лет назад 0
Все легко и все занимает время, которого у нас нет. Зачем изобретать колесо, если оно, вероятно, уже изобретено? Я знаю, как это работает, вы разрабатываете небольшую изящную утилиту для самостоятельного использования, затем расширяете ее, затем отлаживаете ее для исправления ошибок, и легко обнаруживает, что тратит пару дней на то, что уже сделано и проверено другими. 14 лет назад 0
У тебя есть хорошая мысль. Но, с другой стороны, в таком случае, я полагаю, можно потратить больше времени на поиск существующего решения, чем на его создание. Не все эзотерические потребности уже удовлетворительно удовлетворяются существующим продуктом - фактом, которому я обязан своим процветанием. 14 лет назад 0
0
recursive

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

0
Maslow

Таким образом, этот ответ включает в себя загрузку бесплатного 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 =  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 =  let getWindowInfo hwnd =  hwnd |> PInvoke.getWindowThreadProcessId |> Option.map (Process.GetProcessById) |> Option.map (fun p ->  )  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> )