AccessibleObjectFromEvent call inside SetWinEventHook callback causes deadlocks





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}







0















Both the callback and the AccessibleObjectFromEvent call appear to be working as intended, and I'm not using any locking mechanisms, but if AccessibleObjectFromEvent is present in the callback the winforms form will occasionally lock up.



I noticed when it freezes it has this odd property where right-clicking on its taskbar icon unfreezes it.



Pausing with the debugger just takes you to Application.Run(new Form1()), and nothing appears blocked on the .Net side - the debugger's window updates can even trigger some Active Accessibility events and then let you step through those events in the callback - working - all while the form remains frozen!



I note that AccessibleObjectFromEvent works by sending a WM_GETOBJECT message, but the .Net side is never stuck at the AccessibleObjectFromEvent call, and calling AccessibleObjectFromEvent from inside a SetWinEventHook callback is AFAIK a normal way to do Active Accessibility.



I've not noticed any correlation with Active Accessibility events when it freezes, but I don't really have enough information to rule that out. I also tried it compiled x86 (instead of Any), and that made no difference.



I boiled it down to its most minimal form:



using Accessibility;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApp1 {
static class Program {

// PInvoke declarations, see http://www.pinvoke.net/default.aspx/user32.setwineventhook
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, WinEventFlag dwFlags);
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("oleacc.dll")]
public static extern uint AccessibleObjectFromEvent(IntPtr hwnd, uint dwObjectID, uint dwChildID, out IAccessible ppacc, [MarshalAs(UnmanagedType.Struct)] out object pvarChild);

[Flags]
public enum WinEventFlag : uint {
/// <summary>Events are ASYNC</summary>
Outofcontext = 0x0000,
/// <summary>Don't call back for events on installer's thread</summary>
Skipownthread = 0x0001,
/// <summary>Don't call back for events on installer's process</summary>
Skipownprocess = 0x0002,
/// <summary>Events are SYNC, this causes your dll to be injected into every process</summary>
Incontext = 0x0004
}

static IntPtr hookHandle = IntPtr.Zero;
static GCHandle garbageCollectorHandle;

static void AccessibilityEventHandler(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
try {
object objChild = null;
IAccessible accWindow = null;
AccessibleObjectFromEvent(hWnd, (uint)idObject, (uint)idChild, out accWindow, out objChild);
Debug.WriteLine("Hook was invoked");
} catch (Exception ex) {
Debug.WriteLine("Exception " + ex);
}
}

