c# Giving focus back to parent form from other app - c#

I'm trying to start and .exe from a child form of my main app, but the issue is that when I open the other .exe and it finish it's work (scan a finger print) and exit, my app gets minimized, so I try this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
void method {
..........more code...........
using (Process proc = new Process())
{
proc.StartInfo.FileName = "WindowsFormsApplication3.exe";
proc.Start();
SetForegroundWindow(proc.MainWindowHandle);
}
............code here..............
}
but it doesnt work, my main app lost the focus, I find many solutions but any of them work for me, the other .exe is an app that I'm doing too.

If you want to active finger print window, your code is right! but add a waiting before SetForegroundWindow... like this:
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
System.Threading.Thread.Sleep(100);
proc.Refresh();
}
and, If you want to active the caller form (main app) you don't need SetForegroundWindow! You can write:
while (string.IsNullOrEmpty(proc.MainWindowTitle))
{
System.Threading.Thread.Sleep(100);
proc.Refresh();
}
// Then active caller form...
this.Activate();
Anyway, you need wait until finger-print window shown...

Related

FindWindow in C#(via pinvoke) finds desired window handle, but not in the desired conditions. How do I fix it?

I'm trying to get certain window handle. I was searching for solution for many hours and I understand that my question sounds similar to this one:
FindWindow() doesn't find my window [C++]
But that discussion didn't help.
I was trying to use both FindWindow() and FindWindowEx() like these two:
IntPtr SysPropWndHandler = FindWindow("#32770", "Параметри продуктивності");
IntPtr SysPropWndHandler = FindWindowEx(IntPtr.Zero, IntPtr.Zero, "#32770", "Параметри продуктивності");
Weird part is that when I run the program, it starts new process for certain system settings program from system32 folder and it can't find it's handle during same launch time (if that's correct to say so). I tried to pause it to give it time to create window and assign handle, but that doesn't help.
But! If that system program is launched first and then I run my program - it finds it's handle right away.
Two ways for that "external launch":
I run system program manually before launching my program
I run my program, which launches that system program, then I close my program, system program doesn't close then. After that I run my program again.
But what I'm actually trying to make my program do is this:
launch system program (some productivity settings)
hide window
change some settings via WinApi (kind of checkbox clicking emulation)
click ok
close it
Since my code works, at least in some conditions, looks like it has nothing to do with encoding, which was mansioned in that similar question. Otherwise it wouldn't work at all.
I was trying to launch it hidden, but it didn't work. I tried the same code for notepad for debugging it - it works.
string prog_path = #"C:\Windows\System32\SystemPropertiesPerformance.exe";
Process process = new Process();
process.StartInfo.FileName = prog_path;
process.StartInfo.CreateNoWindow = true; // no need for that, but I tried with it and without it just in case it works
process.StartInfo.UseShellExecute = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Start();
According to Microsoft documentation you need to set UseShellExecute to true in order to use StartInfo.WindowStyle = ProcessWindowStyle.Hidden (which I did), but program still can choose to ignore that. Looks like that's exactly what's happening there.
But I tried to get exect window handle via Spy++ and try to hide it - it works, so I can manipulate it from there and do my thing. The only problem is to find it's handle...
How do I find that handle in this case?
P.S.
Windows 10 x64 Pro Ukrainian (for other languages that window title in the code won't work)
.NET Framework 4.7.2
Code is inside .NET Framework Class Library, which is launched from C# Console Application.
For me this one works fine(on Windows 7):
using System;
using System.Diagnostics;
using System.Text;
using System.Runtime.InteropServices;
namespace findwindow
{
class Program
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
public static void Main(string[] args)
{
Process.Start(new ProcessStartInfo(){FileName=#"C:\Windows\System32\SystemPropertiesPerformance.exe"});
System.Threading.Thread.Sleep(100);
IntPtr hwnd = FindWindow("#32770", "Параметры быстродействия");
var sb = new StringBuilder(50);
GetWindowText(hwnd, sb, 49);
Console.WriteLine("hwnd:"+hwnd+", title:"+sb);
Console.ReadKey(true);
}
}
}
Outputs:
hwnd:5636204, title:Параметры быстродействия
Try with that code your title, and say if it works.
Also there is a different approach like in this answer.
Another approach is to use the UI Automation technology that's built in Windows. For example, this sample Console app should work. And because it's event-based, it does not need to use timers which can be context-dependent:
public static void Main(string[] args)
{
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, AutomationElement.RootElement, TreeScope.Children, (sender, e) =>
{
var element = sender as AutomationElement;
if (element.Current.Name == "Параметры быстродействия")
{
Console.WriteLine("hwnd:" + element.Current.NativeWindowHandle);
}
});
Process.Start("SystemPropertiesPerformance.exe");
Console.ReadLine(); // wait ...
Automation.RemoveAllEventHandlers(); // cleanup
}
It works fine on my Windows 10 x64 machine. If this doesn't work, make sure your program and SystemPropertiesPerformance.exe run at the same UAC level.

FreeConsole to detach from cmd.exe box with Console Application

I want to change a WinForms application that way, so it will run without UI with console output if it is called with a command line argument. Therefore I changed the application type to "Console Application" and wrote something like:
my code snippet:
....
[DllImport("kernel32.dll")]
static extern bool FreeConsole();
[STAThread]
static void Main(string[] args)
{
if (args.Length == 0)
{
FreeConsole();
Application.Run(new MyForm());
}
else
Console.WriteLine("Console party");
.....
In debug mode in VS I can see the DOS box popping up and hiding. If I do so via console, the command line keeps attached to the process and is not responding until I've closed the MyForm window. Calling the application with an argument, brings the "Console party" up.
The return value of FreeConsole is true and GetLastError is not telling any error code.
Does anybody knows how to detach the process from the cmd.exe process?
Brainstorming with a colleague brings me to try another way. I've set the application type back to Windows Application and did the following:
...
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int input);
static void Main(string[] args)
{
if (args.Length == 0)
{
Application.Run(new MyForm());
}
else if (args.Length == 1)
{
AttachConsole(-1);
Console.WriteLine("Console party");
...
What happens now is, if I run it from cmd.exe box, the application takes the console(stdin,stdou,stderr) from the parent process and writes to it. When using it without arguments, the console window will not pop up.
I am thinking about, what is better way. Having the parent process dealing with the stdin,stdout and stderr handles or let the application hijack it from its parent!?

Hide multiple windows by Process

I have a process and I would like to hide the window.
It work great if the process have only one window.
But if there is a prompt dialog or an alert dialog or another sub window, the hide method hide only the main window, not the dialog...
Can you help me to hide all windows of a process please ?
Many Thanks
This is my code :
[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);
public void Show()
{
ShowWindow(_processHwnd, SwShow);
}
public void Hide()
{
Process[] processRunning = Process.GetProcesses();
foreach (Process pr in processRunning)
{
if (pr.Id == _process.Id)
{
_processHwnd = pr.MainWindowHandle;
}
}
ShowWindow(_processHwnd, SwHide);
}
You need to use a bit more of the Win32 API through P/invoke to obtain the window handles for the other top-level windows.
Call GetWindowThreadProcessId() to get the thread ID of the main window.
Call EnumThreadWindows() to enumerate all the top-level windows of that thread.
It is possible that there are windows associated with a different thread in the process but the probabilities of that are vanishingly small.

Hiding the Process Monitor application window

I am creating a scheduled task to run process monitor at its highest privileges. I have a windows service that executes the scheduled task on start. Thus on start of my service, process monitor.exe will be executed shown in a window. But I don't want to see the window. I just want the process monitor.exe to run in the background without displaying any windows.
In AutoIT, there is a command: Run (Procmon.exe,"",#SW_Hide) #SW_Hide = Hidden Window
I tried this:
foreach (Process pr in Process.GetProcesses())
{
if(pr.ProcessName == "procmon")
{
hWnd = pr.MainWindowHandle.ToInt32();
ShowWindow(hWnd, SW_HIDE);
}
}
It's better to tell the process to show no window in the first place, instead of hiding it afterwards.
When running a program from .net you usually already have a ProcessStartInfo. Then just set its WindowStyle property to ProcessWindowStyle.Hidden and that should take care of it.
I haven't tried this myself, but that's the way you usually do it when calling the WinApi functions directly.
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.windowstyle.aspx
http://msdn.microsoft.com/en-us/library/system.diagnostics.processwindowstyle.aspx
You need to get Window Handle of Process Monitor first and then you need to call ShowWindow with SW_HIDE to hide it.
You can use FindWindow to get the Window Handle of the ProcMon window.
Edit:
After looking at your code, I tried at my end and it works with the following code:
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
public static void HideWindow()
{
int SW_HIDE = 0;
foreach (Process pr in Process.GetProcesses())
{
if (pr.ProcessName.Contains("Procmon"))
{
//Int32 hWnd = pr.MainWindowHandle.ToInt32();
ShowWindow(pr.MainWindowHandle, SW_HIDE);
}
}
}
static void Main(string[] args)
{
HideWindow();
}
Most likely, the problem with your code is that you are trying to find an exact match of the process name which isn't there.
Procmon has built-in functionality to automatically log at startup, if that's what you're trying to accomplish.

How to hide a console application in C#

I have a console application in C#, and I want that the user won't be able to see it.
How can I do that?
Compile it as a Windows Forms application. Then it won't display any UI, if you do not explicitly open any Windows.
On ProjectProperties set Output Type as Windows Application.
Sounds like you don't want a console application, but a windows GUI application that doesn't open a (visible) window.
Create a console application "MyAppProxy" with following code, and put MyAppProxy in start up dir,
public static void main(string[] args)
{
Process p = new Process("MyApp");
ProcessStartUpInfo pinfo = new ProcessStartUpInfo();
p.StartupInfo = pinfo;
pinfo.CreateNoWindow = true;
pinfo.ShellExecute = false;
p.RaiseEvents = true;
AutoResetEvent wait = new AutoResetEvent(false);
p.ProcessExit += (s,e)=>{ wait.Set(); };
p.Start();
wait.WaitOne();
}
You may need to fix certain items here as I didnt check correctness of the code, it may not compile because some property names may be different, but hope you get the idea.
The best way is to start the process without window.
Process p = new Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "echo Hello!";
//either..
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
//or..
p.StartInfo.CreateNoWindow = true;
p.Start();
See other probable solutions -
Toggle Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden at runtime
and,
Bring another processes Window to foreground when it has ShowInTaskbar = false
To hide a console applicatin in C# when nothing else works use this code:
[DllImport("kernel32.dll")]
public static extern bool FreeConsole();
Place FreeConsole() anywhere in the code, I placed it in the Init(), and the commandline is hidden.
You can Pinvoke a call to FindWindow() to get a handle to your window and then call ShowWindow() to hide the window
OR
Start your application from another one using ProcessStartInfo.CreateNoWindow
I've got a general solution to share:
using System;
using System.Runtime.InteropServices;
namespace WhateverNamepaceYouAreUsing
{
class Magician
{
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int HIDE = 0;
const int SHOW = 5;
public static void DisappearConsole()
{
ShowWindow(GetConsoleWindow(), HIDE);
}
}
}
Just include this class in your project, and call Magician.DisappearConsole();.
A console will flash when you start the program by clicking on it. When executing from the command prompt, the command prompt disappears very shortly after execution.
I do this for a Discord Bot that runs forever in the background of my computer as an invisible process. It was easier than getting TopShelf to work for me. A couple TopShelf tutorials failed me before I wrote this with some help from code I found elsewhere. ;P
I also tried simply changing the settings in Visual Studio > Project > Properties > Application to launch as a Windows Application instead of a Console Application, and something about my project prevented this from hiding my console - perhaps because DSharpPlus demands to launch a console on startup. I don't know. Whatever the reason, this class allows me to easily kill the console after it pops up.
Hope this Magician helps somebody. ;)
Create a wcf service and host it as per your need.

Categories

Resources