Delegate getting GC even after pinning? - c#

Related code here: https://github.com/AkazaRenn/FruitLanguageSwitcher/blob/main/Core/Hotkey.cs#L17
Callback code related class:
internal class Hotkey {
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void AHKDelegate();
private readonly AutoHotkeyEngine ahk = AutoHotkeyEngine.Instance;
private readonly List<GCHandle> handles = new();
public Hotkey(AHKDelegate _onCapsLock) {
SetVarOnSettings();
handles.Add(GCHandle.Alloc(_onCapsLock));
ahk.SetVar("onCapsLockPtr", GetActionDelegateStr(_onCapsLock));
ahk.ExecRaw(System.Text.Encoding.Default.GetString(Properties.Resources.CapsLock));
}
~Hotkey() {
foreach(var handle in handles) {
handle.Free();
}
}
Unmanaged code:
$CapsLock::
If (GetKeyState("CapsLock", "T")) {
SetCapsLockState Off
} else {
KeyWait, CapsLock, T0.5
If (ErrorLevel) {
SetCapsLockState On
KeyWait, CapsLock
} else {
DllCall(onCapsLockPtr)
}
}
Return
The actual delegate passed into Hotkey() can be found here: https://github.com/AkazaRenn/FruitLanguageSwitcher/blob/main/App.xaml.cs#L82
The pinned pointer address of the delegates are sent to AHKDLL (unmanaged) for callback. It will work fine at the beginning, but the program will crash after a random period of time (quite a few hours), with such log in Event Viewer:
Application: FruitLanguageSwitcher.exe
CoreCLR Version: 7.0.222.60605
.NET Version: 7.0.2
Description: The application requested process termination through System.Environment.FailFast.
Message: A callback was made on a garbage collected delegate of type 'FruitLanguageSwitcher!FruitLanguageSwitcher.Core.Hotkey+AHKDelegate::Invoke'.
Stack:
Faulting application name: FruitLanguageSwitcher.exe, version: 1.0.0.0, time stamp: 0x638f99ee
Faulting module name: coreclr.dll, version: 7.0.222.60605, time stamp: 0x638f9099
Exception code: 0x80131623
Fault offset: 0x00000000002662d9
Faulting process id: 0x0xFDC
Faulting application start time: 0x0x1D92F3E416B9F1A
Faulting application path: C:\Program Files\WindowsApps\AkazaRenn.82975CBC0BB1_1.2.2.0_x64__fhf2jh1qk9hx4\FruitLanguageSwitcher.exe
Faulting module path: C:\Program Files\WindowsApps\AkazaRenn.82975CBC0BB1_1.2.2.0_x64__fhf2jh1qk9hx4\coreclr.dll
Report Id: 69384484-bd77-4f32-b5f0-6c01c00fb673
Faulting package full name: AkazaRenn.82975CBC0BB1_1.2.2.0_x64__fhf2jh1qk9hx4
Faulting package-relative application ID: App
I've tried doing mashalling and object pinning, as suggested by some other questions in SOF, but none had solved my problem. I'm quite confused now on how to make my delegate actually pinned. Thanks in advance!

To conclude it simply, I don't even need a GCHandle, simply save the delegate as a static variable can do the job, like:
private static readonly List<AHKDelegate> handlers = new();
public Hotkey(AHKDelegate _onCapsLock, AHKDelegate _onLanguageChange, AHKDelegate _onRaltUp) {
handlers.Add(_onCapsLock);
ahk.SetVar("onCapsLockPtr", GetActionDelegateStr(_onCapsLock));
handlers.Add(_onLanguageChange);
ahk.SetVar("onLanguageChangePtr", GetActionDelegateStr(_onLanguageChange));
handlers.Add(_onRaltUp);
ahk.SetVar("onRaltUpPtr", GetActionDelegateStr(_onRaltUp));
}
Thanks to #HansPassant for pointing it out!

Related

Why does .NetFramework console exe program shut down by itself after 1 day idle?

I have a Console application that is ran on the background. Its a simple server that built using NetMQ library and NLogger that works locally.
I ran the program using taskScheduler with the following command schtasks /create /sc ONSTART /tn "TheServer" /tr "C:\\Temp\TheServer.exe" /ru System
As you can se, now it will start every time the desktop is turned on and it will run as System (It means that we can see TheServer.exe is running as background through Task Manager)
Question:
My timeline was like the follows:
My PC was on on Friday morning (starting of Business day - 09:00 in the morning)
I didn't turn off my PC on Friday before I go back from work
Monday morning, I checked my PC and TheServer is already gone
Does anyone know why it happens and how to prevent it?
FYI, I write my code as follows
Program.cs
class Program
{
[STAThread]
static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
...
static void Main(string[] args)
{
try
{
var inst = Server.GetInstance();
inst.Bind();
inst.Run();
}
catch (Exception e)
{
log.Error(e.Message);
log.Error(e.StackTrace);
throw;
}
}
}
Server.cs
class Server
{
private NetMQ.Sockets.ResponseSocket rSocket = new NetMQ.Sockets.ResponseSocket();
static readonly NLog.Logger log = NLog.LogManager.GetCurrentClassLogger();
...
public void Bind()
{
try
{
//bind is only for the Responder or The Server
rSocket.Bind("tcp://127.0.0.1:32325");
}
catch (Exception e)
{
log.Error(e.Message);
log.Error(e.StackTrace);
throw;
}
}
public void Run()
{
while (true)
{
var message = server.ReceiveFrameString();
Console.WriteLine("Received {0}", message);
// processing the request
Thread.Sleep(100);
Console.WriteLine("Sending World");
server.SendFrame("World");
}
}
}
I wrap my code at Program.cs with try-catch. But nothing written in the log
Then
I tried to find some information at the Window's Event Viewer. But there are no related information why TheServer.exe stopped
Update:
Looks like I found what #PMF means.
Then one extra question. . .
Is there any way to do that through command prompt?
I tried to read https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/schtasks-create Looks like if I didn't set the /du when create the task, it will be forever (?). CMIIW
UPDATE
So yes, we decided to recreate this TheServer.exe as Windows Service. Thanks for your input and opinions.

Unhandled exception reading from X509CertificateStore

I'm working with a really old project and moving it from on-prem to an azure VM running windows server 2016 and after the move we noticed an API endpoint returning Bad Gateway (502). I recreated the request using postman and noticed that I didn't even get a response back. After adding a bunch of logging i narrowed it down to the method below where it's suppose to read the security token from a certificate.
It seems like an unhandled exception occurrs just before the code which iterates each certificate but I can't seem to catch the exception using UnhandledExceptionEventHandler.
As far as I can see all the required certificates are in place. The one used here I even gave the user group "Everyone" full access just to just to eliminate that as a possible reason for the error
In reality this method is full of logging for each line of code but I've removed it for readability.
private static X509SecurityToken GetSecurityTokenBySimpleDisplayName(string simpleDisplayName)
{
if (string.IsNullOrEmpty(simpleDisplayName))
throw new ArgumentNullException("simpleDisplayName");
try
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
using (X509CertificateStore store = X509CertificateStore.LocalMachineStore(X509CertificateStore.MyStore))
{
var isOpen = store.OpenRead();
int certIndex = -1;
/***** HERE IS WHERE IT CRASHES *****/
for (int i = 0; i < store.Certificates.Count; i++)
{
if (store.Certificates[i].SimpleDisplayName.ToLower().Equals(simpleDisplayName.ToLower()))
certIndex = i;
}
if (certIndex < 0)
{
throw new SecurityException("Certificate " + simpleDisplayName + " not found");
}
var token = new X509SecurityToken(store.Certificates[certIndex]);
return token;
}
}
catch(Exception ex)
{
// Logging exception
return null;
}
}
public static void MyHandler(object sender, UnhandledExceptionEventArgs args)
{
Exception e = (Exception)args.ExceptionObject;
// Logging exception
}
The application event log gives this error:
Faulting application name: w3wp.exe, version: 10.0.14393.0, time stamp: 0x57899b8a
Faulting module name: KERNELBASE.dll, version: 10.0.14393.3383, time stamp: 0x5ddcba29
Exception code: 0xe0434352
Fault offset: 0x0000000000034c48
Faulting process id: 0x3528
Faulting application start time: 0x01d5f20898415d08
Faulting application path: c:\windows\system32\inetsrv\w3wp.exe
Faulting module path: C:\windows\System32\KERNELBASE.dll
Report Id: 64f16b87-a524-4e0e-9ab9-d8295ce7b29b
Faulting package full name:
Faulting package-relative application ID:
How can I get a better idea of what's wrong?
Found the answer. The application pool needed to be set to "Enable 32-bit application" once that was in place it started working again

