Nate Diamond
Nate Diamond

Reputation: 5575

Getting Access Violation stemming from Windows.UI.Xaml.dll in C# WinRT app

I have a WinRT app in which I have a page with a Button. The button opens up one of our Settings Flyouts. In order to do this, button's Click event is asynchronous.

In the Flyout's class I have an asynchronous Show() method which returns a Task, much like MessageDialogs. The method initializes a ResultCompletionSource<object>, along with a Popup. It opens the Popup, then returns the ResultCompletionSource<T>.Task so that it can be awaited on.

In order that multiple Panes not be created, I have it set Button.IsEnabled to false immediately upon button press, and return it to true after the completion of the event (and awaiting the Task).

The problem I am having is that if a user were to rapidly click the button in question, eventually it crashes the app, and unpredictably so. Sometimes it's after 4 clicks, sometimes after 20.

I've tried catching the exception and finding out where it is in the debugger. Finding it required debugging with the Native debugger (well, I did Mixed). The exception is a win32 Access Violation exception that is stems from Windows.UI.Xaml.dll.

Is something not getting marshalled back to the UI thread possibly? The Popup which has the Flyout as its Child has LightDismissEnabled = true, which is what (in this scenario) calls the Closed event, which in turn sets the Result of the TaskCompletionSource.

Some basic code describing the issue:

In CustomFlyout:

public Task<object> ShowAsync()
{
    resultCompletionSource = new TaskCompletionSource<object>();
    parentPopup = new Popup();
    //Set all of the height/width/bounds of the popup, along with setting the Closed Event.

    parentPopup.Child = this;
    parentPopup.IsOpen = true;

    return resultCompletionSource.Task;
}

void parentPopup_Closed(object sender, object e)
{
    if(resultCompletionSource != null)
    {
        resultCompletionSource.SetResult(null);
    }

    try
    {
        (sender as Popup).Closed -= parentPopup_closed;
    }
    catch{}
}

Button click in my page:

private async void ShowFlyout_Button_Click(object sender, RoutedEventArgs e)
{
    ShowFlyout_Button.IsEnabled = false;
    try
    {
        CustomSettingsFlyout flyout = new CustomSettingsFlyout();
        await flyout.ShowAsync()
    }
    catch{}
    finally
    {
        ShowFlyout_Button.IsEnabled = false;
    }
}

I don't have access to the C UIElement source, but the debugger/disassembler gave me this stack trace:

>Windows.UI.Xaml.dll!CUIElement::GetRedirectionTransformsAndParentCompNode(CRenderTarget * pRenderTarget, TransformAndClipStack * pTransformsToParentCompNode, CMILMatrix * pTransformToRoot, unsigned int * pIsTransformToRootAnimating, unsigned int * pAreAllAncestorsVisible, HWCompTreeNode * * ppNearestCompNode) Line 7462   C++
Windows.UI.Xaml.dll!CUIElement::GetRedirectionTransformsAndParentCompNode(CRenderTarget * pRenderTarget, TransformAndClipStack * pTransformsToParentCompNode, CMILMatrix * pTransformToRoot, unsigned int * pIsTransformToRootAnimating, unsigned int * pAreAllAncestorsVisible, HWCompTreeNode * * ppNearestCompNode) Line 7495    C++
Windows.UI.Xaml.dll!HWWalk::RenderProperties(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int * pSkipRenderWhileInheritedCollapsed, unsigned int * pSkipRenderWhileTransparent, unsigned int * pSkipRenderWhileClippedOut, unsigned int * pSkipRenderWhileLayoutClippedOut, unsigned int * pSkipRenderWhileTransformTooSmall) Line 441   C++
Windows.UI.Xaml.dll!HWWalk::Render(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int redirectedDraw) Line 199 C++
Windows.UI.Xaml.dll!HWWalk::RenderContentAndChildren(CUIElement * pUIElement, HWRenderParams & myRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int elementHasCompNode) Line 3461    C++
Windows.UI.Xaml.dll!HWWalk::RenderProperties(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int * pSkipRenderWhileInheritedCollapsed, unsigned int * pSkipRenderWhileTransparent, unsigned int * pSkipRenderWhileClippedOut, unsigned int * pSkipRenderWhileLayoutClippedOut, unsigned int * pSkipRenderWhileTransformTooSmall) Line 629   C++
Windows.UI.Xaml.dll!HWWalk::Render(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int redirectedDraw) Line 199 C++
Windows.UI.Xaml.dll!HWWalk::RenderContentAndChildren(CUIElement * pUIElement, HWRenderParams & myRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int elementHasCompNode)  C++
Windows.UI.Xaml.dll!HWWalk::RenderProperties(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int * pSkipRenderWhileInheritedCollapsed, unsigned int * pSkipRenderWhileTransparent, unsigned int * pSkipRenderWhileClippedOut, unsigned int * pSkipRenderWhileLayoutClippedOut, unsigned int * pSkipRenderWhileTransformTooSmall) Line 629   C++
Windows.UI.Xaml.dll!HWWalk::Render(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int redirectedDraw) Line 199 C++
Windows.UI.Xaml.dll!HWWalk::RenderContentAndChildren(CUIElement * pUIElement, HWRenderParams & myRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int elementHasCompNode) Line 3461    C++
Windows.UI.Xaml.dll!HWWalk::RenderProperties(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int requiresRedirectedDrawing, unsigned int * pSkipRenderWhileInheritedCollapsed, unsigned int * pSkipRenderWhileTransparent, unsigned int * pSkipRenderWhileClippedOut, unsigned int * pSkipRenderWhileLayoutClippedOut, unsigned int * pSkipRenderWhileTransformTooSmall) Line 629   C++
Windows.UI.Xaml.dll!HWWalk::Render(CUIElement * pUIElement, const HWRenderParams & parentRP, D2DRenderContext & d2dRenderContext, unsigned int redirectedDraw) Line 199 C++
Windows.UI.Xaml.dll!HWWalk::RenderRoot(CUIElement * pVisualRoot, CRenderTarget * pRenderTarget, HWInstance * pPersistentRenderDataSentinel, HWCrossFrameResources * pCrossFrameResources, HWFrameData * pPreviousFrameData, unsigned int backgroundColor, unsigned int forceRedraw, unsigned int needsToReleaseHardwareResources, unsigned int isOverdrawHeatMapEnabled, TransformAndClipStack * pPrependTransformAndClip, const CMILMatrix & displayOrientationTransform, const CMILMatrix & displayOrientationTransformInverse, unsigned int forceAllSlotsDirty, HWCompTreeNode * * ppRootNode, BrushCloneList * * ppBrushCloneList, unsigned int * pHasRenderedContent) Line 3847    C++
Windows.UI.Xaml.dll!CCoreServices::RenderWalk(HWWalk * pHWWalk, ICoreRenderTarget * pIRenderTarget, VisualTree * pVisualTree, CSwapChainBackgroundPanel * pSCBP, unsigned int uBackgroundColor, unsigned int forceRedraw, unsigned int needsToReleaseHardwareResources, unsigned int isOverdrawHeatMapEnabled, unsigned int forceAllSlotsDirty) Line 11478  C++
Windows.UI.Xaml.dll!CCoreServices::NWDrawTree(HWWalk * pHWWalk, ICoreRenderTarget * pIRenderTarget, VisualTree * pVisualTree, unsigned int uBackgroundColor, unsigned int forceRedraw, unsigned int needsToReleaseHardwareResources, XRECT_WH * prcDirtyRect) Line 10985    C++
Windows.UI.Xaml.dll!CCoreServices::NWDrawMainTree(ICoreRenderTarget * pIRenderTarget, unsigned int fForceRedraw, unsigned int needsToReleaseHardwareResources, XRECT_WH * prcDirtyRect) Line 10697  C++
Windows.UI.Xaml.dll!CWindowRenderTarget::Draw(ICoreServices * pCore, unsigned int fForceRedraw, XRECT_WH * prcDirtyRect) Line 128   C++
Windows.UI.Xaml.dll!CXcpBrowserHost::OnTick() Line 1160 C++
Windows.UI.Xaml.dll!CXcpDispatcher::Tick() Line 1120    C++
Windows.UI.Xaml.dll!CJupiterControl::HandleWindowMessage(unsigned int uMsg, unsigned int wParam, long lParam) Line 249  C++
Windows.UI.Xaml.dll!CJupiterWindow::WindowProc(HWND__ * hwnd, unsigned int uMsg, unsigned int wParam, long lParam) Line 354 C++
Windows.UI.Xaml.dll!CJupiterWindow::StaticWindowProc(HWND__ * hwnd, unsigned int uMsg, unsigned int wParam, long lParam) Line 208   C++
user32.dll!_InternalCallWinProc@20()    Unknown
user32.dll!_UserCallWinProcCheckWow@36()    Unknown
user32.dll!_DispatchClientMessage@24()  Unknown
user32.dll!___fnDWORD@4()   Unknown
ntdll.dll!_KiUserCallbackDispatcher@12()    Unknown
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessMessage(int bDrainQueue, int * pbAnyMessages) Line 110    C++
Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessEvents(Windows::UI::Core::CoreProcessEventsOption options) Line 184   C++
Windows.UI.Xaml.dll!CJupiterWindow::RunCoreWindowMessageLoop() Line 416 C++
Windows.UI.Xaml.dll!CJupiterControl::RunMessageLoop() Line 714  C++
Windows.UI.Xaml.dll!DirectUI::DXamlCore::RunMessageLoop() Line 2538 C++
Windows.UI.Xaml.dll!DirectUI::FrameworkView::Run() Line 91  C++
twinapi.dll!`Windows::ApplicationModel::Core::CoreApplicationViewAgileContainer::RuntimeClassInitialize'::`55'::<lambda_A2234BA2CCD64E2C>::operator()(void * pv) Line 560   C++
twinapi.dll!`Windows::ApplicationModel::Core::CoreApplicationViewAgileContainer::RuntimeClassInitialize'::`55'::<lambda_A2234BA2CCD64E2C>::<helper_func>(void * pv) Line 613    C++
SHCore.dll!_SHWaitForThreadWithWakeMask@12()    Unknown
kernel32.dll!@BaseThreadInitThunk@12()  Unknown
ntdll.dll!___RtlUserThreadStart@8() Unknown
ntdll.dll!__RtlUserThreadStart@8()  Unknown

The only thing I can think of is that somewhere I should be manually marshalling a call to the UI thread with CoreDispather.Invoke, but I'm at a loss for where.

If any MSFT-y has the source and wants to look at the file that's causing the issue, the debugger is pointing me towards d:\win8_gdr\windows\dxaml\xcp\core\core\elements\uielement.cpp, which is obviously not on my system.

Any help would be greatly appreciated.

Upvotes: 1

Views: 1555

Answers (1)

Nate Diamond
Nate Diamond

Reputation: 5575

I seem to have found the answer, taken from the SettingsFlyout example (but not the Popup example).

The SettingsFlyout example has you add

parentPopup.Closed += OnPopupClosed;
Window.Current.Activated += OnWindowActivated;

to the Popup, with the methods being

private void OnWindowActivated(object sender, Windows.UI.Core.WindowActivatedEventArgs e)
    {
        if (e.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.Deactivated)
        {
            parentPopup.IsOpen = false;
        }
    }

void OnPopupClosed(object sender, object e)
    {
        Window.Current.Activated -= OnWindowActivated;
    }

This seems to have fixed the crashes. I haven't been able to get it to repro no matter how vigorously I attack the Show Flyout button.

Upvotes: 1

Related Questions