My code is very simple:
using Microsoft.VisualBasic;
namespace HelloWorld {
class MyClass {
static void Main(string[] args) {
Interaction.AppActivate(6156); // the PID of notepad++
}
}
}
When I execute this program, nothing happens. I would expect 6156 (PID from Task Manager) aka Notepad++ to get focused. What's wrong here?
I'm trying to find the equivalent to Pythons pywin32 code of shell = win32com.client.Dispatch("WScript.Shell") and shell.AppActivate(6156)
The Interaction.AppActivate code will not work if the app is minimized.
Use the following code to active the app:
public const int SW_RESTORE = 9;
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern public bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void Main(string[] args)
{
var process = Process.GetProcessById(18036);
ShowWindow(process.MainWindowHandle, SW_RESTORE);
SetForegroundWindow(process.MainWindowHandle);
}
This works fine for me.
static void Main(string[] args)
{
var process = Process.GetProcessById(13004);//the pid
if (process == null) return;
SwitchToThisWindow(process.MainWindowHandle, true);
}
[DllImport("user32.dll", SetLastError = true)]
static extern void SwitchToThisWindow(IntPtr hWnd, bool turnOn);
Related
Hi so i am trying to get a focus of application and all i could find online was the SetForegroundWindow method so i tried to implement it but its not setting the focus to the application at all, i also found some articles about it not being reliable so wanned to ask if i did it wrong or if there is a better way to inject key presses to an application, thanks!
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
private void JumpRL(object sender, EventArgs e)
{
Process[] processlist = Process.GetProcesses();
var name = processlist.Where(x => x.ProcessName == "RocketLeague").FirstOrDefault();
SetForegroundWindow(name.MainWindowHandle);
SendKeys.SendWait("{BS}");
}
the process is correct i double checked
So after long online searching i found an article with an example code of switching windows, so i said heck it and went to try and it actualy worked and it switches focus here is the snippet hope it helps
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();
[DllImport("user32.dll", SetLastError = true)]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
public static void SwitchWindow(IntPtr windowHandle)
{
if (GetForegroundWindow() == windowHandle)
return;
IntPtr foregroundWindowHandle = GetForegroundWindow();
uint currentThreadId = GetCurrentThreadId();
uint temp;
uint foregroundThreadId = GetWindowThreadProcessId(foregroundWindowHandle, out temp);
AttachThreadInput(currentThreadId, foregroundThreadId, true);
SetForegroundWindow(windowHandle);
AttachThreadInput(currentThreadId, foregroundThreadId, false);
while (GetForegroundWindow() != windowHandle)
{
}
}
after you have the focus a simple SendKeys.SendWait("<key>") works like a charm
I am trying to create a WPF - hybrid application. This application should have the option to be started from command prompt, where in this case, it would not show any window but will only start some process and then quit.
For example (made up example) in my WPF application I enable users to create body of an email message that will be send to any user (sort of a template).
Afterwards when user wants to send the email, he can do it via cmd like following (meaning GUI will not even start, it will only call email connector and send message to selected recipient and then quit program):
MyProgram.exe -recipient john#doe.com -send=true
My Main() looks like this (created based on the following website:http://www.jankowskimichal.pl/en/2011/12/wpf-hybrid-application-with-parameters/)
public static class Program
{
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
[DllImport("kernel32", SetLastError = true)]
static extern bool AttachConsole(int dwProcessId);
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);
[STAThreadAttribute]
[System.Diagnostics.DebuggerNonUserCodeAttribute]
public static void Main(string[] args)
{
//App.Main();
if (args.Length == 0)
{
IP_DynamicMailings.App app = new IP_DynamicMailings.App();
app.InitializeComponent();
app.Run();
}
else
{
// Get uppermost window process
IntPtr ptr = GetForegroundWindow();
int u;
GetWindowThreadProcessId(ptr, out u);
Process process = Process.GetProcessById(u);
// Check if it is console?
if (process.ProcessName == "cmd")
{
// Yes – attach to active console
AttachConsole(process.Id);
}
else
{
// No – create new console
AllocConsole();
}
// Program actions ...
foreach (var item in args)
{
Console.WriteLine(item);
}
FreeConsole();
}
}
}
What happens is, that I need to press Enter in order to quit application.
I am also open to rewrite my hybrid logic, shall you have better solution (this was so far the best I could find).
I want to know how to bring forward a particular window.
SetForegroundWindow works when the window is not minimized!! but when a minimize the window, SetForegroundWindow doesn't work...
this my code:
int IdRemoto = int.Parse(textBoxID.Text);
Process[] processlist = Process.GetProcessesByName("AA_v3.3");
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
if (IdRemoto.ToString() == process.MainWindowTitle)
SetForegroundWindow(process.MainWindowHandle);
}
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
You can check to see if the window is minimized using the IsIconic() API, then use ShowWindow() to restore it:
public const int SW_RESTORE = 9;
[DllImport("user32.dll")]
public static extern bool IsIconic(IntPtr handle);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr handle, int nCmdShow);
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr handle);
private void BringToForeground(IntPtr extHandle)
{
if (IsIconic(extHandle))
{
ShowWindow(extHandle, SW_RESTORE);
}
SetForegroundWindow(extHandle);
}
You can use ShowWindow combined with what you already have, here is your example with a little modification:
int IdRemoto = int.Parse(textBoxID.Text);
Process[] processlist = Process.GetProcessesByName("AA_v3.3");
foreach (Process process in processlist)
{
if (!String.IsNullOrEmpty(process.MainWindowTitle))
{
if (IdRemoto.ToString() == process.MainWindowTitle)
{
ShowWindow(process.MainWindowHandle, 9);
SetForegroundWindow(process.MainWindowHandle);
}
}
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWind, int nCmdShow);
My app has a default setting that makes it run on the Icon tray when you boot your computer.
If you click on the Icon from the Icon tray then the app is displayed on the desktop window.
Further more if a user try to launch a new instance of my app whilst the old one is running, I just display a message that another instance is running and then Quit the new instance.
Now I want the New instance not only to quit but also makes the Old instance active/displayed on the desktop.
This is my present code
if (System.Diagnostics.Process.GetProcessesByName(
System.Diagnostics.Process.GetCurrentProcess().ProcessName).Length > 1)
{
MessageBox.Show(kingCobra.Properties.Resources.Msg_Multiple_Starts,
kingCobra.Properties.Resources.Multiple_Starts,
MessageBoxButtons.OK, MessageBoxIcon.Warning);
System.Diagnostics.Process.GetCurrentProcess().Kill();
return;
}
What you need to do is to add this to your main class:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
Then you need to obtain a reference to the process that is already running, and then call the SetForegroundWindow method like this:
SetForegroundWindow(SameProcess.MainWindowHandle);
You do not need to kill the current process like you are currently doing, just return after focusing the other process' main window as shown above
This is a full working example:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
var currentProcess = Process.GetCurrentProcess();
foreach (Process p in Process.GetProcessesByName(currentProcess.ProcessName))
{
if (p.Id != currentProcess.Id)
{
MessageBox.Show("Already running");
SetForegroundWindow(p.MainWindowHandle);
return;
}
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
This is the best way I've ever seen to get this job done.
public class SingleInstanceController : WindowsFormsApplicationBase
{
public SingleInstanceController()
{
IsSingleInstance = true;
}
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs)
{
Form1 form = MainForm as Form1;
form.Text = "I will run only once!";
form.Activate();
base.OnStartupNextInstance(eventArgs);
}
protected override void OnCreateMainForm()
{
MainForm = new Form1();
}
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string[] args = Environment.GetCommandLineArgs();
SingleInstanceController controller = new SingleInstanceController();
controller.Run(args);
}
}
Actual code from this article Single Instance Application.
Note: this requires you to add reference of Microsoft.VisualBasic.dll
I finally Got what I wanted from Here. My main problem was to bring the old instance from the Icon tray whilst closing the new
static class Program
{
[STAThread]
static void Main()
{
if (!SingleInstance.Start()) {
SingleInstance.ShowFirstInstance();
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try {
MainForm mainForm = new MainForm();
Application.Run(mainForm);
} catch (Exception e) {
MessageBox.Show(e.Message);
}
SingleInstance.Stop();
}
}
//And secondly within your main form, the following code must be added:
protected override void WndProc(ref Message message)
{
if (message.Msg == SingleInstance.WM_SHOWFIRSTINSTANCE) {
Show
Window();
}
base.WndProc(ref message);
}
public void ShowWindow()
{
// Insert code here to make your form show itself.
WinApi.ShowToFront(this.Handle);
}
You can use the Threading Mutex and user32.dll
try this
Step 1 :
Declare the following constantes:
private const int SW_NORMAL = 1; // see WinUser.h for definitions
private const int SW_SHOWMAXIMIZED = 3;
private const int SW_RESTORE = 9;
[DllImport("User32", EntryPoint = "FindWindow")]
static extern IntPtr FindWindow(string className, string windowName);
[DllImport("User32", EntryPoint = "SendMessage")]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("User32", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32", EntryPoint = "SetWindowPlacement")]
private static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
[DllImport("User32", EntryPoint = "GetWindowPlacement")]
private static extern bool GetWindowPlacement(IntPtr hWnd, [In] ref WINDOWPLACEMENT lpwndpl);
private struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
}
Step 2 :
Add this methode :
public void application_run(Form form1)
{
bool createdNew;
System.Threading.Mutex m = new System.Threading.Mutex(true, form1.Name, out createdNew);
if (!createdNew)
{
MessageBox.Show("...", "...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);//Alert message
try
{
// see if we can find the other app and Bring it to front
IntPtr hWnd = FindWindow(null, form1.Text);
if (hWnd != IntPtr.Zero)
{
LoaderDomain.WINDOWPLACEMENT placement = new LoaderDomain.WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hWnd, ref placement);
placement.showCmd = SW_SHOWMAXIMIZED;
SetWindowPlacement(hWnd, ref placement);
SetForegroundWindow(hWnd);
}
}
catch
{
//rien
}
}
else
{
Application.Run(form1);
}
// keep the mutex reference alive until the normal termination of the program
GC.KeepAlive(m);
}
Step 3 :
Replace in the main
Application.run(forms);
by a call to previous the methode
Let's say I have multiple chrome windows open (not tabs),
how can I check the browser title?
I tried the following:
Process[] p = Process.GetProcessesByName("chrome");
foreach (Process item in p)
{
Console.WriteLine(item.MainWindowTitle);
}
but it return me only the last open window name and all other are blanks..
I had to do something like this, but it was amazingly fiddly involving calling Windows API functions. The problem was that Chrome seems to use a single process for multiple windows or some other weirdness that meant the simple approach didn't work for me.
Anyway, try this and see if it works. Basically it uses the Chrome window class name (which might be Chrome_WidgetWin_0 or Chrome_WidgetWin_1) to enumerate all windows with that class name, and returns the window titles for those which are not blank.
Note that this also always returns a windows title called "Chrome App Launcher" for some reason, so you might need to filter that out.
Note: you can also do this for Firefox by using "MozillaWindowClass" and for IE by using "IEFrame" (although any of those are likely to change with different versions).
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
namespace Demo
{
class WindowsByClassFinder
{
public delegate bool EnumWindowsDelegate(IntPtr hWnd, IntPtr lparam);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool EnumWindows(EnumWindowsDelegate lpEnumFunc, IntPtr lparam);
[SuppressMessage("Microsoft.Security", "CA2118:ReviewSuppressUnmanagedCodeSecurityUsage"), SuppressUnmanagedCodeSecurity]
[DllImport("User32", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
/// <summary>Find the windows matching the specified class name.</summary>
public static IEnumerable<IntPtr> WindowsMatching(string className)
{
return new WindowsByClassFinder(className)._result;
}
private WindowsByClassFinder(string className)
{
_className = className;
EnumWindows(callback, IntPtr.Zero);
}
private bool callback(IntPtr hWnd, IntPtr lparam)
{
if (GetClassName(hWnd, _apiResult, _apiResult.Capacity) != 0)
{
if (string.CompareOrdinal(_apiResult.ToString(), _className) == 0)
{
_result.Add(hWnd);
}
}
return true; // Keep enumerating.
}
public static IEnumerable<string> WindowTitlesForClass(string className)
{
foreach (var windowHandle in WindowsMatchingClassName(className))
{
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(windowHandle, sb, sb.Capacity);
yield return sb.ToString();
}
}
public static IEnumerable<IntPtr> WindowsMatchingClassName(string className)
{
if (string.IsNullOrWhiteSpace(className))
throw new ArgumentOutOfRangeException("className", className, "className can't be null or blank.");
return WindowsMatching(className);
}
private readonly string _className;
private readonly List<IntPtr> _result = new List<IntPtr>();
private readonly StringBuilder _apiResult = new StringBuilder(1024);
}
class Program
{
void run()
{
ChromeWindowTitles().Print();
}
public IEnumerable<string> ChromeWindowTitles()
{
foreach (var title in WindowsByClassFinder.WindowTitlesForClass("Chrome_WidgetWin_0"))
if (!string.IsNullOrWhiteSpace(title))
yield return title;
foreach (var title in WindowsByClassFinder.WindowTitlesForClass("Chrome_WidgetWin_1"))
if (!string.IsNullOrWhiteSpace(title))
yield return title;
}
static void Main()
{
new Program().run();
}
}
static class DemoUtil
{
public static void Print(this object self)
{
Console.WriteLine(self);
}
public static void Print(this string self)
{
Console.WriteLine(self);
}
public static void Print<T>(this IEnumerable<T> self)
{
foreach (var item in self)
Console.WriteLine(item);
}
}
}
I know this is already answered, but I also have made a solution, which enumerates all Windows within a thread.
It was built from Matthew Watson's solution, hence some similarities.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Chrome_Windows
{
class Program
{
[DllImport("user32.dll")]
private static extern bool EnumThreadWindows(uint dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("User32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr windowHandle, StringBuilder stringBuilder, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "GetWindowTextLength", SetLastError = true)]
internal static extern int GetWindowTextLength(IntPtr hwnd);
private static List<IntPtr> windowList;
private static string _className;
private static StringBuilder apiResult = new StringBuilder(256); //256 Is max class name length.
private delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
static void Main(string[] args)
{
List<IntPtr> ChromeWindows = WindowsFinder("Chrome_WidgetWin_1", "chrome");
foreach (IntPtr windowHandle in ChromeWindows)
{
int length = GetWindowTextLength(windowHandle);
StringBuilder sb = new StringBuilder(length + 1);
GetWindowText(windowHandle, sb, sb.Capacity);
Console.WriteLine(sb.ToString());
}
}
private static List<IntPtr> WindowsFinder(string className, string process)
{
_className = className;
windowList = new List<IntPtr>();
Process[] chromeList = Process.GetProcessesByName(process);
if (chromeList.Length > 0)
{
foreach (Process chrome in chromeList)
{
if (chrome.MainWindowHandle != IntPtr.Zero)
{
foreach (ProcessThread thread in chrome.Threads)
{
EnumThreadWindows((uint)thread.Id, new EnumThreadDelegate(EnumThreadCallback), IntPtr.Zero);
}
}
}
}
return windowList;
}
static bool EnumThreadCallback(IntPtr hWnd, IntPtr lParam)
{
if (GetClassName(hWnd, apiResult, apiResult.Capacity) != 0)
{
if (string.CompareOrdinal(apiResult.ToString(), _className) == 0)
{
windowList.Add(hWnd);
}
}
return true;
}
}
}
I know this is an old thread, but I have found the answer to this, at least for my use case anyway. I wanted to find all the open chrome windows/tabs by title as well, but in my case I wanted to close the ones I found containing x Title. After reading icbytes and dor-cohen's post above I realized I could achieve what I needed by calling Process.GetProcessesByName() more than once. When making this call you do get an array of all the running chrome processes, but only one instance will contain a value for MainWindowTitle. This is a bit annoying for several reasons. You can have multiple chrome sessions open with and "active" "displayed tab", but still the call only ever returns an array of chrome proc's with just one instance in that array having an value for MainWindowTitle. Again, my solution is not necessarily the OP's intention as he states just wanting to list the titles. My solution wants to close each found title.
What I have done is as follows:
Once I find the first chrome process with the title I am looking for I call CloseMainWindow() on that process. Do not call Kill() as it will crash the browser altogether. I am just closing the active or top level window here. I am posting my code below. I hope this will help someone else! Thanks!
bool foundAll = false;
do
{
bool foundOne = false;
procs = Process.GetProcessesByName("chrome");
foreach (Process p in procs)
{
if (p.MainWindowTitle.Length > 0)
{
string t = p.MainWindowTitle.Replace(" - Google Chrome", "");
if (t.ToLower().Contains(this.BrowserTabText.ToLower()))
{
foundOne = true;
this.WriteEventLogEntry($"Found Tab Title: {this.BrowserTabText} with PID: {p.Id}. \r\nWe will close it.", EventLogEntryType.Information);
p.CloseMainWindow();
break;
}
}
}
if (!foundOne)
{
foundAll = true;
}
} while (!foundAll);
You must get a list of processes.
Iterate through the list and only where name is "chrome".
This will allow You to get all titles.
Because if You have more then one chrome process , Your call will give You only one, because You call it only once.
Which it returns is perhaps another question. In Your case it is the last.