How to catch a external exception - c#

I'm using the nVLC dll's for using the VLC Media Player within my application. It works like a charm except for one thing. I have a DataGridView with a list of movies. When I select a movie from that DataGridView it starts playing the movie within the panel that is handled by nVLC. I also use filters to filter the movies within the DataGridView. When I do this a couple of times I get an error from the nVLC DLL:
CallbackOnCollectedDelegate occurred
Managed Debugging Assistant 'CallbackOnCollectedDelegate' has detected a problem in 'C:\Users\User\Documents\Visual Studio 2013\Projects\Soft.UltimateMovieManager\Soft.UltimateMovieManager\bin\Release\Soft.UltimateMovieManager.vshost.exe'.
Additional information: A callback was made on a garbage collected
delegate of type
'nVLC.Implementation!Implementation.VlcEventHandlerDelegate::Invoke'.
This may cause application crashes, corruption and data loss. When
passing delegates to unmanaged code, they must be kept alive by the
managed application until it is guaranteed that they will never be
called.
The problem is that I can't catch that exeption. Even when I set a try/catch on the application itself, it still can't be handled.
Is this something I can resolve myself or is this a problem of the nVLC dll I use?
if (!string.IsNullOrEmpty(video_url))
{
if (pnlStartVideo != null)
{
pnlStartVideo.Dispose();
}
pnlStartVideo = new System.Windows.Forms.Panel();
pnlStartVideo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
pnlStartVideo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
pnlStartVideo.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
pnlStartVideo.Location = new System.Drawing.Point(pnlStartInfo.Location.X, (pnlStartInfo.Location.Y + (pnlStartInfo.Height - 1)));
pnlStartVideo.Name = "pnlStartVideo";
pnlStartVideo.Size = new System.Drawing.Size(275, 153);
pnlStartVideo.TabIndex = 3;
tpStart.Controls.Add(pnlStartVideo);
m_factory = new MediaPlayerFactory(true);
m_player = m_factory.CreatePlayer<IDiskPlayer>();
m_player.WindowHandle = pnlStartVideo.Handle;
m_player.Events.PlayerStopped += Events_PlayerStopped;
UISync ui = new UISync();
ui.Init(this);
m_media = m_factory.CreateMedia<IMedia>(video_url);
m_player.Open(m_media);
m_media.Parse(true);
m_media.Events.StateChanged += Events_StateChanged;
m_player.Play();
}

Managed Debugging Assistant 'CallbackOnCollectedDelegate' ...
It is not a catchable exception since it is not an exception at all. A managed debugging assistant is helper code added to the debugger that can detect various mishaps at runtime. This one steps in when it sees the VLC player trying to use a disposed delegate object. Without the debugger your program will keel over and die in a much worse way, an AccessViolationException, not catchable either since it is native code that fails.
Looking at the VLC wrapper source code, you must create the m_player instance only once to avoid this failure mode. When you create it over and over again like you do now, the previous IDiskPlayer instances are not reference anywhere anymore. The garbage collector will collect them, big kaboom when the native VLC code makes the callback to fire an event. The wrapper also doesn't implement proper cleanup that I can see, ensuring that the native code cannot fire events anymore when the object is disposed.
Making the m_player variable static is strongly recommended. Assign it just once.
Fixing the wrapper would require writing the equivalent of initializeEventsEngine() but setting all the callbacks back to null. This is not necessarily straight-forward, there are probably threading races involved. Taking a dependency on this code is a liability, you might want to keep shopping.

Related

Win2D APIs fail randomly with error "Objects used together must be created from the same factory instance."

