How to hide a console application in C# - 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.

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.

Hide System.Diagnostics.Process GUI window

I'm really struggling with the following problem. I know that there are similar questions to my scenario but non of them are exactly the same scenario.
I've created an SSIS custom component that starts an external application that I want to run in silent mode. No matter what I try the gui always appears. If I use the same code in a console application I don't run into any issues at all. The only difference I can see between my SSIS custom component (dll) and the console application is that my component references System.Windows.Forms and uses BIDS. I'm using the following code. Any tips I'm more than willing to try.
Process winscp = new Process();
winscp.StartInfo.FileName = #stExe;
winscp.StartInfo.Arguments = "/log=";
winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true;
winscp.StartInfo.RedirectStandardOutput = true;
winscp.StartInfo.CreateNoWindow = true;
winscp.Start();
Try to find the window of the new process, hide it as soon as possible.
Use Win32 API,
HWND hwnd = FindWindow(NULL, "Title");
ShowWindow(hwnd, SW_HIDE);
It is possible using ShowWindow. You need to make sure that the method ShowWindow is called after the process window has been created and not during it's startup.
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
Call the following after the process window appears.
ShowWindow(winscp.MainWindowHandle, 0)
As you are running WinSCP:
If using the winscp.com, the CreateNoWindow should work as the console window is created by the system, hence controlable by the CreateNoWindow
If using the winscp.exe, the CreateNoWindow does not work as the console windows is created by WinSCP itself. But you can force WinSCP not creating the window by omitting the /console argument
For details refer to:
https://winscp.net/eng/docs/executables

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.

Find and activate an application's window

Assume that notepad.exe is opening and the it's window is inactive. I will write an application to activate it. How to make?
Update: The window title is undefined. So, I don't like to use to FindWindow which based on window's title.
My application is Winform C# 2.0. Thanks.
You'll need to P/invoke SetForegroundWindow(). Process.MainWindowHandle can give you the handle you'll need. For example:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program {
static void Main(string[] args) {
var prc = Process.GetProcessesByName("notepad");
if (prc.Length > 0) {
SetForegroundWindow(prc[0].MainWindowHandle);
}
}
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
}
Note the ambiguity if you've got more than one copy of Notepad running.
You'd need to PInvoke the Windows API calls such as FindWindow and or EnumWindows and GetWindowText (for the title). Ideally you might also want to use GeWindowThreadProcessId so you can tie it down to the actual process.
You have to use combination of these -
Toggle Process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden at runtime
and
Bring another processes Window to foreground when it has ShowInTaskbar = false
You need to find the class of the window and do a search on it. Read more about it here.
Just for info, Notepad's class name is "Notepad" (without quotes). You can verify it using Spy++.
Note: You cannot activate a window of an app if it was run with no window. Read more options in API here.

How can I run another application within a panel of my C# program?

