How can I check which program is in focus? - c#

I'm trying to have a timer check if a specific program is in focus every 250ms, but I just can't figure out how...
Current code:
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Hearthstone_Test
{
public partial class Main : Form
{
private void timer1_Tick(object sender, EventArgs e)
{
var activatedHandle = GetForegroundWindow();
if (GetForegroundWindow() == Process.GetProcessesByName("Hearthstone"));
{
Console.WriteLine("Not Focused"); // No window is currently activated
}
else
{
Console.WriteLine("Focused");
}
var procId = Process.GetCurrentProcess().Id;
int activeProcId;
GetWindowThreadProcessId(activatedHandle, out activeProcId);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
}
}
Error is at line 11:
Operator '==' cannot be applied to operands of type 'Process[]' and 'IntPtr'
What I'm doing wrong?

This worked for me, slightly different as it returns the active window name:
public string getActiveWindowName()
{
try
{
var activatedHandle = GetForegroundWindow();
Process[] processes = Process.GetProcesses();
foreach (Process clsProcess in processes)
{
if(activatedHandle == clsProcess.MainWindowHandle)
{
string processName = clsProcess.ProcessName;
return processName;
}
}
}
catch { }
return null;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();
the following will give you the actual window header text:
string processName = clsProcess.MainWindowTitle;

You're comparing an IntPtr returned by GetForegroundWindow() to an Process[].
As the name suggests, Process.GetProcessesByName can return multiple processes and as such you'll need to treat it as an array.
Save Process.GetProcessesByName("Hearthstone") into a variable, and iterate over each entry to see if it is the one that's focused.
Also, you assume that the handle is the process ID; which probably isn't the case. The following code is untested.
...
var processes = Process.GetProcessesByName("Hearthstone");
foreach(Process p in processes) {
if(activedHandle == p.Handle) {
//A instance of the process Hearthstone is currently focused.
...
} else {
...
}
}

Related

Windows Task String [duplicate]

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.

Loading/Injecting .Net Assembly into existing .net process?

In my situation i want to load a custom .net assembly into a running .net process's domain, for example Windows Explorer, What i have tried already is just injecting the assembly to explorer.exe but that doesn't seem to work for no obvious reason.
Injector Code:
public class CodeInjector
{
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(uint dwDesiredAccess, int bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, IntPtr dwSize, uint flAllocationType, uint flProtect);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern int WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, byte[] buffer, uint size, int lpNumberOfBytesWritten);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttribute, IntPtr dwStackSize, IntPtr lpStartAddress,
IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
private static CodeInjector _instance;
public static CodeInjector GetInstance
{
get { return _instance ?? (_instance = new CodeInjector()); }
}
public InjectionResult Inject(string sProcName, string sDllPath)
{
if (!File.Exists(sDllPath))
{
return InjectionResult.DllNotFound;
}
var procs = Process.GetProcesses();
var procId = (from t in procs where t.ProcessName == sProcName select (uint)t.Id).FirstOrDefault();
if (procId == 0)
{
return InjectionResult.ProcessNotFound;
}
if (!Inject(procId, sDllPath))
{
return InjectionResult.InjectionFailed;
}
return InjectionResult.InjectionSucceed;
}
private static bool Inject(uint pToBeInjected, string sDllPath)
{
var hndProc = OpenProcess((0x2 | 0x8 | 0x10 | 0x20 | 0x400), 1, pToBeInjected);
if (hndProc == IntPtr.Zero)
{
return false;
}
var lpLlAddress = GetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
if (lpLlAddress == IntPtr.Zero)
{
return false;
}
var lpAddress = VirtualAllocEx(hndProc, (IntPtr)null, (IntPtr)sDllPath.Length, (0x1000 | 0x2000), 0X40);
if (lpAddress == IntPtr.Zero)
{
return false;
}
var bytes = Encoding.ASCII.GetBytes(sDllPath);
if (WriteProcessMemory(hndProc, lpAddress, bytes, (uint)bytes.Length, 0) == 0)
{
return false;
}
if (CreateRemoteThread(hndProc, (IntPtr)null, IntPtr.Zero, lpLlAddress, lpAddress, 0, (IntPtr)null) == IntPtr.Zero)
{
return false;
}
CloseHandle(hndProc);
return true;
}
}
As another option you can use existing library - ManagedInjector - https://github.com/cplotts/snoopwpf/tree/master/ManagedInjector . There is a tool snoopwpf that can show details of any WPF process, and it uses process injection for that. I used it some time ago and it worked well.
You need to build it, add to your project as reference and call like this:
Injector.Launch(someProcess.MainWindowHandle,
typeof(Loader).Assembly.Location,
typeof(Loader).FullName,
"Inject");
Loader is name of type that will be loaded into process and Inject is a static method that will be executed. In my case i had:
public class Loader
{
public static void Inject()
{
// i did CBT Hook on main window here
// and also displayed sample message box for debugging purposes
MessageBox.Show("Hello from another process");
}
}
That ManagedInjector is written in Managed C++ code. Basically it hooks own unmanaged C++ method as MessageHookProc and it will start specified assembly after injection and run specified method. It should work fine for both managed and unmanaged programs. In my case i used it for unmanaged program.
UPDATE
I tested it locally and it successfully injects my message box into explorer process under Windows 8.1 x64. I compiled ManagedInjector64-4.0 and my sample console project also has x64 in platform selection. Here is my working code:
class Program
{
static void Main(string[] args)
{
var proc = Process.GetProcessesByName("explorer").FirstOrDefault();
Injector.Launch(proc.MainWindowHandle, typeof(Loader).Assembly.Location, typeof(Loader).FullName, "Inject");
}
}
public class Loader
{
public static void Inject()
{
MessageBox.Show("Hello");
Task.Run(() =>
{
Thread.Sleep(3000);
MessageBox.Show("Hello again");
Thread.Sleep(5000);
MessageBox.Show("Hello again again");
});
}
}

Set existing service to "Auto (Delayed start)"

I'm trying to set an already installed windows service to automatic delayed start in C#. How do I set a windows service to
Automatic (Delayed Start)
Can't find that value in the ServiceStartMode enum.
Edit:1
public class ServiceAutoStartInfo
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SERVICE_DELAYED_AUTO_START_INFO
{
public bool fDelayedAutostart;
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, IntPtr lpInfo);
// Service configuration parameter
const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
public bool ChangeDelayedAutoStart(IntPtr hService, bool delayed)
{
// Validate service handle
if (hService != IntPtr.Zero)
{
// Create
SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO();
// Set the DelayedAutostart property
info.fDelayedAutostart = delayed;
// Allocate necessary memory
IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(
typeof(SERVICE_DELAYED_AUTO_START_INFO)));
// Convert structure to pointer
Marshal.StructureToPtr(info, hInfo, true);
// Change the configuration
bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo);
// Release memory
Marshal.FreeHGlobal(hInfo);
return result;
}
return false;
}
}
This is how I call it:
var controller = new ServiceController(s.ServiceName);
var autoDelay = new ServiceAutoStartInfo();
autoDelay.ChangeDelayedAutoStart(controller.ServiceHandle.DangerousGetHandle(), true);
But with no result.
Look into calling the Windows ChangeServiceConfig2 function, with dwInfoLevel of SERVICE_CONFIG_DELAYED_AUTO_START_INFO and a SERVICE_DELAYED_AUTO_START_INFO struct with fDelayedAutostart set to TRUE.
Or, you can do this with the command line:
sc.exe config <servicename> start= delayed-auto
I'm using the following, which works for me on Windows 7 (when run as admin):
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.ServiceProcess;
namespace ServiceManager
{
/// <summary>
/// Extensions to the ServiceController class.
/// </summary>
public static class ServiceControlerExtensions
{
/// <summary>
/// Set the start mode for the service.
/// </summary>
/// <param name="serviceController">The service controller.</param>
/// <param name="mode">The desired start mode.</param>
public static void SetStartMode(this ServiceController serviceController, ServiceStartModeEx mode)
{
IntPtr serviceManagerHandle = OpenServiceManagerHandle();
IntPtr serviceHandle = OpenServiceHandle(serviceController, serviceManagerHandle);
try
{
if (mode == ServiceStartModeEx.DelayedAutomatic)
{
ChangeServiceStartType(serviceHandle, ServiceStartModeEx.Automatic);
ChangeDelayedAutoStart(serviceHandle, true);
}
else
{
// Delayed auto-start overrides other settings, so it must be set first.
ChangeDelayedAutoStart(serviceHandle, false);
ChangeServiceStartType(serviceHandle, mode);
}
}
finally
{
if (serviceHandle != IntPtr.Zero)
{
CloseServiceHandle(serviceHandle);
}
if (serviceHandle != IntPtr.Zero)
{
CloseServiceHandle(serviceManagerHandle);
}
}
}
private static IntPtr OpenServiceHandle(ServiceController serviceController, IntPtr serviceManagerHandle)
{
var serviceHandle = OpenService(
serviceManagerHandle,
serviceController.ServiceName,
SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
if (serviceHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Error");
}
return serviceHandle;
}
private static IntPtr OpenServiceManagerHandle()
{
IntPtr serviceManagerHandle = OpenSCManager(null, null, SC_MANAGER_ALL_ACCESS);
if (serviceManagerHandle == IntPtr.Zero)
{
throw new ExternalException("Open Service Manager Error");
}
return serviceManagerHandle;
}
private static void ChangeServiceStartType(IntPtr serviceHandle, ServiceStartModeEx mode)
{
bool result = ChangeServiceConfig(
serviceHandle,
SERVICE_NO_CHANGE,
(uint)mode,
SERVICE_NO_CHANGE,
null,
null,
IntPtr.Zero,
null,
null,
null,
null);
if (result == false)
{
ThrowLastWin32Error("Could not change service start type");
}
}
private static void ChangeDelayedAutoStart(IntPtr hService, bool delayed)
{
// Create structure that contains DelayedAutoStart property.
SERVICE_DELAYED_AUTO_START_INFO info = new SERVICE_DELAYED_AUTO_START_INFO();
// Set the DelayedAutostart property in that structure.
info.fDelayedAutostart = delayed;
// Allocate necessary memory.
IntPtr hInfo = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(SERVICE_DELAYED_AUTO_START_INFO)));
// Convert structure to pointer.
Marshal.StructureToPtr(info, hInfo, true);
// Change the configuration.
bool result = ChangeServiceConfig2(hService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, hInfo);
// Release memory.
Marshal.FreeHGlobal(hInfo);
if (result == false)
{
ThrowLastWin32Error("Could not set service to delayed automatic");
}
}
private static void ThrowLastWin32Error(string messagePrefix)
{
int nError = Marshal.GetLastWin32Error();
var win32Exception = new Win32Exception(nError);
string message = string.Format("{0}: {1}", messagePrefix, win32Exception.Message);
throw new ExternalException(message);
}
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern IntPtr OpenService(
IntPtr hSCManager,
string lpServiceName,
uint dwDesiredAccess);
[DllImport("advapi32.dll", EntryPoint = "OpenSCManagerW", ExactSpelling = true, CharSet = CharSet.Unicode,
SetLastError = true)]
private static extern IntPtr OpenSCManager(
string machineName,
string databaseName,
uint dwAccess);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern Boolean ChangeServiceConfig(
IntPtr hService,
UInt32 nServiceType,
UInt32 nStartType,
UInt32 nErrorControl,
String lpBinaryPathName,
String lpLoadOrderGroup,
IntPtr lpdwTagId,
[In] char[] lpDependencies,
String lpServiceStartName,
String lpPassword,
String lpDisplayName);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ChangeServiceConfig2(
IntPtr hService,
int dwInfoLevel,
IntPtr lpInfo);
[DllImport("advapi32.dll", EntryPoint = "CloseServiceHandle")]
private static extern int CloseServiceHandle(IntPtr hSCObject);
private const uint SERVICE_NO_CHANGE = 0xFFFFFFFF;
private const uint SERVICE_QUERY_CONFIG = 0x00000001;
private const uint SERVICE_CHANGE_CONFIG = 0x00000002;
private const uint SC_MANAGER_ALL_ACCESS = 0x000F003F;
private const int SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct SERVICE_DELAYED_AUTO_START_INFO
{
public bool fDelayedAutostart;
}
}
}
namespace ServiceManager
{
public enum ServiceStartModeEx
{
Automatic = 2,
Manual = 3,
Disabled = 4,
DelayedAutomatic = 99
}
}
You call it like this:
var serviceController = new ServiceController("Windows Update");
try
{
serviceController.SetStartMode(ServiceStartModeEx.DelayedAutomatic);
}
finally
{
serviceController.Close();
}
Update: This only works for setting up new services and is not what the OP asked for:
You can use the DelayedAutoStart property of the ServiceInstaller.
installer.DelayedAutoStart = true;
I believe you need to combine both methods ChangeServiceConfig and ChangeServiceConfig2.
pseudo-code follows:
public static void ChangeServiceStartupType(ServiceStartupType type, ...)
{
if (type == AutomaticDelayed)
{
if (ChangeServiceConfig2(.., DelayedAutoStart, ..))
{
ChangeServiceConfig(.., Automatic, ..);
}
}
else
{
ChangeServiceConfig2(.., !DelayedAutoStart, ..)
ChangeServiceConfig(.., type, ..)
}
}
edit: you also need to remove "delayed-automatic" when requesting non-delayed startup-type. Otherwise it won't be possible to set "automatic" type. ("automatic-delayed" overrides "automatic")
SERVICE_DELAYED_AUTO_START_INFO structure documentation states:
fDelayedAutostart
If this member is TRUE, the service is started after other auto-start
services are started plus a short delay. Otherwise, the service is
started during system boot.
This setting is ignored unless the service is an auto-start service.
https://learn.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_delayed_auto_start_info?redirectedfrom=MSDN#members
So I think if the service is not auto-start it won't change it to auto delayed, you would have to use sc.exe

