{"id":105727,"date":"2021-09-24T07:00:00","date_gmt":"2021-09-24T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=105727"},"modified":"2021-09-24T07:17:06","modified_gmt":"2021-09-24T14:17:06","slug":"20210924-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20210924-00\/?p=105727","title":{"rendered":"The case of the UWP application that crashes at launch on Windows 10X"},"content":{"rendered":"<p>Application compatibility testing for Windows 10X identified a program that crashed at launch. We were able to obtain a <a href=\"https:\/\/docs.microsoft.com\/en-us\/windows-hardware\/drivers\/debugger\/time-travel-debugging-overview\"> time travel trace<\/a> for the application. Let&#8217;s do some application compatibility debugging.<\/p>\n<p>Even though <a href=\"https:\/\/blogs.windows.com\/windowsexperience\/2021\/05\/18\/how-to-get-the-windows-10-may-2021-update\/\"> the Windows 10X project has been shelved<\/a>, there&#8217;s still a lesson here for other non-Desktop platforms, like Xbox, so let&#8217;s dig in.<\/p>\n<p>The application terminates here:<\/p>\n<pre> # Call Site\r\n00 SharedLibrary!$8_NativePrimitiveDecoder.DecodeUnsigned+0xe3\r\n01 SharedLibrary!$11_NativeReader.DecodeUnsigned+0x3b\r\n02 SharedLibrary!$14_NativeParser.GetUnsigned+0x23\r\n03 SharedLibrary!$11_ExecutionEnvironmentImplementation.TryGetMethodForOriginalLdFtnResult_Inner+0x30a\r\n04 SharedLibrary!$11_ExecutionEnvironmentImplementation.TryGetMethodForOriginalLdFtnResult+0xa9\r\n05 SharedLibrary!$11_ReflectionExecutionDomainCallbacksImplementation.GetMethodNameFromStartAddressIfAvailable+0x45\r\n06 SharedLibrary!DeveloperExperience.CreateStackTraceString+0x65\r\n07 SharedLibrary!StackTraceHelper.FormatStackTrace+0x8b\r\n08 SharedLibrary!Exception.get_StackTrace+0x47\r\n09 Contoso+0x1f6eaa\r\n0a Contoso+0x5a2dc3\r\n0b Windows_UI_Xaml!GetStringRawBuffer+0x1028\r\n0c Windows_UI_Xaml!GetStringRawBuffer+0x1225\r\n0d Windows_UI_Xaml!GetStringRawBuffer+0x46bc1\r\n0e Windows_UI_Xaml!GetStringRawBuffer+0x46a68\r\n0f Windows_UI_Xaml!GetStringRawBuffer+0x46443\r\n10 Windows_UI_Xaml!GetStringRawBuffer+0x46269\r\n11 twinapi_appcore!GitInvokeHelper&lt;IEventHandler&lt;Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs *&gt;&gt;::Invoke+0x5a\r\n12 twinapi_appcore!UnhandledErrorInvokeHelper::Invoke+0x1a\r\n13 twinapi_appcore!EventSource&lt;IEventHandler&lt;UnhandledErrorDetectedEventArgs *&gt;&gt;::InvokeAll::lambda::operator()+0x1d\r\n14 twinapi_appcore!InvokeTraits&lt;2&gt;::InvokeDelegates+0x4f\r\n15 twinapi_appcore!EventSource&lt;IEventHandler&lt;UnhandledErrorDetectedEventArgs *&gt;&gt;::DoInvoke+0x7b\r\n16 twinapi_appcore!EventSource&lt;IEventHandler&lt;UnhandledErrorDetectedEventArgs *&gt;&gt;::InvokeAll+0x29\r\n17 twinapi_appcore!CoreApplication::ForwardLocalError+0x73\r\n18 twinapi_appcore!CoreApplicationFactory::ForwardLocalError+0xf0\r\n19 combase!CallErrorForwarder+0x138\r\n1a SharedLibrary!$8_ExceptionHelpers.ReportUnhandledError+0xcd\r\n1b SharedLibrary!$8_InteropCallbacks.ReportUnhandledError+0x9\r\n1c Contoso+0x35d8d\r\n1d SharedLibrary!RuntimeExceptionHelpers.ReportUnhandledException+0x63\r\n1e SharedLibrary!RuntimeAugments.ReportUnhandledException+0x9\r\n1f SharedLibrary!$13_Invoker.InvokeCore$catch$0+0xa\r\n20 mrt100_app!RhpCallCatchFunclet2\r\n21 mrt100_app!RhRethrow+0x4c9\r\n22 mrt100_app!RhThrowEx+0x4f\r\n23 mrt100_app!RhpThrowEx2\r\n24 SharedLibrary!ExceptionServices::ExceptionDispatchInfo.Throw+0x22\r\n25 SharedLibrary!$22_ExceptionDispatchHelper::&lt;&gt;c__DisplayClass0.&lt;ThrowAsync&gt;b__3+0x1f\r\n26 SharedLibrary!$13_WinRTSynchronizationContext::Invoker.InvokeCore+0x4d\r\n27 SharedLibrary!$13_WinRTSynchronizationContext::Invoker.Invoke+0x1c\r\n28 SharedLibrary!Func$2&lt;__Canon,TimeSpan&gt;.InvokeOpenStaticThunk+0x1a\r\n29 SharedLibrary!$25_AsyncOperationWithProgressCompletedHandler$2&lt;__Canon,UInt32&gt;.Invoke+0x14\r\n2a Contoso+0x35d78\r\n2b Contoso+0x5a320b\r\n2c Windows_UI!CDispatcher::ProcessInvokeItem+0x2cc\r\n2d Windows_UI!CDispatcher::ProcessMessage+0x347\r\n2e Windows_UI!CDispatcher::WaitAndProcessMessagesInternal+0xc9\r\n2f Windows_UI!CDispatcher::ProcessEvents+0x132\r\n30 Windows_UI_Xaml!DllGetActivationFactory+0xbaee0\r\n31 Windows_UI_Xaml!DllGetActivationFactory+0xbae7f\r\n32 twinapi_appcore!CoreApplicationView::Run+0x3a\r\n33 twinapi_appcore!lambda::operator()+0xf2\r\n34 shcore!_WrapperThreadProc+0xfb\r\n35 ntdll!RtlUserThreadStart+0x2f\r\n<\/pre>\n<p>Reading from the bottom, we see that the UI thread is dispatching a work item. This work item is reporting an unhandled exception somewhere else in the application, and the app was trying to build a stack trace when it was terminated, presumably because it had reached some system timeout.<\/p>\n<p>Let&#8217;s fish out the stowed exception to see what the error was. The unhandled exception is provided in the event arguments.<\/p>\n<pre><span style=\"color: blue;\">\u27e6the .frame command changes to a specific stack frame\u27e7<\/span>\r\n0:008&gt; .frame 12\r\n12 0000004b`0a1fe9d0 00007fff`be4fa76b twinapi_appcore!UnhandledErrorInvokeHelper::Invoke+0x1a\r\n\r\n<span style=\"color: blue;\">\u27e6the dv command dumps the frame's local variables\u27e7<\/span>\r\n0:008&gt; dv\r\n           this = &lt;value unavailable&gt;\r\n         source = &lt;value unavailable&gt;\r\n           <span style=\"color: blue;\">args = 0x00000219`7fa93160<\/span>\r\n<span style=\"color: blue;\">\u27e6the ?? command prints a C++ expression\u27e7<\/span>\r\n0:008&gt; ?? args\r\nstruct Windows::ApplicationModel::Core::IUnhandledErrorDetectedEventArgs * 0x00000219`7fa93160\r\n   +0x000 __VFN_table : 0x00007fff`be5c1290\r\n<\/pre>\n<p>The <code>args<\/code> is an <code>IUnhandled\u00adError\u00adDetected\u00adEvent\u00adArgs<\/code>. This is an exclusive interface to the <code>Unhandled\u00adError\u00adDetected\u00adEvent\u00adArgs<\/code> runtime class, so we can take a shortcut and assume that the underlying object is an <code>Unhandled\u00adError\u00adDetected\u00adEvent\u00adArgs<\/code> object. (If we wanted to verify the long way, we would dump the vtable to see what concrete class it came from.)<\/p>\n<pre><span style=\"color: blue;\">\u27e6the dt command dumps a type\u27e7<\/span>\r\n0:008&gt; dt twinapi_appcore!Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs 0x00000219`7fa93160\r\n   +0x000 __VFN_table : 0x00007fff`be5c1290\r\n   +0x008 __VFN_table : 0x00007fff`be5c1270\r\n   +0x010 __VFN_table : 0x00007fff`be5c1228\r\n   +0x028 marshaller_      : Microsoft::WRL::ComPtr&lt;IMarshal&gt;\r\n   +0x038 refCount_        : Microsoft::WRL::Details::ReferenceCountOrWeakReferencePointer\r\n   +0x040 <span style=\"color: blue;\">_error<\/span>           : Microsoft::WRL::ComPtr&lt;Windows::ApplicationModel::Core::UnhandledError&gt;\r\n<\/pre>\n<p>I&#8217;m guessing that the <code>_error<\/code> contains the error being reported. (It had better, seeing as none of the other members appear to contain anything interesting at all!)<\/p>\n<pre><span style=\"color: blue;\">\u27e6the ?? command is handy for for more complex dumping\u27e7<\/span>\r\n0:008&gt; ?? ((twinapi_appcore!Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs*) 0x00000219`7fa93160)-&gt;_error\r\nclass Microsoft::WRL::ComPtr&lt;Windows::ApplicationModel::Core::UnhandledError&gt;\r\n   +0x000 ptr_             : 0x00000219`7fa93250 Windows::ApplicationModel::Core::UnhandledError\r\n<\/pre>\n<p>The <code>ComPtr<\/code> is a smart pointer class, so we have to dig inside to the <code>ptr_<\/code> to get the raw pointer that it is managing. Different smart pointer classes give different names to the inner raw pointer. There&#8217;s no point trying to memorize the names; just dump the type and follow your nose.<\/p>\n<pre>0:008&gt; ?? ((twinapi_appcore!Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs*) 0x00000219`7fa93160)-&gt;_error.ptr_\r\nclass Windows::ApplicationModel::Core::UnhandledError * 0x00000219`7fa93250\r\n   +0x000 __VFN_table : 0x00007fff`be5c1bf0\r\n   +0x008 __VFN_table : 0x00007fff`be5c1c38\r\n   +0x010 __VFN_table : 0x00007fff`be5c1c58\r\n   +0x028 marshaller_      : Microsoft::WRL::ComPtr&lt;IMarshal&gt;\r\n   +0x038 refCount_        : Microsoft::WRL::Details::ReferenceCountOrWeakReferencePointer\r\n   +0x040 _handled         : 0x1 ''\r\n   +0x048 _restrictedError : Microsoft::WRL::ComPtr&lt;IRestrictedErrorInfo&gt;\r\n\r\n0:008&gt; ?? ((twinapi_appcore!Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs*) 0x00000219`7fa93160)-&gt;_error.ptr_-&gt;_restrictedError\r\nclass Microsoft::WRL::ComPtr&lt;IRestrictedErrorInfo&gt;\r\n   +0x000 ptr_             : 0x00000219`777a6888 IRestrictedErrorInfo\r\n<\/pre>\n<p>We land with a raw pointer to a COM interface. It&#8217;s not clear which class implements this interface, so we&#8217;ll have to ask the vtable to identify it for us.<\/p>\n<pre><span style=\"color: blue;\">\u27e6the dps command dumps pointer-sized data in the style of a stack\u27e7<\/span>\r\n0:008&gt; dps 0x00000219`777a6888 L1\r\n00000219`777a6888  00007fff`c2b89208 combase!CRestrictedError::`vftable'\r\n<\/pre>\n<p>Okay, this is a <code>CRestricted\u00adError<\/code> object. We dump the first entry in the vtable to see how much we need to adjust our <code>this<\/code> pointer to get to the start of the object.<\/p>\n<pre><span style=\"color: blue;\">\u27e6the dpp command dumps pointer-sized data, and then dereferences it as a pointer\u27e7<\/span>\r\n0:008&gt; dpp 0x00000219`777a6888 L1\r\n00000219`777a6888  00007fff`c2b89208 00007fff`c2a85090 combase![thunk]:...::QueryInterface`adjustor{8}'\r\n<\/pre>\n<p>The <a title=\"Adjustor thunks\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040206-00\/?p=40723\"> adjustor thunk<\/a> tells us that the object starts 8 bytes earlier, so we need to subtract 8 from the pointer before dumping it as a <code>CRestricted\u00adError<\/code>. Subtracting 8 from a value that ends in 8 is easy to do in your head: Just change the 8 to a zero.<\/p>\n<pre>0:008&gt; dt combase!CRestrictedError 00000219`777a6880\r\n   +0x000 __VFN_table : 0x00007fff`c2b89230\r\n...\r\n   +0x050 _pszDescription  : 0x00000219`7faaa650  \"Class not registered..\"\r\n   +0x058 _pszRestrictedDescription : 0x00000219`7fade760  \"Class not registered (Excep_FromHResult 0x80040154)\"\r\n   +0x068 _hrError         : 80040154\r\n   +0x084 _cStackBackTrace : 0x1e\r\n   +0x088 _ppvStackBackTrace : 0x00000219`7fafc040  -&gt; 0x00007fff`c2a3d884 Void\r\n<\/pre>\n<p>So we&#8217;ve learned so far that original exception was a &#8220;Class not registered&#8221; error. I don&#8217;t know for sure, but based on the name, it&#8217;s pretty likely that <code>_ppvStackBackTrace<\/code> points to a stack backtrace, and <code>_cStackBackTrace<\/code> is the number of elements in the backtrace.<\/p>\n<pre>0:008&gt; dps 0x00000219`7fafc040 l1e\r\n00000219`7fafc040  combase!RoOriginateLanguageException+0x54\r\n00000219`7fafc048  SharedLibrary!$8_::ExceptionHelpers.OriginateLanguageException+0xf8\r\n00000219`7fafc050  SharedLibrary!$8_ExceptionHelpers.ReportUnhandledError+0x7b\r\n00000219`7fafc058  SharedLibrary!$8_InteropCallbacks.ReportUnhandledError+0x9\r\n00000219`7fafc060  Contoso+0x35d8d\r\n00000219`7fafc068  SharedLibrary!SystemRuntimeExceptionHelpers.ReportUnhandledException+0x63\r\n00000219`7fafc070  SharedLibrary!RuntimeAugments.ReportUnhandledException+0x9\r\n00000219`7fafc078  SharedLibrary!$13_WinRTSynchronizationContext::Invoker.InvokeCore$catch$0+0xa\r\n00000219`7fafc080  mrt100_app!RhpCallCatchFunclet2\r\n00000219`7fafc088  mrt100_app!RhRethrow+0x4c9\r\n00000219`7fafc090  mrt100_app!RhThrowEx+0x4f\r\n00000219`7fafc098  mrt100_app!RhpThrowEx2\r\n00000219`7fafc0a0  SharedLibrary!ExceptionDispatchInfo.Throw+0x22\r\n00000219`7fafc0a8  SharedLibrary!$22_ExceptionDispatchHelper::&lt;&gt;c__DisplayClass0.&lt;ThrowAsync&gt;b__3+0x1f\r\n00000219`7fafc0b0  SharedLibrary!$13_Invoker.InvokeCore+0x4d\r\n00000219`7fafc0b8  SharedLibrary!$13_Invoker.Invoke+0x1c\r\n00000219`7fafc0c0  SharedLibrary!Func$2&lt;__Canon,TimeSpan&gt;.InvokeOpenStaticThunk+0x1a\r\n00000219`7fafc0c8  SharedLibrary!$25_AsyncOperationWithProgressCompletedHandler$2&lt;__Canon,UInt32&gt;.Invoke+0x14\r\n00000219`7fafc0d0  Contoso+0x35d78\r\n00000219`7fafc0d8  Contoso+0x5a320b\r\n00000219`7fafc0e0  Windows_UI!CDispatcher::ProcessInvokeItem+0x2cc\r\n00000219`7fafc0e8  Windows_UI!CDispatcher::ProcessMessage+0x347\r\n00000219`7fafc0f0  Windows_UI!CDispatcher::WaitAndProcessMessagesInternal+0xc9\r\n00000219`7fafc0f8  Windows_UI!CDispatcher::ProcessEvents+0x132\r\n00000219`7fafc100  Windows_UI_Xaml!DllGetActivationFactory+0xbaee0\r\n00000219`7fafc108  Windows_UI_Xaml!DllGetActivationFactory+0xbae7f\r\n00000219`7fafc110  twinapi_appcore!CoreApplicationView::Run+0x3a\r\n00000219`7fafc118  twinapi_appcore!lambda::operator()+0xf2\r\n00000219`7fafc120  shcore!_WrapperThreadProc+0xfb\r\n00000219`7fafc128  ntdll!RtlUserThreadStart+0x2f\r\n<\/pre>\n<p>Okay, that stack trace isn&#8217;t interesting, since it&#8217;s the same stack we are on right now. What we want is the stack that generated the original exception.<\/p>\n<p>So let&#8217;s find the work item that was queued onto this thread and see who queued it.<\/p>\n<p>At this point, we take advantage of the fact that we have a time travel trace: Execute backward to the point that the work item was pulled off the queue.<\/p>\n<p>We want to go backward to this point in the stack trace:<\/p>\n<pre>2b 0000004b`0a1ff4c0 00007fff`ad9f9140 Contoso+0x5a320b\r\n2c 0000004b`0a1ff510 00007fff`ad9f790b Windows_UI!Windows::UI::Core::CDispatcher::ProcessInvokeItem+0x2cc\r\n<\/pre>\n<p>The address we want is the instruction immediately before return address of the next function deeper on the stack.<\/p>\n<pre><span style=\"color: blue;\">\u27e6the u command disassembles (\"unassembles\")\u27e7<\/span>\r\n0:008&gt; u 00007fff`ad9f9140-20 00007fff`ad9f9140\r\n00007fff`ad9f9122 488b01          mov     rax,qword ptr [rcx]\r\n00007fff`ad9f9125 488b4068        mov     rax,qword ptr [rax+68h]\r\n00007fff`ad9f9129 ff15e1a70900    call    qword ptr [Windows_UI!__guard_dispatch_icall_fptr (00007fff`ada93910)]\r\n00007fff`ad9f912f 488b4b10        mov     rcx,qword ptr [rbx+10h]\r\n00007fff`ad9f9133 488b01          mov     rax,qword ptr [rcx]\r\n00007fff`ad9f9136 488b4018        mov     rax,qword ptr [rax+18h]\r\n00007fff`ad9f913a ff15d0a70900    call    qword ptr [Windows_UI!__guard_dispatch_icall_fptr (00007fff`ada93910)]\r\n00007fff`ad9f9140 8be8            mov     ebp,eax\r\n<\/pre>\n<p>The return address is <code>00007fff`ad9f9140<\/code>, so we want to go back to the instruction before it, which is <code>00007fff`ad9f913a<\/code>.<\/p>\n<pre><span style=\"color: blue;\">\u27e6the g- command executes backward until a breakpoint is hit\u27e7<\/span>\r\n0:008&gt; g- 00007fff`ad9f913a\r\nTime Travel Position: 1D6637:68\r\nWindows_UI!Windows::UI::Core::CDispatcher::ProcessInvokeItem+0x2c6:\r\n00007fff`ad9f913a ff15d0a70900    call    qword ptr [Windows_UI!__guard_dispatch_icall_fptr (00007fff`ada93910)]\r\n\r\n0:008&gt; dv\r\n                 this = 0x00000219`74134a30\r\npbInvokeItemProcessed = 0x0000004b`0a1ff691\r\n                   hr = 0x00000000\r\n          pInvokeItem = 0x00000219`7f41a170\r\n             dwStatus = &lt;value unavailable&gt;\r\n     requiredPriority = &lt;value unavailable&gt;\r\n                  msg = {msg=0x270 wp=0x0 lp=0x1}\r\n         bucketAssist = 0x00007fff`7d731330\r\n spIdleDispatchedArgs = {...}\r\n   WPP_GLOBAL_Control = &lt;value unavailable&gt;\r\n0:008&gt; ?? pInvokeItem\r\nstruct Windows::UI::Core::_InvokeEntry * 0x00000219`7f41a170\r\n   +0x000 pNext            : 0x00000219`7f41ab30 Windows::UI::Core::_InvokeEntry\r\n   +0x008 dwTickCount      : 0x115a777\r\n   +0x00c Priority         : 0 ( CoreDispatcherPriority_Normal )\r\n   +0x010 spHandler        : Microsoft::WRL::ComPtr&lt;Windows::UI::Core::IDispatchedHandler&gt;\r\n   +0x018 spIdleHandler    : Microsoft::WRL::ComPtr&lt;Windows::UI::Core::IIdleDispatchedHandler&gt;\r\n   +0x020 spCoreAsyncInfo  : Microsoft::WRL::ComPtr&lt;Windows::UI::Core::ICoreAsyncInfo&gt;\r\n<\/pre>\n<p>Now that we&#8217;ve executed back to the point where we&#8217;re about to dispatch the work item, we can look at the local variables to get the item. (If that hadn&#8217;t worked, we could have pulled it out of the <code>rcx<\/code> register, since the code is set up to make a call.)<\/p>\n<p>The <code>pInvokeItem<\/code> looks like it&#8217;s the work item that got queued and is about to be dispatched. I want to go back to when the work item was created, so I picked a field that is probably set only at construction: The priority.<\/p>\n<pre>0:008&gt; ?? pInvokeItem-&gt;Priority\r\nWindows::UI::Core::CoreDispatcherPriority CoreDispatcherPriority_Normal (0n0)\r\n0:008&gt; ?? &amp;pInvokeItem-&gt;Priority\r\nWindows::UI::Core::CoreDispatcherPriority * 0x00000219`7f41a17c\r\n0:008&gt; ba w4 0x00000219`7f41a17c\r\n<\/pre>\n<p>We ask the debugger for the address of the <code>Priority<\/code> member and set a 4-byte write breakpoint on it. Then execute backward some more to see who sets it.<\/p>\n<pre>0:008&gt; g-\r\nBreakpoint 6 hit\r\nTime Travel Position: 1CE288:87\r\nWindows_UI!Windows::UI::Core::CDispatcher::EnqueueAsyncWork+0x390:\r\n00007fff`ad9f88bc 48ff15eda90900  call    qword ptr [Windows_UI!_imp_GetTickCount (00007fff`ada932b0)]\r\n<\/pre>\n<p>From the function name <code>Enqueue\u00adAsync\u00adWork<\/code> it appears that we found the code that creates the work item. Let&#8217;s see why it&#8217;s being created.<\/p>\n<pre><span style=\"color: blue;\">\u27e6the k command takes a stack trace\u27e7<\/span>\r\n0:008&gt; k\r\n # Call Site\r\n00 Windows_UI!Windows::UI::Core::CDispatcher::EnqueueAsyncWork+0x390\r\n01 Windows_UI!Windows::UI::Core::CDispatcher::RunAsyncWorker+0xb0\r\n02 Windows_UI!Windows::UI::Core::CDispatcher::RunAsync+0x58\r\n03 Contoso+0x150d0d\r\n04 Contoso+0x150c07\r\n05 Contoso+0x150b98\r\n06 Contoso+0x150b79\r\n07 Contoso+0x35d46\r\n08 SharedLibrary!$13_System::Threading::WinRTSynchronizationContext.Post+0x68\r\n09 SharedLibrary!$13_System::Runtime::CompilerServices::AsyncMethodBuilderCore.ThrowAsync+0x7f\r\n0a SharedLibrary!$13_System::Runtime::CompilerServices::AsyncVoidMethodBuilder.SetException+0x86\r\n0b Contoso+0x45a79c\r\n0c mrt100_app!RhpCallCatchFunclet2\r\n0d mrt100_app!RhRethrow+0x4c9\r\n0e mrt100_app!RhThrowEx+0x4f\r\n0f mrt100_app!RhpThrowEx2\r\n10 SharedLibrary!$8_Interop::WinRT.RoGetActivationFactory+0x19c\r\n11 SharedLibrary!$8_System::Runtime::InteropServices::FactoryCache.GetActivationFactoryInternal+0x5e\r\n12 SharedLibrary!$8_System::Runtime::InteropServices::FactoryCache.GetActivationFactory+0x126\r\n13 SharedLibrary!$8_System::Runtime::InteropServices::McgMarshal.GetActivationFactory+0x4a\r\n14 SharedLibrary!$8_System::Runtime::InteropServices::McgModuleManager.GetActivationFactory+0x50\r\n15 Contoso+0x3fe578\r\n16 Contoso+0x3fdb71\r\n17 Contoso+0x454fab\r\n18 Contoso+0x454f10\r\n19 Contoso+0x45a446\r\n1a Contoso+0x45a3a7\r\n1b Contoso+0x45a36c\r\n1c Contoso+0x45a351\r\n1d Contoso+0x5a2593\r\n1e Windows_UI_Xaml!GetErrorContextIndex+0x40f58\r\n1f Windows_UI_Xaml!GetErrorContextIndex+0x40cc4\r\n20 Windows_UI_Xaml!DllCanUnloadNow+0x26484\r\n21 Windows_UI_Xaml!DllCanUnloadNow+0x27e91\r\n22 Windows_UI_Xaml!DllCanUnloadNow+0x27a9d\r\n23 Windows_UI_Xaml!DllGetActivationFactory+0x243ea\r\n24 Windows_UI_Xaml!GetErrorContextIndex+0x51cf2\r\n25 Windows_UI_Xaml!GetErrorContextIndex+0x51b1e\r\n26 Windows_UI_Xaml!GetErrorContextIndex+0x519fa\r\n27 minuser!Core::Yield::WndProc+0x6b\r\n28 minuser!Core::Window::DeliverMessage+0x30f\r\n29 minuser!Core::Window::SendCommon+0x82\r\n2a minuser!Core::Window::Send+0x3a\r\n2b minuser!Core::Api::SendMessageAW+0x48\r\n2c minuser!minSendMessageAW+0x5d\r\n2d Windows_UI_Xaml!GetErrorContextIndex+0x24de7\r\n2e Windows_UI_Xaml!GetErrorContextIndex+0x4cc7c\r\n2f Windows_UI_Xaml!GetErrorContextIndex+0x47b05\r\n30 Windows_UI_Xaml!GetErrorContextIndex+0x47a0f\r\n31 Windows_UI_Xaml!GetErrorContextIndex+0x2c29f\r\n32 Windows_UI_Xaml!GetErrorContextIndex+0x9e01d\r\n33 Windows_UI_Xaml!GetErrorContextIndex+0x9deaf\r\n34 Windows_UI_Xaml!GetErrorContextIndex+0x9d7e6\r\n35 Windows_UI_Xaml!DllGetActivationFactory+0x3d26d\r\n36 Windows_UI_Xaml!DllGetActivationFactory+0x3d183\r\n37 Windows_UI_Xaml!GetErrorContextIndex+0x51a89\r\n38 Windows_UI_Xaml!GetErrorContextIndex+0x9dc1b\r\n39 Windows_UI_Xaml!GetErrorContextIndex+0x9db0c\r\n3a CoreMessaging!Microsoft__CoreUI__Dispatch__TimeoutHandler$CallbackThunk+0x11b\r\n3b CoreMessaging!Microsoft::CoreUI::Dispatch::TimeoutHandler::Invoke+0x1a\r\n3c CoreMessaging!Microsoft::CoreUI::Dispatch::TimeoutManager::Callback_OnDispatch+0x18b\r\n3d CoreMessaging!Microsoft::CoreUI::Dispatch::Dispatcher::DispatchNextItem+0x885\r\n3e CoreMessaging!Microsoft::CoreUI::Dispatch::Dispatcher::Callback_DispatchLoop+0x9e3\r\n3f CoreMessaging!Microsoft::CoreUI::Dispatch::EventLoop::Callback_RunCoreLoop+0xc45\r\n40 CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapterBase::DrainCoreMessagingQueue+0x14d\r\n41 CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter::OnUserDispatch+0x1d7\r\n42 CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter::OnUserDispatchRaw+0x9c\r\n43 CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter_DoWork+0xe9\r\n44 CoreMessaging!Microsoft::CoreUI::Dispatch::UserAdapter_WindowProc+0xa3\r\n45 minuser!Core::Yield::WndProc+0x6b\r\n46 minuser!Core::Window::DeliverMessage+0x30f\r\n47 minuser!Input::EventMessageDeliveryManager::OnDispatchNotify+0x27\r\n48 minuser!Input::EventMessageDeliveryManager$R::Delegate0+0x2b\r\n49 minuser!Core::OnWindowEventMessage::Invoke+0x65\r\n4a minuser!Input::EventMessageDeliveryManager::CheckAndConsumeMinQEventMessage+0x193\r\n4b minuser!Input::InputQueue::PeekForInput+0x2f0\r\n4c minuser!Core::ThreadInfo::ReadMessageEntryWorker+0x155\r\n4d minuser!Core::ThreadInfo::ReadMessageEntry+0x50\r\n4e minuser!Core::Api::PeekMessageAW+0x88\r\n4f minuser!minPeekMessageAW+0x66\r\n50 Windows_UI!Windows::UI::Core::CDispatcher::ProcessMessage+0xdf\r\n51 Windows_UI!Windows::UI::Core::CDispatcher::WaitAndProcessMessagesInternal+0xc9\r\n52 Windows_UI!Windows::UI::Core::CDispatcher::ProcessEvents+0x132\r\n53 Windows_UI_Xaml!DllGetActivationFactory+0xbaee0\r\n54 Windows_UI_Xaml!DllGetActivationFactory+0xbae7f\r\n55 twinapi_appcore!Windows::ApplicationModel::Core::CoreApplicationView::Run+0x3a\r\n56 twinapi_appcore!&lt;lambda_643db08282a766b00cec20194396f531&gt;::operator()+0xf2\r\n57 shcore!_WrapperThreadProc+0xfb\r\n58 ntdll!RtlUserThreadStart+0x2f\r\n<\/pre>\n<p>This is a huge stack, but it breaks down neatly into three parts.<\/p>\n<p>The part near the top of the stack is the runtime recording the failure in <code>Ro\u00adGet\u00adActivation\u00adFactory<\/code>.<\/p>\n<p>The part near the bottom is the code that led up to the failure in <code>Ro\u00adGet\u00adActivation\u00adFactory<\/code>. It looks like it was triggered by a timer.<\/p>\n<p>Let&#8217;s see what we were trying to activate.<\/p>\n<pre>0:008&gt; .frame 11\r\n11 0000004b`0a1fd8d0 00007fff`7c209536 SharedLibrary!$8_FactoryCache.GetActivationFactoryInternal+0x5e\r\n0:008&gt; dv\r\n       typeName = 0x00007fff`7ce64060\r\n       typeInfo = 0x0000004b`0a1fdb58\r\n currentContext = 0x00000219`000109b0\r\n       pFactory = struct System::IntPtr\r\n        itfGuid = struct System::Guid\r\n0:008&gt; ?? typeName\r\nclass System::String * 0x00007fff`7ce64060\r\n   +0x000 __VFN_table : 0x00007fff`7c554030\r\n   +0x000 m_pEEType        : System::IntPtr\r\n   +0x008 m_stringLength   : 0n38\r\n   +0x00c m_firstChar      : 0x57 'W'\r\n0:008&gt; du 0x00007fff`7ce64060+c\r\n00007fff`7ce6406c  \"Windows.Devices.Portable.Storage\"\r\n00007fff`7ce640ac  \"Device\"\r\n<\/pre>\n<p>This program is trying to create a <code>Windows.<wbr \/>Devices.<wbr \/>Portable.<wbr \/>StorageDevice<\/code>. I bet it fails.<\/p>\n<pre><span style=\"color: blue;\">\u27e6g- with a parameter sets a temporary breakpoint before executing backward\u27e7<\/span>\r\n0:008&gt; g- combase!RoGetActivationFactory\r\nTime Travel Position: 1CD829:AE\r\ncombase!RoGetActivationFactory:\r\n00007fff`c29ca2f0 4d8bc8          mov     r9,r8\r\n0:008&gt; dv\r\nactivatableClassId = 0x0000004b`0a1fd860 \"Windows.Devices.Portable.StorageDevice\"\r\n               iid = 0x0000004b`0a1fd920 {5ECE44EE-1B23-4DD2-8652-BC164F003128}\r\n           factory = 0x0000004b`0a1fd900\r\n\r\n<span style=\"color: blue;\">\u27e6gu executes until the function returns (\"go up\")\u27e7<\/span>\r\n0:008&gt; gu\r\nTime Travel Position: 1CE201:20\r\nSharedLibrary!$8_Interop::WinRT.RoGetActivationFactory+0x136:\r\n00007fff`7c209836 488b4db0        mov     rcx,qword ptr [rbp-50h] ss:0000004b`0a1fd7f0=000002197408c8e0\r\n0:008&gt; r\r\nrax=<u>0000000080040154<\/u> rbx=00007fff7ce64060 rcx=fff83836ff080000\r\nrdx=0000000000000006 rsi=0000004b0a1fd920 rdi=0000004b0a1fd900\r\nrip=00007fff7c209836 rsp=0000004b0a1fd7c0 rbp=0000004b0a1fd840\r\n r8=0000000000000001  r9=0000000000000001 r10=0000000000005dc0\r\nr11=0000004b0a1fcee0 r12=00000000e409abda r13=000002197fabec70\r\nr14=0000000000000000 r15=0000000000000000\r\niopl=0         nv up ei pl nz na po nc\r\ncs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206\r\nSharedLibrary!$8_Interop::WinRT.RoGetActivationFactory+0x136:\r\n00007fff`7c209836 488b4db0        mov     rcx,qword ptr [rbp-50h] ss:0000004b`0a1fd7f0=000002197408c8e0\r\n<\/pre>\n<p>The function return value is placed in the <code>rax<\/code> register, and we see that it is indeed <code>0x80040154<\/code>, which is &#8220;Class not registered&#8221;.<\/p>\n<p>The <code>Windows.<wbr \/>Devices.<wbr \/>Portable.<wbr \/>Storage\u00adDevice<\/code> class is not part of the Universal contract. It is in a separate PortableDevice contract. The app marked itself as Universal in its manifest, but it used classes outside the Universal contract <a title=\"If you say that your minimum requirements are the Universal contract, then you need to probe for anything beyond that\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200326-00\/?p=103592\"> without first validating that the contract is available<\/a>. The PortableDevice contract is available on Desktop Windows, which is why they get away with it when running on Desktop Windows. But the PortableDevice contract is not present on Windows 10X, which is why the app crashes there.<\/p>\n<p>This program probably also crashes on Xbox, since Xbox doesn&#8217;t support the PortableDevice contract either.<\/p>\n<p>So this app gets a special compatibility flag in the Store that says, &#8220;Yeah, when this app says that it&#8217;s Universal, they&#8217;re lying. Don&#8217;t install it on non-Desktop systems.&#8221;<\/p>\n<p><b>Bonus chatter<\/b>: Now that we know that the answer is, we realize in retrospect that we could have found it faster. The error message &#8220;Class not registered&#8221; suggests that a call to <code>Co\u00adCreate\u00adInstance<\/code>, <code>Co\u00adGet\u00adClass\u00adFactory<\/code>, <code>Ro\u00adActivate\u00adInstance<\/code>, or <code>Co\u00adGet\u00adActivation\u00adFactory<\/code> failed. We could have asked the time travel tracing object model to find all such calls that returned that error code:<\/p>\n<pre style=\"white-space: pre-wrap;\">0:008&gt; dx -r2 @$currsession.TTD.Calls(\"combase!CoCreateInstance\", <!--\r\n-->\"combase!CoGetClassFactory\", \"combase!RoActivateInstance\", <!--\r\n-->\"combase!RoGetActivationFactory\").Where(c =&gt; c.ReturnValue == (HRESULT)0x80040154)\r\n\r\n    [0x97]\r\n        EventType        : 0x0\r\n        ThreadId         : 0x2fc0\r\n        UniqueThreadId   : 0xd\r\n        TimeStart        : 1CD829:AE\r\n        TimeEnd          : 1CE201:20\r\n        Function         : combase!RoGetActivationFactory\r\n        FunctionAddress  : 0x7fffc29ca2f0\r\n        ReturnAddress    : 0x7fff7c209836\r\n        ReturnValue      : 0x80040154 (Class not registered) [Type: HRESULT]\r\n        Parameters\r\n<\/pre>\n<p>Boom, there&#8217;s the failure, at call number 0x97.<\/p>\n<p>Now we can use the <code>!tt<\/code> command to jump to that timecode to see what the object was.<\/p>\n<pre>0:008&gt; !tt 1CD829:AE\r\nSetting position: 1CD829:AE\r\n(4420.3130): Break instruction exception - code 80000003 (first\/second chance not available)\r\nTime Travel Position: 1CD829:AE\r\ncombase!RoGetActivationFactory:\r\n00007fff`c29ca2f0 4d8bc8          mov     r9,r8\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Look before you leap.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-105727","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Look before you leap.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105727","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=105727"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/105727\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=105727"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=105727"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=105727"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}