Control.Invoke() taking very long time - c#

I'm having an issue with a roughly 15y WinForms application, which is being actively maintained. It's being used by around ten companies, each running it on around 5 - 20 clients. Therein we are using a commercial printer driver (PDF X-Change) to create PDFs from printouts, which employs an asynchronous callback mechanism to inform the application that the PDF has been created (or not). The application uses this information to display the PDF file in a window. Basically something like this:
void pdfCreationStatusCallback(PdfCreationStatusArgs pcsa)
{
if (InvokeRequired)
{
Invoke(new PdfCreationStatus(pdfCreationStatusCallback), pcsa);
return;
}
displayPdf(pcsa);
}
A new company started using the software and reported that the application hangs from time to time. Upon debugging I noticed that call to Invoke() sometimes takes between 20 seconds to almost two hours to return! I used remote debugging in combination with .NET Framework debugging (with dotPeek) to see what happens under the hood. I was able to trace it all the way down to the following code in WaitHandle.cs:
[SecurityCritical]
internal static bool InternalWaitOne(
SafeHandle waitableSafeHandle,
long millisecondsTimeout,
bool hasThreadAffinity,
bool exitContext)
{
if (waitableSafeHandle == null)
throw new ObjectDisposedException((string) null, Environment.GetResourceString("ObjectDisposed_Generic"));
int num = WaitHandle.WaitOneNative(waitableSafeHandle, (uint) millisecondsTimeout, hasThreadAffinity, exitContext);
if (AppDomainPauseManager.IsPaused)
AppDomainPauseManager.ResumeEvent.WaitOneWithoutFAS();
if (num == 128)
WaitHandle.ThrowAbandonedMutexException();
return num != 258;
}
Here I noticed that on a "healthy" system the call to WaitHandle.WaitOneNative(...) returns 0, thus the method returns true and all is good. On the affected system WaitHandle.WaitOneNative(...) returns 258 (after 1000 ms, which is the value of millisecondsTimeout), thus the method returns false. The method calling InternalWaitOne(..) then calls it in a loop for as long as it takes for WaitHandle.WaitOneNative(...) to finally return a value other than 258 (which as stated above, can even take two hours). My problem is, that I couldn't find the source code to WaitOneNative(..), only the following declaration:
[SecurityCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int WaitOneNative(
SafeHandle waitableSafeHandle,
uint millisecondsTimeout,
bool hasThreadAffinity,
bool exitContext);
When I set a breakpoint at the line int num = WaitHandle.WaitOneNative(..) I have two threads which both hit that spot, both returning num = 258:
This is the stacktrace for the PDF-creating callback function (_pdfPrinter_OnFileSaved):
> mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) Line 193 C#
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) Line 125 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle) Line 2788 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) Line 4825 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) Line 4551 C#
GUISubsystem.dll!GUISubsystem.CalculationForms.Printouts.PrintoutAnbotsartikel.FrmAnbotsartikelDruckParameter.pdfCreationStatusCallback(PdfCreationStatusArgs pcsa) Line 597 C#
PrinterSubsystem.dll!PrinterSubsystem.PrintingManager._pdfPrinter_OnFileSaved(int jobID, string fileName) Line 885 C#
[Übergang von Nativ zu Verwaltet]
[Übergang von Verwaltet zu Nativ]
mscorlib.dll!System.Delegate.DynamicInvokeImpl(object[] args) Line 113 C#
mscorlib.dll!System.Runtime.InteropServices.ComEventsMethod.DelegateWrapper.Invoke(object[] args) Line 158 C#
mscorlib.dll!System.Runtime.InteropServices.ComEventsMethod.Invoke(object[] args) Line 121 C#
mscorlib.dll!System.Runtime.InteropServices.ComEventsSink.System.Runtime.InteropServices.NativeMethods.IDispatch.Invoke(int dispid, ref System.Guid riid, int lcid, System.Runtime.InteropServices.ComTypes.INVOKEKIND wFlags, ref System.Runtime.InteropServices.ComTypes.DISPPARAMS pDispParams, System.IntPtr pvarResult, System.IntPtr pExcepInfo, System.IntPtr puArgErr) Line 153 C#
This is the stacktrace of the other thread (looks like the main message loop):
> mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) Line 193 C#
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) Line 125 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle waitHandle) Line 2793 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control caller, System.Delegate method, object[] args, bool synchronous) Line 4825 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.Invoke(System.Delegate method, object[] args) Line 4551 C#
System.Windows.Forms.dll!System.Windows.Forms.WindowsFormsSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) Line 74 C#
System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization, object[] args) Line 1272 C#
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization, object key, object[] args) Line 970 C#
System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(int msg, System.IntPtr wParam, System.IntPtr lParam) Line 728 C#
System.dll!Microsoft.Win32.SystemEvents.WindowProc(System.IntPtr hWnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Line 1130 C#
[Übergang von Nativ zu Verwaltet]
[Übergang von Verwaltet zu Nativ]
System.Windows.Forms.dll!System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(System.IntPtr dwComponentID, int reason, int pvLoopData) Line 1258 C#
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(int reason, System.Windows.Forms.ApplicationContext context) Line 2042 C#
System.Windows.Forms.dll!System.Windows.Forms.Application.ThreadContext.RunMessageLoop(int reason, System.Windows.Forms.ApplicationContext context) Line 1982 C#
System.Windows.Forms.dll!System.Windows.Forms.Application.Run(System.Windows.Forms.Form mainForm) Line 988 C#
MainEntry.exe!MainEntry.Main(string[] args) Line 118 C#
An additional observation: it only takes this long the first time Invoke() (and thus WaitOneNative()) is called. Once WaitOneNative() returns 0 (instead of 258) the application runs without any delays. This is "reset" once the application is restarted. This is the first time and the first company that is experiencing this problem on 3/7 clients. One of the clients is using Windows 10, the other two Windows 8.1 with the .Net Framework 4.8. Our application is targeting .Net Framework 4.5.
Can anybody tell me where I can find the source code for static extern int WaitOneNative(..), such that I can further investigate what it's waiting for?
And/or does anybody have a hint what might be going on here, ie. what WaitOnNative() could be waiting for between a few seconds up to hours? What should I be looking for in the stacktraces, threads, etc.?

I was able to identify the problem. It was one of those OnUserPreferenceChanged issues #klaus-gütter mentioned above. We had a Windows.Forms.Form being created one one of the background threads. The pdfCreationStatusCallback callback was simply one of those that would hang due to the "bug" (it wasn't itself the culprit), probably because it was the first one to be called after the background thread mentioned earlier. I debugged it using the method described here: link (...there are a lot of dead links on this topic).
What I don't really understand is why it eventually would be executed (after 1-2h), as well as why it only affected only 3-4 computers out of around 70 using the software, but I can live with that.
Many thanks to everybody who commented on the original post, especially #klaus-gütter and #Jimi: it helped a great deal to know what to look for.

Related

3D App suddenly uses too much memory and crashes. How to find the cause?

I am developing an 3D app using the Helix3d Toolkit Viewport. The app also communicates with an OPC Server in the background and is continously receiving data. It basically works as it should but when i run it "longer" times like 5-10 days there is a possibility that it suddenly crashes.
The crash may occur when i change from the menu with the 3D Viewport to any other menu. In the menu of the 3D Viewport it continously adds and removes 3D Model to the View based upon the data coming from the OPC Server.
So of course the 3D models will allocate their memory but it basically reaches its maximum when all models are constructed and displayed once. After having a look in the task manager, regarding the used memory, it reaches like 350 MB which is totally okay and it stays there...
But like i said after a run time of 5 days and more it occurs that the program crashes when i simply hide the UserControl containing the 3D view.
In the debugger it says:
{"Insufficient memory to continue the execution of the program."} System.OutOfMemoryException
When this happens the Task Manager displays a value of around 2400 MB used for the app. But i really dont know why, because the 3D display and the server communication runs good for a relatively long time.
What i tried so far:
I installed 16 RAM (8GB before) in the PC...
From my experience so far the error appears not so often anymore...
I gave the app a higher priority in memore allocation with
System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.High;
but i does not seem to have any effect at all.
I checked my code that it uses no Constructions of any new myClass();
in the methods and program parts which "run continously" so that i basically should not get "more" memory allocation
Before adding or removing a 3D Model i check system ressources
ObjectQuery wql = new ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wql);
ManagementObjectCollection results = searcher.Get();
But it is not useful because i get the crash when i make a user input like changing a menu.. not while displaying models in 3d...
I switched to 64 Bit
Maybe had the same effect like increasing the RAM...
I would really appreciate if someone could give me a tip how to further locate my problem or maybe what to check exactly. In the background i also write on an MYSQL DB and it also allocates more memory in time but i dont think it has to do something with my original problem...
Concerning the error when it crashes
{"Insufficient memory to continue the execution of the program."} System.OutOfMemoryException
The Strack Trace is:
at System.Windows.Media.Composition.DUCE.Channel.SyncFlush()
at System.Windows.Interop.HwndTarget.UpdateWindowSettings(Boolean enableRenderTarget, Nullable channelSet)
at System.Windows.Interop.HwndTarget.UpdateWindowPos(IntPtr lParam)
at System.Windows.Interop.HwndTarget.HandleMessage(WindowMessage msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Interop.HwndSource.HwndTargetFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
But i really cant figure out something with this.
Thanks for any advice.
Greetings Knally

What is the cause of this OutOfMemoryException on Mutex constructor?

I am getting an System.OutOfMemoryException on this line of code:
mutex2 = new Mutex(true, "Name2");
Here is the stacktrace:
{"Exception of type 'System.OutOfMemoryException' was thrown."}
at Microsoft.Win32.Win32Native.CreateMutex(SECURITY_ATTRIBUTES lpSecurityAttributes, Boolean initialOwner, String name)
at System.Threading.Mutex.CreateMutexHandle(Boolean initiallyOwned, String name, SECURITY_ATTRIBUTES securityAttribute, SafeWaitHandle& mutexHandle)
at System.Threading.Mutex.MutexTryCodeHelper.MutexTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.Mutex.CreateMutexWithGuaranteedCleanup(Boolean initiallyOwned, String name, Boolean& createdNew, SECURITY_ATTRIBUTES secAttrs)
at System.Threading.Mutex..ctor(Boolean initiallyOwned, String name, Boolean& createdNew, MutexSecurity mutexSecurity)
at System.Threading.Mutex..ctor(Boolean initiallyOwned, String name)
at Foo.FooDefinitions.FooManager.FooForm.FooForm_Load(Object sender, EventArgs e) in c:\tfs\DWS\TRUNK\DEV\FooDefinitions\FooManager\FooForm.cs:line 92
It will only occur when I use impersonation. Without impersonation (running on my normal Windows-account) it will run fine. The impersonation is something like this:
if (!NativeMethods.LogonUser(userName, domainName, password, 2, 0, ref this._tokenHandle)) // [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
this._impersonatedUser = new WindowsIdentity(this._tokenHandle).Impersonate();
EDIT: Just to eloborate, I am creating automated tests on legacy code. I would have removed the use of mutexes if I could. I am currently investigating the SecurityCriticalAttribute on the Mutex constructor.
EDIT2: Here is a full example of the code:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Threading;
namespace ReinierDG.MutexTesting
{
[TestClass]
public class MutexTest
{
[TestMethod]
public void CreateMutexUnderImpersonation()
{
var credentials = new NetworkCredential("testagent", "secretpassword");
var tokenHandle = new IntPtr();
if (!NativeMethods.LogonUser(credentials.UserName, credentials.Domain, credentials.Password, 2, 0, ref tokenHandle))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var impersonatedUser = new WindowsIdentity(tokenHandle).Impersonate();
// this will run indefinately or untill memory is full with 1 cpu core at 100%
var mutex = new Mutex(true, "test");
}
internal static class NativeMethods
{
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
internal static extern bool LogonUser([MarshalAs(UnmanagedType.LPWStr)]string lpszUsername, [MarshalAs(UnmanagedType.LPWStr)]string lpszDomain, [MarshalAs(UnmanagedType.LPWStr)]string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
}
}
}
// this will run indefinately or untill memory is full
Well, that would be one explanation. We'll have to assume that the comment just doesn't match the code. Most obvious issue here is that you did not post a stack trace that is relevant enough to the error and will not help you to diagnose the underlying problem. I can only post hints to get you to the next stage.
It is too easy to assume that it is CreateMutex() that failed. That however is not the case, failure of that winapi function is reported differently, you'd see __Error.WinIOError() back in the stack trace. And the error code would be different, you'd get error 1450, ERROR_NO_SYSTEM_RESOURCES, "Insufficient system resources exist to complete the requested service".
It is in fact the CLR that threw the exception. Or in other words, it is the pinvoke marshaller that failed. That considerably complicates the diagnostic, there are a very large number of places in the very large amount of code where it can throw OOM. It often needs to allocate unmanaged memory to get the pinvoke job done, if that fails then you get the OOM-kaboom. Many ways that can happen, internal unmanaged heap corruption is certainly enough. Your LogonUser() pinvoke declaration is technically wrong (CharSet.Auto != UnmanagedType.LPWStr), but not wrong enough to explain this problem.
You'll need to get closer to the root of the exception and that requires enabling the unmanaged debugger. For VS2015, use Project > Properties > Debugging tab > tick the "Enable native code debugging" checkbox. You'll need debugging symbols for the CLR to make sense of the stack trace. Use Tools > Options > Debugging > Symbols > tick "Microsoft Symbol Server". You need to make the debugger stop on the first-chance exception, use Debug > Windows > Exception Settings > tick "Win32 Exceptions".
You'll know a lot more now, you can post a much better stack trace in your question. Still, the odds that this is going to give SO users or you a crystal-clear diagnostic that shows how this mishap could be explained by impersonation is remote. Calling in the help of Microsoft Support would be wise, they however are going to need to know a lot more about exactly how that "testagent" account is configured. Do keep in mind that such accounts are often intentionally crippled to ensure that unit tests can't demand too many system resources.
You can use the LOGON32_LOGON_NEW_CREDENTIALS(9) as LogonType and LOGON32_PROVIDER_WINNT50(3) as LogonProvider, it will success. I think it's about the authority.
When you debug it in your code, you can found it in the infinite loop, the mutexHandle = Win32Native.CreateMutex(securityAttribute, initiallyOwned, name); failed with ERROR_ACCESS_DENIED. It will run Win32Native.OpenMutex(Win32Native.MUTEX_MODIFY_STATE | Win32Native.SYNCHRONIZE, false, name);, but it also failed with ERROR_FILE_NOT_FOUND

Task.Wait in UIThread is causing my UI to go crazy because locks don't work any more

The background:
I have some model which should give predictions once it is trained. The training has to be done only once - which is rather costly (few seconds). The predictions can then be done very fast.
The training is done implicitely when the first prediction is requested. Because I do not know how many models to be trained at startup time and training all at once is much faster than one by one.
My Problem:
When I am starting my training I am waiting for some tasks to finish. Now Windows is realizing that the UI thread is not busy an more and asking other controls if there is some paint to.
Now some other control also wants a model prediction. In my function I see that the training is not finished and start the training again. Result my function goes crazy - undefined behavior. A lock is of no use here because the second function call is from the same (UI) thread!
What makes it even more iteresting is that this is only an issue in Release mode without Visual Studio attached. So no chance of debugging. Only logging. Took me quite some time to figure out the problem...
Start compiling on thread 1
at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
at System.Environment.get_StackTrace()
at MyComp.MyApp.Model.BestModelEvaluator.Compile()
at MyComp.MyApp.Model.BestModelEvaluator.Evaluate(Double[] in_array)
at MyComp.MyApp.Model.BestModel.ScriptBulkEvaluate(DMyAppionary`2 dMyAppactor, Int32 dicCount)
at MyComp.MyApp.Model.BestModel.BulkEvaluate(DMyAppionary`2 dMyAppactor)
at MyComp.MyApp.Model.MyAppModel.Evaluate(DMyAppionary`2 actuatorValues)
at __Evaluate(MyCompModel* MyComp_model, Int32 regressor_index, uArray<double>* xvalues, uArray<double>* yvalues, uArray<double>* ylower, uArray<double>* yupper, uArray<int>* yvalues_inrange)
at MyCompModel.MakePlot(MyCompModel* , Int32 regressor_index)
at MyAppShell.UpdateCanvasPlots(MyAppShell* , OverlayInfo* ovi, PrintInfo* print_info)
at MyAppShell.UpdateCanvas(MyAppShell* )
at MyAppShell.Notify(MyAppShell* , XMEvent* ev)
at XMWidget.SendEvent(XMWidget* , XMEventType et, XMMailbox* mb, Int32 info, Int32 info1, Int32 info2, Int32 info3)
at XMDrawingArea.DoPaint(XMDrawingArea* , xmRect* rect)
at XMDrawingArea.Message(XMDrawingArea* , MessageType type)
at DrawingAreaWndProc(HWND__* hWnd, UInt32 msg, UInt32 wParam, Int32 lParam)
at CallWindowProcA(IntPtr , HWND__* , UInt32 , UInt32 , Int32 )
at XMDrawingAreaWndProc(HWND__* hWnd, UInt32 msg, UInt32 wParam, Int32 lParam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageA(MSG& msg)
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 ecYaRlzjebO5lJJRJM.eAlVyhEdyCVdmimFqq.koonrpaTJfLI7QASS3()
at ecYaRlzjebO5lJJRJM.eAlVyhEdyCVdmimFqq.e5ChpHZQl(Byte[] )
at ecYaRlzjebO5lJJRJM.eAlVyhEdyCVdmimFqq.GetLicense(LicenseContext , Type , Object , Boolean )
at System.ComponentModel.LicenseManager.ValidateInternalRecursive(LicenseContext context, Type type, Object instance, Boolean allowExceptions, License& license, String& licenseKey)
at System.ComponentModel.LicenseManager.Validate(Type type)
at MyComp.MyApp.Scripting.Script..ctor(String source, ScriptLanguage language)
at MyComp.MyApp.Model.BestEvaluation.BestModelScriptCompiler.PrepareCompilation()
at MyComp.MyApp.Model.BestEvaluation.BestModelScriptCompiler.CompileSynchronous()
at MyComp.MyApp.Model.BestModelEvaluator.Compile()
at MyComp.MyApp.Model.BestModelEvaluator.Evaluate(Double[] in_array)
at MyComp.MyApp.Model.BestModel.Evaluate(DMyAppionary`2 dMyAppactor)
at MyComp.MyApp.Model.MyAppModel.Evaluate(DMyAppionary`2 actuatorValues)
at __Evaluate(MyCompModel* MyComp_model, uArray<double>* xvalues, uArray<double>* yvalues, SByte* comment)
at MyCompModel.MakePredMyAppion(MyCompModel* )
at MyAppShell.UpdateCanvasPlots(MyAppShell* , OverlayInfo* ovi, PrintInfo* print_info)
at MyAppShell.UpdateCanvas(MyAppShell* )
at MyAppShell.Notify(MyAppShell* , XMEvent* ev)
at XMWidget.SendEvent(XMWidget* , XMEventType et)
at MyAppShell.UpdateTree(MyAppShell* )
at MyAppShell.Notify(MyAppShell* , XMEvent* ev)
at XMWidget.SendEvent(XMWidget* , XMEventType et, XMMailbox* mb, Int32 info, Int32 info1, Int32 info2, Int32 info3)
at XMTreeView.SelectItem(XMTreeView* , uTreeNode* item, Int32 send_event)
at XMTreeView.WMessage(XMTreeView* , WidgetMessage msg)
at XMDrawingArea.DoInput(XMDrawingArea* , Void* m, Int32 had_focus)
at XMDrawingArea.Message(XMDrawingArea* , MessageType type)
at DrawingAreaWndProc(HWND__* hWnd, UInt32 msg, UInt32 wParam, Int32 lParam)
at CallWindowProcA(IntPtr , HWND__* , UInt32 , UInt32 , Int32 )
at XMDrawingAreaWndProc(HWND__* hWnd, UInt32 msg, UInt32 wParam, Int32 lParam)
at DispatchMessageA(tagMSG* )
at WinMain(HINSTANCE__* hInstance, HINSTANCE__* hPrevInstance, SByte* lpCmdLine, Int32 nCmdShow)
at _WinMainCRTStartup()
My function is call from an outside application where I have no chance to change that to put the call in background worker.
private bool Compile()
{
lock (compilerLock)
{
if (!isCompiled && CanCompile())
{
CompileSynchronous();
}
}
return isCompiled;
}
I already tried to do the work myself in background and put those calls in Tasks and wait for them. Now my application is waiting for itself forever. Because the second task is waiting for the first to complete. But the first cannot complete because the second is not done - thread and call stack are the same in the end.
I even tried to switch to "blocking" waiting for my task - to no avail...
foreach (Task t in runningTasks)
{
try
{
while (t.IsCompleted == false) ;
//t.Wait();
t.Dispose();
}
catch (Exception ex)
{
// some logging
}
}
I have no idea what else can be done...
EDIT
Running VS 2010 and .net 4.0
EDIT No. 2
To be more clear. My function should block. But it is called twice within the same thread. Even though the first call is not finished. Because it is the same thread locks are no good!
at MyComp.MyApp.Model.BestModelEvaluator.Compile()
...
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageA(MSG& msg)
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 MyComp.MyApp.Model.BestModelEvaluator.Compile()
Can't you just have the Compile function return the current value of isCompiled if it's called a second time? So instead of blocking to obtain the lock, you try to take the lock, and return the current value of isCompiled if you can't. Like this:
private bool Compile()
{
if (!Monitor.TryEnter(compilerLock))
{
// Lock already taken. There is a compile in progress.
return isCompiled;
}
try
{
if (!isCompiled && CanCompile())
{
CompileSynchronous();
}
return isCompiled;
}
finally
{
Monitor.Exit(compilerLock);
}
}
Edit
I see now that you can't use Monitor because it allows re-entrant calls. You can use Semaphore, though.
private Semaphore CompileSemaphore = new Semaphore(1, 1);
private bool Compile()
{
if (!CompileSemaphore.WaitOne(0))
{
// Lock already taken. There is a compile in progress.
return false;
}
try
{
if (!isCompiled && CanCompile())
{
CompileSynchronous();
}
return isCompiled;
}
finally
{
CompileSemaphore.Releae();
}
}
That will prevent re-entrant calls to CompileSynchronous, which should limit the problems. You can't block the thread on re-entrant calls, because it's the thread that's doing the compile. The best you can hope is that the second call sees the false return and ignores it.
The real problem, though, is that CompileSynchronous re-enters the message loop. That's going to cause you no end of trouble, and there's not much you can do about it except change the program so that can't happen. If you've designed the program so that it calls DoEvents (or otherwise re-enables the message loop), then you've created a huge problem for yourself and you need to re-think your design.
I finally figured out the true problem!
We are encrypting our assemblies with a 3rd party tool. This tool adds a static constructor which is used for some license checking stuff.
Within that code, Application.DoEvents() is called several times which caused all my problems! See (encrypted) Stacktrace:
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at ecYaRlzjebO5lJJRJM.eAlVyhEdyCVdmimFqq.koonrpaTJfLI7QASS3()
Now on startup, I just create a dummy instance of my class. Suddenly all my problems are gone...
Thanks for all your effort!
Okay, then... you have a library.
This is a possible architectural solution to what I understand as your problem:
Decouple calls to your library from calculations your library does
You have to do at least two things to achive that.
Decouple calls to your library from calculation
This can be easily achieved by using a command pattern.
Every time your library gets called, take all information from the call,
put it into one object, and put that object into some (concurrent) queue.
Start a thread to work on that queue, i.e. dequeue object from it and
perform your calculations (this can be on another thread, too).
You can find more information on the command pattern here (as a starter)
Return values from your library
This can be somewhat problematic. At least as you cannot immediately return
a valid result without blocking the UI thread for the first call.
But blocking the UI thread is one of your major problems here.
I would suggest to return a null value at first. On subsequent calls, you
can return the latest result of your calculations.
I would store the latest result of your learning / trained results somewhere
near the UI thread so that you can return immediately after packing things
into the queue described above. The inital / starting value would be a
perfect match for a null-object.
What is gained so far?
Your calculations can be performed indepentently from the UI thread,
you can return instantly and always provide a sane value, and
multiple calls to your library are no longer a problem.
HTH

Determining the cause of AccessViolationException DragDrop.DoDragDrop

I have a WPF application that is crashing on some computers with an AccessViolationException when a drag operation is started.
The difficulty is it is only occurring on builds from our build server, and never crashes when I build locally in Visual Studio 2010. So I cannot step through the code.
I have the following information:
We're using .net 4.0
Only crashes when the application is run as a 64bit process, 32bit is fine.
Only crashes for builds from the build server.
Doesn't crash on every computer, just on a small subset of laptops we have here. Which incidentally are all the same model
and hardware configuration. All have
Windows 7, and some have sp1, some
don't.
What is the next step I should take to diagnose this issue?
Here's the stack trace from the crash, it seems to be occurring in unmanaged code:
at MS.Win32.UnsafeNativeMethods.DoDragDrop(IDataObject dataObject, IOleDropSource dropSource, Int32 allowedEffects, Int32[] finalEffect)
at System.Windows.OleServicesContext.OleDoDragDrop(IDataObject dataObject, IOleDropSource dropSource, Int32 allowedEffects, Int32[] finalEffect)
at System.Windows.DragDrop.OleDoDragDrop(DependencyObject dragSource, DataObject dataObject, DragDropEffects allowedEffects)
at Acquire.Common.UI.Behaviours.DragDropBehaviour.StartDrag(RoutedEventArgs e)
at Acquire.Common.UI.Behaviours.DragDropBehaviour.AttachedElementMouseMove(Object sender, MouseEventArgs e)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run()
at Acquire.Mica.Application.App.Main()
Update:
Through trial and error I was able to determine the exact line of code that was causing this crash, and it appears to be perfectly valid. As an experiment I disabled code optimization for the method containing the offending line of code, and the application no longer crashes.
AV exception are the worst, you should be aware that the problem may originate from completely different part in the system.
What normally happens is that you accidently access a memory location that you don't have access to, the program continues to execute as usual, however later on another method tries to access that memory location and causes an error by reading incorrect data place there by mistake.
To debug I suggest that you take advantage of gflags, a tool offered by Microsoft to detect deap corruptions. I used it several times and it saved me hours if not days of debugging effort.
Just a hunch, but since you indicated you are optimizing code, and using a mixed 32/64 bit environment:
Verify the build server a x64 bit environment.
Verify the clients have the proper version .Net environment.
Verify the clients that are running the app are running the right version, ie. 64 bit is only being run by win7 x64 systems and vice versa.
Make sure you clear out the servers temp directories, previous builds in temp directories can cause odd issues such as this.
Also note, the Microsoft developers are idiotic in they way they segregated the two environments, and registry keys / program files etc. are not stored where the program indicates. This was a major stumbling block I had to get past with some apps we created at my company.
Also I belive clipboard & drag+drop calls are STA(Single threaded apratments) calls. The crash could be from a conflict between STA to MTA. Do you have the Main() function decorated with the [STAThread] ?
I personally found this article on 64 bit migration useful: http://www.codeguru.com/cpp/misc/samples/basicprogramming/article.php/c16093/Seven-Steps-of-Migrating-a-Program-to-a-64bit-System.htm
First of all check if all updates are installed on the machines.
Later you could use debugdiag to create a crashdump and check the firstchance and secondchance exceptions to get more info on the matter.
Greetings,
Ian
1st thing I would do is to update the video card driver of those laptops.
at MS.Win32.UnsafeNativeMethods..
This usually means that MS .NET engineer trying to tell you:
"Hey, we didn't write this and it crashed."

DisconnectedContext MDA when calling WMI functions in single-threaded application

I write an app in C#, .NET 3.0 in VS2005 with a feature of monitoring insertion/ejection of various removable drives (USB flash disks, CD-ROMs etc.). I did not want to use WMI, since it can be sometimes ambiguous (e.g. it can spawn multiple insertion events for a single USB drive), so I simply override the WndProc of my mainform to catch the WM_DEVICECHANGE message, as proposed here. Yesterday I run into a problem when it turned out that I will have to use WMI anyway to retrieve some obscure disk details like a serial number. It turns out that calling WMI routines from inside the WndProc throws the DisconnectedContext MDA.
After some digging I ended with an awkward workaround for that. The code is as follows:
// the function for calling WMI
private void GetDrives()
{
ManagementClass diskDriveClass = new ManagementClass("Win32_DiskDrive");
// THIS is the line I get DisconnectedContext MDA on when it happens:
ManagementObjectCollection diskDriveList = diskDriveClass.GetInstances();
foreach (ManagementObject dsk in diskDriveList)
{
// ...
}
}
private void button1_Click(object sender, EventArgs e)
{
// here it works perfectly fine
GetDrives();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_DEVICECHANGE)
{
// here it throws DisconnectedContext MDA
// (or RPC_E_WRONG_THREAD if MDA disabled)
// GetDrives();
// so the workaround:
DelegateGetDrives gdi = new DelegateGetDrives(GetDrives);
IAsyncResult result = gdi.BeginInvoke(null, "");
gdi.EndInvoke(result);
}
}
// for the workaround only
public delegate void DelegateGetDrives();
which basically means running the WMI-related procedure on a separate thread - but then, waiting for it to complete.
Now, the question is: why does it work, and why does it have to be that way? (or, does it?)
I don't understand the fact of getting the DisconnectedContext MDA or RPC_E_WRONG_THREAD in the first place. How does running GetDrives() procedure from a button click event handler differs from calling it from a WndProc? Don't they happen on the same main thread of my app? BTW, my app is completely single-threaded, so why all of the sudden an error referring to some 'wrong thread'? Does the use of WMI imply multithreading and special treatment of functions from System.Management?
In the meantime I found another question related to that MDA, it's here. OK, I can take it that calling WMI means creating a separate thread for the underlying COM component - but it still does not occur to me why no-magic is needed when calling it after a button is pressed and do-magic is needed when calling it from the WndProc.
I'm really confused about that and would appreciate some clarification on that matter. There are only a few worse things than having a solution and not knowing why it works :/
Cheers,
Aleksander
There is a rather long discussion of COM Apartments and message pumping here. But the main point of interest is the message pump is used to ensure that calls in a STA are properly marshaled. Since the UI thread is the STA in question, messages would need to be pumped to ensure that everything works properly.
The WM_DEVICECHANGE message can actually be sent to the window multiple times. So in the case where you call GetDrives directly, you effectively end up with recursive calls. Put a break point on the GetDrives call and then attach a device to fire the event.
The first time you hit the break point, everything in fine. Now press F5 to continue and you will hit the break point a second time. This time the call stack is something like:
[In a sleep, wait, or join]
DeleteMeWindowsForms.exe!DeleteMeWindowsForms.Form1.WndProc(ref System.Windows.Forms.Message m) Line 46 C#
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.OnMessage(ref System.Windows.Forms.Message m) + 0x13 bytes
System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) + 0x31 bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg, System.IntPtr wparam, System.IntPtr lparam) + 0x64 bytes
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x2b bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x2d bytes
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0x10 bytes
System.Management.dll!System.Management.MTAHelper.CreateInMTA(System.Type type) + 0x17b bytes
System.Management.dll!System.Management.ManagementPath.CreateWbemPath(string path) + 0x18 bytes
System.Management.dll!System.Management.ManagementClass.ManagementClass(string path) + 0x29 bytes
DeleteMeWindowsForms.exe!DeleteMeWindowsForms.Form1.GetDrives() Line 23 + 0x1b bytes C#
So effectively the window messages are being pumped to ensure the COM calls are properly marshalled, but this has the side effect of calling your WndProc and GetDrives again (as there are pending WM_DEVICECHANGE messages) while still in a previous GetDrives call. When you use BeginInvoke, you remove this recursive call.
Again, put a breakpoint on the GetDrives call and press F5 after the first time it's hit. The next time around, wait a second or two then press F5 again. Sometimes it will fail, sometimes it won't and you'll hit your breakpoint again. This time, your callstack will include three calls to GetDrives, with the last one triggered by the enumeration of the diskDriveList collection. Because again, the messages are pumped to ensure the calls are marshaled.
It's hard to pinpoint exactly why the MDA is triggered, but given the recursive calls it reasonable to assume the COM context may be torn down prematurely and/or an object is collected before the underlying COM object can be released.

Categories

Resources