Console selection stops application - c#

I'm running a socket server on my server and I woke up to numerous messages about its inaccessibility. It turns out that before I went to bed, I had highlighted an IP address in the window and forgot to hit Enter to resume the process.
This is how I disable selection in the console, now, but I still want to be able to select without the application pausing.
#region Disable Quick-Edit Mode
[DllImport("kernel32.dll")]
static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode);
[DllImport("kernel32.dll")]
static extern bool GetConsoleMode(IntPtr hConsoleHandle, out int mode);
[DllImport("kernel32.dll")]
static extern IntPtr GetStdHandle(int handle);
const int STD_INPUT_HANDLE = -10;
const int ENABLE_EXTENDED_FLAGS = 0x80;
public static void DisableQuickEditMode()
{
int mode;
IntPtr handle = GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(handle, out mode);
mode |= ENABLE_EXTENDED_FLAGS;
SetConsoleMode(handle, mode);
mode &= ~ENABLE_QUICK_EDIT;
SetConsoleMode(handle, mode);
}
I really don't want to go back to the Legacy Mode of Command Prompt, because it really does help to have these new features (especially for devs), but I need to find a way to prevent the application from stopping when I pause the console.
What's interesting is that when I hit Enter this morning, all of the connections that had been attempted were processed, and then after they were processed, they were dropped. Which makes me wonder if, perhaps, I'm writing the application wrong; that I need to have a "Console" thread and a "Server" thread. But I'm not sure that could even make a difference.

When in selection mode, any thread in the Windows console will block when writing stdout or stderr. Doesn't matter which thread.
You could separate out the console writes from the server operations and make sure the server threads never write to the console, but then you introduce additional thread management and message queueing concerns.
You could do what most people do: Use log files. If you don't want to build file writing into the application, just pipe stdout and stderr to a file and use some Windows equivalent of tail to monitor the file (or a text editor like Sublime which automatically monitors open files).
server.exe > server.log 2>&1
To clarify: 2>&1 indicates that stderr (file handle 2) should be "merged into" stdout (file handle 1).

For simple tools, executing the Console writes in a different thread may indeed be easiest.
Sample code:
static BlockingCollection<string> messageQueue = new BlockingCollection<string>(new ConcurrentQueue<string>());
static Task messagePrinterTask;
private static void ConsoleWriteLine(string s)
{
messageQueue.Add(s);
}
private static void StartMessageQueuePrinter()
{
messagePrinterTask = Task.Run(() =>
{
try { while(true) Console.WriteLine(messageQueue.Take()); }
catch (InvalidOperationException) { } //CompleteAdding called.
});
}
private static void StopMessageQueuePrinter()
{
messageQueue.CompleteAdding();
messagePrinterTask.Wait();
}

Related

Force windows to wake up from standby mode [duplicate]

