Comment puis-je fermer les fenêtres par leur poignée?


3

Est-ce que quelqu'un connaît une application qui fermerait une fenêtre compte tenu de son handle? La ligne de commande est bonne.

Notez que je ne souhaite pas tuer l'application respective, mais plutôt une fenêtre modale appartenant à cette application.

Raisonnement:

Parfois, une boîte de dialogue modale s'ouvre sous la fenêtre principale de mon ordinateur portable. Ce n'est pas arrivé une fois pour VS et Firefox. Très ennuyant.

Je peux localiser la fenêtre avec Spy ++, mais je n’ai aucun moyen de la tuer.

MODIFIER:

Une application permettant d’envoyer des messages à une fenêtre arbitraire est également utile. Je suppose que je peux alors envoyer quelque chose comme WM_CLOSE ou autre.

MODIFIER:

Je tiens à souligner que je ne suis pas intéressé par la fermeture d’une fenêtre visible. Le but est de traiter les anomalies abominables lorsqu'un dialogue modal s'ouvre sous la fenêtre propriétaire, ce qui s'est produit et pas une seule fois pour moi lorsque je travaillais avec VS et Firefox. La solution souhaitée consiste donc à fermer une fenêtre par sa poignée ou, si elle peut localiser spécifiquement des fenêtres masquées, et à les afficher.


Alt-Tab ramène généralement la boîte de dialogue modale au dessus.
Remus Rusanu

Eh bien, pas dans mes scénarios. Cela ne se produit que si la boîte de dialogue modale est ouverte avec un certain style de fenêtre (ne pas s'en rappeler exactement), ce qui la fait apparaître dans la barre des tâches.

Réponses:


4

D'accord, j'ai créé une petite application qui fait l'affaire.

Screenshot

Vous pouvez le télécharger ici .

Usage:

  1. Commencer le programme
  2. Maintenez votre souris sur la fenêtre que vous souhaitez fermer (ne cliquez pas dessus)
  3. Appuyez sur supprimer.

Il envoie un wm_close à la fenêtre sous le curseur de la souris.

Code Delphi ci-dessous ...

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.

Pas bon. Comme je l'ai dit la fenêtre est cachée derrière une autre fenêtre. Le but entier, il s'attaque à ces cas laids.

Voir le deuxième EDIT dans mon post.

3
Non, vous avez dit que c'était "sous" une autre fenêtre (impliquant la position y), et vous n'avez pas mentionné que la fenêtre n'était pas visible. C'est un peu impoli de votre part de voter après les efforts que j'ai déployés pour vous aider.

À la réflexion, vous avez raison. J'aurais dû mieux m'expliquer. Vous pouvez réduire ma question en retour, à cause de cette absence de clarté, je la mérite.

Il n'y a aucune raison de réduire cette réponse. C'est un valide la programmation répondre à une question pas tellement liée à la programmation. Le vote réciproque est à peine productif.
Sinan Ünür

2

J'ai pris cela comme une excuse pour essayer Win32API pour 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

En utilisant cela, vous pouvez fermer un bloc-notes frais avec

> ruby closewindow.rb "Untitled - Notepad"

ou si vous connaissez le manche

> ruby closewindow.rb 15794730

Bien, mais je ne vais pas installer Ruby pour ça :-)

Il existe un programme d'installation en un clic, au cas où vous changeriez d'avis. rubyforge.org/projects/rubyinstaller
Jonas Elfström

1

Voici un script Perl pour le faire:

#!/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}");
}

Et voici quelques animations utilisant un tel script (veuillez ne pas considérer ce spam, je suis juste en train d’illustrer une utilisation de Perl Win32 :: GuiTest : http://www.youtube.com/watch?v=BAg7K_uwNZs


Mignonne. Mais je n'ai pas envie d'installer Perl juste pour ça.

1

Ce serait incroyablement simple à cuisiner pour vous-même. Je vois que vous avez rejeté Perl. Quelle est votre langue préférée?

Voici un exemple simple en C (non testé, allant de mémoire):

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

Voici un exemple simple en C # (encore une fois, non testé):

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

Tu as raison. Je me demandais s'il y avait des solutions plus conviviales. Bien que, j’ai mentionné que la simple ligne de commande soit suffisante, on s’attend généralement à une interface utilisateur astucieuse qui vous permet de sélectionner la fenêtre, vous donne toutes sortes d’informations à ce sujet, etc. . Mais vous avez raison quand même.

En faire une interface graphique ne prendrait pas beaucoup plus, sauf pour un petit investissement en temps. Le comportement glisser-cible-et-surligner-fenêtre de Spy ++ est assez facile à dupliquer avec une icône et un curseur appropriés. La mise en évidence de la fenêtre se fait facilement avec les fonctions WinAPI GetWindowRgn et FrameRgn. Il existe d'autres fonctions de l'API qui vous donneront toutes les informations sur la fenêtre que vous recherchez. Et SetWindowPos peut être utilisé pour amener la boîte de dialogue cible au sommet de l'ordre Z afin que vous puissiez la voir et interagir avec elle au lieu de la fermer.

Tout est facile et tout prend du temps, nous n'en avons pas. Pourquoi inventer une roue si c'est probablement déjà inventé? Je sais comment cela fonctionne, vous développez un petit utilitaire astucieux pour l’auto-utilisation, puis vous l’étendez, puis vous le déboguez pour corriger les bugs et on se retrouve facilement en train de perdre quelques jours sur quelque chose déjà fait et testé par d’autres.

Vous avez un bon point. Mais dans un cas comme celui-ci, j’estime qu’on pourrait passer plus de temps à chercher une solution existante qu’à en construire une. Tous les besoins ésotériques ne sont pas déjà satisfaits de manière satisfaisante par un produit existant - un fait auquel je dois ma prospérité.

0

presse Alt + Esc pour envoyer la fenêtre de premier plan actuelle à l'arrière. Continuez à appuyer jusqu'à ce que vous veniez à la boîte de dialogue. Cela passera par les fenêtres même pas dans le Alt + Languette liste.


0

Donc, cette réponse implique le téléchargement d'un script gratuit LINQPad pour exécuter le script puis l'exécuter. exécutez-le et il vous demandera de placer votre curseur sur la fenêtre que vous souhaitez fermer. Il interroge cette fenêtre pour le titre, vous le montre, puis vous demande si vous souhaitez le fermer.

// 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>
)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.