I'm making a c# overlay for a game.
It appears on the game but it won't hide if the game is minimized so I'm wondering if there's any way to check if a window is minimized/out of focus. I searched about it on google but I couldn't find anything useful.
To check the state of a window (normal, maximized or minimized) when you have the windows caption name or the windows handle, you can use this code:
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool IsZoomed(IntPtr hWnd);
enum WinState
{
None,
Maximized,
Minimized,
Normal,
}
private static WinState GetWindowState(IntPtr hWnd)
{
WinState winState = WinState.None;
if (hWnd != IntPtr.Zero)
{
if (IsIconic(hWnd))
{
winState = WinState.Minimized;
}
else if (IsZoomed(hWnd))
{
winState = WinState.Maximized;
}
else
{
winState = WinState.Normal;
}
}
return winState;
}
private static WinState GetWindowState(string windowCaption)
{
return GetWindowState((IntPtr)FindWindow(null, windowCaption));
}
Usage:
string windowCaption = "New Tab - Google Chrome";
WinState winState = GetWindowState(windowCaption);
Related
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.
When I have an application opened and I try to open again it, i want to restore the application launched with the actual size.
The code used is this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern int ShowWindow(IntPtr hwnd, int nCmdShow);
private const int SW_SHOW = 5;
public static void SetForegroundMyWindow(IntPtr windowHandle)
{
SetForegroundWindow(windowHandle);
ShowWindow(windowHandle, SW_SHOW);
}
With this code, when the window is maximized, the application is shown with the size without maximize.
Only with SetForegroundWindow, the application is not shown when it is minimized.
What is the way to get my window with the actual size?
I'm new to WindowsForms building a small sample application.
I'm trying to build an application that types text into a Notepad window and I'm getting the error FindWindow does not exist in current context when it's being imported from the dll.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void MenuAbout_Click(object sender, System.EventArgs e)
{
Form1 frm = new Form1();
frm.ShowDialog();
}
private void Launch_Click(object sender, System.EventArgs e)
{
// find window handle of Notepad
IntPtr handle = FindWindow("Notepad", "Untitled - Notepad");
if (!handle.Equals(IntPtr.Zero))
{
// activate Notepad window
if (SetForegroundWindow(handle))
{
// send "Hello World!"
SendKeys.Send("Hello World!");
// send key "Tab"
SendKeys.Send("{TAB}");
// send key "Enter"
SendKeys.Send("{ENTER}");
}
}
//Process.Start(#"D:\\32-Bit Programs\\StarCraft II\\Support\\SC2Switcher.exe");
}
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private extern IntPtr FindWindow(string lp1, string lp2);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private extern bool SetForegroundWindow(IntPtr hWnd);
}
}
Your imported methods must also be static:
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string lp1, string lp2);
[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
How can I prevent WPF window from minimizing when users clicks on show desktop button?
This link will help you : Get the minimize box click of a WPF window
you need to catch the event and handle it yourself.
Edit : This method will alert you once the state is changed, so it might not be the "best" solution but it could work.
Windows are not minimized when "Show Desktop" is issued. Instead the "WorkerW" and "Desktop" windows are brought to the foreground.
I ended up developing my own solution.
I scoured the internet for weeks trying to find an answer so I'm kind of proud of this one.
So what we do is use pinvoke to create a hook for the EVENT_SYSTEM_FOREGROUND window event.
This event triggers whenever the foreground window is changed.
Now what I noticed is when the "Show Desktop" command is issued, the WorkerW window class becomes foreground.
Note this WorkerW window is not the desktop and I confirmed the hwnd of this WorkerW window is not the Desktop hwnd.
So what we do is whenever the WorkerW window becomes the foreground, we set our "WPF Gadget Window" to be topmost!
Whenever a window other the WorkerW window becomes the foreground, we remove topmost from our "WPF Gadget Window".
If you want to take it a step further, you can uncomment out the part where I check if the new foreground window is also "PROGMAN", which is the Desktop window.
However, this will lead to your window becoming topmost if the user clicks their desktop on a different monitor. In my case, I did not want this behavior, but I figured some of you might.
Confirmed to work in Windows 10. Should work in older versions of Windows.
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
namespace YourNamespace
{
internal static class NativeMethods
{
[DllImport("user32.dll")]
internal static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, ShowDesktop.WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
internal static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
internal static extern int GetClassName(IntPtr hwnd, StringBuilder name, int count);
}
public static class ShowDesktop
{
private const uint WINEVENT_OUTOFCONTEXT = 0u;
private const uint EVENT_SYSTEM_FOREGROUND = 3u;
private const string WORKERW = "WorkerW";
private const string PROGMAN = "Progman";
public static void AddHook(Window window)
{
if (IsHooked)
{
return;
}
IsHooked = true;
_delegate = new WinEventDelegate(WinEventHook);
_hookIntPtr = NativeMethods.SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, _delegate, 0, 0, WINEVENT_OUTOFCONTEXT);
_window = window;
}
public static void RemoveHook()
{
if (!IsHooked)
{
return;
}
IsHooked = false;
NativeMethods.UnhookWinEvent(_hookIntPtr.Value);
_delegate = null;
_hookIntPtr = null;
_window = null;
}
private static string GetWindowClass(IntPtr hwnd)
{
StringBuilder _sb = new StringBuilder(32);
NativeMethods.GetClassName(hwnd, _sb, _sb.Capacity);
return _sb.ToString();
}
internal delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
private static void WinEventHook(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
if (eventType == EVENT_SYSTEM_FOREGROUND)
{
string _class = GetWindowClass(hwnd);
if (string.Equals(_class, WORKERW, StringComparison.Ordinal) /*|| string.Equals(_class, PROGMAN, StringComparison.Ordinal)*/ )
{
_window.Topmost = true;
}
else
{
_window.Topmost = false;
}
}
}
public static bool IsHooked { get; private set; } = false;
private static IntPtr? _hookIntPtr { get; set; }
private static WinEventDelegate _delegate { get; set; }
private static Window _window { get; set; }
}
}
You can change your window's parent to not be affected by Show Desktop. (as stated here: Window "on desktop")
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindowLoaded;
}
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private void MainWindowLoaded(object sender, RoutedEventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
var ProgmanHwnd = FindWindowEx(FindWindowEx(FindWindow("Progman", "Program Manager"), IntPtr.Zero, "SHELLDLL_DefView",""), IntPtr.Zero,"SysListView32", "FolderView");
SetParent(hwnd, ProgmanHwnd);
}
}
How can I bring a console application window to front in C# (especially when running the Visual Studio debugger)?
It's hacky, it's horrible, but it works for me (thanks, pinvoke.net!):
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
public class Test
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", EntryPoint="FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr zeroOnly, string lpWindowName);
public static void Main()
{
string originalTitle = Console.Title;
string uniqueTitle = Guid.NewGuid().ToString();
Console.Title = uniqueTitle;
Thread.Sleep(50);
IntPtr handle = FindWindowByCaption(IntPtr.Zero, uniqueTitle);
if (handle == IntPtr.Zero)
{
Console.WriteLine("Oops, cant find main window.");
return;
}
Console.Title = originalTitle;
while (true)
{
Thread.Sleep(3000);
Console.WriteLine(SetForegroundWindow(handle));
}
}
}
This is what I would do.
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public void BringConsoleToFront()
{
SetForegroundWindow(GetConsoleWindow());
}
Get two monitors (at least) and open VisualStudio in the secondary monitor. When you run your app from within VisualStudio it will start up by default on the primary monitor. Since it's the last app to be opened, it starts on top and changing over to VisualStudio doesn't affect it. Works for me anyway.
If you don't already have a second monitor, IMHO, you should.