Get a windows title by it's process name without main window

I have a problem I'm trying to get a window's title by it's process name and I can't do it here s what I tried :
Process[] p = Process.GetProcessesByName("Acrobat");
Console.WriteLine(p[0].MainWindowTitle);
Console.ReadLine();
But the problem is that I can only get it only if the associated process does have a main window. How can I make it working ?
The main goal is that I've a method named BringToFront()
But this method ask for a caption name which is "thenameofthePDF.pdf - Adobe Acrobat Pro (Yes, acrobat is running with an opened pdf)
I would like to bring to front my Acrobat window..
but for this I need the name of the windows as my method is asking for the caption.
Here is the entire code at the moment:
class Program
{
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(int hWnd);
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
private static void BringToFront(string className, string CaptionName)
{
SetForegroundWindow(FindWindow(className, CaptionName));
}
static void Main(string[] args)
{
// BringToFront("Acrobat", "mypdf.pdf - Adobe Acrobate Pro");
Process[] p = Process.GetProcesses();
foreach (var process in p)
{
Console.WriteLine(process.MainWindowTitle);
}
Console.ReadLine();
}
}
Did you read the manual, does the following apply?
A process has a main window associated with it only if the process has a graphical interface. If the associated process does not have a main window (so that MainWindowHandle is zero), MainWindowTitle is an empty string (""). If you have just started a process and want to use its main window title, consider using the WaitForInputIdle method to allow the process to finish starting, ensuring that the main window handle has been created. Otherwise, the system throws an exception.
One possible solution is to enumerate all top-level windows and pick the one you are interested in. In your case this would be all windows with a class of AcrobatSDIWindow and a window title starting with your document name.
class Program
{
public class SearchData
{
public string ClassName { get; set; }
public string Title { get; set; }
private readonly List<IntPtr> _result = new List<IntPtr>();
public List<IntPtr> Result
{
get { return _result; }
}
}
[DllImport("User32.dll")]
public static extern Int32 SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, ref SearchData data);
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public static bool EnumProc(IntPtr hWnd, ref SearchData searchData)
{
var sbClassName = new StringBuilder(1024);
GetClassName(hWnd, sbClassName, sbClassName.Capacity);
if (searchData.ClassName == null || Regex.IsMatch(sbClassName.ToString(), searchData.ClassName))
{
var sbWindowText = new StringBuilder(1024);
GetWindowText(hWnd, sbWindowText, sbWindowText.Capacity);
if (searchData.Title == null || Regex.IsMatch(sbWindowText.ToString(), searchData.Title))
{
searchData.Result.Add(hWnd);
}
}
return true;
}
static void Main(string[] args)
{
var searchData = new SearchData
{
ClassName = "AcrobatSDIWindow",
Title = "^My Document\\.pdf.*"
};
EnumWindows(EnumProc, ref searchData);
var firstResult = searchData.Result.FirstOrDefault();
if (firstResult != IntPtr.Zero)
{
SetForegroundWindow(firstResult);
}
}
}
If you dump them all out using GetProcesses() it appears that the window title will have 'Adobe Reader', prefixed by the name of the PDF if one is open. So you might need to do that and walk the array instead.
For example if I have UserManual.pdf open and I run the code below it displays UserManual.pdf - Adobe Reader on the console:
Process[] p = Process.GetProcesses();
String Title = String.Empty;
for (var i = 0; i < p.Length; i++)
{
Title = p[i].MainWindowTitle;
if (Title.Contains(#"Adobe"))
Console.WriteLine(Title);
}

Get window state of another process

How do I get the window state(maximized, minimized) of another process that's running?
I'd tried by using this:
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.ProcessName == "notepad")
{
MessageBox.Show(proc.StartInfo.WindowStyle.ToString());
}
}
But if process is Maximized or Minimized,it ever returns Normal.
How to fix this?
You’ll need to use Win32 through P/Invoke for checking the state of another window. Here is some sample code:
static void Main(string[] args)
{
Process[] procs = Process.GetProcesses();
foreach (Process proc in procs)
{
if (proc.ProcessName == "notepad")
{
var placement = GetPlacement(proc.MainWindowHandle);
MessageBox.Show(placement.showCmd.ToString());
}
}
}
private static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
{
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hwnd, ref placement);
return placement;
}
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetWindowPlacement(
IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
[Serializable]
[StructLayout(LayoutKind.Sequential)]
internal struct WINDOWPLACEMENT
{
public int length;
public int flags;
public ShowWindowCommands showCmd;
public System.Drawing.Point ptMinPosition;
public System.Drawing.Point ptMaxPosition;
public System.Drawing.Rectangle rcNormalPosition;
}
internal enum ShowWindowCommands : int
{
Hide = 0,
Normal = 1,
Minimized = 2,
Maximized = 3,
}
Definition courtesy of pinvoke.net.
You're using proc.StartInfo, which is incorrect. It does not reflect the runtime window style of the target process. It is just startup info you can set and can then be passed on to the process when it starts up.
The C# signature is:
[DllImport("user32.dll", SetLastError=true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
You need to use p/invoke and call GetWindowLong(hWnd, GWL_STYLE), and pass proc.MainWindowHandle as the hWnd parameter.
You can check if the window is minimized/maximized by doing something like:
int style = GetWindowLong(proc.MainWindowHandle, GWL_STYLE);
if((style & WS_MAXIMIZE) == WS_MAXIMIZE)
{
//It's maximized
}
else if((style & WS_MINIMIZE) == WS_MINIMIZE)
{
//It's minimized
}
NOTE: The values for the flags (WS_MINIMIZE, etc), can be found in this page: http://www.pinvoke.net/default.aspx/user32.getwindowlong
Thanks to Kakashi for pointing our the error in testing the result.
In Windows PowerShell you can do this by following code:
Add-Type -AssemblyName UIAutomationClient
$prList = Get-Process -Name "<ProcessNamesWhichHaveWindow>"
$prList | % {
try {
$ae = [System.Windows.Automation.AutomationElement]::FromHandle($_.MainWindowHandle)
$wp = $ae.GetCurrentPattern([System.Windows.Automation.WindowPatternIdentifiers]::Pattern)
echo "Window title: $($_.MainWindowTitle)"
echo "Window visual state: $($wp.Current.WindowVisualState)"
}
catch { }
}
Two Window States (maximized / minimized) can be gotten by calling WinAPI IsIconic() / IsZoomed() like this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, ShowWindowCommands cmdShow);
if (IsIconic(_helpWindow.MainWindowHandle)) {
ShowWindowAsync(_helpWindow.MainWindowHandle, ShowWindowCommands.SW_RESTORE);
}
Definition of enum ShowWindowCommands and other functions were taken from www.PInvoke.net

Categories

Resources