Get window state of another process - c#

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

Related

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");
});
}
}

C# Get a Pointer by using a Thread ID

EDIT3:
I need a list from all windows a thread has. Not FindWindowsEnum() because it only returns Top level Windows.... I need the window handle befor it's visible
END EDIT3
EDIT2:
Short desciption: I need a method, where i can get a "window handle" from a thread.
END EDIT2:
EDIT:
First of all i can't use FindWindowsEnum()!!!
Because it only returns the top windows. I have to kill the window befor it is visible. So i have to get The Handle of the window by a Thread ID.
EDIT END:
I got a problem by a window which i have to close which is not focused or something like that. I have to close the window as it pops up. I only use code.
What i got:
This is the extern class where I import one dll and some functions which use the functions from the dll.
class FindWindowApi
{
//[DllImport("user32.dll", SetLastError = true)]
//public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
public IntPtr[] GetWindowHandlesForThread(int threadHandle)
{
_results.Clear();
EnumWindows(WindowEnum, threadHandle);
return _results.ToArray();
}
public delegate int EnumWindowsProc(IntPtr hwnd, int lParam);
[DllImport("user32.Dll")]
public static extern int EnumWindows(EnumWindowsProc x, int y);
public List<IntPtr> _results = new List<IntPtr>();
public int WindowEnum(IntPtr hWnd, int lParam)
{
_results.Add(hWnd);
return 1;
}
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
public static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowText(
IntPtr handle,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder caption,
int count);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int GetWindowTextLength(IntPtr handle);
public const UInt32 WM_CLOSE = 0x0010;
}
at this class i use the functions from the extern class.
I start a Thread which runs every 10 milli secounds and kill a window in another method.
public Disk_UC()
{
InitializeComponent();
Thread killit = new Thread(this.killIt);
killit.Start();
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox2.DropDownStyle = ComboBoxStyle.DropDownList;
Thread nt = new Thread(this.fillData);
nt.Start();
}
//Thread Method
private void killIt()
{
bool blac = false;
Int32 oldThreadID = threadID;
FindWindowApi api = new FindWindowApi();
while ((!blac)
&& (!MainDiag.isGoingDown))
{
if (oldThreadID != threadID)
{
IntPtr[] windows = api.GetWindowHandlesForThread(threadID);
if (windows != null && windows.Length > 0)
foreach (IntPtr hWnd in windows)
{
killWindow(hWnd, threadID);
}
}
Thread.Sleep(10);
}
}
//Method which calls all the extern dll stuff
private bool killWindow(IntPtr handle, int param)
{
var length = FindWindowApi.GetWindowTextLength(handle);
var caption = new StringBuilder(length + 1);
FindWindowApi.GetWindowText(handle, caption, caption.Capacity);
IntPtr windowPtr = FindWindowApi.FindWindowByCaption(IntPtr.Zero, caption.ToString());
if (windowPtr == IntPtr.Zero)
{
return false;
}
FindWindowApi.SendMessage(windowPtr, FindWindowApi.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
return true;
}
My Problem is now how can i get this specific window handle.
when the Thread "fillData" pops up the window. So i save the thread ID from this Thread fillData.
Now i call the other Methods with this thread id. I got the Thread ID and i get so many windows from the Process. But i need this specific window from that thread.

How do I detect if software keyboard is visible

Is there a way in Windows 8 to detect if the virtual keyboard is visible on screen? I use tabtip.exe
After a brief search on google , I could do something that might help you. The code below exposes a function of the windows API and uses it to know the current state of a given process. Understand state as Minimized , Maximized, Hidden or Normal.
The ProccesIsRunningNotMinimized method returns true if the program is running and is not minimized or hidden.
I do not know if this will help you, but it's a start .
public bool ProccesIsRunningNotMinimized(string exeName)
{
Process[] processes = Process.GetProcesses();
foreach (Process p in processes)
{
if (p.ProcessName.ToLower() == exeName.ToLower())
{
var placement = GetPlacement(p.MainWindowHandle);
if (placement.showCmd.ToString().ToLower() != "minimized" && placement.showCmd.ToString().ToLower() != "hide")
return true;
}
}
return false;
}
// Get the placement of the target process
private static WINDOWPLACEMENT GetPlacement(IntPtr hwnd)
{
WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
placement.length = Marshal.SizeOf(placement);
GetWindowPlacement(hwnd, ref placement);
return placement;
}
//Exposes the function of Windows API
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetWindowPlacement(
IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
//Create a struct to receive the data
[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,
}
To check if the VK is running and visible in the screen, do:
if (this.ProccesIsRunningNotMinimized("tabtip"))
{
// do something
}
This code works fine on Windows 7. On windows 8 will not work.

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);
}

How to measure system idle time in C#, excluding when watching movies, etc?

I am looking for a program that measures system idle time on Windows. I have found many codes that do this. For example,
http://www.codeproject.com/KB/cs/GetIdleTimeWithCS.aspx
However, I also want to take into account user watching movies, videos, etc. That time no input is given, but still the system is not idle.
Is there anyway to do this?
This function detects if a process is running in fullscreen in forground, and returns name of the process if found so:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[DllImport("user32.dll")]
private static extern Int32 GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool
GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
private struct POINTAPI
{
public int x;
public int y;
}
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
private struct WINDOWPLACEMENT
{
public int length;
public int flags;
public int showCmd;
public POINTAPI ptMinPosition;
public POINTAPI ptMaxPosition;
public RECT rcNormalPosition;
}
public string FullscreenProcess()
{
IntPtr foreWindow = GetForegroundWindow();
// get the placement
WINDOWPLACEMENT forePlacement = new WINDOWPLACEMENT();
forePlacement.length = Marshal.SizeOf(forePlacement);
GetWindowPlacement(foreWindow, ref forePlacement);
if (forePlacement.rcNormalPosition.top == 0 && forePlacement.rcNormalPosition.left == 0 && forePlacement.rcNormalPosition.right == Screen.PrimaryScreen.Bounds.Width && forePlacement.rcNormalPosition.bottom == Screen.PrimaryScreen.Bounds.Height)
{
uint processID;
GetWindowThreadProcessId(foreWindow, out processID);
Process proc = Process.GetProcessById((int)processID);
return proc.ProcessName;
}
return null;
}
After this, we just need to match the returned process name with a set of popular media players or other processes.
Limitation is that we have assumed user plays in fullscreen.
You can get the idle time for computer using this, however your problem is how to know weather a movie is playing, you can check the processes that is currently running on the computer System.Diagnostics.Process.GetProcesses(), and then check if one of them is a known movie player. However I don't think this will achieve what you locking for either, because even if you find out that for example a Gom player is running, you still don't know if it running a video or audio or just opened without any thing actually playing...
In case you watch videos in fullscreen:
You could use code like this do determine if there is an app running in fullscreen:
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
struct RECT
{
public int Left;
public int Top;
public int Width;
public int Height;
}
static bool IsBigWindowRunning()
{
foreach (Process proc in Process.GetProcesses())
{
RECT rect;
var success = GetWindowRect(proc.MainWindowHandle, out rect);
if(success && (r.Left + r.Width) >= Screen.PrimaryScreen.WorkingArea.Width)
{
return true;
}
}
return false;
}
I haven't tested it well and i would definetely play around with this line, add some limits:
if((r.Left + r.Width) >= Screen.PrimaryScreen.WorkingArea.Width)
Good luck!

Categories

Resources