C# Error 1053 during start up Windows Service

I have a problem with a Windows Service application.
The application has a timer that every x seconds performs a function.
By testing the application on the local developer PC, the service works correctly.
By testing the service on the Windows Server 2008 compiling also in Release mode, when I start the service I get the following error
Error 1053: The service did not responde to the start or control request in a timely fashion
If I go to check from the server event viewer I get this information
Below I leave my little snippet of code
private const int TICK_TIMER = 120000; //Start timer every 2 minutes
private Timer readTimer = null;
public BarcodeReader()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
readTimer = new Timer();
readTimer.Interval = TICK_TIMER;
readTimer.Elapsed += readTimer_Tick;
readTimer.Enabled = true;
WriteLog("Servizio Barcode started");
}
private void readTimer_Tick(object sender, ElapsedEventArgs e)
{
//Start function
try
{
MyFunction();
}
catch (Exception ex)
{
WriteLog("ERROR: " + ex.Message);
}
}
private void WriteLog(string mex)
{
try
{
//sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\LogFile.txt", true);
using (var sw = new StreamWriter(Globals.LogPath + "LogBarcodeService.txt", true))
{
sw.WriteLine(DateTime.Now.ToString(CultureInfo.CurrentCulture) + ": " + mex);
sw.Flush();
sw.Close();
}
}
catch (Exception)
{
throw;
}
}
protected override void OnStop()
{
readTimer.Enabled = false;
WriteLog("Servizio Barcode terminated");
}
N.B. On the server NET Framework 4.5 is installed as on the Developer PC
UPDATE
This is the call to the InitializeComponent function
namespace BarcodeReaderService
{
partial class BarcodeReader
{
/// <summary>
/// Variabile di progettazione necessaria.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Pulire le risorse in uso.
/// </summary>
/// <param name="disposing">ha valore true se le risorse gestite devono essere eliminate, false in caso contrario.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Codice generato da Progettazione componenti
/// <summary>
/// Metodo necessario per il supporto della finestra di progettazione. Non modificare
/// il contenuto del metodo con l'editor di codice.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ServiceName = "Service1";
}
#endregion
}
}
UPDATE 2
I tried to bring all the code into an application console and run them smoothly on the server.
The solution should be to include everything from your output directory (e.g. bin\Debug) to copy to a certain folder on your server. From there you run InstallUtil to register the service.
Another way would be to create an installer for the Windows Service.
One thing to check would be the .Net framework version between your development machine and the Server.
We faced a similar issue when our development machine had .Net 4.7 (the latest one as of now) and the Server had 4.5.
In our case, we also had the following logged in our event viewer
First exception
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.IO.FileLoadException
Second exception entry
Faulting module name: KERNELBASE.dll, version: 6.3.9600.18340, time stamp: 0x5736541b
Exception code: 0xe0434352
Fault offset: 0x00014878
You can use this guide to find the exact version:
https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/how-to-determine-which-versions-are-installed
Please also note that the later versions are in-place upgrades ! So once you have the newest version, there is no way to go back to the old version !
https://learn.microsoft.com/en-us/dotnet/framework/install/guide-for-developers
The fact that later .NET Framework 4.x versions are in-place updates to earlier versions means that you cannot install an earlier version listed in the table if a later version is already installed

