I'm studying C# by following the guides in MSDN.
Now, I just tried the Example 1 (here is the link to MSDN), and I've encountered an issue: why is the console window closing immediately once displayed my output?
using System;
public class Hello1
{
public static int Main()
{
Console.WriteLine("Hello, World!");
return 0;
}
}
the issue here is that their Hello World Program is showing up then it would immediately close.
why is that?
Because it's finished. When console applications have completed executing and return from their main method, the associated console window automatically closes. This is expected behavior.
If you want to keep it open for debugging purposes, you'll need to instruct the computer to wait for a key press before ending the app and closing the window.
The Console.ReadLine method is one way of doing that. Adding this line to the end of your code (just before the return statement) will cause the application to wait for you to press a key before exiting.
Alternatively, you could start the application without the debugger attached by pressing Ctrl+F5 from within the Visual Studio environment, but this has the obvious disadvantage of preventing you from using the debugging features, which you probably want at your disposal when writing an application.
The best compromise is probably to call the Console.ReadLine method only when debugging the application by wrapping it in a preprocessor directive. Something like:
#if DEBUG
Console.WriteLine("Press enter to close...");
Console.ReadLine();
#endif
You might also want the window to stay open if an uncaught exception was thrown. To do that you can put the Console.ReadLine(); in a finally block:
#if DEBUG
try
{
//...
}
finally
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
#endif
Instead of using
Console.Readline()
Console.Read()
Console.ReadKey()
you can run your program using Ctrl+F5 (if you are in Visual Studio). Then Visual Studio will keep the console window open, until you press a key.
Note: You cannot debug your code in this approach.
I assume the reason you don't want it to close in Debug mode, is because you want to look at the values of variables etc. So it's probably best to just insert a break-point on the closing "}" of the main function.
If you don't need to debug, then Ctrl-F5 is the best option.
This behaves the same for CtrlF5 or F5.
Place immediately before end of Main method.
using System.Diagnostics;
private static void Main(string[] args) {
DoWork();
if (Debugger.IsAttached) {
Console.WriteLine("Press any key to continue . . .");
Console.ReadKey();
}
}
In Visual Studio 2019 for .NET Core projects the console doesn't close automatically by default. You can configure the behaviour through menu Tools → Options → Debugging → General → Automatically close the console when debugging stops. If you get your console window automatically closing, check if the mentioned setting is not set.
The same applies to the .NET Framework new style console projects:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net472</TargetFramework>
</PropertyGroup>
</Project>
The old style .NET Framework project still unconditionally close the console at the end (as of Visual Studio 16.0.1).
Reference: .NET Core tooling update for Visual Studio 2019 Preview 2
If you want to keep your application opened, you have to do something in order to keep its process alive. The below example is the simplest one, to be put at the end of your program:
while (true) ;
However, it'll cause the CPU to overload, as it's therefore forced to iterate infinitely.
At this point, you can opt to use System.Windows.Forms.Application class (but it requires you to add System.Windows.Forms reference):
Application.Run();
This doesn't leak CPU and works successfully.
In order to avoid to add System.Windows.Forms reference, you can use a simple trick, the so-called spin waiting, importing System.Threading:
SpinWait.SpinUntil(() => false);
This also works perfectly, and it basically consists of a while loop with a negated condition that is returned by the above lambda method. Why isn't this overloading CPU? You can look at the source code here; anyway, it basically waits some CPU cycle before iterating over.
You can also create a message looper, which peeks the pending messages from the system and processes each of them before passing to the next iteration, as follows:
[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "PeekMessage")]
public static extern int PeekMessage(out NativeMessage lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax, int wRemoveMsg);
[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "GetMessage")]
public static extern int GetMessage(out NativeMessage lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax);
[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "TranslateMessage")]
public static extern int TranslateMessage(ref NativeMessage lpMsg);
[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode, DllImport("user32.dll", EntryPoint = "DispatchMessage")]
public static extern int DispatchMessage(ref NativeMessage lpMsg);
[DebuggerHidden, DebuggerStepperBoundary, DebuggerNonUserCode]
public static bool ProcessMessageOnce()
{
NativeMessage message = new NativeMessage();
if (!IsMessagePending(out message))
return true;
if (GetMessage(out message, IntPtr.Zero, 0, 0) == -1)
return true;
Message frameworkMessage = new Message()
{
HWnd = message.handle,
LParam = message.lParam,
WParam = message.wParam,
Msg = (int)message.msg
};
if (Application.FilterMessage(ref frameworkMessage))
return true;
TranslateMessage(ref message);
DispatchMessage(ref message);
return false;
}
Then, you can loop safely by doing something like this:
while (true)
ProcessMessageOnce();
The program immediately closes because there's nothing stopping it from closing. Insert a breakpoint at return 0; or add Console.Read(); before return 0; to prevent the program from closing.
Alternatively, you can delay the closing using the following code:
System.Threading.Thread.Sleep(1000);
Note the Sleep is using milliseconds.
Another way is to use Debugger.Break() before returning from Main method
The code is finished, to continue you need to add this:
Console.ReadLine();
or
Console.Read();
Use Console.Read(); to prevent the program from closing, but make sure you add the Console.Read(); code before return statement, or else it will be a unreachable code .
Console.Read();
return 0;
check this Console.Read
Add The Read method to show the output.
Console.WriteLine("Hello, World!");
Console.Read();
return 0;
Here is a way to do it without involving Console:
var endlessTask = new TaskCompletionSource<bool>().Task;
endlessTask.Wait();
Tools -> Options -> Debugging -> General -> Automatically close the console (5th last option)
Check the box and close.
This applied to all projects.
The program is closing as soon as its execution is complete.
In this case when you return 0;. This is expected functionality.
If you want to see the output then either run it in a terminal manually or set a wait at the end of the program so that it will stay open for a few seconds (using the threading library).
Related
Apologies if this is a stupid question; I'm not overly familiar with Visual Studio and definitely not the new version.
I am trying to hook calls to TextOutA from a Windows application using EasyHook, roughly following this tutorial, in Visual Studio 2019. (I am 100% certain that they are TextOutA; decompiler output indicates as much, and I was able to successfully hook them using C++. Unfortunately C# is far more supported/documented than C++ for EasyHook.)
Per the tutorial I have a console application and a class library as two projects in the same solution. Getting the Visual Studio solution to compile at all was somewhat bumpy -- I had to manually edit the .csproj files to .NET Framework 4.8 (per this question) and it took some tinkering to get it working. But now I am worried that I have tinkered too much.
What happens: The code compiles without errors and warnings, and seemingly runs successfully. However, nothing in the DLL seems to be called; none of its code appears to be executed, a breakpoint in Run() is never hit, and it still compiles if I just get rid of the Run() code entirely.
This is the console app code, so far (filenames redacted; there may well be other issues with this code but I'd have to run it to find out):
static void Main(string[] args)
{
string injectionLibrary = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "[name of DLL].dll");
Console.WriteLine(injectionLibrary);
try
{
Int32 processID = 0;
Process[] process = Process.GetProcessesByName("[process name]");
Console.Write(process[0]);
processID = process[0].Id;
EasyHook.RemoteHooking.Inject(
processID, // ID of process to inject into
injectionLibrary, // 32-bit library to inject (if target is 32-bit)
injectionLibrary, // 64-bit library to inject (if target is 64-bit)
null // the parameters to pass into injected library
// ...
);
Console.WriteLine("Injected, supposedly.");
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("There was an error while injecting into target: ");
Console.ResetColor();
Console.WriteLine(e.ToString());
}
Console.ReadKey();
}
}
}
And this is the class library:
namespace [DLL name]
{
public class MySimpleEntryPoint : EasyHook.IEntryPoint
{
public MySimpleEntryPoint(EasyHook.RemoteHooking.IContext context)
{
}
public void Run(EasyHook.RemoteHooking.IContext context)
{
Console.Write("Test");
var textOutHook = EasyHook.LocalHook.Create(
EasyHook.LocalHook.GetProcAddress("Gdi32.dll", "TextOutA"),
new TextOutDelegate(TextOut_Hook),
this);
textOutHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
}
[UnmanagedFunctionPointer(CallingConvention.StdCall,
CharSet = CharSet.Unicode,
SetLastError = true)]
delegate bool TextOutDelegate(IntPtr orig_handle, int x_value, int y_value, string output_string, int color);
[DllImport("gdi32.dll", CharSet = CharSet.Unicode, EntryPoint = "TextOutA", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
static extern bool TextOutA(IntPtr orig_handle, int x_value, int y_value, string lpString, int color);
bool TextOut_Hook(IntPtr orig_handle, int x_value, int y_value, string output_string, int color)
{
// We aren't going to call the original at all... YET
Console.Write("...intercepted...");
return false;
}
}
}
The console output for the process is as expected, and so is the output of the path:
C:\Users[my username]\source\repos[name of project]\build\net48\ [name of DLL].dll -- which is indeed where the dll is output to. But, as above, nothing in Run() seems to actually be called, TextOutA certainly isn't being suppressed, etc.
What I have tried:
Adding both the .dll and the class library project (separately) as references to the console app
Setting both the .dll and the executable to output to the same folder
Tweaking the line of code that supposedly gets the path
Comparing this code to basically any comparable EasyHook projects I can find, nothing seems obviously amiss
Calling GetProcAddress from within the console app and not the hook; it works as expected, so the problem doesn't seem to be that
Any help would be much appreciated.
Answer as per my comment.
There are two things happening in your example:
when Run exits your hooks are likely to be cleaned up by the GC and therefore uninstalled
when Run exits EasyHook will unload your assembly
The managed EasyHook helper library EasyLoad runs your IEntryPoint.Run method within a new thread and waits for it to exit. When the method exits the assembly is unloaded etc.
Therefore you should add a while loop at the end of your Run method to prevent it exiting until you are finished with your hooks.
public void Run(EasyHook.RemoteHooking.IContext context)
{
// install hooks
...
while (true) {
Thread.Sleep(500);
// optionally perform a check to see if should break
}
// uninstall hooks / cleanup / etc
}
I am trying to automate Windows 10 installation by first mounting the .iso file on the drive. And then using c# to start windows 10 installation by using this below code which passes the keys to the installation application
[DllImport("user32.dll")]
static extern int SetForegroundWindow(IntPtr point);
public static void Main(String[] args){
Process p1 = Process.Start("h:\\setup.exe");
IntPtr h = p1.MainWindowHandle;
SetForegroundWindow(h);
Thread.Sleep(30000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(1000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(1000);
SendKeys.SendWait("{ENTER}");
}
But the problem is that the setup window is not taking the signal of the ENTER key in the code. The setup window is starting with this code. After that, nothing is happening.
Process p1 = Process.Start("h:\\setup.exe");
I tried using notepad instead of setup.exe in the code which is taking all the ENTER keys. Please tell me if anyone has a solution. Thank you
Disclaimer:
I would advise against automating a Windows setup using something like
SendKeys as you can't guarantee a consistent behavior and could
easily mess things up. You may consider looking for different
approaches as suggested by lan Kemp in the comments. This answer
only shows you how to get the handle of the setup window correctly.
You may use it at your own risk.
Update:
Apparently, the Windows 10 setup executable ("Setup.exe") starts another process called "SetupPrep.exe" which starts a third process called "SetupHost.exe" (the one you're after). So, what you can do is start the main process, wait for the target process to start and obtain a MainWindowHandle before executing the remaining code:
Process p1 = Process.Start("H:\\setup.exe");
Process targetProcess;
do
{
Thread.Sleep(500);
targetProcess = Process.GetProcessesByName("SetupHost").FirstOrDefault();
} while (targetProcess == null || targetProcess.MainWindowHandle == IntPtr.Zero);
IntPtr h = targetProcess.MainWindowHandle;
// ...
This should solve your problem, however, it's not a wise idea to use SendKeys for this purpose. Please refer to the disclaimer above.
Original answer:
Did you make sure that h does actually have a value (other than IntPtr.Zero)? Because it probably doesn't have the actual window handle since you don't give the process enough time to start and obtain a window handle.
Try something like this:
Process p1 = Process.Start("h:\\setup.exe");
while (p1.MainWindowHandle == IntPtr.Zero)
{
Thread.Sleep(500);
}
IntPtr h = p1.MainWindowHandle;
// ...
When I run my program, the console window seems to run and close. How to keep it open so I can see the results?
class Program
{
public class StringAddString
{
public virtual void AddString()
{
var strings2 = new string[] { "1", "2", "3", "4", "5","6", "7", "8", "9"};
Console.WriteLine(strings2);
Console.ReadLine();
}
}
static void Main(string[] args)
{
StringAddString s = new StringAddString();
}
}
Put a Console.Read() as the last line in your program. That will prevent it from closing until you press a key
static void Main(string[] args)
{
StringAddString s = new StringAddString();
Console.Read();
}
If you want to keep it open when you are debugging, but still let it close normally when not debugging, you can do something like this:
if (System.Diagnostics.Debugger.IsAttached) Console.ReadLine();
Like other answers have stated, the call to Console.ReadLine() will keep the window open until enter is pressed, but Console.ReadLine() will only be called if the debugger is attached.
There are two ways I know of
1) Console.ReadLine() at the end of the program. Disadvantage, you have to change your code and have to remember to take it out
2) Run outside of the debugger CONTROL-F5 this opens a console window outside of visual studio and that window won't close when finished. Advantage, you don't have to change your code. Disadvantage, if there is an exception, it won't drop into the debugger (however when you do get exceptions, you can simply just rerun it in the debugger)
Console.ReadKey(true);
This command is a bit nicer than readline which passes only when you hit enter, and the true parameter also hides the ugly flashing cursor while reading the result :) then any keystroke terminates
You forgot calling your method:
static void Main(string[] args)
{
StringAddString s = new StringAddString();
s.AddString();
}
it should stop your console, but the result might not be what you expected, you should change your code a little bit:
Console.WriteLine(string.Join(",", strings2));
You can handle this without requiring a user input.
Step 1. Create a ManualRestEvent at the start of Main thread
ManualResetEvent manualResetEvent = new ManualResetEvent(false);
Step 2 . Wait ManualResetEvent
manualResetEvent.WaitOne();
Step 3.To Stop
manualResetEvent.Set();
Write Console.ReadKey(); in the last line of main() method. This line prevents finishing the console. I hope it would help you.
If your using Visual Studio just run the application with Crtl + F5 instead of F5. This will leave the console open when it's finished executing.
Use Console.Readline() at the end .Your code will not close until you close it manually.Since Readline waits for input that needs to be entered for your code hence your console will be open until you type some input.
For visual c# console Application use:
Console.ReadLine();
Console.Read();
Console.ReadKey(true);
for visual c++ win32 console application use:
system("pause");
press ctrl+f5 to run the application.
Make sure to useConsole.ReadLine();
to keep the preceeding Console.WriteLine(""); message from closing.
Console.Read()
-> Console stays open until you press a button on your keyboard
To be able to give it input without it closing as well you could enclose the code in a while loop
while (true)
{
<INSERT CODE HERE>
}
It will continue to halt at Console.ReadLine();, then do another loop when you input something.
If you're using Visual Studio, then the IDE has an option to keep the window open under
Tools > Options > Debugging >
Automatically close the console when debugging stops
Unlike CTRL + F5, this allows you to use breakpoints while debugging.
What I want to have happen is that the console window just goes away, or better yet that it is hidden, but I want my application to keep running. Is that possible? I want to be able to use Console.WriteLine and have the console serve as an output window. I want to be able to hide and show it, and I don't want the whole app to die just because the console was closed.
EDIT
Code:
internal class SomeClass {
[DllImport("kernel32")]
private static extern bool AllocConsole();
private static void Main() {
AllocConsole();
while(true) continue;
}
}
EDIT 2
I tried the accepted solution here [ Capture console exit C# ], per the suggestion in the comments on this question. The example code is bugged in that the DLLImport needs to be "kernel32.dll" or "kernel32", not "Kernel32". After making that change, I'm getting a message to my handler for CTRL_CLOSE_EVENT when I click the X on the console window. However, calling FreeConsole and/or returning true doesn't prevent the application from terminating.
Ah, yes, this is one of the caveats of using the Windows console subsystem. When the user closes the console window (regardless of how the console was allocated), all of the processes that are attached to the console are terminated. That behavior makes obvious sense for console applications (i.e., those that specifically target the console subsystem, as opposed to standard Windows applications), but it can be a major pain in cases like yours.
The only workaround that I know of is to use the SetConsoleCtrlHandler function, which allows you to register a handler function for Ctrl+C and Ctrl+Break signals, as well as system events like the user closing the console window, the user logging off, or the system shutting down. The documentation says that if you're only interested in ignoring these events, you can pass null for the first argument. For example:
[DllImport("kernel32")]
static extern bool SetConsoleCtrlHandler(HandlerRoutine HandlerRoutine, bool Add);
delegate bool HandlerRoutine(uint dwControlType);
static void Main()
{
AllocConsole();
SetConsoleCtrlHandler(null, true);
while (true) continue;
}
That works perfectly for Ctrl+C and Ctrl+Break signals (which would have otherwise caused your application to terminate as well), but it doesn't work for the one you're asking about, which is the CTRL_CLOSE_EVENT, generated by the system when the user closes the console window.
Honestly, I don't know how to prevent that. Even the sample in the SDK doesn't actually allow you to ignore the CTRL_CLOSE_EVENT. I tried it in a little test app, and it beeps when you close the window and prints the message, but the process still gets terminated.
Perhaps more worryingly, the documentation makes me think it is not possible to prevent this:
The system generates CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT signals when the user closes the console, logs off, or shuts down the system so that the process has an opportunity to clean up before termination. Console functions, or any C run-time functions that call console functions, may not work reliably during processing of any of the three signals mentioned previously. The reason is that some or all of the internal console cleanup routines may have been called before executing the process signal handler.
It's that last sentence that catches my eye. If the console subsystem starts cleaning up after itself immediately in response to the user attempting to close the window, it may not be possible to halt it after the fact.
(At least now you understand the problem. Maybe someone else can come along with a solution!)
Unfortunately there's nothing you can do to really alter this behaviour.
Console windows are "special" in that they're hosted by another process and do not allow sub-classing. This limits your ability to modify their behaviour.
From what I know, your two options are:
1. Disable the close button altogether. You can do this with the following code fragment:
HWND hwnd = ::GetConsoleWindow();
if (hwnd != NULL)
{
HMENU hMenu = ::GetSystemMenu(hwnd, FALSE);
if (hMenu != NULL) DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
2. Stop using consoles altogether, and implement your own text output solution.
Option #2 is the more complicated option but would provide you the greatest control. I found an article on CodeProject that implements a console-like application using a rich edit control to display the text (rich edit controls have the ability to stream text like the console, so they are well suited to this sort of application).
On closing the console window obtained using AllocConsole or AttachConsole, the associated process will exit. There is no escape from that.
Prior to Windows Vista, closing the console window would present a confirmation dialogue to the user asking him whether the process should be terminated or not but Windows Vista and later do not provide any such dialogue and the process gets terminated.
One possible solution to work around this is avoiding AttachConsole altogether and achieving the desired functionality through other means.
For instance in the case described by OP, console window was needed to output some text on Console using Console static class.
This can be achieved very easily using inter-process communication. For example a console application can be developed to act as an echo server
namespace EchoServer
{
public class PipeServer
{
public static void Main()
{
var pipeServer = new NamedPipeServerStream(#"Com.MyDomain.EchoServer.PipeServer", PipeDirection.In);
pipeServer.WaitForConnection();
StreamReader reader = new StreamReader(pipeServer);
try
{
int i = 0;
while (i >= 0)
{
i = reader.Read();
if (i >= 0)
{
Console.Write(Convert.ToChar(i));
}
}
}
catch (IOException)
{
//error handling code here
}
finally
{
pipeServer.Close();
}
}
}
}
and then instead of allocating/attaching a console to the current application, the echo server can be started from within the application and Console's output stream can be redirected to write to the pipe server.
class Program
{
private static NamedPipeClientStream _pipeClient;
static void Main(string[] args)
{
//Current application is a Win32 application without any console window
var processStartInfo = new ProcessStartInfo("echoserver.exe");
Process serverProcess = new Process {StartInfo = processStartInfo};
serverProcess.Start();
_pipeClient = new NamedPipeClientStream(".", #"Com.MyDomain.EchoServer.PipeServer", PipeDirection.Out, PipeOptions.None);
_pipeClient.Connect();
StreamWriter writer = new StreamWriter(_pipeClient) {AutoFlush = true};
Console.SetOut(writer);
Console.WriteLine("Testing");
//Do rest of the work.
//Also detect that the server has terminated (serverProcess.HasExited) and then close the _pipeClient
//Also remember to terminate the server process when current process exits, serverProcess.Kill();
while (true)
continue;
}
}
This is just one of the possible solutions. In essence the work around is to allot the console window to its own process so that it can terminate without affecting the parent process.
You can do this by disabling keyboard mouse input by external program called Keyfreez.
you can use it multiple times in your program where no user input required. And if any user input require u can add a process Takskkill /f /IM .
https://www.sordum.org/7921/bluelife-keyfreeze-v1-4-block-keyboard-and-mouse/
Hope this helps all of you
I have seen many examples of a hybrid gui/cli app for C#. I have implemented such an app, but I am having a hard time figuring out how to prevent the .exe, when run on the command line, from not returning back to the prompt right away.
//defines for commandline output
[DllImport("kernel32.dll")]
static extern bool AttachConsole(int dwProcessId);
private const int ATTACH_PARENT_PROCESS = -1;
[STAThreadAttribute]
static void Main(string[] args)
{
// load cli
// redirect console output to parent process;
// must be before any calls to Console.WriteLine()
AttachConsole(ATTACH_PARENT_PROCESS);
if (args.Length == 0)
{
//loads gui
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new form_Main());
}
else
{
cli_main cli = new cli_main();
cli.start_cli(args);
Console.WriteLine("finished");
System.Windows.Forms.SendKeys.SendWait("{ENTER}");
Application.Exit();
}
}
I get the following output
C:\Users\john\Documents\Visual Studio 2010\Projects\test\test\test\bin\Debug>test.exe -param1 test
-param2 test2
C:\Users\john\Documents\Visual Studio 2010\Projects\test\test\test\bin\Debug>Output was successful. File saved as: c:\test\test.html
finished
The line "finished" is a string I output when I know I have reach end of my main code... this works fine in Winforms, my project is Winforms and I started it as a gui but now I am trying to make it hybrid gui/cli
And it seems to be running my main code and threads I see them in debugging and it creates my final output file...
I just am puzzled as to how to keep the .exe when executed from cmd line with it's parameters, to not return to the command prompt?? And have it wait with a blinking cursor, then output the line about the html file and then the line "finished", then finally go back to the command prompt.
I've tried numerous things like removing
System.Windows.Forms.SendKeys.SendWait("{ENTER}");
Application.Exit();
and instead of using Application.Exit(); use Environment.Exit(0); but it always returns to the command prompt right away, also I tried putting in sleep for 5 secs after the line
cli.start_cli(args);
but that didn't work either, I guess I don't understand how it can return to command prompt right away and it hasn't even it the line
Console.WriteLine("finished");
FWIW, I tried the first approach as well. I ended up just hiding the console window using:
IntPtr handle = GetConsoleWindow();
if (handle != IntPtr.Zero)
{
ShowWindow(handle, 0); // 0=SW_HIDE
}
This completely hides the window, even from the Taskbar. It flashes for a brief second but that's acceptable in my case