1

I have ran into a slight problem while configuring some keybinds with my mouse.

The thing I want to achieve is to open the program from the backround(open or closed window) and close it again, but not kill the task(eqivalent to the x-button, so it keeps running in the backround)

I have set up my mouse to start up a application called everything (which is able of very fast file system searches)

I have figured out that with this code:

TASKKILL /F /IM Everything.exe

which I can run with a macro key I can kill the application. But I dont want to kill the application itself just the window, becase it takes a while to index all the important files once I have to restart it.

So heres the question is there any way to bring up a window/task to the front of the screen or trigger the x button event, without having to kill the entire process ?

Also the Mouse(g600) supports lua scripting, but that is proabbly the more harder way to go about it.

zython
  • 1,176
  • 4
  • 22
  • 50
  • Does Taskkill without force work. Without `Force` it posts a wm_exit message requesting the program to close, usually similar to Alt + F4 which sends a wm_close to the window.(which rules are usually exit when last window is closed). /f terminates an app - the app isn't asked or informed. –  Jan 16 '16 at 01:29
  • 1
    Probably, [this](http://www.commandline.co.uk/cmdow/) command line utility would be helpful to minimize/maximize your "everything.exe" – Egor Skriptunoff Jan 16 '16 at 08:22

2 Answers2

1

can't comment so I'll try to answer. the 'x' button will likely kill your application unless the application is configured otherwise I guess. I think I understand you'd rather minimize it into icon tray or something. This is not possible as far as I know if your application isn't doing it naturally. You could try to hit alt + space + n which is a shortcut to minimize the application.

laxa
  • 81
  • 1
  • 6
1

Minimizing a window can be usually done by activating the window (bringing it to the foreground) then using SendKeys() to send Alt+Space, then whatever letter your locale has underlined for "Minimize" (N in English Windows). Here's one of possibly dozens of examples of this using VBScript.

That sequence is overused, inelegant, and boring in my opinion -- and it doesn't work for some windows (the cmd console, for example). It is possible to minimize a window without bringing it to the foreground, and without simulating key presses. One simply needs to import a function from user32.dll. And as long as we're going through that trouble, we might as well import a second function to detect the current window state so we can toggle minimized / restored.

We can import the functions using PowerShell like this. Save this Batch / PowerShell hybrid script with a .bat extension and give it a run.

<# : minimize.bat
:: toggles minimized state of a window by its filename
:: minimize.bat /? for usage
:: https://stackoverflow.com/a/34834953/1683264

@echo off & setlocal

if "%~1"=="" goto usage
set "prog=%~n1"
tasklist | findstr /i "\<%prog%\>" >NUL || goto usage

set /P "=Toggling the minimized state of %prog%... " <NUL
powershell -noprofile -noninteractive "iex ((gc \"%~f0\") -join \"`n\")"

goto :EOF

:usage
echo syntax: %~nx0 progname[.exe]
echo;
echo If the program is visible, minimize it.  If minimized, restore it.
goto :EOF

:: end Batch / begin PowerShell hybrid chimera #>

Add-Type user32_dll @'
    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);
'@ -namespace System

$hwnd = @(Get-Process $env:prog)[0].MainWindowHandle
$state = [user32_dll]::GetWindowLong($hwnd, -16)

# mask of 0x20000000 = minimized; 2 = minimize; 4 = restore
if ($state -band 0x20000000) { $action = 4 } else { $action = 2 }

if ([user32_dll]::ShowWindowAsync($hwnd, $action)) {
    write-host "Success" -f green
} else {
    write-host "Fail" -f red
}

Now, if your program minimizes to the systray, the previous script will be fine for minimizing, but won't be able to find the window handle when minimized. It will fail when trying to restore. Finding the HWND in this situation is tricky. If one knows the window title, one can find the HWND using the user32.dll FindWindow() or FindWindowEx() functions.

I haven't had much luck using WMI or built-in PowerShell commands for finding the title of a window minimized to the tray. Neither get-process nor gwmi win32_process nor [diagnostics.process]::getProcessByName() yielded success. I did, however, discover that the final line of tasklist /v /fo list will show the window title. That's enough to invoke FindWindow() and get the HWND.

This might be more complicated than it needs to be, but then again it might not. I just know I found 1,000 ways to fail, but one way to succeed. Thanks to JPBlanc for helping me figure out how to pass null arguments into FindWindow() and FindWindowEx().

<# : minimize.bat
:: toggles minimized state of a window by its filename
:: minimize.bat /? for usage

@echo off & setlocal

if "%~1"=="" goto usage
set "prog=%~n1"
tasklist | findstr /i "\<%prog%\>" >NUL || goto usage

set /P "=Toggling the minimized state of %prog%... " <NUL
powershell -noprofile -noninteractive "iex ((gc \"%~f0\") -join \"`n\")"

goto :EOF

:usage
echo syntax: %~nx0 progname[.exe]
echo;
echo If the program is visible, minimize it.  If minimized, restore it.
goto :EOF

End batch / begin PowerShell hybrid chimera #>

Add-Type user32_dll @'
    [DllImport("user32.dll")]
    public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    public static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName);

    [DllImport("user32.dll")]
    public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter,
        IntPtr lclassName, string windowTitle);
'@ -namespace System

$hwnd = (ps $env:prog)[0].MainWindowHandle

if ($hwnd -eq 0) {
    tasklist /v /fi "imagename eq $env:prog*" /fo list | %{
        $title = $_ -replace '^[^:]+:\s+'
    }
    $zero = [IntPtr]::Zero
    $hwnd = [user32_dll]::FindWindow($zero, $title)
    if ($hwnd -eq 0) {
        $hwnd = [user32_dll]::FindWindowEx($zero, $zero, $zero, $title)
    }
}

$state = [user32_dll]::GetWindowLong($hwnd, -16)

# mask of 0x20000000 = minimized; 2 = minimize; 4 = restore
if ($state -band 0x20000000) { $action = 4 } else { $action = 2 }

if ([user32_dll]::ShowWindowAsync($hwnd, $action)) {
    write-host "Success" -f green
} else {
    write-host "Fail" -f red
}
Community
  • 1
  • 1
rojo
  • 24,000
  • 5
  • 55
  • 101
  • sending even a simple esc keystroke to that program would be fine. how should I go about that in a vbscript ? – zython Jan 17 '16 at 22:18
  • 1
    Put this into a .vbs file: `CreateObject("WScript.Shell").SendKeys "{ESC}"` then to call it, `wscript vbsfile.vbs`. It sends Esc to whatever window happens to be focused. If all you need is to send an Esc keystroke, are you sure your mouse software doesn't have a keypress as an assignable action? – rojo Jan 17 '16 at 22:26
  • is it also possible to send a sendkey command to a specific window ? – zython Jan 17 '16 at 22:34
  • 1
    You can focus a window using [AppActivate](https://msdn.microsoft.com/en-us/library/wzcddbek%28v=vs.84%29.aspx). Then `SendKeys` sends keystrokes to the focused window. – rojo Jan 17 '16 at 22:40