[STAThread]
static void Main() {
WinEventDelegate callback = new WinEventDelegate(AccessibilityEventHandler);
// Use the member garbageCollectorHandle to keep the delegate object in memory. Might not be needed, and can't properly pin it because it's not a primitive type.
garbageCollectorHandle = GCHandle.Alloc(callback);

SetWinEventHook(
0x7546, // eventMin (0x7546 = PropertyChanged_IsOffscreen)
0x7546, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

// Two hooks are not necessary to cause a freeze, but with two it can happen much faster - sometimes within minutes
SetWinEventHook(
0x0001, // eventMin (0x0001 = System_Sound)
0x0001, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}


With such a minimal app it's harder to notice the message pump freeze, but you won't be able to drag the window or bring it to the foreground once it's locked. The bug is intermittent, often it happens within 5 minutes, sometimes it takes so long I give up, if you leave it overnight and the form is still responsive in the morning then it might depend on machine/OS (tried on Win 10.0.17174 and 10.0.17763, .net 4.5.2 and 4.6.1).



I'm 99% sure the call to AccessibleObjectFromEvent is required for the app to freeze, but with intermittent freezes there's no way to absolutely know for sure.



Reentrancy



Following Jimi's suggestions in the comments, I ran the minimal app with the flags



WinEventFlag.Outofcontext | WinEventFlag.Skipownthread | WinEventFlag.Skipownprocess



It took a while to freeze, but has still frozen. The Debug.WriteLine() calls indicate it's still responding to Active Accessibility events normally - i.e. no recursive busy-loop is happening through that callback (at least not now that I'm looking), but the form is frozen. It's using 0% CPU in the task manager.



The freeze is slightly different now, in that the task manager doesn't list it as "not responding" and I can bring it to the foreground by left-clicking the taskbar icon - normally the taskbar can't even bring it to the foreground. However the form still can't be moved or resized, and you can't bring the form to the foreground by clicking on it.



I'd also added some Debug.WriteLine in front of the AccessibleObjectFromEvent call, and tracked reentrancy depth, I can see that it is occasionally reentrant, but usually to a depth of only one before unwinding, and no deeper than 13 before fully unwinding. This appears to be caused by there being many events already in the message queue, rather than the hook handler recursively causing events it must then handle. The UI is currently frozen and the hook handler is 0 deep (i.e. not currently reentrant).










share|improve this question

























  • I would add WINEVENT_SKIPOWNTHREAD = 0x0001 and WINEVENT_SKIPOWNPROCESS = 0x0002 to WinEventFlag.Outofcontext.

    – Jimi
    Jan 4 at 1:02











  • I've seen it occur with both of those flags set, though I've not tried them both at the same time. I'll confirm it still happens and if so I'll update the code in the question.

    – Treer
    Jan 4 at 1:05








  • 1





    See also: Guarding Against Reentrancy in Hook Functions

    – Jimi
    Jan 4 at 1:17






  • 1





    There is no practical way to debug these kind of deadlocks, they occur in ring0 kernel code. Possible ways to get ahead are removing the jitter forcing (Project > Properties > Build tab) so the process can run in 64-bit mode, stay away from event 0x7546 for now and using Application.OpenForms[0].BeginInvoke() to run the Debug.WriteLine code and minimize the re-entrancy risks. You also need to test this on a relatively clean machine, minimizing the risk of another Automation client causing this problem. Do document the Windows version.

    – Hans Passant
    Jan 5 at 15:41











  • Thanks. I've added the Win version (10.0.17174 and 10.0.17763) and will try on a cleaner machine. The 0x7546 events could well be part of the problem, they looked to be the only useful Active Accessibility event for awareness of UWP alerts/toasts/Action Center, but hopefully there is a better API a desktop app can use for that special case.

    – Treer
    Jan 6 at 7:06




















0















Both the callback and the AccessibleObjectFromEvent call appear to be working as intended, and I'm not using any locking mechanisms, but if AccessibleObjectFromEvent is present in the callback the winforms form will occasionally lock up.



I noticed when it freezes it has this odd property where right-clicking on its taskbar icon unfreezes it.



Pausing with the debugger just takes you to Application.Run(new Form1()), and nothing appears blocked on the .Net side - the debugger's window updates can even trigger some Active Accessibility events and then let you step through those events in the callback - working - all while the form remains frozen!



I note that AccessibleObjectFromEvent works by sending a WM_GETOBJECT message, but the .Net side is never stuck at the AccessibleObjectFromEvent call, and calling AccessibleObjectFromEvent from inside a SetWinEventHook callback is AFAIK a normal way to do Active Accessibility.



I've not noticed any correlation with Active Accessibility events when it freezes, but I don't really have enough information to rule that out. I also tried it compiled x86 (instead of Any), and that made no difference.



I boiled it down to its most minimal form:



using Accessibility;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApp1 {
static class Program {

// PInvoke declarations, see http://www.pinvoke.net/default.aspx/user32.setwineventhook
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, WinEventFlag dwFlags);
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("oleacc.dll")]
public static extern uint AccessibleObjectFromEvent(IntPtr hwnd, uint dwObjectID, uint dwChildID, out IAccessible ppacc, [MarshalAs(UnmanagedType.Struct)] out object pvarChild);

[Flags]
public enum WinEventFlag : uint {
/// <summary>Events are ASYNC</summary>
Outofcontext = 0x0000,
/// <summary>Don't call back for events on installer's thread</summary>
Skipownthread = 0x0001,
/// <summary>Don't call back for events on installer's process</summary>
Skipownprocess = 0x0002,
/// <summary>Events are SYNC, this causes your dll to be injected into every process</summary>
Incontext = 0x0004
}

static IntPtr hookHandle = IntPtr.Zero;
static GCHandle garbageCollectorHandle;

static void AccessibilityEventHandler(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
try {
object objChild = null;
IAccessible accWindow = null;
AccessibleObjectFromEvent(hWnd, (uint)idObject, (uint)idChild, out accWindow, out objChild);
Debug.WriteLine("Hook was invoked");
} catch (Exception ex) {
Debug.WriteLine("Exception " + ex);
}
}

[STAThread]
static void Main() {
WinEventDelegate callback = new WinEventDelegate(AccessibilityEventHandler);
// Use the member garbageCollectorHandle to keep the delegate object in memory. Might not be needed, and can't properly pin it because it's not a primitive type.
garbageCollectorHandle = GCHandle.Alloc(callback);

SetWinEventHook(
0x7546, // eventMin (0x7546 = PropertyChanged_IsOffscreen)
0x7546, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

// Two hooks are not necessary to cause a freeze, but with two it can happen much faster - sometimes within minutes
SetWinEventHook(
0x0001, // eventMin (0x0001 = System_Sound)
0x0001, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}


With such a minimal app it's harder to notice the message pump freeze, but you won't be able to drag the window or bring it to the foreground once it's locked. The bug is intermittent, often it happens within 5 minutes, sometimes it takes so long I give up, if you leave it overnight and the form is still responsive in the morning then it might depend on machine/OS (tried on Win 10.0.17174 and 10.0.17763, .net 4.5.2 and 4.6.1).



I'm 99% sure the call to AccessibleObjectFromEvent is required for the app to freeze, but with intermittent freezes there's no way to absolutely know for sure.



Reentrancy



Following Jimi's suggestions in the comments, I ran the minimal app with the flags



WinEventFlag.Outofcontext | WinEventFlag.Skipownthread | WinEventFlag.Skipownprocess



It took a while to freeze, but has still frozen. The Debug.WriteLine() calls indicate it's still responding to Active Accessibility events normally - i.e. no recursive busy-loop is happening through that callback (at least not now that I'm looking), but the form is frozen. It's using 0% CPU in the task manager.



The freeze is slightly different now, in that the task manager doesn't list it as "not responding" and I can bring it to the foreground by left-clicking the taskbar icon - normally the taskbar can't even bring it to the foreground. However the form still can't be moved or resized, and you can't bring the form to the foreground by clicking on it.



I'd also added some Debug.WriteLine in front of the AccessibleObjectFromEvent call, and tracked reentrancy depth, I can see that it is occasionally reentrant, but usually to a depth of only one before unwinding, and no deeper than 13 before fully unwinding. This appears to be caused by there being many events already in the message queue, rather than the hook handler recursively causing events it must then handle. The UI is currently frozen and the hook handler is 0 deep (i.e. not currently reentrant).










share|improve this question

























  • I would add WINEVENT_SKIPOWNTHREAD = 0x0001 and WINEVENT_SKIPOWNPROCESS = 0x0002 to WinEventFlag.Outofcontext.

    – Jimi
    Jan 4 at 1:02











  • I've seen it occur with both of those flags set, though I've not tried them both at the same time. I'll confirm it still happens and if so I'll update the code in the question.

    – Treer
    Jan 4 at 1:05








  • 1





    See also: Guarding Against Reentrancy in Hook Functions

    – Jimi
    Jan 4 at 1:17






  • 1





    There is no practical way to debug these kind of deadlocks, they occur in ring0 kernel code. Possible ways to get ahead are removing the jitter forcing (Project > Properties > Build tab) so the process can run in 64-bit mode, stay away from event 0x7546 for now and using Application.OpenForms[0].BeginInvoke() to run the Debug.WriteLine code and minimize the re-entrancy risks. You also need to test this on a relatively clean machine, minimizing the risk of another Automation client causing this problem. Do document the Windows version.

    – Hans Passant
    Jan 5 at 15:41











  • Thanks. I've added the Win version (10.0.17174 and 10.0.17763) and will try on a cleaner machine. The 0x7546 events could well be part of the problem, they looked to be the only useful Active Accessibility event for awareness of UWP alerts/toasts/Action Center, but hopefully there is a better API a desktop app can use for that special case.

    – Treer
    Jan 6 at 7:06
















0












0








0








Both the callback and the AccessibleObjectFromEvent call appear to be working as intended, and I'm not using any locking mechanisms, but if AccessibleObjectFromEvent is present in the callback the winforms form will occasionally lock up.



I noticed when it freezes it has this odd property where right-clicking on its taskbar icon unfreezes it.



Pausing with the debugger just takes you to Application.Run(new Form1()), and nothing appears blocked on the .Net side - the debugger's window updates can even trigger some Active Accessibility events and then let you step through those events in the callback - working - all while the form remains frozen!



I note that AccessibleObjectFromEvent works by sending a WM_GETOBJECT message, but the .Net side is never stuck at the AccessibleObjectFromEvent call, and calling AccessibleObjectFromEvent from inside a SetWinEventHook callback is AFAIK a normal way to do Active Accessibility.



I've not noticed any correlation with Active Accessibility events when it freezes, but I don't really have enough information to rule that out. I also tried it compiled x86 (instead of Any), and that made no difference.



I boiled it down to its most minimal form:



using Accessibility;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApp1 {
static class Program {

// PInvoke declarations, see http://www.pinvoke.net/default.aspx/user32.setwineventhook
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, WinEventFlag dwFlags);
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("oleacc.dll")]
public static extern uint AccessibleObjectFromEvent(IntPtr hwnd, uint dwObjectID, uint dwChildID, out IAccessible ppacc, [MarshalAs(UnmanagedType.Struct)] out object pvarChild);

[Flags]
public enum WinEventFlag : uint {
/// <summary>Events are ASYNC</summary>
Outofcontext = 0x0000,
/// <summary>Don't call back for events on installer's thread</summary>
Skipownthread = 0x0001,
/// <summary>Don't call back for events on installer's process</summary>
Skipownprocess = 0x0002,
/// <summary>Events are SYNC, this causes your dll to be injected into every process</summary>
Incontext = 0x0004
}

static IntPtr hookHandle = IntPtr.Zero;
static GCHandle garbageCollectorHandle;

static void AccessibilityEventHandler(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
try {
object objChild = null;
IAccessible accWindow = null;
AccessibleObjectFromEvent(hWnd, (uint)idObject, (uint)idChild, out accWindow, out objChild);
Debug.WriteLine("Hook was invoked");
} catch (Exception ex) {
Debug.WriteLine("Exception " + ex);
}
}

[STAThread]
static void Main() {
WinEventDelegate callback = new WinEventDelegate(AccessibilityEventHandler);
// Use the member garbageCollectorHandle to keep the delegate object in memory. Might not be needed, and can't properly pin it because it's not a primitive type.
garbageCollectorHandle = GCHandle.Alloc(callback);

SetWinEventHook(
0x7546, // eventMin (0x7546 = PropertyChanged_IsOffscreen)
0x7546, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

// Two hooks are not necessary to cause a freeze, but with two it can happen much faster - sometimes within minutes
SetWinEventHook(
0x0001, // eventMin (0x0001 = System_Sound)
0x0001, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}


With such a minimal app it's harder to notice the message pump freeze, but you won't be able to drag the window or bring it to the foreground once it's locked. The bug is intermittent, often it happens within 5 minutes, sometimes it takes so long I give up, if you leave it overnight and the form is still responsive in the morning then it might depend on machine/OS (tried on Win 10.0.17174 and 10.0.17763, .net 4.5.2 and 4.6.1).



I'm 99% sure the call to AccessibleObjectFromEvent is required for the app to freeze, but with intermittent freezes there's no way to absolutely know for sure.



Reentrancy



Following Jimi's suggestions in the comments, I ran the minimal app with the flags



WinEventFlag.Outofcontext | WinEventFlag.Skipownthread | WinEventFlag.Skipownprocess



It took a while to freeze, but has still frozen. The Debug.WriteLine() calls indicate it's still responding to Active Accessibility events normally - i.e. no recursive busy-loop is happening through that callback (at least not now that I'm looking), but the form is frozen. It's using 0% CPU in the task manager.



The freeze is slightly different now, in that the task manager doesn't list it as "not responding" and I can bring it to the foreground by left-clicking the taskbar icon - normally the taskbar can't even bring it to the foreground. However the form still can't be moved or resized, and you can't bring the form to the foreground by clicking on it.



I'd also added some Debug.WriteLine in front of the AccessibleObjectFromEvent call, and tracked reentrancy depth, I can see that it is occasionally reentrant, but usually to a depth of only one before unwinding, and no deeper than 13 before fully unwinding. This appears to be caused by there being many events already in the message queue, rather than the hook handler recursively causing events it must then handle. The UI is currently frozen and the hook handler is 0 deep (i.e. not currently reentrant).










share|improve this question
















Both the callback and the AccessibleObjectFromEvent call appear to be working as intended, and I'm not using any locking mechanisms, but if AccessibleObjectFromEvent is present in the callback the winforms form will occasionally lock up.



I noticed when it freezes it has this odd property where right-clicking on its taskbar icon unfreezes it.



Pausing with the debugger just takes you to Application.Run(new Form1()), and nothing appears blocked on the .Net side - the debugger's window updates can even trigger some Active Accessibility events and then let you step through those events in the callback - working - all while the form remains frozen!



I note that AccessibleObjectFromEvent works by sending a WM_GETOBJECT message, but the .Net side is never stuck at the AccessibleObjectFromEvent call, and calling AccessibleObjectFromEvent from inside a SetWinEventHook callback is AFAIK a normal way to do Active Accessibility.



I've not noticed any correlation with Active Accessibility events when it freezes, but I don't really have enough information to rule that out. I also tried it compiled x86 (instead of Any), and that made no difference.



I boiled it down to its most minimal form:



using Accessibility;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace WindowsFormsApp1 {
static class Program {

// PInvoke declarations, see http://www.pinvoke.net/default.aspx/user32.setwineventhook
[DllImport("user32.dll")]
static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess, uint idThread, WinEventFlag dwFlags);
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("oleacc.dll")]
public static extern uint AccessibleObjectFromEvent(IntPtr hwnd, uint dwObjectID, uint dwChildID, out IAccessible ppacc, [MarshalAs(UnmanagedType.Struct)] out object pvarChild);

[Flags]
public enum WinEventFlag : uint {
/// <summary>Events are ASYNC</summary>
Outofcontext = 0x0000,
/// <summary>Don't call back for events on installer's thread</summary>
Skipownthread = 0x0001,
/// <summary>Don't call back for events on installer's process</summary>
Skipownprocess = 0x0002,
/// <summary>Events are SYNC, this causes your dll to be injected into every process</summary>
Incontext = 0x0004
}

static IntPtr hookHandle = IntPtr.Zero;
static GCHandle garbageCollectorHandle;

static void AccessibilityEventHandler(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) {
try {
object objChild = null;
IAccessible accWindow = null;
AccessibleObjectFromEvent(hWnd, (uint)idObject, (uint)idChild, out accWindow, out objChild);
Debug.WriteLine("Hook was invoked");
} catch (Exception ex) {
Debug.WriteLine("Exception " + ex);
}
}

[STAThread]
static void Main() {
WinEventDelegate callback = new WinEventDelegate(AccessibilityEventHandler);
// Use the member garbageCollectorHandle to keep the delegate object in memory. Might not be needed, and can't properly pin it because it's not a primitive type.
garbageCollectorHandle = GCHandle.Alloc(callback);

SetWinEventHook(
0x7546, // eventMin (0x7546 = PropertyChanged_IsOffscreen)
0x7546, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

// Two hooks are not necessary to cause a freeze, but with two it can happen much faster - sometimes within minutes
SetWinEventHook(
0x0001, // eventMin (0x0001 = System_Sound)
0x0001, // eventMax
IntPtr.Zero,
callback,
0,
0,
WinEventFlag.Outofcontext
);

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}


With such a minimal app it's harder to notice the message pump freeze, but you won't be able to drag the window or bring it to the foreground once it's locked. The bug is intermittent, often it happens within 5 minutes, sometimes it takes so long I give up, if you leave it overnight and the form is still responsive in the morning then it might depend on machine/OS (tried on Win 10.0.17174 and 10.0.17763, .net 4.5.2 and 4.6.1).



I'm 99% sure the call to AccessibleObjectFromEvent is required for the app to freeze, but with intermittent freezes there's no way to absolutely know for sure.



Reentrancy



Following Jimi's suggestions in the comments, I ran the minimal app with the flags



WinEventFlag.Outofcontext | WinEventFlag.Skipownthread | WinEventFlag.Skipownprocess



It took a while to freeze, but has still frozen. The Debug.WriteLine() calls indicate it's still responding to Active Accessibility events normally - i.e. no recursive busy-loop is happening through that callback (at least not now that I'm looking), but the form is frozen. It's using 0% CPU in the task manager.



The freeze is slightly different now, in that the task manager doesn't list it as "not responding" and I can bring it to the foreground by left-clicking the taskbar icon - normally the taskbar can't even bring it to the foreground. However the form still can't be moved or resized, and you can't bring the form to the foreground by clicking on it.



I'd also added some Debug.WriteLine in front of the AccessibleObjectFromEvent call, and tracked reentrancy depth, I can see that it is occasionally reentrant, but usually to a depth of only one before unwinding, and no deeper than 13 before fully unwinding. This appears to be caused by there being many events already in the message queue, rather than the hook handler recursively causing events it must then handle. The UI is currently frozen and the hook handler is 0 deep (i.e. not currently reentrant).







c# .net winforms winapi deadlock






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 6 at 6:42







Treer

















asked Jan 4 at 0:28









TreerTreer

370310




370310













  • I would add WINEVENT_SKIPOWNTHREAD = 0x0001 and WINEVENT_SKIPOWNPROCESS = 0x0002 to WinEventFlag.Outofcontext.

    – Jimi
    Jan 4 at 1:02











  • I've seen it occur with both of those flags set, though I've not tried them both at the same time. I'll confirm it still happens and if so I'll update the code in the question.

    – Treer
    Jan 4 at 1:05








  • 1





    See also: Guarding Against Reentrancy in Hook Functions

    – Jimi
    Jan 4 at 1:17






  • 1





    There is no practical way to debug these kind of deadlocks, they occur in ring0 kernel code. Possible ways to get ahead are removing the jitter forcing (Project > Properties > Build tab) so the process can run in 64-bit mode, stay away from event 0x7546 for now and using Application.OpenForms[0].BeginInvoke() to run the Debug.WriteLine code and minimize the re-entrancy risks. You also need to test this on a relatively clean machine, minimizing the risk of another Automation client causing this problem. Do document the Windows version.

    – Hans Passant
    Jan 5 at 15:41











  • Thanks. I've added the Win version (10.0.17174 and 10.0.17763) and will try on a cleaner machine. The 0x7546 events could well be part of the problem, they looked to be the only useful Active Accessibility event for awareness of UWP alerts/toasts/Action Center, but hopefully there is a better API a desktop app can use for that special case.

    – Treer
    Jan 6 at 7:06





















  • I would add WINEVENT_SKIPOWNTHREAD = 0x0001 and WINEVENT_SKIPOWNPROCESS = 0x0002 to WinEventFlag.Outofcontext.

    – Jimi
    Jan 4 at 1:02











  • I've seen it occur with both of those flags set, though I've not tried them both at the same time. I'll confirm it still happens and if so I'll update the code in the question.

    – Treer
    Jan 4 at 1:05








  • 1





    See also: Guarding Against Reentrancy in Hook Functions

    – Jimi
    Jan 4 at 1:17






  • 1





    There is no practical way to debug these kind of deadlocks, they occur in ring0 kernel code. Possible ways to get ahead are removing the jitter forcing (Project > Properties > Build tab) so the process can run in 64-bit mode, stay away from event 0x7546 for now and using Application.OpenForms[0].BeginInvoke() to run the Debug.WriteLine code and minimize the re-entrancy risks. You also need to test this on a relatively clean machine, minimizing the risk of another Automation client causing this problem. Do document the Windows version.

    – Hans Passant
    Jan 5 at 15:41











  • Thanks. I've added the Win version (10.0.17174 and 10.0.17763) and will try on a cleaner machine. The 0x7546 events could well be part of the problem, they looked to be the only useful Active Accessibility event for awareness of UWP alerts/toasts/Action Center, but hopefully there is a better API a desktop app can use for that special case.

    – Treer
    Jan 6 at 7:06



















I would add WINEVENT_SKIPOWNTHREAD = 0x0001 and WINEVENT_SKIPOWNPROCESS = 0x0002 to WinEventFlag.Outofcontext.

– Jimi
Jan 4 at 1:02





I would add WINEVENT_SKIPOWNTHREAD = 0x0001 and WINEVENT_SKIPOWNPROCESS = 0x0002 to WinEventFlag.Outofcontext.

– Jimi
Jan 4 at 1:02













I've seen it occur with both of those flags set, though I've not tried them both at the same time. I'll confirm it still happens and if so I'll update the code in the question.

– Treer
Jan 4 at 1:05







I've seen it occur with both of those flags set, though I've not tried them both at the same time. I'll confirm it still happens and if so I'll update the code in the question.

– Treer
Jan 4 at 1:05






1




1





See also: Guarding Against Reentrancy in Hook Functions

– Jimi
Jan 4 at 1:17





See also: Guarding Against Reentrancy in Hook Functions

– Jimi
Jan 4 at 1:17




1




1





There is no practical way to debug these kind of deadlocks, they occur in ring0 kernel code. Possible ways to get ahead are removing the jitter forcing (Project > Properties > Build tab) so the process can run in 64-bit mode, stay away from event 0x7546 for now and using Application.OpenForms[0].BeginInvoke() to run the Debug.WriteLine code and minimize the re-entrancy risks. You also need to test this on a relatively clean machine, minimizing the risk of another Automation client causing this problem. Do document the Windows version.

– Hans Passant
Jan 5 at 15:41





There is no practical way to debug these kind of deadlocks, they occur in ring0 kernel code. Possible ways to get ahead are removing the jitter forcing (Project > Properties > Build tab) so the process can run in 64-bit mode, stay away from event 0x7546 for now and using Application.OpenForms[0].BeginInvoke() to run the Debug.WriteLine code and minimize the re-entrancy risks. You also need to test this on a relatively clean machine, minimizing the risk of another Automation client causing this problem. Do document the Windows version.

– Hans Passant
Jan 5 at 15:41













Thanks. I've added the Win version (10.0.17174 and 10.0.17763) and will try on a cleaner machine. The 0x7546 events could well be part of the problem, they looked to be the only useful Active Accessibility event for awareness of UWP alerts/toasts/Action Center, but hopefully there is a better API a desktop app can use for that special case.

– Treer
Jan 6 at 7:06







Thanks. I've added the Win version (10.0.17174 and 10.0.17763) and will try on a cleaner machine. The 0x7546 events could well be part of the problem, they looked to be the only useful Active Accessibility event for awareness of UWP alerts/toasts/Action Center, but hopefully there is a better API a desktop app can use for that special case.

– Treer
Jan 6 at 7:06














0






active

oldest

votes












Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54031673%2faccessibleobjectfromevent-call-inside-setwineventhook-callback-causes-deadlocks%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54031673%2faccessibleobjectfromevent-call-inside-setwineventhook-callback-causes-deadlocks%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Monofisismo

Angular Downloading a file using contenturl with Basic Authentication

Olmecas