Exception on exit() when using C# event source with c++ sink - c#

I have a COM object, implemented in a C# .dll, named ComClass which sources events. Then, I have a C++ object, SimpleSink, that sinks the events sent from ComClass. The event source/sink mechanism works great. But, when the CRT calls exit(), I'm getting a memory access exception thrown from the following code in exe_common.inl
//
// main has returned; exit somehow...
//
if (!__scrt_is_managed_app())
exit(main_result); // Exception is thrown.
The text of the exception message is as follows.
Exception thrown at 0x00000004 in Cpp.exe: 0xC0000005: Access violation executing location 0x00000004.
I understand that something is attempting to access a junk memory location, but I'm unsure as to what. I researched the issue and I came across this, from Microsoft.
https://msdn.microsoft.com/en-us/library/ms235234.aspx
Once the common language runtime (CLR) enters shutdown mode, native functions have limited access to CLR services. When attempting to call Release on a COM object compiled with /clr, the CLR transitions to native code and then transitions back into managed code to service the IUnknown::Release call (which is defined in managed code). The CLR prevents the call back into managed code since it is in shutdown mode.
I'm not sure if this is applicable only to C++ /clr compiled COM objects, or all CLR compiled COM objects. It may be a cold lead, so to speak. I understand that I could disable the exception and 'probably' go about my business, but that makes me feel oily. So, the question is, how can I prevent this exception when my program shuts down?
Here it is.
int main()
{
CoInitialize(NULL);
// explicit scope so that the smart pointer destructs at the correct time
{
IComClassPtr source;
HRESULT createInstance = source.CreateInstance(__uuidof(ComClass));
SinkSimple sink;
HRESULT advise = sink.DispEventAdvise(source);
try
{
source->FireEvent();
}
catch (const _com_error& ex)
{
std::cout << "Error: " << ex.Description();
}
HRESULT unadvise = sink.DispEventUnadvise(source);
}
CoUninitialize();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
return 0;
}

Related

Exceptions raised running COM DLL

