Question Unexpected NullReferenceException caught in Global Exception Handler

mr.prateekg

Member
Joined
Oct 22, 2021
Messages
7
Programming Experience
3-5
We have developed a windows forms application that captures user interactions i.e. Typed text, clicks. Sometimes, out of the blue on some machine, we get the following exception:

Object reference not set to an instance of an object.

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at Recorder.Program.GlobalExceptionHandler(Object sender, UnhandledExceptionEventArgs args)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at Recorder.Program.Main(String[] args)

The issue is not replicated in Development or Testing environment, but occurs in release. Though all our code is covered with exception handling, the above error occurs in the main method and gets caught in the GlobalExcptionHandler. The exception has no details nor stack trace.

ExceptionMessage - Object reference not set to an instance of an object.
ExceptionSource -
ExceptionTarget -
StackTrace - Logging Stack Trace is disabled

I tried to look up the issue online, found the following links those seems similar, but again with no solutions :

Pragmatic Solutions For An Imperfect World

Somebody Help ME With this error plz!

Usually we have noticed, it gets crashed soon after installing the product, or when resource-intensive applications are running i.e. MS Teams, MS Excel

Please guide!
 
Based on the callstack, it looks like you maybe accessing the Office Object Model. If you are doing any kind of COM InterOp, and particularly, if you are doing COM InterOp with Office, you have to be scrupulously paranoid about managing the objects and interfaces. Basically, you have to forget that you are writing C# code, and fallback to as if you were writing C++ or C code where everything needs to be allocated and freed in the right order, the right context, and the right thread.

Another thing I would look at closely is of your code is accidentally re-entrant. This most often happens when people take ancient bad advice from VB programmers who is say "You're code hanging or freezing? Thrown in a DoEvents call in there." Unfortunately, people apply the same advice into their C# and VB.NET code and not realize the re-entrancy implications of doing this, as well as, how hard it will be to reproduce and debug these issues.
 
Based on the callstack, it looks like you maybe accessing the Office Object Model. If you are doing any kind of COM InterOp, and particularly, if you are doing COM InterOp with Office, you have to be scrupulously paranoid about managing the objects and interfaces. Basically, you have to forget that you are writing C# code, and fallback to as if you were writing C++ or C code where everything needs to be allocated and freed in the right order, the right context, and the right thread.

Another thing I would look at closely is of your code is accidentally re-entrant. This most often happens when people take ancient bad advice from VB programmers who is say "You're code hanging or freezing? Thrown in a DoEvents call in there." Unfortunately, people apply the same advice into their C# and VB.NET code and not realize the re-entrancy implications of doing this, as well as, how hard it will be to reproduce and debug these issues.

Hey @Skydiver

Thanks for the prompt response. Yes, I am using Microsoft.Office.Interop.Excel along with Gma.System.MouseKeyHook. Can that be the problem?
 
Just like in the links that your originally posted, you'll have to do the detective work to try to narrow down where an object is unexpectedly being garbage collected.

I my personal experience, it's people playing fast and loose with COM objects that primarily get them into trouble. It's only secondary that they accidentally declare an object in a scope that is shorter lived than the logic that needs it -- the logic thinks the object should still be alive, but from the point of view of the garbage collector, there are no more references and so the object can die.

But there may also be a bug in that mouse key hook library that you are using. Usually making sure that you have the latest version and checking the known issues for the libraries that you use may help.
 
Hi @Skydiver ,

We tried above approach and looked into object creation and disposing. In the process, we tried with debug build on one target system and was able to get more information on exception. Seems like you were correct, it has something to do with Global Mouse Hook. Can you please review the following:

Object reference not set to an instance of an object.

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at WinRecorder.Program.GlobalExceptionHandler(Object sender, UnhandledExceptionEventArgs args)
at UIAutomationClient.CUIAutomationClass.ElementFromPointBuildCache(tagPOINT pt, IUIAutomationCacheRequest cacheRequest)
at UIAutomationClient.CUIAutomationClass.ElementFromPointBuildCache(tagPOINT pt, IUIAutomationCacheRequest cacheRequest)
at System.Windows.Automation.AutomationElement.FromPoint(Point pt)
at WinRecorder.WinAutomationRecorder.CheckAdditionalControlNames(Point cPoint, Process ctrlProc)
at WinRecorder.WinAutomationRecorder.M_GlobalHook_MouseDown(Object sender, MouseEventArgs e)
at Gma.System.MouseKeyHook.Implementation.MouseListener.OnDown(MouseEventArgs e)
at Gma.System.MouseKeyHook.Implementation.MouseListener.ProcessDown(MouseEventExtArgs& e)
at Gma.System.MouseKeyHook.Implementation.GlobalMouseListener.ProcessDown(MouseEventExtArgs& e)
at Gma.System.MouseKeyHook.Implementation.MouseListener.Callback(CallbackData data)
at Gma.System.MouseKeyHook.WinApi.HookHelper.HookProcedure(Int32 nCode, IntPtr wParam, IntPtr lParam, Callback callback)
at Gma.System.MouseKeyHook.WinApi.HookHelper.<>c__DisplayClass4.<HookGlobal>b__3(Int32 code, IntPtr param, IntPtr lParam)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at WinRecorder.Program.Main(String[] args)

