question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Hang when disposing winform in mixed C++/C# interop scenario

See original GitHub issue

.NET version

7.0

Did it work in .NET Framework?

Yes

Did it work in any of the earlier releases of .NET Core or .NET 5+?

No

Issue description

I am trying to debug an issue in code I inherited from someone else, where a form is instantiated using a .NET7 plugin. This plugin ia used to localise other .NET applications, and is able to provide an emulation of a third-party .NET app’s UI, by creating a blank form and populating it with the controls that exist in the third party app. This emulation allows translators to assess the visual impact of translations on particular controls with text, like buttons, labels etc.

Our plugin is invoked using COM Interop by a C++ MFC application, and the handle of the form is used by the native side so the form can be parented by or re-located/re-sized on the screen relative to other MFC UI components. The native code also starts a timer which periodically polls the .NET7 plugin for changes made by a user, such as changes in control selection, edits made to text etc - an event based approach which notifies the native code would probably be better but as I said, this is code I inherited and has worked to date.

This code worked without issue in .NET Framework, but in .NET, we’re seeing a problem when re-drawing our own blank form. We call Form.Close() on it, which eventually calls our override of Dispose, and it’s here that it hangs. It doesn’t seem to happen when the form is first created, but on repopulation of its content instead.

I thought it might be something to do with our timer which executes asycnchronously with respect to user-initiated UI events causing some kind of race condition which corrupts the form in some way, such as dispose being called while a UI event is being handled, but it doesn’t seem to be the case.

Our .NET plugin loads third-party assemblies into their own assembly load contexts, so I made sure that our code and the assembly code was located in the same context, but that made no difference.

I also investigated to see if Dispose was being called multiple times on the same object but it doesn’t seem to be the case. The call stack is quite deep and disappears into Windows DLLs so I can’t see anything other than function names:

```

win32u.dll!NtUserMsgWaitForMultipleObjectsEx() Unknown user32.dll!RealMsgWaitForMultipleObjectsEx() Unknown combase.dll!CCliModalLoop::BlockFn(void * * ahEvent, unsigned long cEvents, unsigned long * lpdwSignaled) Line 2156 C++ combase.dll!ModalLoop(CSyncClientCall * pClientCall) Line 166 C++ combase.dll!ClassicSTAThreadDispatchCrossApartmentCall(tagRPCOLEMESSAGE * pMessage, OXIDEntry * pOXIDEntry, CSyncClientCall * pClientCall) Line 319 C++ [Inline Frame] combase.dll!CSyncClientCall::SwitchAptAndDispatchCall(tagRPCOLEMESSAGE * pMessage) Line 5856 C++ combase.dll!CSyncClientCall::SendReceive2(tagRPCOLEMESSAGE * pMessage, unsigned long * pstatus) Line 5459 C++ [Inline Frame] combase.dll!SyncClientCallRetryContext::SendReceiveWithRetry(tagRPCOLEMESSAGE *) Line 1542 C++ [Inline Frame] combase.dll!CSyncClientCall::SendReceiveInRetryContext(SyncClientCallRetryContext ) Line 565 C++ combase.dll!ClassicSTAThreadSendReceive(CSyncClientCall * pClientCall, tagRPCOLEMESSAGE * pMsg, unsigned long * pulStatus) Line 547 C++ combase.dll!CSyncClientCall::SendReceive(tagRPCOLEMESSAGE * pMessage, unsigned long * pulStatus) Line 726 C++ combase.dll!CClientChannel::SendReceive(tagRPCOLEMESSAGE * pMessage, unsigned long * pulStatus) Line 655 C++ combase.dll!NdrExtpProxySendReceive(void * pThis, _MIDL_STUB_MESSAGE * pStubMsg) Line 2002 C++ rpcrt4.dll!NdrpClientCall3() Unknown combase.dll!ObjectStublessClient(void * ParamAddress, __int64 * FloatRegisters, long Method) Line 369 C++ combase.dll!ObjectStubless() Line 176 Unknown combase.dll!CObjectContext::InternalContextCallback(HRESULT()(void *) pfnCallback, void * pParam, const _GUID & riid, int iMethod, IUnknown * pUnk) Line 4328 C++ combase.dll!CGIPTable::GetInterfaceFromGlobal(unsigned long dwCookie, const _GUID & riid, void * * ppv) Line 1694 C++ UIAutomationCore.dll!00007ff804649779() Unknown UIAutomationCore.dll!00007ff80460e763() Unknown UIAutomationCore.dll!00007ff804630b86() Unknown UIAutomationCore.dll!00007ff804630361() Unknown [Managed to Native Transition] System.Windows.Forms.dll!System.Windows.Forms.Control.ReleaseUiaProvider(nint handle) Unknown System.Windows.Forms.dll!System.Windows.Forms.Control.WmDestroy(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.ScrollableControl.WndProc(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(nint hWnd, Interop.User32.WM msg, nint wparam, nint lparam) Unknown [Native to Managed Transition] user32.dll!UserCallWinProcCheckWow() Unknown user32.dll!DispatchClientMessage() Unknown user32.dll!__fnDWORD() Unknown ntdll.dll!00007ff83df90ef4() Unknown win32u.dll!NtUserDestroyWindow() Unknown System.Windows.Forms.Primitives.dll!00007fffb2858e60() Unknown [Managed to Native Transition] System.Windows.Forms.Primitives.dll!Interop.User32.DestroyWindow(IHandle hWnd) Unknown System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DestroyHandle() Unknown System.Windows.Forms.dll!System.Windows.Forms.Control.DestroyHandle() Unknown System.Windows.Forms.dll!System.Windows.Forms.Control.Dispose(bool disposing) Unknown System.Windows.Forms.dll!System.Windows.Forms.Form.Dispose(bool disposing) Unknown MyDll.dll!MyForm.Dispose(bool disposing) Line 194 C# System.ComponentModel.Primitives.dll!System.ComponentModel.Component.Dispose() Unknown System.Windows.Forms.dll!System.Windows.Forms.Form.WmClose(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.Form.WndProc(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message m) Unknown System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Callback(nint hWnd, Interop.User32.WM msg, nint wparam, nint lparam) Unknown [Native to Managed Transition] user32.dll!UserCallWinProcCheckWow() Unknown user32.dll!DispatchClientMessage() Unknown user32.dll!__fnDWORD() Unknown ntdll.dll!00007ff83df90ef4() Unknown win32u.dll!NtUserMessageCall() Unknown user32.dll!SendMessageWorker(struct tagWND *,unsigned int,unsigned __int64,int64,int) Unknown user32.dll!SendMessageW() Unknown Microsoft.VisualStudio.Debugger.Runtime.Impl.dll!00007fffbc9819f7() Unknown System.Windows.Forms.Primitives.dll!00007fffb285efe6() Unknown [Managed to Native Transition] System.Windows.Forms.Primitives.dll!Interop.User32.SendMessageW(IHandle hWnd, Interop.User32.WM Msg, nint wParam, nint lParam) Unknown System.Windows.Forms.dll!System.Windows.Forms.Form.Close() Unknown MyDll.dll!MyForm.Close() Line 67 C# pDotNetInterface) Line 717 C++ mfc140u.dll!00007fffe28487ef() Unknown mfc140u.dll!00007fffe284608e() Unknown mfc140u.dll!00007fffe2846454() Unknown mfc140u.dll!00007fffe26e95c9() Unknown user32.dll!UserCallWinProcCheckWow() Unknown user32.dll!CallWindowProcW() Unknown Microsoft.VisualStudio.Debugger.Runtime.Impl.dll!00007fffbc981a76() Unknown ToolkitPro2030vc170x64U.dll!CXTPHookManager::HookWndProc(HWND * hWnd, unsigned int message, unsigned __int64 wParam, __int64 lParam) Line 449 C++ user32.dll!UserCallWinProcCheckWow() Unknown user32.dll!DispatchMessageWorker() Unknown mfc140u.dll!00007fffe282ea82() Unknown mfc140u.dll!00007fffe282f385() Unknown MyApp::Run() Line 995 C++ mfc140u.dll!00007fffe2862380() Unknown [Inline Frame] Catalyst.exe!invoke_main() Line 118 C++ MyApp.exe!__scrt_common_main_seh() Line 288 C++ kernel32.dll!00007ff83c147614() Unknown ntdll.dll!00007ff83df426a1() Unknown



### Steps to reproduce

I don't have any easy way to repro this as I don't have an easy way to create a  sample MFC/.NET interop project.

Issue Analytics

  • State:closed
  • Created 9 months ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
ericcdubcommented, Dec 21, 2022

Thanks for your replies all. I’ve resolved this on my side.

After a week of digging around and wild goose chases, I found out that our app (MDI +. NET via COM interop) was launching a modal file picker dialog from within an open child frame instance but outside of the main app thread. Once I interacted with a visible WinForm afterwards, the whole UI would hang.

When I refactored to open the dialog from inside the child frame’s thread, the hang resolved.

The call stack I posted was produced when I clicked “break all” in the debugger, but it seems it was a red herring. I’m guessing the creation of the dialog was gumming up a message pump of the main frame or a child frame, and had a knock on effect in winforms, or corrupting the state of the open child frame.

Will close this shortly unless someone has something to add.

0reactions
dmitrii-drobotovcommented, Dec 22, 2022

@ericcdub thanks for an update, glad it was resolved! I think we are safe to close it then.

Read more comments on GitHub >

github_iconTop Results From Across the Web

c# - WinForm Application UI Hangs during Long-Running ...
You can of course create the BackgroundWorker manually from code, just remember that it needs disposing of when you are finished.
Read more >
Cannot debug net6.0-macos Apps - Developer Community
A fix for this issue has been internally implemented and is being prepared for release. We'll update you once it becomes available for...
Read more >
Performance Improvements in .NET 7
NET 7 is fast. Really fast. This post deep-dives into hundreds of performance improvements that contributed to that reality.
Read more >
Dealing with Powershell Inputs via Basic Windows Form
In this article, few examples of embedding basic Windows Forms and WPF in Powershell script for collecting user inputs are given.
Read more >
C# 10 in a Nutshell
C# 10 takes this syntax further, letting you mix assignment and declaration in the same deconstruction: var point = (3, 4); double x...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found