I will try again .... :)
If I have this code:
void CTestDlg::OnBnClickedButtonTest()
{
MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
HRESULT hr;
hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
if (FAILED(hr))
{
__int64 i;
p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
p->ReadPublisherData(&i);
}
}
And I run it, I get this silent exception:
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0x04242420 (parameters: 0x0000000031415927, 0x00007FFCBF6C0000, 0x00000099D88FBDC0).
But, if I use a wrapper (header:
#pragma once
#import "D:\\My Programs\\2017\\MSAToolsLibrary\\MSAToolsLibrary\\bin\\Release\\MSAToolsLibrary.tlb" raw_interfaces_only named_guids
class CMSATools
{
public:
CMSATools();
~CMSATools();
void SetPathXML(CString strPath);
void OpenPublisherDatabase();
private:
MSAToolsLibrary::IMSAToolsLibraryInterfacePtr m_pInterface;
}
Class:
#include "stdafx.h"
#include "MSATools.h"
CMSATools::CMSATools()
{
m_pInterface = NULL;
HRESULT hr;
hr = m_pInterface.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
if (FAILED(hr))
{
// TODO: Throw exception ?
}
}
CMSATools::~CMSATools()
{
}
void CMSATools::SetPathXML(CString strPath)
{
if (m_pInterface != NULL)
{
CComBSTR bstrText = strPath.AllocSysString();
__int64 iResult;
m_pInterface->SetPathXML(bstrText, &iResult);
}
}
void CMSATools::OpenPublisherDatabase()
{
__int64 iResult;
if (m_pInterface != NULL)
m_pInterface->ReadPublisherData(&iResult);
}
And use this in MFC instead:
void CTestDlg::OnBnClickedButtonGetNames()
{
CMSATools toolsMSA;
UpdateData(TRUE);
toolsMSA.SetPathXML(m_strPublisherDatabaseXML);
toolsMSA.OpenPublisherDatabase();
}
It is doing the same thing, yet I get these silent exceptions:
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0x04242420 (parameters: 0x0000000031415927, 0x00007FFCBF6C0000, 0x00000090F277C040).
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: [rethrow] at memory location 0x0000000000000000.
Exception thrown at 0x00007FFCD00B7788 in Test.exe: Microsoft C++ exception: EEFileLoadException at memory location 0x00000090F277BB80.
Exception thrown at 0x00007FFCD00B7788 (KernelBase.dll) in Test.exe: 0xE0434352 (parameters: 0xFFFFFFFF80070002, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x00007FFCBF6C0000).
Why should one way work and the other cause exceptions (that I can't seem to even detect)?
UPDATE
Please hold off - I see my stupid error now! One moment ....
UPDATE 2
void CTestDlg::OnBnClickedButtonTest()
{
MSAToolsLibrary::IMSAToolsLibraryInterfacePtr p;
HRESULT hr;
hr = p.CreateInstance(__uuidof(MSAToolsLibrary::MSAToolsLibraryClass));
if (SUCCEEDED(hr))
{
__int64 i;
p->SetPathXML(m_strPublisherDatabaseXML.AllocSysString(), &i);
p->ReadPublisherData(&i);
}
}
I corrected the test case now and they both have the same exceptions raised. This is the method that seems to cause the problem in the DLL:
public void ReadPublisherData(out Int64 iResult)
{
iResult = MakeResult(true);
try
{
_PublisherData.Publishers.Clear(); // Reset
XmlSerializer x = new XmlSerializer(_PublisherData.GetType());
using (StreamReader reader = new StreamReader(_strPathXML))
{
_PublisherData = (PublisherData)x.Deserialize(reader);
_PublisherData.BuildPublisherDictionaryFromList();
iResult = _PublisherData.PublisherDictionary.Count;
}
}
catch
{
iResult = MakeResult(false);
}
}
As far as I am aware it doesn't cause any exceptions. It seems ...
The only obvious problem you have is that you don't have a problem. The COM server you are using was written in a managed language. Pretty common, dead-simple to do with just an attribute. Probably C#, given that you've asked questions about it. The point is that these exceptions are silent, they are thrown and caught inside the managed code.
Passing exceptions across a COM boundary is illegal, the CLR gives you a rock-hard guarantee that this will never happen. If a managed exception is not caught then it gets turned into an HRESULT error code that indicates a failure. Since you are using the wrappers generated by #import, you'll never actually see these error codes, the wrapper turns them back into a C++ exception by throwing a _com_error. You make no attempt at catching them so if it happens then your program will keel over and die on terminate(), impossible to not notice that.
Fwiw, 0x04242420 is a non-fatal exception code and is an implementation detail of the debugger. Documented here.
The EEFileLoadException is an unmanaged exception used inside the CLR and triggered when Fusion is asked to load assembly and it can't find it. Turns into a managed FileLoadException. You might be slightly more concerned about it given that managed COM servers often have a problem finding dependent assemblies. But this commonly happens when the managed code uses XML serialization, we know you are using it. Using exceptions for flow-control isn't very nice but performance is a feature as well. More about it in this post.
So rather best to not fret about it. If you don't trust your COM server to be implemented correctly then simply debug both. Project > Properties > Debugging and change the Debugger Type setting from Auto to Mixed. And use Debug > Windows > Exception Settings and tick the checkbox for CLR Exceptions to force the debugger to break when a managed exception is thrown.

Can an .Net exception be raised from unmanaged code using a delegate function?

I searched around SO and found various related questions, some answered with essentially "don't do that."
I want to call some unmanaged C++ code that accesses various existing C++ code. The existing code may have a variety of error conditions that I want to map into C# exceptions. From doing something similar in Java and JNI, it seemed that it might be possible to have a delegate function to raise defined exceptions, which could then be called directly from unmanaged code. The calls then look like (csharp)->(unmanaged)->(csharp delegate,throw/set pending exception) and then return back up.
The code below seems to work fine (vs2010, mono). My question is is there any problem with this approach - e.g. the spec says that the exception is not guaranteed to still be "pending" after unmanaged code is called, or threading issues, etc...
// unmanaged.cpp
#include <cstdio>
#define EXPORT __declspec(dllexport)
#define STDCALL __stdcall
typedef void (STDCALL* raiseExcpFn_t)(const char *);
extern "C" {
// STRUCT ADDED TO TEST CLEANUP
struct Allocated {
int x;
Allocated(int a): x(a) {}
~Allocated() {
printf("--- Deleted allocated stack '%d' ---\n", x);
fflush(stdout);
}
};
static raiseExcpFn_t exceptionRaiser = 0;
EXPORT void STDCALL registerRaiseExcpFn(raiseExcpFn_t fun) {
exceptionRaiser = fun;
}
EXPORT void STDCALL hello(const char * x) {
Allocated a0(0);
try {
Allocated a1(1);
printf("1 --- '%s' ---\n", x); fflush(stdout);
(*exceptionRaiser)("Something bad happened!");
printf("2 --- '%s' ---\n", x); fflush(stdout);
} catch (...) {
printf("3 --- '%s' ---\n", x); fflush(stdout);
throw;
}
printf("4 --- '%s' ---\n", x); fflush(stdout);
}
}
// Program.cs
using System;
using System.Runtime.InteropServices;
class Program {
[DllImport("unmanaged.dll")]
public static extern void registerRaiseExcpFn(RaiseException method);
[DllImport("unmanaged.dll")]
public static extern void hello([MarshalAs(UnmanagedType.LPStr)] string m);
public delegate void RaiseException(string s);
public static RaiseException excpfnDelegate =
new RaiseException(RaiseExceptionMessage);
// Static constructor (initializer)
static Program() {
registerRaiseExcpFn(excpfnDelegate);
}
static void RaiseExceptionMessage(String msg) {
throw new ApplicationException(msg);
}
public static void Main(string[] args) {
try {
hello("Hello World!");
} catch (Exception e) {
Console.WriteLine("Exception: " + e.GetType() + ":" + e.Message);
}
}
}
Updated: Corrected test and output, showing mono and Windows (with /EHsc) leaks
// Observed output // with Release builds /EHa, VS2010, .Net 3.5 target
//cstest.exe
// --- Deleted allocated stack '0' ---
// --- Deleted allocated stack '1' ---
// 1 --- 'Hello World!' ---
// 3 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
// Observed LEAKING output // with Release builds /EHsc, VS2010, .Net 3.5 target
// cstest.exe
// 1 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
// LEAKING output DYLD_LIBRARY_PATH=`pwd` mono program.exe
// 1 --- 'Hello World!' ---
// Exception: System.ApplicationException:Something bad happened!
Yes, you can make this work as long as you run the code on Windows. Both C++ exceptions and .NET exceptions are built on top of the native SEH support provided by Windows. You will not have such guarantee on Linux or Apple operating systems however, a concern when you use Mono.
It is important that you build your C++ code with the correct settings, the MSVC++ compiler uses an optimization to avoid registering exception filters when it can see that code can never throw a C++ exception. That cannot work in your case, your RaiseException delegate target is going to throw one and the compiler has no chance at guessing at that. You must compile with /EHa to ensure your C++ destructors will be called when the stack is unwound. You'll find more details in this answer.
If you're ever planning on running on Mono, the answer is simple:
Don't do it
No more code will be executed in the native methods the exception would unwind over. No cleanup, no C++ destructors, nothing.
On the other hand this means that if you're sure none of the native frames on the stack have any cleanup to do (if you're writing C++ code this can be harder than it looks), then you're free to throw managed exceptions at will.
The reason I so adamantly advice against doing this is because I once spent two days tracking down a memory leak because of exception handling unwinding though native frames. It is quite hard to track down and I was quite boggled for a while (breakpoints aren't hit, printfs don't print... but with the right tools it could have taken 5 minutes).
If you're still decided on throwing managed exceptions from native code, I'd do it just before returning to managed code:
void native_function_called_by_managed_code ()
{
bool result;
/* your code */
if (!result)
throw_managed_exception ();
}
And I would limit myself to C in those methods, since it's too easy to get into automatic memory management in C++ that would still leak:
void native_function_called_by_managed_code ()
{
bool result;
MyCustomObject obj;
/* your code */
if (!result)
throw_managed_exception ();
}
This could leak because MyCustomObject's destructor isn't called.
You might have a problem with native resources not being freed correctly.
When an exception is thrown the stack gets unwind until it finds a matching try-catch block.
This is all good and nice, but there are some side effects of being in the middle of native and managed.
In regular C# all the objects created in the blocks on the way to the exception would eventually be freed by the garbage collector. But Dispose() isn't called unless you're in a using block.
On the other hand, in C++ if you'd have a native exception, all object created with new() would probably stay dangling and you'll have a memory leak, and the objects on the stack would be destroyed properly when the stack got unwound.
BUT if you don't have /EHa set, and you have a managed exception, it will only unwind the managed code. So, the native destructors of native objects created on the stack might not be called, and you might have memory leaks, or even worse - locks not being unlocked...

Unhandled Exception in C# Console Application causing AppCrash

I have a Windows Console application built in Visual Studio 2010 and it keeps crashing but the error is not caught by the visual studio debugging tool nor by try/catch statements in my code.
I have managed to locate the WER file on my system and would like to be able to understand the contents of the file so I can pinpoint exactally what is causing the unhandled exception.
I would be greatful if anyone can offer some idea on how I can use the following information to locate the process causing me this problem and also what the exception may be...
The information from the WER file is:
Version=1
EventType=APPCRASH
EventTime=129973086237604286
ReportType=2
Consent=1
ReportIdentifier=91331e8b-2dc8-11e2-977b-080027f7e5bb
IntegratorReportIdentifier=91331e8a-2dc8-11e2-977b-080027f7e5bb
WOW64=1
Response.type=4
Sig[0].Name=Application Name
Sig[0].Value=SAGE_TESTING.vshost.exe
Sig[1].Name=Application Version
Sig[1].Value=10.0.30319.1
Sig[2].Name=Application Timestamp
Sig[2].Value=4ba2084b
Sig[3].Name=Fault Module Name
Sig[3].Value=ntdll.dll
Sig[4].Name=Fault Module Version
Sig[4].Value=6.1.7600.16385
Sig[5].Name=Fault Module Timestamp
Sig[5].Value=4a5bdb3b
Sig[6].Name=Exception Code
Sig[6].Value=c015000f
Sig[7].Name=Exception Offset
Sig[7].Value=000845bb
DynamicSig[1].Name=OS Version
DynamicSig[1].Value=6.1.7600.2.0.0.272.7
DynamicSig[2].Name=Locale ID
DynamicSig[2].Value=2057
DynamicSig[22].Name=Additional Information 1
DynamicSig[22].Value=0a9e
DynamicSig[23].Name=Additional Information 2
DynamicSig[23].Value=0a9e372d3b4ad19135b953a78882e789
DynamicSig[24].Name=Additional Information 3
DynamicSig[24].Value=0a9e
DynamicSig[25].Name=Additional Information 4
DynamicSig[25].Value=0a9e372d3b4ad19135b953a78882e789
Here is the section of code I believe to be causing the exception to be thrown:
//Data from the project linked to the split data
if (oSplitData.Project != null)
{
oProject = oSplitData.Project as SageDataObject190.Project;
oBasicDetail.ProjectID = oProject.ProjectID;
oBasicDetail.ProjectReference = oProject.Reference.ToString();
}
else
{
oBasicDetail.ProjectID = -1;
oBasicDetail.ProjectReference = "NO_PROJECT";
}
To add to all the above I seem to have found that there is a general exception that is being thrown but it doesn't help me out much - if anyone can put some light on this it would be great:
Unhandled exception at 0x78bc7361 in SAGE_TESTING.exe: 0xC0000005: Access violation reading location 0xfeeefeee.
If your program is multi-threaded and the exception is thrown in one of the spawned threads, the Exception may not be caught depending on how you do exception handling in your program.
You can add a catch-all exception handler like this:
class Program
{
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledExceptionHandler;
// Your code here
}
static void UnhandledExceptionHandler(object sender, UnhandledExceptionEventArgs e)
{
Console.WriteLine(e.ExceptionObject.ToString());
Environment.Exit(1);
}
}
UPDATE
Based on the code you posted, here are some things to look at
Put a try/catch block around the code you posted.
Are you sure that oSplitData is not null?
In the following line, oProject will be null if oSplitData.Project is not of type SageDataObject190.Project. Test for null.
oProject = oSplitData.Project as SageDataObject190.Project;
You are probably dealing with so-called corrupted state exceptions. These exceptions corrupt the process in a way so it is usually more safe to kill the process since it is very difficult to impossible to recover from such an error, even if it would be only for running a short catch-clause. Examples are StackOverflowExceptions, OutOfMemoryExceptions or AccessViolationExceptions.
There is an extensive and generally interesting explanation on corrupted state exceptions in this article.
What is helpful on getting a hand on such exceptions is to use DebugDiag. With this tool from Microsoft (download on this page) you can define a crash rule which generates a crashdump for your failed process. You can easily open these dump files in Visual Studio, where you may find the source of the exception that lead to the failure. This is not guaranteed but it often helped me in the past to nail down some nasty errors.
Are you invoking non-managed C++ or other code?
I'd try something like
static void Main()
{
try
{
DoSomethingUseful() ;
}
catch ( Exception e )
{
// managed exceptions caught here
}
catch
{
// non-managed C++ or other code can throw non-exception objects
// they are caught here.
}
return ;
}
See Will CLR handle both CLS-Complaint and non-CLS complaint exceptions?
Also C++ try, catch and throw statements at msdn: http://msdn.microsoft.com/en-us/library/6dekhbbc(v=vs.100).aspx
And MSIL opcode throw (0x7A) allows the throwing any object reference. C#, however, does not allow it.
But it looks like they improved things with .Net 2.0 and started wrapping oddball stuff in an RuntimeWrappedException.