What's the best way to programmatically cause a Windows XP (or above) machine to wake up at a specific time. (Ideally a lot like how Media Center can start up automatically to record a particular TV program)
I've got a Windows service (written in C#) and I'd like this service to be able to cause the machine it is hosted on to start up at predetermined times.
Are there any BIOS settings or prerequisites (eg. ACPI) that need to be configured for this to work correctly?
This machine would be using dialup or 3G wireless modem, so unfortunately it can't rely on Wake on LAN.
You can use waitable timers to wake from a suspend or hibernate state. From what I can find, it is not possible to programmatically wake from normal shut down mode (soft off/S5), in that case, you need to specify a WakeOnRTC alarm in BIOS. To use waitable timers from C#, you need pInvoke. The import declarations are:
public delegate void TimerCompleteDelegate();
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetWaitableTimer(IntPtr hTimer, [In] ref long pDueTime, int lPeriod, TimerCompleteDelegate pfnCompletionRoutine, IntPtr pArgToCompletionRoutine, bool fResume);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CancelWaitableTimer(IntPtr hTimer);
You can use those functions in the following way:
public static IntPtr SetWakeAt(DateTime dt)
{
TimerCompleteDelegate timerComplete = null;
// read the manual for SetWaitableTimer to understand how this number is interpreted.
long interval = dt.ToFileTimeUtc();
IntPtr handle = CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer");
SetWaitableTimer(handle, ref interval, 0, timerComplete, IntPtr.Zero, true);
return handle;
}
You can then cancel the waitable timer with CancelWaitableTimer, using the returned handle as an argument.
Your program can hibernate and sleep using pInvoke:
[DllImport("powrprof.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetSuspendState(bool hibernate, bool forceCritical, bool disableWakeEvent);
public static bool Hibernate()
{
return SetSuspendState(true, false, false);
}
public static bool Sleep()
{
return SetSuspendState(false, false, false);
}
Your system may not allow programs to let the computer enter hibernation. You can call the following method to allow hibernation:
public static bool EnableHibernate()
{
Process p = new Process();
p.StartInfo.FileName = "powercfg.exe";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.Arguments = "/hibernate on"; // this might be different in other locales
return p.Start();
}
The task scheduler program in Win7, taskschd.msc (and I beleive XP as well) can be set to wake the system on different triggers. Those triggers can be schedule, time, event, etc.
In at least Win7, you need to set "Allow Wake Timers" to 'Enabled' for this to work. This setting is found under...
--> Control Panel\Hardware and Sound\Power Options
click - "Edit Plan Settings"
click - "Change advanced power setting"
expand - "Sleep"
Expand - "Allow Wake timers"
Your best bet is using Wake on LAN capability. This will require another machine to send a packet of a special kind to wake your machine up.
This will not be helpful if your machine is not connected to the network or you for some reason don't wasnt to move this logic onto another machine. But it's useful for some configurations where you have multiple machines and want to wake them up programmatically.
Some machines have a BIOS alarm clock that can be set to wake up the computer at a certain hour. It should be possible to program this clock, but I don't know the specific details.
Edit: I found this program that should let you set the time. It's in C, under Linux, but maybe it can give you some hints.
A warning though: before trying anything that changes the BIOS settings directly be sure to write down every setting from BIOS screens, because in case of an error the BIOS might revert to factory default and you might need to set it up again as it was.

Console, ctrl+c vs close button click

When I click ctrl+c in a console window, event is raised and application can execute some piece of code which should be executed before exiting.
However, when I click [X] close button, event is raised too, but in a short time, my app I forcibly closed - when 'end execution' event is still in progress.
Is it possible to set longer timeout before windows will forcibly close app?
EDIT:
Im setting:
[DllImport("Kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ControlEventHandler e, bool add);
public delegate void ControlEventHandler(ConsoleEvent consoleEvent);
When I click ctrl+c on console window, Im receiving: CTRL_C, and I can process code in mu event handler.
When I click [x] close button, I'm receiveing CTRL_CLOSE flag, I can process handler too, but only for 1-2secs. Then console windwo disappers...
Is it possible to set longer timeout before windows will forcibly close app?
Unfortunately, no. Starting with Windows Vista, you are allowed only 10 seconds or so grace period after receiving the CTRL_CLOSE_EVENT before the console window automatically closes. If you haven't exited the handler by the time 10 seconds has elapsed, then your process is unceremoniously terminated. (Obviously, if you return from the handler sooner, you will not get the full 10 seconds.)
As far as I can tell, this is part of a larger design strategy to ensure that applications cannot override the will of the user. Older versions of the SDK documentation spoke of a dialog box that would appear if the process didn't respond within a certain time-out period, but all mention of that is gone from the current version of the SDK documentation. The dialog box went MIA in Vista, it doesn't exist anymore. This is probably connected to the fact that applications can no longer block system shutdown either.
This doesn't affect your pressing Ctrl+C because that raises a different signal—CTRL_C_EVENT. Same thing with Ctrl+Break, which raises CTRL_BREAK_EVENT. But as far as I can tell from the documentation, CTRL_CLOSE_EVENT, CTRL_LOGOFF_EVENT, and CTRL_SHUTDOWN_EVENT are simply notifications, giving you a chance to clean up before you are terminated. There is no way to block termination or extend the grace period.
There is only one workaround that I can think of, and that is to disable the close button on the console window itself. I see that you're using C#, so a bit of P/Invoke will be required:
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool DeleteMenu(IntPtr hMenu, uint uPosition, uint uFlags);
private const uint MF_BYCOMMAND = 0x0;
private const uint SC_CLOSE = 0xF060;
void DisableConsoleCloseButton()
{
IntPtr hWnd = GetConsoleWindow();
if (hWnd != IntPtr.Zero)
{
IntPtr hMenu = GetSystemMenu(hWnd, false);
if (hMenu != IntPtr.Zero)
{
DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
}
}
If you go this route, you will obviously need to provide the user with some way of closing the console window from within your application. In Win32-land, that functionality would call the FreeConsole function to close it, but I'll bet that's wrapped up in one of the .NET classes. Been too long for me to remember what it's called.

How to show the console on a C# program with Windows application output type

I have a C# Console application project where the output type is set to "Windows application". This is so the console does not flash up at the start of the program.
However i also want to allow a help command line argument which will display details about the program if you run it from the command line with "/?" as an argument.
Is there a way to have the program run as a windows application normally but show a console if the help argument is passed?
EDIT - After reading the answers and a similar one at This question (this question assumes you are running with a console application output type) I am using this solution.
[DllImport(Kernel32_DllName)]
private static extern bool AllocConsole();
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
const int SW_HIDE = 0;
const int SW_SHOW = 5;
static void Main(string[] args)
{
if(args.Contains("/?"))
{
AllocConsole();
Console.WriteLine("helpText");
Console.ReadLine();
var handle = GetConsoleWindow();
//Hides console
ShowWindow(handle, SW_HIDE);
}
}
I have not found a way to do exactly as you are asking, but you can have a console open up depending on the input. For example:
class Program
{
private const string Kernel32_DllName = "kernel32.dll";
[DllImport(Kernel32_DllName)]
private static extern bool AllocConsole();
static void Main(string[] args)
{
if (args[0] == "/")
{
AllocConsole();
Console.WriteLine("Details");
Console.ReadKey();
//cases and such for your menu options
}
That will open a console that you can use if you follow the run command with a / even though the output type of the project is a Windows Application.
Is there a way to have the program run as a windows application normally but show a console if the help argument is passed?
For what you want, learn about using command line arguments here.
Basically declare Main to accept arguments as an array of string:
static void Main(string[] args)
Use a simple dialog form to display the help message or even a MessageBox which is a very simple dialog form.
This gives you much better control rather than trying to cobble something together that wasn't really meant to be put together.
When I need to do stuff like this, I usually make my app a console app. I then parse the args if any in main and decide if I'm going to hide the console window and launch my UI or write to the console.
Hiding a window is fairly straightforward. See How to hide / unhide a process in C#? for an example.

How do I write to command line from a WPF application?

Hi I know how to write to console but if I write to console in my program and call my program from the command line it won't display anything.
How do I make it so that when I say Console.WriteLine or Console.Out.Writeline ir prints to the command prompt from which it was called and not somewhere else?
Once again I know how to do Console.WriteLine so it's not that :-p unless I'm doing it wrong.
From what I can tell it's probably something to do with Console.SetOut(TextWriter t)
this is a WPF application and I need it to post its data to the command line while still retaining the GUI at startup. I've triple checked and my code hits the print lines, I can actually see the lines being printed to the Visual Studio output window, it just won't display in the command line when I run it manually without VS.
If possible I need to conditionally have the console display. ie if run from command line (or even with command arguments), display or post to the prompt, otherwise do not.
This is actually trivial:
public void WriteToConsole(string message)
{
AttachConsole(-1);
Console.WriteLine(message);
}
[DllImport("Kernel32.dll")]
public static extern bool AttachConsole(int processId);
This method will write your message to the console if your program was started from the command line, otherwise it will do nothing.
If you want to use an alternative output mechanism when you weren't started from the command line you can do it this way:
public void WriteToConsole(string message)
{
_connected = _connected || AttachConsole(-1);
if(_connected)
Console.WriteLine("Hello");
else
... other way to output message ...
}
bool _connected;
[DllImport("Kernel32.dll")]
public static extern bool AttachConsole(int processId);
The full code for this particular task is:
public static void WriteToConsole(string message)
{
AttachConsole(-1);
System.Console.WriteLine(message);
SendKeys.SendWait("{ENTER}");
FreeConsole();
}
[DllImport("Kernel32.dll")]
private static extern bool AttachConsole(int processId);
[DllImport("kernel32.dll")]
private static extern bool FreeConsole();
All credits goes to Ray Burns & Scott Marlowe.
Set the project type to "Console Application" instead of "Windows Application". This will cause the Application to attach to the console from which it was launched (or create a console if there was not one already).

Problem with Killing windows explorer?

I need to kill windows explorer's process (explorer.exe), for that
lets say i use a native NT method TerminateProcess
It works but the problem is that the explorer starts again, may be windows is doing that, anyway. When i kill explorer.exe with windows task manager, it doesn't come back, its stays killed.
I want to do whatever taskmanager is doing through my application.
Edit:
Thanks to #sblom i solved it, a quick tweak in the registry did the trick. Although its a clever hack, apparently taskmnager has a cleaner way of doing that, that said, i've decided to go with #sblom's way for now.
From Technet:
You can set the registry key HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\AutoRestartShell to 0, and it will no longer auto-restart.
The "real" solution. (Complete program. Tested to work on Windows 7.)
using System;
using System.Runtime.InteropServices;
namespace ExplorerZap
{
class Program
{
[DllImport("user32.dll")]
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);
static void Main(string[] args)
{
int hwnd;
hwnd = FindWindow("Progman", null);
PostMessage(hwnd, /*WM_QUIT*/ 0x12, 0, 0);
return;
}
}
}
Here's another solution to this problem - instead api calls it uses an external tool shipped with windows (at least Win 7 Professional):
public static class Extensions
{
public static void ForceKill(this Process process)
{
using (Process killer = new Process())
{
killer.StartInfo.FileName = "taskkill";
killer.StartInfo.Arguments = string.Format("/f /PID {0}", process.Id);
killer.StartInfo.CreateNoWindow = true;
killer.StartInfo.UseShellExecute = false;
killer.Start();
killer.WaitForExit();
if (killer.ExitCode != 0)
{
throw new Win32Exception(killer.ExitCode);
}
}
}
}
I know that Win32Exception may not be the best Exception, but this method acts more or less like Kill - with the exception that it actually kills windows explorer.
I've added it as an extension method, so you can use it directly on Process object:
foreach (Process process in Process.GetProcessesByName("explorer"))
{
process.ForceKill();
}
You must first ensure that the taskkill tool is available on production environment (it seems that it's been for a while with windows: https://web.archive.org/web/20171016213040/http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/taskkill.mspx?mfr=true).
EDIT: Original link dead, replaced with cache from Internet Archive Wayback Machine. Updated documentation for Windows 2012/2016 can be found at: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/taskkill
What you probably need to do is instead of using TerminateProcess, post a WM_QUIT message to the explorer windows and main thread. It's a bit involved, but I found this page which has some example code that might help you along:
http://www.replicator.org/node/100
Windows will automatically restart explorer.exe after a TerminateProcess so that it restarts in the case of a crash termination.
I have some researches and these are reslts:
Windows will restart explorer after it closed -except by Task Manager-.
So you should change the related RegistryKey:
RegistryKey regKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Default).OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\Winlogon", RegistryKeyPermissionCheck.ReadWriteSubTree);
if (regKey.GetValue("AutoRestartShell").ToString() == "1")
regKey.SetValue("AutoRestartShell", 0, RegistryValueKind.DWord);
For changing a registry key the program should run as administrator:
You can show UAC prompt to user to run application as administrator as explaining in this Answer.
And if UAC is turned off I direct you to this Answer.
You can embed a manifest file in the exe, which will cause Windows Seven to always run the program as an administrator, As explaining in this Answer.
You should know you can't force your process starts as administrator; so you can run your process inside your process as another process! You can use this blog post or this answer.
You can also use reg command with this [Microsoft Windows Documentation].6.
After setting that -restarting explorer- off: This code can close explorer :
Process[] ps = Process.GetProcessesByName("explorer");
foreach (Process p in ps)
p.Kill();

Categories