NullReferenceException on managing close event of theconsole - c#

this is my scenario: I have a console application and I'm trying to handle the "close event" of the console with this code:
static void Main(string[] args)
{
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
.......
}
[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
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)
{
writeOnLogFile("Closed Manually");
logWriter.WriteLine();
logWriter.WriteLine();
logWriter.Close();
return true;
}
Sometimes, when I close the console with the "X" button, this is the page that is shown to me: No Source available.
I try to look in the stack call, but there is nothing that is useful.
So, how i can resolve this?

I managed to solve this problem changing my code:
Before
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
static void Main(string[] args)
{
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);
.......
}
After
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
public static HandlerRoutine rout = new HandlerRoutine(ConsoleCtrlCheck);
static void Main(string[] args)
{
SetConsoleCtrlHandler(rout, true);
.......
}
Initizialing an "HandlerRoutine" before it works perfectly.
Thank you anyway! I hope it can be useful to someone!

Look, whether the handler is really attached every time.
This looks, as if the handler is not always properly attached.
Do You have a log entry, when this exception occurrs ?

Related

C# Monitor Clipboard changes console

I am working on a console application that is supposed to catch the event when the clipboard content changes. There is an API in WinRT for this, Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged. I have already tested this on a WinForms and WPF application, and it works perfectly. However I am experiencing problems when doing this in a console application. The code is pretty basic. When doing it on a WinForms application, I simply write this line of code:
public MyApp()
{
InitializeComponent();
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;
}
public async void OnClipboardChanged(Object sender, Object e)
{
MyCodeHere
}
However when trying to do the same in my console application:
class Program
{
[STAThread]
static void Main(string[] args)
{
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += OnClipboardChanged;
}
public static void OnClipboardChanged(Object sender, Object e)
{
Console.WriteLine("Hello");
}
}
Yet the console just exits after starting it. If I put "Console.ReadKey" then it still errors but does not exit. Neither way invokes the event I have written in Main. I want the console to be running and not end, even if there is a clipboard change. So it should constantly run in the background, and everytime the clipboard changes then it should just WriteLine a "Hello" to the console. I have gone through all the other answers but none of them works for me, because they want to manipulate the clipboard whereas I am invoking an event on the content change of the clipboard. Thanks for all the help!
Another question, will there be any perfomance difference if I use C++/winRT instead?
In a console context, you must ensure windows messages are processed as clipboard depends on it, so for example, you can use Winforms' DoEvents method (if you don't have a real window and nothing pumps messages):
class Program
{
static void Main()
{
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += (s, e) => Console.WriteLine("ContentChanged");
Console.WriteLine("Press any key to quit");
do
{
System.Windows.Forms.Application.DoEvents();
if (Console.KeyAvailable)
break;
Thread.Sleep(100); // for example
}
while (true);
}
}
To enable Winforms support in a .NET 5 Console project, here is the simplest way of doing it (you don't even need to add the Windows.SDK nuget package), just modify the .csproj to something like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0-windows10.0.19041.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
</PropertyGroup>
</Project>
If you don't have .NET 5, or don't want to reference Winforms, then you can declare your own message pump using P/Invoke, like this:
class Program
{
[STAThread]
static void Main()
{
Windows.ApplicationModel.DataTransfer.Clipboard.ContentChanged += (s, e) => Console.WriteLine("ContentChanged");
Console.WriteLine("Press any key to quit");
do
{
while (GetMessage(out var msg, IntPtr.Zero, 0, 0) != 0)
{
TranslateMessage(ref msg);
DispatchMessage(ref msg);
}
if (Console.KeyAvailable)
break;
Thread.Sleep(100);
Console.Write(".");
}
while (true);
}
[StructLayout(LayoutKind.Sequential)]
private struct MSG
{
public IntPtr hwnd;
public int message;
public IntPtr wParam;
public IntPtr lParam;
public int time;
public POINT pt;
public int lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[DllImport("user32")]
private static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, int wMsgFilterMin, int wMsgFilterMax);
[DllImport("user32")]
private static extern bool TranslateMessage(ref MSG lpMsg);
[DllImport("user32")]
private static extern IntPtr DispatchMessage(ref MSG lpmsg);
}

Is it possible to execute C# callbacks to unmanaged function in a thread?

This is a follow-up question about this. Basically I am trying to send C# callback to a Python Module using a C++ wrapper. the issue is, since the main method, is a blocking method (a while loop that keeps dispatching the information to the callbacks. The issue is, it's so fast the C# GUI can't cope with it and thus gets unresponsive.
I tried using a timer Tick() event to display the information every second, but it seems the callback exhausts the process so much so that the timer itself can't output. I even tried using a thread to execute the callback, but that fails as well meaning, the application continues to be unresponsive.
My question is, Is there something that I can do to rectify this from C# side? for example can we make the callback somehow run in a separate thread that doesn't make the application unresponsive?
Update
Here are some more information (taken from the linked question):
My DllImport are as follows:
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Initialize(bool showFeed);
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Start(bool async);
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void Stop();
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetCpuAffinity(int mask);
public delegate void CallbackDelegate(bool status, string message);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void AddCallback(IntPtr fn);
[DllImport(#"Core_DLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void RemoveCallback(IntPtr fn);
And this is my C# callback:
private CallbackDelegate del;
public void SetUpCallback()
{
txtLog.Text += "Registering C# callback...\r\n";
del = new CallbackDelegate(callback01);
AddCallback(Marshal.GetFunctionPointerForDelegate(del));
txtLog.Text += "Calling passed C++ callback...\r\n";
}
bool status;
string id;
public void callback01(bool status, string id)
{
this.status = status;
this.id = id;
}
Basically, when you call Start() the main loop starts, and the callback gets called indirectly.
If I try to run the Start using a thread, I get no more callback output:
Thread t;
private void btnRunService_Click(object sender, EventArgs e)
{
tmrFetchStatus.Start();
//Start(chkboxAsync.Checked);
t = new Thread(new ThreadStart(() =>
{
RunService();
}));
t.IsBackground = true;
t.Start();
}
void RunService()
{
Start(chkboxAsync.Checked);
if (txtLog.InvokeRequired)
{
txtLog.Invoke(new MethodInvoker(()=>
{
txtLog.Text += "OK";
}));
}
else
{
txtLog.Text += "OK";
}
}
As commented, the threading issue was caused because the Start method wasn't called on the same thread as the AddCallback method.
When working with dependant interop calls (or actually dependant calls in general) it's best to stay on the same thread unless you know it doesn't matter.

Hooking to a C++ DLL event form C#

I want to hook a C# method to a C++ event written in the C++ DLL
C++ side
#include
extern "C"
{
typedef void (__stdcall *PFN_MYCALLBACK)();
int __stdcall MyUnmanagedApi(PFN_MYCALLBACK callback);
}
C# side
public delegate void MyCallback();
[DllImport("data_acquisition_sys.dll")]
public static extern void MyUnmanagedApi(MyCallback callback);
static void Main(string[] args) {
MyUnmanagedApi(
delegate()
{
Console.WriteLine("Called back by unmanaged side");
}
);
}
}
I followed the http://blogs.msdn.com/b/davidnotario/archive/2006/01/13/512436.aspx
Error
Unhandled Exception: System.EntryPointNotFoundException: Unable to find an entry point named 'MyUnmanagedApi' in DLL 'data_acquisition_sys.dll'. at affect_detection_sys.Program.MyUnmanagedApi(MyCallback callback) at affect_detection_sys.Program.Main(String[] args) in C:\Users\Public\Docume
For all interested parties, here is a working solution to the problem.
C++ side
extern "C"
{
typedef void (*callback_function)();
callback_function gCBF;
__declspec(dllexport) void StartAcquisition(callback_function callback) {
gCBF = callback;
cout << "Acquisition started" << endl;
}
void DoWork() {
gCBF()
}
}
C# side
[DllImport("data_acquisition_sys.dll", EntryPoint = "StartAcquisition")]
public static extern void StartAcquisition(MyCallback callback);
StartAcquisition(delegate()
{
Console.WriteLine("Called back by unmanaged side ");
}
);
Note that the callback_function is an empty method (), since returning and accepting back ANY data results in a runtime crash. This has been reported in other threads, but the answer hasn't been given.
MyUnmanagedApi returns int and you have declared void. Try this:
public delegate void MyCallback();
[DllImport("data_acquisition_sys.dll")]
public static extern int MyUnmanagedApi(MyCallback callback);
static void Main(string[] args) {
MyUnmanagedApi(
delegate()
{
Console.WriteLine("Called back by unmanaged side");
}
);
}
}

Capture console exit C# in windows 7

Does anyone know how to react to the ctrl+c event in a console in c# in windows?
this question: Capture console exit C# says how to do it, but I've tried and it only captures the event when the user click the close X in the top of the console window.
Nothing happens when the user types ctrl+c, it doesn't even hit the handler when debugging.
Thanks
Here is my code
namespace EventCloseConsole
{
using System.Runtime.InteropServices;
using System;
class Program
{
[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:
Console.WriteLine("Closing");
System.Threading.Thread.Sleep(500);
return false;
default:
return true;
}
}
static void Main(string[] args)
{
_handler += new EventHandler(Handler);
SetConsoleCtrlHandler(_handler, true);
Console.ReadLine();
}
}
}
That works for me on Windows 7. Closing with x-button
the secret is the variable static ConsoleEventDelegate _d
private static void Main(string[] args)
{
ConsoleEventHooker.Closed += ConsoleEventHooker_Closed;
}
static void ConsoleHooker_Closed(object sender, EventArgs e)
{
}
ConsoleEventHooker.cs
namespace System
{
internal static class ConsoleEventHooker
{
private static bool _initedHooker;
private static EventHandler _closed;
private static EventHandler _shutdown;
private static ConsoleEventDelegate _d;
public static event EventHandler Closed
{
add
{
Init();
_closed += value;
}
remove { _closed -= value; }
}
public static event EventHandler Shutdown
{
add
{
Init();
_shutdown += value;
}
remove { _shutdown -= value; }
}
private static void Init()
{
if (_initedHooker) return;
_initedHooker = true;
_d = ConsoleEventCallback;
SetConsoleCtrlHandler(_d, true);
}
private static bool ConsoleEventCallback(CtrlTypes eventType)
{
if (eventType == CtrlTypes.CTRL_CLOSE_EVENT)
{
if(_closed != null) _closed(null,new EventArgs());
}
if (eventType == CtrlTypes.CTRL_SHUTDOWN_EVENT)
{
if (_shutdown != null) _shutdown(null, new EventArgs());
}
return false;
}
// A delegate type to be used as the handler routine
// for SetConsoleCtrlHandler.
delegate bool ConsoleEventDelegate(CtrlTypes ctrlType);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(ConsoleEventDelegate callback, bool add);
}
// 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
}
You need to wire up the Console.CancelKeyPress event to a handler. Here is a great article on the topic.

Override Console Close

I know the GUI has private void Form1_Closing(object sender, System.ComponentModel.EventArgs e)
{
//do stuff
}
But how can i do the same thing in a console application?
C#/.NET3.5
Here's how:
// Declare the SetConsoleCtrlHandler function
// as external and receiving a delegate.
[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)
{
// Put your own handler here
return true;
}
...
SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

Categories

Resources