COM-Interop, EAccessViolation after i exit the Application

i am having a problem with a ActiveX i am using via COM-Interop. it`s throwing an exception after i exit my Application and i am not sure if this is my fault or the fault of the ActiveX.
is the the correct way to initilize and release an ActiveX via COM-Interop?
Error Message
Sample Code which triggers the Exception
public void CreateInvoice()
{
String path = #"";
FaktNT.OLESrvClass OLESrv = null;
try
{
OLESrv = new FaktNT.OLESrvClass();
if (OLESrv.MandantLogin2() == 0)
{
try
{
//Do Stuff
}
catch (System.Exception ex)
{
//Log Error
throw;
}
finally
{
OLESrv.MandantLogout();
}
}
else
{
//Do Stuff
};
}
finally
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(OLESrv);
OLESrv = null;
GC.Collect();
}
}
You should not need to release the COM object manually using Marshal.ReleaseComObject(). This is done by .net automatically (depending on what you are doing to the reference counting in the native COM code of course).
I would also try to check if the problem originates on the native side (for example in a destructor, which is called when the object is garbage collected).
Is the COM dll generating any native threads, which may be running after the object was garbage collected?
This is not a .NET message, the component itself is trapping the access violation exception. Looks like it was written in Delphi, judging from the exception name. Making native code bomb on an AV doesn't usually require a lot of help. But sure, you may be using the component 'incorrectly'. You stubbed out too much code to really make an informed guess. Other than that making calls on it in a finally block after you caught all exceptions that it might raise is a Bad Idea.
Getting it to bomb on program exit instead of after the GC.Collect() call is not healthy either. Sure sign that you haven't managed to call ReleaseComObject and null all the interface references. That's common, better to leave it up to the garbage collector to do it right. Albeit that this message box is going to bomb the finalizer thread. Yes, you probably need the vendor's help if a thorough code review doesn't help.
i solved the problem now. it was in fact me misusing the COM-Object, i missed to call OLESrv.EngineClose() which closes the COM-Object cleanly.
somehow this little piece of important informationen didn`t make it into the vendors documentation ...