I've been reading lots on how to trigger an application from inside a C# program (Process.Start()), but I haven t been able to find any information on how to have this new application run within a panel of my C# program. For example, I'd like a button click to open a notepad.exe WITHIN my application, not externally.
Using the win32 API it is possible to "eat" another application. Basically you get the top window for that application and set it's parent to be the handle of the panel you want to place it in. If you don't want the MDI style effect you also have to adjust the window style to make it maximised and remove the title bar.
Here is some simple sample code where I have a form with a button and a panel:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Process p = Process.Start("notepad.exe");
Thread.Sleep(500); // Allow the process to open it's window
SetParent(p.MainWindowHandle, panel1.Handle);
}
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
}
}
I just saw another example where they called WaitForInputIdle instead of sleeping. So the code would be like this:
Process p = Process.Start("notepad.exe");
p.WaitForInputIdle();
SetParent(p.MainWindowHandle, panel1.Handle);
The Code Project has a good article one the whole process: Hosting EXE Applications in a WinForm project
I don't know if this is still the recommended thing to use but the "Object Linking and Embedding" framework allows you to embed certain objects/controls directly into your application. This will probably only work for certain applications, I'm not sure if Notepad is one of them. For really simple things like notepad, you'll probably have an easier time just working with the text box controls provided by whatever medium you're using (e.g. WinForms).
Here's a link to OLE info to get started:
http://en.wikipedia.org/wiki/Object_Linking_and_Embedding
Another interesting solution to luch an exeternal application with a WinForm container is the follow:
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private void Form1_Load(object sender, EventArgs e)
{
ProcessStartInfo psi = new ProcessStartInfo("notepad.exe");
psi.WindowStyle = ProcessWindowStyle.Minimized;
Process p = Process.Start(psi);
Thread.Sleep(500);
SetParent(p.MainWindowHandle, panel1.Handle);
CenterToScreen();
psi.WindowStyle = ProcessWindowStyle.Normal;
}
The step to ProcessWindowStyle.Minimized from ProcessWindowStyle.Normal remove the annoying delay.
Adding some solution in Answer..**
This code has helped me to dock some executable in windows form. like NotePad, Excel, word, Acrobat reader n many more...
But it wont work for some applications. As sometimes when you start process of some application.... wait for idle time... and the try to get its mainWindowHandle.... till the time the main window handle becomes null.....
so I have done one trick to solve this
If you get main window handle as null... then search all the runnning processes on sytem and find you process ... then get the main hadle of the process and the set panel as its parent.
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "xxxxxxxxxxxx.exe";
info.Arguments = "yyyyyyyyyy";
info.UseShellExecute = true;
info.CreateNoWindow = true;
info.WindowStyle = ProcessWindowStyle.Maximized;
info.RedirectStandardInput = false;
info.RedirectStandardOutput = false;
info.RedirectStandardError = false;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(info);
p.WaitForInputIdle();
Thread.Sleep(3000);
Process[] p1 ;
if(p.MainWindowHandle == null)
{
List<String> arrString = new List<String>();
foreach (Process p1 in Process.GetProcesses())
{
// Console.WriteLine(p1.MainWindowHandle);
arrString.Add(Convert.ToString(p1.ProcessName));
}
p1 = Process.GetProcessesByName("xxxxxxxxxxxx");
//p.WaitForInputIdle();
Thread.Sleep(5000);
SetParent(p1[0].MainWindowHandle, this.panel2.Handle);
}
else
{
SetParent(p.MainWindowHandle, this.panel2.Handle);
}
I notice that all the prior answers use older Win32 User library functions to accomplish this. I think this will work in most cases, but will work less reliably over time.
Now, not having done this, I can't tell you how well it will work, but I do know that a current Windows technology might be a better solution: the Desktop Windows Manager API.
DWM is the same technology that lets you see live thumbnail previews of apps using the taskbar and task switcher UI. I believe it is closely related to Remote Terminal services.
I think that a probable problem that might happen when you force an app to be a child of a parent window that is not the desktop window is that some application developers will make assumptions about the device context (DC), pointer (mouse) position, screen widths, etc., which may cause erratic or problematic behavior when it is "embedded" in the main window.
I suspect that you can largely eliminate these problems by relying on DWM to help you manage the translations necessary to have an application's windows reliably be presented and interacted with inside another application's container window.
The documentation assumes C++ programming, but I found one person who has produced what he claims is an open source C# wrapper library: https://bytes.com/topic/c-sharp/answers/823547-desktop-window-manager-wrapper. The post is old, and the source is not on a big repository like GitHub, bitbucket, or sourceforge, so I don't know how current it is.
If you want to run notepad inside your app you would probably be better of with a text editor component. There's obviously a basic text box that comes with WinForms, but I suspect more advanced components that offer Notepad functionality (or better) can be found on the interweb.
I know this is possible if the other application can attach itself to a win32 window handle. For example, we have a separate C# application that hosts a DirectX application inside one of its windows. I'm not familiar with the exact details of how this is implemented, but I think just passing the win32 Handle of your panel to the other application is enough for that application to attach its DirectX surface.
Short Answer:
No
Shortish Answer:
Only if the other application is designed to allow it, by providing components for you to add into your own application.

Categories

Resources