I have a small function I want called when my process exits, however, upon closing (via the red exit button) the function will not execute.
My code is as follows:
namespace Client
{
class Program
{
static void Main(string[] args)
{
var callback = new InstanceContext(new ClientCallback());
var client = new MyServiceClient(callback);
client.Open();
client.Register();
AppDomain.CurrentDomain.ProcessExit += (sender, EventArgs) =>
{
client.checkOut();
};
Console.WriteLine("Press a key to exit");
Console.ReadKey();
client.checkOut();
client.Close();
}
}
}
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
HandlerRoutine hr = new HandlerRoutine(InspectControlType);
SetConsoleCtrlHandler(hr, true);
Console.WriteLine("Click on Windows Close Button");
Console.ReadLine();
}
[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
public delegate bool HandlerRoutine(ControlTypes CtrlType);
public enum ControlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
private static bool InspectControlType(ControlTypes ctrlType)
{
Console.WriteLine("Hello You choose to end this program.Do you really want to close? :" + ctrlType.ToString());
Console.ReadLine();
return true;
}
}
}
Source
Related
I've got an hybrid application with either console or WPF functionality. If the WPF application is started or something is done in console window depends on the arguments at start up. I were able to implement this (there are a lot of examples to find at stackoverflow). Now I want that, if the WPF application is started, that the console window will be closed. But this is shown and if I close it, the WPF application is also closed.
This is my current implementation.
using System;
using System.Windows;
namespace MyNamespace
{
class Program
{
[STAThread]
static void Main(string[] args)
{
string option = args[0];
switch (option)
{
case "WPF":
RunApplication();
break;
default:
DoSomething();
break;
}
}
private static void RunApplication()
{
Application app = new Application();
app.Run(new MainWindow());
Environment.Exit(0);
}
private static void DoSomething()
{
// …
}
}
}
If I try to start the application in a new Thread the application is directly closed and the WPF window will not be shown.
using System.Threading;
using System.Threading.Tasks;
private static void RunApplication()
{
new Thread(() => {
Application app = new Application();
app.Run(new MainWindow());
}).Start();
Environment.Exit(0);
}
I have no idea how I could implement this. Is there a possibility to do this?
I could find a solution. According of the accepted answer of this post Show/Hide the console window of a C# console application I hide the console window.
using System;
using System.Runtime.InteropServices;
using System.Windows;
namespace DeploymentPreparer
{
class Program
{
[STAThread]
static void Main(string[] args)
{
string option = args[0];
switch (option)
{
case "WPF":
RunApplication();
break;
default:
DoSomething();
break;
}
}
private static void RunApplication()
{
ShowWindow(GetConsoleWindow(), SW_HIDE);
Application app = new Application();
app.Run(new MainWindow());
}
private static void DoSomething()
{
// ...
}
[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;
}
}
Now I have either the console or the WPF window. If the WPF window is shown the console window is hidden.
I tried the following method that seems to work:
Create a normal Console App. In case of "WPF" argument start the WPF application as a new process. In case of any other argument - call DoSomething()
Example:
using System;
using System.Diagnostics;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
string option = "";
if (args.Length > 0)
{
option = args[0];
}
switch (option)
{
case "WPF":
try
{
using (Process myProcess = new Process())
{
myProcess.StartInfo.UseShellExecute = false;
// Use correct path to the WPF Application
myProcess.StartInfo.FileName = #"C:\Users\Danny\Source\Repo\WpfApp\bin\Debug\WpfApp.exe";
myProcess.Start();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine("Press any key to continue ...");
Console.ReadKey();
}
break;
default:
DoSomething();
break;
}
}
private static void DoSomething()
{
// …
Console.WriteLine("Doing Something ...");
Console.WriteLine("Press any key to continue ...");
Console.ReadKey();
}
}
}
I'd like to Run Code on Application Exit. My Problem is that I have two Application. The First is running. My Second Application now is going to Close the First Application. But on Closing I'd like to run code in the First Application.
public class First
{
public static Main(string[] args)
{
Console.ReadLine();
}
public void DoSomethingOnExit()
{
Console.WriteLine("It Works");
Thread.Sleep(1000);
}
}
public class Second
{
public void method(int number)
{
var prozess = Process.GetProcessById(number);
prozess.Close();
}
}
Try this...
static void Main(string[] args)
{
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
Console.WriteLine("Running");
Console.ReadLine();
}
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig)
{
switch (sig)
{
case CtrlType.CTRL_C_EVENT:
case CtrlType.CTRL_LOGOFF_EVENT:
case CtrlType.CTRL_SHUTDOWN_EVENT:
case CtrlType.CTRL_CLOSE_EVENT:
DoSomeShutdownStuff();
return true;
default:
return false;
}
}
I'm new at C# programming and i'm lost with a thing that could be simple.
Executing a console application, at a moment i need to call a Windows Form that will show statics of the execution but when i call the form1.ShowDialog(); this stop the console runtime.
How do i keep my console execution alive while i show a Windows form screen ?
class Program
{
static Form1 form = new Form1();
public static bool run = true;
static void Main(string[] args)
{
work();
}
public static void work()
{
form.Show();
while (run)
{
Console.WriteLine("Console still running");
}
}
}
try this it work on me
using System.Windows.Forms;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public static bool run = true;
static void Main(string[] args)
{
Startthread();
Application.Run(new Form1());
Console.ReadLine();
}
private static void Startthread()
{
var thread = new Thread(() =>
{
while (run)
{
Console.WriteLine("console is running...");
Thread.Sleep(1000);
}
});
thread.Start();
}
}
}
Threading is like "process inside a process" in my own understanding.
See this question. You have to use Form1.Show() because Form1.ShowDialog() pauses execution until the form is closed.
Update This seems to be working (with Application.Run):-
public static Form1 form = new Form1();
public static bool run = true;
[MTAThread]
static void Main(string[] args)
{
new Thread(() => Application.Run(form)).Start();
new Thread(work).Start();
}
public static void work()
{
while (run)
{
Console.WriteLine("Console Running");
}
}
I wrote this little program to demonstrate the point of the question:
using System;
using System.IO;
using System.Threading;
class Program
{
static void Main(string[] args)
{
using (var disp = new MyDisp())
{
using (var ewhLocalExit = new EventWaitHandle(false, EventResetMode.ManualReset))
{
Console.WriteLine("Enter Ctrl+C to terminate the app.");
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
ewhLocalExit.Set();
};
ewhLocalExit.WaitOne();
}
}
File.AppendAllText("Log.txt", "Terminated.\n");
}
}
class MyDisp : IDisposable
{
public MyDisp()
{
File.AppendAllText("Log.txt", "Started.\n");
}
public void Dispose()
{
File.AppendAllText("Log.txt", "Disposed.\n");
}
}
When I run it and press Ctrl+C, I see "Started.Disposed.Terminated." in Log.txt
When I run it and close it with the mouse, I see only "Started."
How do I make exit gracefully, so that I at least could see "Disposed." ?
You can use DLLImport to import SetConsoleControlHandler and use it to register an event handler for the closed event (and others), here's an example snippet that shows it working (it will write closed in Log.txt whem you click the X to close the console):
class Program
{
[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
// A delegate type to be used as the handler routine
// for SetConsoleCtrlHandler.
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
// An enumerated type for the control messages
// sent to the handler routine.
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
if (ctrlType == CtrlTypes.CTRL_CLOSE_EVENT)
File.AppendAllText(#"Log.txt", "closed");
return true;
}
private static void Main(string[] args)
{
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
Console.WriteLine("Close me");
Console.ReadLine();
}
}
Source
When you close your console app with the mouse by clicking the X button you are asking to have the process killed.
The Wi32 api has a SetConsoleControlHandler that allows you to specify a handler for when various things happen. If the handler is called with CTRL_CLOSE_EVENT then you know that someone is trying to kill your application.
There's an example of how to use this API here
I have a simple server application running as a console application, which works great! But now I want to hide the console window and keep the application running in the background.
If I set the application Output Type to Windows Application, the program seems to run and then close immediately. It's quite frustrating... How can I stop the console app closing but still have it hidden?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using Eneter.Messaging.EndPoints.TypedMessages;
using Eneter.Messaging.MessagingSystems.MessagingSystemBase;
using Eneter.Messaging.MessagingSystems.TcpMessagingSystem;
using System.Threading;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
public class MyRequest
{
public string Text { get; set; }
}
public class MyResponse
{
public string Text { get; set; }
}
class Program
{
private static IDuplexTypedMessageReceiver<MyResponse, MyRequest> myReceiver;
[STAThread]
static void Main(string[] args)
{
IDuplexTypedMessagesFactory aReceiverFactory = new DuplexTypedMessagesFactory();
myReceiver = aReceiverFactory.CreateDuplexTypedMessageReceiver<MyResponse, MyRequest>();
myReceiver.MessageReceived += OnMessageReceived;
IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
IDuplexInputChannel anInputChannel = aMessaging.CreateDuplexInputChannel("IP ADDRESS:8060/");
myReceiver.AttachDuplexInputChannel(anInputChannel);
Console.WriteLine("The service is running. To stop press enter.");
Console.ReadLine();
myReceiver.DetachDuplexInputChannel();
}
private static void OnMessageReceived(object sender, TypedRequestReceivedEventArgs<MyRequest> e)
{
Console.WriteLine("Received: " + e.RequestMessage.Text);
if (e.RequestMessage.Text == "Connect")
{
String computerName = System.Environment.MachineName.ToString();
MyResponse aResponse = new MyResponse();
aResponse.Text = "Connected to:\n" + computerName;
myReceiver.SendResponseMessage(e.ResponseReceiverId, aResponse);
ExecuteCommandSync("Do My CMD");
//Display connection notification
new System.Threading.Thread(() => { System.Windows.Forms.Application.Run(new Form1()); }).Start();
}
else
{
MyResponse aResponse = new MyResponse();
aResponse.Text = "Server Not Connected";
myReceiver.SendResponseMessage(e.ResponseReceiverId, aResponse);
ExecuteCommandSync("Stop My Command");
}
}
public static void ExecuteCommandSync(object command)
{
try
{
var procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = false;
var proc = new System.Diagnostics.Process();
proc.OutputDataReceived += (s, e) => { Console.WriteLine(e.Data); };
proc.StartInfo = procStartInfo;
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
catch (Exception objException)
{
Console.WriteLine("Error: " + objException.Message);
}
}
}
Solved:
class Program
{
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void Main(string[] args)
{
IntPtr h = Process.GetCurrentProcess().MainWindowHandle;
ShowWindow(h, 0);
while (true)
{
System.Threading.Thread.Sleep(1);
IDuplexTypedMessagesFactory aReceiverFactory = new DuplexTypedMessagesFactory();
myReceiver = aReceiverFactory.CreateDuplexTypedMessageReceiver<MyResponse, MyRequest>();
myReceiver.MessageReceived += OnMessageReceived;
IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
IDuplexInputChannel anInputChannel = aMessaging.CreateDuplexInputChannel("tcp://192.168.1.74:8060/");
myReceiver.AttachDuplexInputChannel(anInputChannel);
Console.WriteLine("The service is running. To stop press enter.");
Console.ReadLine();
myReceiver.DetachDuplexInputChannel();
}
}
}
Just converting your app to a Windows app won't achieve your goal.
I recommend you either just handle minimizing your app to the taskbar where it will continue to run in the background or, perhaps, convert your app to a Windows Service.