I am developing a software for a blind individual in C# .NET.
The software works only with the keyboard and voice to speech.
When the computer starts the program is in the start up menu, but for some reason the program is activated not in focus therefore it does not work properly unless the focus is re transferred to it.
I found a way to hook keyboard keys even when the software is not in focus but I don't see that as a solution.
I want a way to do one or more of the following:
Make sure the program loads on start up and is in focus.
Maintain focus on the program (this computer will be run only using this program).
Find a keyboard shortcut, preferably one key only (not Alt + Tab) to return focus to the program.
There are many ways you can solve this ie you can run on startup console app that will run and focus your program:
[STAThread]
static void Main(string[] args)
{
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
myProcess.StartInfo.FileName = "calc";
myProcess.Start();
IntPtr hWnd = myProcess.Handle;
SetFocus(new HandleRef(null, hWnd));
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr SetFocus(HandleRef hWnd);
You can host a windows service application and using timer check if your app is alive and is focused or you can use hotkeys to bring it back focused: http://www.codeproject.com/KB/miscctrl/ashsimplehotkeys.aspx
Edited
this is console application, that will keep your app alive and focused (tested). i need to find walkaround for windows service becouse since vista something changed and form is invisible when stared from service :P
static Process myProcess;
[STAThread]
static void Main(string[] args)
{
for (int i = 0; i < 10000; i++)
{
//count how many procesess with this name are active if more than zero its still alive
Process[] proc = Process.GetProcessesByName("myprog");
if (proc.Length > 0)
{
//its alive check if it has focus
if (proc[0].MainWindowHandle != GetForegroundWindow())
{
SetFocus(proc[0].MainWindowHandle);
}
}
//no process start new one and focus on it
else
{
myProcess = new Process();
myProcess.StartInfo.FileName = "C:\\aa\\myprog.exe";
myProcess.Start();
SetFocus(myProcess.Handle);
}
Thread.Sleep(1000);
}
}
private static void SetFocus(IntPtr handle)
{
SwitchToThisWindow(handle, true);
}
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
Related
Good morning,
I'm trying to figure out how to put the focus on Google Chrome. That is to say to make as a click on the software in the taskbar (already open).
Thank you for helping me to put the focus on Google Chrome.
You can use the following function to bring chrome to front and to focus it.
The code uses 2 windows API calls because what you need is not directly provided by the .Net framework.
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
public class Program
{
[DllImport("user32.dll")]
[return: MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
private static extern bool ShowWindow(IntPtr hWnd, int flags);
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hwnd);
private static bool FocusChromeWindow()
{
foreach (Process chrome in Process.GetProcessesByName("chrome"))
{
// In case the process did not reveal a main window handle
// try to restore it in case it is hidden
if (chrome.MainWindowHandle == IntPtr.Zero)
{
ShowWindow(chrome.Handle, 9); // 9 = Restore
}
// If main window handle is still zero,
// this chrome process is one of the background
// workers chrome starts. Skip it.
if (chrome.MainWindowHandle != IntPtr.Zero)
{
SetForegroundWindow(chrome.MainWindowHandle);
return true;
}
}
return false;
}
static void Main(string[] args)
{
FocusChromeWindow();
Console.ReadLine();
}
}
I just implemented this code that is guarding the Single Instance of the Application, in order to not run the application twice.
Now I am wondering how I can show the original Application process that is already running.
Here is my code in the program class:
static class Program
{
[STAThread]
static void Main()
{
const string appName = "MyappName";
bool createdNew;
mutex = new Mutex(true, appName, out createdNew);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form form = new Form1();
if (!createdNew)
{
form.Show(); <<=========================== NOT WORKING
form.Visible = true; <<===================== None
form.TopMost = true; <<===================== of
form.BringToFront(); <<===================== these working!
form.WindowState = FormWindowState.Maximized;
return;
}
Application.Run(form);
} private static Mutex mutex = null;
}
I propose you a different method, using a combination of the System.Threading.Mutex class and UIAutomation AutomationElement class.
A Mutex can be, as you already know, a simple string. You can assign an application a Mutex in the form of a GUID, but it can be anything else.
Let's assume this is the current Application Mutex:
string ApplicationMutex = "BcFFcd23-3456-6543-Fc44abcd1234";
//Or
string ApplicationMutex = "Global\BcFFcd23-3456-6543-Fc44abcd1234";
Note:
Use the "Global\" Prefix to define the scope of the Mutex. If no prefix is specified, the "Local\" prefix is assumed and used instead. This will prevent a single instance of the process when multiple desktops are active or Terminal Services is running on the server.
If we want to verify whether another running Process has already registered the same Mutex, we try to register our Mutex and if it fails, another instance of our Application is already running.
We let the user know that the Application supports only a single instance, then switch to the running process, showing its interface and finally exit the duplicate Application, disposing of the Mutex.
The method to activate a previous instance of the Application may vary based on the type of the Application, but only some details change.
We can use Process..GetProcesses() to retrieve a list of the running processes and verify if one of them has the same details as ours.
Here, you have a windowed Application (it has an UI), so it's already possible to filter the list, excluding those processes that do not have a MainWindowHandle.
Process[] windowedProcesses =
Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();
To identify the right one, we could test if the Process.ProcessName is the same.
But this name is tied to the executable name. If the file name changes (someone changes it for some reason), we will never identify the Process this way.
One possible way to identify the right Process is to test the Process.MainModule.FileVersionInfo.ProductName and check whether it's the same.
When found, it's possible to bring the original Application to front with an AutomationElement created using the MainWindowHandle of the identified Process.
The AutomationElement can automate different Patterns (sort of controls that provide automation functionalities for UI elements).
A WindowPattern allows to control a window-base control (the Platform is irrelevant, could be a WinForms' Form or a WPF's Window).
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
WindowPattern wPattern = element.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
wPattern.SetWindowVisualState(WindowVisualState.Normal);
To use the UIAutomation functionalities, you have to add these refereneces in your Project:
- UIAutomationClient
- UIAutomationTypes
UPDATE:
Since the Application's Form might be hidden, Process.GetProcesses() will not find it's Window handle, thus AutomationElement.FromHandle() cannot be used to identify the Form Window.
A possible workaround, without dismissing the UIAutomation "pattern", is to register an Automation event, using Automation.AddAutomationEventHandler, which allows to receive a notification when an UI Automation events occurs, such as a new Window is about to be shown (a Program is run).
The event is registerd only if the Application needs to run as Single Instance. When the event is raised, the new Process AutomationElement Name (the Windows Title Text) is compared to the current and, if it's the same, the hidden Form will un-hide and show itself in Normal state.
As a fail-safe measure, we present an information MessageBox. The MessageBox caption has the same caption as the Application MainForm.
(Tested with a Form with its WindowsState set to Minimized and its Visible property set to false).
After the orginal Process has been brought to front, we just neeed to close the current thread and release the resources we created (mainly the Mutex, in this case).
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Automation;
using System.Windows.Forms;
static class Program
{
static Mutex mutex = null;
[STAThread]
static void Main()
{
Application.ThreadExit += ThreadOnExit;
string applicationMutex = #"Global\BcFFcd23-3456-6543-Fc44abcd1234";
mutex = new Mutex(true, applicationMutex);
bool singleInstance = mutex.WaitOne(0, false);
if (!singleInstance)
{
string appProductName = Process.GetCurrentProcess().MainModule.FileVersionInfo.ProductName;
Process[] windowedProcesses =
Process.GetProcesses().Where(p => p.MainWindowHandle != IntPtr.Zero).ToArray();
foreach (Process process in windowedProcesses.Where(p => p.MainModule.FileVersionInfo.ProductName == appProductName))
{
if (process.Id != Process.GetCurrentProcess().Id)
{
AutomationElement wElement = AutomationElement.FromHandle(process.MainWindowHandle);
if (wElement.Current.IsOffscreen)
{
WindowPattern wPattern = wElement.GetCurrentPattern(WindowPattern.Pattern) as WindowPattern;
#if DEBUG
WindowInteractionState state = wPattern.Current.WindowInteractionState;
Debug.Assert(!(state == WindowInteractionState.NotResponding), "The application is not responding");
Debug.Assert(!(state == WindowInteractionState.BlockedByModalWindow), "Main Window blocked by a Modal Window");
#endif
wPattern.SetWindowVisualState(WindowVisualState.Normal);
break;
}
}
}
Thread.Sleep(200);
MessageBox.Show("Application already running", "MyApplicationName",
MessageBoxButtons.OK, MessageBoxIcon.Information,
MessageBoxDefaultButton.Button1, MessageBoxOptions.ServiceNotification);
}
if (SingleInstance) {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyAppMainForm());
}
else {
Application.ExitThread();
}
}
private static void ThreadOnExit(object s, EventArgs e)
{
mutex.Dispose();
Application.ThreadExit -= ThreadOnExit;
Application.Exit();
}
}
In the Application MainForm constructor:
(this is used in case the Application's Main Window is hidden when a new instance is run, hence the procedure in Program.cs cannot find its handle)
public partial class MyAppMainForm : Form
{
public MyAppMainForm()
{
InitializeComponent();
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement,
TreeScope.Subtree, (uiElm, evt) =>
{
AutomationElement element = uiElm as AutomationElement;
string windowText = element.Current.Name;
if (element.Current.ProcessId != Process.GetCurrentProcess().Id && windowText == this.Text)
{
this.BeginInvoke(new MethodInvoker(() =>
{
this.WindowState = FormWindowState.Normal;
this.Show();
}));
}
});
}
}
Run Only One time :
static class Program
{
[STAThread]
static void Main()
{
bool createdNew = true;
using (Mutex mutex = new Mutex(true, "samplename", out createdNew))
{
if (createdNew)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
Application.Run(new Form1());
}
else
{
ProcessUtils.SetFocusToPreviousInstance("samplename");
}
}
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
}
private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
}
}
ProcessUtils :
public static class ProcessUtils
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_RESTORE = 9;
[DllImport("user32.dll")]
static extern IntPtr GetLastActivePopup(IntPtr hWnd);
[DllImport("user32.dll")]
static extern bool IsWindowEnabled(IntPtr hWnd);
public static void SetFocusToPreviousInstance(string windowCaption)
{
IntPtr hWnd = FindWindow(null, windowCaption);
if (hWnd != null)
{
IntPtr hPopupWnd = GetLastActivePopup(hWnd);
if (hPopupWnd != null && IsWindowEnabled(hPopupWnd))
{
hWnd = hPopupWnd;
}
SetForegroundWindow(hWnd);
if (IsIconic(hWnd))
{
ShowWindow(hWnd, SW_RESTORE);
}
}
}
}
Normal Run :
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
If you are still looking for an answer. There is a good example here that
uses windows messages to restore the previous instance. It work even if the first instance is minimized contrary to FindWindow witch does not work in that case.
I'm developing a tiny launcher. Its main idea is to fix the lack of functionality in Viber for Windows.
I want it to make start Viber minimized to tray only.
Normally, when Viber is starting, it appears a Viber main window on desktop and an icon - in system tray. All the time I should close this obsolete window manually.
So, I have written a few lines of code, but I found that it still couldn't close the window:
using System;
using System.Diagnostics;
class ViberStrt {
static void Main() {
Process newProc = Process.Start("c:\\Users\\Dmytro\\AppData\\Local\\Viber\\Viber.exe");
Console.WriteLine("New process has started");
//newProc.CloseMainWindow();
newProc.WaitForExit();
newProc.Close();
newProc.Dispose();
Console.WriteLine("Process has finished");
//newProc.Kill();
}
}
But whatever I tried (Close, Dispose) - it does not work.
Method Kill does not fit, because it kills all. But the only thing I need is to close Viber main window and leave the process in the System Tray.
There is also another way: to start Viber minimized at once:
using System;
using System.Diagnostics;
class LaunchViber
{
void OpenWithStartInfo()
{
ProcessStartInfo startInfo = new ProcessStartInfo("c:\\Users\\Dmytro\\AppData\\Local\\Viber\\Viber.exe");
startInfo.WindowStyle = ProcessWindowStyle.Minimized;
Process.Start(startInfo);
}
static void Main()
{
//Process newProc = Process.Start("c:\\Users\\Dmytro\\AppData\\Local\\Viber\\Viber.exe");
LaunchViber newProc = new LaunchViber();
newProc.OpenWithStartInfo();
}
}
In such a case, we receive a minimized window on the TaskPane and an icon in the SystemTray. But in this case I have absolutely no idea how to get rid of the icon (how to close minimized window) on the TaskPane.
I shall appreciate any help/ ideas in finding a solution for this problem.
Using Pinvoke, you can try getting the handle for the actual window if you know what the window caption will be.
First, import these functions:
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
And you may want to declare the WM_CLOSE constant:
const UInt32 WM_CLOSE = 0x0010;
Then the code to close the window (but keep the process running the in background):
var startInfo = new ProcessStartInfo(#"c:\Users\Dmytro\AppData\Local\Viber\Viber.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
var newProc = Process.Start(startInfo);
var name = "Viber +381112223344";
var windowPtr = FindWindowByCaption(IntPtr.Zero, name);
while (windowPtr == IntPtr.Zero)
{
windowPtr = FindWindowByCaption(IntPtr.Zero, name);
}
System.Threading.Thread.Sleep(100);
SendMessage(windowPtr, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
I have written a program that change the windows theme but after changing the theme personalization window remains open and I want to close it. I tried using process.kill() with familiar process name but it didn't work. Thank you.
The code for what I am doing is as below:
ProcessStartInfo theinfo = new ProcessStartInfo(themepath + "aero.theme");
theinfo.CreateNoWindow = true;
Process thepr = new Process();
thepr.StartInfo = theinfo;
thepr.Start();
where "themepath" is String location to aero.theme.
I have even enabled CreateNoWindow to true then also it opens up Personalization to change theme but didn't close it automatically.
First use find window to get the window from their name by Using FindWindow..
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName,string lpWindowName);
It returns you the handle of the window you want now you can use send message to close it..
[DllImport("User32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
public const int WM_SYSCOMMAND = 0x0112;
public const int SC_CLOSE = 0xF060;
private void closeWindow()
{
// retrieve the handler of the window
int iHandle = FindWindow("CabinetWClass", "Personalization");
if (iHandle > 0)
{
SendMessage(iHandle, WM_SYSCOMMAND, SC_CLOSE, 0);
}
}
You need to obtain the window handle by it's name and then send it a close message. This prevents having to kill any processes. See this article for information on obtaining the windows. See this one for closing windows from the handle.
After seeing the code and doing a little digging, you can accomplish this with two registry edits. You should read this article and just have your program edit the two registry keys in question.
I have a .dll library for c# that loves to pop out a 'Welcome' screen when it starts.
This screen appears as an application in the task manager.
Is there some way to automatically detect this application/form being launched and close it?
Thanks! :)
Here us simple console application that will monitor and close specified window
class Program
{
static void Main(string[] args)
{
while(true)
{
FindAndKill("Welcome");
Thread.Sleep(1000);
}
}
private static void FindAndKill(string caption)
{
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
IntPtr pFoundWindow = p.MainWindowHandle;
StringBuilder windowText = new StringBuilder(256);
GetWindowText(pFoundWindow, windowText, windowText.Capacity);
if (windowText.ToString() == caption)
{
p.CloseMainWindow();
Console.WriteLine("Excellent kill !!!");
}
}
}
[DllImport("user32.dll", EntryPoint = "GetWindowText",ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText(IntPtr hWnd,StringBuilder lpWindowText, int nMaxCount);
}
If it's running within your process and opening a Form (not a Dialog), you can use something like this to close all Forms which aren't opened by your own Assembly.
foreach (Form form in Application.OpenForms)
if (form.GetType().Assembly != typeof(Program).Assembly)
form.Close();
What is your own Assembly is defined by the class Program, you could also use Assembly.GetExecutingAssembly or Assembly.GetCallingAssembly, but I'm not sure it will behave correctly, if you run the Application inside Visual Studio (since it might return the VS Assembly).