I am writing a UWP app with extensive use of Win2D APIs.
Sometimes, with no defined pattern, nor possibility to reproduce the behavior systematically, an un-caught exception of type System.Exception {System.Runtime.InteropServices.COMException} is raised by the framework, with no stack trace and only the following message:
Error HRESULT E_FAIL has been returned from a call to a COM component.
and a slightly more useful description
Objects used together must be created from the same factory instance.
Since there is no stack trace, I am not able to understand what is the cause of such exception, nor the piece of code that produces it.
According to the description, I tried to use a single factory for every Win2D operation, and specifically, I collected into 3 public static variables the factories I use:
public static class Win2DUtils
{
public static readonly Compositor Compositor = Window.Current.Compositor;
public static readonly CanvasDevice CanvasDev = CanvasDevice.GetSharedDevice();
public static readonly CompositionGraphicsDevice GraphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(Compositor, CanvasDev);
}
Even with this escamotage, I am still experiencing the issue.
I also tried in Visual Studio to flag all the possible Exception to stop the execution when they are raised, but if with this setting the Exception is completely un-caught, and can only be perceived thanks to the builtin exception handling of Visual Studio in Debug mode (the code in App.g.i.cs that is automatically added by the scaffolding of Visual Studio in every UWP project, something like:
#if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
UnhandledException += (sender, e) =>
{
if (global::System.Diagnostics.Debugger.IsAttached) global::System.Diagnostics.Debugger.Break();
};
#endif
Is anybody aware of what could be the possible cause and at least how to catch the source of the exception?
Thank you very much
cghersi
I had similar error, but it crash only on some devices(all of them was with Intel HD Graphics). The reason was I forgot to remove CanvasDevice.DebugLevel = CanvasDebugLevel.Information;
if (CanvasDevice != null)
{
CanvasDevice.DeviceLost -= CanvasDeviceOnDeviceLost;
}
CanvasDevice.DebugLevel = CanvasDebugLevel.Information;//Remove this on release. On some devices cause app crash
CanvasDevice = CanvasDevice.GetSharedDevice();
//error:Canvas.GetSharedDevice Error HRESULT E_FAIL has been returned from a call to a COM component.
I finally solved the issue (apparently) so I post for anybody else that hits the same problem.
In our code we are instantiating a CanvasAnimatedControl to draw some ink.
By default, the public parameter-less constructor of CanvasAnimatedControl sets the flag UseSharedDevice to false, which allows the CanvasAnimatedControl to create its own CanvasDevice.
Creating the canvas as:
aniCanvas = new CanvasAnimatedControl()
{
UseSharedDevice = true
};
solved the problem and the exception doesn't show up anymore.

Cleaning up CommandBar buttons

I have an issue with my COM add-in that has been dragging for months, and I can't figure out why.
The IDTExtensibility2 implementation has been peer reviewed by Carlos Quintero (the guy behind MZ-Tools) already, and deemed correct.
Per his recommendations the OnBeginShutdown implementation sets a flag that's checked in OnDisconnection, to ensure ShutdownAddIn only runs once (some VBE host applications don't call OnBeginShutdown, that's why):
public void OnBeginShutdown(ref Array custom)
{
_isBeginShutdownExecuted = true;
ShutdownAddIn();
}
My add-in uses Ninject for DI/IoC, and my ShutdownAddIn method boils down to calling Dispose on the Ninject IKernel instance, and then releasing all COM objects with Marshal.ReleaseComObject:
private void ShutdownAddIn()
{
if (_kernel != null)
{
_kernel.Dispose();
_kernel = null;
}
_ide.Release();
_isInitialized = false;
}
I cannot think of an earlier time to run this code. Yet, when Dispose runs on my commandbar and menu wrappers, I'm getting an InvalidCastException in StopEvents when the commandbar/menus try to dismantle their controls:
public void HandleEvents()
{
// register the unmanaged click events
((Microsoft.Office.Core.CommandBarButton)Target).Click += Target_Click;
}
public void StopEvents()
{
// unregister the unmanaged click events
((Microsoft.Office.Core.CommandBarButton)Target).Click -= Target_Click;
}
public event EventHandler<CommandBarButtonClickEventArgs> Click;
private void Target_Click(Microsoft.Office.Core.CommandBarButton ctrl, ref bool cancelDefault)
{
// handle the unmanaged click events and fire a managed event for managed code to handle
var handler = Click;
if (handler == null)
{
return;
}
var args = new CommandBarButtonClickEventArgs(new CommandBarButton(ctrl));
handler.Invoke(this, args);
cancelDefault = args.Cancel;
}
The InvalidCastException says that it can't cast to IConnectionPoint - and what I've found is that the reason for this is because when this code runs, my Target (the wrapped __ComObject) is gone already, and I'm left with an invalid pointer and a lingering reference to a COM object that no longer exists.
If I catch all exceptions thrown during my teardown process (I have more exceptions stemming from the same root problem, when I try to Delete the buttons and menus), the host application closes but the host process remains - and then I have to kill it from Task Manager. This behavior is consistent with a memory leak caused by not-removed click handlers I think.
Is there a more robust way I can deal with adding/removing event handlers for a Microsoft.Office.Core.CommandBarButton wrapper? Why would my wrapped COM objects be already "gone" when OnBeginShutdown runs, if I haven't released them yet?
I may be wrong, but I don't think InvalidCastException is because some COM object is gone, you would receive “COM object that has been separated from its underlying RCW cannot be used” in that case. InvalidCastException means what it means, that a type cannot be converted to another type, and that can happen not only in the obvious case that the types full names are different, but also I have seen it in edge cases such as
1) The type full names are the same, but come from different assemblies or even from the same assembly that somehow was loaded twice from different locations. Example: case 1 mentioned in Isolating .NET-based add-ins for the VBA editor with COM Shims
2) The type full names are the same but have been loaded in different CLRs (2.0 / 4.0) in the same process. Example: The strange case of System.InvalidCastException (“Unable to cast COM object of type ‘System.__ComObject’ to class type System.Windows.Forms.UserControl”) showing toolwindow
I'd suggest to get the full type name/assembly names/CLR of the types being cast. Adding a temporary reference to Microsoft.VisualBasic reference allows you to use Microsoft.VisualBasic.Information.TypeName(object) to get the actual type behind a __ComObject.