Update the interface in the secondary process

I'm using selenium to perform the automation of a web task and I'm generating a simple log ... However, I would like to "unlock" the interface for the log to be inserted in real time and not at the end of the whole process.
Simple log:
void log(string texto)
{
listBox1.Invoke((MethodInvoker)delegate
{
listBox1.Items.Add(string.Format("{0} - {1}", DateTime.Now.ToString(), texto));
});
}
How im using:
//Selenium Code Here (eg.: driver = new ChromeDriver();)
log("ChromeDriver Started!");
But nothing happens, the interface keeps being updated at the end of every process.

Handling Global Exception Xamarin | Droid | iOS

We all know that mobile is compact platform where we have to look lots of things while building an application. It could be anything e.g. Memory Performance Resolutions Architecture Implementation etc. We never know when and what causes app crash a big ISSUE while playing with the app, It could happen anytime
e.g. App Launch, Load Screen, API Call, Binding Data, Loading Images etc.
And trust me sometime its really hard to find where and what cause an issue in app. I saw many post on forums, tech community and groups which is related to the same issue, where peoples usually asking questions as:
App Crashing at launching.
App Crash at Splash Screen loading.
App Crash while Image showing.
App Crashing while binding data from api.
How to identify issue and where it causes?
Purpose: Our purpose here to grab an exception's stack trace data that help us to identify what exactly causes the issue whether in Release Mode or Debug Mode. We will be able to understand the issue and the reason that causes it. We will store this data in a text file that will be store in device storage.
Solution: Alternatively you can make your own insight grabber that will give you you app insight and clue if something went wrong while testing the app. Its will be your, you can tweak like you want. let's dive to try{} and catch{} globally.
Create a Helper Class file that has a method to generate a Text file for exception data.
public static class ExceptionFileWriter
{
#region Property File Path
static string FilePath
{
get
{
string path = string.Empty;
var _fileName = "Fatal.txt";
#if __IOS__
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); // Documents folder C:\ddddd
string libraryPath = Path.Combine(documentsPath, "..", "Library"); // Library folder C:\dddd\...\library
path = Path.Combine(libraryPath, _fileName); //c:\ddddd\...\library\NBCCSeva.db3
#else
#if __ANDROID__
string dir = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.ToString(), "Exception");
if (Directory.Exists(dir))
return Path.Combine(dir, _fileName);
path= Path.Combine(Directory.CreateDirectory(dir).FullName, _fileName);
#endif
#endif
return path;
}
}
#endregion
#region ToLog Exception
public static void ToLogUnhandledException(this Exception exception)
{
try
{
var errorMessage = String.Format("Time: {0}\r\nError: Unhandled Exception\r\n{1}\n\n", DateTime.Now, string.IsNullOrEmpty(exception.StackTrace) ? exception.ToString() : exception.StackTrace);
File.WriteAllText(FilePath, errorMessage);
}
catch (Exception ex)
{
// just suppress any error logging exceptions
}
}
#endregion
}
Time to implement code: Subscribe following events inside your app's Application file or Splash Activity. I'm using Application in this case.
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;
[Application]
public class ExceptionHandlingApp : Application
{
#region Constructor
public ExceptionHandlingApp(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
#endregion
#region OnCreate
public override void OnCreate()
{
base.OnCreate();
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
TaskScheduler.UnobservedTaskException += TaskSchedulerOnUnobservedTaskException;
}
#endregion
#region Task Schedular Exception
private static void TaskSchedulerOnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs unobservedTaskExceptionEventArgs)
{
var newExc = new Exception("TaskSchedulerOnUnobservedTaskException", unobservedTaskExceptionEventArgs.Exception);
newExc.ToLogUnhandledException();
}
#endregion
#region Current Domain Exception
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
var newExc = new Exception("CurrentDomainOnUnhandledException", unhandledExceptionEventArgs.ExceptionObject as Exception);
newExc.ToLogUnhandledException();
}
#endregion
}
Note: You can find exceptions record file in Device Storage | File Manager > Exception Folder > fatal.txt
Cheers!!
Beside of doing it on your own you can also use Xamarin.Insights as it is free to use for Xamarin users and has got implementations for all platforms.
You receive usage reports, crash reports etc. online without the need for the user to send you a log file manually.
The only thing you need to do to receive crash reports is to initialize Xamarin.Insights on startup of your app:
Insights.HasPendingCrashReport += (sender, isStartupCrash) =>
{
if (isStartupCrash) {
Insights.PurgePendingCrashReports().Wait();
}
};
Insights.Initialize("Your API Key");

Categories