I did a little search in Google and found out the following link :
Crash in MouseKeyHook

We are using Gma.System.MouseKeyHook and have its latest version installed. Does this seems to be the root cause?
 
From what I can see there, it seems like the crash is in WinRecoder.Program rather than in GMA.
 
From what I can see there, it seems like the crash is in WinRecoder.Program rather than in GMA.
WinRecorder.Program is the driver class to run the code. Here is code for your reference:


C#:
        [STAThread]
        [HandleProcessCorruptedStateExceptions]
        static void Main(string[] args)
        {
            try
            {
                AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(GlobalExceptionHandler);

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new WinRecorder());
            }
            catch (Exception ex)
            {
                //Log Exception
            }
        }

The link that I am referring to in previous post has a comment that says something about GC collecting the hook object.
 
Out of curiosity, why do you even need to use that library that uses global mouse and keyboard hooks? If you all you need is hot key functionality, you could use a smaller hammer instead of a sledgehammer approach taken by the library.

Anyway, are you keeping their object alive throughout your program's lifetime? Or are you just using their quickstart sample that calls the Hook.GlobalEvents() just long enough to register? It looks like their README.md shows the proper way to keep the object alive.
 
Out of curiosity, why do you even need to use that library that uses global mouse and keyboard hooks? If you all you need is hot key functionality, you could use a smaller hammer instead of a sledgehammer approach taken by the library.

Anyway, are you keeping their object alive throughout your program's lifetime? Or are you just using their quickstart sample that calls the Hook.GlobalHooks() just long enough to register? It looks like their README.md shows the proper way to keep the object alive.
Two reasons : Legacy codebase and automation. We are into automation domain (Process Discovery) and have to record important user interactions i.e. Keyboard and mouse.

We are keeping their object throughout program's lifetime. As soon as program starts, we register the hooks similar to their Subscribe method. It keeps on running till application runs. The project structure is similar to this :
globalmousekeyhook/examples/FormsExample at vNext · gmamaladze/globalmousekeyhook

Currently the hook object is private
private IKeyboardMouseEvents m_Events;
in WinRecorder class scope, could making it static help?
 
have to record important user interactions i.e. Keyboard and mouse.
In other words, nannyware and keylogging. You're in the one of the industries that I hate... <sarcasm>Why not DLL inject your code into every running application while you are at it?</sarcasm>

Anyway, I doubt that using using static to keep their object alive will help unless your main window is actually closed and disposed, or if the crash you are seeing is happening at the time that your application is shutting down. If it's when your app is shutting down, you may want to move the m_events variable into your Program.cs.

Also consider the object hosts your handler for the events. How are you keeping your object(s) alive? As I found out long ago (while playing with the DataGridView), merely subscribing to a event doesn't actually keep my object that hosts the event handler code alive. I had to pay attention to object lifetimes.
 
In other words, nannyware and keylogging. You're in the one of the industries that I hate... <sarcasm>Why not DLL inject your code into every running application while you are at it?</sarcasm>

Anyway, I doubt that using using static to keep their object alive will help unless your main window is actually closed and disposed, or if the crash you are seeing is happening at the time that your application is shutting down. If it's when your app is shutting down, you may want to move the m_events variable into your Program.cs.

Also consider the object hosts your handler for the events. How are you keeping your object(s) alive? As I found out long ago (while playing with the DataGridView), merely subscribing to a event doesn't actually keep my object that hosts the event handler code alive. I had to pay attention to object lifetimes.
<sarcasm>A man has to work and earn :p </sarcasm>

Crash usually occurs in middle of program execution or as soon as we start our program (mostly with teams/excel running). Haven't noticed it during closing yet. Have made some changes according to Readme file for scope management. Will update you soon.
 
Yup, I agree. At one point, I considered working for a company that helps make nuclear weapons, so I can't really throw stones. The question is, does your company dogfood it's own product? Does your CEO and board of directors use it on their work and home machines? Or do they just install it for show, but actually disable it during day-to-day use?

Good luck tracking down the offending code. I know how hard it is to try to find those intermittent bugs. I'm really happy that you and your team found a relatively consistent and minimal repro scenario.
 
Yup, I agree. At one point, I considered working for a company that helps make nuclear weapons, so I can't really throw stones. The question is, does your company dogfood it's own product? Does your CEO and board of directors use it on their work and home machines? Or do they just install it for show, but actually disable it during day-to-day use?

Good luck tracking down the offending code. I know how hard it is to try to find those intermittent bugs. I'm really happy that you and your team found a relatively consistent and minimal repro scenario.
Update on issue

After making changes for MouseHook, ran build in target system, got issue as soon as user installed the product. This time log does not have a trace of mouse hook. Back to square one.

9:59:20 AM
Object reference not set to an instance of an object.

at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at WinRecorder.Program.GlobalExceptionHandler(Object sender, UnhandledExceptionEventArgs args)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.UnsafeNativeMethods.PeekMessage(MSG& msg, HandleRef hwnd, Int32 msgMin, Int32 msgMax, Int32 remove)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at WinRecorder.Program.Main(String[] args)
 
... bringing new meaning to "Fail fast". That is definitely a puzzle. Anything obvious in the delta between the old mouse hook and the new mouse hook which may point to what is failing? Reference to a logger that isn't initializer yet?
 
Back
Top Bottom