C++ COM client releases two different objects within one call ?! 2nd Release causes access violation

I have the weirdest problem, and most likely there is something I am missing or I don't know.
I created a C# COM interface/class that for this question we'll call it: Ics_obj and Ccs_obj.
In the destructor of the object I added a trace to the output debug:
~Ccs_obj()
{
OutputDebugString("Releasing: "+this.GetHashCode()); // OutputDebugString with p/invoke
}
That I wrote a C++ class that Ics_obj is a member in that class, and the member is the com_ptr_t wrapper of Ics_obj generated in the .tlh:
class lib_exp_macro cpp_client
{
public:
cpp_client();
~cpp_client();
...
...
Ics_objPtr _csobj; // the Ics_obj* wrapped in com_ptr_t.
}
In the constructor I create an instance of Ccs_obj, and in the destructor I release it. I also added the following traces:
cpp_client::cpp_client()
{
HRESULT hr = _csobj.CreateInstance( __uuidof( Ccs_obj ) );
if(FAILED(hr)){ /* throw exception */ }
OutputDebugString("Creating client");
}
cpp_client::~cpp_client()
{
OutputDebugString("before releasing _csobj");
}
Now, I have created 2 instances of cpp_client through my code (creating them with the same thread during initialization of my application), and I get 2 traces of "Creating Client".
The problem is that during shutdown I get ACCESS VIOLATION and the traces are as follow:
before release // first object being released
Releasing: (some number X)
Releasing: (some number Y, Y != X) // <- where did that come from?
before releasing _csobj
SYSTEM CRASH HORRIBLY WITH ACCESS VIOLATION! :-(
When I debug I get ACCESS VIOLATION for accessing the v-table of the COM object.
Does anyone know why I get ACCESS VIOLATION? what am I doing wrong? I am REALLY LOST HERE! :-(
Thanks in advance!
UPDATE:
With the help of two answers (that were deleted), I understood more things, but I still have open questions...
First and the most important thing is that the 2nd release was in dllmain PROCESS_DETACH. When I moved the release code out of this context, everything was fine, but why can't I release the COM object in the PROCESS_DETACH context?!
One of the answers that were deleted said that CLR of the .Net has shutdown, therefore the 2nd release in my traces. This made a lot of sense and what lead me into moving the releasing code out of PROCESS_DETACH context, but if it is so and CLR does shutdown because the PROCESS_DETACH code, why don't I get any of the "Releasing: ..." traces if I'm not releasing the COM object (by detaching _com_ptr_t)??? Or in other words, why does CLR doesn't shutdown if I don't release the 1st object?
Thanks again for your amazing help!

NullReferenceException in finalizer during MSTest

(I know, this is a ridiculously long question. I tried to separate the question from my investigation so far, so it's slightly easier to read.)
I'm running my unit tests using MSTest.exe. Occasionally, I see this test error:
On the individual unit test method: "The agent process was stopped while the test was running."
On the entire test run:
One of the background threads threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Runtime.InteropServices.Marshal.ReleaseComObject(Object o)
at System.Management.Instrumentation.MetaDataInfo.Dispose()
at System.Management.Instrumentation.MetaDataInfo.Finalize()
So, here's what I think I need to do: I need to track down what is causing the error in MetaDataInfo, but I'm drawing a blank. My unit test suite takes over half an hour to run, and the error doesn't happen every time, so it's hard to get it to reproduce.
Has anyone else seen this type of failure in running unit tests? Were you able to track it down to a specific component?
Edit:
The code under test is a mix of C#, C++/CLI, and a little bit of unmanaged C++ code. The unmanaged C++ is used only from the C++/CLI, never directly from the unit tests. The unit tests are all C#.
The code under test will be running in a standalone Windows Service, so there's no complication from ASP.net or anything like that. In the code under test, there's threads starting & stopping, network communication, and file I/O to the local hard drive.
My investigation so far:
I spent some time digging around the multiple versions of the System.Management assembly on my Windows 7 machine, and I found the MetaDataInfo class in System.Management that's in my Windows directory. (The version that's under Program Files\Reference Assemblies is much smaller, and doesn't have the MetaDataInfo class.)
Using Reflector to inspect this assembly, I found what seems to be an obvious bug in MetaDataInfo.Dispose():
// From class System.Management.Instrumentation.MetaDataInfo:
public void Dispose()
{
if (this.importInterface == null) // <---- Should be "!="
{
Marshal.ReleaseComObject(this.importInterface);
}
this.importInterface = null;
GC.SuppressFinalize(this);
}
With this 'if' statement backwards, MetaDataInfo will leak the COM object if present, or throw a NullReferenceException if not. I've reported this on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/779328/
Using reflector, I was able to find all uses of the MetaDataInfo class. (It's an internal class, so just searching the assembly should be a complete list.) There is only one place it is used:
public static Guid GetMvid(Assembly assembly)
{
using (MetaDataInfo info = new MetaDataInfo(assembly))
{
return info.Mvid;
}
}
Since all uses of MetaDataInfo are being properly Disposed, here's what's happening:
If MetaDataInfo.importInterface is not null:
static method GetMvid returns MetaDataInfo.Mvid
The using calls MetaDataInfo.Dispose
Dispose leaks the COM object
Dispose sets importInterface to null
Dispose calls GC.SuppressFinalize
Later, when the GC collects the MetaDataInfo, the finalizer is skipped.
.
If MetaDataInfo.importInterface is null:
static method GetMvid gets a NullReferenceException calling MetaDataInfo.Mvid.
Before the exception propagates up, the using calls MetaDataInfo.Dispose
Dispose calls Marshal.ReleaseComObject
Marshal.ReleaseComObject throws a NullReferenceException.
Because an exception is thrown, Dispose doesn't call GC.SuppressFinalize
The exception propagates up to GetMvid's caller.
Later, when the GC collects the MetaDataInfo, it runs the Finalizer
Finalize calls Dispose
Dispose calls Marshal.ReleaseComObject
Marshal.ReleaseComObject throws a NullReferenceException, which propagates all the way up to the GC, and the application is terminated.
For what it's worth, here's the rest of the relevant code from MetaDataInfo:
public MetaDataInfo(string assemblyName)
{
Guid riid = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(IMetaDataImportInternalOnly), typeof(GuidAttribute), false)).Value);
// The above line retrieves this Guid: "7DAC8207-D3AE-4c75-9B67-92801A497D44"
IMetaDataDispenser o = (IMetaDataDispenser) new CorMetaDataDispenser();
this.importInterface = (IMetaDataImportInternalOnly) o.OpenScope(assemblyName, 0, ref riid);
Marshal.ReleaseComObject(o);
}
private void InitNameAndMvid()
{
if (this.name == null)
{
uint num;
StringBuilder szName = new StringBuilder {
Capacity = 0
};
this.importInterface.GetScopeProps(szName, (uint) szName.Capacity, out num, out this.mvid);
szName.Capacity = (int) num;
this.importInterface.GetScopeProps(szName, (uint) szName.Capacity, out num, out this.mvid);
this.name = szName.ToString();
}
}
public Guid Mvid
{
get
{
this.InitNameAndMvid();
return this.mvid;
}
}
Edit 2:
I was able to reproduce the bug in the MetaDataInfo class for Microsoft. However, my reproduction is slightly different from the issue I'm seeing here.
Reproduction: I try to create a MetaDataInfo object on a file that isn't a managed assembly. This throws an exception from the constructor before importInterface is initialized.
My issue with MSTest: MetaDataInfo is constructed on some managed assembly, and something happens to make importInterface null, or to exit the constructor before importInterface is initialized.
I know that MetaDataInfo is created on a managed assembly, because MetaDataInfo is an internal class, and the only API that calls it does so by passing the result of Assembly.Location.
However, re-creating the issue in Visual Studio meant that it downloaded the source to MetaDataInfo for me. Here's the actual code, with the original developer's comments.
public void Dispose()
{
// We implement IDisposable on this class because the IMetaDataImport
// can be an expensive object to keep in memory.
if(importInterface == null)
Marshal.ReleaseComObject(importInterface);
importInterface = null;
GC.SuppressFinalize(this);
}
~MetaDataInfo()
{
Dispose();
}
The original code confirms what was seen in reflector: The if statement is backwards, and they shouldn't be accessing the managed object from the Finalizer.
I said before that because it was never calling ReleaseComObject, that it was leaking the COM object. I read up more on the use of COM objects in .Net, and if I understand it properly, that was incorrect: The COM object isn't released when Dispose() is called, but it is released when the garbage collector gets around to collecting the Runtime Callable Wrapper, which is a managed object. Even though it's a wrapper for an unmanaged COM object, the RCW is still a managed object, and the rule about "don't access managed objects from the finalizer" should still apply.
Try to add the following code to your class definition:
bool _disposing = false // class property
public void Dispose()
{
if( !disposing )
Marshal.ReleaseComObject(importInterface);
importInterface = null;
GC.SuppressFinalize(this);
disposing = true;
}
If MetaDataInfo uses the IDisposable pattern, then there should also be a finalizer (~MetaDataInfo() in C#). The using statement will make sure to call Dispose(), which sets the importInterface to null. Then when the GC is ready to finalize, the ~MetaDataInfo() is called, which would normally call Dispose (or rather the overload taking a bool disposing: Dispose(false)).
I would say that this error should turn up quite often.
Are you trying to fix this for your tests? If so, rewrite your using. Don't dispose of it yourself but write some code to use reflection to access the private fields and dispose of them correctly and then call GC.SuppressFinalize to prevent the finalizer from running.
As a brief aside (loved your investigation btw) you state that Dispose calls Finalize. It's the other way round, Finalize when invoked by the GC calls Dispose.

new XmlSerializer(typeof(MyClass)) Causing Memory corruption?

I've got an application that loads an assembly dynamically:
Assembly asm = Assembly.Load("MyClass.DLL");
Type type = asm.GetType("MyClass");
MyClass runningAssembly = (MyClass)Activator.CreateInstance(type);
runningAssembly.start();
Once loaded and the start() method is called, this line of code is executed:
XmlSerializer deserializer = new XmlSerializer(typeof(MyClass));
And the following exception is thrown:
"Attempted to read or write protected memory. This is often an indication that other memory is corrupt."
I've been stumbling on the cause of this and haven't been able to get a grasp on it. Does anyone have any tips? I also cannot seem to trap this error... it blows right through the try/catch.
By the way, the error doesn't always happen. Sometimes in debug mode it works fine, but it seems like once it starts, it'll always happen even after restarting Visual Studio. A reboot clears it up and allows it to work at least once. It also happens when running from the compiled EXE.
EDIT
I tried the same thing but without loading the assembly dynamically. I called it as a class directly, i.e:
MyClass c = new MyClass();
c.start();
And the same problem persists, so it does NOT appear to be related to being loaded dynamically.
It is hard to now what causes the problems without knowing anything about MyClass. Whats in the constructor and especially what is in the start() method? Does the code have any unsafe code? If you are addressing unsafe memory you could very likely experience the described behavior.
If your start() method is starting a new thread and an exception is thrown on the new thread you will not catch it in a try/catch around the start method.

Categories