How does SetUnhandledExceptionFilter work in .NET WinForms applications?

I am working on a project to enhance our production debugging capabilities. Our goal is to reliably produce a minidump on any unhandled exception, whether the exception is managed or unmanaged, and whether it occurs on a managed or unmanaged thread.
We use the excellent ClrDump library for this currently, but it does not quite provide the exact features we need, and I'd like to understand the mechanisms behind exception filtering, so I set out to try this for myself.
I started out by following this blog article to install an SEH handler myself: http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx. This technique works for console applications, but when I try the same thing from a WinForms application, my filter is not called for any variety of unmanaged exceptions.
What can ClrDump be doing that I'm not doing? ClrDump produces dumps in all cases, so its exception filter must still be called...
Note: I'm aware of ADPlus's capabilities, and we've also considered using the AeDebug registry keys... These are also possibilities, but also have their tradeoffs.
Thanks,
Dave
// Code adapted from <http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx>
LONG WINAPI MyExceptionFilter(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
{
printf("Native exception filter: %X\n",ExceptionInfo->ExceptionRecord->ExceptionCode);
Beep(1000,1000);
Sleep(500);
Beep(1000,1000);
if(oldFilter_ == NULL)
{
return EXCEPTION_CONTINUE_SEARCH;
}
LONG ret = oldFilter_(ExceptionInfo);
printf("Other handler returned %d\n",ret);
return ret;
}
#pragma managed
namespace SEHInstaller
{
public ref class SEHInstall
{
public:
static void InstallHandler()
{
oldFilter_ = SetUnhandledExceptionFilter(MyExceptionFilter);
printf("Installed handler old=%x\n",oldFilter_);
}
};
}
Windows Forms has a built-in exception handler that does the following by default:
Catches an unhandled managed exception when:
no debugger attached, and
exception occurs during window message processing, and
jitDebugging = false in App.Config.
Shows dialog to user and prevents app termination.
You can disable the first behaviour by setting jitDebugging = true in App.Config. This means that your last chance to stop the app terminating is to catch the unhandled exception by registering for the event Application.ThreadException, e.g. in C#:
Application.ThreadException += new Threading.ThreadExceptionHandler(CatchFormsExceptions);
If you decide not to catch the unhandled exception here, then you will need to check and/or change the registry setting DbgJitDebugLaunchSetting under HKLM\Software.NetFramework. This has one of three values of which I'm aware:
0: shows user dialog asking "debug or terminate".
1: lets exception through for CLR to deal with.
2: launches debugger specified in DbgManagedDebugger registry key.
In Visual Studio, go to Tools>Options>Debugging>JIT to set this key to 0 or 2. But a value of 1 is usually what you want on an end-user's machine. Note that this registry key is acted on before the CLR unhandled exception event that you discuss.
Then you can set the native exception filter that you discussed.
If you want your GUI thread exceptions to work just like your-non GUI ones, so that they get handled the same way, you can do this:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Here's the background:
In a manged GUI app, by default, exceptions that originate in the GUI thread are handled by whatever is assigned to the Application.ThreadException, which you can customize like this:
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Exceptions that originate in the other threads are handled by AppDomain.CurrentDomain.UnhandledException, which you can customize like this:
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(Program.CurrentDomain_UnhandledException);
Assigning to UnHandledException works exactly like calling Win32 SetUnhandledExceptionFilter.
If you goal is to create minidumps and then use them, you'll need to use Debugging Tools for Windows, sos.dll. You'll need to produce minidumps MiniDumpWithFullMemory.
And then, even then, you probably won't have everything you might want. System.Diagnostics.StackTrace to get the call managed call stack.
SetUnhandledExceptionFilter installs a handler that is invoked when a Win32-excpetion reaches the top of a threads callstack without being handled.
In many language runtimes including managed, language exceptions are implemented using Win32 exceptions. But, the managed runtime will have a top level __try __catch(...) block at the top of each thread that will catch any win32 to runtime exceptions and process them without letting them escape to Win32's top level handler.
Knowledge of the specific runtime would be necessary to inject a handler at this level because the exceptions will never be allowed to escape to Win32's TheadProc handler.

Categories

Resources