{"record":{"id":"47eda5469ee2cd34","repo":"dotnet/wpf","slug":"throw-new-win32exception","errorCode":null,"errorMessage":"throw new Win32Exception();","messagePattern":"throw new Win32Exception\\(\\);","errorType":"exception","errorClass":"Win32Exception","httpStatus":null,"severity":"error","filePath":"src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/D3DImage.cs","lineNumber":701,"sourceCode":"\n                data.Type = MILCMD.MilCmdD3DImagePresent;\n                data.Handle = _duceResource.GetHandle(channel);\n\n                // We need to make sure the event stays alive in case we get collected before\n                // the composition thread processes the packet\n                IntPtr hDuplicate;\n                IntPtr hCurrentProc = MS.Win32.UnsafeNativeMethods.GetCurrentProcess();\n                if (!MS.Win32.UnsafeNativeMethods.DuplicateHandle(\n                        hCurrentProc,\n                        _canWriteEvent.SafeWaitHandle,\n                        hCurrentProc,\n                        out hDuplicate,\n                        0,\n                        false,\n                        MS.Win32.UnsafeNativeMethods.DUPLICATE_SAME_ACCESS\n                        ))\n                {\n                    throw new Win32Exception();\n                }\n                \n                data.hEvent = (ulong)hDuplicate.ToPointer();\n\n                // Send packed command structure\n\n                // Note that the command is sent in its own batch (sendInSeparateBatch  == true) because this method is called under the \n                // context of the MediaContext.CommitChannel and the command needs to make it into the current set of changes which are \n                // being commited to the compositor.  If the command would not be added to a separate batch, it would go into the \n                // \"future\" batch which would not get submitted this time around. This leads to a dead-lock situation which occurs when \n                // the app calls Lock on the D3DImage because Lock waits on _canWriteEvent which the compositor sets when it sees the \n                // Present command. However, since the compositor does not get the Present command, it will not set the event and the \n                // UI thread will wait forever on the compositor which will cause the application to stop responding.\n\n                channel.SendCommand(\n                    (byte*)&data,\n                    sizeof(DUCE.MILCMD_D3DIMAGE_PRESENT),\n                    sendInSeparateBatch: true);","sourceCodeStart":683,"sourceCodeEnd":719,"githubUrl":"https://github.com/dotnet/wpf/blob/81131a70a4c573cd62748a5c36908fc4d662daa9/src/Microsoft.DotNet.Wpf/src/PresentationCore/System/Windows/InterOp/D3DImage.cs#L683-L719","documentation":"D3DImage.SendPresent duplicates a shared-D3D-surface handle via the Win32 DuplicateHandle API so the rendered frame can be handed to the rendering thread. When DuplicateHandle fails (returns false), the code throws a bare Win32Exception, which carries the failing Win32 error code as its NativeErrorCode. This indicates the interop handshake that publishes the D3D surface to the composition thread could not be completed.","triggerScenarios":"Calling D3DImage.SetBackBuffer/Invalidate when the shared handle duplication inside SendPresent fails — e.g. invalid or closed source handle, handle-table exhaustion, or the Direct3D device/surface having been destroyed while a present is in flight.","commonSituations":"GPU driver reset or device removal (TDR) mid-render; shutting down an application while D3DImage still presents; running out of GDI/handle resources under heavy load; mixing D3D9Ex shared surfaces across devices that cannot share resources.","solutions":["Check the thrown Win32Exception.NativeErrorCode and fix the underlying Win32 failure (often ERROR_INVALID_HANDLE from a disposed D3D device).","Recreate the D3D device/surface and call SetBackBuffer again after a device-lost condition (check Device9 TestCooperativeLevel / device reset).","Guard the render loop: skip Invalidate/_present if the D3D device or source handle is no longer valid, and reinitialize on failure.","Reduce handle pressure (dispose D3DImage and device resources deterministically) if the failure is handle exhaustion."],"exampleFix":"// before\n_d3dImage.Invalidate(); // may throw Win32Exception if device lost\n// after\nif (_device.TestCooperativeLevel() == 0 /* D3D_OK */)\n{\n    _d3dImage.Invalidate();\n}\nelse\n{\n    RecreateDeviceAndBackBuffer();\n}","handlingStrategy":"try-catch","validationCode":"bool canPresent = _device != null && !_deviceLost && _backBuffer != IntPtr.Zero;","typeGuard":"static bool HasValidBackBuffer(D3DImage img) => img != null && img.IsFrontBufferAvailable;","tryCatchPattern":"try\n{\n    _d3dImage.Invalidate();\n}\ncatch (Win32Exception ex)\n{\n    Log(ex.NativeErrorCode);\n    RecreateDeviceAndBackBuffer();\n}","preventionTips":["Monitor IsFrontBufferAvailable and rebuild the back buffer when it flips to false/true.","Dispose D3D resources deterministically before shutdown.","Handle device-lost (TDR) conditions explicitly instead of letting present calls fail."],"tags":["win32","direct3d","interop","handle"],"backgroundTag":"win32-api-call-failed","analyzedSha":"81131a70a4c573cd62748a5c36908fc4d662daa9","analyzedAt":"2026-09-14T10:12:48.479Z","contentChangedAt":"2026-09-14T10:12:48.479Z","schemaVersion":2},"datasetVersion":"2026-09-21T21:30:21.729Z"}