I´m facing a problem when trying to close a Windows Explorer (not Internet Explorer) window through another application, using the "Process.CloseMainWindow()" method; because it doesn´t close the Explorer window, it tries to close the full Windows (Operative System), by the way, Windows XP.
The code is as follows:
[DllImport("user32.dll")]
static extern int GetForegroundWindow();
[DllImport("user32.dll")]
private static extern UInt32 GetWindowThreadProcessId(Int32 hWnd, out Int32 lpdwProcessId);
public String[] exeCommand()
{
try
{
//Get App
Int32 hwnd = 0;
hwnd = GetForegroundWindow();
Process actualProcess = Process.GetProcessById(GetWindowProcessID(hwnd));
//Close App
if (!actualProcess.CloseMainWindow())
actualProcess.Kill();
}
catch { throw; }
return null;
}
Suppose that the "actualProcess" is "explorer.exe"
Any help will be appreciated!!
Salutes!
I believe this is because the main window for explore is considered the shell. You can however kill the process, but windows will start it right back up.
Related
I wrote an application in C# that brings another application to the foreground.
This function so far. However, there is a problem.
If you set the focus, the application is opened and brought to the foreground, but the Windows docking function does not work. The application is only ever opened in its last window size.
EDIT:
I forgot to mention that the docking should be seen on the Windows desktop (monitor edge).
Does anyone have any idea how to get the docking feature on?
[DllImport("../user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("../user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public void SetWindowToForeground(List<string> formattedPartList)
{
string windowTitle = formattedPartList[4];
int activeResize = 5; //
IntPtr mainWindowHandle = GetProcessIdByName(windowTitle);
SetForegroundWindow(mainWindowHandle);
ShowWindow(mainWindowHandle, activeResize);
}
I am currently working on an app switcher program that would need to switch between all the windows of running applications (not just the top level window) in Windows 10. Is this possible in WPF?
So far, I have tried iterating through each process obtained from calling Process.GetProcesses().
Process[] processList = Process.GetProcesses();
foreach(Process process in processList){
// code
}
By using that API, I have only been able to get the MainWindowHandle and MainWindowTitle from the process object. Instead, I would actually like to get the title of a window that is not in the top level as well.
For example:
If I have two windows of Google Chrome open, I would have access to the titles of each of the windows instead of just the top-level or most recently used window.
So far, I've looked into using EnumWindows, but I noticed that in Windows 10 that will only return the top-level window.
You have to use EnumChildWindows.
This should more or less look like that:
First, create a helper class for WinApi:
class WindowManager
{
public delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);
//this one would iterate through child windows of window
public static bool IterateChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam)
{
return EnumChildWindows(window, callback, lParam);
}
}
Now, you can call IterateChildWindows. OnEnumWindow is the method that will be called on every window found. Note that window is also a button, textbox, etc:
WindowManager.IterateChildWindows(hwnd, OnEnumWindow, IntPtr.Zero);
bool OnEnumWindow(IntPtr foundWindow, IntPtr lParam)
{
//here you have to check if this window is a form or a control and then do your work
}
Intention : Run a single instance of a WPF application. When a new instance, is started the already running instance should be set to the foreground.
While I have achieved most of it, I am facing a problem when the already running application is sitting in the notification tray. The code runs without an error, but fails to restore the window & set it to foreground. Code Snippet (c#):
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int cmdShow);
var currentProcess = Process.GetCurrentProcess();
string processName = currentProcess.ProcessName;
Process[] instances = Process.GetProcessesByName(processName);
if (instances.Length > 1)
{
foreach(var instance in instances)
{
if (!currentProcess.Id.Equals(instance.Id))
{
IntPtr hWnd = instance.MainWindowHandle;
if (IsIconic(hWnd))
ShowWindow(hWnd, SW_RESTORE);
SetForegroundWindow(hWnd);
}
}
currentProcess.Kill();
}
Can any one point out what am I doing wrong. To reiterate again, it works in the case when the already running window is in maximized state but in the hindsight. It fails when the already running window is minimized to the notification tray.
Thanks
Have you verified, that your code executes the ShowWindow when the already running process is in the systray? I am asking, because I don't think that IsIconic is the correct function to use: The documentation states that it "determines whether the specified window is minimized". If the process is in the systray it isn't minimized, it is hidden.
I think you should use IsWindowVisible instead.
I need to kill windows explorer's process (explorer.exe), for that
lets say i use a native NT method TerminateProcess
It works but the problem is that the explorer starts again, may be windows is doing that, anyway. When i kill explorer.exe with windows task manager, it doesn't come back, its stays killed.
I want to do whatever taskmanager is doing through my application.
Edit:
Thanks to #sblom i solved it, a quick tweak in the registry did the trick. Although its a clever hack, apparently taskmnager has a cleaner way of doing that, that said, i've decided to go with #sblom's way for now.
From Technet:
You can set the registry key HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoRestartShell to 0, and it will no longer auto-restart.
The "real" solution. (Complete program. Tested to work on Windows 7.)
using System;
using System.Runtime.InteropServices;
namespace ExplorerZap
{
class Program
{
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);
static void Main(string[] args)
{
int hwnd;
hwnd = FindWindow("Progman", null);
PostMessage(hwnd, /*WM_QUIT*/ 0x12, 0, 0);
return;
}
}
}
Here's another solution to this problem - instead api calls it uses an external tool shipped with windows (at least Win 7 Professional):
public static class Extensions
{
public static void ForceKill(this Process process)
{
using (Process killer = new Process())
{
killer.StartInfo.FileName = "taskkill";
killer.StartInfo.Arguments = string.Format("/f /PID {0}", process.Id);
killer.StartInfo.CreateNoWindow = true;
killer.StartInfo.UseShellExecute = false;
killer.Start();
killer.WaitForExit();
if (killer.ExitCode != 0)
{
throw new Win32Exception(killer.ExitCode);
}
}
}
}
I know that Win32Exception may not be the best Exception, but this method acts more or less like Kill - with the exception that it actually kills windows explorer.
I've added it as an extension method, so you can use it directly on Process object:
foreach (Process process in Process.GetProcessesByName("explorer"))
{
process.ForceKill();
}
You must first ensure that the taskkill tool is available on production environment (it seems that it's been for a while with windows: https://web.archive.org/web/20171016213040/http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/taskkill.mspx?mfr=true).
EDIT: Original link dead, replaced with cache from Internet Archive Wayback Machine. Updated documentation for Windows 2012/2016 can be found at: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/taskkill
What you probably need to do is instead of using TerminateProcess, post a WM_QUIT message to the explorer windows and main thread. It's a bit involved, but I found this page which has some example code that might help you along:
http://www.replicator.org/node/100
Windows will automatically restart explorer.exe after a TerminateProcess so that it restarts in the case of a crash termination.
I have some researches and these are reslts:
Windows will restart explorer after it closed -except by Task Manager-.
So you should change the related RegistryKey:
RegistryKey regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default).OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\Winlogon", RegistryKeyPermissionCheck.ReadWriteSubTree);
if (regKey.GetValue("AutoRestartShell").ToString() == "1")
regKey.SetValue("AutoRestartShell", 0, RegistryValueKind.DWord);
For changing a registry key the program should run as administrator:
You can show UAC prompt to user to run application as administrator as explaining in this Answer.
And if UAC is turned off I direct you to this Answer.
You can embed a manifest file in the exe, which will cause Windows Seven to always run the program as an administrator, As explaining in this Answer.
You should know you can't force your process starts as administrator; so you can run your process inside your process as another process! You can use this blog post or this answer.
You can also use reg command with this [Microsoft Windows Documentation].6.
After setting that -restarting explorer- off: This code can close explorer :
Process[] ps = Process.GetProcessesByName("explorer");
foreach (Process p in ps)
p.Kill();
I have a console application I'm using to run scheduled jobs through windows scheduler. All the communication to/from the application is in email, event logging, database logs. Is there any way I can suppress the console window from coming up?
Sure. Build it as a winforms app and never show your form.
Just be careful, because then it's not really a console app anymore, and there are some environments where you won't be able to use it.
Borrowed from MSDN (link text):
using System.Runtime.InteropServices;
...
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName,string lpWindowName);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
...
//Sometimes System.Windows.Forms.Application.ExecutablePath works for the caption depending on the system you are running under.
IntPtr hWnd = FindWindow(null, "Your console windows caption"); //put your console window caption here
if(hWnd != IntPtr.Zero)
{
//Hide the window
ShowWindow(hWnd, 0); // 0 = SW_HIDE
}
if(hWnd != IntPtr.Zero)
{
//Show window again
ShowWindow(hWnd, 1); //1 = SW_SHOWNORMA
}
It's a hack, but the following blog post describes how you can hide the console window:
http://expsharing.blogspot.com/2008/03/hideshow-console-window-in-net-black.html
Schedule the task to run as a different user than your account and you won't get a window popping up . . .
Simply configure the Scheduled Task as "Run whether user is logged on or not".
Why don't you make the application a Windows Service?