diff --git a/ANNOUNCE.md b/ANNOUNCE.md
index 4480480be783..86f78d564636 100644
--- a/ANNOUNCE.md
+++ b/ANNOUNCE.md
@@ -1,12 +1,13 @@
-The Wine development release 11.13 is now available.
+The Wine development release 11.14 is now available.
 
 What's new in this release:
-  - Better support for input pointers.
-  - Improved keyboard scancode mapping on X11.
-  - FFmpeg optimizations on ARM64EC.
+  - 7.1 format conversions in DirectSound.
+  - Support for AES-GMAC algorithm in BCrypt.
+  - New WoW64 mode supported on FreeBSD.
+  - Icons in Start Menu.
   - Various bug fixes.
 
-The source is available at <https://dl.winehq.org/wine/source/11.x/wine-11.13.tar.xz>
+The source is available at <https://dl.winehq.org/wine/source/11.x/wine-11.14.tar.xz>
 
 Binary packages for various distributions will be available
 from the respective [download sites][1].
@@ -18,303 +19,307 @@ See the file [AUTHORS][3] for the complete list.
 
 [1]: https://gitlab.winehq.org/wine/wine/-/wikis/Download
 [2]: https://gitlab.winehq.org/wine/wine/-/wikis/Documentation
-[3]: https://gitlab.winehq.org/wine/wine/-/raw/wine-11.13/AUTHORS
+[3]: https://gitlab.winehq.org/wine/wine/-/raw/wine-11.14/AUTHORS
 
 ----------------------------------------------------------------
 
-### Bugs fixed in 11.13 (total 22):
-
- - #13088  Adobe Acrobat Pro 7 / Acrobat Reader 7 -- Comments don't work
- - #30824  msvbvm60.dll crashes Gehalt.exe
- - #36373  Requiem: Avenging Angel - Black screen in-game
- - #40231  Grand Theft Auto: Vice City crashes at start
- - #42282  Tales of Zestiria v1.2 (latest Steam provided runtime) crashes at launch
- - #45503  msiexec crashes during Office 2000 setup
- - #49435  cyrrillic text are broken in winbox64.exe
- - #50030  "Hayoola" freezes in wine 5.19 while it works great in 5.13
- - #55030  Nelogica Profitchart freezes and Crash since wine-7.12 [bisect included]
- - #55407  Virtual desktop option breaks wine creating windows
- - #58105  explorer creates extra virtual desktop when using the /desktop=shell argument
- - #58610  Sim Racing Studio fails to start: “Error Loading Prython DLL ”C:\Progam Files\RimsRacingStudio 2.0\python312.dll"
- - #59727  DrawText rendering bug when DT_WORD_ELLIPSIS / DT_PATH_ELLIPSIS is used
- - #59850  Exit unwind is broken
- - #59884  Age of Mythology errors on startup with "Initialization failed"
- - #59914  One i386 uwninding testcase fails with wine built with GCC
- - #59916  d2d1 path geometry leaks figure->vertex_types (steady heap growth under sustained Direct2D path rendering)
- - #59920  msvcrt setjmp/longjmp in x86_64 ELF builds broken by ntdll change
- - #59932  Slingplayer 2's help has an extra window
- - #59960  Sony Acid Pro 7.0 crashes on startup during initialization
- - #59969  winecfg buttons can't be clicked on dpi != 96
- - #59975  SuccubusHeaven camera breaks
-
-### Changes since 11.12:
+### Bugs fixed in 11.14 (total 21):
+
+ - #21811  3impact tech demo collection crashes on first demo
+ - #34665  Adobe Reader 11 PDF portfolio search crashes
+ - #38746  Adobe Reader 9.0 installer fails
+ - #43775  Heroes of the Storm crash on start with d3d11
+ - #49868  Hedgewars 1.0.0 crashes when a game against the computer is started
+ - #52833  Wine's wscript.exe and cscript.exe don't support UTF-16 LE with BOM script files
+ - #53574  MSYS2 "pacman -Sy" fails key lookup
+ - #56317  Falcon BMS 4.37 crashes on start (needs D3DX11CreateTextureFromFileA implementation)
+ - #56501  nProtect Anti-Virus/Spyware 4.0 'tkpl2k64.sys' crashes on unimplemented function 'fltmgr.sys.FltCreateCommunicationPort'
+ - #56580  Xdefiant Beta needs unimplemented function pdh.dll.PdhGetFormattedCounterArrayA
+ - #56745  Amazing Adventures 2: mouse pointer flashes all over the screen
+ - #57801  Marble Marcher Community Edition: Startup error "Compute shader compilation error."
+ - #58826  Winhq 10.17 seems to loose window focus??
+ - #59378  Black rectangle box in foreground blocking application window on TaxAct 2025
+ - #59456  TreeView: TVN_ITEMCHANGING not sent on checkbox change
+ - #59816  cmd: inbuilt 'type' fails on expanding *.txt
+ - #59913  msvcrt: _aligned_offset_realloc alignment validation failure crashes PCSX2 nightly
+ - #59964  Age of Empires I and II both show blank screen in introduction cinematics
+ - #60000  msvcrt: fopen("wb, ccs=UTF-8") prepends a BOM unlike Windows
+ - #60021  Wine loader segfaults converting Unix executable path when no DOS drive maps it
+ - #60039  Microsoft Office Word 2016 hangs after changing a Design style
+
+### Changes since 11.13:
 ```
-Alex Henrie (1):
-      faudio: Handle odd offsets in decode_mono_adpcm_block.
-
-Alexandre Julliard (6):
-      ntdll: Fix handling of exit unwind when there are no TEB frames.
-      msvcrt: Save all registers when calling the exception filter on i386.
-      ffmpeg: Add support for ARM64EC assembly.
-      ffmpeg: Add ARM64EC assembly in libswresample.
-      ffmpeg: Add ARM64EC assembly in libswscale.
-      make_announce: Use the new Bugzilla REST API.
-
-Alexey Prokhin (1):
-      win32u: Enable fullscreen clipping even if not already clipping.
-
-Alistair Leslie-Hughes (14):
-      dplayx: Add missing break.
-      fltmgr.sys: Add FltAllocateContext stub.
-      fltmgr.sys: Add FltReleaseContext stub.
-      fltmgr.sys: Add FltGetStreamContext stub.
-      fltmgr.sys: Add FltSetStreamContext stub.
-      fltmgr.sys: Add FltQueryInformationFile stub.
-      fltmgr.sys: Add FltGetFileNameInformationUnsafe stub.
-      fltmgr.sys: Add FltReadFile stub.
-      fltmgr.sys: Add FltParseFileNameInformation stub.
-      fltmgr.sys: Add FltReleaseFileNameInformation stub.
-      fltmgr.sys: Add FltGetFileNameInformation stub.
-      fltmgr.sys: Add FltCreateCommunicationPort stub.
-      fltmgr.sys: Add FltCloseCommunicationPort stub.
-      fltmgr.sys: Add FltEnumerateVolumes stub.
-
-Anna (navi) Figueiredo Gomes (9):
-      win32u: Move process_pointer_message to input.c.
-      win32u: Keep per-thread list of known pointers.
-      win32u: Preallocate pointerId 1 for the mouse pointer.
-      win32u: Keep track of pointer types.
-      win32u: Implement NtUserGetPointerType.
-      win32u: Hardcode pointer id 1 to PT_MOUSE in GetPointerType.
-      win32u: Update pointerid 1 from mouse_in_pointer events.
-      server: Mask pointer inputs for SetCursorPos requests.
-      win32u: Implement NtUserGetPointerInfoList.
-
-Anton Baskanov (7):
-      dmsynth: Increase the write latency by 10 ms.
-      dsound: Name the parameters of bitsgetfunc and bitsputfunc.
-      dsound: Remove getieee32 from the getbpp array.
-      dsound: Get rid of endianness conversion.
-      dsound: Downmix to mono after resampling and remove get_mono.
-      dsound: Get rid of get_aux and read the values directly.
-      dsound: Get all channel samples in one go.
-
-Benoît Legat (2):
-      crypt32: Avoid conflict between unnamed containers.
-      crypt32: Open MS_ENH_RSA_AES_PROV in PFXImportCertStore.
-
-Bernhard Übelacker (1):
-      secur32/tests: Update count for new test.winehq.org certificate.
-
-Brendan Shanks (4):
-      ntdll: Advertise ARM32 processor features on ARM64.
-      ntdll: Detect ARM32 processor features using getauxval(AT_HWCAP).
-      ntdll: Detect ARM64 processor features on macOS, and on Linux using getauxval(AT_HWCAP).
-      ntdll: Define HWCAP_CPUID on ARM64.
-
-Conor McCarthy (11):
-      windows.storage/tests: Test InMemoryRandomAccessStream.
-      windows.storage: Add InMemoryRandomAccessStream stubs.
-      windows.storage: Implement InMemoryRandomAccessStream IClosable::Close().
-      windows.storage: Implement InMemoryRandomAccessStream IOutputStream::WriteAsync().
-      windows.storage: Implement InMemoryRandomAccessStream IRandomAccessStream::get_Size().
-      windows.storage: Implement InMemoryRandomAccessStream IRandomAccessStream::put_Size().
-      windows.storage: Implement InMemoryRandomAccessStream IRandomAccessStream::get_Position().
-      windows.storage: Implement InMemoryRandomAccessStream IRandomAccessStream::Seek().
-      windows.storage: Implement InMemoryRandomAccessStream IInputStream::ReadAsync().
-      windows.storage: Add InMemoryRandomAccessStream to class registration.
-      windows.storage: Do not limit the size to SIZE_MAX in memory_stream_random_access_put_Size().
+Aidan Racaniello (4):
+      uxtheme: Add GetImmersiveUserColorSetPreference stub.
+      uxtheme: Add GetImmersiveColorTypeFromName stub.
+      uxtheme: Add GetImmersiveColorFromColorSetEx semi-stub.
+      uxtheme: Add GetImmersiveColorNamedTypeByIndex stub.
+
+Alexander Shaikhulin (2):
+      ntdll: Support new wow64 mode on FreeBSD.
+      ntdll: Work around AMD SYSRET SS descriptor behavior on FreeBSD.
+
+Alexandre Julliard (31):
+      setupapi: Delay file copy if truncating fails.
+      win32u: Add missing newline in a trace.
+      server: Make the add_queue() operation optional.
+      server: Make the satisfied() operation optional.
+      server: Make the signal() operation optional.
+      server: Make the get_fd() operation optional.
+      server: Make the get_sync() operation optional.
+      server: Make the map_access() operation optional.
+      server: Make the get_sd() operation optional.
+      server: Make the set_sd() operation optional.
+      server: Make the get_full_name() operation optional.
+      server: Make the lookup_name() operation optional.
+      server: Make the link_name() operation optional.
+      server: Make the unlink_name() operation optional.
+      server: Make the open_file() operation optional.
+      server: Make the get_kernel_obj_list() operation optional.
+      server: Make the close_handle() operation optional.
+      server: Make the destroy() operation optional.
+      server: Use designated initializers for object operations.
+      server: Make the get_poll_events() fd operation optional.
+      server: Make the poll_event() fd operation optional.
+      server: Make the read() fd operation optional.
+      server: Make the write() fd operation optional.
+      server: Make the flush() fd operation optional.
+      server: Make the get_file_info() fd operation optional.
+      server: Make the get_volume_info() fd operation optional.
+      server: Make the ioctl() fd operation optional.
+      server: Make the cancel_async() fd operation optional.
+      server: Make the queue_async() fd operation optional.
+      server: Make the reselect_async() fd operation optional.
+      server: Use designated initializers for fd operations.
+
+Alistair Leslie-Hughes (1):
+      ntoskrnl.exe: Implement IoThreadToProcess.
+
+Andrea Faulds (1):
+      explorer: Display icons next to Start Menu items.
+
+Anton Baskanov (1):
+      dsound: Move the get functions to mixer.c.
+
+Arkadiusz Hiler (1):
+      dsound: Add mono and stereo to 7.1 conversions.
+
+Barath Kannan (2):
+      cmd/tests: Add tests for the expansion of wildcards in the type command's arguments.
+      cmd: Add wildcard expansion for the type command's arguments.
+
+Bernhard Übelacker (4):
+      wow64: Handle PS_ATTRIBUTE_GROUP_AFFINITY in ps_attributes_32to64.
+      taskmgr: Change the default push button.
+      server: Clear connection failure events in IOCTL_AFD_WINE_CONNECT.
+      kernel32/tests: Fix test_GetFinalPathNameByHandleW.
+
+Brandow Lucas (1):
+      msxml3: Handle NULL value for the SelectionNamespaces property.
+
+Brendan McGrath (2):
+      strmbase: Introduce callback for ReceiveCanBlock.
+      winegstreamer: Preserve sign of stride from 2D buffer.
+
+Brendan Shanks (1):
+      ntdll: Hard code the host address space limit on macOS.
+
+Connor McAdams (8):
+      include/ddk: Add some missing enum/structure definitions.
+      ntoskrnl/tests: Add tests to highlight PDO specific behavior.
+      ntoskrnl/tests: Add tests for AttachedTo field in DEVOBJ_EXTENSION.
+      ntoskrnl: Set AttachedTo field in DEVOBJ_EXTENSION when attaching/detaching devices.
+      ntoskrnl: Set DO_BUS_ENUMERATED_DEVICE flag for PDO DEVICE_OBJECTs.
+      ntoskrnl: Add checks for DEVICE_OBJECTs passed into various PnP functions.
+      ntoskrnl: Cache device instance ID for PDOs.
+      ntoskrnl: Use cached device instance ID for DevicePropertyEnumeratorName.
+
+Conor McCarthy (9):
+      wintypes/tests: Test DataWriter.
+      wintypes: Rename struct data_writer to data_writer_factory.
+      wintypes: Add DataWriter stubs.
+      wintypes: Implement IDataWriter::WriteBytes().
+      wintypes: Implement IDataWriter::DetachBuffer().
+      wintypes: Add IDataWriterFactory stubs.
+      wintypes: Implement IDataWriterFactory::CreateDataWriter().
+      wintypes: Implement IDataWriter::StoreAsync().
+      wintypes: Implement IDataWriter::DetachStream().
 
 Daniel Lehman (1):
-      dwrite: Add some more fallback ranges.
-
-Elizabeth Figura (18):
-      wined3d: Store plane_formats as wined3d_format pointers.
-      wined3d: Allow any typed format for planar texture views.
-      wined3d: Do not alter the swapchain latency.
-      wined3d: Use a semaphore for frame latency.
-      dxgi: Implement DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT for d3d11.
-      dxgi: Implement d3d11_swapchain_SetMaximumFrameLatency().
-      dxgi: Implement d3d11_swapchain_GetMaximumFrameLatency().
-      dxgi: Implement d3d11_swapchain_GetFrameLatencyWaitableObject().
-      acledit: No longer prefer native.
-      avrt: No longer prefer native.
-      connect: No longer prefer native.
-      inkobj: No longer prefer native.
-      magnification: No longer prefer native.
-      mscat32: No longer prefer native.
-      msnet32: No longer prefer native.
-      msports: No longer prefer native.
-      mssip32: No longer prefer native.
-      netprofm: No longer prefer native.
-
-Erhan Bilgili (1):
-      cfgmgr32: Fix CM_Get_Device_ID buffer size handling.
-
-Eric Pouech (1):
-      dbghelp/dwarf: Fix out-of-bound write when leaf name is too large.
-
-Etaash Mathamsetty (4):
-      winex11: Don't initialize win_data_mutex twice.
-      winewayland: Don't initialize win_data_mutex twice.
-      winewayland: Use a flag instead of checking zwp_relative_pointer_v1.
-      winewayland: Don't offset client rect in client surface reconfigure.
-
-Francis De Brabandere (1):
-      vbscript: Count carriage returns as line endings when reporting error lines.
-
-Gabriel Ivăncescu (7):
-      mshtml: Don't leak gecko attr when creating attribute.
-      mshtml: Don't leak ref from attribute collection when detaching attribute.
-      mshtml: Don't leak gecko attribute when obtaining DISPID from collection.
-      mshtml: Properly unlink the element refs of frame elements.
-      mshtml: Properly unlink the element refs of iframe elements.
-      mshtml/tests: Fix attribute leak when testing tabIndex.
-      mshtml/tests: Properly close the view of the legacy document when testing attributes across modes.
+      shell32/tests: Remove stray test file after directory rename test.
+
+Dmitry Timoshkov (1):
+      crypt32: Add support for CERT_CLOSE_STORE_FORCE_FLAG.
+
+Elizabeth Figura (13):
+      qwave: No longer prefer native.
+      rstrtmgr: No longer prefer native.
+      svrapi: No longer prefer native.
+      uianimation: No longer prefer native.
+      uiautomationcore: No longer prefer native.
+      websocket: No longer prefer native.
+      winnls32: No longer prefer native.
+      wldp: No longer prefer native.
+      wpc: No longer prefer native.
+      wined3d: Do not disable extendedDynamicState3PolygonMode (validation).
+      slc: No longer prefer native.
+      ncrypt: No longer prefer native.
+      ntdll: Handle Unix paths with no corresponding drive in get_full_path().
+
+Eric Pouech (3):
+      dbghelp/dwarf: Implement DW_OP_shra by shifting signed quantities.
+      dbghelp/dwarf: Follow Dwarf specs for (un)signed arithmetic operations.
+      dbghelp/dwarf: Report errors when attempting to divide by zero.
+
+Esme Povirk (2):
+      mscoree: Use wide string literals.
+      mscoree: Add libmono dll name for arm64.
+
+Georg Lehmann (1):
+      winevulkan: Update to VK spec version 1.4.357.
+
+Hans Leidekker (4):
+      bcrypt: Support BCRYPT_SIGNATURE_LENGTH for RSA.
+      bcrypt: Fix accepted key size for 25519 curve.
+      bcrypt: Support BCRYPT_AES_GMAC_ALGORITHM.
+      bcrypt: Support BCRYPT_MESSAGE_BLOCK_LENGTH.
 
 Haoyang Chen (1):
-      ole32: Add support for writing VT_BOOL properties.
+      crypt32: Fix CryptRegisterOIDInfo size validation for CRYPT_OID_INFO_HAS_EXTRA_FIELDS compatibility.
 
-Jacek Caban (4):
-      dsound/tests: Remove unused variable.
-      qcap/tests: Remove unused variable.
-      ws2_32/tests: Remove unused variable.
-      http.sys: Check thread_stop in request_thread_proc loop.
+Henri Verbeet (2):
+      d3dcompiler: Store a D3D11_SHADER_DESC structure in struct d3dcompiler_shader_reflection.
+      d3dcompiler: Adopt vkd3d's STAT parser.
 
-Jacob Czekalla (1):
-      hhctrl.ocx: Create the index popup window hidden.
+Hieu Le Minh (3):
+      dxcore: Add support for DedicatedAdapterMemory property.
+      dxcore: Add support for SharedSystemMemory property.
+      dxcore: Return stub value for DedicatedSystemMemory property.
 
-Jiajin Cui (6):
-      wininet/tests: Cover long CreateUrlCacheEntryW extensions.
-      urlmon/tests: Cover URLDownloadToCacheFile buffer bounds.
-      wininet: Ignore overly long cache file extensions.
-      urlmon: Fix URLDownloadToCacheFile buffer handling.
-      urlmon: Remove temporary cache files on failure.
-      winewayland: Fix y coordinate of IME cursor rectangle.
+Jacob Czekalla (2):
+      msxml3/tests: Add more tests for setNamedItem().
+      msxml3: Return new node from setNamedItem().
+
+Jiangyi Chen (2):
+      symcrypt: Avoid SSE intrinsic that is missing in old gcc versions.
+      winewayland.drv: Avoid ABBA deadlocks between win_data_mutex and user_mutex.
+
+Kang Kang (1):
+      dxgi: Return the first adapter from EnumWarpAdapter().
+
+Kyle Yang (1):
+      wininet: Fix out-of-bounds read in InternetCrackUrlW for empty file paths.
+
+Lakulish Antani (1):
+      dsound: Add quad and 5.1 to 7.1 conversions.
+
+Lokesh Poovaragan (2):
+      wscript: Support UTF-16 LE encoded script files.
+      wscript/tests: Add encoding tests for UTF-16 script files.
 
 Louis Lenders (3):
-      kernel32: Add stub for PssQuerySnapshot.
-      kernel32: Add stub for PssFreeSnapshot.
-      kernel32: Add stub for PssCaptureSnapshot.
-
-Maotong Zhang (1):
-      user32: Fix lastSlash handling in TEXT_PathEllipsify.
-
-Martin Storsjö (1):
-      configure: Reduce the fixed load address for the preloader on aarch64.
-
-Matteo Bruni (4):
-      winex11: Fix Right Shift scancode.
-      user32/tests: Add a SendInput VK_PAUSE test.
-      user32/tests: Add more key names tests.
-      user32/tests: Add more key map tests.
-
-Nello De Gregoris (1):
-      mfsrcsnk: Ignore empty byte stream origin names.
-
-Nikolay Sivov (4):
-      msxml3/xpath: Add a strstr() variant that handles nulls.
-      msxml3/xpath: Add a string comparison helper that handles nulls.
-      msxml3/tests: Add a test for translate() function.
-      msxml3/xpath: Fix translate() function to actually return its result.
-
-Paul Gofman (4):
-      ws2_32: Add WSCEnumProtocols32().
-      kernel32/tests: Test filename case preservation when opening existing file.
-      kernelbase: Add a stub for FindNextFileNameW().
-      mmdevapi: Implement SAORS_Reset().
-
-Piotr Caban (3):
-      secur32: Return impersonation token from lsa_QuerySecurityContextToken.
-      msv1_0: Decrypt all data buffers in ntlm_SpUnsealMessage.
-      gdiplus: Return InvalidParameter error when GdipLoadImageFromStream is used with empty stream.
-
-Piotr Pawłowski (2):
-      comctl32/tests: Add tests for TVN_ITEMCHANGING and TVN_ITEMCHANGED.
-      comctl32/treeview: Implemented TVN_ITEMCHANGING and TVN_ITEMCHANGED.
-
-Ryan Houdek (1):
-      wow64: Add BTCpuNotifyProcessExecuteFlagsChange interface.
-
-Rémi Bernon (53):
-      winewayland: Make window lock mutex recursive.
-      winewayland: Use update_client_surfaces to detach client surfaces.
-      winewayland: Remove unnecessary client surface attach / detach.
-      winewayland: Move ensure_window_surface_contents into wayland_surface.c.
-      winex11: Use the desired state for mapping delays.
-      server: Map update_window_zorder rect from raw to virtual coordinates.
-      server: Update window zorder directly in queue_mouse_message.
-      wineandroid: Remove now unnecessary update_window_zorder call.
-      winemac: Remove now unnecessary update_window_zorder call.
-      winex11: Remove now unnecessary update_window_zorder call.
-      win32u: Keep track of client surface toplevel window.
-      win32u: Move client_surface_update on present from winex11.
-      win32u: Move client surface rect computation out of the drivers.
-      win32u: Assume that NtUserExposeWindowSurface rect is in raw monitor DPI.
-      win32u: Reorder KEYEVENTF_SCANCODE handling control flow.
-      win32u: Remap some scancodes to better match native behavior.
-      winex11: Use scancode high bit to set KEYEVENTF_EXTENDEDKEY flag.
-      winex11: Support fixed X11 keycode to scancode conversion.
-      opengl32/tests: Test versioned / core / compat context creation and sharing.
-      winemac: Remove unnused macdrv_context renderer_id member.
-      opengl32: Remove duplicated client context member.
-      winex11: Remove unnecessary window send_mouse_input argument.
-      winex11: Pass individual INPUT fields to send_mouse_input.
-      winex11: Pass / return a POINT to / from map_event_coords.
-      winex11: Use send_mouse_input in move_resize_window.
-      winex11: Use send_mouse_input in the RawMotion handler.
-      win32u: Use internal helpers to get present / client rects and dpi.
-      win32u: Introduce a ratio struct for unix-side DPI values.
-      server: Use the ratio struct for DPI values.
-      win32u: Represent raw monitor dpi as rational value.
-      server: Move window monitor DPI to the shared memory.
-      win32u: Ignore empty mouse input in NtUserSendHardwareInput.
-      server: Skip dispatching rawinput message when it is empty.
-      win32u: Accumulate mouse motion in NtUserSendHardwareInput.
-      winex11: Remove now unnecessary mouse motion event merging.
-      winemac: Try initializing GL3_Core and GL4_Core profile contexts.
-      winemac: Create all core contexts with the best supported profile.
-      winemac: Use WGL_CONTEXT_CORE_PROFILE_BIT_ARB to detect core profiles.
-      win32u: Request core profile for internal OpenGL contexts.
-      winemac: Ignore context sharing when profile doesn't match.
-      opengl32: Flag GL_EXT_external_buffer extension as unsupported.
-      opengl32: Move more wow64 wrappers out of the generated code.
-      opengl32: Use a static variable for the buffer storage map.
-      opengl32: Remove unused flags member from buffer struct.
-      opengl32: Reduce WOW64 locking to the buffer storage map accesses.
-      server: Always update window monitor DPI from its parent.
-      winewayland: Remove now unnecessary implicit fullscreen clipping.
-      server: Support explicit raw mouse motion in NtUserSendHardwareInput.
-      winewayland: Send raw mouse motion through NtUserSendHardwareInput.
-      winex11: Enable XI2 raw events when window is focused.
-      winex11: Send raw mouse motion frames from XI2 RawEvents.
-      winex11: Remove unnecessary ConfigureNotify event merging.
-      winex11: Get rid of now unnecessary event merging logic.
-
-Stefan Riesenberger (2):
-      dnsapi: Add stub for DnsStartMulticastQuery().
-      dnsapi: Add stub for DnsStopMulticastQuery().
-
-Sven Baars (2):
-      configure: Set PCSCLITE_LIBS in the AC_CHECK_FUNC error case on macOS.
-      dxgi: Replace FIXMEs in swapchain latency methods by traces.
-
-Thomas Portal (1):
-      hidclass: Return the full report length from IOCTL_HID_WRITE_REPORT.
-
-Zhiyi Zhang (14):
-      dxgi/tests: Wait for destroyed windows to disappear before creating a fullscreen swapchain.
-      dxgi/tests: Run test_create_swapchain() on D3D12 as well.
-      dxgi/tests: Test creating a fullscreen swapchain with an invalid scanline order or scaling.
-      dxgi: Report the DXGI_SWAP_CHAIN_FULLSCREEN_DESC used for creating a D3D11 swapchain.
-      dxgi: Create a windowed swapchain instead when the fullscreen mode scanline order or scaling is invalid.
-      dxgi: Refuse to enter fullscreen when the fullscreen mode scanline order or scaling is invalid.
-      dxgi: Retrieve the fullscreen state from the swapchain state in d3d11_swapchain_GetFullscreenState().
-      user32/tests: Move the test window position further away from the top-left corner of the work area.
-      user32/tests: Fix test failures when the top-left corner of the work area is not (0,0).
-      user32/tests: Add more window placement tests.
-      win32u: Implement coordinates mapping in {Get,Set}WindowPlacement().
-      notepad: Use SetWindowPlacement() to restore the saved normal window position.
-      taskmgr: Use SetWindowPlacement() to restore the saved normal window position.
-      wordpad: Use SetWindowPlacement() to restore the saved normal window position.
+      wminet_utils: Add GetNames.
+      wminet_utils: Add BeginMethodEnumeration.
+      cldapi: Add stub for CfGetPlaceholderInfo.
+
+Marcus Meissner (1):
+      ntdll/tests: GetCurrentDirectoryW gets size in characters not bytes.
+
+Matteo Bruni (1):
+      winex11: Report right shift as an extended key.
+
+Michael Brabec (1):
+      avifil32: Fix ICM_COMPRESS_FRAMES_INFO not being sent without VIDCF_COMPRESSFRAMES.
+
+Nikolay Sivov (24):
+      msxml3/tests: Add some tests for DTD node children.
+      msxml3/dom: Add notations as children of a DTD.
+      msxml3: Add a stub for IXMLDOMNotation node.
+      oleaut32/tests: Add some tests for aggregation with CreateStdDispatch().
+      oleaut32: Add aggregation support for CreateStdDispatch().
+      msxml3: Add entities as children of a DTD.
+      msxml3: Add a stub for IXMLDOMEntity node.
+      msxml3/notation: Implement nodeTypeString() property.
+      msxml3/entity: Implement nodeTypeString() property.
+      msxml3/notation: Implement text() property.
+      msxml3/tests: Add more tests for notation nodes.
+      msxml3: Return name properties for IXMLDOMNotation.
+      msxml3/doctype: Implement hasChildNodes() method.
+      msxml3/tests: Move some notation tests.
+      msxml3: Add a helper to return attribute count.
+      msxml3: Create attributes for IXMLDOMNotation nodes.
+      msxml3/tests: Add more tests for entity nodes.
+      msxml3: Add entities as DTD children.
+      msxml3: Implement name methods for IXMLDOMEntity.
+      msxml3: Correct copy-pasted variable names.
+      msxml3: Set entity nodes text property.
+      msxml3: Add attributes for entity nodes.
+      msxml3/doctype: Implement entities() property.
+      msxml3/doctype: Implement notations() property.
+
+Pan Hui (1):
+      winewayland: Fix restoring window after being maximized on the secondary monitor.
+
+Paul Gofman (5):
+      ntdll/tests: Add tests for skipping directory reopen by RtlSetCurrentDirectory_U().
+      ntdll: Do not reopen directory file when setting the same directory path.
+      winex11.drv: Flush display in acquire_selection().
+      shell32: Add AppDataDocuments known folder.
+      ntdll: Add BirthVolumeId to loaded dll file id.
+
+Pavel Cheloveckov (1):
+      mscoree: Store the sku attribute from supportedRuntime config elements.
+
+Piotr Caban (17):
+      comsvcs/tests: Remove non-needed IHolder pointer checks.
+      comsvcs/tests: Test creating multiple Dispenser Managers.
+      comsvcs: Don't use IDispenserDriver after closing holder.
+      comsvcs/tests: Add more Dispenser Manager tests.
+      comsvcs: Add partial implementation of resources pooling.
+      comsvcs: Implement resource purging thread in Dispenser Manager.
+      comsvcs: Remove COM initilization hack from Dispenser Manager.
+      comsvcs: Create one Dispenser Manager in a process.
+      comsvcs: Exit resource lookup loop when perfect match is found in AllocResource.
+      comsvcs: Exit resource purging loop on first resource in use.
+      comsvcs: Remove the FIXME message since pool purging is implemented.
+      msvcrt/tests: Test BOM handling in files opened in binary mode.
+      msvcrt: Don't append/read BOM in fopen binary mode.
+      msvcrt/tests: Cleanup _aligned_offset_realloc tests.
+      msvcrt/tests: Add more _aligned_offset_realloc tests.
+      msvcrt: Allow changing alignment and offset in _aligned_offset_realloc.
+      server: Set kernel notification events initial state.
+
+Rose Hellsing (1):
+      ntdll: Return empty value instead of failing in NtQueryVolumeInformation.
+
+Shaun Ren (1):
+      windows.ui: Stub IUISettings2::add_TextScaleFactorChanged().
+
+Stian Low (1):
+      winhlp32: Implement MACRO_PopupContext.
+
+Tim Clem (1):
+      winemac.drv: Detect display changes with CGDisplayRegisterReconfigurationCallback.
+
+Yue Zhang (3):
+      setupapi: Implement SPDRP_ENUMERATOR_NAME.
+      gdiplus: Fix potential integer overflow in GdipDrawImagePointsRect.
+      gdiplus: Fix missing newline detection in gdip_format_string.
+
+Zhengyong Chen (3):
+      pdh: Implement PdhGetFormattedCounterArrayA/W.
+      mshtml: Fire property change notification when document title is set.
+      ieframe: Fire TitleChange event on document title change.
+
+Zhiyi Zhang (7):
+      ntdll/tests: Add ALPC Port object tests.
+      ntdll/tests: Add NtAlpcCreatePort() tests.
+      ntdll: Implement NtAlpcCreatePort().
+      dxgi/tests: Add IDXGISwapChain::ResizeBuffers() flag tests.
+      dxgi: Support DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT in dxgi_swapchain_flags_from_wined3d().
+      dxgi: Support modifying swapchain flags in d3d11_swapchain_ResizeBuffers().
+      dxgi: Support modifying swapchain flags in d3d12_swapchain_resize_buffers().
+
+Zhou Zhang (1):
+      user32: Release drop target at the end of drag_drop_drop and drag_drop_leave.
 ```
diff --git a/AUTHORS b/AUTHORS
index b0ca114da3ba..a9362dbef342 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -30,6 +30,7 @@ Adrian Thiele
 Adrian Thurston
 Agustin Principe
 Aida Jonikienė
+Aidan Racaniello
 Aidan Thornton
 Ake Rehnman
 Akihiro Sagawa
@@ -67,6 +68,7 @@ Alexander Morozov
 Alexander Nicolaysen Sørnes
 Alexander Puzankov
 Alexander Scott-Johns
+Alexander Shaikhulin
 Alexander V. Lukyanov
 Alexander Wilms
 Alexander Yaworsky
@@ -113,6 +115,7 @@ Anders Kjersem
 Anderson Lizardo
 Andoni Morales Alastruey
 András Kovács
+Andrea Faulds
 Andreas Bjerkeholt
 Andreas Damm
 Andreas Fuchs
@@ -200,6 +203,7 @@ Aviad Pineles
 Axel Davy
 Axel Schmidt
 Bang Jun-Young
+Barath Kannan
 Bartosz Kosiorek
 Bart Van Assche
 Baruch Rutman
@@ -259,6 +263,7 @@ Brad Pepers
 Brad Smith
 Brandon Moore
 Brandon Woodmansee
+Brandow Lucas
 Brendan McGrath
 Brendan Shanks
 Brian Chang
@@ -726,6 +731,7 @@ Hervé Chanal
 Hervé Poussineau
 Hib Eris
 Hidenori Takeshima
+Hieu Le Minh
 Hilko Bengen
 Hin-Tak Leung
 Hippocrates Sendoukas
@@ -1035,6 +1041,7 @@ Kaj Kaloinen
 Kalen Alwardt
 Kalevi J Hautaniemi
 Kamil Pošvic
+Kang Kang
 Kanit Therdsteerasukdi
 Kareem Aladli
 Karl Backström
@@ -1120,7 +1127,9 @@ Kun Yang
 Kurt Kartaltepe
 Kusanagi Kouichi
 Kyle Luna
+Kyle Yang
 Kyrylo Babikov
+Lakulish Antani
 Lance Jackson
 Lars-Ake Fredlund
 Lars Heete
@@ -1155,6 +1164,7 @@ Liu Spider
 Loïc Hoguin
 Loïc Maury
 Loïc Rebmeister
+Lokesh Poovaragan
 Lorenzo Ferrillo
 Louis Lenders
 Louis Philippe Gagnon
@@ -1293,6 +1303,7 @@ Michael Abbott
 Michael Abd-El-Malek
 Michael Beach
 Michael Bond
+Michael Brabec
 Michael Cardenas
 Michael C. Maggio
 Michael Cronenworth
@@ -1490,6 +1501,7 @@ Paul TBBle Hampson
 Paul van Schayck
 Paul Vriens
 Pavel Borecki
+Pavel Cheloveckov
 Pavel Kankovsky
 Pavel Ondračka
 Pavel Roskin
@@ -2027,6 +2039,7 @@ Yorick Hardy
 Yoshiji Emoto
 Yoshiro Takeno
 Young Chung
+Yue Zhang
 Yuri Hérouard
 Yuri Khan
 Yuri Kozlov
@@ -2052,6 +2065,7 @@ Zhennan Cai
 Zhipeng Zhao
 Zhiyi Zhang
 Zhou Qiankang
+Zhou Zhang
 Ziia Shi
 Zimler Attila
 Ziqing Hui
diff --git a/VERSION b/VERSION
index 0e19529b6b29..6132cfaa0a1f 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-Wine version 11.13
+Wine version 11.14
diff --git a/configure b/configure
index 73a4d6a4b6b5..a1b4b6fd02a6 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.73 for Wine 11.13.
+# Generated by GNU Autoconf 2.73 for Wine 11.14.
 #
 # Report bugs to <wine-devel@winehq.org>.
 #
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='Wine'
 PACKAGE_TARNAME='wine'
-PACKAGE_VERSION='11.13'
-PACKAGE_STRING='Wine 11.13'
+PACKAGE_VERSION='11.14'
+PACKAGE_STRING='Wine 11.14'
 PACKAGE_BUGREPORT='wine-devel@winehq.org'
 PACKAGE_URL='https://www.winehq.org'
 
@@ -2509,7 +2509,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures Wine 11.13 to adapt to many kinds of systems.
+'configure' configures Wine 11.14 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -2579,7 +2579,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Wine 11.13:";;
+     short | recursive ) echo "Configuration of Wine 11.14:";;
    esac
   cat <<\_ACEOF
 
@@ -2940,7 +2940,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Wine configure 11.13
+Wine configure 11.14
 generated by GNU Autoconf 2.73
 
 Copyright (C) 2026 Free Software Foundation, Inc.
@@ -3346,7 +3346,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Wine $as_me 11.13, which was
+It was created by Wine $as_me 11.14, which was
 generated by GNU Autoconf 2.73.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -23964,7 +23964,7 @@ cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Wine $as_me 11.13, which was
+This file was extended by Wine $as_me 11.14, which was
 generated by GNU Autoconf 2.73.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -24024,7 +24024,7 @@ ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-Wine config.status 11.13
+Wine config.status 11.14
 configured by $0, generated by GNU Autoconf 2.73,
   with options \\"\$ac_cs_config\\"
 
diff --git a/dlls/avifil32/icmstream.c b/dlls/avifil32/icmstream.c
index ca7f35eebe75..dada97c50c00 100644
--- a/dlls/avifil32/icmstream.c
+++ b/dlls/avifil32/icmstream.c
@@ -248,19 +248,17 @@ static HRESULT WINAPI ICMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
       This->dwBytesPerFrame = 0;
     }
 
-    if (icinfo.dwFlags & VIDCF_COMPRESSFRAMES) {
-      memset(&icFrames, 0, sizeof(icFrames));
-      icFrames.lpbiOutput  = This->lpbiOutput;
-      icFrames.lpbiInput   = This->lpbiInput;
-      icFrames.lFrameCount = This->sInfo.dwLength;
-      icFrames.lQuality    = This->sInfo.dwQuality;
-      icFrames.lDataRate   = pco->dwBytesPerSecond;
-      icFrames.lKeyRate    = This->lKeyFrameEvery;
-      icFrames.dwRate      = This->sInfo.dwRate;
-      icFrames.dwScale     = This->sInfo.dwScale;
-      ICSendMessage(This->hic, ICM_COMPRESS_FRAMES_INFO,
-		    (LPARAM)&icFrames, (LPARAM)sizeof(icFrames));
-    }
+    memset(&icFrames, 0, sizeof(icFrames));
+    icFrames.lpbiOutput  = This->lpbiOutput;
+    icFrames.lpbiInput   = This->lpbiInput;
+    icFrames.lFrameCount = This->sInfo.dwLength;
+    icFrames.lQuality    = This->sInfo.dwQuality;
+    icFrames.lDataRate   = pco->dwBytesPerSecond;
+    icFrames.lKeyRate    = This->lKeyFrameEvery;
+    icFrames.dwRate      = This->sInfo.dwRate;
+    icFrames.dwScale     = This->sInfo.dwScale;
+    ICSendMessage(This->hic, ICM_COMPRESS_FRAMES_INFO,
+		  (LPARAM)&icFrames, (LPARAM)sizeof(icFrames));
   } else
     This->sInfo.fccHandler = comptypeDIB;
 
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 4426e7e74b26..1231ba20013d 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -54,6 +54,7 @@ enum alg_id
     ALG_ID_3DES,
     ALG_ID_CHACHA20_POLY1305,
     ALG_ID_AES,
+    ALG_ID_AES_GMAC,
     ALG_ID_RC4,
 
     /* hash */
@@ -134,6 +135,7 @@ struct algorithm
     enum chain_mode   mode;
     ULONG             flags;
     enum ecc_curve_id curve_id;
+    enum chain_mode   chain_mode;
 };
 
 struct aes_key
@@ -343,12 +345,14 @@ static const struct
     ULONG        hash_length;
     ULONG        block_bits;
     enum ecc_curve_id curve_id;
+    enum chain_mode   chain_mode;
 }
 builtin_algorithms[] =
 {
     {  BCRYPT_3DES_ALGORITHM,       BCRYPT_CIPHER_INTERFACE,                522,    0,    0 },
     {  BCRYPT_CHACHA20_POLY1305_ALGORITHM, BCRYPT_CIPHER_INTERFACE,         166,    0,    0 },
     {  BCRYPT_AES_ALGORITHM,        BCRYPT_CIPHER_INTERFACE,                654,    0,    0 },
+    {  BCRYPT_AES_GMAC_ALGORITHM,   BCRYPT_CIPHER_INTERFACE,                654,    0,    0, 0, CHAIN_MODE_GCM },
     {  BCRYPT_RC4_ALGORITHM,        BCRYPT_CIPHER_INTERFACE,                654,    0,    0 },
     {  BCRYPT_SHA256_ALGORITHM,     BCRYPT_HASH_INTERFACE,                  286,   32,  512 },
     {  BCRYPT_SHA384_ALGORITHM,     BCRYPT_HASH_INTERFACE,                  382,   48, 1024 },
@@ -458,7 +462,7 @@ static const struct algorithm pseudo_algorithms[] =
     {{ MAGIC_ALG }, ALG_ID_RSA },
     {{ MAGIC_ALG }, ALG_ID_ECDSA },
     {{ 0 }}, /* AES_CMAC */
-    {{ 0 }}, /* AES_GMAC */
+    {{ MAGIC_ALG }, ALG_ID_AES_GMAC, CHAIN_MODE_GCM },
     {{ MAGIC_ALG }, ALG_ID_MD2, 0, BCRYPT_ALG_HANDLE_HMAC_FLAG },
     {{ MAGIC_ALG }, ALG_ID_MD4, 0, BCRYPT_ALG_HANDLE_HMAC_FLAG },
     {{ MAGIC_ALG }, ALG_ID_3DES, CHAIN_MODE_CBC },
@@ -599,10 +603,11 @@ static struct algorithm *create_algorithm( enum alg_id id, DWORD flags )
 {
     struct algorithm *ret;
     if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
-    ret->hdr.magic = MAGIC_ALG;
-    ret->id        = id;
-    ret->flags     = flags;
-    ret->curve_id  = builtin_algorithms[id].curve_id;
+    ret->hdr.magic  = MAGIC_ALG;
+    ret->id         = id;
+    ret->flags      = flags;
+    ret->curve_id   = builtin_algorithms[id].curve_id;
+    ret->chain_mode = builtin_algorithms[id].chain_mode;
     return ret;
 }
 
@@ -684,24 +689,26 @@ NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *enabled)
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS get_dword_property( UCHAR *buf, ULONG size, ULONG *ret_size, DWORD value )
+{
+    *ret_size = sizeof(value);
+    if (size < sizeof(value)) return STATUS_BUFFER_TOO_SMALL;
+    if (buf) *(DWORD *)buf = value;
+    return STATUS_SUCCESS;
+}
+
 static NTSTATUS get_generic_alg_property( enum alg_id id, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     if (!wcscmp( prop, BCRYPT_OBJECT_LENGTH ))
     {
         if (!builtin_algorithms[id].object_length) return STATUS_NOT_SUPPORTED;
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG *)buf = builtin_algorithms[id].object_length;
-        return STATUS_SUCCESS;
+        return get_dword_property( buf, size, ret_size, builtin_algorithms[id].object_length );
     }
 
     if (!wcscmp( prop, BCRYPT_HASH_LENGTH ))
     {
         if (!builtin_algorithms[id].hash_length) return STATUS_NOT_SUPPORTED;
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG*)buf = builtin_algorithms[id].hash_length;
-        return STATUS_SUCCESS;
+        return get_dword_property( buf, size, ret_size, builtin_algorithms[id].hash_length );
     }
 
     if (!wcscmp( prop, BCRYPT_ALGORITHM_NAME ))
@@ -718,12 +725,8 @@ static NTSTATUS get_generic_alg_property( enum alg_id id, const WCHAR *prop, UCH
 static NTSTATUS get_3des_property( enum chain_mode mode, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     if (!wcscmp( prop, BCRYPT_BLOCK_LENGTH ))
-    {
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG *)buf = BLOCK_LENGTH_3DES;
-        return STATUS_SUCCESS;
-    }
+        return get_dword_property( buf, size, ret_size, BLOCK_LENGTH_3DES );
+
     if (!wcscmp( prop, BCRYPT_CHAINING_MODE ))
     {
         const WCHAR *str;
@@ -760,12 +763,11 @@ static NTSTATUS get_3des_property( enum chain_mode mode, const WCHAR *prop, UCHA
 static NTSTATUS get_aes_property( enum chain_mode mode, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     if (!wcscmp( prop, BCRYPT_BLOCK_LENGTH ))
-    {
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG *)buf = BLOCK_LENGTH_AES;
-        return STATUS_SUCCESS;
-    }
+        return get_dword_property( buf, size, ret_size, BLOCK_LENGTH_AES );
+
+    if (!wcscmp( prop, BCRYPT_MESSAGE_BLOCK_LENGTH ))
+        return get_dword_property( buf, size, ret_size, 1 );
+
     if (!wcscmp( prop, BCRYPT_CHAINING_MODE ))
     {
         const WCHAR *str;
@@ -818,12 +820,7 @@ static NTSTATUS get_aes_property( enum chain_mode mode, const WCHAR *prop, UCHAR
 static NTSTATUS get_rc4_property( enum chain_mode mode, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     if (!wcscmp( prop, BCRYPT_BLOCK_LENGTH ))
-    {
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG *)buf = BLOCK_LENGTH_RC4;
-        return STATUS_SUCCESS;
-    }
+        return get_dword_property( buf, size, ret_size, BLOCK_LENGTH_RC4 );
 
     FIXME( "unsupported property %s\n", debugstr_w(prop) );
     return STATUS_NOT_IMPLEMENTED;
@@ -832,12 +829,7 @@ static NTSTATUS get_rc4_property( enum chain_mode mode, const WCHAR *prop, UCHAR
 static NTSTATUS get_rsa_property( enum chain_mode mode, const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     if (!wcscmp( prop, BCRYPT_PADDING_SCHEMES ))
-    {
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG *)buf = BCRYPT_SUPPORTED_PAD_PKCS1_SIG | BCRYPT_SUPPORTED_PAD_OAEP;
-        return STATUS_SUCCESS;
-    }
+        return get_dword_property( buf, size, ret_size, BCRYPT_SUPPORTED_PAD_PKCS1_SIG | BCRYPT_SUPPORTED_PAD_OAEP );
 
     FIXME( "unsupported property %s\n", debugstr_w(prop) );
     return STATUS_NOT_IMPLEMENTED;
@@ -873,12 +865,7 @@ static NTSTATUS get_pbkdf2_property( enum chain_mode mode, const WCHAR *prop, UC
 static NTSTATUS get_chacha20_poly1305_property( const WCHAR *prop, UCHAR *buf, ULONG size, ULONG *ret_size )
 {
     if (!wcscmp( prop, BCRYPT_BLOCK_LENGTH ))
-    {
-        *ret_size = sizeof(ULONG);
-        if (size < sizeof(ULONG)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf) *(ULONG *)buf = BLOCK_LENGTH_CHACHA20_POLY1305;
-        return STATUS_SUCCESS;
-    }
+        return get_dword_property( buf, size, ret_size, BLOCK_LENGTH_CHACHA20_POLY1305 );
 
     FIXME( "unsupported property %s\n", debugstr_w(prop) );
     return STATUS_NOT_IMPLEMENTED;
@@ -901,6 +888,7 @@ static NTSTATUS get_alg_property( const struct algorithm *alg, const WCHAR *prop
         return get_chacha20_poly1305_property( prop, buf, size, ret_size );
 
     case ALG_ID_AES:
+    case ALG_ID_AES_GMAC:
         return get_aes_property( alg->mode, prop, buf, size, ret_size );
 
     case ALG_ID_RC4:
@@ -986,6 +974,9 @@ static NTSTATUS set_alg_property( struct algorithm *alg, const WCHAR *prop, UCHA
                 return STATUS_NOT_IMPLEMENTED;
             }
         }
+        else if (!wcscmp( (WCHAR *)prop, BCRYPT_MESSAGE_BLOCK_LENGTH ))
+            return STATUS_INVALID_PARAMETER;
+
         FIXME( "unsupported aes algorithm property %s\n", debugstr_w(prop) );
         return STATUS_NOT_IMPLEMENTED;
 
@@ -1184,14 +1175,8 @@ static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHA
 {
     if (!wcscmp( prop, BCRYPT_KEY_STRENGTH ))
     {
-        *ret_size = sizeof(DWORD);
-        if (size < sizeof(DWORD)) return STATUS_BUFFER_TOO_SMALL;
-        if (buf)
-        {
-            if (is_symmetric_key(key)) *(DWORD *)buf = key->s.block_size * 8;
-            else *(DWORD *)buf = key->a.bitlen;
-        }
-        return STATUS_SUCCESS;
+        DWORD value = is_symmetric_key (key ) ? key->s.block_size * 8 : key->a.bitlen;
+        return get_dword_property( buf, size, ret_size, value );
     }
 
     switch (key->alg_id)
@@ -1200,6 +1185,7 @@ static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHA
         return get_3des_property( key->s.mode, prop, buf, size, ret_size );
 
     case ALG_ID_AES:
+    case ALG_ID_AES_GMAC:
         if (!wcscmp( prop, BCRYPT_AUTH_TAG_LENGTH )) return STATUS_NOT_SUPPORTED;
         return get_aes_property( key->s.mode, prop, buf, size, ret_size );
 
@@ -1207,6 +1193,11 @@ static NTSTATUS get_key_property( const struct key *key, const WCHAR *prop, UCHA
         if (wcscmp( prop, BCRYPT_DH_PARAMETERS )) return STATUS_NOT_SUPPORTED;
         return get_dh_parameters( key, buf, size, ret_size );
 
+    case ALG_ID_RSA:
+    case ALG_ID_RSA_SIGN:
+        if (wcscmp( prop, BCRYPT_SIGNATURE_LENGTH )) return STATUS_NOT_SUPPORTED;
+        return get_dword_property( buf, size, ret_size, key->a.bitlen / 8 );
+
     default:
         FIXME( "unsupported algorithm %u\n", key->alg_id );
         return STATUS_NOT_IMPLEMENTED;
@@ -1586,6 +1577,7 @@ static NTSTATUS generate_symmetric_key( const struct algorithm *alg, const UCHAR
     switch (alg->id)
     {
     case ALG_ID_AES:
+    case ALG_ID_AES_GMAC:
         if ((status = validate_len_aes( &key_lengths, secret_len, &secret_len )) ||
             (status = alloc_aes_key( key, alg->mode, BLOCK_LENGTH_AES, secret, secret_len )))
         {
@@ -1770,6 +1762,7 @@ static NTSTATUS decrypt_symmetric( struct key *key, const UCHAR *input, ULONG in
     switch (key->alg_id)
     {
     case ALG_ID_AES:
+    case ALG_ID_AES_GMAC:
         switch (key->s.mode)
         {
         case CHAIN_MODE_ECB:
@@ -2114,6 +2107,7 @@ static NTSTATUS encrypt_symmetric( struct key *key, const UCHAR *input, ULONG in
     switch (key->alg_id)
     {
     case ALG_ID_AES:
+    case ALG_ID_AES_GMAC:
         switch (key->s.mode)
         {
         case CHAIN_MODE_ECB:
@@ -3367,6 +3361,22 @@ NTSTATUS WINAPI BCryptImportKeyPair( BCRYPT_ALG_HANDLE handle, BCRYPT_KEY_HANDLE
     return STATUS_SUCCESS;
 }
 
+static ULONG curve_size( enum ecc_curve_id curve_id )
+{
+    switch (curve_id)
+    {
+    case ECC_CURVE_25519:           return 255;
+    case ECC_CURVE_BRAINPOOLP256R1:
+    case ECC_CURVE_P256R1:          return 256;
+    case ECC_CURVE_BRAINPOOLP384R1:
+    case ECC_CURVE_P384R1:          return 384;
+    case ECC_CURVE_P521R1:          return 521;
+    default:
+        FIXME( "unsupported curve %u\n", curve_id );
+        return 0;
+    }
+}
+
 static NTSTATUS generate_key_pair( const struct algorithm *alg, ULONG bitlen, ULONG flags, struct key **ret_key )
 {
     NTSTATUS status;
@@ -3397,7 +3407,7 @@ static NTSTATUS generate_key_pair( const struct algorithm *alg, ULONG bitlen, UL
     case ALG_ID_ECDSA_P256:
     case ALG_ID_ECDSA_P384:
     case ALG_ID_ECDSA_P521:
-        if (bitlen && bitlen != curve_strength( alg->curve_id ))
+        if (bitlen && bitlen != curve_size( alg->curve_id ))
         {
             destroy_key( key );
             return STATUS_INVALID_PARAMETER;
@@ -3522,6 +3532,7 @@ static NTSTATUS duplicate_key( const struct key *src, struct key **ret_key )
     switch (src->alg_id)
     {
     case ALG_ID_AES:
+    case ALG_ID_AES_GMAC:
         if ((status = alloc_key( src->alg_id, src->flags, &dst ))) return status;
         if ((status = alloc_aes_key( dst, src->s.mode, src->s.block_size, src->s.secret, src->s.secret_len )))
         {
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index 75d9c3e166bd..c3d3b2723d1e 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -654,6 +654,15 @@ static void test_aes(void)
     ok(!lstrcmpW((const WCHAR *)mode, BCRYPT_CHAIN_MODE_CFB), "got %s\n", wine_dbgstr_w((const WCHAR *)mode));
     ok(size == 64, "got %lu\n", size);
 
+    len = size = 0;
+    ret = BCryptGetProperty(alg, BCRYPT_MESSAGE_BLOCK_LENGTH, (UCHAR *)&len, sizeof(len), &size, 0);
+    ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
+    ok(len == 1, "got %lu\n", len);
+
+    len = 16;
+    ret = BCryptSetProperty(alg, BCRYPT_MESSAGE_BLOCK_LENGTH, (UCHAR *)&len, 0, 0);
+    ok(ret == STATUS_INVALID_PARAMETER, "got %#lx\n", ret);
+
     test_alg_name(alg, L"AES");
 
     ret = BCryptCloseAlgorithmProvider(alg, 0);
@@ -671,6 +680,14 @@ static void test_aes(void)
         ok(!lstrcmpW((const WCHAR *)mode, BCRYPT_CHAIN_MODE_CBC), "got %s\n", wine_dbgstr_w((const WCHAR *)mode));
         ok(size == 64, "got %lu\n", size);
     }
+
+    alg = NULL;
+    ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_AES_GMAC_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
+    ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
+    ok(alg != NULL, "alg not set\n");
+
+    ret = BCryptCloseAlgorithmProvider(alg, 0);
+    ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
 }
 
 static void test_3des(void)
@@ -2973,12 +2990,18 @@ static void test_RSA(void)
     ret = BCryptImportKeyPair(alg, NULL, BCRYPT_RSAPUBLIC_BLOB, &key, rsaPublicBlob, sizeof(rsaPublicBlob), 0);
     ok(!ret, "BCryptImportKeyPair failed: %#lx\n", ret);
 
-    keylen = 0;
+    size = keylen = 0;
     ret = BCryptGetProperty(key, BCRYPT_KEY_STRENGTH, (UCHAR *)&keylen, sizeof(keylen), &size, 0);
     ok(!ret, "got %#lx\n", ret);
     ok(size == sizeof(keylen), "got %lu\n", size);
     ok(keylen == 2048, "got %lu\n", keylen);
 
+    size = len = 0;
+    ret = BCryptGetProperty(key, BCRYPT_SIGNATURE_LENGTH, (UCHAR *)&len, sizeof(len), &size, 0);
+    ok(!ret, "got %#lx\n", ret);
+    ok(size == sizeof(len), "got %lu\n", size);
+    ok(len == 256, "got %lu\n", len);
+
     pad.pszAlgId = BCRYPT_SHA1_ALGORITHM;
     ret = BCryptVerifySignature(key, &pad, rsaHash, sizeof(rsaHash), rsaSignature, sizeof(rsaSignature), BCRYPT_PAD_PKCS1);
     ok(!ret, "BCryptVerifySignature failed: %#lx\n", ret);
@@ -3186,7 +3209,7 @@ static void test_RSA_SIGN(void)
     BCRYPT_KEY_HANDLE key = NULL;
     BCRYPT_RSAKEY_BLOB *rsablob;
     NTSTATUS ret;
-    ULONG size, size2;
+    ULONG size, size2, len;
     BYTE *buf, buf2[sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(rsaPublicBlob)];
 
     ret = BCryptOpenAlgorithmProvider(&alg, BCRYPT_RSA_SIGN_ALGORITHM, NULL, 0);
@@ -3247,6 +3270,12 @@ static void test_RSA_SIGN(void)
     ret = BCryptFinalizeKeyPair(key, 0);
     ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
 
+    size = len = 0;
+    ret = BCryptGetProperty(key, BCRYPT_SIGNATURE_LENGTH, (UCHAR *)&len, sizeof(len), &size, 0);
+    ok(!ret, "got %#lx\n", ret);
+    ok(size == sizeof(len), "got %lu\n", size);
+    ok(len == 64, "got %lu\n", len);
+
     size = 0;
     ret = BCryptExportKey(key, NULL, BCRYPT_RSAPRIVATE_BLOB, NULL, 0, &size, 0);
     ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
@@ -3643,6 +3672,13 @@ static void test_ECDH(void)
     status = BCryptSetProperty(alg, BCRYPT_ECC_CURVE_NAME, (UCHAR *)BCRYPT_ECC_CURVE_25519, sizeof(BCRYPT_ECC_CURVE_25519), 0);
     ok(status == STATUS_SUCCESS, "got %#lx\n", status);
 
+    status = BCryptGenerateKeyPair(alg, &key, 253, 0);
+    ok(status == STATUS_INVALID_PARAMETER, "got %#lx\n", status);
+
+    status = BCryptGenerateKeyPair(alg, &key, 255, 0);
+    ok(status == STATUS_SUCCESS, "got %#lx\n", status);
+    BCryptDestroyKey(key);
+
     status = BCryptGenerateKeyPair(alg, &key, 0, 0);
     ok(status == STATUS_SUCCESS, "got %#lx\n", status);
 
diff --git a/dlls/cldapi/Makefile.in b/dlls/cldapi/Makefile.in
index c6e7c5be173b..b1784d40e0a4 100644
--- a/dlls/cldapi/Makefile.in
+++ b/dlls/cldapi/Makefile.in
@@ -1 +1,4 @@
 MODULE = cldapi.dll
+
+SOURCES = \
+	main.c
diff --git a/dlls/cldapi/cldapi.spec b/dlls/cldapi/cldapi.spec
index a645b74988e0..93e3d984b448 100644
--- a/dlls/cldapi/cldapi.spec
+++ b/dlls/cldapi/cldapi.spec
@@ -11,7 +11,7 @@
 @ stub CfExecute
 @ stub CfGetCorrelationVector
 @ stub CfGetLastSyncStatus
-@ stub CfGetPlaceholderInfo
+@ stdcall CfGetPlaceholderInfo(ptr long ptr long ptr)
 @ stub CfGetPlaceholderRangeInfo
 @ stub CfGetPlaceholderRangeInfoForHydration
 @ stub CfGetPlaceholderStateFromAttributeTag
diff --git a/dlls/cldapi/main.c b/dlls/cldapi/main.c
new file mode 100644
index 000000000000..f35284c94f77
--- /dev/null
+++ b/dlls/cldapi/main.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2026 Louis Lenders
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "windef.h"
+#include "cfapi.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(cldapi);
+
+HRESULT WINAPI CfGetPlaceholderInfo(HANDLE h, CF_PLACEHOLDER_INFO_CLASS info, void *buf, DWORD len, DWORD *retlen)
+{
+    FIXME("%p %d %p %lu %p: stub\n", h, info, buf, len, retlen);
+
+    return E_NOTIMPL;
+}
diff --git a/dlls/comsvcs/main.c b/dlls/comsvcs/main.c
index 43803f60632d..2bb50c857d3a 100644
--- a/dlls/comsvcs/main.c
+++ b/dlls/comsvcs/main.c
@@ -20,24 +20,44 @@
 
 #include "comsvcs_private.h"
 #include "wine/debug.h"
+#include "wine/list.h"
 #include "initguid.h"
 #include "comsvcs_classes.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(comsvcs);
 
+static IDispenserManager *manager;
+
 typedef struct dispensermanager
 {
     IDispenserManager IDispenserManager_iface;
     LONG ref;
-    CO_MTA_USAGE_COOKIE mta_cookie;
+
+    CRITICAL_SECTION cs;
+    HANDLE thread;              /* pool purging thread */
+    HANDLE quit_event;          /* purging thread quit event */
+    struct list holders;
 } dispensermanager;
 
+#define RESOURCE_IN_USE 0
+typedef struct
+{
+    struct list entry;
+    RESID resid;
+    TIMEINSECS ttl;
+    ULONGLONG timestamp;
+} resource;
+
 typedef struct holder
 {
     IHolder IHolder_iface;
     LONG ref;
 
+    CRITICAL_SECTION cs;
+    IDispenserManager *manager;
+    struct list entry;
     IDispenserDriver *driver;
+    struct list pool;
 } holder;
 
 struct new_moniker
@@ -108,6 +128,8 @@ static ULONG WINAPI holder_Release(IHolder *iface)
 
     if (!ref)
     {
+        DeleteCriticalSection(&This->cs);
+        if (!list_empty(&This->pool)) ERR("pool is not empty\n");
         free(This);
     }
 
@@ -117,29 +139,117 @@ static ULONG WINAPI holder_Release(IHolder *iface)
 static HRESULT WINAPI holder_AllocResource(IHolder *iface, const RESTYPID typeid, RESID *resid)
 {
     holder *This = impl_from_IHolder(iface);
+    RESOURCERATING best_rating = 0, rating;
+    resource *res, *best = NULL;
+    IDispenserDriver *driver;
     HRESULT hr;
-    TIMEINSECS secs;
 
-    TRACE("(%p)->(%08Ix, %p) stub\n", This, typeid, resid);
+    TRACE("(%p)->(%08Ix, %p) semi-stub\n", This, typeid, resid);
+
+    /* TODO: add transactions support */
+
+    EnterCriticalSection(&This->cs);
+    if (!This->driver)
+    {
+        LeaveCriticalSection(&This->cs);
+        return E_UNEXPECTED;
+    }
+
+    LIST_FOR_EACH_ENTRY(res, &This->pool, resource, entry)
+    {
+        if (res->timestamp == RESOURCE_IN_USE) continue;
+        hr = IDispenserDriver_RateResource(This->driver, typeid, res->resid, FALSE, &rating);
+        if (SUCCEEDED(hr) && rating && rating > best_rating)
+        {
+            best_rating = rating;
+            best = res;
+
+            if (rating >= 100)
+                break;
+        }
+    }
+    if (best)
+    {
+        best->timestamp = RESOURCE_IN_USE;
+        *resid = best->resid;
+        LeaveCriticalSection(&This->cs);
+        return S_OK;
+    }
+
+    driver = This->driver;
+    IDispenserDriver_AddRef(driver);
+    LeaveCriticalSection(&This->cs);
 
-    hr = IDispenserDriver_CreateResource(This->driver, typeid, resid, &secs);
+    if (!(res = malloc(sizeof(*res))))
+    {
+        IDispenserDriver_Release(driver);
+        return E_OUTOFMEMORY;
+    }
+    hr = IDispenserDriver_CreateResource(driver, typeid, &res->resid, &res->ttl);
+    TRACE(" creating new resource returned 0x%08lx\n", hr);
+    if (FAILED(hr))
+    {
+        IDispenserDriver_Release(driver);
+        free(res);
+        return hr;
+    }
 
-    TRACE("<- 0x%08lx\n", hr);
+    EnterCriticalSection(&This->cs);
+    if (!This->driver)
+    {
+        IDispenserDriver_DestroyResource(driver, res->resid);
+        free(resid);
+        hr = E_UNEXPECTED;
+    }
+    else
+    {
+        list_add_tail(&This->pool, &res->entry);
+        res->timestamp = RESOURCE_IN_USE;
+        *resid = res->resid;
+    }
+    LeaveCriticalSection(&This->cs);
+    IDispenserDriver_Release(driver);
     return hr;
 }
 
 static HRESULT WINAPI holder_FreeResource(IHolder *iface, const RESID resid)
 {
     holder *This = impl_from_IHolder(iface);
+    resource *res;
     HRESULT hr;
 
-    TRACE("(%p)->(%08Ix) stub\n", This, resid);
+    TRACE("(%p)->(%08Ix)\n", This, resid);
+
+    EnterCriticalSection(&This->cs);
+    if (!This->driver)
+    {
+        LeaveCriticalSection(&This->cs);
+        return S_OK;
+    }
+
+    LIST_FOR_EACH_ENTRY(res, &This->pool, resource, entry)
+    {
+        if (res->resid != resid) continue;
+        if (res->timestamp != RESOURCE_IN_USE)
+            ERR("resource found in pool\n");
 
-    hr = IDispenserDriver_DestroyResource(This->driver, resid);
+        hr = IDispenserDriver_ResetResource(This->driver, resid);
+        if (FAILED(hr))
+        {
+            LeaveCriticalSection(&This->cs);
+            return hr;
+        }
 
-    TRACE("<- 0x%08lx\n", hr);
+        res->timestamp = GetTickCount64();
+        list_remove(&res->entry);
+        list_add_head(&This->pool, &res->entry);
+        LeaveCriticalSection(&This->cs);
+        return hr;
+    }
+    LeaveCriticalSection(&This->cs);
 
-    return hr;
+    ERR("resource not found\n");
+    return E_INVALIDARG;
 }
 
 static HRESULT WINAPI holder_TrackResource(IHolder *iface, const RESID resid)
@@ -178,14 +288,66 @@ static HRESULT WINAPI holder_UntrackResourceS(IHolder *iface, const SRESID resid
     return E_NOTIMPL;
 }
 
+static void unregister_dispenser(IDispenserManager *iface, holder *hold)
+{
+    dispensermanager *manager = impl_from_IDispenserManager(iface);
+    HANDLE thread = NULL;
+    HANDLE quit_event;
+
+    EnterCriticalSection(&manager->cs);
+    list_remove(&hold->entry);
+    if (list_empty(&manager->holders))
+    {
+        thread = manager->thread;
+        manager->thread = NULL;
+        quit_event = manager->quit_event;
+        manager->quit_event = NULL;
+    }
+    LeaveCriticalSection(&manager->cs);
+    IHolder_Release(&hold->IHolder_iface);
+
+    if (thread)
+    {
+        SetEvent(quit_event);
+        WaitForSingleObject(thread, INFINITE);
+        CloseHandle(thread);
+        CloseHandle(quit_event);
+    }
+}
+
 static HRESULT WINAPI holder_Close(IHolder *iface)
 {
     holder *This = impl_from_IHolder(iface);
+    struct list pool = LIST_INIT(pool);
+    IDispenserDriver *driver = NULL;
+    IDispenserManager *manager;
+    resource *res, *tmp;
+
+    TRACE("(%p)\n", This);
 
-    FIXME("(%p) stub\n", This);
+    EnterCriticalSection(&This->cs);
+    if (This->driver)
+    {
+        list_move_head(&pool, &This->pool);
+        driver = This->driver;
+        This->driver = NULL;
+        manager = This->manager;
+        This->manager = NULL;
+    }
+    LeaveCriticalSection(&This->cs);
+    if (!driver) return S_OK;
 
-    IDispenserDriver_Release(This->driver);
+    LIST_FOR_EACH_ENTRY_SAFE(res, tmp, &pool, resource, entry)
+    {
+        if (res->timestamp != RESOURCE_IN_USE)
+            IDispenserDriver_DestroyResource(driver, res->resid);
+        list_remove(&res->entry);
+        free(res);
+    }
 
+    IDispenserDriver_Release(driver);
+    unregister_dispenser(manager, This);
+    IDispenserManager_Release(manager);
     return S_OK;
 }
 
@@ -213,28 +375,20 @@ struct IHolderVtbl holder_vtbl =
     holder_RequestDestroyResource
 };
 
-static HRESULT create_holder(IDispenserDriver *driver, IHolder **object)
+static HRESULT create_holder(IDispenserManager *manager, IDispenserDriver *driver, holder **hold)
 {
-    holder *hold;
-    HRESULT ret;
-
-    TRACE("(%p)\n", object);
-
-    hold = malloc(sizeof(*hold));
-    if (!hold)
-    {
-        *object = NULL;
+    *hold = malloc(sizeof(**hold));
+    if (!*hold)
         return E_OUTOFMEMORY;
-    }
-
-    hold->IHolder_iface.lpVtbl = &holder_vtbl;
-    hold->ref = 1;
-    hold->driver = driver;
 
-    ret = holder_QueryInterface(&hold->IHolder_iface, &IID_IHolder, (void**)object);
-    holder_Release(&hold->IHolder_iface);
-
-    return ret;
+    (*hold)->IHolder_iface.lpVtbl = &holder_vtbl;
+    (*hold)->ref = 1;
+    InitializeCriticalSection(&(*hold)->cs);
+    (*hold)->manager = manager;
+    IDispenserManager_AddRef(manager);
+    (*hold)->driver = driver;
+    list_init(&(*hold)->pool);
+    return S_OK;
 }
 
 static HRESULT WINAPI dismanager_QueryInterface(IDispenserManager *iface, REFIID riid, void **object)
@@ -274,32 +428,96 @@ static ULONG WINAPI dismanager_Release(IDispenserManager *iface)
 
     if (!ref)
     {
-        if (This->mta_cookie)
-            CoDecrementMTAUsage(This->mta_cookie);
+        DeleteCriticalSection(&This->cs);
+        if (!list_empty(&This->holders))
+            ERR("holders list is not empty\n");
         free(This);
     }
 
     return ref;
 }
 
+static DWORD WINAPI purge_expired_resources(void *arg)
+{
+    dispensermanager *manager = arg;
+    resource *res, *tmp;
+    ULONGLONG ticks;
+    holder *hold;
+    HRESULT com_init;
+
+    com_init = CoInitializeEx(0, COINIT_MULTITHREADED);
+
+    while(1)
+    {
+        DWORD r = WaitForSingleObject(manager->quit_event, 20000);
+        if (r == WAIT_OBJECT_0) break;
+
+        ticks = GetTickCount64();
+        EnterCriticalSection(&manager->cs);
+        LIST_FOR_EACH_ENTRY(hold, &manager->holders, holder, entry)
+        {
+            EnterCriticalSection(&hold->cs);
+            LIST_FOR_EACH_ENTRY_SAFE(res, tmp, &hold->pool, resource, entry)
+            {
+                if (res->timestamp == RESOURCE_IN_USE) break;
+                if (!res->ttl) continue;
+                if (res->timestamp + res->ttl * 1000 > ticks) continue;
+
+                IDispenserDriver_DestroyResource(hold->driver, res->resid);
+                list_remove(&res->entry);
+                free(res);
+            }
+            LeaveCriticalSection(&hold->cs);
+        }
+        LeaveCriticalSection(&manager->cs);
+    }
+
+    IDispenserManager_Release(&manager->IDispenserManager_iface);
+    if (SUCCEEDED(com_init))
+        CoUninitialize();
+    return 0;
+}
+
 static HRESULT WINAPI dismanager_RegisterDispenser(IDispenserManager *iface, IDispenserDriver *driver,
                         LPCOLESTR name, IHolder **dispenser)
 {
     dispensermanager *This = impl_from_IDispenserManager(iface);
+    holder *hold;
     HRESULT hr;
 
     TRACE("(%p)->(%p, %s, %p)\n", This, driver, debugstr_w(name), dispenser);
 
     if(!dispenser)
         return E_INVALIDARG;
+    *dispenser = NULL;
 
-    hr = create_holder(driver, dispenser);
-
-    if (!This->mta_cookie)
-        CoIncrementMTAUsage(&This->mta_cookie);
+    if (FAILED((hr = create_holder(iface, driver, &hold))))
+        return hr;
+    EnterCriticalSection(&This->cs);
+    list_add_tail(&This->holders, &hold->entry);
 
-    TRACE("<-- 0x%08lx, %p\n", hr, *dispenser);
+    if (!This->thread)
+    {
+        This->quit_event = CreateEventA(NULL, FALSE, FALSE, NULL);
+        if (This->quit_event)
+           This->thread = CreateThread(NULL, 0, purge_expired_resources, This, 0, NULL);
+        if (This->thread)
+        {
+            IDispenserManager_AddRef(&This->IDispenserManager_iface);
+        }
+        else
+        {
+            if (This->quit_event)
+            {
+                CloseHandle(This->quit_event);
+                This->quit_event = NULL;
+            }
+        }
+    }
+    LeaveCriticalSection(&This->cs);
 
+    *dispenser = &hold->IHolder_iface;
+    IHolder_AddRef(*dispenser);
     return hr;
 }
 
@@ -321,28 +539,35 @@ struct IDispenserManagerVtbl dismanager_vtbl =
     dismanager_GetContext
 };
 
-static HRESULT WINAPI dispenser_manager_cf_CreateInstance(IClassFactory *iface, IUnknown* outer, REFIID riid,
-        void **object)
+static BOOL WINAPI create_dispenser_manager(INIT_ONCE *once, void *param, void **context)
 {
     dispensermanager *dismanager;
-    HRESULT ret;
-
-    TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), object);
 
     dismanager = calloc(1, sizeof(*dismanager));
     if (!dismanager)
-    {
-        *object = NULL;
-        return E_OUTOFMEMORY;
-    }
+        return FALSE;
 
     dismanager->IDispenserManager_iface.lpVtbl = &dismanager_vtbl;
     dismanager->ref = 1;
+    InitializeCriticalSection(&dismanager->cs);
+    list_init(&dismanager->holders);
 
-    ret = dismanager_QueryInterface(&dismanager->IDispenserManager_iface, riid, object);
-    dismanager_Release(&dismanager->IDispenserManager_iface);
+    manager = &dismanager->IDispenserManager_iface;
+    return TRUE;
+}
 
-    return ret;
+static HRESULT WINAPI dispenser_manager_cf_CreateInstance(IClassFactory *iface, IUnknown* outer, REFIID riid,
+        void **object)
+{
+    static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
+
+    TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), object);
+
+    *object = NULL;
+    if (!InitOnceExecuteOnce(&init_once, create_dispenser_manager, NULL, NULL))
+        return E_OUTOFMEMORY;
+
+    return IDispenserManager_QueryInterface(manager, riid, object);
 }
 
 static HRESULT WINAPI comsvcscf_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv )
@@ -1022,3 +1247,13 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
     FIXME("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
     return CLASS_E_CLASSNOTAVAILABLE;
 }
+
+BOOL WINAPI DllMain(HINSTANCE hinst, DWORD reason, LPVOID reserved)
+{
+    if (reason == DLL_PROCESS_DETACH && !reserved)
+    {
+        if (manager)
+            IDispenserManager_Release(manager);
+    }
+    return TRUE;
+}
diff --git a/dlls/comsvcs/tests/comsvcs.c b/dlls/comsvcs/tests/comsvcs.c
index 9f258b24f29d..1416bb4c3d20 100644
--- a/dlls/comsvcs/tests/comsvcs.c
+++ b/dlls/comsvcs/tests/comsvcs.c
@@ -29,21 +29,29 @@
 #include "wine/test.h"
 
 #define DEFINE_EXPECT(func) \
-    static BOOL expect_ ## func = FALSE, called_ ## func = FALSE
+    static BOOL expect_ ## func = FALSE; static unsigned int called_ ## func = 0
 
 #define SET_EXPECT(func) \
-    expect_ ## func = TRUE
+    called_ ## func = FALSE, expect_ ## func = TRUE
 
 #define CHECK_CALLED(func) \
     do { \
         ok(called_ ## func, "expected " #func "\n"); \
-        expect_ ## func = called_ ## func = FALSE; \
+        expect_ ## func = FALSE; \
+        called_ ## func = 0; \
+    }while(0)
+
+#define CHECK_CALLEDN(func, n) \
+    do { \
+        ok(called_ ## func == n, "expected " #func " called %u times, got %u\n", n, called_ ## func); \
+        expect_ ## func = FALSE; \
+        called_ ## func = 0; \
     }while(0)
 
 #define CHECK_EXPECT2(func) \
     do { \
         ok(expect_ ##func, "unexpected call " #func "\n"); \
-        called_ ## func = TRUE; \
+        called_ ## func++; \
     }while(0)
 
 #define CHECK_CALLED_BROKEN(func) \
@@ -52,8 +60,15 @@
         expect_ ## func = called_ ## func = FALSE; \
     }while(0)
 
+#define CHECK_NOT_CALLED(func) \
+    do { \
+        ok(!called_ ## func, "unexpected " #func "\n"); \
+        expect_ ## func = called_ ## func = FALSE; \
+    }while(0)
+
 DEFINE_EXPECT(driver_CreateResource);
 DEFINE_EXPECT(driver_DestroyResource);
+DEFINE_EXPECT(driver_RateResource);
 DEFINE_EXPECT(driver_ResetResource);
 DEFINE_EXPECT(driver_Release);
 
@@ -104,17 +119,27 @@ static ULONG WINAPI driver_Release(IDispenserDriver *iface)
 
 static HRESULT WINAPI driver_CreateResource(IDispenserDriver *iface, const RESTYPID restypid, RESID *resid, TIMEINSECS *destroy)
 {
+    static int i = 10;
     CHECK_EXPECT2(driver_CreateResource);
 
-    *resid = 10;
+    *resid = i++;
+    *destroy = 0;
     return S_OK;
 }
 
 static HRESULT WINAPI driver_RateResource(IDispenserDriver *iface, const RESTYPID restypid, const RESID resid,
     const BOOL requires, RESOURCERATING *rating)
 {
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
+    CHECK_EXPECT2(driver_RateResource);
+
+    ok(!wcscmp((WCHAR *)restypid, L"data1"), "restypid = %s\n", wine_dbgstr_w((WCHAR *)restypid));
+    ok(resid >= 10 && resid <= 11, "resid = %Id\n", resid);
+    ok(!requires, "requires = TRUE\n");
+    ok(rating != NULL, "rating = NULL\n");
+
+    if(resid == 10) *rating = 100;
+    else *rating = 1;
+    return S_OK;
 }
 
 static HRESULT WINAPI driver_EnlistResource(IDispenserDriver *iface, const RESID resid, const TRANSID transid)
@@ -126,14 +151,14 @@ static HRESULT WINAPI driver_EnlistResource(IDispenserDriver *iface, const RESID
 static HRESULT WINAPI driver_ResetResource(IDispenserDriver *iface, const RESID resid)
 {
     CHECK_EXPECT2(driver_ResetResource);
-    ok((int)resid == 10, "RESID %d\n", (int)resid);
+    ok(resid >= 10 && resid <= 12, "RESID %Id\n", resid);
     return S_OK;
 }
 
 static HRESULT WINAPI driver_DestroyResource(IDispenserDriver *iface, const RESID resid)
 {
     struct test_driver *driver = impl_from_IDispenserDriver(iface);
-    todo_wine CHECK_EXPECT2(driver_DestroyResource);
+    CHECK_EXPECT2(driver_DestroyResource);
     return driver->destroy_resource_hr;
 }
 
@@ -177,15 +202,15 @@ static DWORD WINAPI com_thread(void *arg)
 static void create_dispenser(void)
 {
     HRESULT hr;
-    IDispenserManager *dispenser = NULL;
+    IDispenserManager *dispenser = NULL, *dispenser2;
     IHolder *holder1 = NULL, *holder2 = NULL, *holder3 = NULL;
     HANDLE thread;
-    RESID resid;
+    RESID resid, resid2;
     DWORD ret;
     BSTR str;
     struct test_driver driver;
 
-    hr = CoCreateInstance( &CLSID_DispenserManager, NULL, CLSCTX_ALL, &IID_IDispenserManager, (void**)&dispenser);
+    hr = CoCreateInstance(&CLSID_DispenserManager, NULL, CLSCTX_ALL, &IID_IDispenserManager, (void**)&dispenser);
     ok(hr == S_OK, "Failed to create object 0x%08lx\n", hr);
     if(FAILED(hr))
     {
@@ -193,6 +218,11 @@ static void create_dispenser(void)
         return;
     }
 
+    hr = CoCreateInstance(&CLSID_DispenserManager, NULL, CLSCTX_ALL, &IID_IDispenserManager, (void**)&dispenser2);
+    ok(hr == S_OK, "Failed to create object 0x%08lx\n", hr);
+    ok(dispenser == dispenser2, "dispenser objects are different\n");
+    IDispenserManager_Release(dispenser2);
+
     thread = CreateThread(NULL, 0, com_thread, NULL, 0, NULL);
     ok(!WaitForSingleObject(thread, 1000), "wait failed\n");
     GetExitCodeThread(thread, &ret);
@@ -220,72 +250,101 @@ static void create_dispenser(void)
     hr = IDispenserManager_RegisterDispenser(dispenser, &driver.IDispenserDriver_iface, L"SC.Pool 1 1", &holder3);
     ok(hr == S_OK, "got 0x%08lx\n", hr);
 
-    if(holder1)
-    {
-        SET_EXPECT(driver_CreateResource);
-        SET_EXPECT(driver_Release);
-
-        str = SysAllocString(L"data1");
-        hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        ok(resid == 10, "got %d\n", (int)resid);
-        SysFreeString(str);
-
-        CHECK_CALLED(driver_CreateResource);
-        todo_wine CHECK_CALLED_BROKEN(driver_Release);
-
-        SET_EXPECT(driver_ResetResource);
-        hr = IHolder_FreeResource(holder1, resid);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        todo_wine CHECK_CALLED(driver_ResetResource);
-
-        SET_EXPECT(driver_DestroyResource);
-        SET_EXPECT(driver_Release);
-        hr = IHolder_Close(holder1);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        CHECK_CALLED(driver_Release);
-        CHECK_CALLED(driver_DestroyResource);
-
-        IHolder_Release(holder1);
-    }
-    if(holder2)
-    {
-        SET_EXPECT(driver_CreateResource);
-        SET_EXPECT(driver_Release);
-
-        str = SysAllocString(L"data1");
-        hr = IHolder_AllocResource(holder2, (RESTYPID)str, &resid);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        ok(resid == 10, "got %d\n", (int)resid);
-        SysFreeString(str);
-
-        CHECK_CALLED(driver_CreateResource);
-        todo_wine CHECK_CALLED_BROKEN(driver_Release);
-
-        SET_EXPECT(driver_ResetResource);
-        hr = IHolder_FreeResource(holder2, resid);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        todo_wine CHECK_CALLED(driver_ResetResource);
-
-        /* DestroyResource return doesn't directly affect the Holder Close return value */
-        driver.destroy_resource_hr = E_FAIL;
-        SET_EXPECT(driver_DestroyResource);
-        SET_EXPECT(driver_Release);
-        hr = IHolder_Close(holder2);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        CHECK_CALLED(driver_Release);
-        CHECK_CALLED(driver_DestroyResource);
-        driver.destroy_resource_hr = S_OK;
-        IHolder_Release(holder2);
-    }
-    if(holder3)
-    {
-        SET_EXPECT(driver_Release);
-        hr = IHolder_Close(holder3);
-        ok(hr == S_OK, "got 0x%08lx\n", hr);
-        CHECK_CALLED(driver_Release);
-        IHolder_Release(holder3);
-    }
+    SET_EXPECT(driver_CreateResource);
+    SET_EXPECT(driver_Release);
+    str = SysAllocString(L"data1");
+    hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    ok(resid == 10, "got %Id\n", resid);
+    CHECK_CALLED(driver_CreateResource);
+    CHECK_CALLED_BROKEN(driver_Release);
+
+    SET_EXPECT(driver_CreateResource);
+    SET_EXPECT(driver_Release);
+    hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid2);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    ok(resid2 == 11, "got %Id\n", resid2);
+    CHECK_CALLED(driver_CreateResource);
+    CHECK_CALLED_BROKEN(driver_Release);
+
+    SET_EXPECT(driver_ResetResource);
+    hr = IHolder_FreeResource(holder1, resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_ResetResource);
+
+    hr = IHolder_FreeResource(holder2, resid2);
+    ok(hr == E_INVALIDARG, "got 0x%08lx\n", hr);
+
+    SET_EXPECT(driver_ResetResource);
+    hr = IHolder_FreeResource(holder1, resid2);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_ResetResource);
+
+    SET_EXPECT(driver_RateResource);
+    hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    ok(resid == 10, "got %Id\n", resid);
+    CHECK_CALLEDN(driver_RateResource, 2);
+
+    SET_EXPECT(driver_ResetResource);
+    hr = IHolder_FreeResource(holder1, resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_ResetResource);
+
+    SET_EXPECT(driver_RateResource);
+    hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    ok(resid == 10, "got %Id\n", resid);
+    CHECK_CALLEDN(driver_RateResource, 1);
+
+    SET_EXPECT(driver_DestroyResource);
+    SET_EXPECT(driver_Release);
+    hr = IHolder_Close(holder1);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_Release);
+    CHECK_CALLED(driver_DestroyResource);
+
+    hr = IHolder_FreeResource(holder1, resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+
+    hr = IHolder_AllocResource(holder1, (RESTYPID)str, &resid);
+    ok(hr == E_UNEXPECTED, "got 0x%08lx\n", hr);
+
+    hr = IHolder_Close(holder1);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+
+    IHolder_Release(holder1);
+
+    SET_EXPECT(driver_CreateResource);
+    SET_EXPECT(driver_Release);
+    hr = IHolder_AllocResource(holder2, (RESTYPID)str, &resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    ok(resid == 12, "got %Id\n", resid);
+    SysFreeString(str);
+    CHECK_CALLED(driver_CreateResource);
+    CHECK_CALLED_BROKEN(driver_Release);
+
+    SET_EXPECT(driver_ResetResource);
+    hr = IHolder_FreeResource(holder2, resid);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_ResetResource);
+
+    /* DestroyResource return doesn't directly affect the Holder Close return value */
+    driver.destroy_resource_hr = E_FAIL;
+    SET_EXPECT(driver_DestroyResource);
+    SET_EXPECT(driver_Release);
+    hr = IHolder_Close(holder2);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_Release);
+    CHECK_CALLED(driver_DestroyResource);
+    driver.destroy_resource_hr = S_OK;
+    IHolder_Release(holder2);
+
+    SET_EXPECT(driver_Release);
+    hr = IHolder_Close(holder3);
+    ok(hr == S_OK, "got 0x%08lx\n", hr);
+    CHECK_CALLED(driver_Release);
+    IHolder_Release(holder3);
 
     IDispenserManager_Release(dispenser);
 }
diff --git a/dlls/crypt32/collectionstore.c b/dlls/crypt32/collectionstore.c
index d11ec89ecdff..851c79666f59 100644
--- a/dlls/crypt32/collectionstore.c
+++ b/dlls/crypt32/collectionstore.c
@@ -51,12 +51,12 @@ static DWORD Collection_release(WINECRYPT_CERTSTORE *store, DWORD flags)
     WINE_STORE_LIST_ENTRY *entry, *next;
     LONG ref;
 
-    if(flags)
+    if(flags & ~CERT_CLOSE_STORE_FORCE_FLAG)
         FIXME("Unimplemented flags %lx\n", flags);
 
     ref = InterlockedDecrement(&cs->hdr.ref);
     TRACE("(%p) ref=%ld\n", store, ref);
-    if(ref)
+    if(ref && !(flags & CERT_CLOSE_STORE_FORCE_FLAG))
         return ERROR_SUCCESS;
 
     LIST_FOR_EACH_ENTRY_SAFE(entry, next, &cs->stores, WINE_STORE_LIST_ENTRY, entry)
diff --git a/dlls/crypt32/oid.c b/dlls/crypt32/oid.c
index a35917ff8f04..7c6c07e6379b 100644
--- a/dlls/crypt32/oid.c
+++ b/dlls/crypt32/oid.c
@@ -740,15 +740,31 @@ BOOL WINAPI CryptRegisterOIDInfo(PCCRYPT_OID_INFO info, DWORD flags)
     char *key_name;
     HKEY root = 0, key = 0;
     DWORD err;
+    CRYPT_OID_INFO info_copy = {0};
 
     TRACE("(%p, %lx)\n", info, flags );
 
-    if (!info || info->cbSize != sizeof(*info) || !info->pszOID)
+    if (!info || !info->pszOID)
     {
         SetLastError(E_INVALIDARG);
         return FALSE;
     }
 
+    if (info->cbSize != sizeof(*info)) {
+#ifdef CRYPT_OID_INFO_HAS_EXTRA_FIELDS
+        if (info->cbSize == sizeof(CRYPT_OID_INFO) - sizeof(LPWSTR) * 2) {
+            memcpy(&info_copy, info, sizeof(CRYPT_OID_INFO) - sizeof(LPWSTR) * 2);
+            info_copy.cbSize = sizeof(CRYPT_OID_INFO);
+            info = &info_copy;
+        }
+        else
+#endif
+        {
+            SetLastError(E_INVALIDARG);
+            return FALSE;
+        }
+    }
+
     if (!info->dwGroupId) return TRUE;
 
     key_name = CryptMemAlloc(strlen(info->pszOID) + 16);
diff --git a/dlls/crypt32/provstore.c b/dlls/crypt32/provstore.c
index 96945e313e80..b6ae56c24cbc 100644
--- a/dlls/crypt32/provstore.c
+++ b/dlls/crypt32/provstore.c
@@ -54,13 +54,13 @@ static DWORD ProvStore_release(WINECRYPT_CERTSTORE *cert_store, DWORD flags)
     WINE_PROVIDERSTORE *store = (WINE_PROVIDERSTORE*)cert_store;
     LONG ref;
 
-    if(flags)
+    if(flags & ~CERT_CLOSE_STORE_FORCE_FLAG)
         FIXME("Unimplemented flags %lx\n", flags);
 
     ref = InterlockedDecrement(&store->hdr.ref);
     TRACE("(%p) ref=%ld\n", store, ref);
 
-    if(ref)
+    if(ref && !(flags & CERT_CLOSE_STORE_FORCE_FLAG))
         return ERROR_SUCCESS;
 
     if (store->provCloseStore)
diff --git a/dlls/crypt32/regstore.c b/dlls/crypt32/regstore.c
index bee906e422ac..01af9d4c42f9 100644
--- a/dlls/crypt32/regstore.c
+++ b/dlls/crypt32/regstore.c
@@ -320,10 +320,10 @@ static void WINAPI CRYPT_RegCloseStore(HCERTSTORE hCertStore, DWORD dwFlags)
     WINE_REGSTOREINFO *store = hCertStore;
 
     TRACE("(%p, %08lx)\n", store, dwFlags);
-    if (dwFlags)
+    if (dwFlags & ~CERT_CLOSE_STORE_FORCE_FLAG)
         FIXME("Unimplemented flags: %08lx\n", dwFlags);
 
-    CRYPT_RegFlushStore(store, FALSE);
+    CRYPT_RegFlushStore(store, dwFlags & CERT_CLOSE_STORE_FORCE_FLAG);
     RegCloseKey(store->key);
     CloseHandle(store->key_modified_event);
     store->cs.DebugInfo->Spare[0] = 0;
diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c
index ac17a3d4768d..8625737c601a 100644
--- a/dlls/crypt32/store.c
+++ b/dlls/crypt32/store.c
@@ -369,12 +369,12 @@ static DWORD MemStore_release(WINECRYPT_CERTSTORE *cert_store, DWORD flags)
     WINE_MEMSTORE *store = (WINE_MEMSTORE*)cert_store;
     LONG ref;
 
-    if(flags & ~CERT_CLOSE_STORE_CHECK_FLAG)
+    if(flags & ~(CERT_CLOSE_STORE_CHECK_FLAG | CERT_CLOSE_STORE_FORCE_FLAG))
         FIXME("Unimplemented flags %lx\n", flags);
 
     ref = InterlockedDecrement(&store->hdr.ref);
     TRACE("(%p) ref=%ld\n", store, ref);
-    if(ref)
+    if(ref && !(flags & CERT_CLOSE_STORE_FORCE_FLAG))
         return (flags & CERT_CLOSE_STORE_CHECK_FLAG) ? CRYPT_E_PENDING_CLOSE : ERROR_SUCCESS;
 
     free_contexts(&store->certs);
diff --git a/dlls/crypt32/tests/oid.c b/dlls/crypt32/tests/oid.c
index 7206668be177..9a3376caf114 100644
--- a/dlls/crypt32/tests/oid.c
+++ b/dlls/crypt32/tests/oid.c
@@ -36,6 +36,19 @@ struct OIDToAlgID
     DWORD altAlgID;
 };
 
+struct CRYPT_OID_INFO_XP {
+    DWORD   cbSize;
+    LPCSTR  pszOID;
+    LPCWSTR pwszName;
+    DWORD   dwGroupId;
+    union {
+        DWORD  dwValue;
+        ALG_ID Algid;
+        DWORD  dwLength;
+    } DUMMYUNIONNAME;
+    CRYPT_DATA_BLOB ExtraInfo;
+};
+
 static const struct OIDToAlgID oidToAlgID[] = {
  { szOID_RSA_RSA, CALG_RSA_KEYX },
  { szOID_RSA_MD2RSA, CALG_MD2 },
@@ -592,6 +605,7 @@ static void test_registerOIDInfo(void)
 {
     static char test_oid[] = "1.2.3.4.5.6.7.8.9.10";
     CRYPT_OID_INFO info1;
+    struct CRYPT_OID_INFO_XP info_xp = {0};
     const CRYPT_OID_INFO *info2;
     HKEY key;
     DWORD ret, size, type, value;
@@ -631,6 +645,12 @@ static void test_registerOIDInfo(void)
     ret = CryptRegisterOIDInfo(&info1, 0);
     ok(ret, "got %lu\n", GetLastError());
 
+    memcpy(&info_xp, &info1, sizeof(info_xp));
+    info_xp.cbSize = sizeof(info_xp);
+
+    ret = CryptRegisterOIDInfo((CRYPT_OID_INFO*)&info_xp, 0);
+    ok(ret, "got %lu\n", GetLastError());
+
     ret = RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptDllFindOIDInfo\\1.2.3.4.5.6.7.8.9.10!1", &key);
     ok(ret == ERROR_FILE_NOT_FOUND, "got %lu\n", ret);
 
diff --git a/dlls/d3dcompiler_43/reflection.c b/dlls/d3dcompiler_43/reflection.c
index 182b3c99b637..31d48ed3adec 100644
--- a/dlls/d3dcompiler_43/reflection.c
+++ b/dlls/d3dcompiler_43/reflection.c
@@ -122,41 +122,12 @@ struct d3dcompiler_shader_reflection
     struct vkd3d_shader_scan_signature_info signature_info;
     struct vkd3d_shader_scan_thread_group_size_info thread_group_size_info;
 
+    D3D11_SHADER_DESC desc;
+
     uint32_t target;
-    char *creator;
-    UINT flags;
-    UINT version;
-    UINT bound_resource_count;
-    UINT constant_buffer_count;
 
     UINT mov_instruction_count;
     UINT conversion_instruction_count;
-    UINT instruction_count;
-    UINT emit_instruction_count;
-    D3D_PRIMITIVE_TOPOLOGY gs_output_topology;
-    UINT gs_max_output_vertex_count;
-    D3D_PRIMITIVE input_primitive;
-    UINT cut_instruction_count;
-    UINT def_count;
-    UINT dcl_count;
-    UINT static_flow_control_count;
-    UINT float_instruction_count;
-    UINT temp_register_count;
-    UINT int_instruction_count;
-    UINT uint_instruction_count;
-    UINT temp_array_count;
-    UINT array_instruction_count;
-    UINT texture_normal_instructions;
-    UINT texture_load_instructions;
-    UINT texture_comp_instructions;
-    UINT texture_bias_instructions;
-    UINT texture_gradient_instructions;
-    UINT dynamic_flow_control_count;
-    UINT macro_instruction_count;
-    UINT c_control_points;
-    D3D_TESSELLATOR_OUTPUT_PRIMITIVE hs_output_primitive;
-    D3D_TESSELLATOR_PARTITIONING hs_partitioning;
-    D3D_TESSELLATOR_DOMAIN tessellator_domain;
 
     char *resource_string;
     D3D12_SHADER_INPUT_BIND_DESC *bound_resources;
@@ -186,6 +157,24 @@ static struct d3dcompiler_shader_reflection_variable null_variable =
     &null_type
 };
 
+static bool require_space(size_t offset, size_t count, size_t size, size_t data_size)
+{
+    return !count || (data_size - offset) / count >= size;
+}
+
+/* Return a pointer to data in a code blob, with bounds checking. */
+static const void *get_data_ptr(const struct vkd3d_shader_code *code,
+        uint32_t offset, uint32_t count, uint32_t size)
+{
+    if (!require_space(offset, count, size, code->size))
+    {
+        WARN("Offset %#x and size %#x exceeds section size %#Ix.\n", offset, size, code->size);
+        return NULL;
+    }
+
+    return (const uint8_t *)code->code + offset;
+}
+
 static BOOL copy_name(const char *ptr, char **name)
 {
     if (!ptr || !ptr[0]) return TRUE;
@@ -216,6 +205,47 @@ static BOOL copy_value(const char *ptr, void **value, uint32_t size)
     return TRUE;
 }
 
+struct stat
+{
+    uint32_t instruction_count;
+    uint32_t temp_count;
+    uint32_t def_count;
+    uint32_t dcl_count;
+    uint32_t float_count;
+    uint32_t int_count;
+    uint32_t uint_count;
+    uint32_t static_flow_control_count;
+    uint32_t dynamic_flow_control_count;
+    uint32_t macro_instruction_count;
+    uint32_t temp_array_count;
+    uint32_t array_instruction_count;
+    uint32_t cut_count;
+    uint32_t emit_count;
+    uint32_t sample_count;
+    uint32_t load_count;
+    uint32_t sample_compare_count;
+    uint32_t sample_bias_count;
+    uint32_t sample_grad_count;
+    uint32_t mov_count;
+    uint32_t movc_count;
+    uint32_t type_conversion_count;
+    uint32_t bitwise_count;
+    uint32_t input_primitive;
+    uint32_t gs_output_topology;
+    uint32_t gs_max_output_vertex_count;
+    uint32_t gather_count;
+    uint32_t lod_count;
+    uint32_t sample_frequency;
+    uint32_t gs_instance_count;
+    uint32_t control_point_count;
+    uint32_t hs_output_primitive;
+    uint32_t hs_partitioning;
+    uint32_t tessellator_domain;
+    uint32_t barrier_count;
+    uint32_t atomic_count;
+    uint32_t store_count;
+};
+
 static int d3dcompiler_shader_reflection_type_compare(const void *key, const struct wine_rb_entry *entry)
 {
     const struct d3dcompiler_shader_reflection_type *t = WINE_RB_ENTRY_VALUE(entry, const struct d3dcompiler_shader_reflection_type, entry);
@@ -285,7 +315,7 @@ static void reflection_cleanup(struct d3dcompiler_shader_reflection *ref)
     {
         unsigned int i;
 
-        for (i = 0; i < ref->constant_buffer_count; ++i)
+        for (i = 0; i < ref->desc.ConstantBuffers; ++i)
         {
             free_constant_buffer(&ref->constant_buffers[i]);
         }
@@ -295,7 +325,7 @@ static void reflection_cleanup(struct d3dcompiler_shader_reflection *ref)
     free(ref->constant_buffers);
     free(ref->bound_resources);
     free(ref->resource_string);
-    free(ref->creator);
+    free((void *)ref->desc.Creator);
 
     vkd3d_shader_free_scan_signature_info(&ref->signature_info);
 }
@@ -358,7 +388,7 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetDesc(ID3D11Sha
 {
     struct d3dcompiler_shader_reflection *reflection = impl_from_ID3D11ShaderReflection(iface);
 
-    FIXME("iface %p, desc %p partial stub!\n", iface, desc);
+    TRACE("iface %p, desc %p.\n", iface, desc);
 
     if (!desc)
     {
@@ -366,46 +396,7 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetDesc(ID3D11Sha
         return E_FAIL;
     }
 
-    desc->Version = reflection->version;
-    desc->Creator = reflection->creator;
-    desc->Flags = reflection->flags;
-    desc->ConstantBuffers = reflection->constant_buffer_count;
-    desc->BoundResources = reflection->bound_resource_count;
-    desc->InputParameters = reflection->signature_info.input.element_count;
-    desc->OutputParameters = reflection->signature_info.output.element_count;
-    desc->InstructionCount = reflection->instruction_count;
-    desc->TempRegisterCount = reflection->temp_register_count;
-    desc->TempArrayCount = reflection->temp_array_count;
-    desc->DefCount = reflection->def_count;
-    desc->DclCount = reflection->dcl_count;
-    desc->TextureNormalInstructions = reflection->texture_normal_instructions;
-    desc->TextureLoadInstructions = reflection->texture_load_instructions;
-    desc->TextureCompInstructions = reflection->texture_comp_instructions;
-    desc->TextureBiasInstructions = reflection->texture_bias_instructions;
-    desc->TextureGradientInstructions = reflection->texture_gradient_instructions;
-    desc->FloatInstructionCount = reflection->float_instruction_count;
-    desc->IntInstructionCount = reflection->int_instruction_count;
-    desc->UintInstructionCount = reflection->uint_instruction_count;
-    desc->StaticFlowControlCount = reflection->static_flow_control_count;
-    desc->DynamicFlowControlCount = reflection->dynamic_flow_control_count;
-    desc->MacroInstructionCount = reflection->macro_instruction_count;
-    desc->ArrayInstructionCount = reflection->array_instruction_count;
-    desc->CutInstructionCount = reflection->cut_instruction_count;
-    desc->EmitInstructionCount = reflection->emit_instruction_count;
-    desc->GSOutputTopology = reflection->gs_output_topology;
-    desc->GSMaxOutputVertexCount = reflection->gs_max_output_vertex_count;
-#if D3D_COMPILER_VERSION
-    desc->InputPrimitive = reflection->input_primitive;
-    desc->PatchConstantParameters = reflection->signature_info.patch_constant.element_count;
-    desc->cGSInstanceCount = 0;
-    desc->cControlPoints = reflection->c_control_points;
-    desc->HSOutputPrimitive = reflection->hs_output_primitive;
-    desc->HSPartitioning = reflection->hs_partitioning;
-    desc->TessellatorDomain = reflection->tessellator_domain;
-    desc->cBarrierInstructions = 0;
-    desc->cInterlockedInstructions = 0;
-    desc->cTextureStoreInstructions = 0;
-#endif
+    *desc = reflection->desc;
 
     return S_OK;
 }
@@ -417,7 +408,7 @@ static struct ID3D11ShaderReflectionConstantBuffer * STDMETHODCALLTYPE d3dcompil
 
     TRACE("iface %p, index %u\n", iface, index);
 
-    if (index >= This->constant_buffer_count)
+    if (index >= This->desc.ConstantBuffers)
     {
         WARN("Invalid argument specified\n");
         return &null_constant_buffer.ID3D11ShaderReflectionConstantBuffer_iface;
@@ -440,7 +431,7 @@ static struct ID3D11ShaderReflectionConstantBuffer * STDMETHODCALLTYPE d3dcompil
         return &null_constant_buffer.ID3D11ShaderReflectionConstantBuffer_iface;
     }
 
-    for (i = 0; i < This->constant_buffer_count; ++i)
+    for (i = 0; i < This->desc.ConstantBuffers; ++i)
     {
         struct d3dcompiler_shader_reflection_constant_buffer *d = &This->constant_buffers[i];
 
@@ -463,7 +454,7 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetResourceBindin
 
     TRACE("iface %p, index %u, desc %p\n", iface, index, desc);
 
-    if (!desc || index >= reflection->bound_resource_count)
+    if (!desc || index >= reflection->desc.BoundResources)
     {
         WARN("Invalid argument specified\n");
         return E_INVALIDARG;
@@ -530,7 +521,7 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetPatchConstantP
         ID3D11ShaderReflection *iface, UINT index, D3D11_SIGNATURE_PARAMETER_DESC *desc)
 {
     struct d3dcompiler_shader_reflection *reflection = impl_from_ID3D11ShaderReflection(iface);
-    bool output = ((reflection->version & 0xffff0000) >> 16) == D3D12_SHVER_HULL_SHADER;
+    bool output = ((reflection->desc.Version & 0xffff0000) >> 16) == D3D12_SHVER_HULL_SHADER;
 
     TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
 
@@ -551,7 +542,7 @@ static struct ID3D11ShaderReflectionVariable * STDMETHODCALLTYPE d3dcompiler_sha
         return &null_variable.ID3D11ShaderReflectionVariable_iface;
     }
 
-    for (i = 0; i < This->constant_buffer_count; ++i)
+    for (i = 0; i < This->desc.ConstantBuffers; ++i)
     {
         struct d3dcompiler_shader_reflection_constant_buffer *cb = &This->constant_buffers[i];
 
@@ -586,7 +577,7 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetResourceBindin
         return E_INVALIDARG;
     }
 
-    for (i = 0; i < reflection->bound_resource_count; ++i)
+    for (i = 0; i < reflection->desc.BoundResources; ++i)
     {
         D3D12_SHADER_INPUT_BIND_DESC *d = &reflection->bound_resources[i];
 
@@ -1090,121 +1081,60 @@ static const struct ID3D11ShaderReflectionTypeVtbl d3dcompiler_shader_reflection
 #endif
 };
 
-static HRESULT d3dcompiler_parse_stat(struct d3dcompiler_shader_reflection *r, const char *data, size_t data_size)
+static HRESULT parse_stat(struct d3dcompiler_shader_reflection *r, const struct vkd3d_shader_code *section)
 {
-    const char *ptr = data;
-    size_t size = data_size >> 2;
-
-    TRACE("Size %Iu.\n", size);
-
-    r->instruction_count = read_u32(&ptr);
-    TRACE("InstructionCount: %u.\n", r->instruction_count);
-
-    r->temp_register_count = read_u32(&ptr);
-    TRACE("TempRegisterCount: %u.\n", r->temp_register_count);
-
-    r->def_count = read_u32(&ptr);
-    TRACE("DefCount: %u.\n", r->def_count);
-
-    r->dcl_count = read_u32(&ptr);
-    TRACE("DclCount: %u.\n", r->dcl_count);
-
-    r->float_instruction_count = read_u32(&ptr);
-    TRACE("FloatInstructionCount: %u.\n", r->float_instruction_count);
-
-    r->int_instruction_count = read_u32(&ptr);
-    TRACE("IntInstructionCount: %u.\n", r->int_instruction_count);
-
-    r->uint_instruction_count = read_u32(&ptr);
-    TRACE("UintInstructionCount: %u.\n", r->uint_instruction_count);
-
-    r->static_flow_control_count = read_u32(&ptr);
-    TRACE("StaticFlowControlCount: %u.\n", r->static_flow_control_count);
-
-    r->dynamic_flow_control_count = read_u32(&ptr);
-    TRACE("DynamicFlowControlCount: %u.\n", r->dynamic_flow_control_count);
-
-    r->macro_instruction_count = read_u32(&ptr);
-    TRACE("MacroInstructionCount: %u.\n", r->macro_instruction_count);
-
-    r->temp_array_count = read_u32(&ptr);
-    TRACE("TempArrayCount: %u.\n", r->temp_array_count);
-
-    r->array_instruction_count = read_u32(&ptr);
-    TRACE("ArrayInstructionCount: %u.\n", r->array_instruction_count);
-
-    r->cut_instruction_count = read_u32(&ptr);
-    TRACE("CutInstructionCount: %u.\n", r->cut_instruction_count);
-
-    r->emit_instruction_count = read_u32(&ptr);
-    TRACE("EmitInstructionCount: %u.\n", r->emit_instruction_count);
-
-    r->texture_normal_instructions = read_u32(&ptr);
-    TRACE("TextureNormalInstructions: %u.\n", r->texture_normal_instructions);
+    struct stat normalised_stat = {0};
+    size_t stat_size = section->size;
+    const struct stat *stat;
 
-    r->texture_load_instructions = read_u32(&ptr);
-    TRACE("TextureLoadInstructions: %u.\n", r->texture_load_instructions);
-
-    r->texture_comp_instructions = read_u32(&ptr);
-    TRACE("TextureCompInstructions: %u.\n", r->texture_comp_instructions);
-
-    r->texture_bias_instructions = read_u32(&ptr);
-    TRACE("TextureBiasInstructions: %u.\n", r->texture_bias_instructions);
-
-    r->texture_gradient_instructions = read_u32(&ptr);
-    TRACE("TextureGradientInstructions: %u.\n", r->texture_gradient_instructions);
-
-    r->mov_instruction_count = read_u32(&ptr);
-    TRACE("MovInstructionCount: %u.\n", r->mov_instruction_count);
-
-    skip_u32_unknown(&ptr, 1);
-
-    r->conversion_instruction_count = read_u32(&ptr);
-    TRACE("ConversionInstructionCount: %u.\n", r->conversion_instruction_count);
-
-    skip_u32_unknown(&ptr, 1);
-
-    r->input_primitive = read_u32(&ptr);
-    TRACE("InputPrimitive: %x.\n", r->input_primitive);
-
-    r->gs_output_topology = read_u32(&ptr);
-    TRACE("GSOutputTopology: %x.\n", r->gs_output_topology);
-
-    r->gs_max_output_vertex_count = read_u32(&ptr);
-    TRACE("GSMaxOutputVertexCount: %u.\n", r->gs_max_output_vertex_count);
-
-    skip_u32_unknown(&ptr, 2);
-
-    /* old dx10 stat size */
-    if (size == 28) return S_OK;
-
-    skip_u32_unknown(&ptr, 1);
-
-    /* dx10 stat size */
-    if (size == 29) return S_OK;
-
-    skip_u32_unknown(&ptr, 1);
-
-    r->c_control_points = read_u32(&ptr);
-    TRACE("cControlPoints: %u.\n", r->c_control_points);
-
-    r->hs_output_primitive = read_u32(&ptr);
-    TRACE("HSOutputPrimitive: %x.\n", r->hs_output_primitive);
-
-    r->hs_partitioning = read_u32(&ptr);
-    TRACE("HSPartitioning: %x.\n", r->hs_partitioning);
-
-    r->tessellator_domain = read_u32(&ptr);
-    TRACE("TessellatorDomain: %x.\n", r->tessellator_domain);
-
-    skip_u32_unknown(&ptr, 3);
-
-    /* dx11 stat size */
-    if (size == 37) return S_OK;
+    if (stat_size != sizeof(struct stat)
+            && stat_size != offsetof(struct stat, gs_instance_count)
+            && stat_size != offsetof(struct stat, sample_frequency))
+    {
+        FIXME("Unexpected STAT size %#Ix.\n", stat_size);
+        return E_FAIL;
+    }
 
-    FIXME("Unhandled size %Iu.\n", size);
+    if (!(stat = get_data_ptr(section, 0, 1, stat_size)))
+        return E_INVALIDARG;
+    memcpy(&normalised_stat, stat, stat_size);
+
+    r->desc.InstructionCount = normalised_stat.instruction_count;
+    r->desc.TempRegisterCount = normalised_stat.temp_count;
+    r->desc.DefCount = normalised_stat.def_count;
+    r->desc.DclCount = normalised_stat.dcl_count;
+    r->desc.FloatInstructionCount = normalised_stat.float_count;
+    r->desc.IntInstructionCount = normalised_stat.int_count;
+    r->desc.UintInstructionCount = normalised_stat.uint_count;
+    r->desc.StaticFlowControlCount = normalised_stat.static_flow_control_count;
+    r->desc.DynamicFlowControlCount = normalised_stat.dynamic_flow_control_count;
+    r->desc.MacroInstructionCount = normalised_stat.macro_instruction_count;
+    r->desc.TempArrayCount = normalised_stat.temp_array_count;
+    r->desc.ArrayInstructionCount = normalised_stat.array_instruction_count;
+    r->desc.CutInstructionCount = normalised_stat.cut_count;
+    r->desc.EmitInstructionCount = normalised_stat.emit_count;
+    r->desc.TextureNormalInstructions = normalised_stat.sample_count;
+    r->desc.TextureLoadInstructions = normalised_stat.load_count;
+    r->desc.TextureCompInstructions = normalised_stat.sample_compare_count;
+    r->desc.TextureBiasInstructions = normalised_stat.sample_bias_count;
+    r->desc.TextureGradientInstructions = normalised_stat.sample_grad_count;
+    r->mov_instruction_count = normalised_stat.mov_count;
+    r->conversion_instruction_count = normalised_stat.type_conversion_count;
+#if D3D_COMPILER_VERSION
+    r->desc.InputPrimitive = normalised_stat.input_primitive;
+    r->desc.GSOutputTopology = normalised_stat.gs_output_topology;
+    r->desc.GSMaxOutputVertexCount = normalised_stat.gs_max_output_vertex_count;
+    r->desc.cGSInstanceCount = normalised_stat.gs_instance_count;
+    r->desc.cControlPoints = normalised_stat.control_point_count;
+    r->desc.HSOutputPrimitive = normalised_stat.hs_output_primitive;
+    r->desc.HSPartitioning = normalised_stat.hs_partitioning;
+    r->desc.TessellatorDomain = normalised_stat.tessellator_domain;
+    r->desc.cBarrierInstructions = normalised_stat.barrier_count;
+    r->desc.cInterlockedInstructions = normalised_stat.atomic_count;
+    r->desc.cTextureStoreInstructions = normalised_stat.store_count;
+#endif
 
-    return E_FAIL;
+    return S_OK;
 }
 
 static HRESULT d3dcompiler_parse_type_members(struct d3dcompiler_shader_reflection *ref,
@@ -1453,14 +1383,14 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
 
     TRACE("Size %Iu.\n", size);
 
-    r->constant_buffer_count = read_u32(&ptr);
-    TRACE("Constant buffer count: %u.\n", r->constant_buffer_count);
+    r->desc.ConstantBuffers = read_u32(&ptr);
+    TRACE("Constant buffer count: %u.\n", r->desc.ConstantBuffers);
 
     cbuffer_offset = read_u32(&ptr);
     TRACE("Constant buffer offset: %#x.\n", cbuffer_offset);
 
-    r->bound_resource_count = read_u32(&ptr);
-    TRACE("Bound resource count: %u.\n", r->bound_resource_count);
+    r->desc.BoundResources = read_u32(&ptr);
+    TRACE("Bound resource count: %u.\n", r->desc.BoundResources);
 
     resource_offset = read_u32(&ptr);
     TRACE("Bound resource offset: %#x.\n", resource_offset);
@@ -1480,8 +1410,8 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
     }
 #endif
 
-    r->flags = read_u32(&ptr);
-    TRACE("Flags: %u.\n", r->flags);
+    r->desc.Flags = read_u32(&ptr);
+    TRACE("Flags: %#x.\n", r->desc.Flags);
 
     creator_offset = read_u32(&ptr);
     TRACE("Creator at offset %#x.\n", creator_offset);
@@ -1499,10 +1429,10 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
         skip_u32_unknown(&ptr, 8);
     }
 
-    if (r->bound_resource_count)
+    if (r->desc.BoundResources)
     {
         /* 8 for each bind desc */
-        string_data_offset = resource_offset + r->bound_resource_count * 8 * sizeof(uint32_t);
+        string_data_offset = resource_offset + r->desc.BoundResources * 8 * sizeof(uint32_t);
         string_data_size = (cbuffer_offset ? cbuffer_offset : creator_offset) - string_data_offset;
 
         string_data = malloc(string_data_size);
@@ -1514,7 +1444,7 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
         }
         memcpy(string_data, data + string_data_offset, string_data_size);
 
-        bound_resources = calloc(r->bound_resource_count, sizeof(*bound_resources));
+        bound_resources = calloc(r->desc.BoundResources, sizeof(*bound_resources));
         if (!bound_resources)
         {
             ERR("Failed to allocate resources memory.\n");
@@ -1523,7 +1453,7 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
         }
 
         ptr = data + resource_offset;
-        for (i = 0; i < r->bound_resource_count; i++)
+        for (i = 0; i < r->desc.BoundResources; i++)
         {
             D3D12_SHADER_INPUT_BIND_DESC *desc = &bound_resources[i];
 
@@ -1566,9 +1496,9 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
         }
     }
 
-    if (r->constant_buffer_count)
+    if (r->desc.ConstantBuffers)
     {
-        constant_buffers = calloc(r->constant_buffer_count, sizeof(*constant_buffers));
+        constant_buffers = calloc(r->desc.ConstantBuffers, sizeof(*constant_buffers));
         if (!constant_buffers)
         {
             ERR("Failed to allocate constant buffer memory.\n");
@@ -1577,7 +1507,7 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
         }
 
         ptr = data + cbuffer_offset;
-        for (i = 0; i < r->constant_buffer_count; i++)
+        for (i = 0; i < r->desc.ConstantBuffers; i++)
         {
             struct d3dcompiler_shader_reflection_constant_buffer *cb = &constant_buffers[i];
 
@@ -1617,7 +1547,7 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
         }
     }
 
-    r->creator = creator;
+    r->desc.Creator = creator;
     r->resource_string = string_data;
     r->bound_resources = bound_resources;
     r->constant_buffers = constant_buffers;
@@ -1625,7 +1555,7 @@ static HRESULT d3dcompiler_parse_rdef(struct d3dcompiler_shader_reflection *r, c
     return S_OK;
 
 err_out:
-    for (i = 0; i < r->constant_buffer_count; ++i)
+    for (i = 0; i < r->desc.ConstantBuffers; ++i)
     {
         free_constant_buffer(&constant_buffers[i]);
     }
@@ -1642,6 +1572,7 @@ static HRESULT d3dcompiler_shader_reflection_init(struct d3dcompiler_shader_refl
 {
     struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO};
     struct vkd3d_shader_dxbc_desc src_dxbc_desc;
+    bool found_stat = false;
     HRESULT hr = S_OK;
     unsigned int i;
     int ret;
@@ -1687,19 +1618,32 @@ static HRESULT d3dcompiler_shader_reflection_init(struct d3dcompiler_shader_refl
         {
             const char *ptr = section->data.code;
 
-            reflection->version = read_u32(&ptr);
-            TRACE("Shader version: 0x%08x.\n", reflection->version);
+            reflection->desc.Version = read_u32(&ptr);
+            TRACE("Shader version: 0x%08x.\n", reflection->desc.Version);
         }
         else if (section->tag == TAG_STAT)
         {
-            if (FAILED(hr = d3dcompiler_parse_stat(reflection, section->data.code, section->data.size)))
+            if (found_stat)
+            {
+                FIXME("Multiple STAT sections.\n");
+                continue;
+            }
+
+            if (FAILED(hr = parse_stat(reflection, &section->data)))
             {
                 WARN("Failed to parse STAT section.\n");
                 goto err_out;
             }
+            found_stat = true;
         }
     }
 
+    reflection->desc.InputParameters = reflection->signature_info.input.element_count;
+    reflection->desc.OutputParameters = reflection->signature_info.output.element_count;
+#if D3D_COMPILER_VERSION
+    reflection->desc.PatchConstantParameters = reflection->signature_info.patch_constant.element_count;
+#endif
+
     vkd3d_shader_free_dxbc(&src_dxbc_desc);
 
     return hr;
diff --git a/dlls/dbghelp/dwarf.c b/dlls/dbghelp/dwarf.c
index 32ab0029ac0a..46c39231bad8 100644
--- a/dlls/dbghelp/dwarf.c
+++ b/dlls/dbghelp/dwarf.c
@@ -1020,7 +1020,7 @@ compute_location(const struct module *module, const dwarf2_cuhead_t* head,
         case DW_OP_swap:        tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = tmp; break;
         case DW_OP_rot:         tmp = stack[stk]; stack[stk] = stack[stk-1]; stack[stk-1] = stack[stk-2]; stack[stk-2] = tmp; break;
         case DW_OP_abs:         stack[stk] = sizeof(stack[stk]) == 8 ? llabs((INT64)stack[stk]) : abs((INT32)stack[stk]); break;
-        case DW_OP_neg:         stack[stk] = -stack[stk]; break;
+        case DW_OP_neg:         stack[stk] = -(LONG_PTR)stack[stk]; break;
         case DW_OP_not:         stack[stk] = ~stack[stk]; break;
         case DW_OP_and:         stack[stk-1] &= stack[stk]; stk--; break;
         case DW_OP_or:          stack[stk-1] |= stack[stk]; stk--; break;
@@ -1031,13 +1031,29 @@ compute_location(const struct module *module, const dwarf2_cuhead_t* head,
         case DW_OP_shl:         stack[stk-1] <<= stack[stk]; stk--; break;
         case DW_OP_shr:         stack[stk-1] >>= stack[stk]; stk--; break;
         case DW_OP_plus_uconst: stack[stk] += dwarf2_leb128_as_unsigned(ctx); break;
-        case DW_OP_shra:        stack[stk-1] = stack[stk-1] / (1 << stack[stk]); stk--; break;
-        case DW_OP_div:         stack[stk-1] = stack[stk-1] / stack[stk]; stk--; break;
-        case DW_OP_mod:         stack[stk-1] = stack[stk-1] % stack[stk]; stk--; break;
-        case DW_OP_ge:          stack[stk-1] = (stack[stk-1] >= stack[stk]); stk--; break;
-        case DW_OP_gt:          stack[stk-1] = (stack[stk-1] >  stack[stk]); stk--; break;
-        case DW_OP_le:          stack[stk-1] = (stack[stk-1] <= stack[stk]); stk--; break;
-        case DW_OP_lt:          stack[stk-1] = (stack[stk-1] <  stack[stk]); stk--; break;
+        case DW_OP_shra:        stack[stk-1] = (LONG_PTR)stack[stk-1] >> stack[stk]; stk--; break;
+        case DW_OP_div:
+            if (!stack[stk])
+            {
+                ERR("Attempting to divide by zero\n");
+                return loc_err_internal;
+            }
+            stack[stk-1] = (LONG_PTR)stack[stk-1] / (LONG_PTR)stack[stk];
+            stk--;
+            break;
+        case DW_OP_mod:
+            if (!stack[stk])
+            {
+                ERR("Attempting to divide(modulo) by zero\n");
+                return loc_err_internal;
+            }
+            stack[stk-1] %= stack[stk];
+            stk--;
+            break;
+        case DW_OP_ge:          stack[stk-1] = ((LONG_PTR)stack[stk-1] >= (LONG_PTR)stack[stk]); stk--; break;
+        case DW_OP_gt:          stack[stk-1] = ((LONG_PTR)stack[stk-1] >  (LONG_PTR)stack[stk]); stk--; break;
+        case DW_OP_le:          stack[stk-1] = ((LONG_PTR)stack[stk-1] <= (LONG_PTR)stack[stk]); stk--; break;
+        case DW_OP_lt:          stack[stk-1] = ((LONG_PTR)stack[stk-1] <  (LONG_PTR)stack[stk]); stk--; break;
         case DW_OP_eq:          stack[stk-1] = (stack[stk-1] == stack[stk]); stk--; break;
         case DW_OP_ne:          stack[stk-1] = (stack[stk-1] != stack[stk]); stk--; break;
         case DW_OP_skip:        tmp = dwarf2_parse_u2(ctx); ctx->data += tmp; break;
@@ -3782,7 +3798,7 @@ static ULONG_PTR eval_expression(const struct module* module, struct cpu_stack_w
         case DW_OP_swap:        tmp = stack[sp]; stack[sp] = stack[sp-1]; stack[sp-1] = tmp; break;
         case DW_OP_rot:         tmp = stack[sp]; stack[sp] = stack[sp-1]; stack[sp-1] = stack[sp-2]; stack[sp-2] = tmp; break;
         case DW_OP_abs:         stack[sp] = sizeof(stack[sp]) == 8 ? llabs((INT64)stack[sp]) : abs((INT32)stack[sp]); break;
-        case DW_OP_neg:         stack[sp] = -stack[sp]; break;
+        case DW_OP_neg:         stack[sp] = -(LONG_PTR)stack[sp]; break;
         case DW_OP_not:         stack[sp] = ~stack[sp]; break;
         case DW_OP_and:         stack[sp-1] &= stack[sp]; sp--; break;
         case DW_OP_or:          stack[sp-1] |= stack[sp]; sp--; break;
@@ -3793,9 +3809,25 @@ static ULONG_PTR eval_expression(const struct module* module, struct cpu_stack_w
         case DW_OP_shl:         stack[sp-1] <<= stack[sp]; sp--; break;
         case DW_OP_shr:         stack[sp-1] >>= stack[sp]; sp--; break;
         case DW_OP_plus_uconst: stack[sp] += dwarf2_leb128_as_unsigned(&ctx); break;
-        case DW_OP_shra:        stack[sp-1] = (LONG_PTR)stack[sp-1] / (1 << stack[sp]); sp--; break;
-        case DW_OP_div:         stack[sp-1] = (LONG_PTR)stack[sp-1] / (LONG_PTR)stack[sp]; sp--; break;
-        case DW_OP_mod:         stack[sp-1] = (LONG_PTR)stack[sp-1] % (LONG_PTR)stack[sp]; sp--; break;
+        case DW_OP_shra:        stack[sp-1] = (LONG_PTR)stack[sp-1] >> stack[sp]; sp--; break;
+        case DW_OP_div:
+            if (!stack[sp])
+            {
+                ERR("Attempting to divide by zero\n");
+                stack[sp-1] = 0;
+            }
+            else stack[sp-1] = (LONG_PTR)stack[sp-1] / (LONG_PTR)stack[sp];
+            sp--;
+            break;
+        case DW_OP_mod:
+            if (!stack[sp])
+            {
+                ERR("Attempting to divide(modulo) by zero\n");
+                stack[sp-1] = 0;
+            }
+            else stack[sp-1] %= stack[sp];
+            sp--;
+            break;
         case DW_OP_ge:          stack[sp-1] = ((LONG_PTR)stack[sp-1] >= (LONG_PTR)stack[sp]); sp--; break;
         case DW_OP_gt:          stack[sp-1] = ((LONG_PTR)stack[sp-1] >  (LONG_PTR)stack[sp]); sp--; break;
         case DW_OP_le:          stack[sp-1] = ((LONG_PTR)stack[sp-1] <= (LONG_PTR)stack[sp]); sp--; break;
diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index c4ce81234bcb..8814c32447d6 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -1143,7 +1143,8 @@ static HRESULT WINAPI ddraw7_SetDisplayMode(IDirectDraw7 *iface, DWORD width, DW
             DDSURFACEDESC2 *surface_desc = &ddraw->primary->surface_desc;
 
             if (FAILED(hr = wined3d_swapchain_resize_buffers(ddraw->wined3d_swapchain, 0,
-                    surface_desc->dwWidth, surface_desc->dwHeight, mode.format_id, WINED3D_MULTISAMPLE_NONE, 0)))
+                    surface_desc->dwWidth, surface_desc->dwHeight, mode.format_id,
+                    WINED3D_MULTISAMPLE_NONE, 0, 0)))
                 ERR("Failed to resize buffers, hr %#lx.\n", hr);
             else
                 ddrawformat_from_wined3dformat(&ddraw->primary->surface_desc.ddpfPixelFormat, mode.format_id);
diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c
index 3160a4ddefae..9b3d879be540 100644
--- a/dlls/dsound/dsound_convert.c
+++ b/dlls/dsound/dsound_convert.c
@@ -47,70 +47,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dsound);
 
-static void get8(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
-{
-    DWORD channels = dsb->pwfx->nChannels;
-    const BYTE *buf = base + channel;
-    int i;
-
-    for (i = 0; i < samples; ++i)
-        dst[i] = (buf[i * channels] - 0x80) / (float)0x80;
-}
-
-static void get16(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
-{
-    DWORD channels = dsb->pwfx->nChannels;
-    const BYTE *buf = base + 2 * channel;
-    const SHORT *sbuf = (const SHORT*)(buf);
-    int i;
-
-    for (i = 0; i < samples; ++i)
-        dst[i] = sbuf[i * channels] / (float)0x8000;
-}
-
-static void get24(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
-{
-    DWORD channels = dsb->pwfx->nChannels;
-    const BYTE *buf = base + 3 * channel;
-    int i;
-
-    for (i = 0; i < samples; ++i) {
-        /* The next expression deliberately has an overflow for buf[2] >= 0x80,
-           this is how negative values are made.
-         */
-        LONG sample =
-                (buf[i * channels * 3 + 0] << 8) |
-                (buf[i * channels * 3 + 1] << 16) |
-                (buf[i * channels * 3 + 2] << 24);
-        dst[i] = sample / (float)0x80000000U;
-    }
-}
-
-static void get32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
-{
-    DWORD channels = dsb->pwfx->nChannels;
-    const BYTE *buf = base + 4 * channel;
-    const LONG *sbuf = (const LONG*)(buf);
-    int i;
-
-    for (i = 0; i < samples; ++i)
-        dst[i] = sbuf[i * channels] / (float)0x80000000U;
-}
-
-const bitsgetfunc getbpp[4] = {get8, get16, get24, get32};
-
-void getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
-{
-    DWORD channels = dsb->pwfx->nChannels;
-    const BYTE *buf = base + 4 * channel;
-    const float *sbuf = (const float*)(buf);
-    int i;
-
-    for (i = 0; i < samples; ++i)
-        /* The value will be clipped later, when put into some non-float buffer */
-        dst[i] = sbuf[i * channels];
-}
-
 void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
 {
     BYTE *buf = (BYTE *)dsb->device->tmp_buffer;
@@ -180,6 +116,73 @@ void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float
     dsb->put_aux(dsb, pos, 0, value);
 }
 
+void put_mono2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+{
+    dsb->put_aux(dsb, pos, 2, value); /* Front centre */
+
+    dsb->put_aux(dsb, pos, 0, 0.0f); /* Mute front left */
+    dsb->put_aux(dsb, pos, 1, 0.0f); /* Mute front right */
+    dsb->put_aux(dsb, pos, 3, 0.0f); /* Mute LFE */
+    dsb->put_aux(dsb, pos, 4, 0.0f); /* Mute back left */
+    dsb->put_aux(dsb, pos, 5, 0.0f); /* Mute back right */
+    dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */
+    dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */
+}
+
+void put_stereo2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+{
+    if (channel == 0) { /* Left */
+        dsb->put_aux(dsb, pos, 0, value); /* Front left */
+
+        dsb->put_aux(dsb, pos, 2, 0.0f); /* Mute front centre */
+        dsb->put_aux(dsb, pos, 3, 0.0f); /* Mute LFE */
+        dsb->put_aux(dsb, pos, 4, 0.0f); /* Mute back left */
+        dsb->put_aux(dsb, pos, 5, 0.0f); /* Mute back right */
+        dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */
+        dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */
+    } else if (channel == 1) { /* Right */
+        dsb->put_aux(dsb, pos, 1, value); /* Front right */
+    }
+}
+
+void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+{
+    if (channel == 0) { /* Front left */
+        dsb->put_aux(dsb, pos, 0, value); /* Front left */
+
+        dsb->put_aux(dsb, pos, 2, 0.0f); /* Mute front center */
+        dsb->put_aux(dsb, pos, 3, 0.0f); /* Mute LFE */
+        dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */
+        dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */
+    } else if (channel == 1) { /* Front right */
+        dsb->put_aux(dsb, pos, 1, value); /* Front right */
+    } else if (channel == 2) { /* Rear left */
+        dsb->put_aux(dsb, pos, 4, value); /* Rear left */
+    } else if (channel == 3) { /* Rear right */
+        dsb->put_aux(dsb, pos, 5, value); /* Rear right */
+    }
+}
+
+void put_surround512surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
+{
+    if (channel == 0) { /* Front left */
+        dsb->put_aux(dsb, pos, 0, value); /* Front left */
+
+        dsb->put_aux(dsb, pos, 6, 0.0f); /* Mute side left */
+        dsb->put_aux(dsb, pos, 7, 0.0f); /* Mute side right */
+    } else if (channel == 1) { /* Front right */
+        dsb->put_aux(dsb, pos, 1, value); /* Front right */
+    } else if (channel == 2) { /* Front center */
+        dsb->put_aux(dsb, pos, 2, value); /* Front center */
+    } else if (channel == 3) { /* LFE */
+        dsb->put_aux(dsb, pos, 3, value); /* LFE */
+    } else if (channel == 4) { /* Rear left */
+        dsb->put_aux(dsb, pos, 4, value); /* Rear left */
+    } else if (channel == 5) { /* Rear right */
+        dsb->put_aux(dsb, pos, 5, value); /* Rear right */
+    }
+}
+
 void put_surround512stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
 {
     /* based on analyzing a recording of a dsound downmix */
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index fc6fbfd1cc57..a3a240e67e08 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -45,8 +45,6 @@ typedef struct DirectSoundDevice             DirectSoundDevice;
 /* dsound_convert.h */
 typedef void (*bitsgetfunc)(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel);
 typedef void (*bitsputfunc)(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
-extern const bitsgetfunc getbpp[4];
-void getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel);
 void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 void putieee32_sum(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 void mixieee32(float *src, float *dst, unsigned samples);
@@ -179,6 +177,10 @@ void put_mono(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float
 void put_surround512stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 void put_surround712stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 void put_quad2stereo(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
+void put_stereo2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
+void put_mono2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
+void put_quad2surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
+void put_surround512surround71(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 
 HRESULT secondarybuffer_create(DirectSoundDevice *device, const DSBUFFERDESC *dsbd,
         IDirectSoundBuffer **buffer);
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index fca7f09d6b61..1ba56ea2575c 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -99,6 +99,70 @@ void DSOUND_AmpFactorToVolPan(PDSVOLUMEPAN volpan)
     TRACE("Vol=%ld Pan=%ld\n", volpan->lVolume, volpan->lPan);
 }
 
+static void get8(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
+{
+    DWORD channels = dsb->pwfx->nChannels;
+    const BYTE *buf = base + channel;
+    int i;
+
+    for (i = 0; i < samples; ++i)
+        dst[i] = (buf[i * channels] - 0x80) / (float)0x80;
+}
+
+static void get16(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
+{
+    DWORD channels = dsb->pwfx->nChannels;
+    const BYTE *buf = base + 2 * channel;
+    const SHORT *sbuf = (const SHORT*)(buf);
+    int i;
+
+    for (i = 0; i < samples; ++i)
+        dst[i] = sbuf[i * channels] / (float)0x8000;
+}
+
+static void get24(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
+{
+    DWORD channels = dsb->pwfx->nChannels;
+    const BYTE *buf = base + 3 * channel;
+    int i;
+
+    for (i = 0; i < samples; ++i) {
+        /* The next expression deliberately has an overflow for buf[2] >= 0x80,
+           this is how negative values are made.
+         */
+        LONG sample =
+                (buf[i * channels * 3 + 0] << 8) |
+                (buf[i * channels * 3 + 1] << 16) |
+                (buf[i * channels * 3 + 2] << 24);
+        dst[i] = sample / (float)0x80000000U;
+    }
+}
+
+static void get32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
+{
+    DWORD channels = dsb->pwfx->nChannels;
+    const BYTE *buf = base + 4 * channel;
+    const LONG *sbuf = (const LONG*)(buf);
+    int i;
+
+    for (i = 0; i < samples; ++i)
+        dst[i] = sbuf[i * channels] / (float)0x80000000U;
+}
+
+static const bitsgetfunc getbpp[4] = {get8, get16, get24, get32};
+
+static void getieee32(const IDirectSoundBufferImpl *dsb, BYTE *base, float *dst, unsigned samples, DWORD channel)
+{
+    DWORD channels = dsb->pwfx->nChannels;
+    const BYTE *buf = base + 4 * channel;
+    const float *sbuf = (const float*)(buf);
+    int i;
+
+    for (i = 0; i < samples; ++i)
+        /* The value will be clipped later, when put into some non-float buffer */
+        dst[i] = sbuf[i * channels];
+}
+
 /**
  * Recalculate the size for temporary buffer, and new writelead
  * Should be called when one of the following things occur:
@@ -195,6 +259,26 @@ void DSOUND_RecalcFormat(IDirectSoundBufferImpl *dsb)
 		dsb->put = put_quad2stereo;
 		dsb->put_aux = putieee32_sum;
 	}
+	else if (ichannels == 1 && ochannels == 8)
+	{
+		dsb->mix_channels = 1;
+		dsb->put = put_mono2surround71;
+	}
+	else if (ichannels == 2 && ochannels == 8)
+	{
+		dsb->mix_channels = 2;
+		dsb->put = put_stereo2surround71;
+	}
+	else if (ichannels == 4 && ochannels == 8)
+	{
+		dsb->mix_channels = 4;
+		dsb->put = put_quad2surround71;
+	}
+	else if (ichannels == 6 && ochannels == 8)
+	{
+		dsb->mix_channels = 6;
+		dsb->put = put_surround512surround71;
+	}
 	else
 	{
 		if (ichannels > 2)
diff --git a/dlls/dxcore/dxcore.c b/dlls/dxcore/dxcore.c
index a63a8f33d721..0bea5e32a61a 100644
--- a/dlls/dxcore/dxcore.c
+++ b/dlls/dxcore/dxcore.c
@@ -109,6 +109,9 @@ static HRESULT dxcore_adapter_get_property_size(struct dxcore_adapter *adapter,
         [InstanceLuid] = sizeof(LUID),
         [DriverVersion] = sizeof(LARGE_INTEGER),
         [HardwareID] = sizeof(DXCoreHardwareID),
+        [DedicatedAdapterMemory] = sizeof(UINT64),
+        [DedicatedSystemMemory] = sizeof(UINT64),
+        [SharedSystemMemory] = sizeof(UINT64),
         [IsHardware] = sizeof(BYTE),
     };
 
@@ -117,6 +120,9 @@ static HRESULT dxcore_adapter_get_property_size(struct dxcore_adapter *adapter,
         case InstanceLuid:
         case DriverVersion:
         case HardwareID:
+        case DedicatedAdapterMemory:
+        case DedicatedSystemMemory:
+        case SharedSystemMemory:
         case IsHardware:
             *size = property_sizes[property];
             return S_OK;
@@ -174,6 +180,19 @@ static HRESULT STDMETHODCALLTYPE dxcore_adapter_GetProperty(IDXCoreAdapter *ifac
             break;
         }
 
+        case DedicatedAdapterMemory:
+            *(UINT64 *)buffer = adapter->identifier.video_memory;
+            break;
+
+        case DedicatedSystemMemory:
+            FIXME("Returning 0 for DedicatedSystemMemory.\n");
+            *(UINT64 *)buffer = 0;
+            break;
+
+        case SharedSystemMemory:
+            *(UINT64 *)buffer = adapter->identifier.shared_system_memory;
+            break;
+
         case IsHardware:
             FIXME("Returning all adapters as Hardware.\n");
             *(BYTE *)buffer = 1;
diff --git a/dlls/dxcore/tests/dxcore.c b/dlls/dxcore/tests/dxcore.c
index ba22d262a121..820103ff2954 100644
--- a/dlls/dxcore/tests/dxcore.c
+++ b/dlls/dxcore/tests/dxcore.c
@@ -155,6 +155,7 @@ static void test_GetProperty(void)
     DXCoreHardwareID hwid[2];
     IDXCoreAdapter *adapter;
     uint32_t count, dummy;
+    uint64_t memory;
     LARGE_INTEGER version;
     BYTE is_hardware;
     LUID luid[2];
@@ -227,6 +228,60 @@ static void test_GetProperty(void)
         ok(!hwid[1].vendorID, "Expected no vendorID.\n");
         ok(!hwid[1].deviceID, "Expected no deviceID.\n");
 
+        /* DedicatedAdapterMemory */
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedAdapterMemory, 0, NULL);
+        ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedAdapterMemory, 0, &memory);
+        ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedAdapterMemory, sizeof(memory) - 1, &memory);
+        ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
+
+        hr = IDXCoreAdapter_GetPropertySize(adapter, DedicatedAdapterMemory, NULL);
+        ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
+
+        hr = IDXCoreAdapter_GetPropertySize(adapter, DedicatedAdapterMemory, &size);
+        ok(hr == S_OK, "Got hr %#lx.\n", hr);
+        ok(size == sizeof(memory), "Got size %Iu.\n", size);
+
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedAdapterMemory, sizeof(memory), &memory);
+        ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+        /* DedicatedSystemMemory */
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedSystemMemory, 0, NULL);
+        ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedSystemMemory, 0, &memory);
+        ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedSystemMemory, sizeof(memory) - 1, &memory);
+        ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
+
+        hr = IDXCoreAdapter_GetPropertySize(adapter, DedicatedSystemMemory, NULL);
+        ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
+
+        hr = IDXCoreAdapter_GetPropertySize(adapter, DedicatedSystemMemory, &size);
+        ok(hr == S_OK, "Got hr %#lx.\n", hr);
+        ok(size == sizeof(memory), "Got size %Iu.\n", size);
+
+        hr = IDXCoreAdapter_GetProperty(adapter, DedicatedSystemMemory, sizeof(memory), &memory);
+        ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+        /* SharedSystemMemory */
+        hr = IDXCoreAdapter_GetProperty(adapter, SharedSystemMemory, 0, NULL);
+        ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
+        hr = IDXCoreAdapter_GetProperty(adapter, SharedSystemMemory, 0, &memory);
+        ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
+        hr = IDXCoreAdapter_GetProperty(adapter, SharedSystemMemory, sizeof(memory) - 1, &memory);
+        ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
+
+        hr = IDXCoreAdapter_GetPropertySize(adapter, SharedSystemMemory, NULL);
+        ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
+
+        hr = IDXCoreAdapter_GetPropertySize(adapter, SharedSystemMemory, &size);
+        ok(hr == S_OK, "Got hr %#lx.\n", hr);
+        ok(size == sizeof(memory), "Got size %Iu.\n", size);
+
+        hr = IDXCoreAdapter_GetProperty(adapter, SharedSystemMemory, sizeof(memory), &memory);
+        ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
         /* IsHardware */
         hr = IDXCoreAdapter_GetProperty(adapter, IsHardware, 0, NULL);
         ok(hr == E_POINTER, "Got hr %#lx.\n", hr);
diff --git a/dlls/dxgi/dxgi_private.h b/dlls/dxgi/dxgi_private.h
index cbe7c0981e64..ed82d3667994 100644
--- a/dlls/dxgi/dxgi_private.h
+++ b/dlls/dxgi/dxgi_private.h
@@ -95,6 +95,7 @@ void wined3d_display_mode_from_dxgi1(struct wined3d_display_mode *wined3d_mode,
 DXGI_USAGE dxgi_usage_from_wined3d_bind_flags(unsigned int wined3d_bind_flags);
 unsigned int wined3d_bind_flags_from_dxgi_usage(DXGI_USAGE usage);
 unsigned int dxgi_swapchain_flags_from_wined3d(unsigned int wined3d_flags);
+unsigned int wined3d_swapchain_flags_from_dxgi(unsigned int flags);
 HRESULT dxgi_get_output_from_window(IWineDXGIFactory *factory, HWND window, IDXGIOutput **dxgi_output)
        ;
 HRESULT wined3d_swapchain_desc_from_dxgi(struct wined3d_swapchain_desc *wined3d_desc,
diff --git a/dlls/dxgi/factory.c b/dlls/dxgi/factory.c
index 7837bffaca35..c6bb47fa9dd8 100644
--- a/dlls/dxgi/factory.c
+++ b/dlls/dxgi/factory.c
@@ -448,9 +448,21 @@ static HRESULT STDMETHODCALLTYPE dxgi_factory_EnumAdapterByLuid(IWineDXGIFactory
 static HRESULT STDMETHODCALLTYPE dxgi_factory_EnumWarpAdapter(IWineDXGIFactory *iface,
         REFIID iid, void **adapter)
 {
-    FIXME("iface %p, iid %s, adapter %p stub!\n", iface, debugstr_guid(iid), adapter);
+    IDXGIAdapter1 *adapter_object;
+    HRESULT hr;
 
-    return E_NOTIMPL;
+    FIXME("iface %p, iid %s, adapter %p semi-stub, returning a hardware adapter.\n",
+            iface, debugstr_guid(iid), adapter);
+
+    if (!adapter)
+        return DXGI_ERROR_INVALID_CALL;
+
+    if (FAILED(hr = dxgi_factory_EnumAdapters1(iface, 0, &adapter_object)))
+        return hr;
+
+    hr = IDXGIAdapter1_QueryInterface(adapter_object, iid, adapter);
+    IDXGIAdapter1_Release(adapter_object);
+    return hr;
 }
 
 static HRESULT STDMETHODCALLTYPE dxgi_factory_CheckFeatureSupport(IWineDXGIFactory *iface,
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c
index eee4a2a42b33..1186527d8992 100644
--- a/dlls/dxgi/swapchain.c
+++ b/dlls/dxgi/swapchain.c
@@ -549,6 +549,9 @@ static HRESULT d3d11_swapchain_create_d3d11_textures(struct d3d11_swapchain *swa
 static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain4 *iface,
         UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
 {
+    static const UINT supported_flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+            | DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE
+            | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
     struct d3d11_swapchain *swapchain = d3d11_swapchain_from_IDXGISwapChain4(iface);
     struct wined3d_swapchain_desc wined3d_desc;
     struct wined3d_texture *texture;
@@ -559,11 +562,17 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain4 *
     TRACE("iface %p, buffer_count %u, width %u, height %u, format %s, flags %#x.\n",
             iface, buffer_count, width, height, debug_dxgi_format(format), flags);
 
-    if (flags)
-        FIXME("Ignoring flags %#x.\n", flags);
+    if (flags & ~supported_flags)
+        FIXME("Ignoring flags %#x.\n", flags & ~supported_flags);
 
     wined3d_mutex_lock();
     wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &wined3d_desc);
+    if (!(wined3d_desc.flags & WINED3D_SWAPCHAIN_FRAME_LATENCY_WAITABLE_OBJECT)
+            != !(flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+    {
+        wined3d_mutex_unlock();
+        return E_INVALIDARG;
+    }
     for (i = 0; i < wined3d_desc.backbuffer_count; ++i)
     {
         texture = wined3d_swapchain_get_back_buffer(swapchain->wined3d_swapchain, i);
@@ -577,8 +586,10 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_ResizeBuffers(IDXGISwapChain4 *
     }
     if (format != DXGI_FORMAT_UNKNOWN)
         wined3d_desc.backbuffer_format = wined3dformat_from_dxgi_format(format);
+    wined3d_desc.flags = wined3d_swapchain_flags_from_dxgi(flags);
     hr = wined3d_swapchain_resize_buffers(swapchain->wined3d_swapchain, buffer_count, width, height,
-            wined3d_desc.backbuffer_format, wined3d_desc.multisample_type, wined3d_desc.multisample_quality);
+            wined3d_desc.backbuffer_format, wined3d_desc.multisample_type,
+            wined3d_desc.multisample_quality, wined3d_desc.flags);
     /* wined3d_swapchain_resize_buffers() may recreate swapchain textures.
      * We do not need to remove the reference to the wined3d swapchain from the
      * old d3d11 textures: we just validated above that they have 0 references,
@@ -2600,13 +2611,18 @@ static HRESULT d3d12_swapchain_op_resize_buffers_execute(struct d3d12_swapchain
 static HRESULT d3d12_swapchain_resize_buffers(struct d3d12_swapchain *swapchain,
         UINT buffer_count, UINT width, UINT height, DXGI_FORMAT format, UINT flags)
 {
+    static const UINT supported_flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+            | DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
     DXGI_SWAP_CHAIN_DESC1 *desc, new_desc;
     struct d3d12_swapchain_op *op;
     unsigned int i;
     ULONG refcount;
 
-    if (flags)
-        FIXME("Ignoring flags %#x.\n", flags);
+    if (flags & ~supported_flags)
+        FIXME("Ignoring flags %#x.\n", flags & ~supported_flags);
+
+    if ((swapchain->desc.Flags ^ flags) & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
+        return E_INVALIDARG;
 
     for (i = 0; i < swapchain->desc.BufferCount; ++i)
     {
@@ -2620,6 +2636,7 @@ static HRESULT d3d12_swapchain_resize_buffers(struct d3d12_swapchain *swapchain,
 
     desc = &swapchain->desc;
     new_desc = swapchain->desc;
+    new_desc.Flags = flags;
 
     if (buffer_count)
         new_desc.BufferCount = buffer_count;
@@ -2651,6 +2668,9 @@ static HRESULT d3d12_swapchain_resize_buffers(struct d3d12_swapchain *swapchain,
             && desc->Format == new_desc.Format && desc->BufferCount == new_desc.BufferCount)
     {
         swapchain->current_buffer_index = 0;
+        /* DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE is not applicable on D3D12. So there is no need to
+         * recreate buffers when the flag gets toggled */
+        swapchain->desc.Flags = flags;
         return S_OK;
     }
 
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index 518fe47cbd8b..59ed17f00a2d 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -894,6 +894,19 @@ static BOOL dxgi_1_4_supported(IUnknown *device, BOOL is_d3d12)
     return SUCCEEDED(hr);
 }
 
+static BOOL dxgi_1_5_supported(IUnknown *device, BOOL is_d3d12)
+{
+    IDXGIFactory5 *factory5;
+    IDXGIFactory *factory;
+    HRESULT hr;
+
+    get_factory(device, is_d3d12, &factory);
+    if (SUCCEEDED(hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory5, (void **)&factory5)))
+        IDXGIFactory5_Release(factory5);
+    IDXGIFactory_Release(factory);
+    return SUCCEEDED(hr);
+}
+
 #define get_adapter(a, b) get_adapter_(__LINE__, a, b)
 static IDXGIAdapter *get_adapter_(unsigned int line, IUnknown *device, BOOL is_d3d12)
 {
@@ -1151,6 +1164,40 @@ static void test_adapter_luid(void)
     ok(!refcount, "Factory has %lu references left.\n", refcount);
 }
 
+static void test_enum_warp_adapter(void)
+{
+    DXGI_ADAPTER_DESC1 desc;
+    IDXGIFactory4 *factory4;
+    IDXGIAdapter1 *adapter;
+    ULONG refcount;
+    HRESULT hr;
+
+    if (!pCreateDXGIFactory2
+            || FAILED(hr = pCreateDXGIFactory2(0, &IID_IDXGIFactory4, (void **)&factory4)))
+    {
+        skip("DXGI 1.4 is not available.\n");
+        return;
+    }
+
+    hr = IDXGIFactory4_EnumWarpAdapter(factory4, &IID_IDXGIAdapter1, NULL);
+    ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
+
+    hr = IDXGIFactory4_EnumWarpAdapter(factory4, &IID_IDXGIAdapter1, (void **)&adapter);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    hr = IDXGIAdapter1_GetDesc1(adapter, &desc);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    todo_wine ok(desc.Flags == DXGI_ADAPTER_FLAG_SOFTWARE,
+            "Got unexpected flags %#x.\n", desc.Flags);
+    todo_wine ok(desc.VendorId == 0x1414, "Got unexpected vendor ID %#x.\n", desc.VendorId);
+    todo_wine ok(desc.DeviceId == 0x008c, "Got unexpected device ID %#x.\n", desc.DeviceId);
+
+    refcount = IDXGIAdapter1_Release(adapter);
+    ok(!refcount, "Adapter has %lu references left.\n", refcount);
+    refcount = IDXGIFactory4_Release(factory4);
+    ok(!refcount, "Factory has %lu references left.\n", refcount);
+}
+
 static void test_query_video_memory_info(void)
 {
     DXGI_QUERY_VIDEO_MEMORY_INFO memory_info;
@@ -4387,22 +4434,24 @@ static void check_resource_desc_(unsigned int line, ID3D12Resource *resource,
 
 static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12)
 {
+    IDXGISwapChain3 *swapchain3 = NULL, *tmp_swapchain3;
+    IDXGISwapChain *swapchain, *tmp_swapchain;
     DXGI_SWAP_CHAIN_DESC swapchain_desc;
+    BOOL ret, is_dxgi_1_5_supported;
     DXGI_SWAP_EFFECT swap_effect;
     IDXGIResource *dxgi_resource;
-    IDXGISwapChain3 *swapchain3;
     IUnknown *present_queue[2];
-    IDXGISwapChain *swapchain;
     ID3D12Resource *resource;
     ID3D10Texture2D *texture;
     HRESULT hr, expected_hr;
+    IDXGISurface1 *surface1;
     IDXGISurface *surface;
     IDXGIFactory *factory;
     RECT client_rect, r;
     UINT node_mask[2];
     ULONG refcount;
     HWND window;
-    BOOL ret;
+    HDC hdc;
 
     get_factory(device, is_d3d12, &factory);
 
@@ -4689,7 +4738,6 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12)
         hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240,
                 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
         todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
-        IDXGISwapChain3_Release(swapchain3);
     }
     else
     {
@@ -4714,10 +4762,312 @@ static void test_swapchain_resize(IUnknown *device, BOOL is_d3d12)
         hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 0, 320, 240,
                 DXGI_FORMAT_B8G8R8A8_UNORM, 0, node_mask, present_queue);
         ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
+    }
+
+    /* Test ResizeBuffers() flags */
+    is_dxgi_1_5_supported = dxgi_1_5_supported(device, is_d3d12);
+    for (unsigned int flag = DXGI_SWAP_CHAIN_FLAG_NONPREROTATED;
+            flag <= DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS; flag <<= 1)
+    {
+        /* DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED can't be turned off. Test it in a separate test */
+        if (flag == DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED)
+            continue;
+
+        if (!is_dxgi_1_5_supported & (flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING
+                || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS))
+            continue;
+
+        winetest_push_context("flag %#x", flag);
+
+        hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, flag);
+        if (flag == DXGI_SWAP_CHAIN_FLAG_NONPREROTATED
+                || flag == DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY
+                || flag == DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO)
+        {
+            todo_wine
+            ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
+        }
+        else if (flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
+                || flag == DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER
+                || flag == DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO
+                || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
+        {
+            todo_wine_if(flag != DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
+            ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
+        }
+        else
+        {
+            ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+            hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+            ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+            todo_wine_if(!is_d3d12 && !(flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+                    || flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE))
+            ok(swapchain_desc.Flags == flag, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+        }
+
+        /* If a flag is allowed at swapchain creation, then it must be allowed in ResizeBuffers() */
+        swapchain_desc.Flags = flag;
+        swapchain_desc.OutputWindow = create_window();
+        if (flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
+                || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
+            swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+        else
+            swapchain_desc.SwapEffect = swap_effect;
+        hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &tmp_swapchain);
+        if ((is_d3d12 && (flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE
+                || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT
+                || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER))
+                || flag == DXGI_SWAP_CHAIN_FLAG_NONPREROTATED
+                || flag == DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY
+                || flag == DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER
+                || flag == DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO
+                || flag == DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO)
+        {
+            todo_wine
+            ok(hr == DXGI_ERROR_INVALID_CALL, "Creating a swapchain with flag %#x succeeded.\n", flag);
+            if (hr == S_OK)
+                IDXGISwapChain_Release(tmp_swapchain);
+            DestroyWindow(swapchain_desc.OutputWindow);
+            winetest_pop_context();
+            continue;
+        }
+        else
+        {
+            ok(hr == S_OK, "Failed to create swapchain, hr %#lx.\n", hr);
+        }
+
+        hr = IDXGISwapChain_GetDesc(tmp_swapchain, &swapchain_desc);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        todo_wine_if(!is_d3d12 && !(flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE
+                || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+                || flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+        ok(swapchain_desc.Flags == flag, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+        /* Test turning on the flag used at swapchain creation */
+        hr = IDXGISwapChain_ResizeBuffers(tmp_swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, flag);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        /* Test turning off the flag used at swapchain creation */
+        hr = IDXGISwapChain_ResizeBuffers(tmp_swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
+        if ((!is_d3d12 && (flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE
+                || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT
+                || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER))
+                || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+                || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS)
+            ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        else
+            todo_wine_if(flag != DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
+            ok(hr == DXGI_ERROR_INVALID_CALL || hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
+        IDXGISwapChain_Release(tmp_swapchain);
+        DestroyWindow(swapchain_desc.OutputWindow);
+
+        winetest_pop_context();
+    }
+
+    hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!swapchain_desc.Flags, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+
+    /* Test ResizeBuffers1() flags */
+    if (swapchain3)
+    {
+        node_mask[0] = 1;
+        node_mask[1] = 1;
+        present_queue[0] = device;
+        present_queue[1] = device;
+
+        for (unsigned int flag = DXGI_SWAP_CHAIN_FLAG_NONPREROTATED;
+                flag <= DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS; flag <<= 1)
+        {
+            /* DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED can't be turned off. Test it in a separate test */
+            if (flag == DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED)
+                continue;
+
+            if (!is_dxgi_1_5_supported & (flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING
+                    || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS))
+                continue;
+
+            winetest_push_context("flag %#x", flag);
+
+            hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM,
+                    flag, node_mask, present_queue);
+            if (is_d3d12)
+            {
+                if (flag == DXGI_SWAP_CHAIN_FLAG_NONPREROTATED
+                        || flag == DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY
+                        || flag == DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO)
+                {
+                    todo_wine
+                    ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
+                }
+                else if (flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
+                        || flag == DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER
+                        || flag == DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO
+                        || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
+                {
+                    todo_wine_if(flag != DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT)
+                    ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
+                }
+                else
+                {
+                    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+                    hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+                    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+                    ok(swapchain_desc.Flags == flag, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+                }
+            }
+            else
+            {
+                if (flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
+                        || flag == DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER
+                        || flag == DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO
+                        || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
+                    todo_wine
+                    ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
+                else
+                    todo_wine
+                    ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
+            }
+
+            /* If a flag is allowed at swapchain creation, then it must be allowed in ResizeBuffers1() */
+            swapchain_desc.Flags = flag;
+            swapchain_desc.OutputWindow = create_window();
+            if (flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT
+                    || flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING)
+                swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
+            else
+                swapchain_desc.SwapEffect = swap_effect;
+            hr = IDXGIFactory_CreateSwapChain(factory, device, &swapchain_desc, &tmp_swapchain);
+            if ((is_d3d12 && (flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE
+                    || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_CONTENT
+                    || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICT_SHARED_RESOURCE_DRIVER))
+                    || flag == DXGI_SWAP_CHAIN_FLAG_NONPREROTATED
+                    || flag == DXGI_SWAP_CHAIN_FLAG_DISPLAY_ONLY
+                    || flag == DXGI_SWAP_CHAIN_FLAG_FOREGROUND_LAYER
+                    || flag == DXGI_SWAP_CHAIN_FLAG_FULLSCREEN_VIDEO
+                    || flag == DXGI_SWAP_CHAIN_FLAG_YUV_VIDEO)
+            {
+                todo_wine
+                ok(hr == DXGI_ERROR_INVALID_CALL, "Creating a swapchain with flag %#x succeeded.\n", flag);
+                if (hr == S_OK)
+                    IDXGISwapChain_Release(tmp_swapchain);
+                DestroyWindow(swapchain_desc.OutputWindow);
+                winetest_pop_context();
+                continue;
+            }
+            else
+            {
+                ok(hr == S_OK, "Failed to create swapchain, hr %#lx.\n", hr);
+            }
+
+            hr = IDXGISwapChain_QueryInterface(tmp_swapchain, &IID_IDXGISwapChain3, (void **)&tmp_swapchain3);
+            ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+            hr = IDXGISwapChain_GetDesc(tmp_swapchain, &swapchain_desc);
+            ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+            todo_wine_if(!is_d3d12 && !(flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+                    || flag == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE
+                    || flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+            ok(swapchain_desc.Flags == flag, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+            /* Test turning on the flag used at swapchain creation */
+            hr = IDXGISwapChain3_ResizeBuffers1(tmp_swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM,
+                    flag, node_mask, present_queue);
+            todo_wine_if(!is_d3d12)
+            ok(hr == (is_d3d12 ? S_OK : DXGI_ERROR_INVALID_CALL), "Got unexpected hr %#lx.\n", hr);
+            /* Test turning off the flag used at swapchain creation */
+            hr = IDXGISwapChain3_ResizeBuffers1(tmp_swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM,
+                    0, node_mask, present_queue);
+            if (is_d3d12 && (flag == DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH
+                    || flag == DXGI_SWAP_CHAIN_FLAG_RESTRICTED_TO_ALL_HOLOGRAPHIC_DISPLAYS))
+                ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+            else
+                todo_wine_if(!(is_d3d12 && flag == DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT))
+                ok(hr == DXGI_ERROR_INVALID_CALL || hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
+            IDXGISwapChain3_Release(tmp_swapchain3);
+            IDXGISwapChain_Release(tmp_swapchain);
+            DestroyWindow(swapchain_desc.OutputWindow);
+
+            winetest_pop_context();
+        }
+
+        hr = IDXGISwapChain3_ResizeBuffers1(swapchain3, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0,
+                node_mask, present_queue);
+        todo_wine_if(!is_d3d12)
+        ok(hr == (is_d3d12 ? S_OK : DXGI_ERROR_INVALID_CALL), "Got unexpected hr %#lx.\n", hr);
+        hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        ok(!swapchain_desc.Flags, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+
         IDXGISwapChain3_Release(swapchain3);
     }
 
     IDXGISwapChain_Release(swapchain);
+
+    /* Test DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE */
+    swapchain = create_swapchain(device, is_d3d12, window, 0, swap_effect);
+
+    hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM,
+            DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(swapchain_desc.Flags == DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE, "Got unexpected Flags %#x.\n",
+            swapchain_desc.Flags);
+    hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface1);
+    if (hr == S_OK)
+    {
+        hr = IDXGISurface1_GetDC(surface1, FALSE, &hdc);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        IDXGISurface1_ReleaseDC(surface1, NULL);
+        IDXGISurface1_Release(surface1);
+    }
+
+    hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+    ok(!swapchain_desc.Flags, "Got unexpected Flags %#x.\n", swapchain_desc.Flags);
+    hr = IDXGISwapChain_GetBuffer(swapchain, 0, &IID_IDXGISurface1, (void **)&surface1);
+    if (hr == S_OK)
+    {
+        hr = IDXGISurface1_GetDC(surface1, FALSE, &hdc);
+        todo_wine_if(hr == 0x8876086c)
+        ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
+        IDXGISurface1_Release(surface1);
+    }
+
+    IDXGISwapChain_Release(swapchain);
+
+    /* Test DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED */
+    if (dxgi_1_4_supported(device, is_d3d12))
+    {
+        swapchain = create_swapchain(device, is_d3d12, window, 0, swap_effect);
+
+        hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM,
+                DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        todo_wine_if(!is_d3d12)
+        ok(swapchain_desc.Flags == DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED, "Got unexpected Flags %#x.\n",
+                swapchain_desc.Flags);
+        /* Note that MSDN says that DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED can only be used with
+         * DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL. Apparently that is not the case */
+        ok(swapchain_desc.SwapEffect == swap_effect, "Got unexpected SwapEffect %#x.\n",
+                swapchain_desc.SwapEffect);
+
+        /* DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED can't be turned off once it's turned on */
+        hr = IDXGISwapChain_ResizeBuffers(swapchain, 2, 320, 240, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
+        todo_wine
+        ok(hr == E_INVALIDARG, "Got unexpected hr %#lx.\n", hr);
+        hr = IDXGISwapChain_GetDesc(swapchain, &swapchain_desc);
+        ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+        todo_wine
+        ok(swapchain_desc.Flags == DXGI_SWAP_CHAIN_FLAG_HW_PROTECTED, "Got unexpected Flags %#x.\n",
+                swapchain_desc.Flags);
+
+        IDXGISwapChain_Release(swapchain);
+    }
+
     DestroyWindow(window);
     refcount = IDXGIFactory_Release(factory);
     ok(refcount == !is_d3d12, "Got unexpected refcount %lu.\n", refcount);
@@ -8723,6 +9073,7 @@ START_TEST(dxgi)
 
     queue_test(test_adapter_desc);
     queue_test(test_adapter_luid);
+    queue_test(test_enum_warp_adapter);
     queue_test(test_query_video_memory_info);
     queue_test(test_check_interface_support);
     queue_test(test_create_surface);
diff --git a/dlls/dxgi/utils.c b/dlls/dxgi/utils.c
index 3e07f27ff0ab..84402864e7be 100644
--- a/dlls/dxgi/utils.c
+++ b/dlls/dxgi/utils.c
@@ -540,13 +540,19 @@ unsigned int dxgi_swapchain_flags_from_wined3d(unsigned int wined3d_flags)
         flags |= DXGI_SWAP_CHAIN_FLAG_GDI_COMPATIBLE;
     }
 
+    if (wined3d_flags & WINED3D_SWAPCHAIN_FRAME_LATENCY_WAITABLE_OBJECT)
+    {
+        wined3d_flags &= ~WINED3D_SWAPCHAIN_FRAME_LATENCY_WAITABLE_OBJECT;
+        flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT;
+    }
+
     if (wined3d_flags)
         FIXME("Unhandled flags %#x.\n", flags);
 
     return flags;
 }
 
-static unsigned int wined3d_swapchain_flags_from_dxgi(unsigned int flags)
+unsigned int wined3d_swapchain_flags_from_dxgi(unsigned int flags)
 {
     unsigned int wined3d_flags = DXGI_WINED3D_SWAPCHAIN_FLAGS; /* WINED3D_SWAPCHAIN_DISCARD_DEPTHSTENCIL? */
 
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 0faac1325d26..2c951227046c 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -3303,7 +3303,7 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
             RECT dst_area;
             GpRectF graphics_bounds;
             GpRect src_area;
-            int i, x, y, src_stride, dst_stride;
+            int i, x, y, src_stride, dst_stride, dst_width, dst_height;
             LPBYTE src_data, dst_data, dst_dyn_data=NULL;
             BitmapData lockeddata;
             InterpolationMode interpolation = graphics->interpolation;
@@ -3351,6 +3351,10 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
 
             TRACE("src_area: %d x %d\n", src_area.Width, src_area.Height);
 
+            if (src_area.Width <= 0 || src_area.Height <= 0 ||
+                src_area.Width > INT_MAX / src_area.Height)
+                return InvalidParameter;
+
             src_data = calloc(src_area.Width * src_area.Height, sizeof(ARGB));
             if (!src_data)
                 return OutOfMemory;
@@ -3413,7 +3417,15 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
                 y_dy = dst_to_src.matrix[3];
 
                 /* Transform the bits as needed to the destination. */
-                dst_data = dst_dyn_data = calloc((dst_area.right - dst_area.left) * (dst_area.bottom - dst_area.top), sizeof(ARGB));
+                dst_width = dst_area.right - dst_area.left;
+                dst_height = dst_area.bottom - dst_area.top;
+                if (dst_width <= 0 || dst_height <= 0 ||
+                    dst_width > INT_MAX / dst_height)
+                {
+                    free(src_data);
+                    return InvalidParameter;
+                }
+                dst_data = dst_dyn_data = calloc(dst_width * dst_height, sizeof(ARGB));
                 if (!dst_data)
                 {
                     free(src_data);
@@ -5803,7 +5815,7 @@ GpStatus gdip_format_string(GpGraphics *graphics, HDC hdc,
                break;
             }
 
-            if(*(stringdup + sum + lret) == '\r' && lret + 1 < fit
+            if(*(stringdup + sum + lret) == '\r' && sum + lret + 1 < length
                && *(stringdup + sum + lret + 1) == '\n')
             {
                unixstyle_newline = FALSE;
@@ -5811,6 +5823,30 @@ GpStatus gdip_format_string(GpGraphics *graphics, HDC hdc,
             }
         }
 
+        /* If no newline found within fit, check position fit for \n or \r\n.
+         * Wine's GetTextExtentExPointW may assign non-zero advance width to
+         * newline characters (rendering them as missing-glyph boxes), causing
+         * them to be excluded from the fit count. When this happens, the
+         * newline is invisible to the scan above, leading to incorrect line
+         * breaking under StringFormatFlagsNoWrap. */
+        if (lret == fit && sum + fit < length)
+        {
+            if (*(stringdup + sum + fit) == '\n')
+            {
+                unixstyle_newline = TRUE;
+                fitcpy = fit + 1;
+                fit++;
+            }
+            else if (sum + fit + 1 < length &&
+                     *(stringdup + sum + fit) == '\r' &&
+                     *(stringdup + sum + fit + 1) == '\n')
+            {
+                unixstyle_newline = FALSE;
+                fitcpy = fit + 2;
+                fit += 2;
+            }
+        }
+
         /* Line break code (may look strange, but it imitates windows). */
         if(lret < fit)
             lineend = fit = lret;    /* this is not an off-by-one error */
diff --git a/dlls/gdiplus/tests/graphics.c b/dlls/gdiplus/tests/graphics.c
index 8703081070fe..145cacf8148b 100644
--- a/dlls/gdiplus/tests/graphics.c
+++ b/dlls/gdiplus/tests/graphics.c
@@ -3407,7 +3407,7 @@ static void test_string_functions(void)
     expectf(0.0, bounds.X);
     expectf(0.0, bounds.Y);
     todo_wine expect(5, codepointsfitted);
-    todo_wine expect(1, linesfilled);
+    expect(1, linesfilled);
 
     /* Cut off everything after the first space. */
     rc.Width = char_bounds.Width + char_width * 2.1;
@@ -3443,7 +3443,7 @@ static void test_string_functions(void)
     expectf_(char_bounds.Width, bounds.Width, 0.01);
     expectf_(char_bounds.Height + char_height * 3, bounds.Height, 0.05);
     expect(6, codepointsfitted);
-    todo_wine expect(4, linesfilled);
+    expect(4, linesfilled);
 
     for (i = 0; i < 4; i++)
         regions[i] = (GpRegion *)0xdeadbeef;
diff --git a/dlls/ieframe/dochost.c b/dlls/ieframe/dochost.c
index add816fe97e2..b603d24aa6e9 100644
--- a/dlls/ieframe/dochost.c
+++ b/dlls/ieframe/dochost.c
@@ -22,6 +22,7 @@
 
 #include "exdispid.h"
 #include "mshtml.h"
+#include "mshtmdid.h"
 #include "perhist.h"
 #include "initguid.h"
 
@@ -82,6 +83,40 @@ void abort_dochost_tasks(DocHost *This, task_proc_t proc)
     }
 }
 
+static BOOL fire_titlechange(DocHost *This)
+{
+    IHTMLDocument2 *doc;
+    BSTR title = NULL;
+    DISPPARAMS dp = { NULL, NULL, 0, 0 };
+    HRESULT hres;
+    BOOL has_title = FALSE;
+    VARIANTARG arg;
+
+    if(!This->document)
+        return FALSE;
+
+    hres = IUnknown_QueryInterface(This->document, &IID_IHTMLDocument2, (void **)&doc);
+    if(FAILED(hres))
+        return FALSE;
+
+    hres = IHTMLDocument2_get_title(doc, &title);
+    IHTMLDocument2_Release(doc);
+    if(FAILED(hres) || !title)
+        return FALSE;
+
+    has_title = *title != 0;
+
+    VariantInit(&arg);
+    V_VT(&arg) = VT_BSTR;
+    V_BSTR(&arg) = title;
+    dp.rgvarg = &arg;
+    dp.cArgs = 1;
+    call_sink(This->cps.wbe2, DISPID_TITLECHANGE, &dp);
+    VariantClear(&arg);
+
+    return has_title;
+}
+
 void on_commandstate_change(DocHost *doc_host, LONG command, BOOL enable)
 {
     DISPPARAMS dispparams;
@@ -708,6 +743,10 @@ static HRESULT WINAPI ClOleCommandTarget_Exec(IOleCommandTarget *iface,
             if(!This->olecmd)
                 return E_NOTIMPL;
             return IOleCommandTarget_Exec(This->olecmd, pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+        case OLECMDID_SETTITLE:
+            if(fire_titlechange(This) && This->olecmd)
+                return IOleCommandTarget_Exec(This->olecmd, pguidCmdGroup, nCmdID, nCmdexecopt, pvaIn, pvaOut);
+            return S_OK;
         case OLECMDID_SETDOWNLOADSTATE:
             if(pvaIn && V_VT(pvaIn) == VT_I4)
                 This->busy = V_I4(pvaIn) ? VARIANT_TRUE : VARIANT_FALSE;
@@ -1109,6 +1148,9 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D
         update_ready_state(This, ready_state);
         break;
     }
+    case DISPID_IHTMLDOCUMENT2_TITLE:
+        fire_titlechange(This);
+        break;
     default:
         FIXME("unimplemented dispid %ld\n", dispID);
         return E_NOTIMPL;
diff --git a/dlls/ieframe/tests/webbrowser.c b/dlls/ieframe/tests/webbrowser.c
index 8c514a6ffc2f..2cd8491d5f6f 100644
--- a/dlls/ieframe/tests/webbrowser.c
+++ b/dlls/ieframe/tests/webbrowser.c
@@ -1010,7 +1010,10 @@ static HRESULT WINAPI WebBrowserEvents2_Invoke(IDispatch *iface, DISPID dispIdMe
 
     case DISPID_TITLECHANGE:
         CHECK_EXPECT2(Invoke_TITLECHANGE);
-        /* FIXME */
+        ok(pDispParams->rgvarg != NULL, "rgvarg == NULL\n");
+        ok(pDispParams->cArgs == 1, "cArgs=%d, expected 1\n", pDispParams->cArgs);
+        ok(V_VT(pDispParams->rgvarg) == VT_BSTR, "V_VT(pDispParams->rgvarg)=%d, expected VT_BSTR\n",
+           V_VT(pDispParams->rgvarg));
         break;
 
     case DISPID_NAVIGATECOMPLETE2:
@@ -3128,7 +3131,7 @@ static void test_download(DWORD flags)
         CHECK_CALLED(Exec_SETDOWNLOADSTATE_0);
     else
         CHECK_CALLED(Invoke_DOWNLOADCOMPLETE);
-    todo_wine CHECK_CALLED(Invoke_TITLECHANGE);
+    CHECK_CALLED(Invoke_TITLECHANGE);
     if(!(flags & DWL_REFRESH))
         CHECK_CALLED(Invoke_NAVIGATECOMPLETE2);
     if(is_first_load)
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 2427129d093b..dd76c1664b08 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -5806,6 +5806,16 @@ static void test_GetFinalPathNameByHandleW(void)
     wcscpy(test_path, temp_path);
     wcscat(test_path, L"link");
     success = CreateSymbolicLinkW(test_path, temp_path, SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE);
+    if (!success && GetLastError() == ERROR_PRIVILEGE_NOT_HELD)
+    {
+        win_skip("Insufficient permissions to perform symlink tests.\n");
+        return;
+    }
+    if (!success && GetLastError() == ERROR_INVALID_PARAMETER /* <= Win10v1607 */)
+    {
+        win_skip("Flag SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE not supported, skipping test.\n");
+        return;
+    }
     ok(success, "got error %ld.\n", GetLastError());
 
     wcscpy(test_path, temp_path);
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c
index 4dcff7ef8cc9..c65280332431 100644
--- a/dlls/mf/tests/transform.c
+++ b/dlls/mf/tests/transform.c
@@ -7370,7 +7370,6 @@ static void test_wmv_decoder(BOOL use_2d_buffer)
             .output_sample_desc = &output_sample_desc_rgb,
             .result_bitmap = use_2d_buffer ? L"rgb32frame.bmp" : L"rgb32frame-flip.bmp",
             .delta = 5,
-            .todo = use_2d_buffer,
         },
 
         {
@@ -7393,7 +7392,6 @@ static void test_wmv_decoder(BOOL use_2d_buffer)
             .output_sample_desc = &output_sample_desc_rgb,
             .result_bitmap = use_2d_buffer ? L"rgb32frame.bmp" : L"rgb32frame-flip.bmp",
             .delta = 5,
-            .todo = use_2d_buffer,
         },
 
         {
@@ -7417,7 +7415,6 @@ static void test_wmv_decoder(BOOL use_2d_buffer)
             .output_sample_desc = &output_sample_desc_rgb,
             .result_bitmap = use_2d_buffer ? L"rgb32frame-flip.bmp" : L"rgb32frame.bmp",
             .delta = 5,
-            .todo = use_2d_buffer,
         },
 
         {
diff --git a/dlls/mscoree/config.c b/dlls/mscoree/config.c
index 770facf93efc..0fc7443b4af3 100644
--- a/dlls/mscoree/config.c
+++ b/dlls/mscoree/config.c
@@ -376,6 +376,7 @@ static HRESULT parse_supported_runtime(ConfigFileHandler *This, ISAXAttributes *
         entry = malloc(sizeof(supported_runtime));
         if (entry)
         {
+            entry->sku = NULL;
             entry->version = wcsdup(value);
             if (entry->version)
             {
@@ -397,8 +398,14 @@ static HRESULT parse_supported_runtime(ConfigFileHandler *This, ISAXAttributes *
     {
         hr = ISAXAttributes_getValueFromName(pAttr, empty, 0, sku, lstrlenW(sku), &value, &value_size);
         if (SUCCEEDED(hr))
-            FIXME("sku=%s not implemented\n", debugstr_wn(value, value_size));
-        hr = S_OK;
+        {
+            TRACE("sku=%s\n", debugstr_wn(value, value_size));
+            entry->sku = wcsdup(value);
+            if (!entry->sku)
+                hr = E_OUTOFMEMORY;
+        }
+        else
+            hr = S_OK;
     }
 
     return hr;
@@ -700,6 +707,7 @@ void free_parsed_config_file(parsed_config_file *file)
     LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, &file->supported_runtimes, supported_runtime, entry)
     {
         free(cursor->version);
+        free(cursor->sku);
         list_remove(&cursor->entry);
         free(cursor);
     }
diff --git a/dlls/mscoree/metahost.c b/dlls/mscoree/metahost.c
index eb609fccc29d..262a9851c698 100644
--- a/dlls/mscoree/metahost.c
+++ b/dlls/mscoree/metahost.c
@@ -710,11 +710,13 @@ HRESULT ICLRRuntimeInfo_GetRuntimeHost(ICLRRuntimeInfo *iface, RuntimeHost **res
 }
 
 #ifdef __i386__
-static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','.','d','l','l',0};
+static const WCHAR libmono2_arch_dll[] = L"\\bin\\libmono-2.0-x86.dll";
 #elif defined(__x86_64__)
-static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','-','x','8','6','_','6','4','.','d','l','l',0};
+static const WCHAR libmono2_arch_dll[] = L"\\bin\\libmono-2.0-x86_64.dll";
+#elif defined(__aarch64__)
+static const WCHAR libmono2_arch_dll[] = L"\\bin\\libmono-2.0-arm64.dll";
 #else
-static const WCHAR libmono2_arch_dll[] = {'\\','b','i','n','\\','l','i','b','m','o','n','o','-','2','.','0','.','d','l','l',0};
+static const WCHAR libmono2_arch_dll[] = L"\\bin\\libmono-2.0.dll";
 #endif
 
 static BOOL find_mono_dll(LPCWSTR path, LPWSTR dll_path)
diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h
index 2b761c2b2dbc..2bb15947001c 100644
--- a/dlls/mscoree/mscoree_private.h
+++ b/dlls/mscoree/mscoree_private.h
@@ -124,6 +124,7 @@ typedef struct supported_runtime
 {
     struct list entry;
     LPWSTR version;
+    LPWSTR sku;
 } supported_runtime;
 
 extern WCHAR **private_path;
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c
index ef964297404f..f3dee79e997d 100644
--- a/dlls/mshtml/htmldoc.c
+++ b/dlls/mshtml/htmldoc.c
@@ -649,6 +649,11 @@ static HRESULT WINAPI HTMLDocument_put_title(IHTMLDocument2 *iface, BSTR v)
     if(NS_FAILED(nsres))
         ERR("SetTitle failed: %08lx\n", nsres);
 
+    if(This->doc_obj)
+        call_property_onchanged(&This->doc_obj->cp_container, DISPID_IHTMLDOCUMENT2_TITLE);
+    else
+        call_property_onchanged(&This->cp_container, DISPID_IHTMLDOCUMENT2_TITLE);
+
     return S_OK;
 }
 
diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c
index 43451cdba6a0..c0b80c83ce95 100644
--- a/dlls/mshtml/tests/events.c
+++ b/dlls/mshtml/tests/events.c
@@ -127,6 +127,7 @@ DEFINE_EXPECT(QS_GetCaller);
 DEFINE_EXPECT(QS_GetCaller_parent2);
 DEFINE_EXPECT(QS_GetCaller_parent3);
 DEFINE_EXPECT(cmdtarget_Exec);
+DEFINE_EXPECT(OnChanged_title);
 
 static HWND container_hwnd = NULL;
 static IHTMLWindow2 *window;
@@ -4656,6 +4657,26 @@ static void test_create_event(IHTMLDocument2 *doc)
     IDocumentEvent_Release(doc_event);
 }
 
+static void test_doc_title_notify(IHTMLDocument2 *doc)
+{
+    BSTR title = NULL, tmp;
+    HRESULT hres;
+
+    trace("doc title notify tests...\n");
+
+    SET_EXPECT(OnChanged_title);
+    tmp = SysAllocString(L"wine title notify test");
+    hres = IHTMLDocument2_put_title(doc, tmp);
+    ok(hres == S_OK, "put_title failed: %08lx\n", hres);
+    SysFreeString(tmp);
+    CHECK_CALLED(OnChanged_title);
+
+    hres = IHTMLDocument2_get_title(doc, &title);
+    ok(hres == S_OK, "get_title failed: %08lx\n", hres);
+    ok(!lstrcmpW(title, L"wine title notify test"), "unexpected title %s\n", wine_dbgstr_w(title));
+    SysFreeString(title);
+}
+
 static unsigned onstorage_expect_line;
 static const WCHAR *onstorage_expect_key, *onstorage_expect_old_value, *onstorage_expect_new_value;
 
@@ -6473,6 +6494,9 @@ static HRESULT WINAPI PropertyNotifySink_OnChanged(IPropertyNotifySink *iface, D
             nav_notif_test();
     }
 
+    if(dispID == DISPID_IHTMLDOCUMENT2_TITLE)
+        CHECK_EXPECT(OnChanged_title);
+
     return S_OK;
 }
 
@@ -7779,6 +7803,7 @@ START_TEST(events)
         run_test(empty_doc_ie9_str, test_submit);
         run_test(iframe_doc_str, test_message_event);
         run_test(iframe_doc_str, test_iframe_connections);
+        run_test(empty_doc_str, test_doc_title_notify);
         if(is_ie9plus) {
             run_test_from_res(L"doc_with_prop.html", test_doc_obj);
             run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj);
diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c
index e5850ecf0309..a095a4f8b0a8 100644
--- a/dlls/msvcrt/file.c
+++ b/dlls/msvcrt/file.c
@@ -2485,7 +2485,7 @@ int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pm
   sa.lpSecurityDescriptor = NULL;
   sa.bInheritHandle       = !(oflags & _O_NOINHERIT);
 
-  if ((oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
+  if (!(oflags & _O_BINARY) && (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
           && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
           && !(access&GENERIC_READ))
   {
@@ -2505,7 +2505,7 @@ int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pm
     return *_errno();
   }
 
-  if (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
+  if (!(oflags & _O_BINARY) && oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
   {
       LARGE_INTEGER size = {{0}};
 
@@ -2561,13 +2561,16 @@ int CDECL _wsopen_dispatch( const wchar_t* path, int oflags, int shflags, int pm
   if (*fd == -1)
       return *_errno();
 
-  if (oflags & _O_WTEXT)
-      ioinfo_set_unicode(get_ioinfo_nolock(*fd), TRUE);
+  if (!(oflags & _O_BINARY))
+  {
+      if (oflags & _O_WTEXT)
+          ioinfo_set_unicode(get_ioinfo_nolock(*fd), TRUE);
 
-  if (oflags & _O_U16TEXT)
-      ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF16LE);
-  else if (oflags & _O_U8TEXT)
-      ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF8);
+      if (oflags & _O_U16TEXT)
+          ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF16LE);
+      else if (oflags & _O_U8TEXT)
+          ioinfo_set_textmode(get_ioinfo_nolock(*fd), TEXTMODE_UTF8);
+  }
 
   TRACE(":fd (%d) handle (%p)\n", *fd, hand);
   return 0;
diff --git a/dlls/msvcrt/heap.c b/dlls/msvcrt/heap.c
index 70e4ecb815c6..63c5a7cb132e 100644
--- a/dlls/msvcrt/heap.c
+++ b/dlls/msvcrt/heap.c
@@ -33,7 +33,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
 #define UNLOCK_HEAP _unlock( _HEAP_LOCK )
 
 /* _aligned */
-#define SAVED_PTR(x) ((void *)((DWORD_PTR)((char *)x - sizeof(void *)) & \
+#define SAVED_PTR(x) ((void **)((DWORD_PTR)((char *)x - sizeof(void *)) & \
                                ~(sizeof(void *) - 1)))
 #define ALIGN_PTR(ptr, alignment, offset) ((void *) \
     ((((DWORD_PTR)((char *)ptr + alignment + sizeof(void *) + offset)) & \
@@ -612,8 +612,9 @@ void * CDECL _aligned_malloc(size_t size, size_t alignment)
 void * CDECL _aligned_offset_realloc(void *memblock, size_t size,
                                      size_t alignment, size_t offset)
 {
-    void * temp, **saved;
+    void *temp, *alloc_ptr;
     size_t old_padding, new_padding, old_size;
+
     TRACE("(%p, %Iu, %Iu, %Iu)\n", memblock, size, alignment, offset);
 
     if (!memblock)
@@ -643,18 +644,11 @@ void * CDECL _aligned_offset_realloc(void *memblock, size_t size,
     if (alignment < sizeof(void *))
         alignment = sizeof(void *);
 
-    /* make sure alignment and offset didn't change */
-    saved = SAVED_PTR(memblock);
-    if (memblock != ALIGN_PTR(*saved, alignment, offset))
-    {
-        *_errno() = EINVAL;
-        return NULL;
-    }
-
-    old_padding = (char *)memblock - (char *)*saved;
+    alloc_ptr = *SAVED_PTR(memblock);
+    old_padding = (char *)memblock - (char *)alloc_ptr;
 
     /* Get previous size of block */
-    old_size = _msize(*saved);
+    old_size = _msize(alloc_ptr);
     if (old_size == -1)
     {
         /* It seems this function was called with an invalid pointer. Bail out. */
@@ -669,55 +663,34 @@ void * CDECL _aligned_offset_realloc(void *memblock, size_t size,
     }
     old_size -= old_padding;
 
-    temp = realloc(*saved, size + alignment + sizeof(void *));
+    /* Ensure data is preserved if padding block is shrinked */
+    if (alignment + sizeof(void *) < old_padding)
+    {
+        memmove(alloc_ptr, memblock, old_size);
+        old_padding = 0;
+    }
 
+    temp = realloc(alloc_ptr, size + alignment + sizeof(void *));
     if (!temp)
+    {
+        if (!old_padding)
+        {
+            memmove(memblock, alloc_ptr, old_size);
+            *SAVED_PTR(memblock) = alloc_ptr;
+        }
         return NULL;
+    }
 
     /* adjust pointer for proper alignment and offset */
     memblock = ALIGN_PTR(temp, alignment, offset);
-
-    /* Save the real allocation address below returned address */
-    /* so it can be found later to free. */
-    saved = SAVED_PTR(memblock);
-
     new_padding = (char *)memblock - (char *)temp;
-
-/*
-   Memory layout of old block is as follows:
-   +-------+---------------------+-+--------------------------+-----------+
-   |  ...  | "old_padding" bytes | | ... "old_size" bytes ... |    ...    |
-   +-------+---------------------+-+--------------------------+-----------+
-           ^                     ^ ^
-           |                     | |
-        *saved               saved memblock
-
-   Memory layout of new block is as follows:
-   +-------+-----------------------------+-+----------------------+-------+
-   |  ...  |    "new_padding" bytes      | | ... "size" bytes ... |  ...  |
-   +-------+-----------------------------+-+----------------------+-------+
-           ^                             ^ ^
-           |                             | |
-          temp                       saved memblock
-
-   However, in the new block, actual data is still written as follows
-   (because it was copied by realloc):
-   +-------+---------------------+--------------------------------+-------+
-   |  ...  | "old_padding" bytes |   ... "old_size" bytes ...     |  ...  |
-   +-------+---------------------+--------------------------------+-------+
-           ^                             ^ ^
-           |                             | |
-          temp                       saved memblock
-
-   Therefore, min(old_size,size) bytes of actual data have to be moved
-   from the offset they were at in the old block (temp + old_padding),
-   to the offset they have to be in the new block (temp + new_padding == memblock).
-*/
+    /* copy data to new location */
     if (new_padding != old_padding)
         memmove((char *)memblock, (char *)temp + old_padding, (old_size < size) ? old_size : size);
 
-    *saved = temp;
-
+    /* Save the real allocation address below returned address */
+    /* so it can be found later to free. */
+    *SAVED_PTR(memblock) = temp;
     return memblock;
 }
 
diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c
index 1cd3a5bffde8..4942780d425f 100644
--- a/dlls/msvcrt/tests/file.c
+++ b/dlls/msvcrt/tests/file.c
@@ -2174,6 +2174,14 @@ static void test_fopen_s( void )
             ubuff[0], ubuff[1]);
     fclose(file);
 
+    ret = p_fopen_s(&file, name, "rb,ccs=unicode");
+    ok(ret == 0, "fopen_s failed with %d\n", ret);
+    len = fread(buff, 1, 2, file);
+    ok(len == 2, "len = %d\n", len);
+    ok(ubuff[0]==0xff && ubuff[1]==0xfe, "buff[0]=%02x, buff[1]=%02x\n",
+            ubuff[0], ubuff[1]);
+    fclose(file);
+
     ret = p_fopen_s(&file, name, "r,ccs=utf-16le");
     ok(ret == 0, "fopen_s failed with %d\n", ret);
     len = fread(buff, 1, 2, file);
@@ -2215,6 +2223,20 @@ static void test_fopen_s( void )
             ubuff[0], ubuff[1], ubuff[2]);
     fclose(file);
 
+    ret = p_fopen_s(&file, name, "wb, ccs=utf-8");
+    ok(ret == 0, "fopen_s failed with %d\n", ret);
+    fwrite("test", 1, 4, file);
+    fputwc('a', file);
+    fputwc('b', file);
+    fclose(file);
+
+    ret = p_fopen_s(&file, name, "rb");
+    ok(ret == 0, "fopen_s failed with %d\n", ret);
+    len = fread(buff, 1, ARRAY_SIZE(buff) - 1, file);
+    ok(len == 8, "len = %d\n", len);
+    ok(!memcmp(buff, "testa\0b", 8), "got %s\n", wine_dbgstr_an(buff, len));
+    fclose(file);
+
     /* test initial FILE values */
     memset(file, 0xfe, sizeof(*file));
     file->_flag = 0;
diff --git a/dlls/msvcrt/tests/heap.c b/dlls/msvcrt/tests/heap.c
index e8da95bb867f..f526c5d75a4f 100644
--- a/dlls/msvcrt/tests/heap.c
+++ b/dlls/msvcrt/tests/heap.c
@@ -163,74 +163,57 @@ static void test_aligned_realloc(unsigned int size1, unsigned int size2, unsigne
 static void test_aligned_offset_realloc(unsigned int size1, unsigned int size2,
                                         unsigned int alignment, unsigned int offset)
 {
-    void *mem, *mem1, *mem2;
+    static BYTE v[256];
+    BYTE *mem, *mem2;
+    int i;
 
-    mem = p_aligned_offset_malloc(size1, alignment, offset);
+    winetest_push_context("%u, %u, %u, %u", size1, size2, alignment, offset);
 
-    if ((alignment & (alignment - 1)) == 0)
-        ok(mem != NULL, "_aligned_offset_malloc(%d, %d, %d) failed\n", size1, alignment, offset);
-    else
-        ok(mem == NULL, "_aligned_offset_malloc(%d, %d, %d) should have failed\n", size1, alignment, offset);
+    for (i = 0; i < ARRAY_SIZE(v); i++)
+        v[i] = i + 1;
 
-    if (mem)
+    mem = p_aligned_offset_malloc(size1, alignment, offset);
+    if ((alignment & (alignment - 1)) != 0)
     {
-	mem1 = malloc(size1);
-        if (mem1)
-        {
-            unsigned int i;
-            for (i = 0; i < size1; i++)
-                ((char *)mem)[i] = i + 1;
-            memcpy(mem1, mem, size1);
-        }
-
-        ok(((DWORD_PTR)((char *)mem + offset) & (alignment ? alignment - 1 : 0)) == 0,
-           "_aligned_offset_malloc(%d, %d, %d) not aligned: %p\n", size1, alignment, offset, mem);
-        if (winetest_debug > 1)
-        {
-            void *saved;
-            saved = *(void **)((DWORD_PTR)((char *)mem - sizeof(void *)) & ~(sizeof(void *) - 1));
-            trace("_aligned_offset_malloc(%3d, %3d, %3d) returns %p, saved = %p\n",
-                  size1, alignment, offset, mem, saved);
-        }
-
-        mem2 = p_aligned_offset_realloc(mem, size2, alignment, offset);
-
-        ok(mem2 != NULL, "_aligned_offset_realloc(%p, %d, %d, %d) failed\n", mem, size2, alignment, offset);
-
-        if (mem2)
-        {
-            ok(((DWORD_PTR)((char *)mem + offset) & (alignment ? alignment - 1 : 0)) == 0,
-               "_aligned_offset_realloc(%p, %d, %d, %d) not aligned: %p\n", mem, size2, alignment, offset, mem2);
-            if (winetest_debug > 1)
-            {
-                void *saved;
-                saved = *(void **)((DWORD_PTR)((char *)mem2 - sizeof(void *)) & ~(sizeof(void *) - 1));
-                trace("_aligned_offset_realloc(%p, %3d, %3d, %3d) returns %p, saved = %p\n",
-                      mem, size2, alignment, offset, mem2, saved);
-            }
-            if (mem1)
-            {
-                ok(memcmp(mem2, mem1, min(size1, size2))==0, "_aligned_offset_realloc(%p, %d, %d, %d) has different data\n", mem, size2, alignment, offset);
-                if (memcmp(mem2, mem1, min(size1, size2)) && winetest_debug > 1)
-                {
-                    unsigned int i;
-                    for (i = 0; i < min(size1, size2); i++)
-                    {
-                        if (((char *)mem2)[i] != ((char *)mem1)[i])
-                            trace("%d: %02x != %02x\n", i, ((char *)mem2)[i] & 0xff, ((char *)mem1)[i] & 0xff);
-                    }
-                }
-            }
-            p_aligned_free(mem2);
-        } else {
-            ok(errno == EINVAL, "_aligned_offset_realloc(%p, %d, %d, %d) errno: %d != %d\n", mem, size2, alignment, offset, errno, EINVAL);
-            p_aligned_free(mem);
-        }
-
-        free(mem1);
+        ok(!mem, "_aligned_offset_malloc should have failed\n");
+        ok(errno == EINVAL, "errno = %d\n", errno);
+        winetest_pop_context();
+        return;
+    }
+    ok(mem != NULL, "_aligned_offset_malloc failed\n");
+    ok(((DWORD_PTR)(mem + offset) & (alignment ? alignment - 1 : 0)) == 0,
+            "incorrect alignment: %p\n", mem);
+
+    ok(size1 <= ARRAY_SIZE(v), "size1 = %d\n", size1);
+    memcpy(mem, v, size1);
+
+    mem2 = p_aligned_offset_realloc(mem, size2, alignment, offset);
+    ok(mem2 != NULL, "_aligned_offset_realloc failed\n");
+    ok(((DWORD_PTR)(mem2 + offset) & (alignment ? alignment - 1 : 0)) == 0,
+            "incorrect alignment: %p\n", mem2);
+    ok(!memcmp(mem2, v, min(size1, size2)), "wrong data\n");
+
+    /* change offset */
+    mem = p_aligned_offset_realloc(mem2, size2, alignment, offset + 1);
+    if (offset + 1 < size2)
+    {
+        ok (mem != NULL, "changing offset failed\n");
+        ok(!memcmp(mem, v, min(size1, size2)), "wrong data\n");
     }
     else
-        ok(errno == EINVAL, "_aligned_offset_malloc(%d, %d) errno: %d != %d\n", size1, alignment, errno, EINVAL);
+    {
+        ok(mem == NULL, "_aligned_offset_realloc should have failed\n");
+        ok(errno == EINVAL, "errno = %d\n", errno);
+        mem = mem2;
+    }
+
+    /* change alignment */
+    mem2 = p_aligned_offset_realloc(mem, size2, alignment / 2, offset);
+    ok(mem2 != NULL, "changing alignment failed\n");
+    ok(!memcmp(mem2, v, min(size1, size2)), "wrong data\n");
+    p_aligned_free(mem2);
+
+    winetest_pop_context();
 }
 
 static void test_aligned(void)
@@ -413,6 +396,7 @@ static void test_aligned(void)
     test_aligned_offset_realloc(256, 128, 32, 112);
     test_aligned_offset_realloc(256, 512, 64, 112);
     test_aligned_offset_realloc(256, 128, 64, 112);
+    test_aligned_offset_realloc(256, 128, 64, 127);
 }
 
 static void test_sbheap(void)
diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in
index 90d90ea4f12a..b769ad65c9c4 100644
--- a/dlls/msxml3/Makefile.in
+++ b/dlls/msxml3/Makefile.in
@@ -17,6 +17,7 @@ SOURCES = \
 	domdoc.c \
 	domimpl.c \
 	element.c \
+	entity.c \
 	entityref.c \
 	factory.c \
 	httprequest.c \
@@ -28,6 +29,7 @@ SOURCES = \
 	node.c \
 	nodelist.c \
 	nodemap.c \
+	notation.c \
 	parseerror.c \
 	pi.c \
 	rsrc.rc \
diff --git a/dlls/msxml3/dispex.c b/dlls/msxml3/dispex.c
index 700b36ea2f86..d31283561667 100644
--- a/dlls/msxml3/dispex.c
+++ b/dlls/msxml3/dispex.c
@@ -91,11 +91,13 @@ static tid_id_t tid_ids[] = {
     { &IID_IXMLDOMDocumentFragment, LibXml2 },
     { &IID_IXMLDOMDocumentType, LibXml2 },
     { &IID_IXMLDOMElement, LibXml2 },
+    { &IID_IXMLDOMEntity, LibXml2 },
     { &IID_IXMLDOMEntityReference, LibXml2 },
     { &IID_IXMLDOMImplementation, LibXml2 },
     { &IID_IXMLDOMNamedNodeMap, LibXml2 },
     { &IID_IXMLDOMNode, LibXml2 },
     { &IID_IXMLDOMNodeList, LibXml2 },
+    { &IID_IXMLDOMNotation, LibXml2 },
     { &IID_IXMLDOMParseError2, LibXml2 },
     { &IID_IXMLDOMProcessingInstruction, LibXml2 },
     { &IID_IXMLDOMSchemaCollection, LibXml2 },
diff --git a/dlls/msxml3/doctype.c b/dlls/msxml3/doctype.c
index 478e68ca9024..6417df81cb3c 100644
--- a/dlls/msxml3/doctype.c
+++ b/dlls/msxml3/doctype.c
@@ -43,6 +43,9 @@ typedef struct _domdoctype
     struct domnode *node;
 } domdoctype;
 
+static const struct nodemap_funcs domdoctype_entities_map;
+static const struct nodemap_funcs domdoctype_notations_map;
+
 static const tid_t doctype_se_tids[] =
 {
     IXMLDOMNode_tid,
@@ -187,23 +190,29 @@ static HRESULT WINAPI domdoctype_get_parentNode(IXMLDOMDocumentType *iface, IXML
 
 static HRESULT WINAPI domdoctype_get_childNodes(IXMLDOMDocumentType *iface, IXMLDOMNodeList **list)
 {
-    FIXME("%p, %p: stub\n", iface, list);
+    domdoctype *doctype = impl_from_IXMLDOMDocumentType(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, list);
+
+    return node_get_child_nodes(doctype->node, list);
 }
 
 static HRESULT WINAPI domdoctype_get_firstChild(IXMLDOMDocumentType *iface, IXMLDOMNode **node)
 {
-    FIXME("%p, %p: stub\n", iface, node);
+    domdoctype *doctype = impl_from_IXMLDOMDocumentType(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, node);
+
+    return node_get_first_child(doctype->node, node);
 }
 
 static HRESULT WINAPI domdoctype_get_lastChild(IXMLDOMDocumentType *iface, IXMLDOMNode **node)
 {
-    FIXME("%p, %p: stub\n", iface, node);
+    domdoctype *doctype = impl_from_IXMLDOMDocumentType(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, node);
+
+    return node_get_last_child(doctype->node, node);
 }
 
 static HRESULT WINAPI domdoctype_get_previousSibling(IXMLDOMDocumentType *iface, IXMLDOMNode **node)
@@ -265,9 +274,11 @@ static HRESULT WINAPI domdoctype_appendChild(IXMLDOMDocumentType *iface, IXMLDOM
 
 static HRESULT WINAPI domdoctype_hasChildNodes(IXMLDOMDocumentType *iface, VARIANT_BOOL *v)
 {
-    FIXME("%p, %p: stub\n", iface, v);
+    domdoctype *doctype = impl_from_IXMLDOMDocumentType(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, v);
+
+    return node_has_childnodes(doctype->node, v);
 }
 
 static HRESULT WINAPI domdoctype_get_ownerDocument(IXMLDOMDocumentType *iface, IXMLDOMDocument **doc)
@@ -423,18 +434,22 @@ static HRESULT WINAPI domdoctype_get_name(IXMLDOMDocumentType *iface, BSTR *p)
     return node_get_name(doctype->node, p);
 }
 
-static HRESULT WINAPI domdoctype_get_entities(IXMLDOMDocumentType *iface, IXMLDOMNamedNodeMap **entities)
+static HRESULT WINAPI domdoctype_get_entities(IXMLDOMDocumentType *iface, IXMLDOMNamedNodeMap **map)
 {
-    FIXME("%p, %p: stub\n", iface, entities);
+    domdoctype *doctype = impl_from_IXMLDOMDocumentType(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, map);
+
+    return create_nodemap(doctype->node, &domdoctype_entities_map, map);
 }
 
-static HRESULT WINAPI domdoctype_get_notations(IXMLDOMDocumentType *iface, IXMLDOMNamedNodeMap **notations)
+static HRESULT WINAPI domdoctype_get_notations(IXMLDOMDocumentType *iface, IXMLDOMNamedNodeMap **map)
 {
-    FIXME("%p, %p: stub\n", iface, notations);
+    domdoctype *doctype = impl_from_IXMLDOMDocumentType(iface);
 
-    return E_NOTIMPL;
+    TRACE("%p, %p.\n", iface, map);
+
+    return create_nodemap(doctype->node, &domdoctype_notations_map, map);
 }
 
 static const struct IXMLDOMDocumentTypeVtbl domdoctype_vtbl =
@@ -487,6 +502,204 @@ static const struct IXMLDOMDocumentTypeVtbl domdoctype_vtbl =
     domdoctype_get_notations
 };
 
+static HRESULT domnode_get_children_count_for_type(const struct domnode *node, DOMNodeType type, LONG *length)
+{
+    struct domnode *child;
+
+    if (!length)
+        return E_INVALIDARG;
+
+    *length = 0;
+
+    LIST_FOR_EACH_ENTRY(child, &node->children, struct domnode, entry)
+    {
+        if (child->type == type)
+            *length = *length + 1;
+    }
+
+    return S_OK;
+}
+
+static HRESULT domnode_get_named_child_for_type(const struct domnode *node, BSTR name, DOMNodeType type, IXMLDOMNode **item)
+{
+    struct domnode *child;
+
+    if (!name || !item)
+        return E_INVALIDARG;
+
+    *item = NULL;
+
+    LIST_FOR_EACH_ENTRY(child, &node->children, struct domnode, entry)
+    {
+        if (child->type == type && !wcscmp(child->name, name))
+            return create_node(child, item);
+    }
+
+    return S_FALSE;
+}
+
+static HRESULT domnode_get_child_for_type(const struct domnode *node, LONG index, DOMNodeType type, IXMLDOMNode **item)
+{
+    struct domnode *child, *curr = NULL;
+
+    *item = NULL;
+
+    if (index < 0)
+        return S_FALSE;
+
+    LIST_FOR_EACH_ENTRY(child, &node->children, struct domnode, entry)
+    {
+        if (child->type != type) continue;
+
+        curr = child;
+        if (!index--) break;
+        curr = NULL;
+    }
+
+    if (!curr)
+        return S_FALSE;
+
+    return create_node(curr, item);
+}
+
+static HRESULT domdoctype_entities_get_qualified_item(const struct domnode *node, BSTR name, BSTR uri,
+    IXMLDOMNode **item)
+{
+    FIXME("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT domdoctype_entities_get_named_item(const struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    return domnode_get_named_child_for_type(node, name, NODE_ENTITY, item);
+}
+
+static HRESULT domdoctype_entities_set_named_item(struct domnode *node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem)
+{
+    TRACE("%p, %p, %p.\n", node, newItem, namedItem );
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domdoctype_entities_remove_qualified_item(struct domnode *node, BSTR name, BSTR uri, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domdoctype_entities_remove_named_item(struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domdoctype_entities_get_item(struct domnode *node, LONG index, IXMLDOMNode **item)
+{
+    TRACE("%p, %ld, %p.\n", node, index, item);
+
+    return domnode_get_child_for_type(node, index, NODE_ENTITY, item);
+}
+
+static HRESULT domdoctype_entities_get_length(struct domnode *node, LONG *length)
+{
+    TRACE("%p, %p.\n", node, length);
+
+    return domnode_get_children_count_for_type(node, NODE_ENTITY, length);
+}
+
+static HRESULT domdoctype_entities_next_node(const struct domnode *node, LONG *iter, IXMLDOMNode **nextNode)
+{
+    FIXME("%p, %ld, %p.\n", node, *iter, nextNode);
+
+    return E_NOTIMPL;
+}
+
+static const struct nodemap_funcs domdoctype_entities_map =
+{
+    .get_named_item = domdoctype_entities_get_named_item,
+    .set_named_item = domdoctype_entities_set_named_item,
+    .remove_named_item = domdoctype_entities_remove_named_item,
+    .get_item = domdoctype_entities_get_item,
+    .get_length = domdoctype_entities_get_length,
+    .get_qualified_item = domdoctype_entities_get_qualified_item,
+    .remove_qualified_item = domdoctype_entities_remove_qualified_item,
+    .next_node = domdoctype_entities_next_node,
+};
+
+static HRESULT domdoctype_notations_get_qualified_item(const struct domnode *node, BSTR name, BSTR uri,
+    IXMLDOMNode **item)
+{
+    FIXME("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT domdoctype_notations_get_named_item(const struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    return domnode_get_named_child_for_type(node, name, NODE_NOTATION, item);
+}
+
+static HRESULT domdoctype_notations_set_named_item(struct domnode *node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem)
+{
+    TRACE("%p, %p, %p.\n", node, newItem, namedItem );
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domdoctype_notations_remove_qualified_item(struct domnode *node, BSTR name, BSTR uri, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domdoctype_notations_remove_named_item(struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domdoctype_notations_get_item(struct domnode *node, LONG index, IXMLDOMNode **item)
+{
+    TRACE("%p, %ld, %p.\n", node, index, item);
+
+    return domnode_get_child_for_type(node, index, NODE_NOTATION, item);
+}
+
+static HRESULT domdoctype_notations_get_length(struct domnode *node, LONG *length)
+{
+    TRACE("%p, %p.\n", node, length);
+
+    return domnode_get_children_count_for_type(node, NODE_NOTATION, length);
+}
+
+static HRESULT domdoctype_notations_next_node(const struct domnode *node, LONG *iter, IXMLDOMNode **nextNode)
+{
+    FIXME("%p, %ld, %p.\n", node, *iter, nextNode);
+
+    return E_NOTIMPL;
+}
+
+static const struct nodemap_funcs domdoctype_notations_map =
+{
+    .get_named_item = domdoctype_notations_get_named_item,
+    .set_named_item = domdoctype_notations_set_named_item,
+    .remove_named_item = domdoctype_notations_remove_named_item,
+    .get_item = domdoctype_notations_get_item,
+    .get_length = domdoctype_notations_get_length,
+    .get_qualified_item = domdoctype_notations_get_qualified_item,
+    .remove_qualified_item = domdoctype_notations_remove_qualified_item,
+    .next_node = domdoctype_notations_next_node,
+};
+
 static const tid_t domdoctype_iface_tids[] =
 {
     IXMLDOMDocumentType_tid,
diff --git a/dlls/msxml3/element.c b/dlls/msxml3/element.c
index 35a41b091574..30ca3f48e3f9 100644
--- a/dlls/msxml3/element.c
+++ b/dlls/msxml3/element.c
@@ -1188,7 +1188,7 @@ static HRESULT domelem_set_named_item(struct domnode *node, IXMLDOMNode *newItem
 {
     TRACE("%p, %p, %p.\n", node, newItem, namedItem );
 
-    return node_set_attribute(node, newItem, namedItem);
+    return node_set_named_attribute(node, newItem, namedItem);
 }
 
 static HRESULT domelem_remove_qualified_item(struct domnode *node, BSTR name, BSTR uri, IXMLDOMNode **item)
@@ -1218,11 +1218,7 @@ static HRESULT domelem_get_length(struct domnode *node, LONG *length)
 {
     TRACE("%p, %p.\n", node, length);
 
-    if (!length)
-        return E_INVALIDARG;
-
-    *length = list_count(&node->attributes);
-    return S_OK;
+    return node_get_attribute_count(node, length);
 }
 
 static HRESULT domelem_next_node(const struct domnode *node, LONG *iter, IXMLDOMNode **nextNode)
diff --git a/dlls/msxml3/entity.c b/dlls/msxml3/entity.c
new file mode 100644
index 000000000000..b0ecc0d56550
--- /dev/null
+++ b/dlls/msxml3/entity.c
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2026 Nikolay Sivov for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "ole2.h"
+#include "msxml6.h"
+
+#include "msxml_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msxml);
+
+struct domentity
+{
+    DispatchEx dispex;
+    IXMLDOMEntity IXMLDOMEntity_iface;
+    LONG refcount;
+    struct domnode *node;
+};
+
+static const struct nodemap_funcs domentity_attr_map;
+
+static const tid_t entity_se_tids[] =
+{
+    IXMLDOMNode_tid,
+    IXMLDOMEntity_tid,
+    NULL_tid
+};
+
+static inline struct domentity *impl_from_IXMLDOMEntity(IXMLDOMEntity *iface)
+{
+    return CONTAINING_RECORD(iface, struct domentity, IXMLDOMEntity_iface);
+}
+
+static HRESULT WINAPI domentity_QueryInterface(IXMLDOMEntity *iface, REFIID riid, void **obj)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+    if (IsEqualGUID(riid, &IID_IXMLDOMEntity) ||
+        IsEqualGUID(riid, &IID_IXMLDOMNode) ||
+        IsEqualGUID(riid, &IID_IDispatch) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *obj = &entity->IXMLDOMEntity_iface;
+    }
+    else if (dispex_query_interface(&entity->dispex, riid, obj))
+    {
+        return *obj ? S_OK : E_NOINTERFACE;
+    }
+    else if (node_query_interface(entity->node, riid, obj))
+    {
+        return *obj ? S_OK : E_NOINTERFACE;
+    }
+    else if (IsEqualGUID(riid, &IID_ISupportErrorInfo))
+    {
+        return node_create_supporterrorinfo(entity_se_tids, obj);
+    }
+    else
+    {
+        TRACE("interface %s not implemented\n", debugstr_guid(riid));
+        *obj = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef( (IUnknown*)*obj );
+    return S_OK;
+}
+
+static ULONG WINAPI domentity_AddRef(IXMLDOMEntity *iface)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+    LONG refcount = InterlockedIncrement(&entity->refcount);
+
+    TRACE("%p, refcount %ld.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI domentity_Release(IXMLDOMEntity *iface)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+    ULONG refcount = InterlockedDecrement(&entity->refcount);
+
+    TRACE("%p, refcount %ld.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        domnode_release(entity->node);
+        free(entity);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI domentity_GetTypeInfoCount(IXMLDOMEntity *iface, UINT *count)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+    return IDispatchEx_GetTypeInfoCount(&entity->dispex.IDispatchEx_iface, count);
+}
+
+static HRESULT WINAPI domentity_GetTypeInfo(IXMLDOMEntity *iface, UINT index, LCID lcid, ITypeInfo **ti)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+    return IDispatchEx_GetTypeInfo(&entity->dispex.IDispatchEx_iface, index, lcid, ti);
+}
+
+static HRESULT WINAPI domentity_GetIDsOfNames(IXMLDOMEntity *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+    return IDispatchEx_GetIDsOfNames(&entity->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI domentity_Invoke(IXMLDOMEntity *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+        WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *ei, UINT *puArgErr)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+    return IDispatchEx_Invoke(&entity->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, flags, params,
+            result, ei, puArgErr);
+}
+
+static HRESULT WINAPI domentity_get_nodeName(IXMLDOMEntity *iface, BSTR *p)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, p);
+
+    return node_get_name(entity->node, p);
+}
+
+static HRESULT WINAPI domentity_get_nodeValue(IXMLDOMEntity *iface, VARIANT *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_put_nodeValue(IXMLDOMEntity *iface, VARIANT v)
+{
+    FIXME("%p, %s: stub\n", iface, debugstr_variant(&v));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_nodeType(IXMLDOMEntity *iface, DOMNodeType *type)
+{
+    TRACE("%p, %p.\n", iface, type);
+
+    *type = NODE_ENTITY;
+    return S_OK;
+}
+
+static HRESULT WINAPI domentity_get_parentNode(IXMLDOMEntity *iface, IXMLDOMNode **parent)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, parent);
+
+    return node_get_parent(entity->node, parent);
+}
+
+static HRESULT WINAPI domentity_get_childNodes(IXMLDOMEntity *iface, IXMLDOMNodeList **list)
+{
+    FIXME("%p, %p: stub\n", iface, list);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_firstChild(IXMLDOMEntity *iface, IXMLDOMNode **node)
+{
+    FIXME("%p, %p: stub\n", iface, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_lastChild(IXMLDOMEntity *iface, IXMLDOMNode **node)
+{
+    FIXME("%p, %p: stub\n", iface, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_previousSibling(IXMLDOMEntity *iface, IXMLDOMNode **node)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, node);
+
+    return node_get_previous_sibling(entity->node, node);
+}
+
+static HRESULT WINAPI domentity_get_nextSibling(IXMLDOMEntity *iface, IXMLDOMNode **node)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, node);
+
+    return node_get_next_sibling(entity->node, node);
+}
+
+static HRESULT WINAPI domentity_get_attributes(IXMLDOMEntity *iface, IXMLDOMNamedNodeMap **map)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, map);
+
+    return create_nodemap(entity->node, &domentity_attr_map, map);
+}
+
+static HRESULT WINAPI domentity_insertBefore(IXMLDOMEntity *iface, IXMLDOMNode *node,
+        VARIANT refChild, IXMLDOMNode **out_node)
+{
+    FIXME("%p, %p, %s, %p: stub\n", iface, node, debugstr_variant(&refChild), out_node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_replaceChild(IXMLDOMEntity *iface, IXMLDOMNode *newNode,
+        IXMLDOMNode *oldNode, IXMLDOMNode **outOldNode)
+{
+    FIXME("%p, %p, %p, %p: stub\n", iface, newNode, oldNode, outOldNode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_removeChild(IXMLDOMEntity *iface, IXMLDOMNode *node,
+        IXMLDOMNode **oldNode)
+{
+    FIXME("%p, %p, %p: stub\n", iface, node, oldNode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_appendChild(IXMLDOMEntity *iface, IXMLDOMNode *newNode,
+        IXMLDOMNode **outNewNode)
+{
+    FIXME("%p, %p, %p: stub\n", iface, newNode, outNewNode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_hasChildNodes(IXMLDOMEntity *iface, VARIANT_BOOL *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_ownerDocument(IXMLDOMEntity *iface, IXMLDOMDocument **doc)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, doc);
+
+    return node_get_owner_document(entity->node, doc);
+}
+
+static HRESULT WINAPI domentity_cloneNode(IXMLDOMEntity *iface, VARIANT_BOOL deep, IXMLDOMNode **node)
+{
+    FIXME("%p, %d, %p: stub\n", iface, deep, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_nodeTypeString(IXMLDOMEntity *iface, BSTR *p)
+{
+    TRACE("%p, %p.\n", iface, p);
+
+    return return_bstr(L"entity", p);
+}
+
+static HRESULT WINAPI domentity_get_text(IXMLDOMEntity *iface, BSTR *p)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, p);
+
+    return node_get_text(entity->node, p);
+}
+
+static HRESULT WINAPI domentity_put_text(IXMLDOMEntity *iface, BSTR p)
+{
+    TRACE("%p, %s.\n", iface, debugstr_w(p));
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI domentity_get_specified(IXMLDOMEntity *iface, VARIANT_BOOL *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_definition(IXMLDOMEntity *iface, IXMLDOMNode **node)
+{
+    FIXME("%p, %p: stub\n", iface, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_nodeTypedValue(IXMLDOMEntity *iface, VARIANT *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_put_nodeTypedValue(IXMLDOMEntity *iface, VARIANT value)
+{
+    FIXME("%p, %s: stub\n", iface, debugstr_variant(&value));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_dataType(IXMLDOMEntity *iface, VARIANT *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_put_dataType(IXMLDOMEntity *iface, BSTR p)
+{
+    FIXME("%p, %s: stub\n", iface, debugstr_w(p));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_xml(IXMLDOMEntity *iface, BSTR *p)
+{
+    FIXME("%p, %p.\n", iface, p);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_transformNode(IXMLDOMEntity *iface, IXMLDOMNode *node, BSTR *p)
+{
+    FIXME("%p, %p, %p: stub\n", iface, node, p);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_selectNodes(IXMLDOMEntity *iface, BSTR p, IXMLDOMNodeList **list)
+{
+    FIXME("%p, %s, %p: stub\n", iface, debugstr_w(p), list);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_selectSingleNode(IXMLDOMEntity *iface, BSTR p, IXMLDOMNode **node)
+{
+    FIXME("%p, %s, %p: stub\n", iface, debugstr_w(p), node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_parsed(IXMLDOMEntity *iface, VARIANT_BOOL *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_namespaceURI(IXMLDOMEntity *iface, BSTR *p)
+{
+    FIXME("%p, %p: stub\n", iface, p);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_prefix(IXMLDOMEntity *iface, BSTR *prefix)
+{
+    FIXME("%p, %p: stub\n", iface, prefix);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_baseName(IXMLDOMEntity *iface, BSTR *p)
+{
+    struct domentity *entity = impl_from_IXMLDOMEntity(iface);
+
+    TRACE("%p, %p.\n", iface, p);
+
+    return node_get_name(entity->node, p);
+}
+
+static HRESULT WINAPI domentity_transformNodeToObject(IXMLDOMEntity *iface, IXMLDOMNode *node, VARIANT var1)
+{
+    FIXME("%p, %p, %s: stub\n", iface, node, debugstr_variant(&var1));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_publicId(IXMLDOMEntity *iface, VARIANT *id)
+{
+    FIXME("%p, %p: stub\n", iface, id);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_systemId(IXMLDOMEntity *iface, VARIANT *id)
+{
+    FIXME("%p, %p: stub\n", iface, id);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domentity_get_notationName(IXMLDOMEntity *iface, BSTR *p)
+{
+    FIXME("%p, %p: stub\n", iface, p);
+
+    return E_NOTIMPL;
+}
+
+static const struct IXMLDOMEntityVtbl domentity_vtbl =
+{
+    domentity_QueryInterface,
+    domentity_AddRef,
+    domentity_Release,
+    domentity_GetTypeInfoCount,
+    domentity_GetTypeInfo,
+    domentity_GetIDsOfNames,
+    domentity_Invoke,
+    domentity_get_nodeName,
+    domentity_get_nodeValue,
+    domentity_put_nodeValue,
+    domentity_get_nodeType,
+    domentity_get_parentNode,
+    domentity_get_childNodes,
+    domentity_get_firstChild,
+    domentity_get_lastChild,
+    domentity_get_previousSibling,
+    domentity_get_nextSibling,
+    domentity_get_attributes,
+    domentity_insertBefore,
+    domentity_replaceChild,
+    domentity_removeChild,
+    domentity_appendChild,
+    domentity_hasChildNodes,
+    domentity_get_ownerDocument,
+    domentity_cloneNode,
+    domentity_get_nodeTypeString,
+    domentity_get_text,
+    domentity_put_text,
+    domentity_get_specified,
+    domentity_get_definition,
+    domentity_get_nodeTypedValue,
+    domentity_put_nodeTypedValue,
+    domentity_get_dataType,
+    domentity_put_dataType,
+    domentity_get_xml,
+    domentity_transformNode,
+    domentity_selectNodes,
+    domentity_selectSingleNode,
+    domentity_get_parsed,
+    domentity_get_namespaceURI,
+    domentity_get_prefix,
+    domentity_get_baseName,
+    domentity_transformNodeToObject,
+    domentity_get_publicId,
+    domentity_get_systemId,
+    domentity_get_notationName,
+};
+
+static HRESULT domentity_get_qualified_item(const struct domnode *node, BSTR name, BSTR uri,
+    IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    if (!name || !item)
+        return E_INVALIDARG;
+
+    return node_get_qualified_attribute(node, name, uri, item);
+}
+
+static HRESULT domentity_get_named_item(const struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    if (!name || !item)
+        return E_INVALIDARG;
+
+    return node_get_attribute(node, name, (IXMLDOMAttribute **)item);
+}
+
+static HRESULT domentity_set_named_item(struct domnode *node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem)
+{
+    TRACE("%p, %p, %p.\n", node, newItem, namedItem );
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domentity_remove_qualified_item(struct domnode *node, BSTR name, BSTR uri, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domentity_remove_named_item(struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domentity_get_item(struct domnode *node, LONG index, IXMLDOMNode **item)
+{
+    TRACE("%p, %ld, %p.\n", node, index, item);
+
+    return node_get_attribute_by_index(node, index, item);
+}
+
+static HRESULT domentity_get_length(struct domnode *node, LONG *length)
+{
+    TRACE("%p, %p.\n", node, length);
+
+    return node_get_attribute_count(node, length);
+}
+
+static HRESULT domentity_next_node(const struct domnode *node, LONG *iter, IXMLDOMNode **nextNode)
+{
+    FIXME("%p, %ld, %p.\n", node, *iter, nextNode);
+
+    return E_NOTIMPL;
+}
+
+static const struct nodemap_funcs domentity_attr_map =
+{
+    .get_named_item = domentity_get_named_item,
+    .set_named_item = domentity_set_named_item,
+    .remove_named_item = domentity_remove_named_item,
+    .get_item = domentity_get_item,
+    .get_length = domentity_get_length,
+    .get_qualified_item = domentity_get_qualified_item,
+    .remove_qualified_item = domentity_remove_qualified_item,
+    .next_node = domentity_next_node,
+};
+
+static const tid_t domentity_iface_tids[] =
+{
+    IXMLDOMEntity_tid,
+    0
+};
+
+static dispex_static_data_t domentity_dispex =
+{
+    NULL,
+    IXMLDOMEntity_tid,
+    NULL,
+    domentity_iface_tids
+};
+
+HRESULT create_entity(struct domnode *node, IUnknown **obj)
+{
+    struct domentity *object;
+
+    *obj = NULL;
+
+    if (!(object = calloc(1, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IXMLDOMEntity_iface.lpVtbl = &domentity_vtbl;
+    object->refcount = 1;
+    object->node = domnode_addref(node);
+
+    init_dispex(&object->dispex, (IUnknown *)&object->IXMLDOMEntity_iface, &domentity_dispex);
+
+    *obj = (IUnknown *)&object->IXMLDOMEntity_iface;
+
+    return S_OK;
+}
diff --git a/dlls/msxml3/msxml_dispex.h b/dlls/msxml3/msxml_dispex.h
index 62fa96bcfb2d..e907e9ba56ca 100644
--- a/dlls/msxml3/msxml_dispex.h
+++ b/dlls/msxml3/msxml_dispex.h
@@ -47,11 +47,13 @@ typedef enum tid_t
     IXMLDOMDocumentFragment_tid,
     IXMLDOMDocumentType_tid,
     IXMLDOMElement_tid,
+    IXMLDOMEntity_tid,
     IXMLDOMEntityReference_tid,
     IXMLDOMImplementation_tid,
     IXMLDOMNamedNodeMap_tid,
     IXMLDOMNode_tid,
     IXMLDOMNodeList_tid,
+    IXMLDOMNotation_tid,
     IXMLDOMParseError2_tid,
     IXMLDOMProcessingInstruction_tid,
     IXMLDOMSchemaCollection_tid,
diff --git a/dlls/msxml3/msxml_private.h b/dlls/msxml3/msxml_private.h
index c10a7defc2ee..f8c9e85900fb 100644
--- a/dlls/msxml3/msxml_private.h
+++ b/dlls/msxml3/msxml_private.h
@@ -322,12 +322,14 @@ extern HRESULT create_cdata(struct domnode *, IUnknown **);
 extern HRESULT create_children_nodelist(struct domnode *, IXMLDOMNodeList **);
 extern HRESULT create_nodemap(struct domnode *, const struct nodemap_funcs *, IXMLDOMNamedNodeMap **);
 extern HRESULT create_doc_fragment(struct domnode *, IUnknown **);
+extern HRESULT create_entity(struct domnode *, IUnknown **);
 extern HRESULT create_entity_ref(struct domnode *, IUnknown **);
 extern HRESULT create_doc_type(struct domnode *, IUnknown **);
 extern HRESULT create_selection(struct domnode *, BSTR, bool xpath, IXMLDOMNodeList** );
 extern HRESULT create_selection_from_nodeset( xmlXPathObjectPtr, IXMLDOMNodeList ** );
 extern HRESULT create_enumvariant( IUnknown*, BOOL, const struct enumvariant_funcs*, IEnumVARIANT**);
 extern HRESULT create_dom_implementation(IXMLDOMImplementation **obj);
+extern HRESULT create_notation(struct domnode *, IUnknown **);
 
 extern void wineXmlCallbackLog(char const* caller, xmlErrorLevel lvl, char const* msg, va_list ap);
 extern void wineXmlCallbackError(char const* caller, const xmlError* err);
@@ -364,8 +366,10 @@ extern HRESULT node_put_value(struct domnode*,VARIANT*);
 extern HRESULT node_get_attribute(const struct domnode *,const WCHAR *,IXMLDOMAttribute **);
 extern HRESULT node_get_qualified_attribute(const struct domnode *, const WCHAR *name, const WCHAR *uri, IXMLDOMNode **);
 extern HRESULT node_get_attribute_by_index(const struct domnode *, LONG, IXMLDOMNode **);
+extern HRESULT node_get_attribute_count(const struct domnode *, LONG *);
 extern HRESULT node_get_attribute_value(struct domnode *,const WCHAR *,VARIANT *);
 extern HRESULT node_set_attribute(struct domnode *, IXMLDOMNode *, IXMLDOMNode **);
+extern HRESULT node_set_named_attribute(struct domnode *, IXMLDOMNode *, IXMLDOMNode **);
 extern HRESULT node_set_attribute_value(struct domnode *,const WCHAR *,const VARIANT *);
 extern HRESULT node_remove_attribute(struct domnode *, const WCHAR *, IXMLDOMNode **);
 extern HRESULT node_remove_attribute_node(struct domnode *,IXMLDOMAttribute *,IXMLDOMAttribute **);
diff --git a/dlls/msxml3/node.c b/dlls/msxml3/node.c
index 4c2fda32e750..70e0b02c0777 100644
--- a/dlls/msxml3/node.c
+++ b/dlls/msxml3/node.c
@@ -1715,6 +1715,7 @@ HRESULT node_get_text(struct domnode *node, BSTR *text)
         case NODE_COMMENT:
         case NODE_ENTITY_REFERENCE:
         case NODE_CDATA_SECTION:
+        case NODE_ENTITY:
             return return_bstr(node->data, text);
 
         case NODE_PROCESSING_INSTRUCTION:
@@ -3439,6 +3440,15 @@ HRESULT node_get_attribute_by_index(const struct domnode *node, LONG index, IXML
     return create_node(curr, attr);
 }
 
+HRESULT node_get_attribute_count(const struct domnode *node, LONG *count)
+{
+    if (!count)
+        return E_INVALIDARG;
+
+    *count = list_count(&node->attributes);
+    return S_OK;
+}
+
 HRESULT node_get_attribute_value(struct domnode *node, const WCHAR *name, VARIANT *value)
 {
     struct string_buffer buffer;
@@ -3504,6 +3514,43 @@ HRESULT node_set_attribute(struct domnode *node, IXMLDOMNode *attribute, IXMLDOM
     return S_OK;
 }
 
+/* Used for setNamedItem(), using different semantics for returned node comparing to setAttributeNode() */
+HRESULT node_set_named_attribute(struct domnode *node, IXMLDOMNode *attribute, IXMLDOMNode **ret)
+{
+    struct domnode *attr, *old_attr;
+    HRESULT hr = S_OK;
+
+    if (!attribute)
+        return E_INVALIDARG;
+
+    if (!(attr = get_node_obj(attribute)))
+        return E_FAIL;
+
+    if (attr->type != NODE_ATTRIBUTE)
+        return E_FAIL;
+
+    if (attr->parent)
+        return E_FAIL;
+
+    if (ret)
+        *ret = NULL;
+
+    if (domnode_get_attribute(node, attr->qname, &old_attr) == S_OK)
+    {
+        domnode_insert_attribute(node, attr, old_attr);
+        domnode_unlink_attribute(old_attr);
+    }
+    else
+    {
+        domnode_insert_attribute(node, attr, NULL);
+    }
+
+    if (ret)
+        hr = create_node(attr, ret);
+
+    return hr;
+}
+
 static bool is_namespace_definition_name(const struct parsed_name *name)
 {
     if (!name->prefix && !wcscmp(name->local, L"xmlns"))
@@ -3608,9 +3655,11 @@ HRESULT create_node(struct domnode *node, IXMLDOMNode **ret)
         hr = create_doc_type(node, &obj);
         break;
     case NODE_ENTITY:
+        hr = create_entity(node, &obj);
+        break;
     case NODE_NOTATION:
-        FIXME("Unsupported node type %d.\n", node->type);
-        return E_NOTIMPL;
+        hr = create_notation(node, &obj);
+        break;
     default:
         WARN("Invalid node type %d\n", node->type);
         return E_FAIL;
@@ -3630,6 +3679,8 @@ struct parse_context
     ISAXExtensionHandler extension_handler;
     ISAXContentHandler content_handler;
     ISAXLexicalHandler lexical_handler;
+    ISAXDTDHandler dtd_handler;
+    ISAXDeclHandler decl_handler;
     ISAXXMLReaderExtension *reader_extension;
     ISAXXMLReader *reader;
 
@@ -3762,6 +3813,16 @@ static struct parse_context *impl_from_ISAXExtensionHandler(ISAXExtensionHandler
     return CONTAINING_RECORD(iface, struct parse_context, extension_handler);
 }
 
+static struct parse_context *impl_from_ISAXDTDHandler(ISAXDTDHandler *iface)
+{
+    return CONTAINING_RECORD(iface, struct parse_context, dtd_handler);
+}
+
+static struct parse_context *impl_from_ISAXDeclHandler(ISAXDeclHandler *iface)
+{
+    return CONTAINING_RECORD(iface, struct parse_context, decl_handler);
+}
+
 static HRESULT WINAPI parse_content_handler_QueryInterface(ISAXContentHandler *iface, REFIID riid, void **obj)
 {
     if (IsEqualGUID(riid, &IID_ISAXContentHandler)
@@ -3923,6 +3984,172 @@ static const ISAXContentHandlerVtbl parse_content_handler_vtbl =
     parse_content_handler_skippedEntity,
 };
 
+static HRESULT WINAPI parse_dtd_handler_QueryInterface(ISAXDTDHandler *iface, REFIID riid, void **obj)
+{
+    if (IsEqualGUID(riid, &IID_ISAXDTDHandler)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        ISAXDTDHandler_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI parse_dtd_handler_AddRef(ISAXDTDHandler *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI parse_dtd_handler_Release(ISAXDTDHandler *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI parse_dtd_handler_notationDecl(ISAXDTDHandler *iface, const WCHAR *name,
+        int name_len, const WCHAR *pubid, int pubid_len, const WCHAR *sysid, int sysid_len)
+{
+    struct parse_context *c = impl_from_ISAXDTDHandler(iface);
+    struct domnode *node, *attr;
+
+    parse_context_node_create(c, NODE_NOTATION, name, name_len, NULL, 0, c->root, &node);
+    parse_context_append_child(c, c->node, node);
+
+    if (pubid)
+    {
+        parse_context_node_create(c, NODE_ATTRIBUTE, L"PUBLIC", 6, NULL, 0, c->root, &attr);
+        parse_context_append_attribute(c, node, attr);
+        parse_context_node_put_data(c, attr, pubid, pubid_len);
+    }
+
+    if (sysid)
+    {
+        parse_context_node_create(c, NODE_ATTRIBUTE, L"SYSTEM", 6, NULL, 0, c->root, &attr);
+        parse_context_append_attribute(c, node, attr);
+        parse_context_node_put_data(c, attr, sysid, sysid_len);
+    }
+
+    return c->status;
+}
+
+static HRESULT WINAPI parse_dtd_handler_unparsedEntityDecl(ISAXDTDHandler *iface, const WCHAR *name,
+        int name_len, const WCHAR *pubid, int pubid_len, const WCHAR *sysid, int sysid_len,
+        const WCHAR *notation_name, int notation_name_len)
+{
+    struct parse_context *c = impl_from_ISAXDTDHandler(iface);
+    struct domnode *node, *attr;
+
+    parse_context_node_create(c, NODE_ENTITY, name, name_len, NULL, 0, c->root, &node);
+    parse_context_node_put_data(c, node, NULL, 0);
+
+    if (pubid)
+    {
+        parse_context_node_create(c, NODE_ATTRIBUTE, L"PUBLIC", 6, NULL, 0, c->root, &attr);
+        parse_context_append_attribute(c, node, attr);
+        parse_context_node_put_data(c, attr, pubid, pubid_len);
+    }
+
+    if (sysid)
+    {
+        parse_context_node_create(c, NODE_ATTRIBUTE, L"SYSTEM", 6, NULL, 0, c->root, &attr);
+        parse_context_append_attribute(c, node, attr);
+        parse_context_node_put_data(c, attr, sysid, sysid_len);
+    }
+
+    if (notation_name)
+    {
+        parse_context_node_create(c, NODE_ATTRIBUTE, L"NDATA", 6, NULL, 0, c->root, &attr);
+        parse_context_append_attribute(c, node, attr);
+        parse_context_node_put_data(c, attr, notation_name, notation_name_len);
+    }
+
+    parse_context_append_child(c, c->node, node);
+
+    return c->status;
+}
+
+static const ISAXDTDHandlerVtbl parse_dtd_handler_vtbl =
+{
+    parse_dtd_handler_QueryInterface,
+    parse_dtd_handler_AddRef,
+    parse_dtd_handler_Release,
+    parse_dtd_handler_notationDecl,
+    parse_dtd_handler_unparsedEntityDecl,
+};
+
+static HRESULT WINAPI parse_decl_handler_QueryInterface(ISAXDeclHandler *iface, REFIID riid, void **obj)
+{
+    if (IsEqualGUID(riid, &IID_ISAXDeclHandler)
+            || IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        ISAXDeclHandler_AddRef(iface);
+        return S_OK;
+    }
+
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI parse_decl_handler_AddRef(ISAXDeclHandler *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI parse_decl_handler_Release(ISAXDeclHandler *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI parse_decl_handler_elementDecl(ISAXDeclHandler *iface, const WCHAR *name,
+        int name_len, const WCHAR *model, int model_len)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI parse_decl_handler_attributeDecl(ISAXDeclHandler *iface, const WCHAR *element_name,
+        int element_name_len, const WCHAR *attribute_name, int attribute_name_len,
+        const WCHAR *type, int type_len, const WCHAR *value_default, int value_default_len,
+        const WCHAR *value, int value_len)
+{
+    return S_OK;
+}
+
+static HRESULT WINAPI parse_decl_handler_internalEntityDecl(ISAXDeclHandler *iface, const WCHAR *name,
+        int name_len, const WCHAR *value, int value_len)
+{
+    struct parse_context *c = impl_from_ISAXDeclHandler(iface);
+    struct domnode *node;
+
+    if (name[0] != '%')
+    {
+        parse_context_node_create(c, NODE_ENTITY, name, name_len, NULL, 0, c->root, &node);
+        parse_context_append_child(c, c->node, node);
+        parse_context_node_put_data(c, node, value, value_len);
+    }
+
+    return c->status;
+}
+
+static HRESULT WINAPI parse_decl_handler_externalEntityDecl(ISAXDeclHandler *iface, const WCHAR *name,
+        int name_len, const WCHAR *pubid, int pubid_len, const WCHAR *sysid, int sysid_len)
+{
+    return S_OK;
+}
+
+static const ISAXDeclHandlerVtbl parse_decl_handler_vtbl =
+{
+    parse_decl_handler_QueryInterface,
+    parse_decl_handler_AddRef,
+    parse_decl_handler_Release,
+    parse_decl_handler_elementDecl,
+    parse_decl_handler_attributeDecl,
+    parse_decl_handler_internalEntityDecl,
+    parse_decl_handler_externalEntityDecl,
+};
+
 static HRESULT WINAPI parse_extension_handler_QueryInterface(ISAXExtensionHandler *iface, REFIID riid, void **obj)
 {
     if (IsEqualGUID(riid, &IID_ISAXExtensionHandler)
@@ -4118,6 +4345,8 @@ static HRESULT parse_context_init(struct parse_context *c, const struct domdoc_p
     c->content_handler.lpVtbl = &parse_content_handler_vtbl;
     c->extension_handler.lpVtbl = &parse_extension_handler_vtbl;
     c->lexical_handler.lpVtbl = &parse_lexical_handler_vtbl;
+    c->dtd_handler.lpVtbl = &parse_dtd_handler_vtbl;
+    c->decl_handler.lpVtbl = &parse_decl_handler_vtbl;
     c->buffer.status = &c->status;
     c->max_depth = properties->max_element_depth;
     c->version = properties->version;
@@ -4130,11 +4359,16 @@ static HRESULT parse_context_init(struct parse_context *c, const struct domdoc_p
     IUnknown_Release(unk);
 
     ISAXXMLReader_putContentHandler(c->reader, &c->content_handler);
+    ISAXXMLReader_putDTDHandler(c->reader, &c->dtd_handler);
 
     V_VT(&v) = VT_UNKNOWN;
     V_UNKNOWN(&v) = (IUnknown *)&c->lexical_handler;
     ISAXXMLReader_putProperty(c->reader, L"http://xml.org/sax/properties/lexical-handler", v);
 
+    V_VT(&v) = VT_UNKNOWN;
+    V_UNKNOWN(&v) = (IUnknown *)&c->decl_handler;
+    ISAXXMLReader_putProperty(c->reader, L"http://xml.org/sax/properties/declaration-handler", v);
+
     V_VT(&v) = VT_UNKNOWN;
     V_UNKNOWN(&v) = (IUnknown *)&c->extension_handler;
     ISAXXMLReader_putProperty(c->reader, L"http://winehq.org/sax/properties/extension-handler", v);
diff --git a/dlls/msxml3/notation.c b/dlls/msxml3/notation.c
new file mode 100644
index 000000000000..1936c568657b
--- /dev/null
+++ b/dlls/msxml3/notation.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright 2026 Nikolay Sivov for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define COBJMACROS
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "ole2.h"
+#include "msxml6.h"
+
+#include "msxml_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(msxml);
+
+struct domnotation
+{
+    DispatchEx dispex;
+    IXMLDOMNotation IXMLDOMNotation_iface;
+    LONG refcount;
+    struct domnode *node;
+};
+
+static const struct nodemap_funcs domnotation_attr_map;
+
+static const tid_t notation_se_tids[] =
+{
+    IXMLDOMNode_tid,
+    IXMLDOMNotation_tid,
+    NULL_tid
+};
+
+static inline struct domnotation *impl_from_IXMLDOMNotation(IXMLDOMNotation *iface)
+{
+    return CONTAINING_RECORD(iface, struct domnotation, IXMLDOMNotation_iface);
+}
+
+static HRESULT WINAPI domnotation_QueryInterface(IXMLDOMNotation *iface, REFIID riid, void **obj)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+    if (IsEqualGUID(riid, &IID_IXMLDOMNotation) ||
+        IsEqualGUID(riid, &IID_IXMLDOMNode) ||
+        IsEqualGUID(riid, &IID_IDispatch) ||
+        IsEqualGUID(riid, &IID_IUnknown))
+    {
+        *obj = &notation->IXMLDOMNotation_iface;
+    }
+    else if (dispex_query_interface(&notation->dispex, riid, obj))
+    {
+        return *obj ? S_OK : E_NOINTERFACE;
+    }
+    else if (node_query_interface(notation->node, riid, obj))
+    {
+        return *obj ? S_OK : E_NOINTERFACE;
+    }
+    else if (IsEqualGUID(riid, &IID_ISupportErrorInfo))
+    {
+        return node_create_supporterrorinfo(notation_se_tids, obj);
+    }
+    else
+    {
+        TRACE("interface %s not implemented\n", debugstr_guid(riid));
+        *obj = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef( (IUnknown*)*obj );
+    return S_OK;
+}
+
+static ULONG WINAPI domnotation_AddRef(IXMLDOMNotation *iface)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+    LONG refcount = InterlockedIncrement(&notation->refcount);
+
+    TRACE("%p, refcount %ld.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI domnotation_Release(IXMLDOMNotation *iface)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+    ULONG refcount = InterlockedDecrement(&notation->refcount);
+
+    TRACE("%p, refcount %ld.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        domnode_release(notation->node);
+        free(notation);
+    }
+
+    return refcount;
+}
+
+static HRESULT WINAPI domnotation_GetTypeInfoCount(IXMLDOMNotation *iface, UINT *count)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+    return IDispatchEx_GetTypeInfoCount(&notation->dispex.IDispatchEx_iface, count);
+}
+
+static HRESULT WINAPI domnotation_GetTypeInfo(IXMLDOMNotation *iface, UINT index, LCID lcid, ITypeInfo **ti)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+    return IDispatchEx_GetTypeInfo(&notation->dispex.IDispatchEx_iface, index, lcid, ti);
+}
+
+static HRESULT WINAPI domnotation_GetIDsOfNames(IXMLDOMNotation *iface, REFIID riid, LPOLESTR* rgszNames,
+    UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+    return IDispatchEx_GetIDsOfNames(&notation->dispex.IDispatchEx_iface, riid, rgszNames, cNames, lcid, rgDispId);
+}
+
+static HRESULT WINAPI domnotation_Invoke(IXMLDOMNotation *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+        WORD flags, DISPPARAMS *params, VARIANT *result, EXCEPINFO *ei, UINT *puArgErr)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+    return IDispatchEx_Invoke(&notation->dispex.IDispatchEx_iface, dispIdMember, riid, lcid, flags, params,
+            result, ei, puArgErr);
+}
+
+static HRESULT WINAPI domnotation_get_nodeName(IXMLDOMNotation *iface, BSTR *p)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, p);
+
+    return node_get_name(notation->node, p);
+}
+
+static HRESULT WINAPI domnotation_get_nodeValue(IXMLDOMNotation *iface, VARIANT *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_put_nodeValue(IXMLDOMNotation *iface, VARIANT v)
+{
+    FIXME("%p, %s: stub\n", iface, debugstr_variant(&v));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_nodeType(IXMLDOMNotation *iface, DOMNodeType *type)
+{
+    TRACE("%p, %p.\n", iface, type);
+
+    *type = NODE_NOTATION;
+    return S_OK;
+}
+
+static HRESULT WINAPI domnotation_get_parentNode(IXMLDOMNotation *iface, IXMLDOMNode **parent)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, parent);
+
+    return node_get_parent(notation->node, parent);
+}
+
+static HRESULT WINAPI domnotation_get_childNodes(IXMLDOMNotation *iface, IXMLDOMNodeList **list)
+{
+    FIXME("%p, %p: stub\n", iface, list);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_firstChild(IXMLDOMNotation *iface, IXMLDOMNode **node)
+{
+    FIXME("%p, %p: stub\n", iface, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_lastChild(IXMLDOMNotation *iface, IXMLDOMNode **node)
+{
+    FIXME("%p, %p: stub\n", iface, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_previousSibling(IXMLDOMNotation *iface, IXMLDOMNode **node)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, node);
+
+    return node_get_previous_sibling(notation->node, node);
+}
+
+static HRESULT WINAPI domnotation_get_nextSibling(IXMLDOMNotation *iface, IXMLDOMNode **node)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, node);
+
+    return node_get_next_sibling(notation->node, node);
+}
+
+static HRESULT WINAPI domnotation_get_attributes(IXMLDOMNotation *iface, IXMLDOMNamedNodeMap **map)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, map);
+
+    return create_nodemap(notation->node, &domnotation_attr_map, map);
+}
+
+static HRESULT WINAPI domnotation_insertBefore(IXMLDOMNotation *iface, IXMLDOMNode *node,
+        VARIANT refChild, IXMLDOMNode **out_node)
+{
+    FIXME("%p, %p, %s, %p: stub\n", iface, node, debugstr_variant(&refChild), out_node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_replaceChild(IXMLDOMNotation *iface, IXMLDOMNode *newNode,
+        IXMLDOMNode *oldNode, IXMLDOMNode **outOldNode)
+{
+    FIXME("%p, %p, %p, %p: stub\n", iface, newNode, oldNode, outOldNode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_removeChild(IXMLDOMNotation *iface, IXMLDOMNode *node,
+        IXMLDOMNode **oldNode)
+{
+    FIXME("%p, %p, %p: stub\n", iface, node, oldNode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_appendChild(IXMLDOMNotation *iface, IXMLDOMNode *newNode,
+        IXMLDOMNode **outNewNode)
+{
+    FIXME("%p, %p, %p: stub\n", iface, newNode, outNewNode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_hasChildNodes(IXMLDOMNotation *iface, VARIANT_BOOL *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_ownerDocument(IXMLDOMNotation *iface, IXMLDOMDocument **doc)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, doc);
+
+    return node_get_owner_document(notation->node, doc);
+}
+
+static HRESULT WINAPI domnotation_cloneNode(IXMLDOMNotation *iface, VARIANT_BOOL deep, IXMLDOMNode **node)
+{
+    FIXME("%p, %d, %p: stub\n", iface, deep, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_nodeTypeString(IXMLDOMNotation *iface, BSTR *p)
+{
+    TRACE("%p, %p.\n", iface, p);
+
+    return return_bstr(L"notation", p);
+}
+
+static HRESULT WINAPI domnotation_get_text(IXMLDOMNotation *iface, BSTR *p)
+{
+    TRACE("%p, %p.\n", iface, p);
+
+    return return_bstr(L"", p);
+}
+
+static HRESULT WINAPI domnotation_put_text(IXMLDOMNotation *iface, BSTR p)
+{
+    TRACE("%p, %s.\n", iface, debugstr_w(p));
+
+    return E_FAIL;
+}
+
+static HRESULT WINAPI domnotation_get_specified(IXMLDOMNotation *iface, VARIANT_BOOL *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_definition(IXMLDOMNotation *iface, IXMLDOMNode **node)
+{
+    FIXME("%p, %p: stub\n", iface, node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_nodeTypedValue(IXMLDOMNotation *iface, VARIANT *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_put_nodeTypedValue(IXMLDOMNotation *iface, VARIANT value)
+{
+    FIXME("%p, %s: stub\n", iface, debugstr_variant(&value));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_dataType(IXMLDOMNotation *iface, VARIANT *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_put_dataType(IXMLDOMNotation *iface, BSTR p)
+{
+    FIXME("%p, %s: stub\n", iface, debugstr_w(p));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_xml(IXMLDOMNotation *iface, BSTR *p)
+{
+    FIXME("%p, %p.\n", iface, p);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_transformNode(IXMLDOMNotation *iface, IXMLDOMNode *node, BSTR *p)
+{
+    FIXME("%p, %p, %p: stub\n", iface, node, p);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_selectNodes(IXMLDOMNotation *iface, BSTR p, IXMLDOMNodeList **list)
+{
+    FIXME("%p, %s, %p: stub\n", iface, debugstr_w(p), list);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_selectSingleNode(IXMLDOMNotation *iface, BSTR p, IXMLDOMNode **node)
+{
+    FIXME("%p, %s, %p: stub\n", iface, debugstr_w(p), node);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_parsed(IXMLDOMNotation *iface, VARIANT_BOOL *v)
+{
+    FIXME("%p, %p: stub\n", iface, v);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_namespaceURI(IXMLDOMNotation *iface, BSTR *p)
+{
+    FIXME("%p, %p: stub\n", iface, p);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_prefix(IXMLDOMNotation *iface, BSTR *prefix)
+{
+    FIXME("%p, %p: stub\n", iface, prefix);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_baseName(IXMLDOMNotation *iface, BSTR *name)
+{
+    struct domnotation *notation = impl_from_IXMLDOMNotation(iface);
+
+    TRACE("%p, %p.\n", iface, name);
+
+    return node_get_name(notation->node, name);
+}
+
+static HRESULT WINAPI domnotation_transformNodeToObject(IXMLDOMNotation *iface, IXMLDOMNode *node, VARIANT var1)
+{
+    FIXME("%p, %p, %s: stub\n", iface, node, debugstr_variant(&var1));
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_publicId(IXMLDOMNotation *iface, VARIANT *id)
+{
+    FIXME("%p, %p: stub\n", iface, id);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI domnotation_get_systemId(IXMLDOMNotation *iface, VARIANT *id)
+{
+    FIXME("%p, %p: stub\n", iface, id);
+
+    return E_NOTIMPL;
+}
+
+static const struct IXMLDOMNotationVtbl domnotation_vtbl =
+{
+    domnotation_QueryInterface,
+    domnotation_AddRef,
+    domnotation_Release,
+    domnotation_GetTypeInfoCount,
+    domnotation_GetTypeInfo,
+    domnotation_GetIDsOfNames,
+    domnotation_Invoke,
+    domnotation_get_nodeName,
+    domnotation_get_nodeValue,
+    domnotation_put_nodeValue,
+    domnotation_get_nodeType,
+    domnotation_get_parentNode,
+    domnotation_get_childNodes,
+    domnotation_get_firstChild,
+    domnotation_get_lastChild,
+    domnotation_get_previousSibling,
+    domnotation_get_nextSibling,
+    domnotation_get_attributes,
+    domnotation_insertBefore,
+    domnotation_replaceChild,
+    domnotation_removeChild,
+    domnotation_appendChild,
+    domnotation_hasChildNodes,
+    domnotation_get_ownerDocument,
+    domnotation_cloneNode,
+    domnotation_get_nodeTypeString,
+    domnotation_get_text,
+    domnotation_put_text,
+    domnotation_get_specified,
+    domnotation_get_definition,
+    domnotation_get_nodeTypedValue,
+    domnotation_put_nodeTypedValue,
+    domnotation_get_dataType,
+    domnotation_put_dataType,
+    domnotation_get_xml,
+    domnotation_transformNode,
+    domnotation_selectNodes,
+    domnotation_selectSingleNode,
+    domnotation_get_parsed,
+    domnotation_get_namespaceURI,
+    domnotation_get_prefix,
+    domnotation_get_baseName,
+    domnotation_transformNodeToObject,
+    domnotation_get_publicId,
+    domnotation_get_systemId,
+};
+
+static HRESULT domnotation_get_qualified_item(const struct domnode *node, BSTR name, BSTR uri,
+    IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    if (!name || !item)
+        return E_INVALIDARG;
+
+    return node_get_qualified_attribute(node, name, uri, item);
+}
+
+static HRESULT domnotation_get_named_item(const struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    if (!name || !item)
+        return E_INVALIDARG;
+
+    return node_get_attribute(node, name, (IXMLDOMAttribute **)item);
+}
+
+static HRESULT domnotation_set_named_item(struct domnode *node, IXMLDOMNode *newItem, IXMLDOMNode **namedItem)
+{
+    TRACE("%p, %p, %p.\n", node, newItem, namedItem );
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domnotation_remove_qualified_item(struct domnode *node, BSTR name, BSTR uri, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %s, %p.\n", node, debugstr_w(name), debugstr_w(uri), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domnotation_remove_named_item(struct domnode *node, BSTR name, IXMLDOMNode **item)
+{
+    TRACE("%p, %s, %p.\n", node, debugstr_w(name), item);
+
+    return E_INVALIDARG;
+}
+
+static HRESULT domnotation_get_item(struct domnode *node, LONG index, IXMLDOMNode **item)
+{
+    TRACE("%p, %ld, %p.\n", node, index, item);
+
+    return node_get_attribute_by_index(node, index, item);
+}
+
+static HRESULT domnotation_get_length(struct domnode *node, LONG *length)
+{
+    TRACE("%p, %p.\n", node, length);
+
+    return node_get_attribute_count(node, length);
+}
+
+static HRESULT domnotation_next_node(const struct domnode *node, LONG *iter, IXMLDOMNode **nextNode)
+{
+    FIXME("%p, %ld, %p.\n", node, *iter, nextNode);
+
+    return E_NOTIMPL;
+}
+
+static const struct nodemap_funcs domnotation_attr_map =
+{
+    .get_named_item = domnotation_get_named_item,
+    .set_named_item = domnotation_set_named_item,
+    .remove_named_item = domnotation_remove_named_item,
+    .get_item = domnotation_get_item,
+    .get_length = domnotation_get_length,
+    .get_qualified_item = domnotation_get_qualified_item,
+    .remove_qualified_item = domnotation_remove_qualified_item,
+    .next_node = domnotation_next_node,
+};
+
+static const tid_t domnotation_iface_tids[] =
+{
+    IXMLDOMNotation_tid,
+    0
+};
+
+static dispex_static_data_t domnotation_dispex =
+{
+    NULL,
+    IXMLDOMNotation_tid,
+    NULL,
+    domnotation_iface_tids
+};
+
+HRESULT create_notation(struct domnode *node, IUnknown **obj)
+{
+    struct domnotation *object;
+
+    *obj = NULL;
+
+    if (!(object = calloc(1, sizeof(*object))))
+        return E_OUTOFMEMORY;
+
+    object->IXMLDOMNotation_iface.lpVtbl = &domnotation_vtbl;
+    object->refcount = 1;
+    object->node = domnode_addref(node);
+
+    init_dispex(&object->dispex, (IUnknown *)&object->IXMLDOMNotation_iface, &domnotation_dispex);
+
+    *obj = (IUnknown *)&object->IXMLDOMNotation_iface;
+
+    return S_OK;
+}
diff --git a/dlls/msxml3/pi.c b/dlls/msxml3/pi.c
index 6f98218f1083..1931a5beba91 100644
--- a/dlls/msxml3/pi.c
+++ b/dlls/msxml3/pi.c
@@ -569,7 +569,7 @@ static HRESULT dom_pi_set_named_item(struct domnode *node, IXMLDOMNode *newItem,
 {
     TRACE("%p, %p, %p.\n", node, newItem, namedItem);
 
-    return node_set_attribute(node, newItem, namedItem);
+    return node_set_named_attribute(node, newItem, namedItem);
 }
 
 static HRESULT dom_pi_remove_qualified_item(struct domnode *node, BSTR name, BSTR uri, IXMLDOMNode **item)
@@ -597,8 +597,7 @@ static HRESULT dom_pi_get_length(struct domnode *node, LONG *length)
 {
     TRACE("%p, %p.\n", node, length);
 
-    *length = list_count(&node->attributes);
-    return S_OK;
+    return node_get_attribute_count(node, length);
 }
 
 static HRESULT dom_pi_next_node(const struct domnode *node, LONG *iter, IXMLDOMNode **nextNode)
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 9254914ca07e..2425e1615fbc 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -1283,6 +1283,15 @@ static void get_str_for_type(DOMNodeType type, char *buf)
         case NODE_CDATA_SECTION:
             strcpy(buf, "CD");
             break;
+        case NODE_DOCUMENT_TYPE:
+            strcpy(buf, "DT");
+            break;
+        case NODE_NOTATION:
+            strcpy(buf, "N");
+            break;
+        case NODE_ENTITY:
+            strcpy(buf, "EN");
+            break;
         default:
             wsprintfA(buf, "[%d]", type);
     }
@@ -3018,6 +3027,11 @@ static void test_create(void)
     ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
     ok( node == (void*)0x1, "expected same ptr, got %p\n", node);
 
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMDocument_createNode(doc, var, _bstr_("name"), NULL, &node);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    ok(node == (void *)0x1, "Unexpected value %p.\n", node);
+
     V_VT(&var) = VT_I1;
     V_I1(&var) = NODE_NOTATION;
     node = (IXMLDOMNode*)0x1;
@@ -3025,6 +3039,11 @@ static void test_create(void)
     ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
     ok( node == (void*)0x1, "expected same ptr, got %p\n", node);
 
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMDocument_createNode(doc, var, _bstr_("name"), NULL, &node);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    ok(node == (void *)0x1, "Unexpected value %p.\n", node);
+
     /* NODE_COMMENT */
     V_VT(&var) = VT_I1;
     V_I1(&var) = NODE_COMMENT;
@@ -4770,6 +4789,55 @@ static void test_IXMLDOMDocument2(void)
     ok(!wcscmp(V_BSTR(&var), L"XSLPattern"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
     VariantClear(&var);
 
+    /* Empty or null value will reset a property. */
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(L"xmlns:ns=\'uri\'");
+    hr = IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"xmlns:ns=\'uri\'"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = NULL;
+    hr = IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L""), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(L"xmlns:ns=\'uri\'");
+    hr = IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"xmlns:ns=\'uri\'"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(L"");
+    hr = IXMLDOMDocument2_setProperty(doc2, _bstr_("SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L""), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
     IXMLDOMDocument2_Release( doc2 );
     IXMLDOMDocument_Release( doc );
     free_bstrs();
@@ -16644,6 +16712,8 @@ static void test_xmldecl_attributes(void)
     ok(!wcscmp(str, L""), "Unexpected string %s.\n", debugstr_w(str));
     SysFreeString(str);
 
+    hr = IXMLDOMNamedNodeMap_get_length(map, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
     hr = IXMLDOMNamedNodeMap_get_length(map, &length);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!length, "Unexpected length %ld.\n", length);
@@ -16658,8 +16728,14 @@ static void test_xmldecl_attributes(void)
     hr = IXMLDOMAttribute_put_text(attr, _bstr_("no"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    hr = IXMLDOMNamedNodeMap_setNamedItem(map, (IXMLDOMNode *)attr, NULL);
+    /* Insert new attribute */
+    hr = IXMLDOMNamedNodeMap_setNamedItem(map, (IXMLDOMNode *)attr, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"no"), "Unexpected node text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMNode_Release(node);
     IXMLDOMAttribute_Release(attr);
 
     hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
@@ -16730,6 +16806,22 @@ static void test_xmldecl_attributes(void)
     ok(!wcscmp(str, L"<?xml version=\"2.0abc\" standalone=\"no\"?>"), "Unexpected string %s.\n", debugstr_w(str));
     SysFreeString(str);
 
+    /* Replace existing attribute */
+    hr = IXMLDOMDocument_createAttribute(doc, _bstr_("encoding"), &attr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMAttribute_put_text(attr, _bstr_("utf-16"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNamedNodeMap_setNamedItem(map, (IXMLDOMNode *)attr, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"utf-16"), "Unexpected node text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMAttribute_Release(attr);
+
     IXMLDOMNamedNodeMap_Release(map);
 
     IXMLDOMProcessingInstruction_Release(pi);
@@ -17732,9 +17824,7 @@ if (hr == S_OK)
 
     b = VARIANT_TRUE;
     hr = IXMLDOMDocumentType_hasChildNodes(doctype, &b);
-    todo_wine
     ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
-    todo_wine
     ok(b == VARIANT_FALSE, "Unexpected value %d\n", b);
 
     IXMLDOMDocumentType_Release(doctype);
@@ -17801,6 +17891,465 @@ static void test_entityref(void)
     free_bstrs();
 }
 
+static void test_dtd_children(void)
+{
+    static const char xml_dtd[] =
+        "<?xml version=\"1.0\" ?>\n"
+        "<!DOCTYPE a [\n"
+        "<!NOTATION notation0 PUBLIC \"pub-id\" \"sys-id\" >\n"
+        "<!ENTITY ent1 SYSTEM \"sys-id\" NDATA notation0 >\n"
+        "<!ENTITY % ent1 \"sys-id\" >\n"
+        "<!ENTITY % ent2 SYSTEM \"sys-id-2\" >\n"
+        "<!NOTATION notation1 PUBLIC \"pub-id\" \"sys-id\" >\n"
+        "<!ELEMENT a ANY>\n"
+        "]>\n"
+        "<a></a>";
+
+    IXMLDOMDocumentType *doctype;
+    IXMLDOMNode *node, *node2;
+    IXMLDOMNamedNodeMap *map;
+    IXMLDOMNodeList *list;
+    IXMLDOMDocument *doc;
+    VARIANT_BOOL b;
+    HRESULT hr;
+    LONG len;
+    BSTR str;
+
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_(xml_dtd), NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_doctype(doc, &doctype);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    b = VARIANT_FALSE;
+    hr = IXMLDOMDocumentType_hasChildNodes(doctype, &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_TRUE, "Unexpected value %d\n", b);
+
+    hr = IXMLDOMDocumentType_get_firstChild(doctype, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expect_node(node, "N1.DT2.D1");
+    hr = IXMLDOMDocumentType_removeChild(doctype, node, &node2);
+    todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMDocumentType_get_lastChild(doctype, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    expect_node(node, "N3.DT2.D1");
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMDocumentType_get_childNodes(doctype, &list);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNodeList_get_length(list, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 3, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNodeList_nextNode(list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    expect_node(node, "N1.DT2.D1");
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNodeList_nextNode(list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeTypeString(node, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeTypeString(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"entity"), "Unexpected type %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    expect_node(node, "EN2.DT2.D1");
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNodeList_nextNode(list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    expect_node(node, "N3.DT2.D1");
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMNodeList_Release(list);
+
+    /* Maps */
+    hr = IXMLDOMDocumentType_get_entities(doctype, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNamedNodeMap_get_length(map, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 1, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"ent1"), "Unexpected name %s.\n", debugstr_w(str));
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, str, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, str, &node2);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    SysFreeString(str);
+
+    IXMLDOMNode_Release(node);
+    IXMLDOMNamedNodeMap_Release(map);
+
+    hr = IXMLDOMDocumentType_get_notations(doctype, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNamedNodeMap_get_length(map, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 2, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"notation0"), "Unexpected name %s.\n", debugstr_w(str));
+
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, str, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, str, &node2);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    SysFreeString(str);
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMNamedNodeMap_Release(map);
+
+    IXMLDOMDocumentType_Release(doctype);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_dtd_notation(void)
+{
+    static const char xml_dtd[] =
+        "<?xml version=\"1.0\" ?>\n"
+        "<!DOCTYPE a [\n"
+        "<!NOTATION notation0 PUBLIC  \"pub-id-0\" \"sys-id-0\" >\n"
+        "<!NOTATION notation1  PUBLIC \"pub-id-1\" >\n"
+        "<!ELEMENT a ANY>\n"
+        "]>\n"
+        "<a></a>";
+
+    IXMLDOMDocumentType *doctype;
+    IXMLDOMNode *node, *node2;
+    IXMLDOMNamedNodeMap *map;
+    DOMNodeType node_type;
+    IXMLDOMDocument *doc;
+    HRESULT hr;
+    BSTR str;
+    LONG len;
+
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_(xml_dtd), NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_doctype(doc, &doctype);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentType_get_firstChild(doctype, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"notation0"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_get_baseName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"notation0"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_get_nodeType(node, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_NOTATION, "Unexpected type %d.\n", node_type);
+
+    hr = IXMLDOMNode_get_nodeTypeString(node, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeTypeString(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"notation"), "Unexpected type %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    /* Text property */
+    hr = IXMLDOMNode_get_text(node, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!*str, "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_put_text(node, NULL);
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_put_text(node, _bstr_("text"));
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    /* XML property */
+    hr = IXMLDOMDocumentType_get_firstChild(doctype, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_xml(node, &str);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+if (hr == S_OK)
+{
+    ok(!wcscmp(str, L"<!NOTATION notation0 PUBLIC \"pub-id-0\" \"sys-id-0\">"), "Unexpected type %s.\n", debugstr_w(str));
+    SysFreeString(str);
+}
+
+    /* Notation attributes */
+    hr = IXMLDOMNode_get_attributes(node, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNamedNodeMap_get_length(map, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNamedNodeMap_get_length(map, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 2, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeType(node2, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_ATTRIBUTE, "Unexpected type %d.\n", node_type);
+    EXPECT_CHILDREN(node2);
+    hr = IXMLDOMNode_get_nodeName(node2, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"PUBLIC"), "Unexpected name %s.\n", debugstr_w(str));
+    IXMLDOMNode_Release(node2);
+    SysFreeString(str);
+
+    hr = IXMLDOMNamedNodeMap_get_item(map, 1, &node2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeName(node2, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"SYSTEM"), "Unexpected name %s.\n", debugstr_w(str));
+    IXMLDOMNode_Release(node2);
+    SysFreeString(str);
+
+    IXMLDOMNamedNodeMap_Release(map);
+
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMDocumentType_get_lastChild(doctype, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_xml(node, &str);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+if (hr == S_OK)
+{
+    ok(!wcscmp(str, L"<!NOTATION notation1 PUBLIC \"pub-id-1\">"), "Unexpected type %s.\n", debugstr_w(str));
+    SysFreeString(str);
+}
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMDocumentType_Release(doctype);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_dtd_entity(void)
+{
+    static const char xml_dtd[] =
+        "<?xml version=\"1.0\" ?>\n"
+        "<!DOCTYPE a [\n"
+        "<!NOTATION notation0 PUBLIC \"pub-id\" \"sys-id\" >\n"
+        "<!ENTITY ent1 SYSTEM \"sys-id\" NDATA notation0 >\n"
+        "<!ENTITY % ent1 \"sys-id\" >\n"
+        "<!ENTITY % ent2 SYSTEM \"sys-id-2\" >\n"
+        "<!ENTITY ent3 \"text3\" >\n"
+        "<!ELEMENT a ANY>\n"
+        "]>\n"
+        "<a></a>";
+
+    IXMLDOMDocumentType *doctype;
+    IXMLDOMNode *node, *node2;
+    IXMLDOMNamedNodeMap *map;
+    DOMNodeType node_type;
+    IXMLDOMNodeList *list;
+    IXMLDOMDocument *doc;
+    HRESULT hr;
+    BSTR str;
+    LONG len;
+
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_(xml_dtd), NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_doctype(doc, &doctype);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentType_get_childNodes(doctype, &list);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNodeList_get_length(list, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 3, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNodeList_get_item(list, 1, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"ent1"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_get_nodeType(node, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_ENTITY, "Unexpected type %d.\n", node_type);
+
+    hr = IXMLDOMNode_get_nodeTypeString(node, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeTypeString(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"entity"), "Unexpected type %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    /* Text property */
+    hr = IXMLDOMNode_get_text(node, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!*str, "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_put_text(node, NULL);
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_put_text(node, _bstr_("text"));
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNode_get_xml(node, &str);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+if (hr == S_OK)
+{
+    ok(!wcscmp(str, L"<!ENTITY ent1 SYSTEM \"sys-id\" NDATA notation0>"), "Unexpected type %s.\n", debugstr_w(str));
+    SysFreeString(str);
+}
+    /* Entity attributes */
+    hr = IXMLDOMNode_get_attributes(node, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNamedNodeMap_get_length(map, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNamedNodeMap_get_length(map, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 2, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeType(node2, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_ATTRIBUTE, "Unexpected type %d.\n", node_type);
+    EXPECT_CHILDREN(node2);
+    hr = IXMLDOMNode_get_nodeName(node2, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"SYSTEM"), "Unexpected name %s.\n", debugstr_w(str));
+    IXMLDOMNode_Release(node2);
+    SysFreeString(str);
+
+    hr = IXMLDOMNamedNodeMap_get_item(map, 1, &node2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeName(node2, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"NDATA"), "Unexpected name %s.\n", debugstr_w(str));
+    IXMLDOMNode_Release(node2);
+    SysFreeString(str);
+
+    IXMLDOMNamedNodeMap_Release(map);
+    IXMLDOMNode_Release(node);
+
+    /* Character entity */
+    hr = IXMLDOMNodeList_get_item(list, 2, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNode_get_attributes(node, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNamedNodeMap_get_length(map, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!len, "Unexpected length %ld.\n", len);
+    IXMLDOMNamedNodeMap_Release(map);
+
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"ent3"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    /* Text property */
+    hr = IXMLDOMNode_get_text(node, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"text3"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMNodeList_Release(list);
+
+    IXMLDOMDocumentType_Release(doctype);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_element_setNamedItem(void)
+{
+    IXMLDOMAttribute *attr1, *attr2;
+    IXMLDOMNamedNodeMap *map;
+    IXMLDOMElement *element;
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *node;
+    HRESULT hr;
+    BSTR str;
+
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    hr = IXMLDOMDocument_createElement(doc, _bstr_("e"), &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_get_attributes(element, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createAttribute(doc, _bstr_("attr"), &attr1);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMAttribute_put_text(attr1, _bstr_("text1"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createAttribute(doc, _bstr_("attr"), &attr2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMAttribute_put_text(attr2, _bstr_("text2"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* New attribute */
+    hr = IXMLDOMNamedNodeMap_setNamedItem(map, (IXMLDOMNode *)attr1, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"text1"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNamedNodeMap_setNamedItem(map, (IXMLDOMNode *)attr2, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_text(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"text2"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMAttribute_Release(attr1);
+    IXMLDOMAttribute_Release(attr2);
+
+    IXMLDOMNamedNodeMap_Release(map);
+    IXMLDOMElement_Release(element);
+    IXMLDOMDocument_Release(doc);
+    free_bstrs();
+}
+
 START_TEST(domdoc)
 {
     HRESULT hr;
@@ -17911,6 +18460,10 @@ START_TEST(domdoc)
     test_dtd_validation();
     test_doctype();
     test_entityref();
+    test_dtd_children();
+    test_dtd_notation();
+    test_dtd_entity();
+    test_element_setNamedItem();
 
     if (is_clsid_supported(&CLSID_MXNamespaceManager40, &IID_IMXNamespaceManager))
     {
diff --git a/dlls/msxml3/xpath.c b/dlls/msxml3/xpath.c
index f2cb685e5c99..3033a2f7954b 100644
--- a/dlls/msxml3/xpath.c
+++ b/dlls/msxml3/xpath.c
@@ -7749,6 +7749,9 @@ HRESULT xpath_parse_selection_namespaces(const WCHAR *value, struct domdoc_prope
     HRESULT hr = S_OK;
     WCHAR *uri;
 
+    if (!value)
+        return S_OK;
+
     ctxt.cur = ctxt.base = value;
 
     while (*ctxt.cur)
diff --git a/dlls/msxml6/tests/domdoc.c b/dlls/msxml6/tests/domdoc.c
index 996b214ffe15..82b58a588438 100644
--- a/dlls/msxml6/tests/domdoc.c
+++ b/dlls/msxml6/tests/domdoc.c
@@ -1277,6 +1277,69 @@ static void test_max_element_depth_values(void)
     free_bstrs();
 }
 
+static void test_selection_namespaces(void)
+{
+    IXMLDOMDocument2 *doc;
+    VARIANT var;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IXMLDOMDocument2, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* Empty or null value will reset a property. */
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(L"xmlns:ns=\'uri\'");
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_(L"SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_(L"SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"xmlns:ns=\'uri\'"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = NULL;
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_(L"SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_(L"SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L""), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(L"xmlns:ns=\'uri\'");
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_(L"SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_(L"SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"xmlns:ns=\'uri\'"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    V_VT(&var) = VT_BSTR;
+    V_BSTR(&var) = SysAllocString(L"");
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_(L"SelectionNamespaces"), var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    memset(&var, 0, sizeof(var));
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_(L"SelectionNamespaces"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L""), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    IXMLDOMDocument2_Release(doc);
+    free_bstrs();
+}
+
 START_TEST(domdoc)
 {
     HRESULT hr;
@@ -1303,6 +1366,7 @@ START_TEST(domdoc)
     test_interfaces();
     test_dtd_validation();
     test_max_element_depth_values();
+    test_selection_namespaces();
 
     CoUninitialize();
 }
diff --git a/dlls/ncrypt/Makefile.in b/dlls/ncrypt/Makefile.in
index 9b63d5e511fd..86e57733f61c 100644
--- a/dlls/ncrypt/Makefile.in
+++ b/dlls/ncrypt/Makefile.in
@@ -2,7 +2,5 @@ IMPORTLIB = ncrypt
 MODULE    = ncrypt.dll
 IMPORTS   = bcrypt
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	main.c
diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c
index 1ced62bf6087..d6c5fb7c01ab 100644
--- a/dlls/ntdll/env.c
+++ b/dlls/ntdll/env.c
@@ -682,7 +682,7 @@ void init_user_process_params(void)
     WCHAR *env;
     SIZE_T size = 0, env_size;
     RTL_USER_PROCESS_PARAMETERS *new_params, *params = NtCurrentTeb()->Peb->ProcessParameters;
-    UNICODE_STRING curdir;
+    UNICODE_STRING curdir = { 0 };
 
     /* environment needs to be a separate memory block */
     env_size = params->EnvironmentSize;
@@ -692,8 +692,9 @@ void init_user_process_params(void)
         else env[0] = 0;
     }
 
+    curdir.MaximumLength = params->CurrentDirectory.DosPath.MaximumLength;
     if (!(new_params = alloc_process_params( 1, &params->ImagePathName, &params->DllPath,
-                                             &params->CurrentDirectory.DosPath, &params->CommandLine,
+                                             &curdir, &params->CommandLine,
                                              NULL, &params->WindowTitle, &params->Desktop,
                                              &params->ShellInfo, &params->RuntimeInfo )))
         return;
@@ -718,15 +719,14 @@ void init_user_process_params(void)
     new_params->ProcessGroupId  = params->ProcessGroupId;
 
     NtCurrentTeb()->Peb->ProcessParameters = new_params;
-    NtFreeVirtualMemory( GetCurrentProcess(), (void **)&params, &size, MEM_RELEASE );
-
-    if (RtlSetCurrentDirectory_U( &new_params->CurrentDirectory.DosPath ))
+    if (RtlSetCurrentDirectory_U( &params->CurrentDirectory.DosPath ))
     {
         MESSAGE("wine: could not open working directory %s, starting in the Windows directory.\n",
-                debugstr_w( new_params->CurrentDirectory.DosPath.Buffer ));
+                debugstr_w( params->CurrentDirectory.DosPath.Buffer ));
         RtlInitUnicodeString( &curdir, windows_dir );
         RtlSetCurrentDirectory_U( &curdir );
     }
+    NtFreeVirtualMemory( GetCurrentProcess(), (void **)&params, &size, MEM_RELEASE );
     set_wow64_environment( &new_params->Environment );
     new_params->EnvironmentSize = RtlSizeHeap( GetProcessHeap(), 0, new_params->Environment );
 }
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 443b98411707..d8b7a92bade6 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -127,6 +127,7 @@ static const char * const reason_names[] =
 struct file_id
 {
     BYTE ObjectId[16];
+    BYTE BirthVolumeId[16];
 };
 
 #define HASH_MAP_SIZE 32
@@ -2723,7 +2724,8 @@ static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDL
 
     if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
     {
-        memcpy( id, fid.ObjectId, sizeof(*id) );
+        memcpy( id->ObjectId, fid.ObjectId, sizeof(id->ObjectId) );
+        memcpy( id->BirthVolumeId, fid.BirthVolumeId, sizeof(id->BirthVolumeId) );
         if ((*pwm = find_fileid_module( id )))
         {
             TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
diff --git a/dlls/ntdll/path.c b/dlls/ntdll/path.c
index 9a511f8e11ce..b95a5ebf0f1a 100644
--- a/dlls/ntdll/path.c
+++ b/dlls/ntdll/path.c
@@ -958,7 +958,7 @@ ULONG WINAPI RtlGetCurrentDirectory_U(ULONG buflen, LPWSTR buf)
         us = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory.DosPath;
 
     len = us->Length / sizeof(WCHAR);
-    if (us->Buffer[len - 1] == '\\' && us->Buffer[len - 2] != ':')
+    if (len && us->Buffer[len - 1] == '\\' && us->Buffer[len - 2] != ':')
         len--;
 
     if (buflen / sizeof(WCHAR) > len)
@@ -984,6 +984,7 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir)
 {
     FILE_FS_DEVICE_INFORMATION device_info;
     HANDLE handle, old_handle;
+    WCHAR cur_path[MAX_PATH];
     OBJECT_ATTRIBUTES attr;
     UNICODE_STRING newdir;
     IO_STATUS_BLOCK io;
@@ -994,6 +995,16 @@ NTSTATUS WINAPI RtlSetCurrentDirectory_U(const UNICODE_STRING* dir)
 
     newdir.Buffer = NULL;
 
+    if (RtlGetCurrentDirectory_U( sizeof(cur_path), cur_path ) < sizeof(cur_path))
+    {
+        size = wcslen( cur_path ) * sizeof(*cur_path);
+        if (dir->Length == size && !memcmp( dir->Buffer, cur_path, size ))
+        {
+            TRACE( "same directory.\n" );
+            return STATUS_SUCCESS;
+        }
+    }
+
     if (!RtlDosPathNameToNtPathName_U( dir->Buffer, &newdir, NULL, NULL )) return STATUS_OBJECT_NAME_INVALID;
 
     InitializeObjectAttributes( &attr, &newdir, OBJ_CASE_INSENSITIVE, 0, NULL );
diff --git a/dlls/ntdll/tests/alpc.c b/dlls/ntdll/tests/alpc.c
index f34da2090417..39b8b02526fd 100644
--- a/dlls/ntdll/tests/alpc.c
+++ b/dlls/ntdll/tests/alpc.c
@@ -29,6 +29,7 @@
 DECL_FUNCPTR(AlpcGetHeaderSize)
 DECL_FUNCPTR(AlpcGetMessageAttribute)
 DECL_FUNCPTR(AlpcInitializeMessageAttribute)
+DECL_FUNCPTR(NtAlpcCreatePort)
 
 #undef DECL_FUNCPTR
 
@@ -44,10 +45,27 @@ static void init_functions(void)
     LOAD_FUNCPTR(AlpcGetHeaderSize)
     LOAD_FUNCPTR(AlpcGetMessageAttribute)
     LOAD_FUNCPTR(AlpcInitializeMessageAttribute)
+    LOAD_FUNCPTR(NtAlpcCreatePort)
 
 #undef LOAD_FUNCPTR
 }
 
+static void init_port_attr(ALPC_PORT_ATTRIBUTES *attr, ULONG flags, SIZE_T max_msg_length)
+{
+    attr->Flags = flags;
+    attr->SecurityQos.Length = sizeof(attr->SecurityQos);
+    attr->SecurityQos.ImpersonationLevel = SecurityIdentification;
+    attr->SecurityQos.ContextTrackingMode = SECURITY_STATIC_TRACKING;
+    attr->SecurityQos.EffectiveOnly = FALSE;
+    attr->MaxMessageLength = max_msg_length;
+    attr->MemoryBandwidth = 512;
+    attr->MaxPoolUsage = 0xffffffff;
+    attr->MaxSectionSize = 0xffffffff;
+    attr->MaxViewSize = 0xffffffff;
+    attr->MaxTotalSectionSize = 0xffffffff;
+    attr->DupObjectTypes = (flags & ALPC_PORTFLG_ALLOW_DUP_OBJECT) ? 0xffffffff : 0;
+}
+
 static void test_AlpcGetHeaderSize(void)
 {
     unsigned int i, j;
@@ -342,6 +360,119 @@ static void test_AlpcInitializeMessageAttribute(void)
     }
 }
 
+static void test_NtAlpcCreatePort(void)
+{
+    UNICODE_STRING name = RTL_CONSTANT_STRING(L"\\BaseNamedObjects\\test_NtAlpcCreatePort_port");
+    OBJECT_NAME_INFORMATION *name_info;
+    OBJECT_TYPE_INFORMATION *type_info;
+    ALPC_PORT_ATTRIBUTES port_attr;
+    OBJECT_BASIC_INFORMATION info;
+    unsigned char buffer[1024];
+    HANDLE handle, handle2;
+    OBJECT_ATTRIBUTES attr;
+    DWORD size, flags;
+    NTSTATUS status;
+    ULONG flag;
+    BOOL ret;
+
+    if (!pNtAlpcCreatePort)
+    {
+        win_skip("NtAlpcCreatePort is unavailable.\n");
+        return;
+    }
+
+    InitializeObjectAttributes(&attr, &name, 0, NULL, NULL);
+    init_port_attr(&port_attr, 0, 1024);
+
+    /* Check parameters */
+    status = pNtAlpcCreatePort(NULL, &attr, &port_attr);
+    ok(status == STATUS_ACCESS_VIOLATION, "Got unexpected status %#lx.\n", status);
+
+    status = pNtAlpcCreatePort(&handle, NULL, &port_attr);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+    ret = GetHandleInformation(handle, &flags);
+    ok(ret, "GetHandleInformation failed, error %ld.\n", GetLastError());
+    CloseHandle(handle);
+
+    status = pNtAlpcCreatePort(&handle, &attr, NULL);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+    ret = GetHandleInformation(handle, &flags);
+    ok(ret, "GetHandleInformation failed, error %ld.\n", GetLastError());
+    CloseHandle(handle);
+
+    status = pNtAlpcCreatePort(&handle, NULL, NULL);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+    ret = GetHandleInformation(handle, &flags);
+    ok(ret, "GetHandleInformation failed, error %ld.\n", GetLastError());
+    CloseHandle(handle);
+
+    /* Normal calls */
+    status = pNtAlpcCreatePort(&handle, &attr, &port_attr);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+
+    /* Check handle */
+    ret = GetHandleInformation(handle, &flags);
+    ok(ret, "GetHandleInformation failed, error %ld.\n", GetLastError());
+
+    /* Check object attributes and granted access */
+    status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info), NULL);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+    ok(info.Attributes == 0, "Got attributes %#lx\n", info.Attributes);
+    ok(info.GrantedAccess == (STANDARD_RIGHTS_ALL | 0x1), "Got access %#lx\n", info.GrantedAccess);
+
+    /* Check object name */
+    status = NtQueryObject(handle, ObjectNameInformation, buffer, sizeof(buffer), &size);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+    name_info = (OBJECT_NAME_INFORMATION *)buffer;
+    ok(!wcsicmp(name_info->Name.Buffer, name.Buffer), "Got unexpected name %s.\n",
+       debugstr_w(name_info->Name.Buffer));
+
+    /* Check object type */
+    status = NtQueryObject(handle, ObjectTypeInformation, buffer, sizeof(buffer), &size);
+    ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+    type_info = (OBJECT_TYPE_INFORMATION *)buffer;
+    ok(!wcscmp(type_info->TypeName.Buffer, L"ALPC Port"), "Got unexpected type %s.\n",
+       debugstr_w(type_info->TypeName.Buffer));
+
+    /* Duplicate name */
+    status = pNtAlpcCreatePort(&handle2, &attr, &port_attr);
+    ok(status == STATUS_OBJECT_NAME_COLLISION, "Got unexpected status %#lx.\n", status);
+
+    CloseHandle(handle);
+
+    /* Test handle validity after deletion */
+    ret = GetHandleInformation(handle, &flags);
+    ok(!ret, "GetHandleInformation succeeded.\n");
+
+    /* Test Flags */
+    for (flag = 0x1; flag != 0; flag = flag << 1)
+    {
+        winetest_push_context("%#lx", flag);
+
+        port_attr.Flags = flag;
+        status = pNtAlpcCreatePort(&handle, &attr, &port_attr);
+        if (flag == 0x100000)
+        {
+            ok(status == STATUS_INVALID_PARAMETER, "Got unexpected status %#lx.\n", status);
+            winetest_pop_context();
+            continue;
+        }
+        else
+        {
+            ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+        }
+        ret = GetHandleInformation(handle, &flags);
+        ok(ret, "GetHandleInformation failed, error %ld.\n", GetLastError());
+        status = NtQueryObject(handle, ObjectBasicInformation, &info, sizeof(info), NULL);
+        ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+        ok(info.Attributes == 0, "Got attributes %#lx\n", info.Attributes);
+        ok(info.GrantedAccess == (STANDARD_RIGHTS_ALL | 0x1), "Got access %#lx\n", info.GrantedAccess);
+
+        CloseHandle(handle);
+        winetest_pop_context();
+    }
+}
+
 START_TEST(alpc)
 {
     init_functions();
@@ -349,4 +480,5 @@ START_TEST(alpc)
     test_AlpcGetHeaderSize();
     test_AlpcGetMessageAttribute();
     test_AlpcInitializeMessageAttribute();
+    test_NtAlpcCreatePort();
 }
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 049efb955189..f741ffbfd3c6 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4798,11 +4798,15 @@ static void test_query_volume_information_file(void)
     NTSTATUS status;
     HANDLE dir;
     WCHAR path[MAX_PATH];
+    WCHAR drives[MAX_PATH];
+    WCHAR *drive;
+    WCHAR sysdrive[4];
     OBJECT_ATTRIBUTES attr;
     IO_STATUS_BLOCK io;
     UNICODE_STRING nameW;
     FILE_FS_VOLUME_INFORMATION *ffvi;
     BYTE buf[sizeof(FILE_FS_VOLUME_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
+    DWORD count;
 
     GetWindowsDirectoryW( path, MAX_PATH );
     pRtlDosPathNameToNtPathName_U( path, &nameW, NULL, NULL );
@@ -4836,6 +4840,50 @@ static void test_query_volume_information_file(void)
     trace("VolumeSerialNumber: %lx VolumeLabelName: %s\n", ffvi->VolumeSerialNumber, wine_dbgstr_w(ffvi->VolumeLabel));
 
     CloseHandle( dir );
+
+    GetSystemDirectoryW( sysdrive, ARRAY_SIZE(sysdrive) );
+    count = GetLogicalDriveStringsW( ARRAY_SIZE(drives), drives );
+    ok( count && count < ARRAY_SIZE(drives), "GetLogicalDriveStringsW returned %lu\n", count );
+
+    for (drive = drives; *drive; drive += lstrlenW(drive) + 1)
+    {
+        UINT type = GetDriveTypeW( drive );
+        HANDLE root;
+
+        if ((drive[0] | 0x20) == (sysdrive[0] | 0x20)) continue;
+        if (type != DRIVE_FIXED && type != DRIVE_REMOTE && type != DRIVE_RAMDISK)
+            continue;
+
+        root = CreateFileW( drive, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,
+                            OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL );
+        if (root == INVALID_HANDLE_VALUE)
+        {
+            skip( "cannot open %s: %lu\n", wine_dbgstr_w(drive), GetLastError() );
+            continue;
+        }
+
+        ZeroMemory( buf, sizeof(buf) );
+        io.Status = 0xdadadada;
+        io.Information = 0xcacacaca;
+
+        status = pNtQueryVolumeInformationFile( root, &io, buf, sizeof(buf),
+                                                FileFsVolumeInformation );
+        ok( status == STATUS_SUCCESS,
+            "NtQueryVolumeInformationFile(FileFsVolumeInformation) on %s returned %lx\n",
+            wine_dbgstr_w(drive), status );
+        ok( io.Status == STATUS_SUCCESS,
+            "io.Status on %s is %lx\n", wine_dbgstr_w(drive), io.Status );
+        if (status == STATUS_SUCCESS)
+        {
+            ok( io.Information == (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel)
+                                   + ffvi->VolumeLabelLength),
+                "expected %ld, got %Iu on %s\n",
+                (FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + ffvi->VolumeLabelLength),
+                io.Information, wine_dbgstr_w(drive) );
+        }
+
+        CloseHandle( root );
+    }
 }
 
 static void test_query_attribute_information_file(void)
diff --git a/dlls/ntdll/tests/om.c b/dlls/ntdll/tests/om.c
index 7f16584d911f..61919d9c3656 100644
--- a/dlls/ntdll/tests/om.c
+++ b/dlls/ntdll/tests/om.c
@@ -2199,6 +2199,9 @@ static void test_token(void)
     pNtClose( handle );
 }
 
+#define ALPC_PORT_GENERIC_EXECUTE     0
+#define ALPC_PORT_GENERIC_READ        (STANDARD_RIGHTS_READ|0x1)
+#define ALPC_PORT_GENERIC_WRITE       (DELETE|0x1)
 #define DEBUG_GENERIC_EXECUTE         (STANDARD_RIGHTS_EXECUTE|SYNCHRONIZE)
 #define DEBUG_GENERIC_READ            (STANDARD_RIGHTS_READ|DEBUG_READ_EVENT)
 #define DEBUG_GENERIC_WRITE           (STANDARD_RIGHTS_WRITE|DEBUG_PROCESS_ASSIGN)
@@ -2330,6 +2333,7 @@ static void test_object_types(void)
     {
 #define TYPE(name,gen,extra,broken) { name, { gen ## _GENERIC_READ, gen ## _GENERIC_WRITE, \
                 gen ## _GENERIC_EXECUTE, gen ## _ALL_ACCESS }, gen ## _ALL_ACCESS | extra, broken }
+        TYPE( L"ALPC Port",     ALPC_PORT, 0, 0 ),
         TYPE( L"DebugObject",   DEBUG, 0, 0 ),
         TYPE( L"Desktop",       DESKTOP, 0, 0 ),
         TYPE( L"Device",        FILE, 0, 0 ),
diff --git a/dlls/ntdll/tests/path.c b/dlls/ntdll/tests/path.c
index bee7a20c43e0..901e772a704d 100644
--- a/dlls/ntdll/tests/path.c
+++ b/dlls/ntdll/tests/path.c
@@ -739,6 +739,81 @@ static void test_nt_names(void)
     }
 }
 
+static void test_RtlSetCurrentDirectory_U(void)
+{
+    CURDIR *cd = &NtCurrentTeb()->Peb->ProcessParameters->CurrentDirectory;
+    WCHAR curdir[MAX_PATH], name[MAX_PATH + 4];
+    HANDLE prev_handle;
+    UNICODE_STRING us;
+    unsigned int len;
+    NTSTATUS status;
+    BOOL bret;
+
+    bret = GetCurrentDirectoryW( ARRAY_SIZE(curdir), curdir );
+    ok( bret, "got error %ld.\n", GetLastError() );
+    ok( curdir[wcslen(curdir) - 1] != '\\' || curdir[wcslen(curdir) - 2] == ':', "got %s.\n", debugstr_w(curdir));
+    ok( !!cd->Handle && cd->Handle != INVALID_HANDLE_VALUE, "got %p.\n", cd->Handle );
+    len = cd->DosPath.Length / sizeof(WCHAR);
+    ok( cd->DosPath.Buffer[len - 1] == '\\' , "got %s.\n", debugstr_wn(cd->DosPath.Buffer, len) );
+
+    prev_handle = cd->Handle;
+    RtlInitUnicodeString( &us, curdir );
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle == prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+
+    prev_handle = cd->Handle;
+    cd->DosPath.Length = 0;
+    cd->DosPath.Buffer[0] = 0;
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle != prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+
+    prev_handle = cd->Handle;
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle == prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+    prev_handle = cd->Handle;
+
+    wcscpy( name, L"." );
+    RtlInitUnicodeString( &us, name );
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle != prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+    prev_handle = cd->Handle;
+    wcscpy( name, L"\\\\?\\" );
+    wcscat( name, curdir );
+    RtlInitUnicodeString( &us, name );
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle != prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+    prev_handle = cd->Handle;
+
+    wcscat( curdir, L"\\" );
+    RtlInitUnicodeString( &us, curdir );
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle != prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+
+    wcscpy( name, curdir );
+    wcscat( name, L"cdtestdir1" );
+    bret = CreateDirectoryW( L"cdtestdir1", NULL );
+    ok( bret, "got %ld.\n", GetLastError() );
+
+    prev_handle = cd->Handle;
+    RtlInitUnicodeString( &us, name );
+    status = RtlSetCurrentDirectory_U( &us );
+    ok( !status, "got %#lx.\n", status );
+    ok( cd->Handle != prev_handle, "got %p, %p.\n", cd->Handle, prev_handle );
+
+    bret = MoveFileW( L"..\\cdtestdir1", L"..\\cdtestdir2" );
+    ok( !bret && GetLastError() == ERROR_SHARING_VIOLATION, "got bret %d, error %ld.\n", bret, GetLastError() );
+
+    bret = SetCurrentDirectoryW( curdir );
+    ok( bret, "got error %ld.\n", GetLastError() );
+    bret = RemoveDirectoryW( L"cdtestdir1" );
+    ok( bret, "got error %ld.\n", GetLastError() );
+}
 
 START_TEST(path)
 {
@@ -755,6 +830,7 @@ START_TEST(path)
     pRtlDosPathNameToNtPathName_U_WithStatus = (void *)GetProcAddress(mod, "RtlDosPathNameToNtPathName_U_WithStatus");
     pNtOpenFile             = (void *)GetProcAddress(mod, "NtOpenFile");
 
+    test_RtlSetCurrentDirectory_U();
     test_RtlDetermineDosPathNameType_U();
     test_RtlIsDosDeviceName_U();
     test_RtlIsNameLegalDOS8Dot3();
diff --git a/dlls/ntdll/unix/alpc.c b/dlls/ntdll/unix/alpc.c
index c708b5880111..513a4b296fb9 100644
--- a/dlls/ntdll/unix/alpc.c
+++ b/dlls/ntdll/unix/alpc.c
@@ -24,6 +24,7 @@
 
 #include "ntstatus.h"
 #include "wine/debug.h"
+#include "wine/server.h"
 #include "unix_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(alpc);
@@ -52,10 +53,61 @@ NTSTATUS WINAPI NtAlpcConnectPort( HANDLE *port_handle, UNICODE_STRING *port_nam
     return STATUS_NOT_IMPLEMENTED;
 }
 
-NTSTATUS WINAPI NtAlpcCreatePort( HANDLE *port_handle, OBJECT_ATTRIBUTES *obj_attr, ALPC_PORT_ATTRIBUTES *port_attr )
+NTSTATUS WINAPI NtAlpcCreatePort( HANDLE *port_handle, OBJECT_ATTRIBUTES *attr, ALPC_PORT_ATTRIBUTES *port_attr )
 {
-    FIXME( "%p, %p, %p stub!\n", port_handle, obj_attr, port_attr );
-    return STATUS_NOT_IMPLEMENTED;
+    struct object_attributes *objattr = NULL;
+    unsigned int status;
+    data_size_t len = 0;
+
+    TRACE( "%p, %p, %p.\n", port_handle, attr, port_attr );
+
+    if (!port_handle) return STATUS_ACCESS_VIOLATION;
+
+    *port_handle = NULL;
+
+    if (port_attr)
+        TRACE( "port attributes: flags %#x qos (length %#x impersonation_level %d tracking_mode %d "
+               "effective only %d) max_msg_length %#lx memory_bandwidth %#lx max_pool_usage %#lx "
+               "max_section_size %#lx max_view_size %#lx max_total_section_size %#lx.\n",
+               port_attr->Flags, port_attr->SecurityQos.Length, port_attr->SecurityQos.ImpersonationLevel,
+               port_attr->SecurityQos.ContextTrackingMode, port_attr->SecurityQos.EffectiveOnly,
+               port_attr->MaxMessageLength, port_attr->MemoryBandwidth, port_attr->MaxPoolUsage,
+               port_attr->MaxSectionSize, port_attr->MaxViewSize, port_attr->MaxTotalSectionSize );
+
+    if (port_attr && port_attr->Flags & 0x100000) return STATUS_INVALID_PARAMETER;
+
+    if (attr)
+    {
+        if (attr->ObjectName) TRACE( "name %s.\n", debugstr_us( attr->ObjectName ) );
+        if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
+    }
+
+    SERVER_START_REQ( alpc_create_port )
+    {
+        if (port_attr)
+        {
+            req->flags = port_attr->Flags;
+            req->max_msg_len = port_attr->MaxMessageLength;
+        }
+        else
+        {
+            req->flags = 0;
+            req->max_msg_len = 65535;
+        }
+        wine_server_add_data( req, objattr, len );
+        if (!(status = wine_server_call( req )))
+        {
+            *port_handle = wine_server_ptr_handle( reply->handle );
+            TRACE( "created %p.\n", *port_handle );
+        }
+        else
+        {
+            WARN( "status %#x.\n", status );
+        }
+    }
+    SERVER_END_REQ;
+    free( objattr );
+    return status;
 }
 
 NTSTATUS WINAPI NtAlpcDisconnectPort( HANDLE port_handle, ULONG flags )
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index b641e4ca3361..48a532b1d250 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -4434,7 +4434,7 @@ NTSTATUS get_full_path( char *name, const WCHAR *curdir, UNICODE_STRING *nt_name
     ULONG prefix_len, len = max( ARRAY_SIZE(unix_prefixW), wcslen(curdir) ) + strlen(name) + 1;
 
     /* special case for Unix file name */
-    if (name[0] == '/' && !find_drive_nt_root( name, strlen(name), &ret, FILE_OPEN )) goto done;
+    if (name[0] == '/' && !find_drive_nt_root( name, strlen(name), &ret, FILE_OPEN ) && ret) goto done;
 
     if (!(ret = malloc( len * sizeof(WCHAR) ))) return STATUS_NO_MEMORY;
 
@@ -4457,7 +4457,13 @@ NTSTATUS get_full_path( char *name, const WCHAR *curdir, UNICODE_STRING *nt_name
             prefix_len = ARRAY_SIZE(unc_prefixW);
         }
     }
-    else if (IS_SEPARATOR(name[0]))  /* absolute path */
+    else if (name[0] == '/') /* Unix path */
+    {
+        /* if we got here, there is no DOS drive */
+        memcpy( ret, unix_prefixW, sizeof(unix_prefixW) );
+        prefix_len = ARRAY_SIZE(unix_prefixW);
+    }
+    else if (name[0] == '\\')  /* absolute path */
     {
         memcpy( ret, dos_prefixW, sizeof(dos_prefixW) );
         prefix_len = ARRAY_SIZE(dos_prefixW);
@@ -7554,7 +7560,6 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io
         FILE_FS_VOLUME_INFORMATION *info = buffer;
         ULONGLONG data[64];
         struct mountmgr_unix_drive *drive = (struct mountmgr_unix_drive *)data;
-        const WCHAR *label;
 
         if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
         {
@@ -7564,17 +7569,22 @@ NTSTATUS WINAPI NtQueryVolumeInformationFile( HANDLE handle, IO_STATUS_BLOCK *io
 
         if (get_mountmgr_fs_info( handle, fd, drive, sizeof(data) ))
         {
-            status = STATUS_NOT_IMPLEMENTED;
-            break;
+            /* fall back to an empty reply rather than failing */
+            info->VolumeCreationTime.QuadPart = 0;
+            info->VolumeSerialNumber = 0;
+            info->VolumeLabelLength = 0;
+            info->SupportsObjects = FALSE;
+        }
+        else
+        {
+            const WCHAR *label = (WCHAR *)((char *)drive + drive->label_offset);
+            info->VolumeCreationTime.QuadPart = 0; /* FIXME */
+            info->VolumeSerialNumber = drive->serial;
+            info->VolumeLabelLength = min( wcslen( label ) * sizeof(WCHAR),
+                                           length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
+            info->SupportsObjects = (drive->fs_type == MOUNTMGR_FS_TYPE_NTFS);
+            memcpy( info->VolumeLabel, label, info->VolumeLabelLength );
         }
-
-        label = (WCHAR *)((char *)drive + drive->label_offset);
-        info->VolumeCreationTime.QuadPart = 0; /* FIXME */
-        info->VolumeSerialNumber = drive->serial;
-        info->VolumeLabelLength = min( wcslen( label ) * sizeof(WCHAR),
-                                       length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
-        info->SupportsObjects = (drive->fs_type == MOUNTMGR_FS_TYPE_NTFS);
-        memcpy( info->VolumeLabel, label, info->VolumeLabelLength );
         io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
         status = STATUS_SUCCESS;
         break;
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 0023abf1d2b8..68a4afada6c3 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -203,6 +203,7 @@ __ASM_GLOBAL_FUNC( modify_ldt,
 
 #elif defined(__FreeBSD__) || defined (__FreeBSD_kernel__)
 
+#include <machine/segments.h>
 #include <machine/trap.h>
 
 #define RAX_sig(context)     ((context)->uc_mcontext.mc_rax)
@@ -1674,7 +1675,7 @@ __ASM_GLOBAL_FUNC( call_user_mode_callback,
                    "1:\tmovq %rdi,%rsp\n\t"    /* user_rsp */
                    "movq 0x98(%r14),%rbp\n\t"  /* prev_frame->rbp */
                    "ldmxcsr 0xd8(%r14)\n\t"    /* prev_frame->xsave.MxCsr */
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
                    "movb $1,0x340(%r13)\n\t"   /* amd64_thread_data()->syscall_dispatch */
                    "movw 0x338(%r13),%ax\n"    /* amd64_thread_data()->fs */
                    "testw %ax,%ax\n\t"
@@ -2653,6 +2654,16 @@ void ldt_set_entry( WORD sel, LDT_ENTRY entry )
     if ((ret = modify_ldt( &ldt_info ))) ERR( "modify_ldt failed %d\n", ret );
 #elif defined(__APPLE__)
     if (i386_set_ldt(sel >> 3, (union ldt_entry *)&entry, 1) < 0) perror("i386_set_ldt");
+#elif defined(__FreeBSD__)
+    struct i386_ldt_args p;
+    p.start = sel >> 3;
+    p.descs = (struct user_segment_descriptor *)&entry;
+    p.num   = 1;
+    if (sysarch(I386_SET_LDT, &p) == -1)
+    {
+        perror("i386_set_ldt");
+        exit(1);
+    }
 #else
     fprintf( stderr, "No LDT support on this platform\n" );
     exit(1);
@@ -2798,6 +2809,8 @@ void signal_init_process( TEB *teb )
         fs32_sel = alloc_fs_sel( -1, wow_teb );
 #elif defined(__APPLE__)
         cs32_sel = ldt_alloc_entry( ldt_make_cs32_entry() );
+#elif defined(__FreeBSD__)
+        cs32_sel = GSEL(GUCODE32_SEL, SEL_UPL);
 #endif
     }
 
@@ -2870,6 +2883,7 @@ void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, TEB *teb )
         WARN_(seh)( "could not enable syscall user dispatch\n" );
 #elif defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
     amd64_set_gsbase( teb );
+    amd64_get_fsbase( &thread_data->pthread_teb );
 #elif defined(__NetBSD__)
     sysarch( X86_64_SET_GSBASE, &teb );
 #elif defined (__APPLE__)
@@ -3084,6 +3098,28 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
                    "syscall\n\t"
                    "leaq -0x98(%rbp),%rcx\n"
                    "2:\n\t"
+#elif defined(__FreeBSD__)
+                   "movq 0x320(%r13),%rsi\n\t"     /* amd64_thread_data()->pthread_teb */
+                   "testq %rsi,%rsi\n\t"
+                   "jz 2f\n\t"
+                   "cmpb $0,0x7ffe028a\n\t"        /* user_shared_data->ProcessorFeatures[PF_RDWRFSGSBASE_AVAILABLE] */
+                   "jz 1f\n\t"
+                   "wrfsbase %rsi\n\t"
+                   "jmp 2f\n"
+                   "1:\n\t"
+                   "pushq %r8\n\t"
+                   "pushq %r9\n\t"
+                   "pushq %r10\n\t"
+                   "pushq %r11\n\t"
+                   "movq $0xa5,%rax\n\t"           /* sysarch */
+                   "movq $0x81,%rdi\n\t"           /* AMD64_SET_FSBASE */
+                   "syscall\n\t"
+                   "popq %r11\n\t"
+                   "popq %r10\n\t"
+                   "popq %r9\n\t"
+                   "popq %r8\n\t"
+                   "leaq -0x98(%rbp),%rcx\n"
+                   "2:\n\t"
 #elif defined __APPLE__
                    "movq 0x320(%r13),%rdi\n\t"     /* amd64_thread_data()->pthread_teb */
                    "xorl %esi,%esi\n\t"
@@ -3130,12 +3166,17 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
                    __ASM_CFI(".cfi_remember_state\n\t")
                    __ASM_CFI_CFA_IS_AT2(rcx, 0xa8, 0x01) /* frame->syscall_cfa */
                    "leaq 0x70(%rcx),%rsp\n\t"      /* %rsp > frame means no longer inside syscall */
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
                    "movb $1,0x340(%r13)\n\t"       /* amd64_thread_data()->syscall_dispatch */
                    "movw 0x338(%r13),%dx\n"        /* amd64_thread_data()->fs */
                    "testw %dx,%dx\n\t"
                    "jz 1f\n\t"
                    "movw %dx,%fs\n"
+# ifdef __FreeBSD__
+                   /* reset %ss (after sysret) for AMD */
+                   "movw $0x3b,%dx\n\t"           /* GSEL(GUDATA_SEL, SEL_UPL) */
+                   "movw %dx,%ss\n\t"
+# endif
                    "1:\n\t"
 #elif defined __APPLE__
                    "movq %rax,%r8\n\t"
@@ -3374,6 +3415,27 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher,
                    "mov $158,%eax\n\t"             /* SYS_arch_prctl */
                    "syscall\n\t"
                    "2:\n\t"
+#elif defined(__FreeBSD__)
+                   "movq 0x320(%r13),%rsi\n\t"     /* amd64_thread_data()->pthread_teb */
+                   "testq %rsi,%rsi\n\t"
+                   "jz 2f\n\t"
+                   "cmpb $0,0x7ffe028a\n\t"        /* user_shared_data->ProcessorFeatures[PF_RDWRFSGSBASE_AVAILABLE] */
+                   "jz 1f\n\t"
+                   "wrfsbase %rsi\n\t"
+                   "jmp 2f\n"
+                   "1:\n\t"
+                   "pushq %r8\n\t"
+                   "pushq %r9\n\t"
+                   "pushq %r10\n\t"
+                   "pushq %r11\n\t"
+                   "movq $0xa5,%rax\n\t"           /* sysarch */
+                   "movq $0x81,%rdi\n\t"           /* AMD64_SET_FSBASE */
+                   "syscall\n\t"
+                   "popq %r11\n\t"
+                   "popq %r10\n\t"
+                   "popq %r9\n\t"
+                   "popq %r8\n\t"
+                   "2:\n\t"
 #elif defined __APPLE__
                    "movq 0x320(%r13),%rdi\n\t"     /* amd64_thread_data()->pthread_teb */
                    "xorl %esi,%esi\n\t"
@@ -3400,12 +3462,17 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher,
                    /* switch to user stack */
                    "movq 0x88(%rcx),%rsp\n\t"
                    __ASM_CFI(".cfi_restore_state\n\t")
-#ifdef __linux__
+#if defined(__linux__) || defined(__FreeBSD__)
                    "movb $1,0x340(%r13)\n\t"       /* amd64_thread_data()->syscall_dispatch */
                    "movw 0x338(%r13),%dx\n"        /* amd64_thread_data()->fs */
                    "testw %dx,%dx\n\t"
                    "jz 1f\n\t"
                    "movw %dx,%fs\n"
+# ifdef __FreeBSD__
+                   /* reset %ss (after sysret) for AMD */
+                   "movw $0x3b,%dx\n\t"           /* GSEL(GUDATA_SEL, SEL_UPL) */
+                   "movw %dx,%ss\n\t"
+# endif
                    "1:\n\t"
 #elif defined __APPLE__
                    "movq %rax,%rdx\n\t"
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index eda3fee3d8b3..db820a89525a 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -2767,6 +2767,10 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, size_t map_size, int fd,
  */
 static void *get_host_addr_space_limit(void)
 {
+#ifdef __APPLE__
+    /* See MACH_VM_MAX_ADDRESS_RAW in xnu osfmk/mach/arm/vm_param.h */
+    return (void *)0x7ffffe000000;
+#else
     unsigned int flags = MAP_PRIVATE | MAP_ANON;
     UINT_PTR addr = (UINT_PTR)1 << 63;
 
@@ -2786,6 +2790,7 @@ static void *get_host_addr_space_limit(void)
         addr >>= 1;
     }
     return (void *)((addr << 1) - (granularity_mask + 1));
+#endif
 }
 
 #endif /* _WIN64 */
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index bf6554debe17..bf9d37489e40 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -1355,6 +1355,8 @@ DEVICE_OBJECT* WINAPI IoGetAttachedDevice( DEVICE_OBJECT *device )
 
 void WINAPI IoDetachDevice( DEVICE_OBJECT *device )
 {
+    if (device->AttachedDevice)
+        device->AttachedDevice->DeviceObjectExtension->AttachedTo = NULL;
     device->AttachedDevice = NULL;
 }
 
@@ -1367,6 +1369,7 @@ PDEVICE_OBJECT WINAPI IoAttachDeviceToDeviceStack( DEVICE_OBJECT *source,
     TRACE( "%p, %p\n", source, target );
     target = IoGetAttachedDevice( target );
     target->AttachedDevice = source;
+    source->DeviceObjectExtension->AttachedTo = target;
     source->StackSize = target->StackSize + 1;
     return target;
 }
@@ -1679,6 +1682,8 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size,
     device->DeviceExtension = wine_device + 1;
     device->DeviceType      = type;
     device->StackSize       = 1;
+    device->DeviceObjectExtension = &wine_device->devobj_ext;
+    device->DeviceObjectExtension->DeviceObject = device;
 
     if (characteristics & FILE_AUTOGENERATED_DEVICE_NAME)
     {
@@ -4804,6 +4809,12 @@ NTSTATUS WINAPI EtwUnregister(REGHANDLE handle)
     return STATUS_SUCCESS;
 }
 
+PEPROCESS WINAPI IoThreadToProcess(PETHREAD thread)
+{
+    TRACE("thread %p\n", thread);
+    return thread->kthread.process;
+}
+
 /*****************************************************
  *           DllMain
  */
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 85e530e55460..2829e97ddf9b 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -497,7 +497,7 @@
 @ stdcall IoStopTimer(ptr)
 @ stub IoSynchronousInvalidateDeviceRelations
 @ stub IoSynchronousPageWrite
-@ stub IoThreadToProcess
+@ stdcall IoThreadToProcess(ptr)
 @ stdcall IoUnregisterFileSystem(ptr)
 @ stub IoUnregisterFsRegistrationChange
 @ stdcall IoUnregisterPlugPlayNotification(ptr)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h
index 5f3fa69ecf32..79a124671b1f 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl_private.h
+++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h
@@ -29,8 +29,10 @@
 #include "winbase.h"
 #include "winsvc.h"
 #include "winternl.h"
+#include "winreg.h"
 #include "ddk/ntifs.h"
 #include "ddk/wdm.h"
+#include "cfgmgr32.h"
 
 #include "wine/asm.h"
 #include "wine/debug.h"
@@ -119,7 +121,11 @@ static const WCHAR servicesW[] = {'\\','R','e','g','i','s','t','r','y',
 struct wine_device
 {
     DEVICE_OBJECT device_obj;
+    DEVOBJ_EXTENSION devobj_ext;
     DEVICE_RELATIONS *children;
     HKEY dyn_data_key;
+
+    /* Combination of device_id and instance_id. Only set on PDO devices. */
+    WCHAR device_instance_id[MAX_DEVICE_ID_LEN];
 };
 #endif
diff --git a/dlls/ntoskrnl.exe/pnp.c b/dlls/ntoskrnl.exe/pnp.c
index 11a578a75457..775394c49481 100644
--- a/dlls/ntoskrnl.exe/pnp.c
+++ b/dlls/ntoskrnl.exe/pnp.c
@@ -149,29 +149,43 @@ static NTSTATUS send_pnp_irp( DEVICE_OBJECT *device, UCHAR minor )
 
 static NTSTATUS get_device_instance_id( DEVICE_OBJECT *device, WCHAR *buffer )
 {
-    static const WCHAR backslashW[] = {'\\',0};
+    struct wine_device *pdo_dev;
     NTSTATUS status;
     WCHAR *id;
 
-    if ((status = get_device_id( device, BusQueryDeviceID, &id )))
+    while (device->DeviceObjectExtension->AttachedTo)
+        device = device->DeviceObjectExtension->AttachedTo;
+
+    if (!(device->Flags & DO_BUS_ENUMERATED_DEVICE))
     {
-        ERR("Failed to get device ID, status %#lx.\n", status);
-        return status;
+        ERR( "Lowest device in stack is not a PDO.\n" );
+        return STATUS_INVALID_DEVICE_REQUEST;
     }
 
-    lstrcpyW( buffer, id );
-    ExFreePool( id );
-
-    if ((status = get_device_id( device, BusQueryInstanceID, &id )))
+    pdo_dev = CONTAINING_RECORD(device, struct wine_device, device_obj);
+    if (!wcslen( pdo_dev->device_instance_id ))
     {
-        ERR("Failed to get instance ID, status %#lx.\n", status);
-        return status;
-    }
+        if ((status = get_device_id( device, BusQueryDeviceID, &id )))
+        {
+            ERR("Failed to get device ID, status %#lx.\n", status);
+            return status;
+        }
+
+        wcscpy( pdo_dev->device_instance_id, id );
+        wcscat( pdo_dev->device_instance_id, L"\\" );
+        ExFreePool( id );
 
-    lstrcatW( buffer, backslashW );
-    lstrcatW( buffer, id );
-    ExFreePool( id );
+        if ((status = get_device_id( device, BusQueryInstanceID, &id )))
+        {
+            ERR("Failed to get instance ID, status %#lx.\n", status);
+            pdo_dev->device_instance_id[0] = 0;
+            return status;
+        }
+        wcscat( pdo_dev->device_instance_id, id );
+        ExFreePool( id );
+    }
 
+    wcscpy( buffer, pdo_dev->device_instance_id );
     TRACE("Returning ID %s.\n", debugstr_w(buffer));
 
     return STATUS_SUCCESS;
@@ -392,6 +406,7 @@ static void enumerate_new_device( DEVICE_OBJECT *device, HDEVINFO set, DEVICE_OB
     HKEY key;
     WCHAR *id;
 
+    device->Flags |= DO_BUS_ENUMERATED_DEVICE;
     if (get_device_instance_id( device, device_instance_id ))
         return;
 
@@ -668,6 +683,9 @@ NTSTATUS WINAPI IoGetDevicePropertyData( DEVICE_OBJECT *device, const DEVPROPKEY
            device, debugstr_propkey( property_key ), lcid, flags, size, data, required_size,
            property_type );
 
+    if (!(device->Flags & DO_BUS_ENUMERATED_DEVICE))
+        ERR( "Passed in non-PDO device, this would crash on native.\n" );
+
     if (lcid == LOCALE_SYSTEM_DEFAULT || lcid == LOCALE_USER_DEFAULT) return STATUS_INVALID_PARAMETER;
     if (lcid != LOCALE_NEUTRAL) FIXME( "Only LOCALE_NEUTRAL is supported\n" );
 
@@ -716,29 +734,40 @@ NTSTATUS WINAPI IoGetDeviceProperty( DEVICE_OBJECT *device, DEVICE_REGISTRY_PROP
     TRACE("device %p, property %u, length %lu, buffer %p, needed %p.\n",
             device, property, length, buffer, needed);
 
+    if (!(device->Flags & DO_BUS_ENUMERATED_DEVICE))
+    {
+        WARN( "Passed in non-PDO device.\n" );
+        return STATUS_INVALID_DEVICE_REQUEST;
+    }
+
     switch (property)
     {
         case DevicePropertyEnumeratorName:
         {
-            WCHAR *id, *ptr;
+            WCHAR *ptr;
 
-            status = get_device_id( device, BusQueryDeviceID, &id );
+            status = get_device_instance_id( device, device_instance_id );
             if (status != STATUS_SUCCESS)
             {
                 ERR("Failed to get instance ID, status %#lx.\n", status);
-                break;
+                return status;
             }
 
-            ptr = wcschr( id, '\\' );
-            if (ptr) *ptr = 0;
+            if (!(ptr = wcschr( device_instance_id, '\\' )))
+            {
+                ERR( "Instance ID %s has no enumerator separator.\n", debugstr_w(device_instance_id) );
+                return STATUS_UNSUCCESSFUL;
+            }
 
-            *needed = sizeof(WCHAR) * (lstrlenW(id) + 1);
+            *needed = ((ptr - device_instance_id) + 1) * sizeof(WCHAR);
             if (length >= *needed)
-                memcpy( buffer, id, *needed );
+            {
+                memcpy( buffer, device_instance_id, *needed - sizeof(WCHAR) );
+                ((WCHAR *)buffer)[((ptr - device_instance_id) + 1)] = 0;
+            }
             else
                 status = STATUS_BUFFER_TOO_SMALL;
 
-            ExFreePool( id );
             return status;
         }
         case DevicePropertyPhysicalDeviceObjectName:
@@ -1163,6 +1192,9 @@ NTSTATUS WINAPI IoSetDevicePropertyData( DEVICE_OBJECT *device, const DEVPROPKEY
 
     if (lcid != LOCALE_NEUTRAL) FIXME( "only LOCALE_NEUTRAL is supported\n" );
 
+    if (!(device->Flags & DO_BUS_ENUMERATED_DEVICE))
+        ERR( "Passed in non-PDO device, this would crash on native.\n" );
+
     if ((status = get_device_instance_id( device, device_instance_id ))) return status;
 
     if ((set = SetupDiCreateDeviceInfoList( &GUID_NULL, NULL )) == INVALID_HANDLE_VALUE)
@@ -1343,6 +1375,12 @@ NTSTATUS WINAPI IoOpenDeviceRegistryKey( DEVICE_OBJECT *device, ULONG type, ACCE
 
     TRACE("device %p, type %#lx, access %#lx, key %p.\n", device, type, access, key);
 
+    if (!(device->Flags & DO_BUS_ENUMERATED_DEVICE))
+    {
+        WARN( "Passed in non-PDO device.\n" );
+        return STATUS_INVALID_PARAMETER;
+    }
+
     if ((status = get_device_instance_id( device, device_instance_id )))
     {
         ERR("Failed to get device instance ID, error %#lx.\n", status);
@@ -1623,6 +1661,7 @@ void CDECL wine_enumerate_root_devices( const WCHAR *driver_name )
         wcscpy( pnp_device->id, id );
         pnp_device->device = device;
         list_add_tail( &new_list, &pnp_device->entry );
+        device->Flags |= DO_BUS_ENUMERATED_DEVICE;
 
         start_device( device, set, &sp_device );
     }
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 030c6476a525..6cf88cdf2032 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -1855,17 +1855,27 @@ static void test_completion(void)
 static void test_IoAttachDeviceToDeviceStack(void)
 {
     DEVICE_OBJECT *dev1, *dev2, *dev3, *ret;
+    DEVOBJ_EXTENSION *ext1, *ext2, *ext3;
     NTSTATUS status;
 
     status = IoCreateDevice(driver_obj, 0, NULL, FILE_DEVICE_UNKNOWN,
             FILE_DEVICE_SECURE_OPEN, FALSE, &dev1);
     ok(status == STATUS_SUCCESS, "IoCreateDevice failed\n");
+    ok(!!dev1->DeviceObjectExtension, "Got NULL DeviceObjectExtension.\n");
+    ext1 = dev1->DeviceObjectExtension;
     status = IoCreateDevice(driver_obj, 0, NULL, FILE_DEVICE_UNKNOWN,
             FILE_DEVICE_SECURE_OPEN, FALSE, &dev2);
     ok(status == STATUS_SUCCESS, "IoCreateDevice failed\n");
+    ok(!!dev2->DeviceObjectExtension, "Got NULL DeviceObjectExtension.\n");
+    ext2 = dev2->DeviceObjectExtension;
     status = IoCreateDevice(driver_obj, 0, NULL, FILE_DEVICE_UNKNOWN,
             FILE_DEVICE_SECURE_OPEN, FALSE, &dev3);
     ok(status == STATUS_SUCCESS, "IoCreateDevice failed\n");
+    ok(!!dev3->DeviceObjectExtension, "Got NULL DeviceObjectExtension.\n");
+    ext3 = dev3->DeviceObjectExtension;
+    ok(!ext1->AttachedTo, "Unexpected AttachedTo %p.\n", ext1->AttachedTo);
+    ok(!ext2->AttachedTo, "Unexpected AttachedTo %p.\n", ext2->AttachedTo);
+    ok(!ext3->AttachedTo, "Unexpected AttachedTo %p.\n", ext3->AttachedTo);
 
     /* TODO: initialize devices properly */
     dev1->Flags &= ~DO_DEVICE_INITIALIZING;
@@ -1875,7 +1885,9 @@ static void test_IoAttachDeviceToDeviceStack(void)
     ok(ret == dev1, "IoAttachDeviceToDeviceStack returned %p, expected %p\n", ret, dev1);
     ok(dev1->AttachedDevice == dev2, "dev1->AttachedDevice = %p, expected %p\n",
             dev1->AttachedDevice, dev2);
+    ok(!ext1->AttachedTo, "Unexpected AttachedTo %p.\n", ext1->AttachedTo);
     ok(!dev2->AttachedDevice, "dev2->AttachedDevice = %p\n", dev2->AttachedDevice);
+    ok(ext2->AttachedTo == dev1, "Unexpected AttachedTo %p.\n", ext2->AttachedTo);
     ok(dev1->StackSize == 1, "dev1->StackSize = %d\n", dev1->StackSize);
     ok(dev2->StackSize == 2, "dev2->StackSize = %d\n", dev2->StackSize);
 
@@ -1883,9 +1895,12 @@ static void test_IoAttachDeviceToDeviceStack(void)
     ok(ret == dev2, "IoAttachDeviceToDeviceStack returned %p, expected %p\n", ret, dev2);
     ok(dev1->AttachedDevice == dev2, "dev1->AttachedDevice = %p, expected %p\n",
             dev1->AttachedDevice, dev2);
+    ok(!ext1->AttachedTo, "Unexpected AttachedTo %p.\n", ext1->AttachedTo);
     ok(dev2->AttachedDevice == dev3, "dev2->AttachedDevice = %p, expected %p\n",
             dev2->AttachedDevice, dev3);
+    ok(ext2->AttachedTo == dev1, "Unexpected AttachedTo %p.\n", ext2->AttachedTo);
     ok(!dev3->AttachedDevice, "dev3->AttachedDevice = %p\n", dev3->AttachedDevice);
+    ok(ext3->AttachedTo == dev2, "Unexpected AttachedTo %p.\n", ext3->AttachedTo);
     ok(dev1->StackSize == 1, "dev1->StackSize = %d\n", dev1->StackSize);
     ok(dev2->StackSize == 2, "dev2->StackSize = %d\n", dev2->StackSize);
     ok(dev3->StackSize == 3, "dev3->StackSize = %d\n", dev3->StackSize);
@@ -1893,9 +1908,11 @@ static void test_IoAttachDeviceToDeviceStack(void)
     IoDetachDevice(dev1);
     ok(!dev1->AttachedDevice, "dev1->AttachedDevice = %p\n", dev1->AttachedDevice);
     ok(dev2->AttachedDevice == dev3, "dev2->AttachedDevice = %p\n", dev2->AttachedDevice);
+    ok(!ext2->AttachedTo, "Unexpected AttachedTo %p.\n", ext2->AttachedTo);
 
     IoDetachDevice(dev2);
     ok(!dev2->AttachedDevice, "dev2->AttachedDevice = %p\n", dev2->AttachedDevice);
+    ok(!ext3->AttachedTo, "Unexpected AttachedTo %p.\n", ext3->AttachedTo);
     ok(dev1->StackSize == 1, "dev1->StackSize = %d\n", dev1->StackSize);
     ok(dev2->StackSize == 2, "dev2->StackSize = %d\n", dev2->StackSize);
     ok(dev3->StackSize == 3, "dev3->StackSize = %d\n", dev3->StackSize);
diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c
index c33a8d6a0821..ea7306a89005 100644
--- a/dlls/ntoskrnl.exe/tests/driver_pnp.c
+++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c
@@ -324,7 +324,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp)
 
             query_id_count = 0;
             status = IoRegisterDeviceInterface(device_obj, &child_class, NULL, &device->child_symlink);
-            todo_wine ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
+            ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
             ok(!status, "Failed to register interface, status %#lx.\n", status);
             ok(device->child_symlink.Length == sizeof(expect_symlink) - sizeof(WCHAR),
                     "Got length %u.\n", device->child_symlink.Length);
@@ -693,6 +693,16 @@ static void test_device_properties( DEVICE_OBJECT *device )
         const DEVPROPKEY *key = deviceprops[i].key;
         void *value = &deviceprops[i].value;
 
+        /*
+         * Io{Get,Set}DevicePropertyData() being used with a non-PDO device causes a
+         * BSoD on native with an error code of PNP_DETECTED_FATAL_ERROR.
+         */
+        if (0)
+        {
+            status = IoSetDevicePropertyData( bus_fdo, key, LOCALE_NEUTRAL, 0, type, size, value );
+            ok( status == STATUS_SUCCESS, "Failed to set device property, status %#lx.\n", status );
+        }
+
         status = IoSetDevicePropertyData( device, key, LOCALE_NEUTRAL, 0, type, size, value );
         ok( status == STATUS_SUCCESS, "Failed to set device property, status %#lx.\n", status );
         if (status == STATUS_SUCCESS)
@@ -726,6 +736,17 @@ static void test_device_properties( DEVICE_OBJECT *device )
                 if (status == STATUS_SUCCESS)
                     ok( kmemcmp( buf, value, size ) == 0,
                         "Got unexpected device property value.\n" );
+                /* Crashes in the same manner as IoSetDevicePropertyData(). */
+                if (0)
+                {
+                    req_size = 0;
+                    stored_type = DEVPROP_TYPE_EMPTY;
+                    memset( buf, 0, size );
+                    status = IoGetDevicePropertyData( bus_fdo, key, LOCALE_NEUTRAL, 0, size, buf,
+                                                      &req_size, &stored_type );
+                    ok( status == STATUS_SUCCESS, "Failed to get device property, status %#lx.\n",
+                        status );
+                }
                 ExFreePool( buf );
             }
         }
@@ -747,12 +768,12 @@ static void test_child_device_properties(DEVICE_OBJECT *device)
 
     query_id_count = 0;
     status = IoSetDevicePropertyData(device, key, LOCALE_NEUTRAL, 0, type, size, &value);
-    todo_wine ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
+    ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
     ok(status == STATUS_SUCCESS, "failed to set device property, status %#lx\n", status);
 
     query_id_count = 0;
     status = IoGetDevicePropertyData(device, key, LOCALE_NEUTRAL, 0, size, &stored_value, &req_size, &stored_type);
-    todo_wine ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
+    ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
     ok(status == STATUS_SUCCESS, "failed to get device property, status %#lx\n", status);
     ok(req_size == size, "expected required size %lu, got %lu\n", req_size, size);
     ok(stored_type == type, "expected DEVPROPTYPE value %#lx, got %#lx\n", type, stored_type);
@@ -760,7 +781,7 @@ static void test_child_device_properties(DEVICE_OBJECT *device)
 
     query_id_count = 0;
     status = IoSetDevicePropertyData(device, key, LOCALE_NEUTRAL, 0, type, 0, NULL);
-    todo_wine ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
+    ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
     ok(status == STATUS_SUCCESS, "failed to delete device property, status %#lx\n", status);
 }
 
@@ -833,12 +854,14 @@ static void test_enumerator_name(void)
     NTSTATUS status;
 
     status = IoGetDeviceProperty(bus_fdo, DevicePropertyEnumeratorName, sizeof(buffer), buffer, &req_size);
-    todo_wine ok(status == STATUS_INVALID_DEVICE_REQUEST, "got unexpected status %#lx\n", status);
+    ok(status == STATUS_INVALID_DEVICE_REQUEST, "got unexpected status %#lx\n", status);
+    ok(!(bus_fdo->Flags & DO_BUS_ENUMERATED_DEVICE), "Unexpected bus_fdo flags %#lx.\n", bus_fdo->Flags);
 
     req_size = 0;
     memset(buffer, 0, sizeof(buffer));
     status = IoGetDeviceProperty(bus_pdo, DevicePropertyEnumeratorName, sizeof(buffer), buffer, &req_size);
     ok(status == STATUS_SUCCESS, "IoGetDeviceProperty failed: %#lx\n", status);
+    ok(!!(bus_pdo->Flags & DO_BUS_ENUMERATED_DEVICE), "Unexpected bus_pdo flags %#lx.\n", bus_pdo->Flags);
     ok(req_size == sizeof(root), "unexpected size %lu\n", req_size);
     if (status == STATUS_SUCCESS)
         ok(!wcscmp(root, buffer), "unexpected property value '%ls'\n", buffer);
@@ -853,7 +876,7 @@ static void test_child_enumerator_name(DEVICE_OBJECT *device)
 
     query_id_count = 0;
     status = IoGetDeviceProperty(device, DevicePropertyEnumeratorName, sizeof(buffer), buffer, &req_size);
-    todo_wine ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
+    ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
     ok(status == STATUS_SUCCESS, "IoGetDeviceProperty failed: %#lx\n", status);
     ok(req_size == sizeof(wine), "unexpected size %lu\n", req_size);
     if (status == STATUS_SUCCESS)
@@ -872,10 +895,12 @@ static void test_device_registry_key(void)
     DWORD size;
 
     status = IoOpenDeviceRegistryKey(bus_fdo, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &hkey);
-    todo_wine ok(status == STATUS_INVALID_PARAMETER, "got unexpected status %#lx\n", status);
+    ok(status == STATUS_INVALID_PARAMETER, "got unexpected status %#lx\n", status);
+    ok(!(bus_fdo->Flags & DO_BUS_ENUMERATED_DEVICE), "Unexpected bus_fdo flags %#lx.\n", bus_fdo->Flags);
 
     status = IoOpenDeviceRegistryKey(bus_pdo, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &hkey);
     ok(status == STATUS_SUCCESS, "IoOpenDeviceRegistryKey failed: %#lx\n", status);
+    ok(!!(bus_pdo->Flags & DO_BUS_ENUMERATED_DEVICE), "Unexpected bus_pdo flags %#lx.\n", bus_pdo->Flags);
     if (status == STATUS_SUCCESS)
     {
         RtlInitUnicodeString(&name_str, foobar);
@@ -913,7 +938,7 @@ static void test_child_device_registry_key(DEVICE_OBJECT *device)
 
     query_id_count = 0;
     status = IoOpenDeviceRegistryKey(device, PLUGPLAY_REGKEY_DEVICE, KEY_ALL_ACCESS, &hkey);
-    todo_wine ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
+    ok(query_id_count == 0, "expected no IRP_MN_QUERY_ID\n");
     ok(status == STATUS_SUCCESS, "IoOpenDeviceRegistryKey failed: %#lx\n", status);
     if (status == STATUS_SUCCESS)
     {
@@ -1144,11 +1169,15 @@ static NTSTATUS WINAPI driver_ioctl(DEVICE_OBJECT *device, IRP *irp)
 
 static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *pdo)
 {
+    DEVOBJ_EXTENSION *pdo_ext = pdo->DeviceObjectExtension;
+    DEVOBJ_EXTENSION *fdo_ext;
     NTSTATUS ret;
 
+    ok(!!(pdo->Flags & DO_BUS_ENUMERATED_DEVICE), "Unexpected pdo flags %#lx.\n", pdo->Flags);
     if ((ret = IoCreateDevice(driver, 0, NULL, FILE_DEVICE_BUS_EXTENDER, 0, FALSE, &bus_fdo)))
         return ret;
 
+    fdo_ext = bus_fdo->DeviceObjectExtension;
     if ((ret = IoRegisterDeviceInterface(pdo, &control_class, NULL, &control_symlink)))
     {
         IoDeleteDevice(bus_fdo);
@@ -1156,6 +1185,12 @@ static NTSTATUS WINAPI driver_add_device(DRIVER_OBJECT *driver, DEVICE_OBJECT *p
     }
 
     IoAttachDeviceToDeviceStack(bus_fdo, pdo);
+    ok(pdo->AttachedDevice == bus_fdo, "Unexpected AttachedDevice %p.\n", pdo->AttachedDevice);
+    if (pdo_ext)
+        ok(!pdo_ext->AttachedTo, "Unexpected AttachedTo %p.\n", pdo_ext->AttachedTo);
+    ok(!bus_fdo->AttachedDevice, "Unexpected AttachedDevice %p.\n", bus_fdo->AttachedDevice);
+    if (fdo_ext)
+        ok(fdo_ext->AttachedTo == pdo, "Unexpected AttachedTo %p.\n", fdo_ext->AttachedTo);
     bus_pdo = pdo;
     bus_fdo->Flags &= ~DO_DEVICE_INITIALIZING;
     return STATUS_SUCCESS;
diff --git a/dlls/oleaut32/dispatch.c b/dlls/oleaut32/dispatch.c
index 7fa96e5af836..f6d2ee2b3918 100644
--- a/dlls/oleaut32/dispatch.c
+++ b/dlls/oleaut32/dispatch.c
@@ -203,6 +203,8 @@ done:
 typedef struct
 {
     IDispatch IDispatch_iface;
+    IUnknown IUnknown_inner;
+    IUnknown *outer_unk;
     void * pvThis;
     ITypeInfo * pTypeInfo;
     LONG ref;
@@ -213,65 +215,27 @@ static inline StdDispatch *impl_from_IDispatch(IDispatch *iface)
     return CONTAINING_RECORD(iface, StdDispatch, IDispatch_iface);
 }
 
-/******************************************************************************
- * IDispatch_QueryInterface {OLEAUT32}
- *
- * See IUnknown_QueryInterface.
- */
-static HRESULT WINAPI StdDispatch_QueryInterface(
-  LPDISPATCH iface,
-  REFIID riid,
-  void** ppvObject)
+static inline StdDispatch *impl_from_IUnknown(IUnknown *iface)
 {
-    StdDispatch *This = impl_from_IDispatch(iface);
-    TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppvObject);
-
-    *ppvObject = NULL;
-
-    if (IsEqualIID(riid, &IID_IDispatch) ||
-        IsEqualIID(riid, &IID_IUnknown))
-    {
-        *ppvObject = iface;
-        IDispatch_AddRef(iface);
-        return S_OK;
-    }
-    return E_NOINTERFACE;
+    return CONTAINING_RECORD(iface, StdDispatch, IUnknown_inner);
 }
 
-/******************************************************************************
- * IDispatch_AddRef {OLEAUT32}
- *
- * See IUnknown_AddRef.
- */
-static ULONG WINAPI StdDispatch_AddRef(LPDISPATCH iface)
+static HRESULT WINAPI StdDispatch_QueryInterface(IDispatch *iface, REFIID riid, void **obj)
 {
-    StdDispatch *This = impl_from_IDispatch(iface);
-    ULONG refCount = InterlockedIncrement(&This->ref);
-
-    TRACE("%p, refcount %lu.\n", iface, refCount);
-
-    return refCount;
+    StdDispatch *dispatch = impl_from_IDispatch(iface);
+    return IUnknown_QueryInterface(dispatch->outer_unk, riid, obj);
 }
 
-/******************************************************************************
- * IDispatch_Release {OLEAUT32}
- *
- * See IUnknown_Release.
- */
-static ULONG WINAPI StdDispatch_Release(LPDISPATCH iface)
+static ULONG WINAPI StdDispatch_AddRef(IDispatch *iface)
 {
-    StdDispatch *This = impl_from_IDispatch(iface);
-    ULONG refCount = InterlockedDecrement(&This->ref);
-
-    TRACE("%p, refcount %lu.\n", iface, refCount);
-
-    if (!refCount)
-    {
-        ITypeInfo_Release(This->pTypeInfo);
-        CoTaskMemFree(This);
-    }
+    StdDispatch *dispatch = impl_from_IDispatch(iface);
+    return IUnknown_AddRef(dispatch->outer_unk);
+}
 
-    return refCount;
+static ULONG WINAPI StdDispatch_Release(IDispatch *iface)
+{
+    StdDispatch *dispatch = impl_from_IDispatch(iface);
+    return IUnknown_Release(dispatch->outer_unk);
 }
 
 /******************************************************************************
@@ -422,17 +386,66 @@ static const IDispatchVtbl StdDispatch_VTable =
   StdDispatch_Invoke
 };
 
+static HRESULT WINAPI std_dispatch_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
+{
+    StdDispatch *dispatch = impl_from_IUnknown(iface);
+
+    TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
+
+    if (IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+    }
+    else if (IsEqualIID(riid, &IID_IDispatch))
+    {
+        *obj = &dispatch->IDispatch_iface;
+    }
+    else
+    {
+        WARN("Unsupported interface %s.\n", debugstr_guid(riid));
+        *obj = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*obj);
+    return S_OK;
+}
+
+static ULONG WINAPI std_dispatch_inner_AddRef(IUnknown *iface)
+{
+    StdDispatch *dispatch = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedIncrement(&dispatch->ref);
+
+    TRACE("%p, refcount %lu.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI std_dispatch_inner_Release(IUnknown *iface)
+{
+    StdDispatch *dispatch = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedDecrement(&dispatch->ref);
+
+    TRACE("%p, refcount %lu.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        ITypeInfo_Release(dispatch->pTypeInfo);
+        CoTaskMemFree(dispatch);
+    }
+
+    return refcount;
+}
+
+static const IUnknownVtbl std_dispatch_inner_vtbl =
+{
+    std_dispatch_inner_QueryInterface,
+    std_dispatch_inner_AddRef,
+    std_dispatch_inner_Release,
+};
+
 /******************************************************************************
  * CreateStdDispatch [OLEAUT32.32]
- *
- * Create and return a standard IDispatch object.
- *
- * RETURNS
- *  Success: S_OK. ppunkStdDisp contains the new object.
- *  Failure: An HRESULT error code.
- *
- * NOTES
- *  Outer unknown appears to be completely ignored.
  */
 HRESULT WINAPI CreateStdDispatch(
         IUnknown* punkOuter,
@@ -452,14 +465,14 @@ HRESULT WINAPI CreateStdDispatch(
         return E_OUTOFMEMORY;
 
     pStdDispatch->IDispatch_iface.lpVtbl = &StdDispatch_VTable;
+    pStdDispatch->IUnknown_inner.lpVtbl = &std_dispatch_inner_vtbl;
+    pStdDispatch->outer_unk = punkOuter ? punkOuter : &pStdDispatch->IUnknown_inner;
+    pStdDispatch->ref = 1;
     pStdDispatch->pvThis = pvThis;
     pStdDispatch->pTypeInfo = ptinfo;
-    pStdDispatch->ref = 1;
-
-    /* we keep a reference to the type info so prevent it from
-     * being destroyed until we are done with it */
     ITypeInfo_AddRef(ptinfo);
-    *stddisp = (IUnknown*)&pStdDispatch->IDispatch_iface;
+
+    *stddisp = &pStdDispatch->IUnknown_inner;
 
     return S_OK;
 }
diff --git a/dlls/oleaut32/tests/dispatch.c b/dlls/oleaut32/tests/dispatch.c
index 022eb4b7e67e..eb0a93a0aef6 100644
--- a/dlls/oleaut32/tests/dispatch.c
+++ b/dlls/oleaut32/tests/dispatch.c
@@ -303,12 +303,51 @@ static const IUnknownVtbl unkvtbl =
 
 static IUnknown test_unk = { &unkvtbl };
 
+static HRESULT WINAPI outer_unk_QI(IUnknown *iface, REFIID riid, void **obj)
+{
+    if (IsEqualIID(riid, &IID_IUnknown))
+    {
+        *obj = iface;
+        return S_OK;
+    }
+    else if (IsEqualIID(riid, &IID_IDispatch))
+    {
+        *obj = NULL;
+        return 0x80010003;
+    }
+    else
+    {
+        *obj = NULL;
+        return E_NOINTERFACE;
+    }
+}
+
+static ULONG WINAPI outer_unk_AddRef(IUnknown *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI outer_unk_Release(IUnknown *iface)
+{
+    return 1;
+}
+
+static const IUnknownVtbl outerunkvtbl =
+{
+    outer_unk_QI,
+    outer_unk_AddRef,
+    outer_unk_Release
+};
+
+static IUnknown outer_test_unk = { &outerunkvtbl };
+
 static void test_CreateStdDispatch(void)
 {
     static const WCHAR stdole2W[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
+    IDispatch *disp, *disp2;
+    IUnknown *unk, *unk2;
     ITypeLib *tl;
     ITypeInfo *ti;
-    IUnknown *unk;
     HRESULT hr;
 
     hr = CreateStdDispatch(NULL, NULL, NULL, NULL);
@@ -331,6 +370,33 @@ static void test_CreateStdDispatch(void)
 
     hr = CreateStdDispatch(NULL, &test_unk, ti, &unk);
     ok(hr == S_OK, "got %08lx\n", hr);
+    hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void **)&disp);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok((IUnknown *)disp != unk, "Unexpected interface pointer %p.\n", disp);
+    IDispatch_Release(disp);
+
+    IUnknown_Release(unk);
+
+    /* With aggregation */
+    hr = CreateStdDispatch(&outer_test_unk, &test_unk, ti, &unk);
+    ok(hr == S_OK, "got %08lx\n", hr);
+
+    hr = IUnknown_QueryInterface(unk, &IID_IDispatch, (void **)&disp);
+    ok(hr == S_OK, "got %08lx\n", hr);
+    ok((IUnknown *)disp != unk, "Unexpected interface pointer %p.\n", disp);
+
+    /* Outer does not support IDispatch */
+    disp2 = (void *)0x1;
+    hr = IDispatch_QueryInterface(disp, &IID_IDispatch, (void **)&disp2);
+    ok(hr == 0x80010003, "Unexpected hr %#lx.\n", hr);
+    ok(!disp2, "Unexpected pointer %p.\n", disp2);
+
+    hr = IDispatch_QueryInterface(disp, &IID_IUnknown, (void **)&unk2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(unk2 == &outer_test_unk, "Unexpected pointer %p.\n", unk2);
+    IUnknown_Release(unk2);
+
+    IDispatch_Release(disp);
     IUnknown_Release(unk);
 
     ITypeInfo_Release(ti);
diff --git a/dlls/pdh/pdh.spec b/dlls/pdh/pdh.spec
index 1e6289c55848..93db4f56eea5 100644
--- a/dlls/pdh/pdh.spec
+++ b/dlls/pdh/pdh.spec
@@ -58,8 +58,8 @@
 @ stub PdhGetDefaultPerfObjectHW
 @ stub PdhGetDefaultPerfObjectW
 @ stdcall PdhGetDllVersion(ptr)
-@ stub PdhGetFormattedCounterArrayA
-@ stub PdhGetFormattedCounterArrayW
+@ stdcall PdhGetFormattedCounterArrayA(ptr long ptr ptr ptr)
+@ stdcall PdhGetFormattedCounterArrayW(ptr long ptr ptr ptr)
 @ stdcall PdhGetFormattedCounterValue(ptr long ptr ptr)
 @ stub PdhGetLogFileSize
 @ stdcall PdhGetLogFileTypeA(str ptr)
diff --git a/dlls/pdh/pdh_main.c b/dlls/pdh/pdh_main.c
index 2cd7afeed58b..55315cda71a8 100644
--- a/dlls/pdh/pdh_main.c
+++ b/dlls/pdh/pdh_main.c
@@ -761,6 +761,108 @@ PDH_STATUS WINAPI PdhGetFormattedCounterValue( PDH_HCOUNTER handle, DWORD format
     return ret;
 }
 
+/* caller must hold counter lock; PDH_FMT_COUNTERVALUE_ITEM_A and _W share the same layout */
+static PDH_STATUS get_formatted_counter_array( PDH_HCOUNTER handle, DWORD format,
+                                                LPDWORD bufsize, LPDWORD count, void *buffer, BOOL wide )
+{
+    PDH_STATUS ret;
+    struct counter *counter = handle;
+    PDH_FMT_COUNTERVALUE value;
+    DWORD needed = sizeof(PDH_FMT_COUNTERVALUE_ITEM_W) + (wide ? sizeof(WCHAR) : sizeof(CHAR));
+
+    *count = 1;
+
+    if (!buffer || *bufsize < needed)
+    {
+        *bufsize = needed;
+        return PDH_MORE_DATA;
+    }
+
+    if (!(ret = format_value( counter, format, &counter->one, &counter->two, &value )))
+    {
+        PPDH_FMT_COUNTERVALUE_ITEM_W item = buffer;
+        char *name = (char *)buffer + sizeof(PDH_FMT_COUNTERVALUE_ITEM_W);
+        item->FmtValue = value;
+        item->FmtValue.CStatus = ERROR_SUCCESS;
+        if (wide)
+        {
+            item->szName = (LPWSTR)name;
+            *(WCHAR *)name = 0;
+        }
+        else
+        {
+            ((PPDH_FMT_COUNTERVALUE_ITEM_A)item)->szName = (LPSTR)name;
+            *name = 0;
+        }
+    }
+    *bufsize = needed;
+    return ret;
+}
+
+/***********************************************************************
+ *              PdhGetFormattedCounterArrayW   (PDH.@)
+ */
+PDH_STATUS WINAPI PdhGetFormattedCounterArrayW( PDH_HCOUNTER handle, DWORD format,
+                                                 LPDWORD bufsize, LPDWORD count,
+                                                 PPDH_FMT_COUNTERVALUE_ITEM_W buffer )
+{
+    PDH_STATUS ret;
+    struct counter *counter = handle;
+
+    TRACE("%p %lx %p %p %p\n", handle, format, bufsize, count, buffer);
+
+    if (!bufsize || !count || !handle) return PDH_INVALID_ARGUMENT;
+
+    EnterCriticalSection( &pdh_handle_cs );
+    if (counter->magic != PDH_MAGIC_COUNTER)
+    {
+        LeaveCriticalSection( &pdh_handle_cs );
+        return PDH_INVALID_HANDLE;
+    }
+    if (counter->status)
+    {
+        LeaveCriticalSection( &pdh_handle_cs );
+        return PDH_INVALID_DATA;
+    }
+
+    ret = get_formatted_counter_array( handle, format, bufsize, count, buffer, TRUE );
+
+    LeaveCriticalSection( &pdh_handle_cs );
+    return ret;
+}
+
+/***********************************************************************
+ *              PdhGetFormattedCounterArrayA   (PDH.@)
+ */
+PDH_STATUS WINAPI PdhGetFormattedCounterArrayA( PDH_HCOUNTER handle, DWORD format,
+                                                 LPDWORD bufsize, LPDWORD count,
+                                                 PPDH_FMT_COUNTERVALUE_ITEM_A buffer )
+{
+    PDH_STATUS ret;
+    struct counter *counter = handle;
+
+    TRACE("%p %lx %p %p %p\n", handle, format, bufsize, count, buffer);
+
+    if (!bufsize || !count || !handle) return PDH_INVALID_ARGUMENT;
+
+    EnterCriticalSection( &pdh_handle_cs );
+    if (counter->magic != PDH_MAGIC_COUNTER)
+    {
+        LeaveCriticalSection( &pdh_handle_cs );
+        return PDH_INVALID_HANDLE;
+    }
+    if (counter->status)
+    {
+        LeaveCriticalSection( &pdh_handle_cs );
+        return PDH_INVALID_DATA;
+    }
+
+    ret = get_formatted_counter_array( handle, format, bufsize, count, buffer, FALSE );
+
+    LeaveCriticalSection( &pdh_handle_cs );
+    return ret;
+}
+
 /***********************************************************************
  *              PdhGetRawCounterValue   (PDH.@)
  */
diff --git a/dlls/pdh/tests/pdh.c b/dlls/pdh/tests/pdh.c
index 5408e4cc3f32..4920289475a6 100644
--- a/dlls/pdh/tests/pdh.c
+++ b/dlls/pdh/tests/pdh.c
@@ -426,6 +426,184 @@ static void test_PdhGetRawCounterValue( void )
     ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08lx\n", ret);
 }
 
+static void test_PdhGetFormattedCounterArrayW( void )
+{
+    PDH_STATUS ret;
+    PDH_HQUERY query;
+    PDH_HCOUNTER counter;
+    PDH_FMT_COUNTERVALUE_ITEM_W buffer[2];
+    PDH_FMT_COUNTERVALUE value;
+    DWORD size, count;
+
+    ret = PdhOpenQueryW( NULL, 0, &query );
+    ok(ret == ERROR_SUCCESS, "PdhOpenQueryW failed 0x%08lx\n", ret);
+
+    ret = PdhAddCounterW( query, system_uptime, 0, &counter );
+    ok(ret == ERROR_SUCCESS, "PdhAddCounterW failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayW( NULL, PDH_FMT_LARGE, NULL, NULL, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayW( NULL, PDH_FMT_LARGE, &size, &count, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, NULL, &count, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, &size, NULL, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    size = 0;
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, &size, &count, NULL );
+    ok(ret == PDH_MORE_DATA, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+    ok(size == sizeof(*buffer) + sizeof(WCHAR), "expected %lu got %lu\n",
+       (DWORD)(sizeof(*buffer) + sizeof(WCHAR)), size);
+    ok(count == 1, "expected 1 got %lu\n", count);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+    ok(size == sizeof(*buffer) + sizeof(WCHAR), "expected %lu got %lu\n",
+       (DWORD)(sizeof(*buffer) + sizeof(WCHAR)), size);
+    ok(count == 1, "expected 1 got %lu\n", count);
+    ok(buffer[0].szName == (LPWSTR)((char *)buffer + sizeof(*buffer)),
+       "expected %p got %p\n", (LPWSTR)((char *)buffer + sizeof(*buffer)), buffer[0].szName);
+    ok(buffer[0].FmtValue.CStatus == ERROR_SUCCESS, "expected ERROR_SUCCESS got %lx\n", buffer[0].FmtValue.CStatus);
+
+    ret = PdhCollectQueryData( query );
+    ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+    ok(count == 1, "expected 1 got %lu\n", count);
+
+    ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+    ok(buffer[0].FmtValue.largeValue == value.largeValue,
+       "expected %s got %s\n", wine_dbgstr_longlong(value.largeValue),
+       wine_dbgstr_longlong(buffer[0].FmtValue.largeValue));
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LONG, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_DOUBLE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE | PDH_FMT_1000, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    size = 0;
+    ret = PdhGetFormattedCounterArrayW( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == PDH_MORE_DATA, "PdhGetFormattedCounterArrayW failed 0x%08lx\n", ret);
+
+    ret = PdhCloseQuery( query );
+    ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08lx\n", ret);
+}
+
+static void test_PdhGetFormattedCounterArrayA( void )
+{
+    PDH_STATUS ret;
+    PDH_HQUERY query;
+    PDH_HCOUNTER counter;
+    PDH_FMT_COUNTERVALUE_ITEM_A buffer[2];
+    PDH_FMT_COUNTERVALUE value;
+    DWORD size, count;
+
+    ret = PdhOpenQueryA( NULL, 0, &query );
+    ok(ret == ERROR_SUCCESS, "PdhOpenQueryA failed 0x%08lx\n", ret);
+
+    ret = PdhAddCounterA( query, "\\System\\System Up Time", 0, &counter );
+    ok(ret == ERROR_SUCCESS, "PdhAddCounterA failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayA( NULL, PDH_FMT_LARGE, NULL, NULL, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayA( NULL, PDH_FMT_LARGE, &size, &count, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, NULL, &count, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, &size, NULL, NULL );
+    ok(ret == PDH_INVALID_ARGUMENT, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    size = 0;
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, &size, &count, NULL );
+    ok(ret == PDH_MORE_DATA, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+    ok(size == sizeof(*buffer) + sizeof(CHAR), "expected %lu got %lu\n",
+       (DWORD)(sizeof(*buffer) + sizeof(CHAR)), size);
+    ok(count == 1, "expected 1 got %lu\n", count);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+    ok(size == sizeof(*buffer) + sizeof(CHAR), "expected %lu got %lu\n",
+       (DWORD)(sizeof(*buffer) + sizeof(CHAR)), size);
+    ok(count == 1, "expected 1 got %lu\n", count);
+    ok(buffer[0].szName == (LPSTR)((char *)buffer + sizeof(*buffer)),
+       "expected %p got %p\n", (LPSTR)((char *)buffer + sizeof(*buffer)), buffer[0].szName);
+    ok(buffer[0].FmtValue.CStatus == ERROR_SUCCESS, "expected ERROR_SUCCESS got %lx\n", buffer[0].FmtValue.CStatus);
+
+    ret = PdhCollectQueryData( query );
+    ok(ret == ERROR_SUCCESS, "PdhCollectQueryData failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+    ok(count == 1, "expected 1 got %lu\n", count);
+
+    ret = PdhGetFormattedCounterValue( counter, PDH_FMT_LARGE, NULL, &value );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterValue failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+    ok(buffer[0].FmtValue.largeValue == value.largeValue,
+       "expected %s got %s\n", wine_dbgstr_longlong(value.largeValue),
+       wine_dbgstr_longlong(buffer[0].FmtValue.largeValue));
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LONG, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_DOUBLE, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    size = sizeof(buffer);
+    count = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE | PDH_FMT_1000, &size, &count, buffer );
+    ok(ret == ERROR_SUCCESS, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    size = 0;
+    ret = PdhGetFormattedCounterArrayA( counter, PDH_FMT_LARGE, &size, &count, buffer );
+    ok(ret == PDH_MORE_DATA, "PdhGetFormattedCounterArrayA failed 0x%08lx\n", ret);
+
+    ret = PdhCloseQuery( query );
+    ok(ret == ERROR_SUCCESS, "PdhCloseQuery failed 0x%08lx\n", ret);
+}
+
 static void test_PdhVbGetDoubleCounterValue(void)
 {
     PDH_FMT_COUNTERVALUE value;
@@ -1037,6 +1215,8 @@ START_TEST(pdh)
 
     test_PdhGetFormattedCounterValue();
     test_PdhGetRawCounterValue();
+    test_PdhGetFormattedCounterArrayW();
+    test_PdhGetFormattedCounterArrayA();
     test_PdhSetCounterScaleFactor();
     test_PdhGetCounterTimeBase();
 
diff --git a/dlls/qwave/Makefile.in b/dlls/qwave/Makefile.in
index 6ae6d18c0e1b..6a82e042ebab 100644
--- a/dlls/qwave/Makefile.in
+++ b/dlls/qwave/Makefile.in
@@ -1,7 +1,5 @@
 MODULE    = qwave.dll
 IMPORTLIB = qwave
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	main.c
diff --git a/dlls/rstrtmgr/Makefile.in b/dlls/rstrtmgr/Makefile.in
index b7f6ad8a741c..b369bff972c0 100644
--- a/dlls/rstrtmgr/Makefile.in
+++ b/dlls/rstrtmgr/Makefile.in
@@ -1,6 +1,4 @@
 MODULE    = rstrtmgr.dll
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	main.c
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c
index 8f36ead4ef38..121dda98a59e 100644
--- a/dlls/setupapi/devinst.c
+++ b/dlls/setupapi/devinst.c
@@ -3132,6 +3132,63 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
         return FALSE;
     }
 
+    if (Property == SPDRP_ENUMERATOR_NAME)
+    {
+        const WCHAR *backslash;
+        DWORD len;
+        int size_needed, size_written;
+
+        if (!device->instanceId || !*device->instanceId)
+        {
+            SetLastError(ERROR_INVALID_DATA);
+            return FALSE;
+        }
+
+        backslash = wcschr(device->instanceId, L'\\');
+        len = backslash ? (DWORD)(backslash - device->instanceId) : lstrlenW(device->instanceId);
+        if (len == 0)
+        {
+            SetLastError(ERROR_INVALID_DATA);
+            return FALSE;
+        }
+
+        size_needed = WideCharToMultiByte(CP_ACP, 0, device->instanceId, len, NULL, 0, NULL, NULL);
+        if (size_needed <= 0)
+        {
+            SetLastError(ERROR_INVALID_DATA);
+            return FALSE;
+        }
+
+        size_needed++;
+
+        if (RequiredSize)
+            *RequiredSize = size_needed;
+
+        if (PropertyRegDataType)
+            *PropertyRegDataType = REG_SZ;
+
+        if (!PropertyBuffer || (int)PropertyBufferSize < size_needed)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            return FALSE;
+        }
+
+        size_written = WideCharToMultiByte(CP_ACP, 0,
+                                           device->instanceId, len,
+                                           (char *)PropertyBuffer,
+                                           PropertyBufferSize - 1,
+                                           NULL, NULL);
+
+        if (size_written <= 0)
+        {
+            SetLastError(ERROR_INVALID_DATA);
+            return FALSE;
+        }
+
+        ((char *)PropertyBuffer)[size_written] = 0;
+        return TRUE;
+    }
+
     if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameA)
     {
         DWORD size = PropertyBufferSize;
@@ -3149,6 +3206,10 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyA(HDEVINFO devinfo,
         if (RequiredSize)
             *RequiredSize = size;
     }
+    else
+    {
+        SetLastError(ERROR_INVALID_DATA);
+    }
     return ret;
 }
 
@@ -3174,6 +3235,44 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
         return FALSE;
     }
 
+    if (Property == SPDRP_ENUMERATOR_NAME)
+    {
+        const WCHAR *backslash;
+        DWORD len, size_needed;
+
+        if (!device->instanceId || !*device->instanceId)
+        {
+            SetLastError(ERROR_INVALID_DATA);
+            return FALSE;
+        }
+
+        backslash = wcschr(device->instanceId, L'\\');
+        len = backslash ? (DWORD)(backslash - device->instanceId) : lstrlenW(device->instanceId);
+        if (len == 0)
+        {
+            SetLastError(ERROR_INVALID_DATA);
+            return FALSE;
+        }
+
+        size_needed = (len + 1) * sizeof(WCHAR);
+
+        if (RequiredSize)
+            *RequiredSize = size_needed;
+
+        if (PropertyRegDataType)
+            *PropertyRegDataType = REG_SZ;
+
+        if (!PropertyBuffer || PropertyBufferSize < size_needed)
+        {
+            SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            return FALSE;
+        }
+
+        memcpy(PropertyBuffer, device->instanceId, len * sizeof(WCHAR));
+        ((WCHAR *)PropertyBuffer)[len] = 0;
+        return TRUE;
+    }
+
     if (Property < ARRAY_SIZE(PropertyMap) && PropertyMap[Property].nameW)
     {
         DWORD size = PropertyBufferSize;
@@ -3191,6 +3290,10 @@ BOOL WINAPI SetupDiGetDeviceRegistryPropertyW(HDEVINFO devinfo,
         if (RequiredSize)
             *RequiredSize = size;
     }
+    else
+    {
+        SetLastError(ERROR_INVALID_DATA);
+    }
     return ret;
 }
 
diff --git a/dlls/setupapi/fakedll.c b/dlls/setupapi/fakedll.c
index 9daef65c5b29..4dce22b98243 100644
--- a/dlls/setupapi/fakedll.c
+++ b/dlls/setupapi/fakedll.c
@@ -502,11 +502,13 @@ static HANDLE create_dest_file( const WCHAR *name, BOOL delete )
         }
         /* truncate the file */
         SetFilePointer( h, 0, NULL, FILE_BEGIN );
-        SetEndOfFile( h );
+        if (SetEndOfFile( h )) return h;
+        CloseHandle( h );
     }
-    else if (GetLastError() == ERROR_SHARING_VIOLATION &&
-             (h = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
-                               OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE)
+
+    if ((GetLastError() == ERROR_SHARING_VIOLATION || GetLastError() == ERROR_USER_MAPPED_FILE) &&
+        (h = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
+                          OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE)
     {
         if (!is_fake_dll( h ))
         {
diff --git a/dlls/setupapi/tests/devinst.c b/dlls/setupapi/tests/devinst.c
index d21a78b36ad5..de29d93edd32 100644
--- a/dlls/setupapi/tests/devinst.c
+++ b/dlls/setupapi/tests/devinst.c
@@ -2438,6 +2438,46 @@ todo_wine {
     ok(ret, "Failed to get property, error %#lx.\n", GetLastError());
     ok(!lstrcmpA(buf, "device_name"), "Got unexpected value %s.\n", buf);
 
+    /* SPDRP_UNUSED0: PropertyMap[3].nameW == NULL, fix returns ERROR_INVALID_DATA */
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_UNUSED0, NULL, (BYTE *)buf, sizeof(buf), NULL);
+    ok(!ret, "Expected failure for SPDRP_UNUSED0.\n");
+    ok(GetLastError() == ERROR_INVALID_DATA, "Got unexpected error %#lx for SPDRP_UNUSED0.\n", GetLastError());
+
+    /* SPDRP_ENUMERATOR_NAME: enumerator is first segment of instanceId ("ROOT\...\0000" → "ROOT") */
+    memset(buf, 0, sizeof(buf));
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, sizeof(buf), NULL);
+    ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError());
+    ok(!strcmp(buf, "ROOT"), "Got unexpected enumerator '%s', expected 'ROOT'.\n", buf);
+
+    /* SPDRP_ENUMERATOR_NAME: test PropertyRegDataType output */
+    memset(buf, 0, sizeof(buf));
+    type = 0xdeadbeef;
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, &type, (BYTE *)buf, sizeof(buf), NULL);
+    ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError());
+    ok(type == REG_SZ, "Got unexpected type %#lx, expected REG_SZ.\n", type);
+
+    /* SPDRP_ENUMERATOR_NAME: test RequiredSize output (PropertyBuffer=NULL, PropertyBufferSize=0) */
+    size = 0xdeadbeef;
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, 0, &size);
+    ok(!ret, "Expected failure for NULL buffer.\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError());
+    ok(size > 0, "Got unexpected size %lu.\n", size);
+
+    /* SPDRP_ENUMERATOR_NAME: test with buffer too small */
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, 3, &size);
+    ok(!ret, "Expected failure for small buffer.\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError());
+
+    /* SPDRP_ENUMERATOR_NAME: PropertyBuffer is NULL but PropertyBufferSize > 0 */
+    /* Windows returns ERROR_INVALID_PARAMETER (A) or ERROR_PARTIAL_COPY (W) here,
+     * Wine returns ERROR_INVALID_DATA. Just check for failure. */
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyA(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, sizeof(buf), NULL);
+    ok(!ret, "Expected failure for NULL buffer with size.\n");
+
     SetupDiDestroyDeviceInfoList(set);
 
     /* Create device from a registered class */
@@ -2598,6 +2638,46 @@ todo_wine {
     ok(ret, "Failed to get property, error %#lx.\n", GetLastError());
     ok(!lstrcmpW(buf, L"device_name"), "Got unexpected value %s.\n", wine_dbgstr_w(buf));
 
+    /* SPDRP_UNUSED0: PropertyMap[3].nameW == NULL, fix returns ERROR_INVALID_DATA */
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_UNUSED0, NULL, (BYTE *)buf, sizeof(buf), NULL);
+    ok(!ret, "Expected failure for SPDRP_UNUSED0.\n");
+    ok(GetLastError() == ERROR_INVALID_DATA, "Got unexpected error %#lx for SPDRP_UNUSED0.\n", GetLastError());
+
+    /* SPDRP_ENUMERATOR_NAME: enumerator is first segment of instanceId ("ROOT\...\0000" → "ROOT") */
+    memset(buf, 0, sizeof(buf));
+    ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, sizeof(buf), NULL);
+    ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError());
+    ok(!lstrcmpW(buf, L"ROOT"), "Got unexpected enumerator %s.\n", wine_dbgstr_w(buf));
+
+    /* SPDRP_ENUMERATOR_NAME: test PropertyRegDataType output */
+    memset(buf, 0, sizeof(buf));
+    type = 0xdeadbeef;
+    ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, &type, (BYTE *)buf, sizeof(buf), NULL);
+    ok(ret, "Failed to get SPDRP_ENUMERATOR_NAME, error %#lx.\n", GetLastError());
+    ok(type == REG_SZ, "Got unexpected type %#lx, expected REG_SZ.\n", type);
+
+    /* SPDRP_ENUMERATOR_NAME: test RequiredSize output (PropertyBuffer=NULL, PropertyBufferSize=0) */
+    size = 0xdeadbeef;
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, 0, &size);
+    ok(!ret, "Expected failure for NULL buffer.\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError());
+    ok(size > 0, "Got unexpected size %lu.\n", size);
+
+    /* SPDRP_ENUMERATOR_NAME: test with buffer too small */
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, (BYTE *)buf, 3 * sizeof(WCHAR), &size);
+    ok(!ret, "Expected failure for small buffer.\n");
+    ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got unexpected error %#lx.\n", GetLastError());
+
+    /* SPDRP_ENUMERATOR_NAME: PropertyBuffer is NULL but PropertyBufferSize > 0 */
+    /* Windows returns ERROR_INVALID_PARAMETER (A) or ERROR_PARTIAL_COPY (W) here,
+     * Wine returns ERROR_INVALID_DATA. Just check for failure. */
+    SetLastError(0xdeadbeef);
+    ret = SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_ENUMERATOR_NAME, NULL, NULL, sizeof(buf), NULL);
+    ok(!ret, "Expected failure for NULL buffer with size.\n");
+
     SetupDiDestroyDeviceInfoList(set);
 
     /* Create device from a registered class */
diff --git a/dlls/shell32/shellpath.c b/dlls/shell32/shellpath.c
index 6eb5d5cc3457..bf13a7351f01 100644
--- a/dlls/shell32/shellpath.c
+++ b/dlls/shell32/shellpath.c
@@ -2094,6 +2094,15 @@ static const CSIDL_DATA CSIDL_Data[] =
         .path       = L"Screenshots",
         .flags      = KFDF_PRECREATE | KFDF_ROAMABLE,
     },
+    { /* 0x75 */
+        .id         = &FOLDERID_AppDataDocuments,
+        .type       = CSIDL_Type_User,
+        .category   = KF_CATEGORY_PERUSER,
+        .name       = L"AppDataDocuments",
+        .parent     = &FOLDERID_LocalAppData,
+        .path       = L"Documents",
+        .flags      = KFDF_PRECREATE | KFDF_ROAMABLE,
+    },
 };
 
 static int csidl_from_id( const KNOWNFOLDERID *id )
diff --git a/dlls/shell32/tests/shellpath.c b/dlls/shell32/tests/shellpath.c
index d1674b3ff039..42e82682ef1e 100644
--- a/dlls/shell32/tests/shellpath.c
+++ b/dlls/shell32/tests/shellpath.c
@@ -1332,6 +1332,15 @@ static const struct knownFolderDef known_folders[] = {
                  NULL,
                  0,
                  KFDF_PRECREATE | KFDF_ROAMABLE),
+    KNOWN_FOLDER(FOLDERID_AppDataDocuments,
+                 NO_CSIDL,
+                 "AppDataDocuments",
+                 KF_CATEGORY_PERUSER,
+                 FOLDERID_LocalAppData, GUID_NULL,
+                 "Documents",
+                 NULL,
+                 0,
+                 KFDF_PRECREATE | KFDF_ROAMABLE),
 };
 #undef KNOWN_FOLDER
 BOOL known_folder_found[ARRAY_SIZE(known_folders)];
diff --git a/dlls/shell32/tests/shlfileop.c b/dlls/shell32/tests/shlfileop.c
index 000b213b46b9..aa04ac87160f 100644
--- a/dlls/shell32/tests/shlfileop.c
+++ b/dlls/shell32/tests/shlfileop.c
@@ -183,6 +183,7 @@ static void clean_after_shfo_tests(void)
     DeleteFileA("testdir4\\nested\\subnested\\3.txt");
     DeleteFileA("testdir4\\nested\\two.txt");
     DeleteFileA("testdir4\\nested\\2.txt");
+    DeleteFileA("testdir4\\one.txt");
     RemoveDirectoryA("testdir4\\nested\\subnested");
     RemoveDirectoryA("testdir4\\nested");
     RemoveDirectoryA("testdir4");
@@ -843,6 +844,9 @@ static void test_rename(void)
         check_file_operation(FO_RENAME, FOF_NO_UI,
                 "testdir2\0", "testdir4\0",
                 ERROR_SUCCESS, FALSE, TRUE, FALSE);
+        todo_wine
+        ok(!dir_exists("testdir2"), "The dir is not renamed\n");
+        ok(dir_exists("testdir4"), "The dir is not renamed\n");
     }
     else
         win_skip("Skip FO_RENAME with already existing target directory.\n");
diff --git a/dlls/slc/Makefile.in b/dlls/slc/Makefile.in
index 440e7af4c27d..5ccfb14d24ed 100644
--- a/dlls/slc/Makefile.in
+++ b/dlls/slc/Makefile.in
@@ -2,7 +2,5 @@ EXTRADEFS = -D_SLC_
 MODULE    = slc.dll
 IMPORTLIB = slc
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	slc.c
diff --git a/dlls/svrapi/Makefile.in b/dlls/svrapi/Makefile.in
index 4ebcc804cda3..2f6fc7513546 100644
--- a/dlls/svrapi/Makefile.in
+++ b/dlls/svrapi/Makefile.in
@@ -1,3 +1 @@
 MODULE    = svrapi.dll
-
-EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uianimation/Makefile.in b/dlls/uianimation/Makefile.in
index 29192a60c6e6..326f8bd83c35 100644
--- a/dlls/uianimation/Makefile.in
+++ b/dlls/uianimation/Makefile.in
@@ -1,8 +1,6 @@
 MODULE    = uianimation.dll
 IMPORTS   = uuid
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	main.c \
 	uianimation_reg.idl \
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in
index 008c7b1deb19..d421b8a37b02 100644
--- a/dlls/uiautomationcore/Makefile.in
+++ b/dlls/uiautomationcore/Makefile.in
@@ -2,8 +2,6 @@ MODULE = uiautomationcore.dll
 IMPORTLIB = uiautomationcore
 IMPORTS   = uuid ole32 oleaut32 user32 oleacc
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	uia_classes.idl \
 	uia_classes_client.idl \
diff --git a/dlls/user32/clipboard.c b/dlls/user32/clipboard.c
index 3c3ba7c584c9..4a05d40dc1e5 100644
--- a/dlls/user32/clipboard.c
+++ b/dlls/user32/clipboard.c
@@ -1158,7 +1158,14 @@ void drag_drop_leave(void)
 
     TRACE("DND Operation canceled\n");
 
-    if ((object = get_data_object( TRUE ))) IDataObject_Release( &object->IDataObject_iface );
+    if (!(object = get_data_object( TRUE ))) return;
+    if (object->drop_target)
+    {
+        IDropTarget_DragLeave( object->drop_target );
+        IDropTarget_Release( object->drop_target );
+        object->drop_target = NULL;
+    }
+    IDataObject_Release( &object->IDataObject_iface );
 }
 
 DWORD drag_drop_drag( HWND hwnd, POINT point, DWORD effect )
@@ -1276,8 +1283,6 @@ DWORD drag_drop_drop( HWND hwnd )
     {
         HRESULT hr = IDropTarget_DragLeave( object->drop_target );
         if (FAILED(hr)) WARN( "IDropTarget_DragLeave returned %#lx\n", hr );
-        IDropTarget_Release( object->drop_target );
-        object->drop_target = NULL;
     }
 
     if (drop_file)
@@ -1306,6 +1311,12 @@ DWORD drag_drop_drop( HWND hwnd )
         }
     }
 
+     if (object->drop_target)
+    {
+        IDropTarget_Release( object->drop_target );
+        object->drop_target = NULL;
+    }
+
     TRACE("effectRequested(0x%lx) accept(%d) performed(0x%lx) at x(%ld),y(%ld)\n",
           object->target_effect, accept, effect, object->target_pos.x, object->target_pos.y);
 
diff --git a/dlls/uxtheme/system.c b/dlls/uxtheme/system.c
index 8f963115cde1..b5f659d05171 100644
--- a/dlls/uxtheme/system.c
+++ b/dlls/uxtheme/system.c
@@ -1334,3 +1334,50 @@ BOOLEAN WINAPI IsDarkModeAllowedForWindow(HWND hwnd)
     FIXME("%p: stub\n", hwnd);
     return FALSE;
 }
+
+/**********************************************************************
+ *      GetImmersiveColorFromColorSetEx                    (UXTHEME.95)
+ *
+ * Semi-stub: the immersive color tables are not implemented; return a
+ * color following ShouldAppsUseDarkMode (black for light, white for dark).
+ */
+DWORD WINAPI GetImmersiveColorFromColorSetEx(UINT color_set, UINT color_type,
+                                             BOOL ignore_high_contrast, UINT high_contrast_cache_mode)
+{
+    FIXME("%u %u %d %u: semi-stub\n", color_set, color_type,
+          ignore_high_contrast, high_contrast_cache_mode);
+
+    return ShouldAppsUseDarkMode() ? 0xffffffff : 0xff000000;
+}
+
+/**********************************************************************
+ *      GetImmersiveColorTypeFromName                      (UXTHEME.96)
+ *
+ */
+UINT WINAPI GetImmersiveColorTypeFromName(const WCHAR *name)
+{
+    FIXME("%s: stub\n", debugstr_w(name));
+    return ~0u;
+}
+
+/**********************************************************************
+ *      GetImmersiveUserColorSetPreference                 (UXTHEME.98)
+ *
+ */
+int WINAPI GetImmersiveUserColorSetPreference(BOOL force_check_registry, BOOL skip_check_on_fail)
+{
+    FIXME("%d %d: stub\n", force_check_registry, skip_check_on_fail);
+    return 0;
+}
+
+/**********************************************************************
+ *      GetImmersiveColorNamedTypeByIndex                 (UXTHEME.100)
+ *
+ * Returns a pointer to the color type name at the given index, without
+ * its "Immersive" prefix, or NULL when the index is out of range.
+ */
+const WCHAR ** WINAPI GetImmersiveColorNamedTypeByIndex(UINT index)
+{
+    FIXME("%u: stub\n", index);
+    return NULL;
+}
diff --git a/dlls/uxtheme/tests/system.c b/dlls/uxtheme/tests/system.c
index 6c7993e5757f..fda57bbe1479 100644
--- a/dlls/uxtheme/tests/system.c
+++ b/dlls/uxtheme/tests/system.c
@@ -52,6 +52,10 @@ static HRESULT (WINAPI *pGetThemeIntList)(HTHEME, int, int, int, INTLIST *);
 static HRESULT (WINAPI *pGetThemeTransitionDuration)(HTHEME, int, int, int, int, DWORD *);
 static BOOLEAN (WINAPI *pShouldSystemUseDarkMode)(void);
 static BOOLEAN (WINAPI *pShouldAppsUseDarkMode)(void);
+static DWORD (WINAPI *pGetImmersiveColorFromColorSetEx)(UINT, UINT, BOOL, UINT);
+static UINT (WINAPI *pGetImmersiveColorTypeFromName)(const WCHAR *);
+static int (WINAPI *pGetImmersiveUserColorSetPreference)(BOOL, BOOL);
+static const WCHAR ** (WINAPI *pGetImmersiveColorNamedTypeByIndex)(UINT);
 
 static LONG (WINAPI *pDisplayConfigGetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER *);
 static LONG (WINAPI *pDisplayConfigSetDeviceInfo)(DISPLAYCONFIG_DEVICE_INFO_HEADER *);
@@ -82,6 +86,8 @@ static void init_funcs(void)
     pCloseThemeFile = (void *)GetProcAddress(uxtheme, MAKEINTRESOURCEA(3));
     pShouldSystemUseDarkMode = (void *)GetProcAddress(uxtheme, MAKEINTRESOURCEA(138));
     pShouldAppsUseDarkMode = (void *)GetProcAddress(uxtheme, MAKEINTRESOURCEA(132));
+    pGetImmersiveColorTypeFromName = (void *)GetProcAddress(uxtheme, MAKEINTRESOURCEA(96));
+    pGetImmersiveColorNamedTypeByIndex = (void *)GetProcAddress(uxtheme, MAKEINTRESOURCEA(100));
 
 #define GET_PROC(module, func)                       \
     p##func = (void *)GetProcAddress(module, #func); \
@@ -100,6 +106,8 @@ static void init_funcs(void)
     GET_PROC(uxtheme, GetThemeTransitionDuration)
     GET_PROC(uxtheme, OpenThemeDataEx)
     GET_PROC(uxtheme, OpenThemeDataForDpi)
+    GET_PROC(uxtheme, GetImmersiveColorFromColorSetEx)
+    GET_PROC(uxtheme, GetImmersiveUserColorSetPreference)
 
     GET_PROC(user32, DisplayConfigGetDeviceInfo)
     GET_PROC(user32, DisplayConfigSetDeviceInfo)
@@ -2778,6 +2786,45 @@ static void test_ShouldAppsUseDarkMode(void)
     ok(result == !light_theme, "Expected value %d, got %d\n", !light_theme, result);
 }
 
+static void test_GetImmersiveColors(void)
+{
+    const WCHAR **name;
+    DWORD color;
+    UINT type;
+    int pref;
+
+    if (!pGetImmersiveColorFromColorSetEx || !pGetImmersiveColorTypeFromName
+        || !pGetImmersiveUserColorSetPreference || !pGetImmersiveColorNamedTypeByIndex)
+    {
+        win_skip("Immersive color set functions are unavailable.\n");
+        return;
+    }
+
+    pref = pGetImmersiveUserColorSetPreference(FALSE, FALSE);
+    ok(pref >= 0, "Got unexpected color set preference %d.\n", pref);
+
+    type = pGetImmersiveColorTypeFromName(L"NoSuchImmersiveColorName");
+    ok(type == ~0u, "Got unexpected color type %#x.\n", type);
+
+    color = pGetImmersiveColorFromColorSetEx(pref, 0, FALSE, 0);
+    ok(color != 0, "Got unexpected color %#lx.\n", color);
+
+    name = pGetImmersiveColorNamedTypeByIndex(0);
+    todo_wine ok(!!name, "Got unexpected NULL color type name.\n");
+    if (name)
+    {
+        WCHAR full_name[128];
+
+        ok(*name && (*name)[0], "Got an empty color type name.\n");
+
+        /* Color type names are returned without their "Immersive" prefix. */
+        lstrcpyW(full_name, L"Immersive");
+        lstrcatW(full_name, *name);
+        type = pGetImmersiveColorTypeFromName(full_name);
+        ok(type != ~0u, "Got unexpected color type %#x for %s.\n", type, wine_dbgstr_w(full_name));
+    }
+}
+
 static void test_DrawThemeEdge(void)
 {
     HTHEME htheme;
@@ -2883,6 +2930,7 @@ START_TEST(system)
     test_theme(FALSE);
     test_ShouldSystemUseDarkMode();
     test_ShouldAppsUseDarkMode();
+    test_GetImmersiveColors();
     test_DrawThemeEdge();
     test_DrawThemeTextEx();
 
diff --git a/dlls/uxtheme/uxtheme.spec b/dlls/uxtheme/uxtheme.spec
index 60a258da9bcf..dec298c0edbe 100644
--- a/dlls/uxtheme/uxtheme.spec
+++ b/dlls/uxtheme/uxtheme.spec
@@ -43,6 +43,10 @@
 61 stdcall OpenThemeDataEx(ptr wstr long)
 62 stub -noname ServerClearStockObjects
 63 stub -noname MarkSelection
+95 stdcall GetImmersiveColorFromColorSetEx(long long long long)
+96 stdcall -noname GetImmersiveColorTypeFromName(wstr)
+98 stdcall GetImmersiveUserColorSetPreference(long long)
+100 stdcall -noname GetImmersiveColorNamedTypeByIndex(long)
 104 stdcall -noname RefreshImmersiveColorPolicyState()
 132 stdcall -noname ShouldAppsUseDarkMode()
 133 stdcall -noname AllowDarkModeForWindow(ptr long)
diff --git a/dlls/websocket/Makefile.in b/dlls/websocket/Makefile.in
index 9a8493d617c9..823783e00cd2 100644
--- a/dlls/websocket/Makefile.in
+++ b/dlls/websocket/Makefile.in
@@ -1,6 +1,4 @@
 MODULE    = websocket.dll
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	websocket.c
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index 32cb925b6012..28c8c1d50fcc 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -3151,7 +3151,7 @@ BOOL WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_P
         return FALSE;
     }
 
-    if (type != PT_POINTER) FIXME( "Pointer type %#x not implemented!", type );
+    if (type != PT_POINTER) FIXME( "Pointer type %#x not implemented\n", type );
 
     *entry_count = 1;
     *pointer_count = 1;
diff --git a/dlls/windows.ui/uisettings.c b/dlls/windows.ui/uisettings.c
index c816ed83d20a..ce967678c6be 100644
--- a/dlls/windows.ui/uisettings.c
+++ b/dlls/windows.ui/uisettings.c
@@ -286,7 +286,8 @@ static HRESULT WINAPI uisettings2_add_TextScaleFactorChanged( IUISettings2 *ifac
         EventRegistrationToken *cookie )
 {
     FIXME( "iface %p, handler %p, cookie %p stub!\n", iface, handler, cookie );
-    return E_NOTIMPL;
+    *cookie = dummy_cookie;
+    return S_OK;
 }
 
 static HRESULT WINAPI uisettings2_remove_TextScaleFactorChanged( IUISettings2 *iface, EventRegistrationToken cookie )
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 79014b4c3315..7f68edb36513 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -221,7 +221,6 @@ static void wined3d_disable_vulkan_features(struct wined3d_physical_device_info
     dynamic_state3->extendedDynamicState3LineRasterizationMode = VK_FALSE;
     dynamic_state3->extendedDynamicState3LineStippleEnable = VK_FALSE;
     dynamic_state3->extendedDynamicState3LogicOpEnable = VK_FALSE;
-    dynamic_state3->extendedDynamicState3PolygonMode = VK_FALSE;
     dynamic_state3->extendedDynamicState3ProvokingVertexMode = VK_FALSE;
     dynamic_state3->extendedDynamicState3RasterizationStream = VK_FALSE;
     dynamic_state3->extendedDynamicState3RepresentativeFragmentTestEnable = VK_FALSE;
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 11934fccad2a..62c5f40181e6 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -5005,6 +5005,7 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
     static struct wined3d_rendertarget_view *const views[WINED3D_MAX_RENDER_TARGETS];
     const struct wined3d_d3d_info *d3d_info = &device->adapter->d3d_info;
     struct wined3d_device_context *context = &device->cs->c;
+    BOOL backbuffer_resized, flags_changed, windowed;
     struct wined3d_swapchain_state *swapchain_state;
     struct wined3d_state *state = context->state;
     struct wined3d_swapchain_desc *current_desc;
@@ -5012,7 +5013,6 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
     struct wined3d_rendertarget_view *view;
     struct wined3d_swapchain *swapchain;
     struct wined3d_view_desc view_desc;
-    BOOL backbuffer_resized, windowed;
     HRESULT hr = WINED3D_OK;
     HWND device_window;
     unsigned int i;
@@ -5112,6 +5112,7 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
 
     backbuffer_resized = swapchain_desc->backbuffer_width != current_desc->backbuffer_width
             || swapchain_desc->backbuffer_height != current_desc->backbuffer_height;
+    flags_changed = swapchain_desc->flags != current_desc->flags;
     windowed = current_desc->windowed;
 
     if (!swapchain_desc->windowed != !windowed || swapchain->reapply_mode
@@ -5166,13 +5167,11 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device,
 
     if (FAILED(hr = wined3d_swapchain_resize_buffers(swapchain, swapchain_desc->backbuffer_count,
             swapchain_desc->backbuffer_width, swapchain_desc->backbuffer_height, swapchain_desc->backbuffer_format,
-            swapchain_desc->multisample_type, swapchain_desc->multisample_quality)))
+            swapchain_desc->multisample_type, swapchain_desc->multisample_quality, swapchain_desc->flags)))
         return hr;
 
-    if (swapchain_desc->flags != current_desc->flags)
+    if (flags_changed)
     {
-        current_desc->flags = swapchain_desc->flags;
-
         update_swapchain_flags(swapchain->front_buffer);
         for (i = 0; i < current_desc->backbuffer_count; ++i)
         {
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 06451c93d65f..01a16b17b4b0 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -2030,7 +2030,8 @@ void wined3d_swapchain_activate(struct wined3d_swapchain *swapchain, BOOL activa
 
 HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count,
         unsigned int width, unsigned int height, enum wined3d_format_id format_id,
-        enum wined3d_multisample_type multisample_type, unsigned int multisample_quality)
+        enum wined3d_multisample_type multisample_type, unsigned int multisample_quality,
+        unsigned int flags)
 {
     struct wined3d_swapchain_desc *desc = &swapchain->state.desc;
     bool recreate = false;
@@ -2096,6 +2097,13 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha
         recreate = true;
     }
 
+    if (flags)
+    {
+        if ((desc->flags ^ flags) & WINED3D_SWAPCHAIN_GDI_COMPATIBLE)
+            recreate = true;
+        desc->flags = flags;
+    }
+
     if (recreate)
     {
         struct wined3d_texture *new_texture;
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index 4f40e55f1bd1..da7db0c21840 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -310,7 +310,7 @@
 @ cdecl wined3d_swapchain_get_state(ptr)
 @ cdecl wined3d_swapchain_incref(ptr)
 @ cdecl wined3d_swapchain_present(ptr ptr ptr ptr long long)
-@ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long)
+@ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long long)
 @ cdecl wined3d_swapchain_set_gamma_ramp(ptr long ptr)
 @ cdecl wined3d_swapchain_set_max_frame_latency(ptr long)
 @ cdecl wined3d_swapchain_set_palette(ptr ptr)
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index f545df7ad0b1..24cef388bb59 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -192,7 +192,7 @@ struct wg_sample
     UINT32 flags;
     UINT32 max_size;
     UINT32 size;
-    UINT32 stride;
+    INT32 stride;
     UINT64 data; /* pointer to user memory */
 };
 
@@ -335,7 +335,7 @@ struct wg_parser_stream_seek_params
 struct wg_transform_attrs
 {
     UINT32 output_plane_align;
-    UINT32 output_plane_stride;
+    INT32 output_plane_stride;
     UINT32 input_queue_length;
     BOOL allow_format_change;
     BOOL low_latency;
diff --git a/dlls/winegstreamer/wg_sample.c b/dlls/winegstreamer/wg_sample.c
index 05a9425a98e1..5865df61b953 100644
--- a/dlls/winegstreamer/wg_sample.c
+++ b/dlls/winegstreamer/wg_sample.c
@@ -125,8 +125,6 @@ HRESULT wg_sample_create_mf(IMFSample *mf_sample, struct wg_sample **out)
             sample->u.mf.buffer = NULL;
             sample->u.mf.buffer2d = buffer2d;
             IMF2DBuffer2_GetContiguousLength(buffer2d, &current_length);
-            if (pitch < 0)
-                pitch = -pitch;
         }
         else
         {
diff --git a/dlls/winegstreamer/wg_transform.c b/dlls/winegstreamer/wg_transform.c
index 1537a88d6143..22c2f8ccf1e0 100644
--- a/dlls/winegstreamer/wg_transform.c
+++ b/dlls/winegstreamer/wg_transform.c
@@ -103,10 +103,11 @@ static struct wg_transform *get_transform(wg_transform_t trans)
     return (struct wg_transform *)(ULONG_PTR)trans;
 }
 
-static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align, guint stride,
+static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align, gint stride,
         GstVideoInfo *info, GstVideoAlignment *align)
 {
     bool fix_nv12 = !plane_align && info->finfo->format == GST_VIDEO_FORMAT_NV12 && (info->width & 3) && (info->width & 3) != 3;
+    bool bottom_up = video_info->VideoFlags & MFVideoFlag_BottomUpLinearRep;
     const MFVideoArea *aperture = &video_info->MinimumDisplayAperture;
 
     gst_video_alignment_reset(align);
@@ -133,6 +134,10 @@ static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align,
         gst_video_format_info_component(finfo, 0, comp);
         pixel_stride = finfo->pixel_stride[comp[0]];
 
+        bottom_up = stride < 0;
+        if (bottom_up)
+            stride = -stride;
+
         if (stride % pixel_stride)
             GST_ERROR("Stride %u not aligned to pixel size", stride);
         stride /= pixel_stride;
@@ -143,7 +148,7 @@ static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align,
             align->padding_right += stride - width;
     }
 
-    if (video_info->VideoFlags & MFVideoFlag_BottomUpLinearRep)
+    if (bottom_up)
     {
         gsize top = align->padding_top;
         align->padding_top = align->padding_bottom;
@@ -169,7 +174,7 @@ static void align_video_info_planes(MFVideoInfo *video_info, gsize plane_align,
         gst_video_info_align(info, align);
     }
 
-    if (video_info->VideoFlags & MFVideoFlag_BottomUpLinearRep)
+    if (bottom_up)
     {
         for (guint i = 0; i < ARRAY_SIZE(info->offset); ++i)
         {
diff --git a/dlls/winemac.drv/cocoa_app.h b/dlls/winemac.drv/cocoa_app.h
index 85d252abb7e7..e2f25c6cc413 100644
--- a/dlls/winemac.drv/cocoa_app.h
+++ b/dlls/winemac.drv/cocoa_app.h
@@ -24,6 +24,12 @@
 
 #define ERR(...) do { if (macdrv_err_on) LogError(__func__, __VA_ARGS__); } while (false)
 
+/* Internal notification sent on NSApp for display configuration changes. The
+   userInfo contains the two keys, NSNumbers for the effected CGDirectDisplayID
+   and the CGDisplayChangeSummaryFlags from the underlying CG callback. */
+static NSString* const WineDisplayConfigurationChangedNotification = @"WineDisplayConfigurationChanged";
+static NSString* const WineDisplayConfigurationNotificationDisplayIDKey = @"DisplayID";
+static NSString* const WineDisplayConfigurationNotificationFlagsKey = @"Flags";
 
 enum {
     WineApplicationEventWakeQuery,
diff --git a/dlls/winemac.drv/cocoa_app.m b/dlls/winemac.drv/cocoa_app.m
index 2a9dab26989d..102a5b70702e 100644
--- a/dlls/winemac.drv/cocoa_app.m
+++ b/dlls/winemac.drv/cocoa_app.m
@@ -217,6 +217,7 @@ - (void) dealloc
             CFRunLoopSourceInvalidate(requestSource);
             CFRelease(requestSource);
         }
+        CGDisplayRemoveReconfigurationCallback(DisplayReconfigCallback, NULL);
         [super dealloc];
     }
 
@@ -2154,6 +2155,48 @@ - (void) setRetinaMode:(BOOL)mode
     /*
      * ---------- NSApplicationDelegate methods ----------
      */
+    - (void)cgDisplay:(CGDirectDisplayID)display wasReconfiguredWithFlags:(CGDisplayChangeSummaryFlags)flags
+    {
+        NSDictionary *userInfo;
+
+        primaryScreenHeightValid = FALSE;
+        [self sendDisplaysChanged:FALSE];
+        [self adjustWindowLevels];
+
+        /* When the display configuration changes, the cursor position may jump.
+           Accumulated mouse movement deltas are invalidated.  Make sure the
+           next mouse move event starts over from an absolute baseline. */
+        forceNextMouseMoveAbsolute = TRUE;
+
+        userInfo = @{
+            WineDisplayConfigurationNotificationDisplayIDKey: @(display),
+            WineDisplayConfigurationNotificationFlagsKey: @(flags)
+        };
+        [NSNotificationCenter.defaultCenter postNotificationName:WineDisplayConfigurationChangedNotification
+                                                          object:NSApp
+                                                        userInfo:userInfo];
+    }
+
+    static void DisplayReconfigCallback(CGDirectDisplayID display, CGDisplayChangeSummaryFlags flags, void *userInfo)
+    {
+        /* A callback with flag == kCGDisplayBeginConfigurationFlag is
+           documented to be sent at the beginning of a change set. We should
+           ignore it; the actual changes will come in separate callbacks. */
+        if (flags == kCGDisplayBeginConfigurationFlag)
+            return;
+
+        /* We're called back on an internal CG thread, so kick this over to the
+           main thread. */
+        OnMainThreadAsync(^{
+            [WineApplicationController.sharedController cgDisplay:display wasReconfiguredWithFlags:flags];
+        });
+    }
+
+    - (void)applicationDidFinishLaunching:(NSNotification *)notification
+    {
+        CGDisplayRegisterReconfigurationCallback(DisplayReconfigCallback, NULL);
+    }
+
     - (void)applicationDidBecomeActive:(NSNotification *)notification
     {
         NSNumber* displayID;
@@ -2191,18 +2234,6 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification
         forceNextMouseMoveAbsolute = TRUE;
     }
 
-    - (void)applicationDidChangeScreenParameters:(NSNotification *)notification
-    {
-        primaryScreenHeightValid = FALSE;
-        [self sendDisplaysChanged:FALSE];
-        [self adjustWindowLevels];
-
-        // When the display configuration changes, the cursor position may jump.
-        // Accumulated mouse movement deltas are invalidated.  Make sure the next
-        // mouse move event starts over from an absolute baseline.
-        forceNextMouseMoveAbsolute = TRUE;
-    }
-
     - (void)applicationDidResignActive:(NSNotification *)notification
     {
         macdrv_event* event;
diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m
index 6b0ab117cd12..8ca5dd766356 100644
--- a/dlls/winemac.drv/cocoa_window.m
+++ b/dlls/winemac.drv/cocoa_window.m
@@ -1122,7 +1122,7 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w
 
         [nc addObserver:window
                selector:@selector(updateFullscreen)
-                   name:NSApplicationDidChangeScreenParametersNotification
+                   name:WineDisplayConfigurationChangedNotification
                  object:NSApp];
         [window updateFullscreen];
 
@@ -2293,7 +2293,7 @@ - (NSMutableDictionary*) displayIDToDisplayLinkMap
         {
             displayIDToDisplayLinkMap = [[NSMutableDictionary alloc] init];
 
-            [[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationDidChangeScreenParametersNotification
+            [[NSNotificationCenter defaultCenter] addObserverForName:WineDisplayConfigurationChangedNotification
                                                               object:NSApp
                                                                queue:nil
                                                           usingBlock:^(NSNotification *note){
@@ -3801,7 +3801,7 @@ macdrv_view macdrv_create_view(CGRect rect)
 #pragma clang diagnostic pop
         [nc addObserver:view
                selector:@selector(updateGLContexts)
-                   name:NSApplicationDidChangeScreenParametersNotification
+                   name:WineDisplayConfigurationChangedNotification
                  object:NSApp];
     });
 
@@ -3831,7 +3831,7 @@ void macdrv_dispose_view(macdrv_view v)
                     object:view];
 #pragma clang diagnostic pop
         [nc removeObserver:view
-                      name:NSApplicationDidChangeScreenParametersNotification
+                      name:WineDisplayConfigurationChangedNotification
                     object:NSApp];
         [view removeFromSuperview];
         [view release];
diff --git a/dlls/winevulkan/loader_thunks.c b/dlls/winevulkan/loader_thunks.c
index 6a0cfdebf598..cc82c2572d6e 100644
--- a/dlls/winevulkan/loader_thunks.c
+++ b/dlls/winevulkan/loader_thunks.c
@@ -5266,6 +5266,14 @@ VkResult WINAPI vkGetImageViewOpaqueCaptureDescriptorDataEXT(VkDevice device, co
     return params.result;
 }
 
+void WINAPI vkGetLatencyTimingsLegacyNV(VkDevice device, void *pTimings)
+{
+    struct vkGetLatencyTimingsLegacyNV_params params;
+    params.device = device;
+    params.pTimings = pTimings;
+    UNIX_CALL_CHECKED(vkGetLatencyTimingsLegacyNV, &params);
+}
+
 void WINAPI vkGetLatencyTimingsNV(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV *pLatencyMarkerInfo)
 {
     struct vkGetLatencyTimingsNV_params params;
@@ -6220,6 +6228,14 @@ void WINAPI vkGetShaderModuleIdentifierEXT(VkDevice device, VkShaderModule shade
     UNIX_CALL_CHECKED(vkGetShaderModuleIdentifierEXT, &params);
 }
 
+void WINAPI vkGetSleepStatusLegacyNV(VkDevice device, VkBool32 *pLowLatencyMode)
+{
+    struct vkGetSleepStatusLegacyNV_params params;
+    params.device = device;
+    params.pLowLatencyMode = pLowLatencyMode;
+    UNIX_CALL_CHECKED(vkGetSleepStatusLegacyNV, &params);
+}
+
 VkResult WINAPI vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages)
 {
     struct vkGetSwapchainImagesKHR_params params;
@@ -6352,6 +6368,15 @@ VkResult WINAPI vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryR
     return params.result;
 }
 
+void WINAPI vkLatencySleepLegacyNV(VkDevice device, VkSemaphore signalSemaphore, uint64_t value)
+{
+    struct vkLatencySleepLegacyNV_params params;
+    params.device = device;
+    params.signalSemaphore = signalSemaphore;
+    params.value = value;
+    UNIX_CALL_CHECKED(vkLatencySleepLegacyNV, &params);
+}
+
 VkResult WINAPI vkLatencySleepNV(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV *pSleepInfo)
 {
     struct vkLatencySleepNV_params params;
@@ -6451,6 +6476,14 @@ void WINAPI vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLab
     UNIX_CALL_CHECKED(vkQueueInsertDebugUtilsLabelEXT, &params);
 }
 
+void WINAPI vkQueueNotifyOutOfBandLegacyNV(VkQueue queue, uint32_t queueType)
+{
+    struct vkQueueNotifyOutOfBandLegacyNV_params params;
+    params.queue = queue;
+    params.queueType = queueType;
+    UNIX_CALL_CHECKED(vkQueueNotifyOutOfBandLegacyNV, &params);
+}
+
 void WINAPI vkQueueNotifyOutOfBandNV(VkQueue queue, const VkOutOfBandQueueTypeInfoNV *pQueueTypeInfo)
 {
     struct vkQueueNotifyOutOfBandNV_params params;
@@ -6714,6 +6747,15 @@ void WINAPI vkSetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const
     UNIX_CALL_CHECKED(vkSetHdrMetadataEXT, &params);
 }
 
+void WINAPI vkSetLatencyMarkerLegacyNV(VkDevice device, uint64_t frameID, uint32_t marker)
+{
+    struct vkSetLatencyMarkerLegacyNV_params params;
+    params.device = device;
+    params.frameID = frameID;
+    params.marker = marker;
+    UNIX_CALL_CHECKED(vkSetLatencyMarkerLegacyNV, &params);
+}
+
 void WINAPI vkSetLatencyMarkerNV(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV *pLatencyMarkerInfo)
 {
     struct vkSetLatencyMarkerNV_params params;
@@ -6723,6 +6765,16 @@ void WINAPI vkSetLatencyMarkerNV(VkDevice device, VkSwapchainKHR swapchain, cons
     UNIX_CALL_CHECKED(vkSetLatencyMarkerNV, &params);
 }
 
+void WINAPI vkSetLatencySleepModeLegacyNV(VkDevice device, VkBool32 lowLatencyMode, VkBool32 lowLatencyBoost, uint32_t minimumIntervalUs)
+{
+    struct vkSetLatencySleepModeLegacyNV_params params;
+    params.device = device;
+    params.lowLatencyMode = lowLatencyMode;
+    params.lowLatencyBoost = lowLatencyBoost;
+    params.minimumIntervalUs = minimumIntervalUs;
+    UNIX_CALL_CHECKED(vkSetLatencySleepModeLegacyNV, &params);
+}
+
 VkResult WINAPI vkSetLatencySleepModeNV(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV *pSleepModeInfo)
 {
     struct vkSetLatencySleepModeNV_params params;
@@ -6767,6 +6819,13 @@ VkResult WINAPI vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapc
     return params.result;
 }
 
+void WINAPI vkShutdownLatencyDeviceLegacyNV(VkDevice device)
+{
+    struct vkShutdownLatencyDeviceLegacyNV_params params;
+    params.device = device;
+    UNIX_CALL_CHECKED(vkShutdownLatencyDeviceLegacyNV, &params);
+}
+
 VkResult WINAPI vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo)
 {
     struct vkSignalSemaphore_params params;
@@ -7578,6 +7637,7 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkGetImageViewHandle64NVX", vkGetImageViewHandle64NVX},
     {"vkGetImageViewHandleNVX", vkGetImageViewHandleNVX},
     {"vkGetImageViewOpaqueCaptureDescriptorDataEXT", vkGetImageViewOpaqueCaptureDescriptorDataEXT},
+    {"vkGetLatencyTimingsLegacyNV", vkGetLatencyTimingsLegacyNV},
     {"vkGetLatencyTimingsNV", vkGetLatencyTimingsNV},
     {"vkGetMemoryHostPointerPropertiesEXT", vkGetMemoryHostPointerPropertiesEXT},
     {"vkGetMemoryWin32HandleKHR", vkGetMemoryWin32HandleKHR},
@@ -7616,6 +7676,7 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkGetShaderInstrumentationValuesARM", vkGetShaderInstrumentationValuesARM},
     {"vkGetShaderModuleCreateInfoIdentifierEXT", vkGetShaderModuleCreateInfoIdentifierEXT},
     {"vkGetShaderModuleIdentifierEXT", vkGetShaderModuleIdentifierEXT},
+    {"vkGetSleepStatusLegacyNV", vkGetSleepStatusLegacyNV},
     {"vkGetSwapchainImagesKHR", vkGetSwapchainImagesKHR},
     {"vkGetSwapchainTimeDomainPropertiesEXT", vkGetSwapchainTimeDomainPropertiesEXT},
     {"vkGetSwapchainTimingPropertiesEXT", vkGetSwapchainTimingPropertiesEXT},
@@ -7629,6 +7690,7 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkImportSemaphoreWin32HandleKHR", vkImportSemaphoreWin32HandleKHR},
     {"vkInitializePerformanceApiINTEL", vkInitializePerformanceApiINTEL},
     {"vkInvalidateMappedMemoryRanges", vkInvalidateMappedMemoryRanges},
+    {"vkLatencySleepLegacyNV", vkLatencySleepLegacyNV},
     {"vkLatencySleepNV", vkLatencySleepNV},
     {"vkMapMemory", vkMapMemory},
     {"vkMapMemory2", vkMapMemory2},
@@ -7639,6 +7701,7 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkQueueBindSparse", vkQueueBindSparse},
     {"vkQueueEndDebugUtilsLabelEXT", vkQueueEndDebugUtilsLabelEXT},
     {"vkQueueInsertDebugUtilsLabelEXT", vkQueueInsertDebugUtilsLabelEXT},
+    {"vkQueueNotifyOutOfBandLegacyNV", vkQueueNotifyOutOfBandLegacyNV},
     {"vkQueueNotifyOutOfBandNV", vkQueueNotifyOutOfBandNV},
     {"vkQueuePresentKHR", vkQueuePresentKHR},
     {"vkQueueSetPerfHintQCOM", vkQueueSetPerfHintQCOM},
@@ -7667,11 +7730,14 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkSetEvent", vkSetEvent},
     {"vkSetGpaDeviceClockModeAMD", vkSetGpaDeviceClockModeAMD},
     {"vkSetHdrMetadataEXT", vkSetHdrMetadataEXT},
+    {"vkSetLatencyMarkerLegacyNV", vkSetLatencyMarkerLegacyNV},
     {"vkSetLatencyMarkerNV", vkSetLatencyMarkerNV},
+    {"vkSetLatencySleepModeLegacyNV", vkSetLatencySleepModeLegacyNV},
     {"vkSetLatencySleepModeNV", vkSetLatencySleepModeNV},
     {"vkSetPrivateData", vkSetPrivateData},
     {"vkSetPrivateDataEXT", vkSetPrivateDataEXT},
     {"vkSetSwapchainPresentTimingQueueSizeEXT", vkSetSwapchainPresentTimingQueueSizeEXT},
+    {"vkShutdownLatencyDeviceLegacyNV", vkShutdownLatencyDeviceLegacyNV},
     {"vkSignalSemaphore", vkSignalSemaphore},
     {"vkSignalSemaphoreKHR", vkSignalSemaphoreKHR},
     {"vkTransitionImageLayout", vkTransitionImageLayout},
diff --git a/dlls/winevulkan/loader_thunks.h b/dlls/winevulkan/loader_thunks.h
index 069ce5ba4df1..90f24c3f8a5d 100644
--- a/dlls/winevulkan/loader_thunks.h
+++ b/dlls/winevulkan/loader_thunks.h
@@ -579,6 +579,7 @@ enum unix_call
     unix_vkGetImageViewHandle64NVX,
     unix_vkGetImageViewHandleNVX,
     unix_vkGetImageViewOpaqueCaptureDescriptorDataEXT,
+    unix_vkGetLatencyTimingsLegacyNV,
     unix_vkGetLatencyTimingsNV,
     unix_vkGetMemoryHostPointerPropertiesEXT,
     unix_vkGetMemoryWin32HandleKHR,
@@ -674,6 +675,7 @@ enum unix_call
     unix_vkGetShaderInstrumentationValuesARM,
     unix_vkGetShaderModuleCreateInfoIdentifierEXT,
     unix_vkGetShaderModuleIdentifierEXT,
+    unix_vkGetSleepStatusLegacyNV,
     unix_vkGetSwapchainImagesKHR,
     unix_vkGetSwapchainTimeDomainPropertiesEXT,
     unix_vkGetSwapchainTimingPropertiesEXT,
@@ -687,6 +689,7 @@ enum unix_call
     unix_vkImportSemaphoreWin32HandleKHR,
     unix_vkInitializePerformanceApiINTEL,
     unix_vkInvalidateMappedMemoryRanges,
+    unix_vkLatencySleepLegacyNV,
     unix_vkLatencySleepNV,
     unix_vkMapMemory,
     unix_vkMapMemory2,
@@ -697,6 +700,7 @@ enum unix_call
     unix_vkQueueBindSparse,
     unix_vkQueueEndDebugUtilsLabelEXT,
     unix_vkQueueInsertDebugUtilsLabelEXT,
+    unix_vkQueueNotifyOutOfBandLegacyNV,
     unix_vkQueueNotifyOutOfBandNV,
     unix_vkQueuePresentKHR,
     unix_vkQueueSetPerfHintQCOM,
@@ -725,11 +729,14 @@ enum unix_call
     unix_vkSetEvent,
     unix_vkSetGpaDeviceClockModeAMD,
     unix_vkSetHdrMetadataEXT,
+    unix_vkSetLatencyMarkerLegacyNV,
     unix_vkSetLatencyMarkerNV,
+    unix_vkSetLatencySleepModeLegacyNV,
     unix_vkSetLatencySleepModeNV,
     unix_vkSetPrivateData,
     unix_vkSetPrivateDataEXT,
     unix_vkSetSwapchainPresentTimingQueueSizeEXT,
+    unix_vkShutdownLatencyDeviceLegacyNV,
     unix_vkSignalSemaphore,
     unix_vkSignalSemaphoreKHR,
     unix_vkSubmitDebugUtilsMessageEXT,
@@ -5000,6 +5007,12 @@ struct vkGetImageViewOpaqueCaptureDescriptorDataEXT_params
     VkResult result;
 };
 
+struct vkGetLatencyTimingsLegacyNV_params
+{
+    VkDevice device;
+    void *pTimings;
+};
+
 struct vkGetLatencyTimingsNV_params
 {
     VkDevice device;
@@ -5764,6 +5777,12 @@ struct vkGetShaderModuleIdentifierEXT_params
     VkShaderModuleIdentifierEXT *pIdentifier;
 };
 
+struct vkGetSleepStatusLegacyNV_params
+{
+    VkDevice device;
+    VkBool32 *pLowLatencyMode;
+};
+
 struct vkGetSwapchainImagesKHR_params
 {
     VkDevice device;
@@ -5870,6 +5889,13 @@ struct vkInvalidateMappedMemoryRanges_params
     VkResult result;
 };
 
+struct vkLatencySleepLegacyNV_params
+{
+    VkDevice device;
+    VkSemaphore DECLSPEC_ALIGN(8) signalSemaphore;
+    uint64_t DECLSPEC_ALIGN(8) value;
+};
+
 struct vkLatencySleepNV_params
 {
     VkDevice device;
@@ -5949,6 +5975,12 @@ struct vkQueueInsertDebugUtilsLabelEXT_params
     const VkDebugUtilsLabelEXT *pLabelInfo;
 };
 
+struct vkQueueNotifyOutOfBandLegacyNV_params
+{
+    VkQueue queue;
+    uint32_t queueType;
+};
+
 struct vkQueueNotifyOutOfBandNV_params
 {
     VkQueue queue;
@@ -6156,6 +6188,13 @@ struct vkSetHdrMetadataEXT_params
     const VkHdrMetadataEXT *pMetadata;
 };
 
+struct vkSetLatencyMarkerLegacyNV_params
+{
+    VkDevice device;
+    uint64_t DECLSPEC_ALIGN(8) frameID;
+    uint32_t marker;
+};
+
 struct vkSetLatencyMarkerNV_params
 {
     VkDevice device;
@@ -6163,6 +6202,14 @@ struct vkSetLatencyMarkerNV_params
     const VkSetLatencyMarkerInfoNV *pLatencyMarkerInfo;
 };
 
+struct vkSetLatencySleepModeLegacyNV_params
+{
+    VkDevice device;
+    VkBool32 lowLatencyMode;
+    VkBool32 lowLatencyBoost;
+    uint32_t minimumIntervalUs;
+};
+
 struct vkSetLatencySleepModeNV_params
 {
     VkDevice device;
@@ -6199,6 +6246,11 @@ struct vkSetSwapchainPresentTimingQueueSizeEXT_params
     VkResult result;
 };
 
+struct vkShutdownLatencyDeviceLegacyNV_params
+{
+    VkDevice device;
+};
+
 struct vkSignalSemaphore_params
 {
     VkDevice device;
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 71994e45788c..f8375c96e328 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -62,7 +62,7 @@ from enum import Enum
 LOGGER = logging.Logger("vulkan")
 LOGGER.addHandler(logging.StreamHandler())
 
-VK_XML_VERSION = "1.4.353"
+VK_XML_VERSION = "1.4.357"
 
 # Filenames to create.
 WINE_VULKAN_H = "../../include/wine/vulkan.h"
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index 7ed99c4ff3cc..664377ece77e 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -7719,6 +7719,16 @@ typedef struct VkPhysicalDeviceShaderMultipleWaitQueuesPropertiesQCOM32
     uint32_t maxShaderWaitQueues;
 } VkPhysicalDeviceShaderMultipleWaitQueuesPropertiesQCOM32;
 
+typedef struct VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    VkBool32 shaderFloat4;
+    VkBool32 shaderFloat6;
+    VkBool32 shaderFloat8UnsignedE8M0;
+    VkBool32 shaderMXInt8;
+} VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32;
+
 typedef struct VkPhysicalDeviceShaderObjectFeaturesEXT32
 {
     VkStructureType sType;
@@ -10081,6 +10091,17 @@ typedef struct VkTensorDependencyInfoARM32
     PTR32 pTensorMemoryBarriers;
 } VkTensorDependencyInfoARM32;
 
+typedef struct VkTensorExplicitTilingFormatPropertiesARM32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) brick16TilingTensorFeatures;
+    VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) brick8TilingTensorFeatures;
+    VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) brick4TilingTensorFeatures;
+    VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) blockUTilingTensorFeatures;
+    VkFormatFeatureFlags2 DECLSPEC_ALIGN(8) blockU64kTilingTensorFeatures;
+} VkTensorExplicitTilingFormatPropertiesARM32;
+
 typedef struct VkTensorFormatPropertiesARM32
 {
     VkStructureType sType;
@@ -10096,6 +10117,13 @@ typedef struct VkTensorMemoryRequirementsInfoARM32
     VkTensorARM DECLSPEC_ALIGN(8) tensor;
 } VkTensorMemoryRequirementsInfoARM32;
 
+typedef struct VkTensorRollingBackingCreateInfoARM32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    uint32_t wraps[VK_MAX_TENSOR_CREATE_INFO_ROLLING_BACKING_WRAP_COUNT_ARM];
+} VkTensorRollingBackingCreateInfoARM32;
+
 typedef struct VkTensorViewCaptureDescriptorDataInfoARM32
 {
     VkStructureType sType;
@@ -18101,6 +18129,20 @@ static void convert_VkPipelineShaderStageCreateInfo_win32_to_host(struct convers
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT:
+        {
+            VkValidationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkValidationFeaturesEXT32 *in_ext = (const VkValidationFeaturesEXT32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->enabledValidationFeatureCount = in_ext->enabledValidationFeatureCount;
+            out_ext->pEnabledValidationFeatures = UlongToPtr(in_ext->pEnabledValidationFeatures);
+            out_ext->disabledValidationFeatureCount = in_ext->disabledValidationFeatureCount;
+            out_ext->pDisabledValidationFeatures = UlongToPtr(in_ext->pDisabledValidationFeatures);
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         default:
             FIXME("Unhandled sType %u.\n", in_header->sType);
             break;
@@ -18223,6 +18265,20 @@ static void convert_VkComputePipelineCreateInfo_win32_to_host(struct conversion_
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT:
+        {
+            VkValidationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkValidationFeaturesEXT32 *in_ext = (const VkValidationFeaturesEXT32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->enabledValidationFeatureCount = in_ext->enabledValidationFeatureCount;
+            out_ext->pEnabledValidationFeatures = UlongToPtr(in_ext->pEnabledValidationFeatures);
+            out_ext->disabledValidationFeatureCount = in_ext->disabledValidationFeatureCount;
+            out_ext->pDisabledValidationFeatures = UlongToPtr(in_ext->pDisabledValidationFeatures);
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         default:
             FIXME("Unhandled sType %u.\n", in_header->sType);
             break;
@@ -21585,6 +21641,20 @@ static void convert_VkDeviceCreateInfo_win64_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT:
+        {
+            VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *in_ext = (const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->shaderFloat4 = in_ext->shaderFloat4;
+            out_ext->shaderFloat6 = in_ext->shaderFloat6;
+            out_ext->shaderFloat8UnsignedE8M0 = in_ext->shaderFloat8UnsignedE8M0;
+            out_ext->shaderMXInt8 = in_ext->shaderMXInt8;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT:
         {
             VkPhysicalDeviceShaderObjectFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -24968,6 +25038,20 @@ static void convert_VkDeviceCreateInfo_win32_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT:
+        {
+            VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->shaderFloat4 = in_ext->shaderFloat4;
+            out_ext->shaderFloat6 = in_ext->shaderFloat6;
+            out_ext->shaderFloat8UnsignedE8M0 = in_ext->shaderFloat8UnsignedE8M0;
+            out_ext->shaderMXInt8 = in_ext->shaderMXInt8;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT:
         {
             VkPhysicalDeviceShaderObjectFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -26843,6 +26927,20 @@ static void convert_VkGraphicsPipelineCreateInfo_win32_to_host(struct conversion
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT:
+        {
+            VkValidationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkValidationFeaturesEXT32 *in_ext = (const VkValidationFeaturesEXT32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->enabledValidationFeatureCount = in_ext->enabledValidationFeatureCount;
+            out_ext->pEnabledValidationFeatures = UlongToPtr(in_ext->pEnabledValidationFeatures);
+            out_ext->disabledValidationFeatureCount = in_ext->disabledValidationFeatureCount;
+            out_ext->pDisabledValidationFeatures = UlongToPtr(in_ext->pDisabledValidationFeatures);
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         default:
             FIXME("Unhandled sType %u.\n", in_header->sType);
             break;
@@ -28569,6 +28667,20 @@ static void convert_VkRayTracingPipelineCreateInfoKHR_win32_to_host(struct conve
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT:
+        {
+            VkValidationFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkValidationFeaturesEXT32 *in_ext = (const VkValidationFeaturesEXT32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->enabledValidationFeatureCount = in_ext->enabledValidationFeatureCount;
+            out_ext->pEnabledValidationFeatures = UlongToPtr(in_ext->pEnabledValidationFeatures);
+            out_ext->disabledValidationFeatureCount = in_ext->disabledValidationFeatureCount;
+            out_ext->pDisabledValidationFeatures = UlongToPtr(in_ext->pDisabledValidationFeatures);
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         default:
             FIXME("Unhandled sType %u.\n", in_header->sType);
             break;
@@ -29824,6 +29936,17 @@ static void convert_VkTensorCreateInfoARM_win32_to_host(struct conversion_contex
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_TENSOR_ROLLING_BACKING_CREATE_INFO_ARM:
+        {
+            VkTensorRollingBackingCreateInfoARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkTensorRollingBackingCreateInfoARM32 *in_ext = (const VkTensorRollingBackingCreateInfoARM32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_TENSOR_ROLLING_BACKING_CREATE_INFO_ARM;
+            out_ext->pNext = NULL;
+            memcpy(out_ext->wraps, in_ext->wraps, VK_MAX_TENSOR_CREATE_INFO_ROLLING_BACKING_WRAP_COUNT_ARM * sizeof(uint32_t));
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         default:
             FIXME("Unhandled sType %u.\n", in_header->sType);
             break;
@@ -35504,6 +35627,20 @@ static void convert_VkPhysicalDeviceFeatures2_win32_to_host(struct conversion_co
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT:
+        {
+            VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32 *in_ext = (const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT;
+            out_ext->pNext = NULL;
+            out_ext->shaderFloat4 = in_ext->shaderFloat4;
+            out_ext->shaderFloat6 = in_ext->shaderFloat6;
+            out_ext->shaderFloat8UnsignedE8M0 = in_ext->shaderFloat8UnsignedE8M0;
+            out_ext->shaderMXInt8 = in_ext->shaderMXInt8;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT:
         {
             VkPhysicalDeviceShaderObjectFeaturesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -38279,6 +38416,18 @@ static void convert_VkPhysicalDeviceFeatures2_host_to_win32(const VkPhysicalDevi
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT:
+        {
+            VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT);
+            const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *in_ext = (const VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT;
+            out_ext->shaderFloat4 = in_ext->shaderFloat4;
+            out_ext->shaderFloat6 = in_ext->shaderFloat6;
+            out_ext->shaderFloat8UnsignedE8M0 = in_ext->shaderFloat8UnsignedE8M0;
+            out_ext->shaderMXInt8 = in_ext->shaderMXInt8;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT:
         {
             VkPhysicalDeviceShaderObjectFeaturesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT);
@@ -38935,6 +39084,15 @@ static void convert_VkFormatProperties2_win32_to_host(struct conversion_context
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM:
+        {
+            VkTensorExplicitTilingFormatPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_TENSOR_FORMAT_PROPERTIES_ARM:
         {
             VkTensorFormatPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -38995,6 +39153,19 @@ static void convert_VkFormatProperties2_host_to_win32(const VkFormatProperties2
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM:
+        {
+            VkTensorExplicitTilingFormatPropertiesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM);
+            const VkTensorExplicitTilingFormatPropertiesARM *in_ext = (const VkTensorExplicitTilingFormatPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM;
+            out_ext->brick16TilingTensorFeatures = in_ext->brick16TilingTensorFeatures;
+            out_ext->brick8TilingTensorFeatures = in_ext->brick8TilingTensorFeatures;
+            out_ext->brick4TilingTensorFeatures = in_ext->brick4TilingTensorFeatures;
+            out_ext->blockUTilingTensorFeatures = in_ext->blockUTilingTensorFeatures;
+            out_ext->blockU64kTilingTensorFeatures = in_ext->blockU64kTilingTensorFeatures;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_TENSOR_FORMAT_PROPERTIES_ARM:
         {
             VkTensorFormatPropertiesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_TENSOR_FORMAT_PROPERTIES_ARM);
@@ -65546,6 +65717,32 @@ static NTSTATUS thunk32_vkGetImageViewOpaqueCaptureDescriptorDataEXT(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkGetLatencyTimingsLegacyNV(void *args)
+{
+    struct vkGetLatencyTimingsLegacyNV_params *params = args;
+
+    TRACE("%p, %p\n", params->device, params->pTimings);
+
+    vulkan_device_from_handle(params->device)->p_vkGetLatencyTimingsLegacyNV(vulkan_device_from_handle(params->device)->host.device, params->pTimings);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkGetLatencyTimingsLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        PTR32 pTimings;
+    } *params = args;
+
+    TRACE("%#x, %#x\n", params->device, params->pTimings);
+
+    vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkGetLatencyTimingsLegacyNV(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, (void *)UlongToPtr(params->pTimings));
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkGetLatencyTimingsNV(void *args)
 {
@@ -68713,6 +68910,32 @@ static NTSTATUS thunk32_vkGetShaderModuleIdentifierEXT(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkGetSleepStatusLegacyNV(void *args)
+{
+    struct vkGetSleepStatusLegacyNV_params *params = args;
+
+    TRACE("%p, %p\n", params->device, params->pLowLatencyMode);
+
+    vulkan_device_from_handle(params->device)->p_vkGetSleepStatusLegacyNV(vulkan_device_from_handle(params->device)->host.device, params->pLowLatencyMode);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkGetSleepStatusLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        PTR32 pLowLatencyMode;
+    } *params = args;
+
+    TRACE("%#x, %#x\n", params->device, params->pLowLatencyMode);
+
+    vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkGetSleepStatusLegacyNV(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, (VkBool32 *)UlongToPtr(params->pLowLatencyMode));
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkGetSwapchainImagesKHR(void *args)
 {
@@ -69133,6 +69356,33 @@ static NTSTATUS thunk32_vkInvalidateMappedMemoryRanges(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkLatencySleepLegacyNV(void *args)
+{
+    struct vkLatencySleepLegacyNV_params *params = args;
+
+    TRACE("%p, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->signalSemaphore), wine_dbgstr_longlong(params->value));
+
+    vulkan_device_from_handle(params->device)->p_vkLatencySleepLegacyNV(vulkan_device_from_handle(params->device)->host.device, vulkan_semaphore_from_handle(params->signalSemaphore)->host.semaphore, params->value);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkLatencySleepLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        VkSemaphore DECLSPEC_ALIGN(8) signalSemaphore;
+        uint64_t DECLSPEC_ALIGN(8) value;
+    } *params = args;
+
+    TRACE("%#x, 0x%s, 0x%s\n", params->device, wine_dbgstr_longlong(params->signalSemaphore), wine_dbgstr_longlong(params->value));
+
+    vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkLatencySleepLegacyNV(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, vulkan_semaphore_from_handle(params->signalSemaphore)->host.semaphore, params->value);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkLatencySleepNV(void *args)
 {
@@ -69447,6 +69697,32 @@ static NTSTATUS thunk32_vkQueueInsertDebugUtilsLabelEXT(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkQueueNotifyOutOfBandLegacyNV(void *args)
+{
+    struct vkQueueNotifyOutOfBandLegacyNV_params *params = args;
+
+    TRACE("%p, %u\n", params->queue, params->queueType);
+
+    vulkan_queue_from_handle(params->queue)->device->p_vkQueueNotifyOutOfBandLegacyNV(vulkan_queue_from_handle(params->queue)->host.queue, params->queueType);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkQueueNotifyOutOfBandLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 queue;
+        uint32_t queueType;
+    } *params = args;
+
+    TRACE("%#x, %u\n", params->queue, params->queueType);
+
+    vulkan_queue_from_handle((VkQueue)UlongToPtr(params->queue))->device->p_vkQueueNotifyOutOfBandLegacyNV(vulkan_queue_from_handle((VkQueue)UlongToPtr(params->queue))->host.queue, params->queueType);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkQueueNotifyOutOfBandNV(void *args)
 {
@@ -70315,6 +70591,33 @@ static NTSTATUS thunk32_vkSetHdrMetadataEXT(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkSetLatencyMarkerLegacyNV(void *args)
+{
+    struct vkSetLatencyMarkerLegacyNV_params *params = args;
+
+    TRACE("%p, 0x%s, %u\n", params->device, wine_dbgstr_longlong(params->frameID), params->marker);
+
+    vulkan_device_from_handle(params->device)->p_vkSetLatencyMarkerLegacyNV(vulkan_device_from_handle(params->device)->host.device, params->frameID, params->marker);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkSetLatencyMarkerLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        uint64_t DECLSPEC_ALIGN(8) frameID;
+        uint32_t marker;
+    } *params = args;
+
+    TRACE("%#x, 0x%s, %u\n", params->device, wine_dbgstr_longlong(params->frameID), params->marker);
+
+    vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkSetLatencyMarkerLegacyNV(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, params->frameID, params->marker);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkSetLatencyMarkerNV(void *args)
 {
@@ -70344,6 +70647,34 @@ static NTSTATUS thunk32_vkSetLatencyMarkerNV(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkSetLatencySleepModeLegacyNV(void *args)
+{
+    struct vkSetLatencySleepModeLegacyNV_params *params = args;
+
+    TRACE("%p, %u, %u, %u\n", params->device, params->lowLatencyMode, params->lowLatencyBoost, params->minimumIntervalUs);
+
+    vulkan_device_from_handle(params->device)->p_vkSetLatencySleepModeLegacyNV(vulkan_device_from_handle(params->device)->host.device, params->lowLatencyMode, params->lowLatencyBoost, params->minimumIntervalUs);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkSetLatencySleepModeLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        VkBool32 lowLatencyMode;
+        VkBool32 lowLatencyBoost;
+        uint32_t minimumIntervalUs;
+    } *params = args;
+
+    TRACE("%#x, %u, %u, %u\n", params->device, params->lowLatencyMode, params->lowLatencyBoost, params->minimumIntervalUs);
+
+    vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkSetLatencySleepModeLegacyNV(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, params->lowLatencyMode, params->lowLatencyBoost, params->minimumIntervalUs);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkSetLatencySleepModeNV(void *args)
 {
@@ -70462,6 +70793,31 @@ static NTSTATUS thunk32_vkSetSwapchainPresentTimingQueueSizeEXT(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkShutdownLatencyDeviceLegacyNV(void *args)
+{
+    struct vkShutdownLatencyDeviceLegacyNV_params *params = args;
+
+    TRACE("%p\n", params->device);
+
+    vulkan_device_from_handle(params->device)->p_vkShutdownLatencyDeviceLegacyNV(vulkan_device_from_handle(params->device)->host.device);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkShutdownLatencyDeviceLegacyNV(void *args)
+{
+    struct
+    {
+        PTR32 device;
+    } *params = args;
+
+    TRACE("%#x\n", params->device);
+
+    vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkShutdownLatencyDeviceLegacyNV(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkSignalSemaphore(void *args)
 {
@@ -71896,6 +72252,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk64_vkGetImageViewHandle64NVX,
     thunk64_vkGetImageViewHandleNVX,
     thunk64_vkGetImageViewOpaqueCaptureDescriptorDataEXT,
+    thunk64_vkGetLatencyTimingsLegacyNV,
     thunk64_vkGetLatencyTimingsNV,
     thunk64_vkGetMemoryHostPointerPropertiesEXT,
     thunk64_vkGetMemoryWin32HandleKHR,
@@ -71991,6 +72348,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk64_vkGetShaderInstrumentationValuesARM,
     thunk64_vkGetShaderModuleCreateInfoIdentifierEXT,
     thunk64_vkGetShaderModuleIdentifierEXT,
+    thunk64_vkGetSleepStatusLegacyNV,
     thunk64_vkGetSwapchainImagesKHR,
     thunk64_vkGetSwapchainTimeDomainPropertiesEXT,
     thunk64_vkGetSwapchainTimingPropertiesEXT,
@@ -72004,6 +72362,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk64_vkImportSemaphoreWin32HandleKHR,
     thunk64_vkInitializePerformanceApiINTEL,
     thunk64_vkInvalidateMappedMemoryRanges,
+    thunk64_vkLatencySleepLegacyNV,
     thunk64_vkLatencySleepNV,
     thunk64_vkMapMemory,
     thunk64_vkMapMemory2,
@@ -72014,6 +72373,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk64_vkQueueBindSparse,
     thunk64_vkQueueEndDebugUtilsLabelEXT,
     thunk64_vkQueueInsertDebugUtilsLabelEXT,
+    thunk64_vkQueueNotifyOutOfBandLegacyNV,
     thunk64_vkQueueNotifyOutOfBandNV,
     thunk64_vkQueuePresentKHR,
     thunk64_vkQueueSetPerfHintQCOM,
@@ -72042,11 +72402,14 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk64_vkSetEvent,
     thunk64_vkSetGpaDeviceClockModeAMD,
     thunk64_vkSetHdrMetadataEXT,
+    thunk64_vkSetLatencyMarkerLegacyNV,
     thunk64_vkSetLatencyMarkerNV,
+    thunk64_vkSetLatencySleepModeLegacyNV,
     thunk64_vkSetLatencySleepModeNV,
     thunk64_vkSetPrivateData,
     thunk64_vkSetPrivateDataEXT,
     thunk64_vkSetSwapchainPresentTimingQueueSizeEXT,
+    thunk64_vkShutdownLatencyDeviceLegacyNV,
     thunk64_vkSignalSemaphore,
     thunk64_vkSignalSemaphoreKHR,
     thunk64_vkSubmitDebugUtilsMessageEXT,
@@ -72645,6 +73008,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk32_vkGetImageViewHandle64NVX,
     thunk32_vkGetImageViewHandleNVX,
     thunk32_vkGetImageViewOpaqueCaptureDescriptorDataEXT,
+    thunk32_vkGetLatencyTimingsLegacyNV,
     thunk32_vkGetLatencyTimingsNV,
     thunk32_vkGetMemoryHostPointerPropertiesEXT,
     thunk32_vkGetMemoryWin32HandleKHR,
@@ -72740,6 +73104,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk32_vkGetShaderInstrumentationValuesARM,
     thunk32_vkGetShaderModuleCreateInfoIdentifierEXT,
     thunk32_vkGetShaderModuleIdentifierEXT,
+    thunk32_vkGetSleepStatusLegacyNV,
     thunk32_vkGetSwapchainImagesKHR,
     thunk32_vkGetSwapchainTimeDomainPropertiesEXT,
     thunk32_vkGetSwapchainTimingPropertiesEXT,
@@ -72753,6 +73118,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk32_vkImportSemaphoreWin32HandleKHR,
     thunk32_vkInitializePerformanceApiINTEL,
     thunk32_vkInvalidateMappedMemoryRanges,
+    thunk32_vkLatencySleepLegacyNV,
     thunk32_vkLatencySleepNV,
     thunk32_vkMapMemory,
     thunk32_vkMapMemory2,
@@ -72763,6 +73129,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk32_vkQueueBindSparse,
     thunk32_vkQueueEndDebugUtilsLabelEXT,
     thunk32_vkQueueInsertDebugUtilsLabelEXT,
+    thunk32_vkQueueNotifyOutOfBandLegacyNV,
     thunk32_vkQueueNotifyOutOfBandNV,
     thunk32_vkQueuePresentKHR,
     thunk32_vkQueueSetPerfHintQCOM,
@@ -72791,11 +73158,14 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk32_vkSetEvent,
     thunk32_vkSetGpaDeviceClockModeAMD,
     thunk32_vkSetHdrMetadataEXT,
+    thunk32_vkSetLatencyMarkerLegacyNV,
     thunk32_vkSetLatencyMarkerNV,
+    thunk32_vkSetLatencySleepModeLegacyNV,
     thunk32_vkSetLatencySleepModeNV,
     thunk32_vkSetPrivateData,
     thunk32_vkSetPrivateDataEXT,
     thunk32_vkSetSwapchainPresentTimingQueueSizeEXT,
+    thunk32_vkShutdownLatencyDeviceLegacyNV,
     thunk32_vkSignalSemaphore,
     thunk32_vkSignalSemaphoreKHR,
     thunk32_vkSubmitDebugUtilsMessageEXT,
diff --git a/dlls/winevulkan/winevulkan.json b/dlls/winevulkan/winevulkan.json
index 4a2c53b7e1c8..f93b7a4f889b 100644
--- a/dlls/winevulkan/winevulkan.json
+++ b/dlls/winevulkan/winevulkan.json
@@ -2,6 +2,6 @@
     "file_format_version": "1.0.0",
     "ICD": {
         "library_path": ".\\winevulkan.dll",
-        "api_version": "1.4.353"
+        "api_version": "1.4.357"
     }
 }
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c
index 5ce2f445fea7..6a5f3f310299 100644
--- a/dlls/winewayland.drv/wayland_surface.c
+++ b/dlls/winewayland.drv/wayland_surface.c
@@ -1182,12 +1182,13 @@ static void wayland_client_surface_update(struct client_surface *client)
     struct wayland_client_surface *surface = impl_from_client_surface(client);
     HWND hwnd = client->hwnd, toplevel = client->toplevel;
     struct wayland_win_data *data;
+    BOOL visible = FALSE;
 
     TRACE("%s\n", debugstr_client_surface(client));
-
+    if(toplevel) visible = NtUserIsWindowVisible(hwnd);
     if (!(data = wayland_win_data_get(hwnd))) return;
 
-    if (toplevel && NtUserIsWindowVisible(hwnd))
+    if (toplevel && visible)
         wayland_client_surface_attach(surface, toplevel, &client->monitor_rect);
     else
         wayland_client_surface_attach(surface, NULL, NULL);
diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c
index c16eb1f4b3e5..c726d482bce0 100644
--- a/dlls/winewayland.drv/window.c
+++ b/dlls/winewayland.drv/window.c
@@ -251,6 +251,9 @@ static void wayland_surface_update_state_toplevel(struct wayland_surface *surfac
      * window state to determine and update the Wayland state. */
     if (!processing_config)
     {
+        xdg_toplevel_set_min_size(surface->xdg_toplevel, 0, 0);
+        xdg_toplevel_set_max_size(surface->xdg_toplevel, 0, 0);
+
          /* First do all state unsettings, before setting new state. Some
           * Wayland compositors misbehave if the order is reversed. */
         if (!(surface->window.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
@@ -810,10 +813,11 @@ void set_client_surface(HWND hwnd, struct wayland_client_surface *new_client)
     RECT rect = new_client->client.monitor_rect;
     struct wayland_client_surface *old_client;
     struct wayland_win_data *data;
+    BOOL visible = FALSE;
 
     /* ownership is shared with the callers, the last caller to release
      * its reference will also destroy it and clear our pointer. */
-
+    if(toplevel) visible = NtUserIsWindowVisible(hwnd);
     if (!(data = wayland_win_data_get(hwnd))) return;
 
     if (new_client != data->client_surface)
@@ -823,7 +827,7 @@ void set_client_surface(HWND hwnd, struct wayland_client_surface *new_client)
 
         if ((data->client_surface = new_client))
         {
-            if (toplevel && NtUserIsWindowVisible(hwnd))
+            if (toplevel && visible)
                 wayland_client_surface_attach(new_client, toplevel, &rect);
             else
                 wayland_client_surface_attach(new_client, NULL, NULL);
diff --git a/dlls/winex11.drv/clipboard.c b/dlls/winex11.drv/clipboard.c
index ac098d998334..e2e07a636a43 100644
--- a/dlls/winex11.drv/clipboard.c
+++ b/dlls/winex11.drv/clipboard.c
@@ -1921,6 +1921,7 @@ static void acquire_selection( Display *display )
 
     XSetSelectionOwner( display, x11drv_atom(CLIPBOARD), selection_window, CurrentTime );
     if (use_primary_selection) XSetSelectionOwner( display, XA_PRIMARY, selection_window, CurrentTime );
+    XFlush( display );
     TRACE( "win %lx\n", selection_window );
 }
 
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 668a25b13455..8645d893f4a6 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1346,6 +1346,11 @@ static void update_key_state( BYTE *keystate, BYTE key, int down )
     else keystate[key] &= ~0x80;
 }
 
+static BOOL scan_is_extended( WORD scan )
+{
+    return scan & 0x100 || scan == 0x36;
+}
+
 /***********************************************************************
  *           X11DRV_KeymapNotify
  *
@@ -1430,7 +1435,7 @@ BOOL X11DRV_KeymapNotify( HWND hwnd, XEvent *event )
             {
                 TRACE( "Sending KEYUP for a modifier %#.2x\n", vkey);
                 flags = KEYEVENTF_KEYUP;
-                if (keys[vkey].scan & 0x100) flags |= KEYEVENTF_EXTENDEDKEY;
+                if (scan_is_extended( keys[vkey].scan )) flags |= KEYEVENTF_EXTENDEDKEY;
                 X11DRV_send_keyboard_input( keymapnotify_hwnd, vkey, keys[vkey].scan & 0xff, flags, NtGetTickCount() );
             }
 
@@ -1595,7 +1600,7 @@ BOOL X11DRV_KeyEvent( HWND hwnd, XEvent *xev )
 
     dwFlags = 0;
     if ( event->type == KeyRelease ) dwFlags |= KEYEVENTF_KEYUP;
-    if ( scan & 0x100 ) dwFlags |= KEYEVENTF_EXTENDEDKEY;
+    if (scan_is_extended( scan )) dwFlags |= KEYEVENTF_EXTENDEDKEY;
 
     update_lock_state( hwnd, vkey, event->state, event_time );
 
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c
index 7eb9dd710cb8..aacd50718cc4 100644
--- a/dlls/wininet/internet.c
+++ b/dlls/wininet/internet.c
@@ -2317,9 +2317,9 @@ BOOL WINAPI InternetCrackUrlW(const WCHAR *lpszUrl, DWORD dwUrlLength, DWORD dwF
                 }
             }
             /* if ends in \. or \.. append a backslash */
-            if (tmppath[len - 1] == '.' &&
+            if (len >= 2 && tmppath[len - 1] == '.' &&
                     (tmppath[len - 2] == '\\' ||
-                     (tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
+                     (len >= 3 && tmppath[len - 2] == '.' && tmppath[len - 3] == '\\')))
             {
                 if (len < MAX_PATH - 1)
                 {
diff --git a/dlls/wininet/tests/url.c b/dlls/wininet/tests/url.c
index 2177d651f087..5f6ea7042e1b 100644
--- a/dlls/wininet/tests/url.c
+++ b/dlls/wininet/tests/url.c
@@ -671,6 +671,23 @@ static void InternetCrackUrl_test(void)
   ok(ret, "InternetCrackUrlA failed with error %ld\n", GetLastError());
   ok(urlComponents.dwUrlPathLength == 0,
     "Expected dwUrlPathLength of 0, got %ld\n", urlComponents.dwUrlPathLength);
+
+  /* file:// URLs with empty path and fragment/query immediately after //
+   * These previously caused a crash (STATUS_STACK_OVERFLOW) due to tmppath[-1]
+   * array underflow in InternetCrackUrlW when path length was 0. */
+  copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024);
+  SetLastError(0xdeadbeef);
+  ret = InternetCrackUrlA("file://#:] ", 10, ICU_DECODE, &urlComponents);
+  ok(ret, "InternetCrackUrlA failed with error %ld\n", GetLastError());
+  ok(urlComponents.nScheme == INTERNET_SCHEME_FILE,
+     "Expected INTERNET_SCHEME_FILE, got %d\n", urlComponents.nScheme);
+
+  copy_compsA(&urlSrc, &urlComponents, 32, 1024, 1024, 1024, 1024, 1024);
+  SetLastError(0xdeadbeef);
+  ret = InternetCrackUrlA("file://#fragment", 0, 0, &urlComponents);
+  ok(ret, "InternetCrackUrlA failed with error %ld\n", GetLastError());
+  ok(urlComponents.nScheme == INTERNET_SCHEME_FILE,
+     "Expected INTERNET_SCHEME_FILE, got %d\n", urlComponents.nScheme);
 }
 
 static void InternetCrackUrlW_test(void)
@@ -878,6 +895,35 @@ static void InternetCrackUrlW_test(void)
     ok(r, "InternetCrackUrlW failed with error %ld\n", GetLastError());
     ok(comp.dwUrlPathLength == 0,
         "Expected dwUrlPathLength of 0, got %ld\n", comp.dwUrlPathLength);
+
+    /* file:// URLs with empty path and fragment/query immediately after //
+     * These previously caused a crash (STATUS_STACK_OVERFLOW) due to tmppath[-1]
+     * array underflow in InternetCrackUrlW when path length was 0. */
+    host[0] = 0;
+    urlpart[0] = 0;
+    memset(&comp, 0, sizeof(comp));
+    comp.dwStructSize = sizeof(comp);
+    comp.lpszHostName = host;
+    comp.dwHostNameLength = ARRAY_SIZE(host);
+    comp.lpszUrlPath = urlpart;
+    comp.dwUrlPathLength = ARRAY_SIZE(urlpart);
+    r = InternetCrackUrlW(L"file://#:]", 10, ICU_DECODE, &comp);
+    ok(r, "InternetCrackUrlW(\"file://#:]\") failed with error %ld\n", GetLastError());
+    ok(comp.nScheme == INTERNET_SCHEME_FILE,
+        "Expected INTERNET_SCHEME_FILE, got %d\n", comp.nScheme);
+
+    host[0] = 0;
+    urlpart[0] = 0;
+    memset(&comp, 0, sizeof(comp));
+    comp.dwStructSize = sizeof(comp);
+    comp.lpszHostName = host;
+    comp.dwHostNameLength = ARRAY_SIZE(host);
+    comp.lpszUrlPath = urlpart;
+    comp.dwUrlPathLength = ARRAY_SIZE(urlpart);
+    r = InternetCrackUrlW(L"file://#frag", 0, 0, &comp);
+    ok(r, "InternetCrackUrlW(\"file://#frag\") failed with error %ld\n", GetLastError());
+    ok(comp.nScheme == INTERNET_SCHEME_FILE,
+        "Expected INTERNET_SCHEME_FILE, got %d\n", comp.nScheme);
 }
 
 static void fill_url_components(URL_COMPONENTSA *lpUrlComponents)
diff --git a/dlls/winnls32/Makefile.in b/dlls/winnls32/Makefile.in
index f0833e3c7f72..d9196f8d11dd 100644
--- a/dlls/winnls32/Makefile.in
+++ b/dlls/winnls32/Makefile.in
@@ -1,7 +1,5 @@
 MODULE    = winnls32.dll
 IMPORTLIB = winnls32
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	winnls.c
diff --git a/dlls/wintypes/storage.c b/dlls/wintypes/storage.c
index 096307ed93e3..aaef09004f18 100644
--- a/dlls/wintypes/storage.c
+++ b/dlls/wintypes/storage.c
@@ -1,6 +1,7 @@
 /*
  * Copyright 2022-2024 Zhiyi Zhang for CodeWeavers
  * Copyright 2025 Jactry Zeng for CodeWeavers
+ * Copyright 2026 Conor McCarthy for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -18,18 +19,690 @@
  */
 
 #include "private.h"
+#include "robuffer.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(wintypes);
 
+/* Synchronous wrapper for async operations returned by IOutputStream async methods.
+ * The IAsyncInfo object is queried from the inner operation. */
+
+#define DEFINE_IASYNCOPERATION(iface_type, cs_type_str, impl_type, result_type,                                   \
+        handler_iface_type, inner_op_iface_type, outer_handler_iface_type)                                        \
+struct impl_type                                                                                                  \
+{                                                                                                                 \
+    iface_type iface_type##_iface;                                                                                \
+    handler_iface_type handler_iface_type##_iface;                                                                \
+    IAsyncInfo *async_inner;                                                                                      \
+    LONG refcount;                                                                                                \
+    struct data_writer *data_writer;                                                                              \
+    outer_handler_iface_type *outer_handler;                                                                      \
+    AsyncStatus status;                                                                                           \
+    result_type result;                                                                                           \
+};                                                                                                                \
+                                                                                                                  \
+static inline struct impl_type *impl_from_##handler_iface_type(handler_iface_type *iface)                         \
+{                                                                                                                 \
+    return CONTAINING_RECORD(iface, struct impl_type, handler_iface_type##_iface);                                \
+}                                                                                                                 \
+                                                                                                                  \
+static HRESULT WINAPI impl_type##_handler_QueryInterface(handler_iface_type *iface, REFIID iid, void **out)       \
+{                                                                                                                 \
+    if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IAgileObject) ||                                 \
+        IsEqualGUID(iid, &IID_##handler_iface_type))                                                              \
+    {                                                                                                             \
+        IUnknown_AddRef(iface);                                                                                   \
+        *out = iface;                                                                                             \
+        return S_OK;                                                                                              \
+    }                                                                                                             \
+                                                                                                                  \
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));                                   \
+    *out = NULL;                                                                                                  \
+    return E_NOINTERFACE;                                                                                         \
+}                                                                                                                 \
+                                                                                                                  \
+static ULONG WINAPI impl_type##_handler_AddRef(handler_iface_type *iface)                                         \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##handler_iface_type(iface);                                               \
+    return iface_type##_AddRef(&impl->iface_type##_iface);                                                        \
+}                                                                                                                 \
+                                                                                                                  \
+static ULONG WINAPI impl_type##_handler_Release(handler_iface_type *iface)                                        \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##handler_iface_type(iface);                                               \
+    return iface_type##_Release(&impl->iface_type##_iface);                                                       \
+}                                                                                                                 \
+                                                                                                                  \
+static HRESULT impl_type##_handle_completion(struct impl_type *impl)                                              \
+{                                                                                                                 \
+    if (impl->status && impl->outer_handler)                                                                      \
+        return outer_handler_iface_type##_Invoke(impl->outer_handler, &impl->iface_type##_iface, impl->status);   \
+    return S_OK;                                                                                                  \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_handler_Invoke(handler_iface_type *iface,                                       \
+        inner_op_iface_type *operation, AsyncStatus status)                                                       \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##handler_iface_type(iface);                                               \
+    HRESULT hr;                                                                                                   \
+    if (!status) return S_OK;                                                                                     \
+    if (status == Completed && FAILED(hr = inner_op_iface_type##_GetResults(operation, &impl->result)))           \
+        status = Error;                                                                                           \
+    impl->status = status;                                                                                        \
+    data_writer_async_complete(impl->data_writer);                                                                \
+    return impl_type##_handle_completion(impl);                                                                   \
+}                                                                                                                 \
+                                                                                                                  \
+static handler_iface_type##Vtbl impl_type##_handler_vtbl =                                                        \
+{                                                                                                                 \
+    impl_type##_handler_QueryInterface,                                                                           \
+    impl_type##_handler_AddRef,                                                                                   \
+    impl_type##_handler_Release,                                                                                  \
+    impl_type##_handler_Invoke,                                                                                   \
+};                                                                                                                \
+                                                                                                                  \
+static inline struct impl_type *impl_from_##iface_type(iface_type *iface)                                         \
+{                                                                                                                 \
+    return CONTAINING_RECORD(iface, struct impl_type, iface_type##_iface);                                        \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_QueryInterface(iface_type *iface, REFIID iid, void **out)                       \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##iface_type(iface);                                                       \
+                                                                                                                  \
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);                                         \
+                                                                                                                  \
+    if (IsEqualGUID(iid, &IID_IUnknown) ||                                                                        \
+        IsEqualGUID(iid, &IID_IInspectable) ||                                                                    \
+        IsEqualGUID(iid, &IID_IAgileObject) ||                                                                    \
+        IsEqualGUID(iid, &IID_##iface_type))                                                                      \
+    {                                                                                                             \
+        iface_type##_AddRef((*out = &impl->iface_type##_iface));                                                  \
+        return S_OK;                                                                                              \
+    }                                                                                                             \
+                                                                                                                  \
+    if (IsEqualGUID(iid, &IID_IAsyncInfo))                                                                        \
+    {                                                                                                             \
+        IAsyncInfo_AddRef(*out = impl->async_inner);                                                              \
+        return S_OK;                                                                                              \
+    }                                                                                                             \
+                                                                                                                  \
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));                                   \
+    *out = NULL;                                                                                                  \
+    return E_NOINTERFACE;                                                                                         \
+}                                                                                                                 \
+static ULONG WINAPI impl_type##_AddRef(iface_type *iface)                                                         \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##iface_type(iface);                                                       \
+    ULONG ref = InterlockedIncrement(&impl->refcount);                                                            \
+    TRACE("iface %p, ref %lu.\n", iface, ref);                                                                    \
+    return ref;                                                                                                   \
+}                                                                                                                 \
+static ULONG WINAPI impl_type##_Release(iface_type *iface)                                                        \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##iface_type(iface);                                                       \
+    ULONG ref = InterlockedDecrement(&impl->refcount);                                                            \
+    TRACE("iface %p, ref %lu.\n", iface, ref);                                                                    \
+                                                                                                                  \
+    if (!ref)                                                                                                     \
+    {                                                                                                             \
+        IDataWriter_Release(&impl->data_writer->IDataWriter_iface);                                               \
+        IAsyncInfo_Release(impl->async_inner);                                                                    \
+        if (impl->outer_handler)                                                                                  \
+            outer_handler_iface_type##_Release(impl->outer_handler);                                              \
+        free(impl);                                                                                               \
+    }                                                                                                             \
+                                                                                                                  \
+    return ref;                                                                                                   \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_GetIids(iface_type *iface, ULONG *iid_count, IID **iids)                        \
+{                                                                                                                 \
+    FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);                                     \
+    return E_NOTIMPL;                                                                                             \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_GetRuntimeClassName(iface_type *iface, HSTRING *class_name)                     \
+{                                                                                                                 \
+    return WindowsCreateString(L"Windows.Foundation.IAsyncOperation`1<"cs_type_str">",                            \
+                                ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<"cs_type_str">"),               \
+                                class_name);                                                                      \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_GetTrustLevel(iface_type *iface, TrustLevel *trust_level)                       \
+{                                                                                                                 \
+    FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);                                                \
+    return E_NOTIMPL;                                                                                             \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_put_Completed(iface_type *iface, outer_handler_iface_type *handler)             \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##iface_type(iface);                                                       \
+    TRACE("iface %p, handler %p.\n", iface, handler);                                                             \
+    impl->outer_handler = handler;                                                                                \
+    outer_handler_iface_type##_AddRef(impl->outer_handler);                                                       \
+    return impl_type##_handle_completion(impl);                                                                   \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_get_Completed(iface_type *iface, outer_handler_iface_type **handler)            \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##iface_type(iface);                                                       \
+    TRACE("iface %p, handler %p.\n", iface, handler);                                                             \
+    if ((*handler = impl->outer_handler))                                                                         \
+        outer_handler_iface_type##_AddRef(*handler);                                                              \
+    return S_OK;                                                                                                  \
+}                                                                                                                 \
+static HRESULT WINAPI impl_type##_GetResults(iface_type *iface, result_type *results)                             \
+{                                                                                                                 \
+    struct impl_type *impl = impl_from_##iface_type(iface);                                                       \
+                                                                                                                  \
+    TRACE("iface %p, results %p.\n", iface, results);                                                             \
+                                                                                                                  \
+    if (impl->status != Completed)                                                                                \
+        return E_ILLEGAL_METHOD_CALL;                                                                             \
+                                                                                                                  \
+    *results = impl->result;                                                                                      \
+    return S_OK;                                                                                                  \
+}                                                                                                                 \
+static const struct iface_type##Vtbl impl_type##_vtbl =                                                           \
+{                                                                                                                 \
+    /* IUnknown methods */                                                                                        \
+    impl_type##_QueryInterface,                                                                                   \
+    impl_type##_AddRef,                                                                                           \
+    impl_type##_Release,                                                                                          \
+    /* IInspectable methods */                                                                                    \
+    impl_type##_GetIids,                                                                                          \
+    impl_type##_GetRuntimeClassName,                                                                              \
+    impl_type##_GetTrustLevel,                                                                                    \
+    /* IAsyncOperation<iface_type> */                                                                             \
+    impl_type##_put_Completed,                                                                                    \
+    impl_type##_get_Completed,                                                                                    \
+    impl_type##_GetResults,                                                                                       \
+};                                                                                                                \
+HRESULT async_operation_##result_type##_create(struct data_writer *data_writer,                                   \
+        inner_op_iface_type *inner_op, iface_type **out)                                                          \
+{                                                                                                                 \
+    struct impl_type *impl;                                                                                       \
+    HRESULT hr;                                                                                                   \
+                                                                                                                  \
+    *out = NULL;                                                                                                  \
+    if (!(impl = calloc(1, sizeof(*impl)))) return E_OUTOFMEMORY;                                                 \
+                                                                                                                  \
+    impl->iface_type##_iface.lpVtbl = &impl_type##_vtbl;                                                          \
+    impl->handler_iface_type##_iface.lpVtbl = &impl_type##_handler_vtbl;                                          \
+    impl->data_writer = data_writer;                                                                              \
+    impl->refcount = 1;                                                                                           \
+                                                                                                                  \
+    if (FAILED(hr = inner_op_iface_type##_QueryInterface(inner_op, &IID_IAsyncInfo, (void **)&impl->async_inner)) \
+            || FAILED(hr = inner_op_iface_type##_put_Completed(inner_op, &impl->handler_iface_type##_iface)))     \
+    {                                                                                                             \
+        if (impl->async_inner)                                                                                    \
+            IAsyncInfo_Release(impl->async_inner);                                                                \
+        free(impl);                                                                                               \
+        return hr;                                                                                                \
+    }                                                                                                             \
+                                                                                                                  \
+    IDataWriter_AddRef(&data_writer->IDataWriter_iface);                                                          \
+                                                                                                                  \
+    *out = &impl->iface_type##_iface;                                                                             \
+    TRACE("created IAsyncOperation %p\n", *out);                                                                  \
+    return S_OK;                                                                                                  \
+}                                                                                                                 \
+
+static HRESULT buffer_create(UINT32 capacity, IBuffer **out)
+{
+    IBufferFactory *buffer_factory;
+    HRESULT hr;
+
+    IActivationFactory_QueryInterface(buffer_activation_factory, &IID_IBufferFactory, (void **)&buffer_factory);
+    hr = IBufferFactory_Create(buffer_factory, capacity, out);
+    IBufferFactory_Release(buffer_factory);
+    return hr;
+}
+
 struct data_writer
+{
+    IDataWriter IDataWriter_iface;
+    LONG ref;
+
+    IOutputStream *stream;
+    IBuffer *buffer;
+    byte *data;
+    BOOL storing;
+};
+
+static HRESULT data_writer_async_complete(struct data_writer *impl);
+
+DEFINE_IASYNCOPERATION(IAsyncOperation_UINT32, "IAsyncOperation<UInt32>", async_uint32, UINT32, \
+        IAsyncOperationWithProgressCompletedHandler_UINT32_UINT32, \
+        IAsyncOperationWithProgress_UINT32_UINT32, \
+        IAsyncOperationCompletedHandler_UINT32)
+
+static HRESULT data_writer_init_buffer(struct data_writer *impl, UINT32 extra_capacity)
+{
+    /* Native capacity starts at 0x88 */
+    UINT32 new_capacity, capacity = max(extra_capacity, 0x88), pos = 0;
+    IBufferByteAccess *access;
+    IBuffer *buffer;
+    HRESULT hr;
+    byte *data;
+
+    if (impl->buffer)
+    {
+        IBuffer_get_Capacity(impl->buffer, &capacity);
+        IBuffer_get_Length(impl->buffer, &pos);
+
+        new_capacity = pos + extra_capacity;
+        if (new_capacity < pos || new_capacity < extra_capacity)
+            return E_OUTOFMEMORY;
+        if (new_capacity <= capacity)
+            return S_OK;
+
+        /* If allocation size grows by 50%, the sixth allocation can fit in freed
+         * memory of the first four if they were contiguous. This matches native. */
+        capacity = max(new_capacity, capacity + capacity / 2u);
+    }
+
+    if (FAILED(hr = buffer_create(capacity, &buffer)))
+        return hr;
+
+    IBuffer_QueryInterface(buffer, &IID_IBufferByteAccess, (void **)&access);
+    IBufferByteAccess_Buffer(access, &data);
+    IBufferByteAccess_Release(access);
+
+    if (impl->buffer)
+    {
+        memcpy(data, impl->data, pos);
+        IBuffer_Release(impl->buffer);
+    }
+
+    impl->buffer = buffer;
+    impl->data = data;
+
+    return S_OK;
+}
+
+static struct data_writer *impl_from_IDataWriter(IDataWriter *iface)
+{
+    return CONTAINING_RECORD(iface, struct data_writer, IDataWriter_iface);
+}
+
+static HRESULT WINAPI data_writer_QueryInterface(IDataWriter *iface, REFIID iid, void **out)
+{
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_IUnknown)
+            || IsEqualGUID(iid, &IID_IInspectable)
+            || IsEqualGUID(iid, &IID_IAgileObject)
+            || IsEqualGUID(iid, &IID_IDataWriter))
+    {
+        *out = iface;
+        IDataWriter_AddRef(iface);
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI data_writer_AddRef(IDataWriter *iface)
+{
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+    ULONG ref = InterlockedIncrement(&impl->ref);
+    TRACE("iface %p, ref %lu.\n", iface, ref);
+    return ref;
+}
+
+static ULONG WINAPI data_writer_Release(IDataWriter *iface)
+{
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+    ULONG ref = InterlockedDecrement(&impl->ref);
+
+    TRACE("iface %p, ref %lu.\n", iface, ref);
+
+    if (!ref)
+    {
+        if (impl->stream)
+        {
+            IClosable *closable;
+            HRESULT hr;
+
+            if (SUCCEEDED(hr = IOutputStream_QueryInterface(impl->stream, &IID_IClosable, (void **)&closable)))
+            {
+                hr = IClosable_Close(closable);
+                IClosable_Release(closable);
+            }
+
+            if (FAILED(hr))
+                WARN("Failed to close stream, hr %#lx.\n", hr);
+
+            IOutputStream_Release(impl->stream);
+        }
+        if (impl->buffer)
+            IBuffer_Release(impl->buffer);
+        free(impl);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI data_writer_GetIids(IDataWriter *iface, ULONG *iid_count, IID **iids)
+{
+    FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_GetRuntimeClassName(IDataWriter *iface, HSTRING *class_name)
+{
+    FIXME("iface %p, class_name %p stub!\n", iface, class_name);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_GetTrustLevel(IDataWriter *iface, TrustLevel *trust_level)
+{
+    FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_get_UnstoredBufferLength(IDataWriter *iface, UINT32 *value)
+{
+    FIXME("iface %p, value %p stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_get_UnicodeEncoding(IDataWriter *iface, UnicodeEncoding *value)
+{
+    FIXME("iface %p, value %p stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_put_UnicodeEncoding(IDataWriter *iface, UnicodeEncoding value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_get_ByteOrder(IDataWriter *iface, ByteOrder *value)
+{
+    FIXME("iface %p, value %p stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_put_ByteOrder(IDataWriter *iface, ByteOrder value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteByte(IDataWriter *iface, BYTE value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteBytes(IDataWriter *iface, UINT32 value_size, BYTE *value)
+{
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+    UINT32 pos = 0;
+    HRESULT hr;
+
+    TRACE("iface %p, value_size %u, value %p.\n", iface, value_size, value);
+
+    if (FAILED(hr = data_writer_init_buffer(impl, value_size)))
+        return hr;
+
+    IBuffer_get_Length(impl->buffer, &pos);
+    memcpy(&impl->data[pos], value, value_size);
+    IBuffer_put_Length(impl->buffer, pos + value_size);
+
+    return hr;
+}
+
+static HRESULT WINAPI data_writer_WriteBuffer(IDataWriter *iface, IBuffer *buffer)
+{
+    FIXME("iface %p, buffer %p stub!\n", iface, buffer);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteBufferRange(IDataWriter *iface, IBuffer *buffer, UINT32 start, UINT32 count)
+{
+    FIXME("iface %p, buffer %p, start %u, count %u stub!\n", iface, buffer, start, count);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteBoolean(IDataWriter *iface, boolean value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteGuid(IDataWriter *iface, GUID value)
+{
+    FIXME("iface %p, value %s stub!\n", iface, debugstr_guid(&value));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteInt16(IDataWriter *iface, INT16 value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteInt32(IDataWriter *iface, INT32 value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteInt64(IDataWriter *iface, INT64 value)
+{
+    FIXME("iface %p, value %I64d stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteUInt16(IDataWriter *iface, UINT16 value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteUInt32(IDataWriter *iface, UINT32 value)
+{
+    FIXME("iface %p, value %u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteUInt64(IDataWriter *iface, UINT64 value)
+{
+    FIXME("iface %p, value %I64u stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteSingle(IDataWriter *iface, FLOAT value)
+{
+    FIXME("iface %p, value %.7f stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteDouble(IDataWriter *iface, DOUBLE value)
+{
+    FIXME("iface %p, value %.15f stub!\n", iface, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteDateTime(IDataWriter *iface, DateTime value)
+{
+    FIXME("iface %p, value %I64u stub!\n", iface, value.UniversalTime);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteTimeSpan(IDataWriter *iface, TimeSpan value)
+{
+    FIXME("iface %p, value %I64u stub!\n", iface, value.Duration);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_WriteString(IDataWriter *iface, HSTRING value, UINT32 *code_unit_count)
+{
+    FIXME("iface %p, value %p, code_unit_count %p stub!\n", iface, value, code_unit_count);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_MeasureString(IDataWriter *iface, HSTRING value, UINT32 *code_unit_count)
+{
+    FIXME("iface %p, value %p, code_unit_count %p stub!\n", iface, value, code_unit_count);
+    return E_NOTIMPL;
+}
+
+static HRESULT data_writer_async_complete(struct data_writer *impl)
+{
+    impl->storing = FALSE;
+    return S_OK;
+}
+
+static HRESULT WINAPI data_writer_StoreAsync(IDataWriter *iface, IAsyncOperation_UINT32 **operation)
+{
+    IAsyncOperationWithProgress_UINT32_UINT32 *inner_operation;
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+    HRESULT hr;
+
+    TRACE("iface %p, operation %p.\n", iface, operation);
+
+    *operation = NULL;
+
+    if (!impl->stream)
+        return HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
+
+    if (FAILED(hr = IOutputStream_WriteAsync(impl->stream, impl->buffer, &inner_operation)))
+        return hr;
+    IBuffer_Release(impl->buffer);
+    impl->buffer = NULL;
+    impl->storing = TRUE;
+
+    hr = async_operation_UINT32_create(impl, inner_operation, operation);
+    IAsyncOperationWithProgress_UINT32_UINT32_Release(inner_operation);
+
+    if (SUCCEEDED(hr))
+        hr = data_writer_init_buffer(impl, 0);
+
+    return hr;
+}
+
+static HRESULT WINAPI data_writer_FlushAsync(IDataWriter *iface, IAsyncOperation_boolean **operation)
+{
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+
+    FIXME("iface %p, operation %p stub!\n", iface, operation);
+
+    *operation = NULL;
+
+    if (!impl->stream)
+        return HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI data_writer_DetachBuffer(IDataWriter *iface, IBuffer **buffer)
+{
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+
+    TRACE("iface %p, buffer %p.\n", iface, buffer);
+
+    *buffer = impl->buffer;
+    impl->buffer = NULL;
+    return data_writer_init_buffer(impl, 0);
+}
+
+static HRESULT WINAPI data_writer_DetachStream(IDataWriter *iface, IOutputStream **output_stream)
+{
+    struct data_writer *impl = impl_from_IDataWriter(iface);
+
+    TRACE("iface %p, output_stream %p.\n", iface, output_stream);
+
+    *output_stream = NULL;
+
+    if (impl->storing)
+        return HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION);
+
+    *output_stream = impl->stream;
+    impl->stream = NULL;
+    return S_OK;
+}
+
+static const struct IDataWriterVtbl data_writer_vtbl =
+{
+    /* IUnknown methods */
+    data_writer_QueryInterface,
+    data_writer_AddRef,
+    data_writer_Release,
+    /* IInspectable methods */
+    data_writer_GetIids,
+    data_writer_GetRuntimeClassName,
+    data_writer_GetTrustLevel,
+    /* IDataWriter */
+    data_writer_get_UnstoredBufferLength,
+    data_writer_get_UnicodeEncoding,
+    data_writer_put_UnicodeEncoding,
+    data_writer_get_ByteOrder,
+    data_writer_put_ByteOrder,
+    data_writer_WriteByte,
+    data_writer_WriteBytes,
+    data_writer_WriteBuffer,
+    data_writer_WriteBufferRange,
+    data_writer_WriteBoolean,
+    data_writer_WriteGuid,
+    data_writer_WriteInt16,
+    data_writer_WriteInt32,
+    data_writer_WriteInt64,
+    data_writer_WriteUInt16,
+    data_writer_WriteUInt32,
+    data_writer_WriteUInt64,
+    data_writer_WriteSingle,
+    data_writer_WriteDouble,
+    data_writer_WriteDateTime,
+    data_writer_WriteTimeSpan,
+    data_writer_WriteString,
+    data_writer_MeasureString,
+    data_writer_StoreAsync,
+    data_writer_FlushAsync,
+    data_writer_DetachBuffer,
+    data_writer_DetachStream,
+};
+
+static HRESULT data_writer_create(IOutputStream *output_stream, IDataWriter **out)
+{
+    struct data_writer *impl;
+    HRESULT hr;
+
+    *out = NULL;
+    if (!(impl = calloc(1, sizeof(*impl))))
+        return E_OUTOFMEMORY;
+
+    impl->IDataWriter_iface.lpVtbl = &data_writer_vtbl;
+    impl->stream = output_stream;
+    impl->ref = 1;
+
+    if (FAILED(hr = data_writer_init_buffer(impl, 0)))
+    {
+        free(impl);
+        return hr;
+    }
+
+    if (output_stream)
+        IOutputStream_AddRef(output_stream);
+
+    *out = &impl->IDataWriter_iface;
+    return S_OK;
+}
+
+struct data_writer_factory
 {
     IActivationFactory IActivationFactory_iface;
+    IDataWriterFactory IDataWriterFactory_iface;
     LONG ref;
 };
 
-static inline struct data_writer *impl_data_writer_from_IActivationFactory(IActivationFactory *iface)
+static inline struct data_writer_factory *impl_data_writer_factory_from_IActivationFactory(IActivationFactory *iface)
+{
+    return CONTAINING_RECORD(iface, struct data_writer_factory, IActivationFactory_iface);
+}
+
+static inline struct data_writer_factory *impl_data_writer_factory_from_IDataWriterFactory(IDataWriterFactory *iface)
 {
-    return CONTAINING_RECORD(iface, struct data_writer, IActivationFactory_iface);
+    return CONTAINING_RECORD(iface, struct data_writer_factory, IDataWriterFactory_iface);
 }
 
 static HRESULT STDMETHODCALLTYPE data_writer_activation_factory_QueryInterface(IActivationFactory *iface, REFIID iid,
@@ -47,6 +720,14 @@ static HRESULT STDMETHODCALLTYPE data_writer_activation_factory_QueryInterface(I
         return S_OK;
     }
 
+    if (IsEqualGUID(iid, &IID_IDataWriterFactory))
+    {
+        struct data_writer_factory *impl = impl_data_writer_factory_from_IActivationFactory(iface);
+        IDataWriterFactory_AddRef(&impl->IDataWriterFactory_iface);
+        *out = &impl->IDataWriterFactory_iface;
+        return S_OK;
+    }
+
     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
     *out = NULL;
     return E_NOINTERFACE;
@@ -54,7 +735,7 @@ static HRESULT STDMETHODCALLTYPE data_writer_activation_factory_QueryInterface(I
 
 static ULONG STDMETHODCALLTYPE data_writer_activation_factory_AddRef(IActivationFactory *iface)
 {
-    struct data_writer *impl = impl_data_writer_from_IActivationFactory(iface);
+    struct data_writer_factory *impl = impl_data_writer_factory_from_IActivationFactory(iface);
     ULONG ref = InterlockedIncrement(&impl->ref);
     TRACE("iface %p, ref %lu.\n", iface, ref);
     return ref;
@@ -62,7 +743,7 @@ static ULONG STDMETHODCALLTYPE data_writer_activation_factory_AddRef(IActivation
 
 static ULONG STDMETHODCALLTYPE data_writer_activation_factory_Release(IActivationFactory *iface)
 {
-    struct data_writer *impl = impl_data_writer_from_IActivationFactory(iface);
+    struct data_writer_factory *impl = impl_data_writer_factory_from_IActivationFactory(iface);
     ULONG ref = InterlockedDecrement(&impl->ref);
     TRACE("iface %p, ref %lu.\n", iface, ref);
     return ref;
@@ -92,8 +773,18 @@ static HRESULT STDMETHODCALLTYPE data_writer_activation_factory_GetTrustLevel(IA
 static HRESULT STDMETHODCALLTYPE data_writer_activation_factory_ActivateInstance(IActivationFactory *iface,
         IInspectable **instance)
 {
-    FIXME("iface %p, instance %p stub!\n", iface, instance);
-    return S_OK;
+    IDataWriter *data_writer;
+    HRESULT hr;
+
+    TRACE("iface %p, instance %p.\n", iface, instance);
+
+    if (FAILED(hr = data_writer_create(NULL, &data_writer)))
+        return hr;
+
+    hr = IDataWriter_QueryInterface(data_writer, &IID_IInspectable, (void **)instance);
+    IDataWriter_Release(data_writer);
+
+    return hr;
 }
 
 static const struct IActivationFactoryVtbl data_writer_activation_factory_vtbl =
@@ -109,10 +800,95 @@ static const struct IActivationFactoryVtbl data_writer_activation_factory_vtbl =
     data_writer_activation_factory_ActivateInstance,
 };
 
-struct data_writer data_writer =
+static HRESULT STDMETHODCALLTYPE data_writer_factory_QueryInterface(IDataWriterFactory *iface, REFIID iid, void **out)
+{
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_IUnknown)
+            || IsEqualGUID(iid, &IID_IInspectable)
+            || IsEqualGUID(iid, &IID_IAgileObject)
+            || IsEqualGUID(iid, &IID_IDataWriterFactory))
+    {
+        IUnknown_AddRef(iface);
+        *out = iface;
+        return S_OK;
+    }
+
+    if (IsEqualGUID(iid, &IID_IActivationFactory))
+    {
+        struct data_writer_factory *impl = impl_data_writer_factory_from_IDataWriterFactory(iface);
+        IActivationFactory_AddRef(&impl->IActivationFactory_iface);
+        *out = &impl->IActivationFactory_iface;
+        return S_OK;
+    }
+
+    WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG STDMETHODCALLTYPE data_writer_factory_AddRef(IDataWriterFactory *iface)
+{
+    struct data_writer_factory *impl = impl_data_writer_factory_from_IDataWriterFactory(iface);
+    ULONG ref = InterlockedIncrement(&impl->ref);
+    TRACE("iface %p, ref %lu.\n", iface, ref);
+    return ref;
+}
+
+static ULONG STDMETHODCALLTYPE data_writer_factory_Release(IDataWriterFactory *iface)
+{
+    struct data_writer_factory *impl = impl_data_writer_factory_from_IDataWriterFactory(iface);
+    ULONG ref = InterlockedDecrement(&impl->ref);
+    TRACE("iface %p, ref %lu.\n", iface, ref);
+    return ref;
+}
+
+static HRESULT STDMETHODCALLTYPE data_writer_factory_GetIids(IDataWriterFactory *iface, ULONG *iid_count,
+        IID **iids)
+{
+    FIXME("iface %p, iid_count %p, iids %p stub!\n", iface, iid_count, iids);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE data_writer_factory_GetRuntimeClassName(IDataWriterFactory *iface,
+        HSTRING *class_name)
+{
+    FIXME("iface %p, class_name %p stub!\n", iface, class_name);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE data_writer_factory_GetTrustLevel(IDataWriterFactory *iface,
+        TrustLevel *trust_level)
+{
+    FIXME("iface %p, trust_level %p stub!\n", iface, trust_level);
+    return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE data_writer_factory_CreateDataWriter(IDataWriterFactory *iface,
+        IOutputStream *output_stream, IDataWriter **data_writer)
+{
+    TRACE("iface %p, output_stream %p, data_writer %p.\n", iface, output_stream, data_writer);
+    return data_writer_create(output_stream, data_writer);
+}
+
+static const struct IDataWriterFactoryVtbl data_writer_factory_vtbl =
+{
+    data_writer_factory_QueryInterface,
+    data_writer_factory_AddRef,
+    data_writer_factory_Release,
+    /* IInspectable methods */
+    data_writer_factory_GetIids,
+    data_writer_factory_GetRuntimeClassName,
+    data_writer_factory_GetTrustLevel,
+    /* IDataWriterFactory methods */
+    data_writer_factory_CreateDataWriter,
+};
+
+struct data_writer_factory data_writer_factory =
 {
     {&data_writer_activation_factory_vtbl},
+    {&data_writer_factory_vtbl},
     1
 };
 
-IActivationFactory *data_writer_activation_factory = &data_writer.IActivationFactory_iface;
+IActivationFactory *data_writer_activation_factory = &data_writer_factory.IActivationFactory_iface;
diff --git a/dlls/wintypes/tests/wintypes.c b/dlls/wintypes/tests/wintypes.c
index 49eb82a6bf91..94f9ba2edd44 100644
--- a/dlls/wintypes/tests/wintypes.c
+++ b/dlls/wintypes/tests/wintypes.c
@@ -1,5 +1,6 @@
 /*
  * Copyright 2022 Zhiyi Zhang for CodeWeavers
+ * Copyright 2026 Conor McCarthy for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -43,6 +44,159 @@
 
 static BOOL is_wow64;
 
+static HRESULT get_activation_factory(const WCHAR *name, IActivationFactory **factory)
+{
+    HSTRING str = NULL;
+    HRESULT hr;
+
+    hr = WindowsCreateString(name, wcslen(name), &str);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = RoGetActivationFactory(str, &IID_IActivationFactory, (void **)factory);
+    WindowsDeleteString(str);
+    ok(hr == S_OK || broken(hr == REGDB_E_CLASSNOTREG), "got hr %#lx.\n", hr);
+
+    if (hr == REGDB_E_CLASSNOTREG)
+        win_skip("%s runtimeclass not registered, skipping tests.\n", wine_dbgstr_w(name));
+
+    return hr;
+}
+
+static BYTE *buffer_get_data(IBuffer *buffer)
+{
+    IBufferByteAccess *access;
+    BYTE *data = NULL;
+    HRESULT hr;
+
+    hr = IBuffer_QueryInterface(buffer, &IID_IBufferByteAccess, (void **)&access);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IBufferByteAccess_Buffer(access, &data);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IBufferByteAccess_Release(access);
+
+    return data;
+}
+
+#define DEFINE_ASYNC_COMPLETED_HANDLER(name, iface_type, async_type)                                \
+    struct name                                                                                     \
+    {                                                                                               \
+        iface_type iface_type##_iface;                                                              \
+        LONG refcount;                                                                              \
+        BOOL invoked;                                                                               \
+        HANDLE event;                                                                               \
+    };                                                                                              \
+                                                                                                    \
+    static HRESULT WINAPI name##_QueryInterface(iface_type *iface, REFIID iid, void **out)          \
+    {                                                                                               \
+        if (IsEqualGUID(iid, &IID_IUnknown) || IsEqualGUID(iid, &IID_IAgileObject) ||               \
+            IsEqualGUID(iid, &IID_##iface_type))                                                    \
+        {                                                                                           \
+            IUnknown_AddRef(iface);                                                                 \
+            *out = iface;                                                                           \
+            return S_OK;                                                                            \
+        }                                                                                           \
+                                                                                                    \
+        trace("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));                \
+        *out = NULL;                                                                                \
+        return E_NOINTERFACE;                                                                       \
+    }                                                                                               \
+                                                                                                    \
+    static ULONG WINAPI name##_AddRef(iface_type *iface)                                            \
+    {                                                                                               \
+        struct name *impl = CONTAINING_RECORD(iface, struct name, iface_type##_iface);              \
+        return InterlockedIncrement(&impl->refcount);                                               \
+    }                                                                                               \
+                                                                                                    \
+    static ULONG WINAPI name##_Release(iface_type *iface)                                           \
+    {                                                                                               \
+        struct name *impl = CONTAINING_RECORD(iface, struct name, iface_type##_iface);              \
+        ULONG ref = InterlockedDecrement(&impl->refcount);                                          \
+        if (!ref) free(impl);                                                                       \
+        return ref;                                                                                 \
+    }                                                                                               \
+                                                                                                    \
+    static HRESULT WINAPI name##_Invoke(iface_type *iface, async_type *async, AsyncStatus status)   \
+    {                                                                                               \
+        struct name *impl = CONTAINING_RECORD(iface, struct name, iface_type##_iface);              \
+        ok(!impl->invoked, "invoked twice\n");                                                      \
+        impl->invoked = TRUE;                                                                       \
+        if (impl->event) SetEvent(impl->event);                                                     \
+        return S_OK;                                                                                \
+    }                                                                                               \
+                                                                                                    \
+    static iface_type##Vtbl name##_vtbl =                                                           \
+    {                                                                                               \
+        name##_QueryInterface,                                                                      \
+        name##_AddRef,                                                                              \
+        name##_Release,                                                                             \
+        name##_Invoke,                                                                              \
+    };                                                                                              \
+                                                                                                    \
+    static iface_type *name##_create(HANDLE event)                                                  \
+    {                                                                                               \
+        struct name *impl;                                                                          \
+                                                                                                    \
+        if (!(impl = calloc(1, sizeof(*impl)))) return NULL;                                        \
+        impl->iface_type##_iface.lpVtbl = &name##_vtbl;                                             \
+        impl->event = event;                                                                        \
+        impl->refcount = 1;                                                                         \
+                                                                                                    \
+        return &impl->iface_type##_iface;                                                           \
+    }                                                                                               \
+                                                                                                    \
+    static DWORD await_##async_type(async_type *async, DWORD timeout)                               \
+    {                                                                                               \
+        iface_type *handler;                                                                        \
+        HANDLE event;                                                                               \
+        HRESULT hr;                                                                                 \
+        DWORD ret;                                                                                  \
+                                                                                                    \
+        event = CreateEventW(NULL, FALSE, FALSE, NULL);                                             \
+        ok(!!event, "CreateEventW failed, error %lu\n", GetLastError());                            \
+        handler = name##_create(event);                                                             \
+        ok(!!handler, "Failed to create completion handler\n");                                     \
+        hr = async_type##_put_Completed(async, handler);                                            \
+        ok(hr == S_OK, "put_Completed returned %#lx\n", hr);                                        \
+        ret = WaitForSingleObject(event, timeout);                                                  \
+        ok(!ret, "WaitForSingleObject returned %#lx\n", ret);                                       \
+        CloseHandle(event);                                                                         \
+        iface_type##_Release(handler);                                                              \
+                                                                                                    \
+        return ret;                                                                                 \
+    }
+
+#define check_async_info(a, b, c) check_async_info_(__LINE__, a, b, c)
+static void check_async_info_(int line, void *async, AsyncStatus expect_status, HRESULT expect_hr)
+{
+    AsyncStatus async_status;
+    IAsyncInfo *async_info;
+    HRESULT hr, async_hr;
+    UINT32 async_id;
+
+    hr = IInspectable_QueryInterface(async, &IID_IAsyncInfo, (void **)&async_info);
+    ok_(__FILE__, line)(hr == S_OK, "QueryInterface returned %#lx\n", hr);
+
+    async_id = 0xdeadbeef;
+    hr = IAsyncInfo_get_Id(async_info, &async_id);
+    if (expect_status < 4) ok_(__FILE__, line)(hr == S_OK, "get_Id returned %#lx\n", hr);
+    else ok_(__FILE__, line)(hr == E_ILLEGAL_METHOD_CALL, "get_Id returned %#lx\n", hr);
+    ok_(__FILE__, line)(!!async_id, "got id %u\n", async_id);
+
+    async_status = 0xdeadbeef;
+    hr = IAsyncInfo_get_Status(async_info, &async_status);
+    if (expect_status < 4) ok_(__FILE__, line)(hr == S_OK, "get_Status returned %#lx\n", hr);
+    else ok_(__FILE__, line)(hr == E_ILLEGAL_METHOD_CALL, "get_Status returned %#lx\n", hr);
+    ok_(__FILE__, line)(async_status == expect_status, "got status %u\n", async_status);
+
+    async_hr = 0xdeadbeef;
+    hr = IAsyncInfo_get_ErrorCode(async_info, &async_hr);
+    if (expect_status < 4) ok_(__FILE__, line)(hr == S_OK, "get_ErrorCode returned %#lx\n", hr);
+    else ok_(__FILE__, line)(hr == E_ILLEGAL_METHOD_CALL, "get_ErrorCode returned %#lx\n", hr);
+    if (expect_status < 4) todo_wine_if(FAILED(expect_hr)) ok_(__FILE__, line)(async_hr == expect_hr, "got error %#lx\n", async_hr);
+    else ok_(__FILE__, line)(async_hr == E_ILLEGAL_METHOD_CALL, "got error %#lx\n", async_hr);
+
+    IAsyncInfo_Release(async_info);
+}
+
 #define check_interface(obj, iid, supported) check_interface_(__LINE__, obj, iid, supported)
 static void check_interface_(unsigned int line, void *obj, const IID *iid, BOOL supported)
 {
@@ -110,7 +264,7 @@ static void test_interfaces(void)
     check_interface(factory, &IID_IInspectable, TRUE);
     check_interface(factory, &IID_IAgileObject, TRUE);
     check_interface(factory, &IID_IActivationFactory, TRUE);
-    todo_wine check_interface(factory, &IID_IDataWriterFactory, TRUE);
+    check_interface(factory, &IID_IDataWriterFactory, TRUE);
     check_interface(factory, &IID_IRandomAccessStreamReferenceStatics, FALSE);
     check_interface(factory, &IID_IApiInformationStatics, FALSE);
     check_interface(factory, &IID_IPropertyValueStatics, FALSE);
@@ -1485,6 +1639,232 @@ done:
     RoUninitialize();
 }
 
+DEFINE_ASYNC_COMPLETED_HANDLER(async_uint32_result_handler, IAsyncOperationCompletedHandler_UINT32, IAsyncOperation_UINT32)
+
+static void test_DataWriter(void)
+{
+    static const WCHAR *in_memory_stream_statics_name = L"Windows.Storage.Streams.InMemoryRandomAccessStream";
+    static const WCHAR *data_writer_statics_name = L"Windows.Storage.Streams.DataWriter";
+    IAsyncOperationWithProgress_IBuffer_UINT32 *op_with_progress;
+    IRandomAccessStream *in_memory_stream = (void *)0xdeadbeef;
+    IOutputStream *detached_stream = (void *)0xdeadbeef;
+    IOutputStream *output_stream = (void *)0xdeadbeef;
+    IActivationFactory *factory = (void *)0xdeadbeef;
+    IInspectable *inspectable = (void *)0xdeadbeef;
+    const UINT64 uint64_value = 0xdeadbeefcafef00d;
+    IDataWriterFactory *data_writer_factory = NULL;
+    IAsyncOperation_UINT32 *operation;
+    IAsyncOperation_boolean *bool_op;
+    IInputStream *input_stream;
+    IDataWriter *data_writer;
+    BYTE byte_value = 0xab;
+    IBuffer *buffer;
+    UINT64 value64;
+    UINT32 value;
+    UINT res, i;
+    HRESULT hr;
+    BYTE *data;
+    LONG ref;
+
+    hr = RoInitialize(RO_INIT_MULTITHREADED);
+    ok(hr == S_OK, "got %#lx\n", hr);
+
+    if (FAILED(hr = get_activation_factory(data_writer_statics_name, &factory)))
+    {
+        RoUninitialize();
+        return;
+    }
+
+    hr = IActivationFactory_ActivateInstance(factory, &inspectable);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IActivationFactory_QueryInterface(factory, &IID_IDataWriterFactory, (void **)&data_writer_factory);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IActivationFactory_Release(factory);
+
+    hr = IInspectable_QueryInterface(inspectable, &IID_IDataWriter, (void **)&data_writer);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IInspectable_Release(inspectable);
+
+    check_interface(data_writer, &IID_IAgileObject, TRUE);
+
+    hr = IDataWriter_DetachStream(data_writer, &output_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(!output_stream, "got stream %p.\n", output_stream);
+
+    hr = IDataWriter_WriteBytes(data_writer, 8, (BYTE *)&uint64_value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+
+    hr = IDataWriter_StoreAsync(data_writer, &operation);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION), "got hr %#lx.\n", hr);
+    hr = IDataWriter_FlushAsync(data_writer, &bool_op);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION), "got hr %#lx.\n", hr);
+
+    hr = IDataWriter_DetachBuffer(data_writer, &buffer);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IBuffer_get_Length(buffer, &value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value == 8, "got length %u.\n", value);
+
+    data = buffer_get_data(buffer);
+    memcpy(&value64, data, sizeof(value64));
+    ok(value64 == uint64_value, "got %I64x.\n", value64);
+
+    IBuffer_Release(buffer);
+
+    ref = IDataWriter_Release(data_writer);
+    ok(ref == 0, "got ref %ld.\n", ref);
+
+    get_activation_factory(in_memory_stream_statics_name, &factory);
+
+    hr = IActivationFactory_ActivateInstance(factory, &inspectable);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IInspectable_QueryInterface(inspectable, &IID_IRandomAccessStream, (void **)&in_memory_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IInspectable_Release(inspectable);
+
+    hr = IRandomAccessStream_QueryInterface(in_memory_stream, &IID_IOutputStream, (void **)&output_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IDataWriterFactory_CreateDataWriter(data_writer_factory, output_stream, &data_writer);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IOutputStream_Release(output_stream);
+
+    for (i = 0; i < 2; ++i)
+    {
+        winetest_push_context("%u", i);
+
+        hr = IDataWriter_DetachBuffer(data_writer, &buffer);
+        ok(hr == S_OK, "got hr %#lx.\n", hr);
+        hr = IBuffer_get_Capacity(buffer, &value);
+        ok(hr == S_OK, "got hr %#lx.\n", hr);
+        /* Capacity starts small */
+        ok(value > 0 && value <= 16384, "got capacity %u.\n", value);
+        hr = IBuffer_get_Length(buffer, &value);
+        ok(hr == S_OK, "got hr %#lx.\n", hr);
+        ok(value == 0, "got length %u.\n", value);
+        IBuffer_Release(buffer);
+
+        winetest_pop_context();
+    }
+
+    hr = IDataWriter_WriteBytes(data_writer, 8, (BYTE *)&uint64_value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IDataWriter_StoreAsync(data_writer, &operation);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+
+    /* Writing is allowed while storing, and the data will be stored by the next StoreAsync() call */
+    hr = IDataWriter_WriteBytes(data_writer, 1, &byte_value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    res = await_IAsyncOperation_UINT32(operation, 1000);
+    ok(res == 0, "await_IAsyncOperation_UINT32 returned %#x\n", res);
+    check_async_info(operation, Completed, S_OK);
+    hr = IAsyncOperation_UINT32_GetResults(operation, &value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value == 8, "got written %u.\n", value);
+    check_async_info(operation, Completed, S_OK);
+    ref = IAsyncOperation_UINT32_Release(operation);
+    ok(ref == 0, "got ref %ld.\n", ref);
+
+    hr = IDataWriter_StoreAsync(data_writer, &operation);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+
+    /* Storing replaces the buffer */
+    hr = IDataWriter_DetachBuffer(data_writer, &buffer);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IBuffer_get_Length(buffer, &value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value == 0, "got length %u.\n", value);
+    /* Use the buffer later */
+
+    res = await_IAsyncOperation_UINT32(operation, 1000);
+    ok(res == 0, "await_IAsyncOperation_UINT32 returned %#x\n", res);
+    check_async_info(operation, Completed, S_OK);
+    hr = IAsyncOperation_UINT32_GetResults(operation, &value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value == 1, "got written %u.\n", value);
+    ref = IAsyncOperation_UINT32_Release(operation);
+    ok(ref == 0, "got ref %ld.\n", ref);
+
+    hr = IRandomAccessStream_get_Size(in_memory_stream, &value64);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value64 == 9, "got size %lu.\n", (long)value64);
+    hr = IRandomAccessStream_get_Position(in_memory_stream, &value64);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value64 == 9, "got pos %lu.\n", (long)value64);
+
+    data = buffer_get_data(buffer);
+    hr = IBuffer_get_Capacity(buffer, &value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value >= 9, "got capacity %u.\n", value);
+    memset(data, 0xcd, 9);
+
+    hr = IRandomAccessStream_QueryInterface(in_memory_stream, &IID_IInputStream, (void **)&input_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+
+    hr = IRandomAccessStream_Seek(in_memory_stream, 0);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IInputStream_ReadAsync(input_stream, buffer, 9, 0, &op_with_progress);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IBuffer_Release(buffer);
+    hr = IAsyncOperationWithProgress_IBuffer_UINT32_GetResults(op_with_progress, &buffer);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ref = IAsyncOperationWithProgress_IBuffer_UINT32_Release(op_with_progress);
+    ok(ref == 0, "got ref %ld.\n", ref);
+    hr = IBuffer_get_Length(buffer, &value);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(value == 9, "got read %u.\n", value);
+
+    data = buffer_get_data(buffer);
+    memcpy(&value64, data, sizeof(value64));
+    ok(value64 == uint64_value, "got %I64x.\n", value64);
+    ok(data[8] == byte_value, "got %#x.\n", data[8]);
+
+    ref = IDataWriter_Release(data_writer);
+    ok(ref == 0, "got ref %ld.\n", ref);
+
+    /* Releasing the data writer closes all streams */
+    hr = IInputStream_ReadAsync(input_stream, buffer, 8, 0, &op_with_progress);
+    ok(hr == RO_E_CLOSED, "got hr %#lx.\n", hr);
+
+    IBuffer_Release(buffer);
+    IInputStream_Release(input_stream);
+    ref = IRandomAccessStream_Release(in_memory_stream);
+    ok(ref == 0, "got ref %ld.\n", ref);
+
+    /* DetachStream() */
+
+    hr = IActivationFactory_ActivateInstance(factory, &inspectable);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IActivationFactory_Release(factory);
+    hr = IInspectable_QueryInterface(inspectable, &IID_IRandomAccessStream, (void **)&in_memory_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IInspectable_Release(inspectable);
+
+    hr = IRandomAccessStream_QueryInterface(in_memory_stream, &IID_IOutputStream, (void **)&output_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    hr = IDataWriterFactory_CreateDataWriter(data_writer_factory, output_stream, &data_writer);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    IOutputStream_Release(output_stream);
+
+    hr = IDataWriter_DetachStream(data_writer, &detached_stream);
+    ok(hr == S_OK, "got hr %#lx.\n", hr);
+    ok(detached_stream == output_stream, "got stream %p.\n", detached_stream);
+    IOutputStream_Release(detached_stream);
+
+    hr = IDataWriter_StoreAsync(data_writer, &operation);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION), "got hr %#lx.\n", hr);
+    hr = IDataWriter_FlushAsync(data_writer, &bool_op);
+    ok(hr == HRESULT_FROM_WIN32(ERROR_INVALID_OPERATION), "got hr %#lx.\n", hr);
+
+    ref = IDataWriter_Release(data_writer);
+    ok(ref == 0, "got ref %ld.\n", ref);
+    ref = IRandomAccessStream_Release(in_memory_stream);
+    ok(ref == 0, "got ref %ld.\n", ref);
+    ref = IDataWriterFactory_Release(data_writer_factory);
+    ok(ref == 1, "got ref %ld.\n", ref);
+
+    RoUninitialize();
+}
+
 START_TEST(wintypes)
 {
     IsWow64Process(GetCurrentProcess(), &is_wow64);
@@ -1496,4 +1876,5 @@ START_TEST(wintypes)
     test_RoParseTypeName();
     test_RoResolveNamespace();
     test_IPropertySet();
+    test_DataWriter();
 }
diff --git a/dlls/wldp/Makefile.in b/dlls/wldp/Makefile.in
index b9871a8609ad..dc485c400d3a 100644
--- a/dlls/wldp/Makefile.in
+++ b/dlls/wldp/Makefile.in
@@ -1,6 +1,4 @@
 MODULE    = wldp.dll
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	wldp.c
diff --git a/dlls/wminet_utils/main.c b/dlls/wminet_utils/main.c
index 7af46dce1b51..2377a1d5fab7 100644
--- a/dlls/wminet_utils/main.c
+++ b/dlls/wminet_utils/main.c
@@ -120,3 +120,18 @@ HRESULT WINAPI Initialize(BOOLEAN bAllowIManagementObjectQI)
     TRACE("%i\n", bAllowIManagementObjectQI);
     return S_OK;
 }
+
+HRESULT WINAPI GetNames(int vFunc, IWbemClassObject *ptr, LPCWSTR wszQualifierName, LONG lFlags,
+    VARIANT *pQualifierVal, SAFEARRAY **pNames)
+{
+    TRACE("%i %p %s %lx %p %p\n", vFunc, ptr, debugstr_w(wszQualifierName), lFlags, pQualifierVal, pNames);
+
+    return IWbemClassObject_GetNames(ptr, wszQualifierName, lFlags, pQualifierVal, pNames);
+}
+
+HRESULT WINAPI BeginMethodEnumeration(int vFunc, IWbemClassObject *ptr, LONG lEnumFlags)
+{
+    TRACE("%i %p %lx\n", vFunc, ptr, lEnumFlags);
+
+    return IWbemClassObject_BeginMethodEnumeration(ptr, lEnumFlags);
+}
diff --git a/dlls/wminet_utils/wminet_utils.spec b/dlls/wminet_utils/wminet_utils.spec
index 4cc7536b3105..4cddf19c6187 100644
--- a/dlls/wminet_utils/wminet_utils.spec
+++ b/dlls/wminet_utils/wminet_utils.spec
@@ -1,5 +1,5 @@
 @ stub BeginEnumeration
-@ stub BeginMethodEnumeration
+@ stdcall BeginMethodEnumeration(long ptr long)
 @ stub BlessIWbemServices
 @ stub BlessIWbemServicesObject
 @ stub Clone
@@ -25,7 +25,7 @@
 @ stub GetMethod
 @ stub GetMethodOrigin
 @ stub GetMethodQualifierSet
-@ stub GetNames
+@ stdcall GetNames(long ptr wstr long ptr ptr)
 @ stub GetObjectText
 @ stub GetPropertyHandle
 @ stub GetPropertyInfoByHandle
diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c
index 98d1c600dd93..b8ac135a9428 100644
--- a/dlls/wow64/process.c
+++ b/dlls/wow64/process.c
@@ -201,6 +201,20 @@ static PS_ATTRIBUTE_LIST *ps_attributes_32to64( PS_ATTRIBUTE_LIST **attr, const
             ret->Attributes[i].Size     = sizeof(TEB *);
             ret->Attributes[i].ValuePtr = Wow64AllocateTemp( ret->Attributes[i].Size );
             break;
+        case PS_ATTRIBUTE_GROUP_AFFINITY:
+            {
+                GROUP_AFFINITY32 *aff32 = ret->Attributes[i].ValuePtr;
+                GROUP_AFFINITY *aff64;
+                ret->Attributes[i].Size     = sizeof(GROUP_AFFINITY);
+                ret->Attributes[i].ValuePtr = Wow64AllocateTemp( ret->Attributes[i].Size );
+                aff64 = ret->Attributes[i].ValuePtr;
+                aff64->Mask = aff32->Mask;
+                aff64->Group = aff32->Group;
+                aff64->Reserved[0] = aff32->Reserved[0];
+                aff64->Reserved[1] = aff32->Reserved[1];
+                aff64->Reserved[2] = aff32->Reserved[2];
+            }
+            break;
         }
     }
     *attr = ret;
diff --git a/dlls/wpc/Makefile.in b/dlls/wpc/Makefile.in
index 75bf0a7827e7..ca7fd48eac3e 100644
--- a/dlls/wpc/Makefile.in
+++ b/dlls/wpc/Makefile.in
@@ -1,7 +1,5 @@
 MODULE = wpc.dll
 
-EXTRADLLFLAGS = -Wb,--prefer-native
-
 SOURCES = \
 	wpc.c \
 	wpc_classes.idl
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c
index e67e50907b01..698ae0fe0b9b 100644
--- a/dlls/ws2_32/tests/sock.c
+++ b/dlls/ws2_32/tests/sock.c
@@ -6823,6 +6823,7 @@ static void test_connect_events(struct event_test_ctx *ctx)
     const struct sockaddr_in addr = {.sin_family = AF_INET, .sin_addr.s_addr = htonl(INADDR_LOOPBACK)};
     SOCKET listener, server, client;
     struct sockaddr_in destaddr;
+    struct sockaddr_in invalid_addr;
     int len, ret;
 
     listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
@@ -6937,6 +6938,95 @@ static void test_connect_events(struct event_test_ctx *ctx)
     closesocket(server);
 
     closesocket(listener);
+
+    memset( &invalid_addr, 0, sizeof(invalid_addr) );
+    invalid_addr.sin_family = AF_INET;
+    invalid_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    invalid_addr.sin_port = htons(255);
+
+    /* Test events getting cleared on second connect after connection got refused.
+     * w10pro64 sometimes takes over 2 seconds for an error to be reported,
+     * so make the test interactive-only. */
+
+    if (winetest_interactive)
+    {
+        client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+        ok(client != -1, "failed to create socket, error %u\n", WSAGetLastError());
+
+        select_events(ctx, client, FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE);
+        check_events(ctx, 0, 0, 0);
+        check_events(ctx, 0, 0, 0);
+
+        /* set event by connecting to closed port */
+        ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000);
+        check_events(ctx, 0, 0, 0);
+
+        /* set event by connecting to closed port, second try, should behave the same */
+        ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000);
+        check_events(ctx, 0, 0, 0);
+
+        /* set event by connecting to closed port */
+        ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        /* try with invalid size, after event was set */
+        ret = connect(client, (struct sockaddr *)&invalid_addr, 1);
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000);
+        check_events(ctx, 0, 0, 0);
+
+        /* set event by connecting to closed port */
+        ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        /* try with invalid sin_family, after event was set */
+        invalid_addr.sin_family = 0xf1;
+        ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        check_events(ctx, MAKELONG(FD_CONNECT, WSAECONNREFUSED), 0, 4000);
+        check_events(ctx, 0, 0, 0);
+        invalid_addr.sin_family = AF_INET;
+
+        closesocket(client);
+    }
+
+    if (winetest_interactive && !ctx->is_message)
+    {
+        /* setup listener */
+        listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+        ok(listener != -1, "failed to create socket, error %u\n", WSAGetLastError());
+        ret = bind(listener, (const struct sockaddr *)&addr, sizeof(addr));
+        ok(!ret, "failed to bind, error %u\n", WSAGetLastError());
+        len = sizeof(destaddr);
+        ret = getsockname(listener, (struct sockaddr *)&destaddr, &len);
+        ok(!ret, "failed to get address, error %u\n", WSAGetLastError());
+        ret = listen(listener, 2);
+        ok(!ret, "failed to listen, error %u\n", WSAGetLastError());
+        client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+        ok(client != -1, "failed to create socket, error %u\n", WSAGetLastError());
+        select_events(ctx, client, FD_ACCEPT | FD_CLOSE | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE);
+        check_events(ctx, 0, 0, 0);
+        check_events(ctx, 0, 0, 0);
+
+        /* set event by connecting to closed port */
+        ret = connect(client, (struct sockaddr *)&invalid_addr, sizeof(invalid_addr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        check_poll_todo(client, 0);
+        Sleep(2000);
+        /* try successful connect, after event was set */
+        ret = connect(client, (struct sockaddr *)&destaddr, sizeof(destaddr));
+        ok(ret == SOCKET_ERROR, "expected SOCKET_ERROR, got %d\n", ret);
+        ok(WSAGetLastError() == WSAEWOULDBLOCK, "expected WSAEWOULDBLOCK, got %u\n", WSAGetLastError());
+        check_poll(client, POLLWRNORM);
+        check_events(ctx, MAKELONG(FD_CONNECT | FD_WRITE, WSAECONNREFUSED), 0, 4000);
+        check_events(ctx, 0, 0, 0);
+
+        closesocket(client);
+
+        closesocket(listener);
+    }
 }
 
 /* perform a blocking recv() even on a nonblocking socket */
@@ -7415,6 +7505,7 @@ static void test_events(void)
     struct event_test_ctx ctx;
 
     ctx.is_message = FALSE;
+    winetest_push_context("is_message=0");
     ctx.event = CreateEventW(NULL, TRUE, FALSE, NULL);
 
     test_accept_events(&ctx);
@@ -7426,7 +7517,9 @@ static void test_events(void)
 
     CloseHandle(ctx.event);
 
+    winetest_pop_context();
     ctx.is_message = TRUE;
+    winetest_push_context("is_message=1");
     ctx.window = CreateWindowA("Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
 
     test_accept_events(&ctx);
@@ -7437,6 +7530,7 @@ static void test_events(void)
     test_oob_events(&ctx);
 
     DestroyWindow(ctx.window);
+    winetest_pop_context();
 }
 
 static void test_ipv6only(void)
diff --git a/include/Makefile.in b/include/Makefile.in
index 72a8d43988ce..d19d160343c9 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -67,6 +67,7 @@ SOURCES = \
 	bthsdpdef.h \
 	cderr.h \
 	cdosys.idl \
+	cfapi.h \
 	cfg.h \
 	cfgmgr32.h \
 	cguid.h \
diff --git a/include/bcrypt.h b/include/bcrypt.h
index fe361307b6c2..b78a18a4ba2e 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -94,6 +94,7 @@ extern "C" {
 
 #define BCRYPT_3DES_ALGORITHM       L"3DES"
 #define BCRYPT_AES_ALGORITHM        L"AES"
+#define BCRYPT_AES_GMAC_ALGORITHM   L"AES-GMAC"
 #define BCRYPT_CHACHA20_POLY1305_ALGORITHM L"CHACHA20_POLY1305"
 #define BCRYPT_DES_ALGORITHM        L"DES"
 #define BCRYPT_DH_ALGORITHM         L"DH"
@@ -142,6 +143,8 @@ extern "C" {
 #define BCRYPT_KDF_RAW_SECRET       L"TRUNCATE"
 
 #define BCRYPT_DH_PARAMETERS        L"DHParameters"
+
+#define BCRYPT_MESSAGE_BLOCK_LENGTH L"MessageBlockLength"
 #else
 static const WCHAR BCRYPT_ALGORITHM_NAME[] = {'A','l','g','o','r','i','t','h','m','N','a','m','e',0};
 static const WCHAR BCRYPT_AUTH_TAG_LENGTH[] = {'A','u','t','h','T','a','g','L','e','n','g','t','h',0};
@@ -190,6 +193,7 @@ static const WCHAR MS_PLATFORM_CRYPTO_PROVIDER[] = \
 
 static const WCHAR BCRYPT_3DES_ALGORITHM[] = {'3','D','E','S',0};
 static const WCHAR BCRYPT_AES_ALGORITHM[] = {'A','E','S',0};
+static const WCHAR BCRYPT_AES_GMAC_ALGORITHM[] = {'A','E','S','-','G','M','A','C',0};
 static const WCHAR BCRYPT_CHACHA20_POLY1305_ALGORITHM[] = {'C','H','A','C','H','A','2','0','_','P','O','L','Y','1','3','0','5',0};
 static const WCHAR BCRYPT_DES_ALGORITHM[] = {'D','E','S',0};
 static const WCHAR BCRYPT_DH_ALGORITHM[] = {'D','H',0};
@@ -238,6 +242,7 @@ static const WCHAR BCRYPT_KDF_SP80056A_CONCAT[] = {'S','P','8','0','0','_','5','
 static const WCHAR BCRYPT_KDF_RAW_SECRET[] = {'T','R','U','N','C','A','T','E',0};
 
 static const WCHAR BCRYPT_DH_PARAMETERS[] = {'D','H','P','a','r','a','m','e','t','e','r','s',0};
+static const WCHAR BCRYPT_MESSAGE_BLOCK_LENGTH[] = {'M','e','s','s','a','g','e','B','l','o','c','k','L','e','n','g','t','h',0};
 #endif
 
 #define BCRYPT_ECDSA_PUBLIC_P256_MAGIC  0x31534345
diff --git a/include/cfapi.h b/include/cfapi.h
new file mode 100644
index 000000000000..968acc4ac7c1
--- /dev/null
+++ b/include/cfapi.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2026 Louis Lenders
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef CFAPI_H
+#define CFAPI_H
+
+typedef enum CF_PLACEHOLDER_INFO_CLASS
+{
+  CF_PLACEHOLDER_INFO_BASIC    = 0,
+  CF_PLACEHOLDER_INFO_STANDARD = 1
+} CF_PLACEHOLDER_INFO_CLASS;
+
+HRESULT WINAPI CfGetPlaceholderInfo(HANDLE h, CF_PLACEHOLDER_INFO_CLASS info, void *buf, DWORD len, DWORD *retlen);
+
+#endif  /* CFAPI_H */
diff --git a/include/ddk/ntifs.h b/include/ddk/ntifs.h
index 965715738d74..9b900df2a888 100644
--- a/include/ddk/ntifs.h
+++ b/include/ddk/ntifs.h
@@ -207,6 +207,7 @@ NTSTATUS WINAPI FsRtlGetFileSize(PFILE_OBJECT, PLARGE_INTEGER);
 BOOLEAN WINAPI FsRtlIsNameInExpression(PUNICODE_STRING, PUNICODE_STRING, BOOLEAN, PWCH);
 DEVICE_OBJECT * WINAPI IoGetAttachedDevice(DEVICE_OBJECT*);
 PEPROCESS WINAPI IoGetRequestorProcess(IRP*);
+PEPROCESS WINAPI IoThreadToProcess(PETHREAD);
 void WINAPI KeStackAttachProcess(KPROCESS*,KAPC_STATE*);
 void WINAPI KeUnstackDetachProcess(KAPC_STATE*);
 NTSTATUS WINAPI ObOpenObjectByPointer(void*,ULONG,PACCESS_STATE,ACCESS_MASK,POBJECT_TYPE,KPROCESSOR_MODE,HANDLE*);
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 406870d8f067..d450db178034 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -477,6 +477,26 @@ typedef struct _DEVICE_OBJECT {
 } DEVICE_OBJECT;
 typedef struct _DEVICE_OBJECT *PDEVICE_OBJECT;
 
+struct _DEVICE_OBJECT_POWER_EXTENSION;
+typedef struct _DEVOBJ_EXTENSION {
+  CSHORT Type;
+  USHORT Size;
+  PDEVICE_OBJECT DeviceObject;
+  ULONG PowerFlags;
+  struct _DEVICE_OBJECT_POWER_EXTENSION *Dope;
+  ULONG ExtensionFlags;
+  PVOID DeviceNode;
+  PDEVICE_OBJECT AttachedTo;
+  LONG StartIoCount;
+  LONG StartIoKey;
+  ULONG StartIoFlags;
+  PVPB Vpb;
+  PVOID DependencyNode;
+  PVOID InterruptContext;
+  LONG InterruptCount;
+  PVOID VerifierContext;
+} DEVOBJ_EXTENSION, *PDEVOBJ_EXTENSION;
+
 typedef struct _DEVICE_RELATIONS {
   ULONG Count;
   PDEVICE_OBJECT Objects[1];
@@ -909,7 +929,10 @@ typedef enum {
   DevicePropertyAddress,
   DevicePropertyUINumber,
   DevicePropertyInstallState,
-  DevicePropertyRemovalPolicy
+  DevicePropertyRemovalPolicy,
+  DevicePropertyResourceRequirements,
+  DevicePropertyAllocatedResources,
+  DevicePropertyContainerID,
 } DEVICE_REGISTRY_PROPERTY;
 
 typedef enum _DEVICE_TEXT_TYPE {
diff --git a/include/pdh.h b/include/pdh.h
index 5ef76b07abe4..01b96c2de815 100644
--- a/include/pdh.h
+++ b/include/pdh.h
@@ -189,6 +189,21 @@ typedef struct _PDH_COUNTER_INFO_W
     DWORD DataBuffer[1];
 } PDH_COUNTER_INFO_W, *PPDH_COUNTER_INFO_W;
 
+typedef struct _PDH_FMT_COUNTERVALUE_ITEM_A
+{
+    LPSTR szName;
+    PDH_FMT_COUNTERVALUE FmtValue;
+} PDH_FMT_COUNTERVALUE_ITEM_A,*PPDH_FMT_COUNTERVALUE_ITEM_A;
+
+typedef struct _PDH_FMT_COUNTERVALUE_ITEM_W
+{
+    LPWSTR szName;
+    PDH_FMT_COUNTERVALUE FmtValue;
+} PDH_FMT_COUNTERVALUE_ITEM_W,*PPDH_FMT_COUNTERVALUE_ITEM_W;
+
+DECL_PDH_TYPE_AW(PDH_FMT_COUNTERVALUE_ITEM)
+DECL_PDH_TYPE_AW(PPDH_FMT_COUNTERVALUE_ITEM)
+
 typedef struct _PDH_RAW_COUNTER_ITEM_A
 {
     LPSTR szName;
@@ -230,6 +245,9 @@ PDH_STATUS WINAPI PdhGetCounterInfoW(PDH_HCOUNTER, BOOLEAN, LPDWORD, PPDH_COUNTE
 #define    PdhGetCounterInfo WINELIB_NAME_AW(PdhGetCounterInfo)
 PDH_STATUS WINAPI PdhGetCounterTimeBase(PDH_HCOUNTER, LONGLONG *);
 PDH_STATUS WINAPI PdhGetDllVersion(LPDWORD);
+PDH_STATUS WINAPI PdhGetFormattedCounterArrayA(PDH_HCOUNTER, DWORD, LPDWORD, LPDWORD, PPDH_FMT_COUNTERVALUE_ITEM_A);
+PDH_STATUS WINAPI PdhGetFormattedCounterArrayW(PDH_HCOUNTER, DWORD, LPDWORD, LPDWORD, PPDH_FMT_COUNTERVALUE_ITEM_W);
+#define    PdhGetFormattedCounterArray WINELIB_NAME_AW(PdhGetFormattedCounterArray)
 PDH_STATUS WINAPI PdhGetFormattedCounterValue(PDH_HCOUNTER, DWORD, LPDWORD, PPDH_FMT_COUNTERVALUE);
 PDH_STATUS WINAPI PdhGetRawCounterArrayA(PDH_HCOUNTER, LPDWORD, LPDWORD, PPDH_RAW_COUNTER_ITEM_A);
 PDH_STATUS WINAPI PdhGetRawCounterArrayW(PDH_HCOUNTER, LPDWORD, LPDWORD, PPDH_RAW_COUNTER_ITEM_W);
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index efc1cbe76c84..b667504c34ab 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -6221,6 +6221,22 @@ struct d3dkmt_mutex_release_reply
 };
 
 
+
+struct alpc_create_port_request
+{
+    struct request_header __header;
+    unsigned int        flags;
+    mem_size_t          max_msg_len;
+    /* VARARG(obj_attr,object_attributes); */
+};
+struct alpc_create_port_reply
+{
+    struct reply_header __header;
+    obj_handle_t        handle;
+    char __pad_12[4];
+};
+
+
 enum request
 {
     REQ_new_process,
@@ -6530,6 +6546,7 @@ enum request
     REQ_d3dkmt_object_open_name,
     REQ_d3dkmt_mutex_acquire,
     REQ_d3dkmt_mutex_release,
+    REQ_alpc_create_port,
     REQ_NB_REQUESTS
 };
 
@@ -6844,6 +6861,7 @@ union generic_request
     struct d3dkmt_object_open_name_request d3dkmt_object_open_name_request;
     struct d3dkmt_mutex_acquire_request d3dkmt_mutex_acquire_request;
     struct d3dkmt_mutex_release_request d3dkmt_mutex_release_request;
+    struct alpc_create_port_request alpc_create_port_request;
 };
 union generic_reply
 {
@@ -7156,8 +7174,9 @@ union generic_reply
     struct d3dkmt_object_open_name_reply d3dkmt_object_open_name_reply;
     struct d3dkmt_mutex_acquire_reply d3dkmt_mutex_acquire_reply;
     struct d3dkmt_mutex_release_reply d3dkmt_mutex_release_reply;
+    struct alpc_create_port_reply alpc_create_port_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 956
+#define SERVER_PROTOCOL_VERSION 957
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/wine/strmbase.h b/include/wine/strmbase.h
index 978d1c671602..a8b852769dcd 100644
--- a/include/wine/strmbase.h
+++ b/include/wine/strmbase.h
@@ -125,6 +125,7 @@ struct strmbase_sink_ops
     HRESULT (*sink_begin_flush)(struct strmbase_sink *pin);
     HRESULT (*sink_end_flush)(struct strmbase_sink *pin);
     HRESULT (*sink_new_segment)(struct strmbase_sink *pin, REFERENCE_TIME start, REFERENCE_TIME stop, double rate);
+    HRESULT (*sink_receive_can_block)(struct strmbase_sink *pin);
 };
 
 /* Base Pin */
diff --git a/include/wine/vulkan.h b/include/wine/vulkan.h
index 5ab758f03388..9b00aeeec049 100644
--- a/include/wine/vulkan.h
+++ b/include/wine/vulkan.h
@@ -120,7 +120,7 @@ struct OH_NativeBuffer;
     #endif
 #endif
 #define VK_FALSE 0
-#define VK_HEADER_VERSION 353
+#define VK_HEADER_VERSION 357
 #define VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION(0, 1, 4, VK_HEADER_VERSION)
 #define VK_LOD_CLAMP_NONE 1000.0F
 #define VK_LUID_SIZE 8
@@ -139,6 +139,7 @@ struct OH_NativeBuffer;
 #define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
 #define VK_MAX_PIPELINE_BINARY_KEY_SIZE_KHR 32
 #define VK_MAX_SHADER_MODULE_IDENTIFIER_SIZE_EXT 32
+#define VK_MAX_TENSOR_CREATE_INFO_ROLLING_BACKING_WRAP_COUNT_ARM 4
 #define VK_MAX_VIDEO_AV1_REFERENCES_PER_FRAME_KHR 7
 #define VK_MAX_VIDEO_VP9_REFERENCES_PER_FRAME_KHR 3
 #ifndef VK_DEFINE_NON_DISPATCHABLE_HANDLE
@@ -318,6 +319,8 @@ typedef void* VkRemoteAddressNV;
 #define VK_ARM_SHADER_INSTRUMENTATION_SPEC_VERSION 1
 #define VK_ARM_TENSORS_EXTENSION_NAME "VK_ARM_tensors"
 #define VK_ARM_TENSORS_SPEC_VERSION 2
+#define VK_ARM_TENSOR_CONTROLS_EXTENSION_NAME "VK_ARM_tensor_controls"
+#define VK_ARM_TENSOR_CONTROLS_SPEC_VERSION 1
 #define VK_EXT_4444_FORMATS_EXTENSION_NAME "VK_EXT_4444_formats"
 #define VK_EXT_4444_FORMATS_SPEC_VERSION 1
 #define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode"
@@ -540,6 +543,8 @@ typedef void* VkRemoteAddressNV;
 #define VK_EXT_SHADER_MODULE_IDENTIFIER_SPEC_VERSION 1
 #define VK_EXT_SHADER_OBJECT_EXTENSION_NAME "VK_EXT_shader_object"
 #define VK_EXT_SHADER_OBJECT_SPEC_VERSION 1
+#define VK_EXT_SHADER_OCP_MICROSCALING_TYPES_EXTENSION_NAME "VK_EXT_shader_ocp_microscaling_types"
+#define VK_EXT_SHADER_OCP_MICROSCALING_TYPES_SPEC_VERSION 1
 #define VK_EXT_SHADER_REPLICATED_COMPOSITES_EXTENSION_NAME "VK_EXT_shader_replicated_composites"
 #define VK_EXT_SHADER_REPLICATED_COMPOSITES_SPEC_VERSION 1
 #define VK_EXT_SHADER_SPLIT_BARRIER_EXTENSION_NAME "VK_EXT_shader_split_barrier"
@@ -614,6 +619,8 @@ typedef void* VkRemoteAddressNV;
 #define VK_HUAWEI_SUBPASS_SHADING_SPEC_VERSION 3
 #define VK_IMG_FILTER_CUBIC_EXTENSION_NAME "VK_IMG_filter_cubic"
 #define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1
+#define VK_IMG_FILTER_LINEAR_2D_EXTENSION_NAME "VK_IMG_filter_linear_2d"
+#define VK_IMG_FILTER_LINEAR_2D_SPEC_VERSION 1
 #define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
 #define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
 #define VK_IMG_RELAXED_LINE_RASTERIZATION_EXTENSION_NAME "VK_IMG_relaxed_line_rasterization"
@@ -981,7 +988,7 @@ typedef void* VkRemoteAddressNV;
 #define VK_NV_LOW_LATENCY_2_EXTENSION_NAME "VK_NV_low_latency2"
 #define VK_NV_LOW_LATENCY_2_SPEC_VERSION 2
 #define VK_NV_LOW_LATENCY_EXTENSION_NAME "VK_NV_low_latency"
-#define VK_NV_LOW_LATENCY_SPEC_VERSION 1
+#define VK_NV_LOW_LATENCY_SPEC_VERSION 2
 #define VK_NV_MEMORY_DECOMPRESSION_EXTENSION_NAME "VK_NV_memory_decompression"
 #define VK_NV_MEMORY_DECOMPRESSION_SPEC_VERSION 1
 #define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader"
@@ -1696,6 +1703,8 @@ typedef enum StdVideoH264ProfileIdc
     STD_VIDEO_H264_PROFILE_IDC_BASELINE = 66,
     STD_VIDEO_H264_PROFILE_IDC_MAIN = 77,
     STD_VIDEO_H264_PROFILE_IDC_HIGH = 100,
+    STD_VIDEO_H264_PROFILE_IDC_HIGH_10 = 110,
+    STD_VIDEO_H264_PROFILE_IDC_HIGH_422 = 122,
     STD_VIDEO_H264_PROFILE_IDC_HIGH_444_PREDICTIVE = 244,
     STD_VIDEO_H264_PROFILE_IDC_INVALID = 0x7fffffff,
 } StdVideoH264ProfileIdc;
@@ -2552,6 +2561,11 @@ typedef enum VkComponentTypeKHR
     VK_COMPONENT_TYPE_UINT8_PACKED_NV = 1000491001,
     VK_COMPONENT_TYPE_FLOAT8_E4M3_EXT = 1000491002,
     VK_COMPONENT_TYPE_FLOAT8_E5M2_EXT = 1000491003,
+    VK_COMPONENT_TYPE_FLOAT6_E2M3_EXT = 1000672000,
+    VK_COMPONENT_TYPE_FLOAT6_E3M2_EXT = 1000672001,
+    VK_COMPONENT_TYPE_FLOAT4_E2M1_EXT = 1000672002,
+    VK_COMPONENT_TYPE_FLOAT8_UNSIGNED_E8M0_EXT = 1000672003,
+    VK_COMPONENT_TYPE_MXINT8_EXT = 1000672004,
     VK_COMPONENT_TYPE_KHR_MAX_ENUM = 0x7fffffff,
     VK_COMPONENT_TYPE_FLOAT16_NV = VK_COMPONENT_TYPE_FLOAT16_KHR,
     VK_COMPONENT_TYPE_FLOAT32_NV = VK_COMPONENT_TYPE_FLOAT32_KHR,
@@ -3090,6 +3104,7 @@ typedef enum VkDriverId
     VK_DRIVER_ID_VULKAN_SC_EMULATION_ON_VULKAN = 27,
     VK_DRIVER_ID_MESA_KOSMICKRISP = 28,
     VK_DRIVER_ID_MESA_GFXSTREAM = 29,
+    VK_DRIVER_ID_APE_SOFT = 30,
     VK_DRIVER_ID_MAX_ENUM = 0x7fffffff,
     VK_DRIVER_ID_AMD_PROPRIETARY_KHR = VK_DRIVER_ID_AMD_PROPRIETARY,
     VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = VK_DRIVER_ID_AMD_OPEN_SOURCE,
@@ -3801,6 +3816,7 @@ static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_VECTOR_BI
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_OPTICAL_FLOW_COST_BIT_NV = 0x40000000000ull;
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TENSOR_IMAGE_ALIASING_BIT_ARM = 0x80000000000ull;
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_SXD_BIT_QCOM = 0x100000000000ull;
+static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_SAMPLED_IMAGE_FILTER_LINEAR_2D_BIT_IMG = 0x200000000000ull;
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT = 0x400000000000ull;
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT = 0x400000000000ull;
 static const VkFormatFeatureFlagBits2 VK_FORMAT_FEATURE_2_TENSOR_DATA_GRAPH_BIT_ARM = 0x1000000000000ull;
@@ -6836,6 +6852,8 @@ typedef enum VkStructureType
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR = 1000562004,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV = 1000563000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_REPLICATED_COMPOSITES_FEATURES_EXT = 1000564000,
+    VK_STRUCTURE_TYPE_TENSOR_EXPLICIT_TILING_FORMAT_PROPERTIES_ARM = 1000565000,
+    VK_STRUCTURE_TYPE_TENSOR_ROLLING_BACKING_CREATE_INFO_ARM = 1000565001,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT8_FEATURES_EXT = 1000567000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_VALIDATION_FEATURES_NV = 1000568000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_FEATURES_NV = 1000569000,
@@ -6957,6 +6975,7 @@ typedef enum VkStructureType
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_FLAGS_FEATURES_KHR = 1000668004,
     VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_2_CREATE_INFO_KHR = 1000668005,
     VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_2_KHR = 1000668006,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OCP_MICROSCALING_TYPES_FEATURES_EXT = 1000672000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MIXED_FLOAT_DOT_PRODUCT_FEATURES_VALVE = 1000673000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_THROTTLE_HINT_FEATURES_SEC = 1000674000,
     VK_STRUCTURE_TYPE_THROTTLE_HINT_SUBMIT_INFO_SEC = 1000674001,
@@ -7340,6 +7359,11 @@ typedef enum VkTensorTilingARM
 {
     VK_TENSOR_TILING_OPTIMAL_ARM = 0,
     VK_TENSOR_TILING_LINEAR_ARM = 1,
+    VK_TENSOR_TILING_BRICK_16_WIDE_ARM = 1000565000,
+    VK_TENSOR_TILING_BRICK_8_WIDE_ARM = 1000565001,
+    VK_TENSOR_TILING_BRICK_4_WIDE_ARM = 1000565002,
+    VK_TENSOR_TILING_BLOCK_U_INTERLEAVED_ARM = 1000565003,
+    VK_TENSOR_TILING_BLOCK_U_INTERLEAVED_64K_ARM = 1000565004,
     VK_TENSOR_TILING_ARM_MAX_ENUM = 0x7fffffff,
 } VkTensorTilingARM;
 
@@ -7460,6 +7484,7 @@ typedef enum VkVendorId
     VK_VENDOR_ID_MESA = 0x00010005,
     VK_VENDOR_ID_POCL = 0x00010006,
     VK_VENDOR_ID_MOBILEYE = 0x00010007,
+    VK_VENDOR_ID_APE = 0x00010008,
     VK_VENDOR_ID_MAX_ENUM = 0x7fffffff,
 } VkVendorId;
 
@@ -17710,6 +17735,16 @@ typedef struct VkPhysicalDeviceShaderMultipleWaitQueuesPropertiesQCOM
     uint32_t maxShaderWaitQueues;
 } VkPhysicalDeviceShaderMultipleWaitQueuesPropertiesQCOM;
 
+typedef struct VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT
+{
+    VkStructureType sType;
+    void *pNext;
+    VkBool32 shaderFloat4;
+    VkBool32 shaderFloat6;
+    VkBool32 shaderFloat8UnsignedE8M0;
+    VkBool32 shaderMXInt8;
+} VkPhysicalDeviceShaderOCPMicroscalingTypesFeaturesEXT;
+
 typedef struct VkPhysicalDeviceShaderObjectFeaturesEXT
 {
     VkStructureType sType;
@@ -20145,6 +20180,17 @@ typedef struct VkTensorDependencyInfoARM
     const VkTensorMemoryBarrierARM *pTensorMemoryBarriers;
 } VkTensorDependencyInfoARM;
 
+typedef struct VkTensorExplicitTilingFormatPropertiesARM
+{
+    VkStructureType sType;
+    void *pNext;
+    VkFormatFeatureFlags2 WINE_VK_ALIGN(8) brick16TilingTensorFeatures;
+    VkFormatFeatureFlags2 WINE_VK_ALIGN(8) brick8TilingTensorFeatures;
+    VkFormatFeatureFlags2 WINE_VK_ALIGN(8) brick4TilingTensorFeatures;
+    VkFormatFeatureFlags2 WINE_VK_ALIGN(8) blockUTilingTensorFeatures;
+    VkFormatFeatureFlags2 WINE_VK_ALIGN(8) blockU64kTilingTensorFeatures;
+} VkTensorExplicitTilingFormatPropertiesARM;
+
 typedef struct VkTensorFormatPropertiesARM
 {
     VkStructureType sType;
@@ -20160,6 +20206,13 @@ typedef struct VkTensorMemoryRequirementsInfoARM
     VkTensorARM WINE_VK_ALIGN(8) tensor;
 } VkTensorMemoryRequirementsInfoARM;
 
+typedef struct VkTensorRollingBackingCreateInfoARM
+{
+    VkStructureType sType;
+    const void *pNext;
+    uint32_t wraps[VK_MAX_TENSOR_CREATE_INFO_ROLLING_BACKING_WRAP_COUNT_ARM];
+} VkTensorRollingBackingCreateInfoARM;
+
 typedef struct VkTensorViewCaptureDescriptorDataInfoARM
 {
     VkStructureType sType;
@@ -21670,6 +21723,7 @@ typedef uint64_t (VKAPI_PTR *PFN_vkGetImageViewHandle64NVX)(VkDevice device, con
 typedef uint32_t (VKAPI_PTR *PFN_vkGetImageViewHandleNVX)(VkDevice device, const VkImageViewHandleInfoNVX *pInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkGetImageViewOpaqueCaptureDescriptorDataEXT)(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT *pInfo, void *pData);
 typedef PFN_vkVoidFunction (VKAPI_PTR *PFN_vkGetInstanceProcAddr)(VkInstance instance, const char *pName);
+typedef void (VKAPI_PTR *PFN_vkGetLatencyTimingsLegacyNV)(VkDevice device, void *pTimings);
 typedef void (VKAPI_PTR *PFN_vkGetLatencyTimingsNV)(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV *pLatencyMarkerInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdKHR)(VkDevice device, const VkMemoryGetFdInfoKHR *pGetFdInfo, int *pFd);
 typedef VkResult (VKAPI_PTR *PFN_vkGetMemoryFdPropertiesKHR)(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR *pMemoryFdProperties);
@@ -21772,6 +21826,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInfoAMD)(VkDevice device, VkPipeline
 typedef VkResult (VKAPI_PTR *PFN_vkGetShaderInstrumentationValuesARM)(VkDevice device, VkShaderInstrumentationARM instrumentation, uint32_t *pMetricBlockCount, void *pMetricValues, VkShaderInstrumentationValuesFlagsARM flags);
 typedef void (VKAPI_PTR *PFN_vkGetShaderModuleCreateInfoIdentifierEXT)(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, VkShaderModuleIdentifierEXT *pIdentifier);
 typedef void (VKAPI_PTR *PFN_vkGetShaderModuleIdentifierEXT)(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT *pIdentifier);
+typedef void (VKAPI_PTR *PFN_vkGetSleepStatusLegacyNV)(VkDevice device, VkBool32 *pLowLatencyMode);
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainImagesKHR)(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages);
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainTimeDomainPropertiesEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties, uint64_t *pTimeDomainsCounter);
 typedef VkResult (VKAPI_PTR *PFN_vkGetSwapchainTimingPropertiesEXT)(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties, uint64_t *pSwapchainTimingPropertiesCounter);
@@ -21787,6 +21842,7 @@ typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreFdKHR)(VkDevice device, const
 typedef VkResult (VKAPI_PTR *PFN_vkImportSemaphoreWin32HandleKHR)(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkInitializePerformanceApiINTEL)(VkDevice device, const VkInitializePerformanceApiInfoINTEL *pInitializeInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkInvalidateMappedMemoryRanges)(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges);
+typedef void (VKAPI_PTR *PFN_vkLatencySleepLegacyNV)(VkDevice device, VkSemaphore signalSemaphore, uint64_t value);
 typedef VkResult (VKAPI_PTR *PFN_vkLatencySleepNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV *pSleepInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkMapMemory)(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData);
 typedef VkResult (VKAPI_PTR *PFN_vkMapMemory2)(VkDevice device, const VkMemoryMapInfo *pMemoryMapInfo, void **ppData);
@@ -21797,6 +21853,7 @@ typedef void (VKAPI_PTR *PFN_vkQueueBeginDebugUtilsLabelEXT)(VkQueue queue, cons
 typedef VkResult (VKAPI_PTR *PFN_vkQueueBindSparse)(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence);
 typedef void (VKAPI_PTR *PFN_vkQueueEndDebugUtilsLabelEXT)(VkQueue queue);
 typedef void (VKAPI_PTR *PFN_vkQueueInsertDebugUtilsLabelEXT)(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo);
+typedef void (VKAPI_PTR *PFN_vkQueueNotifyOutOfBandLegacyNV)(VkQueue queue, uint32_t queueType);
 typedef void (VKAPI_PTR *PFN_vkQueueNotifyOutOfBandNV)(VkQueue queue, const VkOutOfBandQueueTypeInfoNV *pQueueTypeInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkQueuePresentKHR)(VkQueue queue, const VkPresentInfoKHR *pPresentInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkQueueSetPerfHintQCOM)(VkQueue queue, const VkPerfHintInfoQCOM *pPerfHintInfo);
@@ -21825,11 +21882,14 @@ typedef void (VKAPI_PTR *PFN_vkSetDeviceMemoryPriorityEXT)(VkDevice device, VkDe
 typedef VkResult (VKAPI_PTR *PFN_vkSetEvent)(VkDevice device, VkEvent event);
 typedef VkResult (VKAPI_PTR *PFN_vkSetGpaDeviceClockModeAMD)(VkDevice device, VkGpaDeviceClockModeInfoAMD *pInfo);
 typedef void (VKAPI_PTR *PFN_vkSetHdrMetadataEXT)(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR *pSwapchains, const VkHdrMetadataEXT *pMetadata);
+typedef void (VKAPI_PTR *PFN_vkSetLatencyMarkerLegacyNV)(VkDevice device, uint64_t frameID, uint32_t marker);
 typedef void (VKAPI_PTR *PFN_vkSetLatencyMarkerNV)(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV *pLatencyMarkerInfo);
+typedef void (VKAPI_PTR *PFN_vkSetLatencySleepModeLegacyNV)(VkDevice device, VkBool32 lowLatencyMode, VkBool32 lowLatencyBoost, uint32_t minimumIntervalUs);
 typedef VkResult (VKAPI_PTR *PFN_vkSetLatencySleepModeNV)(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV *pSleepModeInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateData)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data);
 typedef VkResult (VKAPI_PTR *PFN_vkSetPrivateDataEXT)(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data);
 typedef VkResult (VKAPI_PTR *PFN_vkSetSwapchainPresentTimingQueueSizeEXT)(VkDevice device, VkSwapchainKHR swapchain, uint32_t size);
+typedef void (VKAPI_PTR *PFN_vkShutdownLatencyDeviceLegacyNV)(VkDevice device);
 typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphore)(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkSignalSemaphoreKHR)(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo);
 typedef void (VKAPI_PTR *PFN_vkSubmitDebugUtilsMessageEXT)(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
@@ -22426,6 +22486,7 @@ uint64_t VKAPI_CALL vkGetImageViewHandle64NVX(VkDevice device, const VkImageView
 uint32_t VKAPI_CALL vkGetImageViewHandleNVX(VkDevice device, const VkImageViewHandleInfoNVX *pInfo);
 VkResult VKAPI_CALL vkGetImageViewOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT *pInfo, void *pData);
 PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance, const char *pName);
+void VKAPI_CALL vkGetLatencyTimingsLegacyNV(VkDevice device, void *pTimings);
 void VKAPI_CALL vkGetLatencyTimingsNV(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV *pLatencyMarkerInfo);
 VkResult VKAPI_CALL vkGetMemoryFdKHR(VkDevice device, const VkMemoryGetFdInfoKHR *pGetFdInfo, int *pFd);
 VkResult VKAPI_CALL vkGetMemoryFdPropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, int fd, VkMemoryFdPropertiesKHR *pMemoryFdProperties);
@@ -22528,6 +22589,7 @@ VkResult VKAPI_CALL vkGetShaderInfoAMD(VkDevice device, VkPipeline pipeline, VkS
 VkResult VKAPI_CALL vkGetShaderInstrumentationValuesARM(VkDevice device, VkShaderInstrumentationARM instrumentation, uint32_t *pMetricBlockCount, void *pMetricValues, VkShaderInstrumentationValuesFlagsARM flags);
 void VKAPI_CALL vkGetShaderModuleCreateInfoIdentifierEXT(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, VkShaderModuleIdentifierEXT *pIdentifier);
 void VKAPI_CALL vkGetShaderModuleIdentifierEXT(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT *pIdentifier);
+void VKAPI_CALL vkGetSleepStatusLegacyNV(VkDevice device, VkBool32 *pLowLatencyMode);
 VkResult VKAPI_CALL vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages);
 VkResult VKAPI_CALL vkGetSwapchainTimeDomainPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties, uint64_t *pTimeDomainsCounter);
 VkResult VKAPI_CALL vkGetSwapchainTimingPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties, uint64_t *pSwapchainTimingPropertiesCounter);
@@ -22543,6 +22605,7 @@ VkResult VKAPI_CALL vkImportSemaphoreFdKHR(VkDevice device, const VkImportSemaph
 VkResult VKAPI_CALL vkImportSemaphoreWin32HandleKHR(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo);
 VkResult VKAPI_CALL vkInitializePerformanceApiINTEL(VkDevice device, const VkInitializePerformanceApiInfoINTEL *pInitializeInfo);
 VkResult VKAPI_CALL vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges);
+void VKAPI_CALL vkLatencySleepLegacyNV(VkDevice device, VkSemaphore signalSemaphore, uint64_t value);
 VkResult VKAPI_CALL vkLatencySleepNV(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV *pSleepInfo);
 VkResult VKAPI_CALL vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData);
 VkResult VKAPI_CALL vkMapMemory2(VkDevice device, const VkMemoryMapInfo *pMemoryMapInfo, void **ppData);
@@ -22553,6 +22616,7 @@ void VKAPI_CALL vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtils
 VkResult VKAPI_CALL vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence);
 void VKAPI_CALL vkQueueEndDebugUtilsLabelEXT(VkQueue queue);
 void VKAPI_CALL vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo);
+void VKAPI_CALL vkQueueNotifyOutOfBandLegacyNV(VkQueue queue, uint32_t queueType);
 void VKAPI_CALL vkQueueNotifyOutOfBandNV(VkQueue queue, const VkOutOfBandQueueTypeInfoNV *pQueueTypeInfo);
 VkResult VKAPI_CALL vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo);
 VkResult VKAPI_CALL vkQueueSetPerfHintQCOM(VkQueue queue, const VkPerfHintInfoQCOM *pPerfHintInfo);
@@ -22581,11 +22645,14 @@ void VKAPI_CALL vkSetDeviceMemoryPriorityEXT(VkDevice device, VkDeviceMemory mem
 VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event);
 VkResult VKAPI_CALL vkSetGpaDeviceClockModeAMD(VkDevice device, VkGpaDeviceClockModeInfoAMD *pInfo);
 void VKAPI_CALL vkSetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR *pSwapchains, const VkHdrMetadataEXT *pMetadata);
+void VKAPI_CALL vkSetLatencyMarkerLegacyNV(VkDevice device, uint64_t frameID, uint32_t marker);
 void VKAPI_CALL vkSetLatencyMarkerNV(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV *pLatencyMarkerInfo);
+void VKAPI_CALL vkSetLatencySleepModeLegacyNV(VkDevice device, VkBool32 lowLatencyMode, VkBool32 lowLatencyBoost, uint32_t minimumIntervalUs);
 VkResult VKAPI_CALL vkSetLatencySleepModeNV(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV *pSleepModeInfo);
 VkResult VKAPI_CALL vkSetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data);
 VkResult VKAPI_CALL vkSetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data);
 VkResult VKAPI_CALL vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKHR swapchain, uint32_t size);
+void VKAPI_CALL vkShutdownLatencyDeviceLegacyNV(VkDevice device);
 VkResult VKAPI_CALL vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo);
 VkResult VKAPI_CALL vkSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo);
 void VKAPI_CALL vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData);
@@ -23155,6 +23222,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_FUNC(vkGetImageViewHandle64NVX) \
     USE_VK_FUNC(vkGetImageViewHandleNVX) \
     USE_VK_FUNC(vkGetImageViewOpaqueCaptureDescriptorDataEXT) \
+    USE_VK_FUNC(vkGetLatencyTimingsLegacyNV) \
     USE_VK_FUNC(vkGetLatencyTimingsNV) \
     USE_VK_FUNC(vkGetMemoryFdKHR) \
     USE_VK_FUNC(vkGetMemoryFdPropertiesKHR) \
@@ -23198,6 +23266,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_FUNC(vkGetShaderInstrumentationValuesARM) \
     USE_VK_FUNC(vkGetShaderModuleCreateInfoIdentifierEXT) \
     USE_VK_FUNC(vkGetShaderModuleIdentifierEXT) \
+    USE_VK_FUNC(vkGetSleepStatusLegacyNV) \
     USE_VK_FUNC(vkGetSwapchainImagesKHR) \
     USE_VK_FUNC(vkGetSwapchainTimeDomainPropertiesEXT) \
     USE_VK_FUNC(vkGetSwapchainTimingPropertiesEXT) \
@@ -23213,6 +23282,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_FUNC(vkImportSemaphoreWin32HandleKHR) \
     USE_VK_FUNC(vkInitializePerformanceApiINTEL) \
     USE_VK_FUNC(vkInvalidateMappedMemoryRanges) \
+    USE_VK_FUNC(vkLatencySleepLegacyNV) \
     USE_VK_FUNC(vkLatencySleepNV) \
     USE_VK_FUNC(vkMapMemory) \
     USE_VK_FUNC(vkMapMemory2) \
@@ -23223,6 +23293,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_FUNC(vkQueueBindSparse) \
     USE_VK_FUNC(vkQueueEndDebugUtilsLabelEXT) \
     USE_VK_FUNC(vkQueueInsertDebugUtilsLabelEXT) \
+    USE_VK_FUNC(vkQueueNotifyOutOfBandLegacyNV) \
     USE_VK_FUNC(vkQueueNotifyOutOfBandNV) \
     USE_VK_FUNC(vkQueuePresentKHR) \
     USE_VK_FUNC(vkQueueSetPerfHintQCOM) \
@@ -23251,11 +23322,14 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_FUNC(vkSetEvent) \
     USE_VK_FUNC(vkSetGpaDeviceClockModeAMD) \
     USE_VK_FUNC(vkSetHdrMetadataEXT) \
+    USE_VK_FUNC(vkSetLatencyMarkerLegacyNV) \
     USE_VK_FUNC(vkSetLatencyMarkerNV) \
+    USE_VK_FUNC(vkSetLatencySleepModeLegacyNV) \
     USE_VK_FUNC(vkSetLatencySleepModeNV) \
     USE_VK_FUNC(vkSetPrivateData) \
     USE_VK_FUNC(vkSetPrivateDataEXT) \
     USE_VK_FUNC(vkSetSwapchainPresentTimingQueueSizeEXT) \
+    USE_VK_FUNC(vkShutdownLatencyDeviceLegacyNV) \
     USE_VK_FUNC(vkSignalSemaphore) \
     USE_VK_FUNC(vkSignalSemaphoreKHR) \
     USE_VK_FUNC(vkTransitionImageLayout) \
@@ -23320,6 +23394,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_EXT(VK_ARM_shader_core_builtins) \
     USE_VK_EXT(VK_ARM_shader_core_properties) \
     USE_VK_EXT(VK_ARM_shader_instrumentation) \
+    USE_VK_EXT(VK_ARM_tensor_controls) \
     USE_VK_EXT(VK_ARM_tensors) \
     USE_VK_EXT(VK_EXT_4444_formats) \
     USE_VK_EXT(VK_EXT_astc_decode_mode) \
@@ -23423,6 +23498,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_EXT(VK_EXT_shader_long_vector) \
     USE_VK_EXT(VK_EXT_shader_module_identifier) \
     USE_VK_EXT(VK_EXT_shader_object) \
+    USE_VK_EXT(VK_EXT_shader_ocp_microscaling_types) \
     USE_VK_EXT(VK_EXT_shader_replicated_composites) \
     USE_VK_EXT(VK_EXT_shader_split_barrier) \
     USE_VK_EXT(VK_EXT_shader_stencil_export) \
@@ -23455,6 +23531,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_EXT(VK_HUAWEI_invocation_mask) \
     USE_VK_EXT(VK_HUAWEI_subpass_shading) \
     USE_VK_EXT(VK_IMG_filter_cubic) \
+    USE_VK_EXT(VK_IMG_filter_linear_2d) \
     USE_VK_EXT(VK_IMG_format_pvrtc) \
     USE_VK_EXT(VK_IMG_relaxed_line_rasterization) \
     USE_VK_EXT(VK_INTEL_performance_query) \
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 002bab2b9c64..49c6672fa3f8 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2922,7 +2922,8 @@ HRESULT __cdecl wined3d_swapchain_present(struct wined3d_swapchain *swapchain, c
         const RECT *dst_rect, HWND dst_window_override, unsigned int swap_interval, uint32_t flags);
 HRESULT __cdecl wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count,
         unsigned int width, unsigned int height, enum wined3d_format_id format_id,
-        enum wined3d_multisample_type multisample_type, unsigned int multisample_quality);
+        enum wined3d_multisample_type multisample_type, unsigned int multisample_quality,
+        unsigned int flags);
 HRESULT __cdecl wined3d_swapchain_set_gamma_ramp(const struct wined3d_swapchain *swapchain,
         uint32_t flags, const struct wined3d_gamma_ramp *ramp);
 HRESULT __cdecl wined3d_swapchain_set_max_frame_latency(struct wined3d_swapchain *swapchain, unsigned int latency);
diff --git a/include/winnt.h b/include/winnt.h
index 2dc1aaddddea..c8a43b49d944 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -5457,6 +5457,9 @@ typedef enum tagSID_NAME_USE {
 #define MAXIMUM_ALLOWED            0x02000000
 #define ACCESS_SYSTEM_SECURITY     0x01000000
 
+#define ALPC_PORT_QUERY_STATE      0x0001
+#define ALPC_PORT_ALL_ACCESS       (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|ALPC_PORT_QUERY_STATE)
+
 #define EVENT_QUERY_STATE          0x0001
 #define EVENT_MODIFY_STATE         0x0002
 #define EVENT_ALL_ACCESS           (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
diff --git a/libs/strmbase/pin.c b/libs/strmbase/pin.c
index f01541a26a32..f332ef7ef07a 100644
--- a/libs/strmbase/pin.c
+++ b/libs/strmbase/pin.c
@@ -1148,10 +1148,14 @@ static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSa
 static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
 {
     struct strmbase_sink *pin = impl_from_IMemInputPin(iface);
+    HRESULT hr = S_OK;
 
     TRACE("pin %p %s:%s.\n", pin, debugstr_w(pin->pin.filter->name), debugstr_w(pin->pin.name));
 
-    return S_OK;
+    if (pin->pFuncsTable->sink_receive_can_block)
+        hr = pin->pFuncsTable->sink_receive_can_block(pin);
+
+    return hr;
 }
 
 static const IMemInputPinVtbl MemInputPin_Vtbl =
diff --git a/libs/symcrypt/lib/mlkem_primitives.c b/libs/symcrypt/lib/mlkem_primitives.c
index ab8a6e86c82d..786629b3767c 100644
--- a/libs/symcrypt/lib/mlkem_primitives.c
+++ b/libs/symcrypt/lib/mlkem_primitives.c
@@ -244,11 +244,11 @@ cleanup:
 #define VEC128_TYPE_UINT16 __m128i
 
 #define VEC128_LOAD_UINT16( addr )       _mm_loadu_si128( (__m128i*) (addr) )
-#define VEC64_LOAD_UINT16( addr )        _mm_loadu_si64( (PBYTE) (addr) )
+#define VEC64_LOAD_UINT16( addr )        _mm_loadl_epi64( (__m128i const*) (addr) )
 #define VEC32_LOAD_UINT16( addr )        _mm_cvtsi32_si128( SYMCRYPT_LOAD_LSBFIRST32( addr ) )
 
 #define VEC128_STORE_UINT16( addr, vec ) _mm_storeu_si128( (__m128i*) (addr), (vec) )
-#define VEC64_STORE_UINT16( addr, vec )  _mm_storeu_si64( (PBYTE) (addr), (vec) )
+#define VEC64_STORE_UINT16( addr, vec )  _mm_storel_epi64( (__m128i*) (addr), (vec) )
 #define VEC32_STORE_UINT16( addr, vec )  SYMCRYPT_STORE_LSBFIRST32( (addr), _mm_cvtsi128_si32( vec ) )
 
 #define VEC128_SET_UINT16( value )       _mm_set1_epi16( (value) )
diff --git a/libs/symcrypt/lib/sha512.c b/libs/symcrypt/lib/sha512.c
index 0b763c546771..823176bb403d 100644
--- a/libs/symcrypt/lib/sha512.c
+++ b/libs/symcrypt/lib/sha512.c
@@ -1300,12 +1300,6 @@ SymCryptSha512AppendBlocks_ull3(
 #pragma GCC target("ssse3")
 #endif
 
-#if SYMCRYPT_MS_VC
-#ifndef _mm_storeu_si64
-    // Workaround missing intrinsic on some versions of MSVC
-    #define _mm_storeu_si64(p, a) (_mm_storel_epi64((__m128i*)(p), (a)))
-#endif
-#endif
 
 #define XMMADD( _a, _b ) _mm_add_epi64((_a), (_b))
 #define XMMAND( _a, _b ) _mm_and_si128((_a), (_b))
@@ -1313,7 +1307,7 @@ SymCryptSha512AppendBlocks_ull3(
 #define XMMROR( _a, _n ) _mm_xor_si128( _mm_slli_epi64( (_a), 64-(_n)), _mm_srli_epi64( (_a), (_n)) )
 #define XMMSHR( _a, _n ) _mm_srli_epi64((_a), (_n))
 #define XMMXOR( _a, _b ) _mm_xor_si128((_a), (_b))
-#define XMMSTORE_UINT64( _a, _addr ) _mm_storeu_si64((_addr), (_a))
+#define XMMSTORE_UINT64( _a, _addr ) _mm_storel_epi64((__m128i*)(_addr), (_a))
 
 #define XMMMAJ( x, y, z )  XMMOR( XMMAND( XMMOR( (z), (y)), (x)), XMMAND( (z), (y) ) )
 #define XMMCH(  x, y, z )  XMMXOR( XMMAND( XMMXOR( (z), (y) ), (x)), (z))
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 1c9074b75d33..b706feb39c70 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -30,6 +30,8 @@
 
 #include "wcmd.h"
 #include <shellapi.h>
+#include <shlwapi.h>
+#include <strsafe.h>
 #include "winternl.h"
 #include "winioctl.h"
 #include "ddk/ntifs.h"
@@ -3439,6 +3441,10 @@ RETURN_CODE WCMD_type(WCHAR *args)
   int   argno         = 0;
   WCHAR *argN          = args;
   BOOL  writeHeaders  = FALSE;
+  HANDLE hOut;
+  BOOL is_ascii_out;
+  DWORD console_mode;
+  DWORD file_share_access_flags;
 
   if (param1[0] == 0x00) {
     WCMD_output_stderr(WCMD_LoadMessage(WCMD_NOARG));
@@ -3447,33 +3453,139 @@ RETURN_CODE WCMD_type(WCHAR *args)
 
   if (param2[0] != 0x00) writeHeaders = TRUE;
 
-  /* Loop through all args */
   return_code = NO_ERROR;
+  hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+  is_ascii_out = GetConsoleMode(hOut, &console_mode);
+  file_share_access_flags = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+  /* Loop through all args */
   while (argN) {
     WCHAR *thisArg = WCMD_parameter (args, argno++, &argN, FALSE, FALSE);
 
-    HANDLE hIn, hOut;
-    DWORD console_mode;
+    HANDLE hIn;
 
     if (!argN) break;
 
     WINE_TRACE("type: Processing arg '%s'\n", wine_dbgstr_w(thisArg));
-    hIn = CreateFileW(thisArg, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
-            FILE_ATTRIBUTE_NORMAL, NULL);
-    if (hIn == INVALID_HANDLE_VALUE) {
-      WCMD_print_error ();
-      WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), thisArg);
-      return errorlevel = ERROR_INVALID_FUNCTION;
-    }
-    hOut = GetStdHandle(STD_OUTPUT_HANDLE);
 
-    if (writeHeaders) {
-      WCMD_output_stderr(L"\n%1\n\n\n", thisArg);
+    if (wcspbrk(thisArg, L"*?"))
+    {
+        BOOL foundOnlyDirectories = TRUE;
+        WIN32_FIND_DATAW fd;
+        HANDLE hff = INVALID_HANDLE_VALUE;
+        WCHAR *fileNamePart;
+        DWORD till_file_name_part_len;
+        DWORD full_path_len;
+        WCHAR srcpath[MAX_PATH];
+
+        hff = FindFirstFileW(thisArg, &fd);
+
+        if (hff == INVALID_HANDLE_VALUE) {
+          DWORD is_dir_error;
+
+          /* Store GetLastError right after CreateFileW so that it isn't overwritten */
+          is_dir_error = GetLastError();
+
+          WCMD_print_error ();
+          WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), thisArg);
+
+          /* Invalid directory path; Return immediately */
+          if(is_dir_error == ERROR_PATH_NOT_FOUND) {
+            return errorlevel = ERROR_INVALID_FUNCTION;
+          }
+
+          continue;
+        }
+
+        writeHeaders = TRUE;
+        fileNamePart = NULL;
+        srcpath[0] = L'\0';
+
+        do {
+          if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+              WINE_TRACE("Skipping directories\n");
+              continue;
+          }
+
+          foundOnlyDirectories = FALSE;
+
+          /* Compute fileNamePart and till_file_name_part_len only for the first time */
+          if (fileNamePart == NULL) {
+            fileNamePart = PathFindFileNameW(thisArg);
+            till_file_name_part_len = thisArg - fileNamePart;
+          }
+
+          /* Calculate length till fileNamePart */
+          full_path_len = till_file_name_part_len + wcslen(fd.cFileName);
+
+          if (full_path_len >= MAX_PATH) {
+              return_code = ERROR_INVALID_FUNCTION;
+              WCMD_output_stderr(WCMD_LoadMessage(WCMD_FILENAMETOOLONG), thisArg);
+
+              continue;
+          }
+
+          /* Copy to srcpath only if it is empty */
+          if (!srcpath[0]) {
+              StringCbCopyNW(srcpath, MAX_PATH, thisArg, till_file_name_part_len);
+          }
+
+          lstrcpyW(srcpath + till_file_name_part_len, fd.cFileName);
+          srcpath[full_path_len] = L'\0';
+
+          WINE_TRACE("type: Expanded arg to'%s'\n", wine_dbgstr_w(srcpath));
+
+          hIn = CreateFileW(srcpath, GENERIC_READ, file_share_access_flags, NULL, OPEN_EXISTING,
+          FILE_ATTRIBUTE_NORMAL, NULL);
+
+          if (writeHeaders) {
+            WCMD_output_stderr(L"\n%1\n\n\n", srcpath);
+          }
+
+          WCMD_copy_loop(hIn, hOut, is_ascii_out || GetConsoleMode(hIn, &console_mode));
+
+          CloseHandle (hIn);
+
+      } while (FindNextFileW(hff, &fd) != 0);
+
+      FindClose (hff);
+
+      if (foundOnlyDirectories) {
+        return_code = ERROR_INVALID_FUNCTION;
+        WCMD_output_stderr(WCMD_LoadMessage(WCMD_FILENOTFOUND), thisArg);
+      }
     }
+    else
+    {
+          hIn = CreateFileW(thisArg, GENERIC_READ, file_share_access_flags, NULL, OPEN_EXISTING,
+          FILE_ATTRIBUTE_NORMAL, NULL);
+
+          if (hIn == INVALID_HANDLE_VALUE) {
+            DWORD is_dir_error;
+
+            /* Store GetLastError right after CreateFileW so that it isn't overwritten */
+            is_dir_error = GetLastError();
+
+            return_code = ERROR_INVALID_FUNCTION;
+            WCMD_print_error ();
+            WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), thisArg);
+
+            /* Invalid directory path; Return immediately */
+            if(is_dir_error == ERROR_PATH_NOT_FOUND) {
+              return errorlevel = ERROR_INVALID_FUNCTION;
+            }
 
-    WCMD_copy_loop(hIn, hOut, GetConsoleMode(hIn, &console_mode) || GetConsoleMode(hOut, &console_mode));
+            continue;
+          }
 
-    CloseHandle (hIn);
+          if (writeHeaders) {
+            WCMD_output_stderr(L"\n%1\n\n\n", thisArg);
+          }
+
+          WCMD_copy_loop(hIn, hOut, is_ascii_out || GetConsoleMode(hIn, &console_mode));
+
+          CloseHandle (hIn);
+      }
   }
 
   return errorlevel = return_code;
diff --git a/programs/cmd/tests/test_builtins.bat b/programs/cmd/tests/test_builtins.bat
index 4c3d0e7107ea..7711aa917e3d 100644
--- a/programs/cmd/tests/test_builtins.bat
+++ b/programs/cmd/tests/test_builtins.bat
@@ -99,16 +99,22 @@ call :setError 666 & (start /B /WAIT /d "%FOO_PATH%" cmd /s /c "if /I \"%%cd%%\"
 rd /q /s foo
 echo --- success/failure for TYPE command
 mkdir foo & cd foo
+mkdir bar
+mkdir spam
 echo a > fileA
 echo b > fileB
 call :setError 666 & (type &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
 call :setError 666 & (type NUL &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
 call :setError 666 & (type i\dont\exist\at\all.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
-call :setError 666 & (type file* i\dont\exist\at\all.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
 echo ---
-call :setError 666 & (type i\dont\exist\at\all.txt file* &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
-cd .. && rd /q /s foo
-
+call :setError 666 & (type file* i\dont\exist\at\all.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+call :setError 666 & (type file* idontexistatall.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+call :setError 666 & (type idontexistatall.txt file* &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+call :setError 666 & (type i\dont\exist\at\all.txt file*&&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+cd ..
+del foo\file*
+call :setError 666 & (type foo\* &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+rd /q /s foo
 echo --- success/failure for COPY command
 mkdir foo & cd foo
 echo a > fileA
diff --git a/programs/cmd/tests/test_builtins.bat.exp b/programs/cmd/tests/test_builtins.bat.exp
index 36e14d5be911..77ca71c8778e 100644
--- a/programs/cmd/tests/test_builtins.bat.exp
+++ b/programs/cmd/tests/test_builtins.bat.exp
@@ -67,10 +67,17 @@ SUCCESS 1024
 FAILURE 1
 SUCCESS 0
 FAILURE 1
-@todo_wine@a@space@
-@todo_wine@b@space@
-@todo_wine@FAILURE 1
-@todo_wine@---
+---
+a@space@
+b@space@
+FAILURE 1
+a@space@
+b@space@
+FAILURE 1
+a@space@
+b@space@
+FAILURE 1
+FAILURE 1
 FAILURE 1
 --- success/failure for COPY command
 FAILURE 1
diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd
index f65a301d914f..34d1f0764853 100644
--- a/programs/cmd/tests/test_builtins.cmd
+++ b/programs/cmd/tests/test_builtins.cmd
@@ -682,16 +682,22 @@ call :setError 666 & (start /B /WAIT /d "%FOO_PATH%" cmd /s /c "if /I \"%%cd%%\"
 rd /q /s foo
 echo --- success/failure for TYPE command
 mkdir foo & cd foo
+mkdir bar
+mkdir spam
 echo a > fileA
 echo b > fileB
 call :setError 666 & (type &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
 call :setError 666 & (type NUL &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
 call :setError 666 & (type i\dont\exist\at\all.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
-call :setError 666 & (type file* i\dont\exist\at\all.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
 echo ---
-call :setError 666 & (type i\dont\exist\at\all.txt file* &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
-cd .. && rd /q /s foo
-
+call :setError 666 & (type file* i\dont\exist\at\all.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+call :setError 666 & (type file* idontexistatall.txt &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+call :setError 666 & (type idontexistatall.txt file* &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+call :setError 666 & (type i\dont\exist\at\all.txt file*&&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+cd ..
+del foo\file*
+call :setError 666 & (type foo\* &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!)
+rd /q /s foo
 echo --- success/failure for COPY command
 mkdir foo & cd foo
 echo a > fileA
diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp
index 0f6d9bdb4946..dc6420e14326 100644
--- a/programs/cmd/tests/test_builtins.cmd.exp
+++ b/programs/cmd/tests/test_builtins.cmd.exp
@@ -586,10 +586,17 @@ SUCCESS 1024
 FAILURE 1
 SUCCESS 0
 FAILURE 1
-@todo_wine@a@space@
-@todo_wine@b@space@
-@todo_wine@FAILURE 1
-@todo_wine@---
+---
+a@space@
+b@space@
+FAILURE 1
+a@space@
+b@space@
+FAILURE 1
+a@space@
+b@space@
+FAILURE 1
+FAILURE 1
 FAILURE 1
 --- success/failure for COPY command
 FAILURE 1
diff --git a/programs/explorer/startmenu.c b/programs/explorer/startmenu.c
index 63120026dad0..33a0d0c0c9c5 100644
--- a/programs/explorer/startmenu.c
+++ b/programs/explorer/startmenu.c
@@ -34,6 +34,8 @@ struct menu_item
 {
     struct list entry;
     LPWSTR displayname;
+    HIMAGELIST icon_himl;
+    int icon_i;
 
     /* parent information */
     struct menu_item* parent;
@@ -185,6 +187,8 @@ static struct menu_item* add_shell_item(struct menu_item* parent, LPITEMIDLIST p
     int existing_item_count, i;
     BOOL match = FALSE;
     SFGAOF flags;
+    SHFILEINFOW sfi;
+    HIMAGELIST himl;
 
     item = calloc( 1, sizeof(struct menu_item) );
 
@@ -206,6 +210,13 @@ static struct menu_item* add_shell_item(struct menu_item* parent, LPITEMIDLIST p
             IShellFolder_BindToObject(parent->folder, pidl, NULL, &IID_IShellFolder, (void *)&item->folder);
     }
 
+    himl = (HIMAGELIST)SHGetFileInfoW((LPCWSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_PIDL|SHGFI_SYSICONINDEX|SHGFI_SMALLICON);
+    if (himl)
+    {
+        item->icon_himl = himl;
+        item->icon_i = sfi.iIcon;
+    }
+
     if (item->folder && shell_folder_is_empty(item->folder))
     {
         IShellFolder_Release(item->folder);
@@ -266,6 +277,10 @@ static struct menu_item* add_shell_item(struct menu_item* parent, LPITEMIDLIST p
         mii.fMask = MIIM_STRING|MIIM_DATA;
         mii.dwTypeData = item->displayname;
         mii.dwItemData = (ULONG_PTR)item;
+        if (item->icon_himl) {
+            mii.fMask |= MIIM_BITMAP;
+            mii.hbmpItem = HBMMENU_CALLBACK;
+        }
 
         if (item->folder)
         {
@@ -275,7 +290,8 @@ static struct menu_item* add_shell_item(struct menu_item* parent, LPITEMIDLIST p
             mii.hSubMenu = item->menuhandle;
 
             mi.cbSize = sizeof(mi);
-            mi.fMask = MIM_MENUDATA;
+            mi.fMask = MIM_MENUDATA|MIM_STYLE;
+            mi.dwStyle = MNS_NOTIFYBYPOS|MNS_NOCHECK;
             mi.dwMenuData = (ULONG_PTR)item;
             SetMenuInfo(item->menuhandle, &mi);
         }
@@ -438,6 +454,20 @@ LRESULT menu_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
 
             return 0;
         }
+
+    case WM_MEASUREITEM:
+        ((MEASUREITEMSTRUCT*)lparam)->itemWidth = GetSystemMetrics(SM_CXSMICON) + 5;
+        ((MEASUREITEMSTRUCT*)lparam)->itemHeight = GetSystemMetrics(SM_CYSMICON);
+        return TRUE;
+
+    case WM_DRAWITEM:
+        {
+            DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT*)lparam;
+            struct menu_item* item = (struct menu_item*)dis->itemData;
+
+            ImageList_Draw(item->icon_himl, item->icon_i, dis->hDC, dis->rcItem.left - 2, dis->rcItem.top, ILD_NORMAL);
+            return TRUE;
+        }
     }
 
     return DefWindowProcW(hwnd, msg, wparam, lparam);
@@ -508,7 +538,7 @@ void do_startmenu(HWND hwnd)
 
     mi.cbSize = sizeof(mi);
     mi.fMask = MIM_STYLE;
-    mi.dwStyle = MNS_NOTIFYBYPOS;
+    mi.dwStyle = MNS_NOTIFYBYPOS|MNS_NOCHECK;
     SetMenuInfo(root_menu.menuhandle, &mi);
 
     GetWindowRect(hwnd, &rc);
diff --git a/programs/explorer/systray.c b/programs/explorer/systray.c
index a2098c808aec..69d3ec61b6a0 100644
--- a/programs/explorer/systray.c
+++ b/programs/explorer/systray.c
@@ -1133,9 +1133,16 @@ static LRESULT WINAPI shell_traywnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LP
         return 0;
 
     case WM_DRAWITEM:
+        if (((MEASUREITEMSTRUCT*)lparam)->CtlType == ODT_MENU)
+            return menu_wndproc(hwnd, msg, wparam, lparam);
         paint_taskbar_button( (const DRAWITEMSTRUCT *)lparam );
         break;
 
+    case WM_MEASUREITEM:
+        if (((MEASUREITEMSTRUCT*)lparam)->CtlType == ODT_MENU)
+            return menu_wndproc(hwnd, msg, wparam, lparam);
+        break;
+
     case WM_COMMAND:
         if (HIWORD(wparam) == BN_CLICKED)
         {
diff --git a/programs/taskmgr/taskmgr.c b/programs/taskmgr/taskmgr.c
index 69b69ef2b541..e668a2e40563 100644
--- a/programs/taskmgr/taskmgr.c
+++ b/programs/taskmgr/taskmgr.c
@@ -179,6 +179,9 @@ static BOOL OnCreate(HWND hWnd)
     hUpdateSpeedMenu = GetSubMenu(hViewMenu, 1);
     hCPUHistoryMenu = GetSubMenu(hViewMenu, 7);
 
+    /* Change the default push button to avoid the application closing on pressing enter */
+    SendMessageW(hMainWnd, DM_SETDEFID, IDIGNORE, 0);
+
     /* Check or uncheck the always on top menu item */
     if (TaskManagerSettings.AlwaysOnTop) {
         CheckMenuItem(hEditMenu, ID_OPTIONS_ALWAYSONTOP, MF_BYCOMMAND|MF_CHECKED);
diff --git a/programs/winhlp32/macro.c b/programs/winhlp32/macro.c
index 36bda654afdd..86095101e93e 100644
--- a/programs/winhlp32/macro.c
+++ b/programs/winhlp32/macro.c
@@ -671,7 +671,21 @@ static void CALLBACK MACRO_NoShow(void)
 
 void CALLBACK MACRO_PopupContext(LPCSTR str, LONG u)
 {
-    WINE_FIXME("(%s, %lu)\n", debugstr_a(str), u);
+    HLPFILE_WINDOWINFO* wi;
+    HLPFILE *hlpfile;
+    POINT origin = { 0, 0 };
+
+    WINE_TRACE("(%s, %lu)\n", debugstr_a(str), u);
+
+    if (!(hlpfile = WINHELP_LookupHelpFile(str)))
+    {
+        WINE_ERR("Failed to load .hlp file for %s\n", debugstr_a(str));
+        return;
+    }
+
+    GetCursorPos(&origin);
+    wi = WINHELP_GetPopupWindowInfo(hlpfile, MACRO_CurrentWindow(), MAKELPARAM(origin.x, origin.y));
+    WINHELP_OpenHelpWindow(HLPFILE_PageByMap, hlpfile, u, wi, SW_NORMAL);
 }
 
 static void CALLBACK MACRO_PopupHash(LPCSTR str, LONG u)
diff --git a/programs/winhlp32/winhelp.c b/programs/winhlp32/winhelp.c
index 1c112f08aafa..304231df9f63 100644
--- a/programs/winhlp32/winhelp.c
+++ b/programs/winhlp32/winhelp.c
@@ -293,8 +293,7 @@ HLPFILE_WINDOWINFO*     WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)
  *
  *
  */
-static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
-                                                          WINHELP_WINDOW* parent, LPARAM mouse)
+HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, WINHELP_WINDOW* parent, LPARAM mouse)
 {
     static      HLPFILE_WINDOWINFO      wi;
 
@@ -316,7 +315,9 @@ static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,
 
     wi.style = SW_SHOW;
     wi.win_style = WS_POPUP | WS_BORDER;
-    if (parent->page->file->has_popup_color)
+    if (hlpfile->has_popup_color)
+        wi.sr_color = hlpfile->popup_color;
+    else if (parent->page && parent->page->file->has_popup_color)
         wi.sr_color = parent->page->file->popup_color;
     else
         wi.sr_color = parent->info->sr_color;
diff --git a/programs/winhlp32/winhelp.h b/programs/winhlp32/winhelp.h
index 519dec215a95..6d2f0ebc01fe 100644
--- a/programs/winhlp32/winhelp.h
+++ b/programs/winhlp32/winhelp.h
@@ -170,6 +170,7 @@ BOOL WINHELP_CreateIndexWindow(BOOL);
 void WINHELP_DeleteBackSet(WINHELP_WINDOW*);
 HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile);
 HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name);
+HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, WINHELP_WINDOW* parent, LPARAM mouse);
 void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win);
 WINHELP_WINDOW* WINHELP_GrabWindow(WINHELP_WINDOW*);
 BOOL WINHELP_ReleaseWindow(WINHELP_WINDOW*);
diff --git a/programs/wscript/main.c b/programs/wscript/main.c
index a971ceeec8d5..c801e0be34ab 100644
--- a/programs/wscript/main.c
+++ b/programs/wscript/main.c
@@ -504,6 +504,7 @@ static BSTR get_script_str(const WCHAR *filename)
     HANDLE file, map;
     DWORD size, len;
     BSTR ret;
+    int flags;
 
     file = CreateFileW(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
     if(file == INVALID_HANDLE_VALUE)
@@ -525,9 +526,27 @@ static BSTR get_script_str(const WCHAR *filename)
     if(!file_map)
         return NULL;
 
+    flags = IS_TEXT_UNICODE_UNICODE_MASK;
+    if(IsTextUnicode(file_map, size, &flags))
+    {
+        const WCHAR *start = (const WCHAR *)file_map;
+        DWORD count = size / sizeof(WCHAR);
+
+        if(flags & IS_TEXT_UNICODE_SIGNATURE)
+        {
+            start++;
+            count--;
+        }
+        ret = SysAllocStringLen(start, count);
+        UnmapViewOfFile(file_map);
+        return ret;
+    }
+
+    /* Not Unicode, fall back to system ANSI code page. */
     len = MultiByteToWideChar(CP_ACP, 0, file_map, size, NULL, 0);
     ret = SysAllocStringLen(NULL, len);
-    MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len);
+    if(ret)
+        MultiByteToWideChar(CP_ACP, 0, file_map, size, ret, len);
 
     UnmapViewOfFile(file_map);
     return ret;
diff --git a/programs/wscript/tests/run.c b/programs/wscript/tests/run.c
index abb01774117f..170757022be5 100644
--- a/programs/wscript/tests/run.c
+++ b/programs/wscript/tests/run.c
@@ -835,6 +835,17 @@ static void run_cscript_error_on_stdout_test(void)
     ok(stderr_buf[0] == 0, "expected no stderr output, got: %s\n", stderr_buf);
 }
 
+static void test_script_encoding(void)
+{
+    static const WCHAR utf16le[] =
+        L"new ActiveXObject('Wine.Test').reportSuccess();\n";
+    static const WCHAR utf16le_bom[] =
+        L"\ufeffnew ActiveXObject('Wine.Test').reportSuccess();\n";
+
+    run_script("utf16le.js", (const char *)utf16le, sizeof(utf16le), 0);
+    run_script("utf16lebom.js", (const char *)utf16le_bom, sizeof(utf16le_bom), 0);
+}
+
 START_TEST(run)
 {
     char **argv;
@@ -859,6 +870,7 @@ START_TEST(run)
                            "WScript.Quit(3);\n"
                            "winetest.ok(false, 'not quit?');\n", 3);
 
+        test_script_encoding();
         run_cscript_error_test();
         run_cscript_unknown_option_test();
         run_cscript_no_file_test();
diff --git a/server/Makefile.in b/server/Makefile.in
index 84a6bd74d9df..0dd53951c4f6 100644
--- a/server/Makefile.in
+++ b/server/Makefile.in
@@ -1,6 +1,7 @@
 PROGRAMS = wineserver
 
 SOURCES = \
+	alpc.c \
 	async.c \
 	atom.c \
 	change.c \
diff --git a/server/alpc.c b/server/alpc.c
new file mode 100644
index 000000000000..aa6713a03705
--- /dev/null
+++ b/server/alpc.c
@@ -0,0 +1,149 @@
+﻿/*
+ * Server-side advanced local procedure call management
+ *
+ * Copyright 2026 Zhiyi Zhang for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+
+#include "windef.h"
+#include "winternl.h"
+#include "ntstatus.h"
+
+#include "handle.h"
+#include "thread.h"
+#include "security.h"
+#include "request.h"
+
+static const WCHAR alpc_port_name[] = {'A','L','P','C',' ','P','o','r','t'};
+
+struct type_descr alpc_port_type =
+{
+    { alpc_port_name, sizeof(alpc_port_name) }, /* name */
+    ALPC_PORT_ALL_ACCESS,                       /* valid_access */
+    {                                           /* mapping */
+         STANDARD_RIGHTS_READ | ALPC_PORT_QUERY_STATE,
+         DELETE | ALPC_PORT_QUERY_STATE,
+         0,
+         ALPC_PORT_ALL_ACCESS
+    },
+};
+
+enum alpc_port_enum_type
+{
+    CONNECTION_PORT,
+    COMMUNICATION_PORT
+};
+
+enum alpc_port_status
+{
+    UNINITIALIZED,
+    CONNECTED,
+    REFUSED,
+    DISCONNECTED
+};
+
+struct alpc_port
+{
+    struct object            obj;                   /* object header */
+    enum alpc_port_enum_type type;                  /* communication port or connection port */
+    enum alpc_port_status    status;                /* port status */
+    struct thread           *thread;                /* thread owning the port */
+    unsigned int             flags;                 /* flags in port attributes */
+    mem_size_t               max_msg_len;           /* max message length in port attributes */
+};
+
+static void alpc_port_dump( struct object *obj, int verbose );
+static void alpc_port_destroy( struct object *obj );
+
+static const struct object_ops alpc_port_ops =
+{
+    .size         = sizeof(struct alpc_port),
+    .type         = &alpc_port_type,
+    .dump         = alpc_port_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .destroy      = alpc_port_destroy
+};
+
+static void alpc_port_dump( struct object *obj, int verbose )
+{
+    struct alpc_port *port = (struct alpc_port *)obj;
+    assert( obj->ops == &alpc_port_ops );
+    fprintf( stderr, "ALPC Port type=%d status=%d\n", port->type, port->status );
+}
+
+static void alpc_port_destroy( struct object *obj )
+{
+    struct alpc_port *port = (struct alpc_port *)obj;
+    assert( obj->ops == &alpc_port_ops );
+    release_object( port->thread );
+}
+
+static struct alpc_port *alpc_create_port( struct object *root, const struct unicode_str *name,
+                                           unsigned int attr, const struct security_descriptor *sd,
+                                           enum alpc_port_enum_type type, unsigned int flags,
+                                           mem_size_t max_msg_len )
+{
+    struct alpc_port *port;
+
+    port = create_named_object( root, &alpc_port_ops, name, attr, sd );
+    if (port)
+    {
+        if (get_error() != STATUS_OBJECT_NAME_EXISTS)
+        {
+            port->type = type;
+            port->status = UNINITIALIZED;
+            port->thread = (struct thread *)grab_object( current );
+            port->flags = flags;
+            port->max_msg_len = max_msg_len;
+        }
+        else
+        {
+            release_object( port );
+            return NULL;
+        }
+    }
+
+    return port;
+}
+
+/* Create an ALPC port */
+DECL_HANDLER(alpc_create_port)
+{
+    struct alpc_port *alpc_port;
+    const struct security_descriptor *sd;
+    struct unicode_str name;
+    struct object *root;
+    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
+
+    if ((alpc_port = alpc_create_port( root, &name, objattr->attributes, sd, CONNECTION_PORT,
+                                       req->flags, req->max_msg_len )))
+    {
+        reply->handle = alloc_handle( current->process, alpc_port, ALPC_PORT_ALL_ACCESS, objattr->attributes );
+        release_object( alpc_port );
+    }
+
+    if (root) release_object( root );
+}
diff --git a/server/async.c b/server/async.c
index d7f665ba10bf..81b45daa09c2 100644
--- a/server/async.c
+++ b/server/async.c
@@ -46,27 +46,11 @@ static void async_cancel_destroy( struct object *obj );
 
 static const struct object_ops async_cancel_ops =
 {
-    sizeof(struct async_cancel), /* size */
-    &no_type,                    /* type */
-    async_cancel_dump,           /* dump */
-    NULL,                        /* add_queue */
-    NULL,                        /* remove_queue */
-    NULL,                        /* signaled */
-    NULL,                        /* satisfied */
-    no_signal,                   /* signal */
-    no_get_fd,                   /* get_fd */
-    async_cancel_get_sync,       /* get_sync */
-    default_map_access,          /* map_access */
-    default_get_sd,              /* get_sd */
-    default_set_sd,              /* set_sd */
-    no_get_full_name,            /* get_full_name */
-    no_lookup_name,              /* lookup_name */
-    no_link_name,                /* link_name */
-    NULL,                        /* unlink_name */
-    no_open_file,                /* open_file */
-    no_kernel_obj_list,          /* get_kernel_obj_list */
-    no_close_handle,             /* close_handle */
-    async_cancel_destroy         /* destroy */
+    .size     = sizeof(struct async_cancel),
+    .type     = &no_type,
+    .dump     = async_cancel_dump,
+    .get_sync = async_cancel_get_sync,
+    .destroy  = async_cancel_destroy,
 };
 
 static void async_cancel_dump( struct object *obj, int verbose )
@@ -147,27 +131,14 @@ static void async_destroy( struct object *obj );
 
 static const struct object_ops async_ops =
 {
-    sizeof(struct async),      /* size */
-    &no_type,                  /* type */
-    async_dump,                /* dump */
-    add_queue,                 /* add_queue */
-    remove_queue,              /* remove_queue */
-    async_signaled,            /* signaled */
-    async_satisfied,           /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    no_get_full_name,          /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    no_link_name,              /* link_name */
-    NULL,                      /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    async_destroy              /* destroy */
+    .size         = sizeof(struct async),
+    .type         = &no_type,
+    .dump         = async_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .signaled     = async_signaled,
+    .satisfied    = async_satisfied,
+    .destroy      = async_destroy,
 };
 
 static inline void async_reselect( struct async *async )
@@ -821,27 +792,10 @@ static void iosb_destroy( struct object *obj );
 
 static const struct object_ops iosb_ops =
 {
-    sizeof(struct iosb),      /* size */
-    &no_type,                 /* type */
-    iosb_dump,                /* dump */
-    no_add_queue,             /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    no_get_fd,                /* get_fd */
-    default_get_sync,         /* get_sync */
-    default_map_access,       /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
-    no_get_full_name,         /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    no_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,          /* close_handle */
-    iosb_destroy              /* destroy */
+    .size    = sizeof(struct iosb),
+    .type    = &no_type,
+    .dump    = iosb_dump,
+    .destroy = iosb_destroy,
 };
 
 static void iosb_dump( struct object *obj, int verbose )
diff --git a/server/atom.c b/server/atom.c
index 607cd96da672..55a7fb8da7be 100644
--- a/server/atom.c
+++ b/server/atom.c
@@ -70,27 +70,10 @@ static void atom_table_destroy( struct object *obj );
 
 static const struct object_ops atom_table_ops =
 {
-    sizeof(struct atom_table),    /* size */
-    &no_type,                     /* type */
-    atom_table_dump,              /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    no_get_full_name,             /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    atom_table_destroy            /* destroy */
+    .size    = sizeof(struct atom_table),
+    .type    = &no_type,
+    .dump    = atom_table_dump,
+    .destroy = atom_table_destroy,
 };
 
 static struct atom_table *global_table;
diff --git a/server/change.c b/server/change.c
index f7c2ac9a6d55..37fa9460dd96 100644
--- a/server/change.c
+++ b/server/change.c
@@ -107,27 +107,17 @@ static struct list *dir_get_kernel_obj_list( struct object *obj );
 
 static const struct object_ops dir_ops =
 {
-    sizeof(struct dir),       /* size */
-    &file_type,               /* type */
-    dir_dump,                 /* dump */
-    NULL,                     /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    dir_get_fd,               /* get_fd */
-    default_fd_get_sync,      /* get_sync */
-    default_map_access,       /* map_access */
-    dir_get_sd,               /* get_sd */
-    dir_set_sd,               /* set_sd */
-    default_fd_get_full_name, /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    dir_get_kernel_obj_list,  /* get_kernel_obj_list */
-    dir_close_handle,         /* close_handle */
-    dir_destroy               /* destroy */
+    .size                = sizeof(struct dir),
+    .type                = &file_type,
+    .dump                = dir_dump,
+    .get_fd              = dir_get_fd,
+    .get_sync            = default_fd_get_sync,
+    .get_sd              = dir_get_sd,
+    .set_sd              = dir_set_sd,
+    .get_full_name       = default_fd_get_full_name,
+    .get_kernel_obj_list = dir_get_kernel_obj_list,
+    .close_handle        = dir_close_handle,
+    .destroy             = dir_destroy,
 };
 
 static int dir_get_poll_events( struct fd *fd );
@@ -135,18 +125,11 @@ static enum server_fd_type dir_get_fd_type( struct fd *fd );
 
 static const struct fd_ops dir_fd_ops =
 {
-    dir_get_poll_events,         /* get_poll_events */
-    default_poll_event,          /* poll_event */
-    dir_get_fd_type,             /* get_fd_type */
-    no_fd_read,                  /* read */
-    no_fd_write,                 /* write */
-    no_fd_flush,                 /* flush */
-    default_fd_get_file_info,    /* get_file_info */
-    no_fd_get_volume_info,       /* get_volume_info */
-    default_fd_ioctl,            /* ioctl */
-    default_fd_cancel_async,     /* cancel_async */
-    default_fd_queue_async,      /* queue_async */
-    default_fd_reselect_async    /* reselect_async */
+    .get_poll_events = dir_get_poll_events,
+    .get_fd_type     = dir_get_fd_type,
+    .get_file_info   = default_fd_get_file_info,
+    .ioctl           = default_fd_ioctl,
+    .queue_async     = default_fd_queue_async,
 };
 
 static struct list change_list = LIST_INIT(change_list);
@@ -650,13 +633,8 @@ static void inotify_poll_event( struct fd *fd, int event );
 
 static const struct fd_ops inotify_fd_ops =
 {
-    inotify_get_poll_events,     /* get_poll_events */
-    inotify_poll_event,          /* poll_event */
-    NULL,                        /* flush */
-    NULL,                        /* get_fd_type */
-    NULL,                        /* ioctl */
-    NULL,                        /* queue_async */
-    NULL                         /* reselect_async */
+    .get_poll_events = inotify_get_poll_events,
+    .poll_event      = inotify_poll_event,
 };
 
 static int inotify_get_poll_events( struct fd *fd )
diff --git a/server/clipboard.c b/server/clipboard.c
index 81e6c5694324..510490e7305f 100644
--- a/server/clipboard.c
+++ b/server/clipboard.c
@@ -69,27 +69,10 @@ static void clipboard_destroy( struct object *obj );
 
 static const struct object_ops clipboard_ops =
 {
-    sizeof(struct clipboard),     /* size */
-    &no_type,                     /* type */
-    clipboard_dump,               /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    no_get_full_name,             /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    clipboard_destroy             /* destroy */
+    .size    = sizeof(struct clipboard),
+    .type    = &no_type,
+    .dump    = clipboard_dump,
+    .destroy = clipboard_destroy,
 };
 
 
diff --git a/server/completion.c b/server/completion.c
index 8242bf790542..601ce519fda5 100644
--- a/server/completion.c
+++ b/server/completion.c
@@ -85,27 +85,14 @@ static void completion_wait_destroy( struct object * );
 
 static const struct object_ops completion_wait_ops =
 {
-    sizeof(struct completion_wait), /* size */
-    &no_type,                       /* type */
-    completion_wait_dump,           /* dump */
-    add_queue,                      /* add_queue */
-    remove_queue,                   /* remove_queue */
-    completion_wait_signaled,       /* signaled */
-    completion_wait_satisfied,      /* satisfied */
-    no_signal,                      /* signal */
-    no_get_fd,                      /* get_fd */
-    default_get_sync,               /* get_sync */
-    default_map_access,             /* map_access */
-    default_get_sd,                 /* get_sd */
-    default_set_sd,                 /* set_sd */
-    no_get_full_name,               /* get_full_name */
-    no_lookup_name,                 /* lookup_name */
-    no_link_name,                   /* link_name */
-    NULL,                           /* unlink_name */
-    no_open_file,                   /* open_file */
-    no_kernel_obj_list,             /* get_kernel_obj_list */
-    no_close_handle,                /* close_handle */
-    completion_wait_destroy         /* destroy */
+    .size         = sizeof(struct completion_wait),
+    .type         = &no_type,
+    .dump         = completion_wait_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .signaled     = completion_wait_signaled,
+    .satisfied    = completion_wait_satisfied,
+    .destroy      = completion_wait_destroy,
 };
 
 static void completion_wait_destroy( struct object *obj )
@@ -160,27 +147,12 @@ static void completion_destroy( struct object * );
 
 static const struct object_ops completion_ops =
 {
-    sizeof(struct completion), /* size */
-    &completion_type,          /* type */
-    completion_dump,           /* dump */
-    NULL,                      /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    completion_get_sync,       /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    completion_close_handle,   /* close_handle */
-    completion_destroy         /* destroy */
+    .size         = sizeof(struct completion),
+    .type         = &completion_type,
+    .dump         = completion_dump,
+    .get_sync     = completion_get_sync,
+    .close_handle = completion_close_handle,
+    .destroy      = completion_destroy,
 };
 
 static void completion_destroy( struct object *obj)
diff --git a/server/console.c b/server/console.c
index 0ee1110be916..40a783801f1d 100644
--- a/server/console.c
+++ b/server/console.c
@@ -76,27 +76,14 @@ static struct object *console_open_file( struct object *obj, unsigned int access
 
 static const struct object_ops console_ops =
 {
-    sizeof(struct console),           /* size */
-    &file_type,                       /* type */
-    console_dump,                     /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    console_get_fd,                   /* get_fd */
-    console_get_sync,                 /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    console_lookup_name,              /* lookup_name */
-    no_link_name,                     /* link_name */
-    NULL,                             /* unlink_name */
-    console_open_file,                /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    console_destroy                   /* destroy */
+    .size        = sizeof(struct console),
+    .type        = &file_type,
+    .dump        = console_dump,
+    .get_fd      = console_get_fd,
+    .get_sync    = console_get_sync,
+    .lookup_name = console_lookup_name,
+    .open_file   = console_open_file,
+    .destroy     = console_destroy,
 };
 
 static enum server_fd_type console_get_fd_type( struct fd *fd );
@@ -108,18 +95,13 @@ static void console_ioctl( struct fd *fd, ioctl_code_t code, struct async *async
 
 static const struct fd_ops console_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    console_get_fd_type,          /* get_fd_type */
-    console_read,                 /* read */
-    no_fd_write,                  /* write */
-    console_flush,                /* flush */
-    console_get_file_info,        /* get_file_info */
-    console_get_volume_info,      /* get_volume_info */
-    console_ioctl,                /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type     = console_get_fd_type,
+    .read            = console_read,
+    .flush           = console_flush,
+    .get_file_info   = console_get_file_info,
+    .get_volume_info = console_get_volume_info,
+    .ioctl           = console_ioctl,
+    .queue_async     = default_fd_queue_async,
 };
 
 struct console_host_ioctl
@@ -155,45 +137,23 @@ static struct object *console_server_open_file( struct object *obj, unsigned int
 
 static const struct object_ops console_server_ops =
 {
-    sizeof(struct console_server),    /* size */
-    &file_type,                       /* type */
-    console_server_dump,              /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    console_server_get_fd,            /* get_fd */
-    console_server_get_sync,          /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    console_server_lookup_name,       /* lookup_name */
-    no_link_name,                     /* link_name */
-    NULL,                             /* unlink_name */
-    console_server_open_file,         /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    console_server_destroy            /* destroy */
+    .size        = sizeof(struct console_server),
+    .type        = &file_type,
+    .dump        = console_server_dump,
+    .get_fd      = console_server_get_fd,
+    .get_sync    = console_server_get_sync,
+    .lookup_name = console_server_lookup_name,
+    .open_file   = console_server_open_file,
+    .destroy     = console_server_destroy,
 };
 
 static void console_server_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
 
 static const struct fd_ops console_server_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    console_get_fd_type,          /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    no_fd_get_file_info,          /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    console_server_ioctl,         /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type = console_get_fd_type,
+    .ioctl       = console_server_ioctl,
+    .queue_async = default_fd_queue_async,
 };
 
 struct font_info
@@ -226,27 +186,13 @@ static struct object *screen_buffer_open_file( struct object *obj, unsigned int
 
 static const struct object_ops screen_buffer_ops =
 {
-    sizeof(struct screen_buffer),     /* size */
-    &file_type,                       /* type */
-    screen_buffer_dump,               /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    screen_buffer_get_fd,             /* get_fd */
-    screen_buffer_get_sync,           /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    no_link_name,                     /* link_name */
-    NULL,                             /* unlink_name */
-    screen_buffer_open_file,          /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    screen_buffer_destroy             /* destroy */
+    .size      = sizeof(struct screen_buffer),
+    .type      = &file_type,
+    .dump      = screen_buffer_dump,
+    .get_fd    = screen_buffer_get_fd,
+    .get_sync  = screen_buffer_get_sync,
+    .open_file = screen_buffer_open_file,
+    .destroy   = screen_buffer_destroy,
 };
 
 static void screen_buffer_write( struct fd *fd, struct async *async, file_pos_t pos );
@@ -254,18 +200,12 @@ static void screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async
 
 static const struct fd_ops screen_buffer_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    console_get_fd_type,          /* get_fd_type */
-    no_fd_read,                   /* read */
-    screen_buffer_write,          /* write */
-    no_fd_flush,                  /* flush */
-    console_get_file_info,        /* get_file_info */
-    console_get_volume_info,      /* get_volume_info */
-    screen_buffer_ioctl,          /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type     = console_get_fd_type,
+    .write           = screen_buffer_write,
+    .get_file_info   = console_get_file_info,
+    .get_volume_info = console_get_volume_info,
+    .ioctl           = screen_buffer_ioctl,
+    .queue_async     = default_fd_queue_async,
 };
 
 static void console_device_dump( struct object *obj, int verbose );
@@ -276,27 +216,11 @@ static struct object *console_device_open_file( struct object *obj, unsigned int
 
 static const struct object_ops console_device_ops =
 {
-    sizeof(struct object),            /* size */
-    &device_type,                     /* type */
-    console_device_dump,              /* dump */
-    no_add_queue,                     /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    no_satisfied,                     /* satisfied */
-    no_signal,                        /* signal */
-    no_get_fd,                        /* get_fd */
-    default_get_sync,                 /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    default_get_full_name,            /* get_full_name */
-    console_device_lookup_name,       /* lookup_name */
-    directory_link_name,              /* link_name */
-    default_unlink_name,              /* unlink_name */
-    console_device_open_file,         /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    no_destroy                        /* destroy */
+    .size        = sizeof(struct object),
+    .type        = &device_type,
+    .dump        = console_device_dump,
+    .lookup_name = console_device_lookup_name,
+    .open_file   = console_device_open_file,
 };
 
 struct console_input
@@ -317,27 +241,13 @@ static void console_input_destroy( struct object *obj );
 
 static const struct object_ops console_input_ops =
 {
-    sizeof(struct console_input),     /* size */
-    &device_type,                     /* type */
-    console_input_dump,               /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    console_input_get_fd,             /* get_fd */
-    console_input_get_sync,           /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    directory_link_name,              /* link_name */
-    default_unlink_name,              /* unlink_name */
-    console_input_open_file,          /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    console_input_destroy             /* destroy */
+    .size      = sizeof(struct console_input),
+    .type      = &device_type,
+    .dump      = console_input_dump,
+    .get_fd    = console_input_get_fd,
+    .get_sync  = console_input_get_sync,
+    .open_file = console_input_open_file,
+    .destroy   = console_input_destroy,
 };
 
 static void console_input_read( struct fd *fd, struct async *async, file_pos_t pos );
@@ -346,18 +256,13 @@ static void console_input_ioctl( struct fd *fd, ioctl_code_t code, struct async
 
 static const struct fd_ops console_input_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    console_get_fd_type,          /* get_fd_type */
-    console_input_read,           /* read */
-    no_fd_write,                  /* write */
-    console_input_flush,          /* flush */
-    console_get_file_info,        /* get_file_info */
-    console_get_volume_info,      /* get_volume_info */
-    console_input_ioctl,          /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type     = console_get_fd_type,
+    .read            = console_input_read,
+    .flush           = console_input_flush,
+    .get_file_info   = console_get_file_info,
+    .get_volume_info = console_get_volume_info,
+    .ioctl           = console_input_ioctl,
+    .queue_async     = default_fd_queue_async,
 };
 
 struct console_output
@@ -378,27 +283,13 @@ static void console_output_destroy( struct object *obj );
 
 static const struct object_ops console_output_ops =
 {
-    sizeof(struct console_output),    /* size */
-    &device_type,                     /* type */
-    console_output_dump,              /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    console_output_get_fd,            /* get_fd */
-    console_output_get_sync,          /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    directory_link_name,              /* link_name */
-    default_unlink_name,              /* unlink_name */
-    console_output_open_file,         /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    console_output_destroy            /* destroy */
+    .size      = sizeof(struct console_output),
+    .type      = &device_type,
+    .dump      = console_output_dump,
+    .get_fd    = console_output_get_fd,
+    .get_sync  = console_output_get_sync,
+    .open_file = console_output_open_file,
+    .destroy   = console_output_destroy,
 };
 
 static void console_output_write( struct fd *fd, struct async *async, file_pos_t pos );
@@ -406,18 +297,12 @@ static void console_output_ioctl( struct fd *fd, ioctl_code_t code, struct async
 
 static const struct fd_ops console_output_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    console_get_fd_type,          /* get_fd_type */
-    no_fd_read,                   /* read */
-    console_output_write,         /* write */
-    no_fd_flush,                  /* flush */
-    console_get_file_info,        /* get_file_info */
-    console_get_volume_info,      /* get_volume_info */
-    console_output_ioctl,         /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type     = console_get_fd_type,
+    .write           = console_output_write,
+    .get_file_info   = console_get_file_info,
+    .get_volume_info = console_get_volume_info,
+    .ioctl           = console_output_ioctl,
+    .queue_async     = default_fd_queue_async,
 };
 
 struct console_connection
@@ -437,45 +322,23 @@ static void console_connection_destroy( struct object *obj );
 
 static const struct object_ops console_connection_ops =
 {
-    sizeof(struct console_connection),/* size */
-    &device_type,                     /* type */
-    console_connection_dump,          /* dump */
-    no_add_queue,                     /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    no_satisfied,                     /* satisfied */
-    no_signal,                        /* signal */
-    console_connection_get_fd,        /* get_fd */
-    default_get_sync,                 /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    console_connection_lookup_name,   /* lookup_name */
-    directory_link_name,              /* link_name */
-    default_unlink_name,              /* unlink_name */
-    console_connection_open_file,     /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    console_connection_close_handle,  /* close_handle */
-    console_connection_destroy        /* destroy */
+    .size         = sizeof(struct console_connection),
+    .type         = &device_type,
+    .dump         = console_connection_dump,
+    .get_fd       = console_connection_get_fd,
+    .lookup_name  = console_connection_lookup_name,
+    .open_file    = console_connection_open_file,
+    .close_handle = console_connection_close_handle,
+    .destroy      = console_connection_destroy,
 };
 
 static void console_connection_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
 
 static const struct fd_ops console_connection_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    console_get_fd_type,          /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    no_fd_get_file_info,          /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    console_connection_ioctl,     /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type = console_get_fd_type,
+    .ioctl       = console_connection_ioctl,
+    .queue_async = default_fd_queue_async,
 };
 
 static int queue_host_ioctl( struct console_server *server, unsigned int code, unsigned int output,
diff --git a/server/d3dkmt.c b/server/d3dkmt.c
index bd0e879f4f32..843c1895d5c1 100644
--- a/server/d3dkmt.c
+++ b/server/d3dkmt.c
@@ -50,27 +50,11 @@ static void d3dkmt_object_destroy( struct object *obj );
 
 static const struct object_ops d3dkmt_object_ops =
 {
-    sizeof(struct d3dkmt_object),   /* size */
-    &no_type,                       /* type */
-    d3dkmt_object_dump,             /* dump */
-    no_add_queue,                   /* add_queue */
-    NULL,                           /* remove_queue */
-    NULL,                           /* signaled */
-    NULL,                           /* satisfied */
-    no_signal,                      /* signal */
-    d3dkmt_object_get_fd,           /* get_fd */
-    default_get_sync,               /* get_sync */
-    default_map_access,             /* map_access */
-    default_get_sd,                 /* get_sd */
-    default_set_sd,                 /* set_sd */
-    no_get_full_name,               /* get_full_name */
-    no_lookup_name,                 /* lookup_name */
-    no_link_name,                   /* link_name */
-    NULL,                           /* unlink_name */
-    no_open_file,                   /* open_file */
-    no_kernel_obj_list,             /* get_kernel_obj_list */
-    no_close_handle,                /* close_handle */
-    d3dkmt_object_destroy,          /* destroy */
+    .size    = sizeof(struct d3dkmt_object),
+    .type    = &no_type,
+    .dump    = d3dkmt_object_dump,
+    .get_fd  = d3dkmt_object_get_fd,
+    .destroy = d3dkmt_object_destroy,
 };
 
 static enum server_fd_type d3dkmt_get_fd_type( struct fd *fd )
@@ -80,18 +64,7 @@ static enum server_fd_type d3dkmt_get_fd_type( struct fd *fd )
 
 static const struct fd_ops d3dkmt_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    d3dkmt_get_fd_type,           /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    no_fd_get_file_info,          /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    no_fd_ioctl,                  /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    no_fd_queue_async,            /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type = d3dkmt_get_fd_type,
 };
 
 struct keyed_wait
@@ -118,27 +91,10 @@ static void d3dkmt_mutex_destroy( struct object *obj );
 
 static const struct object_ops d3dkmt_mutex_ops =
 {
-    sizeof(struct d3dkmt_mutex),    /* size */
-    &no_type,                       /* type */
-    d3dkmt_mutex_dump,              /* dump */
-    no_add_queue,                   /* add_queue */
-    NULL,                           /* remove_queue */
-    NULL,                           /* signaled */
-    NULL,                           /* satisfied */
-    no_signal,                      /* signal */
-    no_get_fd,                      /* get_fd */
-    default_get_sync,               /* get_sync */
-    default_map_access,             /* map_access */
-    default_get_sd,                 /* get_sd */
-    default_set_sd,                 /* set_sd */
-    no_get_full_name,               /* get_full_name */
-    no_lookup_name,                 /* lookup_name */
-    no_link_name,                   /* link_name */
-    NULL,                           /* unlink_name */
-    no_open_file,                   /* open_file */
-    no_kernel_obj_list,             /* get_kernel_obj_list */
-    no_close_handle,                /* close_handle */
-    d3dkmt_mutex_destroy,           /* destroy */
+    .size    = sizeof(struct d3dkmt_mutex),
+    .type    = &no_type,
+    .dump    = d3dkmt_mutex_dump,
+    .destroy = d3dkmt_mutex_destroy,
 };
 
 #define DXGK_SHARED_SYNC_QUERY_STATE  0x0001
@@ -170,27 +126,10 @@ static void dxgk_shared_sync_destroy( struct object *obj );
 
 static const struct object_ops dxgk_shared_sync_ops =
 {
-    sizeof(struct dxgk_shared_sync),    /* size */
-    &dxgk_shared_sync_type,             /* type */
-    dxgk_shared_sync_dump,              /* dump */
-    no_add_queue,                       /* add_queue */
-    NULL,                               /* remove_queue */
-    NULL,                               /* signaled */
-    NULL,                               /* satisfied */
-    no_signal,                          /* signal */
-    no_get_fd,                          /* get_fd */
-    default_get_sync,                   /* get_sync */
-    default_map_access,                 /* map_access */
-    default_get_sd,                     /* get_sd */
-    default_set_sd,                     /* set_sd */
-    default_get_full_name,              /* get_full_name */
-    no_lookup_name,                     /* lookup_name */
-    directory_link_name,                /* link_name */
-    default_unlink_name,                /* unlink_name */
-    no_open_file,                       /* open_file */
-    no_kernel_obj_list,                 /* get_kernel_obj_list */
-    no_close_handle,                    /* close_handle */
-    dxgk_shared_sync_destroy,           /* destroy */
+    .size    = sizeof(struct dxgk_shared_sync),
+    .type    = &dxgk_shared_sync_type,
+    .dump    = dxgk_shared_sync_dump,
+    .destroy = dxgk_shared_sync_destroy,
 };
 
 static void dxgk_shared_sync_dump( struct object *obj, int verbose )
@@ -237,27 +176,10 @@ static void dxgk_shared_resource_destroy( struct object *obj );
 
 static const struct object_ops dxgk_shared_resource_ops =
 {
-    sizeof(struct dxgk_shared_resource),    /* size */
-    &dxgk_shared_resource_type,             /* type */
-    dxgk_shared_resource_dump,              /* dump */
-    no_add_queue,                           /* add_queue */
-    NULL,                                   /* remove_queue */
-    NULL,                                   /* signaled */
-    NULL,                                   /* satisfied */
-    no_signal,                              /* signal */
-    no_get_fd,                              /* get_fd */
-    default_get_sync,                       /* get_sync */
-    default_map_access,                     /* map_access */
-    default_get_sd,                         /* get_sd */
-    default_set_sd,                         /* set_sd */
-    default_get_full_name,                  /* get_full_name */
-    no_lookup_name,                         /* lookup_name */
-    directory_link_name,                    /* link_name */
-    default_unlink_name,                    /* unlink_name */
-    no_open_file,                           /* open_file */
-    no_kernel_obj_list,                     /* get_kernel_obj_list */
-    no_close_handle,                        /* close_handle */
-    dxgk_shared_resource_destroy,           /* destroy */
+    .size    = sizeof(struct dxgk_shared_resource),
+    .type    = &dxgk_shared_resource_type,
+    .dump    = dxgk_shared_resource_dump,
+    .destroy = dxgk_shared_resource_destroy,
 };
 
 static void dxgk_shared_resource_dump( struct object *obj, int verbose )
diff --git a/server/debugger.c b/server/debugger.c
index 97f24bb0fb0e..cfd826423abb 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -81,27 +81,11 @@ static void debug_event_destroy( struct object *obj );
 
 static const struct object_ops debug_event_ops =
 {
-    sizeof(struct debug_event),    /* size */
-    &no_type,                      /* type */
-    debug_event_dump,              /* dump */
-    NULL,                          /* add_queue */
-    NULL,                          /* remove_queue */
-    NULL,                          /* signaled */
-    NULL,                          /* satisfied */
-    no_signal,                     /* signal */
-    no_get_fd,                     /* get_fd */
-    debug_event_get_sync,          /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    no_get_full_name,              /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    no_link_name,                  /* link_name */
-    NULL,                          /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    no_close_handle,               /* close_handle */
-    debug_event_destroy            /* destroy */
+    .size     = sizeof(struct debug_event),
+    .type     = &no_type,
+    .dump     = debug_event_dump,
+    .get_sync = debug_event_get_sync,
+    .destroy  = debug_event_destroy,
 };
 
 static void debug_obj_dump( struct object *obj, int verbose );
@@ -110,27 +94,11 @@ static void debug_obj_destroy( struct object *obj );
 
 static const struct object_ops debug_obj_ops =
 {
-    sizeof(struct debug_obj),      /* size */
-    &debug_obj_type,               /* type */
-    debug_obj_dump,                /* dump */
-    NULL,                          /* add_queue */
-    NULL,                          /* remove_queue */
-    NULL,                          /* signaled */
-    NULL,                          /* satisfied */
-    no_signal,                     /* signal */
-    no_get_fd,                     /* get_fd */
-    debug_obj_get_sync,            /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    default_get_full_name,         /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    directory_link_name,           /* link_name */
-    default_unlink_name,           /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    no_close_handle,               /* close_handle */
-    debug_obj_destroy              /* destroy */
+    .size     = sizeof(struct debug_obj),
+    .type     = &debug_obj_type,
+    .dump     = debug_obj_dump,
+    .get_sync = debug_obj_get_sync,
+    .destroy  = debug_obj_destroy,
 };
 
 /* get a pointer to TEB->ArbitraryUserPointer in the client address space */
diff --git a/server/device.c b/server/device.c
index 2a1a9c75a465..9b39e95ea447 100644
--- a/server/device.c
+++ b/server/device.c
@@ -59,27 +59,10 @@ static void irp_call_destroy( struct object *obj );
 
 static const struct object_ops irp_call_ops =
 {
-    sizeof(struct irp_call),          /* size */
-    &no_type,                         /* type */
-    irp_call_dump,                    /* dump */
-    no_add_queue,                     /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    no_get_fd,                        /* get_fd */
-    default_get_sync,                 /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    no_link_name,                     /* link_name */
-    NULL,                             /* unlink_name */
-    no_open_file,                     /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    irp_call_destroy                  /* destroy */
+    .size    = sizeof(struct irp_call),
+    .type    = &no_type,
+    .dump    = irp_call_dump,
+    .destroy = irp_call_destroy,
 };
 
 
@@ -101,27 +84,11 @@ static void device_manager_destroy( struct object *obj );
 
 static const struct object_ops device_manager_ops =
 {
-    sizeof(struct device_manager),    /* size */
-    &no_type,                         /* type */
-    device_manager_dump,              /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    no_get_fd,                        /* get_fd */
-    device_manager_get_sync,          /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    no_get_full_name,                 /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    no_link_name,                     /* link_name */
-    NULL,                             /* unlink_name */
-    no_open_file,                     /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    device_manager_destroy            /* destroy */
+    .size     = sizeof(struct device_manager),
+    .type     = &no_type,
+    .dump     = device_manager_dump,
+    .get_sync = device_manager_get_sync,
+    .destroy  = device_manager_destroy,
 };
 
 
@@ -159,27 +126,12 @@ static struct list *device_get_kernel_obj_list( struct object *obj );
 
 static const struct object_ops device_ops =
 {
-    sizeof(struct device),            /* size */
-    &device_type,                     /* type */
-    device_dump,                      /* dump */
-    no_add_queue,                     /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    no_satisfied,                     /* satisfied */
-    no_signal,                        /* signal */
-    no_get_fd,                        /* get_fd */
-    default_get_sync,                 /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    default_get_full_name,            /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    directory_link_name,              /* link_name */
-    default_unlink_name,              /* unlink_name */
-    device_open_file,                 /* open_file */
-    device_get_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    device_destroy                    /* destroy */
+    .size                = sizeof(struct device),
+    .type                = &device_type,
+    .dump                = device_dump,
+    .open_file           = device_open_file,
+    .get_kernel_obj_list = device_get_kernel_obj_list,
+    .destroy             = device_destroy,
 };
 
 
@@ -212,51 +164,31 @@ static void device_file_get_volume_info( struct fd *fd, struct async *async, uns
 
 static const struct object_ops device_file_ops =
 {
-    sizeof(struct device_file),       /* size */
-    &file_type,                       /* type */
-    device_file_dump,                 /* dump */
-    NULL,                             /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    NULL,                             /* satisfied */
-    no_signal,                        /* signal */
-    device_file_get_fd,               /* get_fd */
-    default_fd_get_sync,              /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    device_file_get_full_name,        /* get_full_name */
-    no_lookup_name,                   /* lookup_name */
-    no_link_name,                     /* link_name */
-    NULL,                             /* unlink_name */
-    no_open_file,                     /* open_file */
-    device_file_get_kernel_obj_list,  /* get_kernel_obj_list */
-    device_file_close_handle,         /* close_handle */
-    device_file_destroy               /* destroy */
+    .size                = sizeof(struct device_file),
+    .type                = &file_type,
+    .dump                = device_file_dump,
+    .get_fd              = device_file_get_fd,
+    .get_sync            = default_fd_get_sync,
+    .get_full_name       = device_file_get_full_name,
+    .get_kernel_obj_list = device_file_get_kernel_obj_list,
+    .close_handle        = device_file_close_handle,
+    .destroy             = device_file_destroy,
 };
 
 static const struct fd_ops device_file_fd_ops =
 {
-    default_fd_get_poll_events,       /* get_poll_events */
-    default_poll_event,               /* poll_event */
-    device_file_get_fd_type,          /* get_fd_type */
-    device_file_read,                 /* read */
-    device_file_write,                /* write */
-    device_file_flush,                /* flush */
-    default_fd_get_file_info,         /* get_file_info */
-    device_file_get_volume_info,      /* get_volume_info */
-    device_file_ioctl,                /* ioctl */
-    device_file_cancel_async,         /* cancel_async */
-    default_fd_queue_async,           /* queue_async */
-    default_fd_reselect_async,        /* reselect_async */
+    .get_fd_type     = device_file_get_fd_type,
+    .read            = device_file_read,
+    .write           = device_file_write,
+    .flush           = device_file_flush,
+    .get_file_info   = default_fd_get_file_info,
+    .get_volume_info = device_file_get_volume_info,
+    .ioctl           = device_file_ioctl,
+    .cancel_async    = device_file_cancel_async,
+    .queue_async     = default_fd_queue_async,
 };
 
 
-struct list *no_kernel_obj_list( struct object *obj )
-{
-    return NULL;
-}
-
 struct kernel_object
 {
     struct device_manager  *manager;
@@ -278,6 +210,7 @@ static struct kernel_object *kernel_object_from_obj( struct device_manager *mana
     struct kernel_object *kernel_object;
     struct list *list;
 
+    if (!obj->ops->get_kernel_obj_list) return NULL;
     if (!(list = obj->ops->get_kernel_obj_list( obj ))) return NULL;
     LIST_FOR_EACH_ENTRY( kernel_object, list, struct kernel_object, list_entry )
     {
@@ -298,6 +231,7 @@ static struct kernel_object *set_kernel_object( struct device_manager *manager,
     struct kernel_object *kernel_object;
     struct list *list;
 
+    if (!obj->ops->get_kernel_obj_list) return NULL;
     if (!(list = obj->ops->get_kernel_obj_list( obj ))) return NULL;
 
     if (!(kernel_object = malloc( sizeof(*kernel_object) ))) return NULL;
@@ -442,10 +376,10 @@ static struct object *device_open_file( struct object *obj, unsigned int access,
     list_add_tail( &device->files, &file->entry );
     if (device->unix_path)
     {
-        if ((fullname = device->obj.ops->get_full_name( &device->obj, ~0u, &nt_name.len )))
+        if ((fullname = default_get_full_name( &device->obj, ~0u, &nt_name.len )))
         {
             mode_t mode = 0666;
-            access = file->obj.ops->map_access( &file->obj, access );
+            access = map_obj_access( &file->obj, access );
             nt_name.str = fullname;
             file->fd = open_fd( NULL, device->unix_path, nt_name, O_NONBLOCK, &mode, access, sharing, options );
             if (file->fd) set_fd_user( file->fd, &device_file_fd_ops, &file->obj );
@@ -507,7 +441,7 @@ static struct fd *device_file_get_fd( struct object *obj )
 static WCHAR *device_file_get_full_name( struct object *obj, data_size_t max, data_size_t *len )
 {
     struct device_file *file = (struct device_file *)obj;
-    WCHAR *ret = file->device->obj.ops->get_full_name( &file->device->obj, max, len );
+    WCHAR *ret = default_get_full_name( &file->device->obj, max, len );
     if (*len > max) set_error( STATUS_BUFFER_OVERFLOW );
     return ret;
 }
@@ -860,6 +794,7 @@ void free_kernel_objects( struct object *obj )
 {
     struct list *ptr, *list;
 
+    if (!obj->ops->get_kernel_obj_list) return;
     if (!(list = obj->ops->get_kernel_obj_list( obj ))) return;
 
     while ((ptr = list_head( list )))
diff --git a/server/directory.c b/server/directory.c
index 091ceb84c719..323da8bd9e61 100644
--- a/server/directory.c
+++ b/server/directory.c
@@ -62,27 +62,9 @@ static void object_type_dump( struct object *obj, int verbose );
 
 static const struct object_ops object_type_ops =
 {
-    sizeof(struct object_type),   /* size */
-    &objtype_type,                /* type */
-    object_type_dump,             /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    default_get_full_name,        /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    directory_link_name,          /* link_name */
-    default_unlink_name,          /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    no_destroy                    /* destroy */
+    .size = sizeof(struct object_type),
+    .type = &objtype_type,
+    .dump = object_type_dump,
 };
 
 
@@ -113,27 +95,11 @@ static void directory_destroy( struct object *obj );
 
 static const struct object_ops directory_ops =
 {
-    sizeof(struct directory),     /* size */
-    &directory_type,              /* type */
-    directory_dump,               /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    default_get_full_name,        /* get_full_name */
-    directory_lookup_name,        /* lookup_name */
-    directory_link_name,          /* link_name */
-    default_unlink_name,          /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    directory_destroy             /* destroy */
+    .size        = sizeof(struct directory),
+    .type        = &directory_type,
+    .dump        = directory_dump,
+    .lookup_name = directory_lookup_name,
+    .destroy     = directory_destroy,
 };
 
 static struct directory *root_directory;
@@ -164,6 +130,7 @@ static struct type_descr *types[] =
     &key_type,
     &apc_reserve_type,
     &completion_reserve_type,
+    &alpc_port_type,
 };
 
 static void object_type_dump( struct object *obj, int verbose )
@@ -428,14 +395,18 @@ void init_directories( struct fd *intl_fd )
     static const WCHAR event_high_pagedW[] = {'H','i','g','h','P','a','g','e','d','P','o','o','l','C','o','n','d','i','t','i','o','n'};
     static const WCHAR event_high_nonpgW[] = {'H','i','g','h','N','o','n','P','a','g','e','d','P','o','o','l','C','o','n','d','i','t','i','o','n'};
     static const WCHAR keyed_event_crit_sectW[] = {'C','r','i','t','S','e','c','O','u','t','O','f','M','e','m','o','r','y','E','v','e','n','t'};
-    static const struct unicode_str kernel_events[] =
+    static const struct
     {
-        { event_low_memW, sizeof(event_low_memW) },
-        { event_low_pagedW, sizeof(event_low_pagedW) },
-        { event_low_nonpgW, sizeof(event_low_nonpgW) },
-        { event_high_memW, sizeof(event_high_memW) },
-        { event_high_pagedW, sizeof(event_high_pagedW) },
-        { event_high_nonpgW, sizeof(event_high_nonpgW) }
+        struct unicode_str name;
+        int initial_state;
+    } kernel_events[] =
+    {
+        { { event_low_memW, sizeof(event_low_memW) }, 0 },
+        { { event_low_pagedW, sizeof(event_low_pagedW) }, 0 },
+        { { event_low_nonpgW, sizeof(event_low_nonpgW) }, 0 },
+        { { event_high_memW, sizeof(event_high_memW) }, 1 },
+        { { event_high_pagedW, sizeof(event_high_pagedW) }, 1 },
+        { { event_high_nonpgW, sizeof(event_high_nonpgW) }, 1 }
     };
     static const struct unicode_str keyed_event_crit_sect_str = {keyed_event_crit_sectW, sizeof(keyed_event_crit_sectW)};
 
@@ -489,7 +460,10 @@ void init_directories( struct fd *intl_fd )
 
     /* events */
     for (i = 0; i < ARRAY_SIZE( kernel_events ); i++)
-        release_object( create_event( &dir_kernel->obj, &kernel_events[i], OBJ_PERMANENT, 1, 0, NULL ));
+    {
+        release_object( create_event( &dir_kernel->obj, &kernel_events[i].name, OBJ_PERMANENT,
+                                      1, kernel_events[i].initial_state, NULL ));
+    }
     release_object( create_keyed_event( &dir_kernel->obj, &keyed_event_crit_sect_str, OBJ_PERMANENT, NULL ));
 
     /* mappings */
diff --git a/server/event.c b/server/event.c
index cbc7af10c0a8..150ec13aa4ca 100644
--- a/server/event.c
+++ b/server/event.c
@@ -63,27 +63,14 @@ static int event_sync_signal( struct object *obj, unsigned int access, int signa
 
 static const struct object_ops event_sync_ops =
 {
-    sizeof(struct event_sync), /* size */
-    &no_type,                  /* type */
-    event_sync_dump,           /* dump */
-    add_queue,                 /* add_queue */
-    remove_queue,              /* remove_queue */
-    event_sync_signaled,       /* signaled */
-    event_sync_satisfied,      /* satisfied */
-    event_sync_signal,         /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    no_destroy                 /* destroy */
+    .size         = sizeof(struct event_sync),
+    .type         = &no_type,
+    .dump         = event_sync_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .signaled     = event_sync_signaled,
+    .satisfied    = event_sync_satisfied,
+    .signal       = event_sync_signal,
 };
 
 static struct object *create_event_sync( int manual, int signaled )
@@ -164,27 +151,13 @@ static void event_destroy( struct object *obj );
 
 static const struct object_ops event_ops =
 {
-    sizeof(struct event),      /* size */
-    &event_type,               /* type */
-    event_dump,                /* dump */
-    NULL,                      /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    event_signal,              /* signal */
-    no_get_fd,                 /* get_fd */
-    event_get_sync,            /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    event_get_kernel_obj_list, /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    event_destroy,             /* destroy */
+    .size                = sizeof(struct event),
+    .type                = &event_type,
+    .dump                = event_dump,
+    .signal              = event_signal,
+    .get_sync            = event_get_sync,
+    .get_kernel_obj_list = event_get_kernel_obj_list,
+    .destroy             = event_destroy,
 };
 
 
@@ -212,27 +185,12 @@ static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *en
 
 static const struct object_ops keyed_event_ops =
 {
-    sizeof(struct keyed_event),  /* size */
-    &keyed_event_type,           /* type */
-    keyed_event_dump,            /* dump */
-    add_queue,                   /* add_queue */
-    remove_queue,                /* remove_queue */
-    keyed_event_signaled,        /* signaled */
-    no_satisfied,                /* satisfied */
-    no_signal,                   /* signal */
-    no_get_fd,                   /* get_fd */
-    default_get_sync,            /* get_sync */
-    default_map_access,          /* map_access */
-    default_get_sd,              /* get_sd */
-    default_set_sd,              /* set_sd */
-    default_get_full_name,       /* get_full_name */
-    no_lookup_name,              /* lookup_name */
-    directory_link_name,         /* link_name */
-    default_unlink_name,         /* unlink_name */
-    no_open_file,                /* open_file */
-    no_kernel_obj_list,          /* get_kernel_obj_list */
-    no_close_handle,             /* close_handle */
-    no_destroy                   /* destroy */
+    .size         = sizeof(struct keyed_event),
+    .type         = &keyed_event_type,
+    .dump         = keyed_event_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .signaled     = keyed_event_signaled,
 };
 
 
diff --git a/server/fd.c b/server/fd.c
index b6012161f7c9..b5a7d13befdb 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -169,27 +169,11 @@ static void fd_destroy( struct object *obj );
 
 static const struct object_ops fd_ops =
 {
-    sizeof(struct fd),        /* size */
-    &no_type,                 /* type */
-    fd_dump,                  /* dump */
-    NULL,                     /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    no_get_fd,                /* get_fd */
-    fd_get_sync,              /* get_sync */
-    default_map_access,       /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
-    no_get_full_name,         /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    no_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,          /* close_handle */
-    fd_destroy                /* destroy */
+    .size     = sizeof(struct fd),
+    .type     = &no_type,
+    .dump     = fd_dump,
+    .get_sync = fd_get_sync,
+    .destroy  = fd_destroy,
 };
 
 /* device object */
@@ -211,27 +195,10 @@ static void device_destroy( struct object *obj );
 
 static const struct object_ops device_ops =
 {
-    sizeof(struct device),    /* size */
-    &no_type,                 /* type */
-    device_dump,              /* dump */
-    no_add_queue,             /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    no_get_fd,                /* get_fd */
-    default_get_sync,         /* get_sync */
-    default_map_access,       /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
-    no_get_full_name,         /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    no_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,          /* close_handle */
-    device_destroy            /* destroy */
+    .size    = sizeof(struct device),
+    .type    = &no_type,
+    .dump    = device_dump,
+    .destroy = device_destroy,
 };
 
 /* inode object */
@@ -252,27 +219,10 @@ static void inode_destroy( struct object *obj );
 
 static const struct object_ops inode_ops =
 {
-    sizeof(struct inode),     /* size */
-    &no_type,                 /* type */
-    inode_dump,               /* dump */
-    no_add_queue,             /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    no_get_fd,                /* get_fd */
-    default_get_sync,         /* get_sync */
-    default_map_access,       /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
-    no_get_full_name,         /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    no_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,          /* close_handle */
-    inode_destroy             /* destroy */
+    .size    = sizeof(struct inode),
+    .type    = &no_type,
+    .dump    = inode_dump,
+    .destroy = inode_destroy,
 };
 
 /* file lock object */
@@ -297,27 +247,11 @@ static void file_lock_destroy( struct object *obj );
 
 static const struct object_ops file_lock_ops =
 {
-    sizeof(struct file_lock),   /* size */
-    &no_type,                   /* type */
-    file_lock_dump,             /* dump */
-    NULL,                       /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    NULL,                       /* satisfied */
-    no_signal,                  /* signal */
-    no_get_fd,                  /* get_fd */
-    file_lock_get_sync,         /* get_sync */
-    default_map_access,         /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    no_get_full_name,           /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    no_link_name,               /* link_name */
-    NULL,                       /* unlink_name */
-    no_open_file,               /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    file_lock_destroy,          /* destroy */
+    .size     = sizeof(struct file_lock),
+    .type     = &no_type,
+    .dump     = file_lock_dump,
+    .get_sync = file_lock_get_sync,
+    .destroy  = file_lock_destroy,
 };
 
 
@@ -527,7 +461,8 @@ static int get_next_timeout( struct timespec *ts );
 
 static inline void fd_poll_event( struct fd *fd, int event )
 {
-    fd->fd_ops->poll_event( fd, event );
+    if (fd->fd_ops->poll_event) fd->fd_ops->poll_event( fd, event );
+    else default_poll_event( fd, event );
 }
 
 #ifdef USE_EPOLL
@@ -1691,6 +1626,13 @@ void set_fd_events( struct fd *fd, int events )
     }
 }
 
+/* get the events we want to poll() for */
+static int get_poll_events( struct fd *fd )
+{
+    if (fd->fd_ops->get_poll_events) return fd->fd_ops->get_poll_events( fd );
+    return default_fd_get_poll_events( fd );
+}
+
 /* prepare an fd for unmounting its corresponding device */
 static inline void unmount_fd( struct fd *fd )
 {
@@ -2255,7 +2197,7 @@ void default_poll_event( struct fd *fd, int event )
 
     /* if an error occurred, stop polling this fd to avoid busy-looping */
     if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 );
-    else if (!fd->inode) set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) );
+    else if (!fd->inode) set_fd_events( fd, get_poll_events( fd ) );
 }
 
 void fd_queue_async( struct fd *fd, struct async *async, int type )
@@ -2283,7 +2225,7 @@ void fd_queue_async( struct fd *fd, struct async *async, int type )
     if (type != ASYNC_TYPE_WAIT)
     {
         if (!fd->inode)
-            set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) );
+            set_fd_events( fd, get_poll_events( fd ) );
         else  /* regular files are always ready for read and write */
             async_wake_up( queue, STATUS_ALERTED );
     }
@@ -2309,22 +2251,14 @@ void fd_async_wake_up( struct fd *fd, int type, unsigned int status )
 
 void fd_cancel_async( struct fd *fd, struct async *async )
 {
-    fd->fd_ops->cancel_async( fd, async );
+    if (fd->fd_ops->cancel_async) fd->fd_ops->cancel_async( fd, async );
+    else async_terminate( async, STATUS_CANCELLED );
 }
 
 void fd_reselect_async( struct fd *fd, struct async_queue *queue )
 {
-    fd->fd_ops->reselect_async( fd, queue );
-}
-
-void no_fd_queue_async( struct fd *fd, struct async *async, int type, int count )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
-void default_fd_cancel_async( struct fd *fd, struct async *async )
-{
-    async_terminate( async, STATUS_CANCELLED );
+    if (fd->fd_ops->reselect_async) fd->fd_ops->reselect_async( fd, queue );
+    else default_fd_reselect_async( fd, queue );
 }
 
 void default_fd_queue_async( struct fd *fd, struct async *async, int type, int count )
@@ -2338,9 +2272,9 @@ void default_fd_reselect_async( struct fd *fd, struct async_queue *queue )
 {
     if (queue == &fd->read_q || queue == &fd->write_q)
     {
-        int poll_events = fd->fd_ops->get_poll_events( fd );
+        int poll_events = get_poll_events( fd );
         int events = check_fd_events( fd, poll_events );
-        if (events) fd->fd_ops->poll_event( fd, events );
+        if (events) fd_poll_event( fd, events );
         else set_fd_events( fd, poll_events );
     }
 }
@@ -2625,30 +2559,6 @@ static void delete_reparse_point( struct fd *fd, struct async *async )
     xattr_fremove( fd->unix_fd, XATTR_REPARSE );
 }
 
-/* default read() routine */
-void no_fd_read( struct fd *fd, struct async *async, file_pos_t pos )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
-/* default write() routine */
-void no_fd_write( struct fd *fd, struct async *async, file_pos_t pos )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
-/* default flush() routine */
-void no_fd_flush( struct fd *fd, struct async *async )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
-/* default get_file_info() routine */
-void no_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
 /* default get_file_info() routine */
 void default_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class )
 {
@@ -2722,18 +2632,6 @@ void default_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int
     }
 }
 
-/* default get_volume_info() routine */
-void no_fd_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
-/* default ioctl() routine */
-void no_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-}
-
 /* default ioctl() routine */
 void default_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
 {
@@ -3046,7 +2944,8 @@ DECL_HANDLER(flush)
 
     if ((async = create_request_async( fd, fd->comp_flags, &req->async, 0 )))
     {
-        fd->fd_ops->flush( fd, async );
+        if (fd->fd_ops->flush) fd->fd_ops->flush( fd, async );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         reply->event = async_handoff( async, NULL, 1 );
         release_object( async );
     }
@@ -3060,7 +2959,8 @@ DECL_HANDLER(get_file_info)
 
     if (fd)
     {
-        fd->fd_ops->get_file_info( fd, req->handle, req->info_class );
+        if (fd->fd_ops->get_file_info) fd->fd_ops->get_file_info( fd, req->handle, req->info_class );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         release_object( fd );
     }
 }
@@ -3075,7 +2975,8 @@ DECL_HANDLER(get_volume_info)
 
     if ((async = create_request_async( fd, fd->comp_flags, &req->async, 0 )))
     {
-        fd->fd_ops->get_volume_info( fd, async, req->info_class );
+        if (fd->fd_ops->get_volume_info) fd->fd_ops->get_volume_info( fd, async, req->info_class );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         reply->wait = async_handoff( async, NULL, 1 );
         release_object( async );
     }
@@ -3094,7 +2995,8 @@ DECL_HANDLER(open_file_object)
     if (root) release_object( root );
     if (!obj) return;
 
-    if ((result = obj->ops->open_file( obj, req->access, req->sharing, req->options )))
+    if (!obj->ops->open_file) set_error( STATUS_OBJECT_TYPE_MISMATCH );
+    else if ((result = obj->ops->open_file( obj, req->access, req->sharing, req->options )))
     {
         reply->handle = alloc_handle( current->process, result, req->access, req->attributes );
         release_object( result );
@@ -3151,7 +3053,8 @@ DECL_HANDLER(read)
 
     if ((async = create_request_async( fd, fd->comp_flags, &req->async, 0 )))
     {
-        fd->fd_ops->read( fd, async, req->pos );
+        if (fd->fd_ops->read) fd->fd_ops->read( fd, async, req->pos );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         reply->wait = async_handoff( async, NULL, 0 );
         reply->options = fd->options;
         release_object( async );
@@ -3169,7 +3072,8 @@ DECL_HANDLER(write)
 
     if ((async = create_request_async( fd, fd->comp_flags, &req->async, 0 )))
     {
-        fd->fd_ops->write( fd, async, req->pos );
+        if (fd->fd_ops->write) fd->fd_ops->write( fd, async, req->pos );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         reply->wait = async_handoff( async, &reply->size, 0 );
         reply->options = fd->options;
         release_object( async );
@@ -3188,7 +3092,8 @@ DECL_HANDLER(ioctl)
 
     if ((async = create_request_async( fd, fd->comp_flags, &req->async, 0 )))
     {
-        fd->fd_ops->ioctl( fd, req->code, async );
+        if (fd->fd_ops->ioctl) fd->fd_ops->ioctl( fd, req->code, async );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         reply->wait = async_handoff( async, NULL, 0 );
         reply->options = fd->options;
         release_object( async );
@@ -3218,7 +3123,8 @@ DECL_HANDLER(register_async)
 
     if ((fd = get_handle_fd_obj( current->process, req->async.handle, access )))
     {
-        if (get_unix_fd( fd ) != -1 && (async = create_async( fd, current, &req->async, NULL )))
+        if (!fd->fd_ops->queue_async) set_error( STATUS_OBJECT_TYPE_MISMATCH );
+        else if (get_unix_fd( fd ) != -1 && (async = create_async( fd, current, &req->async, NULL )))
         {
             fd->fd_ops->queue_async( fd, async, req->type, req->count );
             release_object( async );
diff --git a/server/file.c b/server/file.c
index 7b3324e99389..441bdc0e83cc 100644
--- a/server/file.c
+++ b/server/file.c
@@ -87,43 +87,26 @@ static enum server_fd_type file_get_fd_type( struct fd *fd );
 
 static const struct object_ops file_ops =
 {
-    sizeof(struct file),          /* size */
-    &file_type,                   /* type */
-    file_dump,                    /* dump */
-    NULL,                         /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    file_get_fd,                  /* get_fd */
-    default_fd_get_sync,          /* get_sync */
-    default_map_access,           /* map_access */
-    file_get_sd,                  /* get_sd */
-    file_set_sd,                  /* set_sd */
-    default_fd_get_full_name,     /* get_full_name */
-    file_lookup_name,             /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    file_open_file,               /* open_file */
-    file_get_kernel_obj_list,     /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    file_destroy                  /* destroy */
+    .size                = sizeof(struct file),
+    .type                = &file_type,
+    .dump                = file_dump,
+    .get_fd              = file_get_fd,
+    .get_sync            = default_fd_get_sync,
+    .get_sd              = file_get_sd,
+    .set_sd              = file_set_sd,
+    .get_full_name       = default_fd_get_full_name,
+    .lookup_name         = file_lookup_name,
+    .open_file           = file_open_file,
+    .get_kernel_obj_list = file_get_kernel_obj_list,
+    .destroy             = file_destroy,
 };
 
 static const struct fd_ops file_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    file_get_fd_type,             /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    default_fd_get_file_info,     /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    default_fd_ioctl,             /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    default_fd_queue_async,       /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type   = file_get_fd_type,
+    .get_file_info = default_fd_get_file_info,
+    .ioctl         = default_fd_ioctl,
+    .queue_async   = default_fd_queue_async,
 };
 
 /* create a file from a file descriptor */
diff --git a/server/file.h b/server/file.h
index e1485e4d5fcd..030db069e7b3 100644
--- a/server/file.h
+++ b/server/file.h
@@ -116,23 +116,13 @@ extern void fd_cancel_async( struct fd *fd, struct async *async );
 extern void fd_queue_async( struct fd *fd, struct async *async, int type );
 extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status );
 extern void fd_reselect_async( struct fd *fd, struct async_queue *queue );
-extern void no_fd_read( struct fd *fd, struct async *async, file_pos_t pos );
-extern void no_fd_write( struct fd *fd, struct async *async, file_pos_t pos );
-extern void no_fd_flush( struct fd *fd, struct async *async );
-extern void no_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class );
 extern void default_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class );
-extern void no_fd_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class );
-extern void no_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
 extern void default_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
-extern void default_fd_cancel_async( struct fd *fd, struct async *async );
-extern void no_fd_queue_async( struct fd *fd, struct async *async, int type, int count );
 extern void default_fd_queue_async( struct fd *fd, struct async *async, int type, int count );
 extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue );
 extern void main_loop(void);
 extern void remove_process_locks( struct process *process );
 
-static inline struct fd *get_obj_fd( struct object *obj ) { return obj->ops->get_fd( obj ); }
-
 /* timeout functions */
 
 struct timeout_user;
diff --git a/server/handle.c b/server/handle.c
index a51a794191c0..8adad86911f8 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -119,27 +119,10 @@ static void handle_table_destroy( struct object *obj );
 
 static const struct object_ops handle_table_ops =
 {
-    sizeof(struct handle_table),     /* size */
-    &no_type,                        /* type */
-    handle_table_dump,               /* dump */
-    no_add_queue,                    /* add_queue */
-    NULL,                            /* remove_queue */
-    NULL,                            /* signaled */
-    NULL,                            /* satisfied */
-    no_signal,                       /* signal */
-    no_get_fd,                       /* get_fd */
-    default_get_sync,                /* get_sync */
-    default_map_access,              /* map_access */
-    default_get_sd,                  /* get_sd */
-    default_set_sd,                  /* set_sd */
-    no_get_full_name,                /* get_full_name */
-    no_lookup_name,                  /* lookup_name */
-    no_link_name,                    /* link_name */
-    NULL,                            /* unlink_name */
-    no_open_file,                    /* open_file */
-    no_kernel_obj_list,              /* get_kernel_obj_list */
-    no_close_handle,                 /* close_handle */
-    handle_table_destroy             /* destroy */
+    .size    = sizeof(struct handle_table),
+    .type    = &no_type,
+    .dump    = handle_table_dump,
+    .destroy = handle_table_destroy,
 };
 
 /* dump a handle table */
@@ -180,7 +163,7 @@ static void handle_table_destroy( struct object *obj )
         entry->ptr = NULL;
         if (obj)
         {
-            if (table->process)
+            if (table->process && obj->ops->close_handle)
                 obj->ops->close_handle( obj, table->process, index_to_handle(i) );
             release_object_from_handle( obj );
         }
@@ -273,7 +256,7 @@ obj_handle_t alloc_handle_no_access_check( struct process *process, void *ptr, u
 {
     struct object *obj = ptr;
     if (access & MAXIMUM_ALLOWED) access = GENERIC_ALL;
-    access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
+    access = map_obj_access( obj, access ) & ~RESERVED_ALL;
     return alloc_handle_entry( process, ptr, access, attr );
 }
 
@@ -284,7 +267,7 @@ obj_handle_t alloc_handle( struct process *process, void *ptr, unsigned int acce
 {
     struct object *obj = ptr;
 
-    if (!(access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL))
+    if (!(access = map_obj_access( obj, access ) & ~RESERVED_ALL))
     {
         set_error( STATUS_ACCESS_DENIED );
         return 0;
@@ -433,7 +416,8 @@ unsigned int close_handle( struct process *process, obj_handle_t handle )
     if (!(entry = get_handle( process, handle ))) return STATUS_INVALID_HANDLE;
     if (entry->access & RESERVED_CLOSE_PROTECT) return STATUS_HANDLE_NOT_CLOSABLE;
     obj = entry->ptr;
-    if (!obj->ops->close_handle( obj, process, handle )) return STATUS_HANDLE_NOT_CLOSABLE;
+    if (obj->ops->close_handle && !obj->ops->close_handle( obj, process, handle ))
+        return STATUS_HANDLE_NOT_CLOSABLE;
 
     table = handle_is_global(handle) ? global_table : process->handles;
     table->entries[index].ptr = NULL;
@@ -581,14 +565,14 @@ obj_handle_t duplicate_handle( struct process *src, obj_handle_t src_handle, str
     if ((entry = get_handle( src, src_handle )))
         src_access = entry->access;
     else  /* pseudo-handle, give it full access */
-        src_access = obj->ops->map_access( obj, GENERIC_ALL );
+        src_access = map_obj_access( obj, GENERIC_ALL );
     src_flags = (src_access & RESERVED_ALL) >> RESERVED_SHIFT;
     src_access &= ~RESERVED_ALL;
 
     if (options & DUPLICATE_SAME_ACCESS)
         access = src_access;
     else
-        access = obj->ops->map_access( obj, access ) & ~RESERVED_ALL;
+        access = map_obj_access( obj, access ) & ~RESERVED_ALL;
 
     /* asking for the more access rights than src_access? */
     if (access & ~src_access)
@@ -724,8 +708,12 @@ DECL_HANDLER(get_object_name)
 
     if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return;
 
-    if ((name = obj->ops->get_full_name( obj, get_reply_max_size(), &reply->total )))
-        set_reply_data_ptr( name, min( reply->total, get_reply_max_size() ));
+    if (obj->ops->get_full_name)
+        name = obj->ops->get_full_name( obj, get_reply_max_size(), &reply->total );
+    else
+        name = default_get_full_name( obj, get_reply_max_size(), &reply->total );
+
+    if (name) set_reply_data_ptr( name, min( reply->total, get_reply_max_size() ));
     release_object( obj );
 }
 
@@ -753,7 +741,9 @@ DECL_HANDLER(set_security_object)
 
     if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
 
-    obj->ops->set_sd( obj, sd, req->security_info );
+    if (obj->ops->set_sd) obj->ops->set_sd( obj, sd, req->security_info );
+    else default_set_sd( obj, sd, req->security_info );
+
     release_object( obj );
 }
 
@@ -773,7 +763,7 @@ DECL_HANDLER(get_security_object)
 
     if (!(obj = get_handle_obj( current->process, req->handle, access, NULL ))) return;
 
-    sd = obj->ops->get_sd( obj );
+    sd = obj->ops->get_sd ? obj->ops->get_sd( obj ) : obj->sd;
     if (sd)
     {
         req_sd.control = sd->control & ~SE_SELF_RELATIVE;
diff --git a/server/hook.c b/server/hook.c
index 2423f182c472..0a7222963160 100644
--- a/server/hook.c
+++ b/server/hook.c
@@ -69,27 +69,10 @@ static void hook_table_destroy( struct object *obj );
 
 static const struct object_ops hook_table_ops =
 {
-    sizeof(struct hook_table),    /* size */
-    &no_type,                     /* type */
-    hook_table_dump,              /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    no_get_full_name,             /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    hook_table_destroy            /* destroy */
+    .size    = sizeof(struct hook_table),
+    .type    = &no_type,
+    .dump    = hook_table_dump,
+    .destroy = hook_table_destroy,
 };
 
 
diff --git a/server/inproc_sync.c b/server/inproc_sync.c
index ef68ee049029..522d9a4e3201 100644
--- a/server/inproc_sync.c
+++ b/server/inproc_sync.c
@@ -67,27 +67,11 @@ static void inproc_sync_destroy( struct object *obj );
 
 static const struct object_ops inproc_sync_ops =
 {
-    sizeof(struct inproc_sync), /* size */
-    &no_type,                   /* type */
-    inproc_sync_dump,           /* dump */
-    no_add_queue,               /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    NULL,                       /* satisfied */
-    inproc_sync_signal,         /* signal */
-    no_get_fd,                  /* get_fd */
-    default_get_sync,           /* get_sync */
-    default_map_access,         /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    default_get_full_name,      /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    directory_link_name,        /* link_name */
-    default_unlink_name,        /* unlink_name */
-    no_open_file,               /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    inproc_sync_destroy,        /* destroy */
+    .size    = sizeof(struct inproc_sync),
+    .type    = &no_type,
+    .dump    = inproc_sync_dump,
+    .signal  = inproc_sync_signal,
+    .destroy = inproc_sync_destroy,
 };
 
 int get_inproc_sync_fd( struct inproc_sync *sync )
diff --git a/server/mailslot.c b/server/mailslot.c
index b16040ed7c39..2ab42d4e2bc5 100644
--- a/server/mailslot.c
+++ b/server/mailslot.c
@@ -75,27 +75,16 @@ static void mailslot_destroy( struct object * );
 
 static const struct object_ops mailslot_ops =
 {
-    sizeof(struct mailslot),   /* size */
-    &file_type,                /* type */
-    mailslot_dump,             /* dump */
-    NULL,                      /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    mailslot_get_fd,           /* get_fd */
-    default_fd_get_sync,       /* get_sync */
-    mailslot_map_access,       /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    mailslot_get_full_name,    /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    mailslot_link_name,        /* link_name */
-    default_unlink_name,       /* unlink_name */
-    mailslot_open_file,        /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    mailslot_destroy           /* destroy */
+    .size          = sizeof(struct mailslot),
+    .type          = &file_type,
+    .dump          = mailslot_dump,
+    .get_fd        = mailslot_get_fd,
+    .get_sync      = default_fd_get_sync,
+    .map_access    = mailslot_map_access,
+    .get_full_name = mailslot_get_full_name,
+    .link_name     = mailslot_link_name,
+    .open_file     = mailslot_open_file,
+    .destroy       = mailslot_destroy,
 };
 
 static enum server_fd_type mailslot_get_fd_type( struct fd *fd );
@@ -105,18 +94,11 @@ static void mailslot_get_file_info( struct fd *fd, obj_handle_t handle, unsigned
 
 static const struct fd_ops mailslot_fd_ops =
 {
-    default_fd_get_poll_events, /* get_poll_events */
-    default_poll_event,         /* poll_event */
-    mailslot_get_fd_type,       /* get_fd_type */
-    mailslot_read,              /* read */
-    mailslot_write,             /* write */
-    no_fd_flush,                /* flush */
-    mailslot_get_file_info,     /* get_file_info */
-    no_fd_get_volume_info,      /* get_volume_info */
-    default_fd_ioctl,           /* ioctl */
-    default_fd_cancel_async,    /* cancel_async */
-    no_fd_queue_async,          /* queue_async */
-    default_fd_reselect_async   /* reselect_async */
+    .get_fd_type   = mailslot_get_fd_type,
+    .read          = mailslot_read,
+    .write         = mailslot_write,
+    .get_file_info = mailslot_get_file_info,
+    .ioctl         = default_fd_ioctl,
 };
 
 
@@ -137,27 +119,12 @@ static void mail_writer_destroy( struct object *obj);
 
 static const struct object_ops mail_writer_ops =
 {
-    sizeof(struct mail_writer), /* size */
-    &file_type,                 /* type */
-    mail_writer_dump,           /* dump */
-    no_add_queue,               /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    NULL,                       /* satisfied */
-    no_signal,                  /* signal */
-    mail_writer_get_fd,         /* get_fd */
-    default_get_sync,           /* get_sync */
-    mail_writer_map_access,     /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    no_get_full_name,           /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    no_link_name,               /* link_name */
-    NULL,                       /* unlink_name */
-    no_open_file,               /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    mail_writer_destroy         /* destroy */
+    .size       = sizeof(struct mail_writer),
+    .type       = &file_type,
+    .dump       = mail_writer_dump,
+    .get_fd     = mail_writer_get_fd,
+    .map_access = mail_writer_map_access,
+    .destroy    = mail_writer_destroy,
 };
 
 static enum server_fd_type mail_writer_get_fd_type( struct fd *fd );
@@ -166,18 +133,12 @@ static void mail_writer_write( struct fd *fd, struct async *async, file_pos_t po
 
 static const struct fd_ops mail_writer_fd_ops =
 {
-    default_fd_get_poll_events,  /* get_poll_events */
-    default_poll_event,          /* poll_event */
-    mail_writer_get_fd_type,     /* get_fd_type */
-    mail_writer_read,            /* read */
-    mail_writer_write,           /* write */
-    no_fd_flush,                 /* flush */
-    default_fd_get_file_info,    /* get_file_info */
-    no_fd_get_volume_info,       /* get_volume_info */
-    default_fd_ioctl,            /* ioctl */
-    default_fd_cancel_async,     /* cancel_async */
-    default_fd_queue_async,      /* queue_async */
-    default_fd_reselect_async    /* reselect_async */
+    .get_fd_type   = mail_writer_get_fd_type,
+    .read          = mail_writer_read,
+    .write         = mail_writer_write,
+    .get_file_info = default_fd_get_file_info,
+    .ioctl         = default_fd_ioctl,
+    .queue_async   = default_fd_queue_async,
 };
 
 
@@ -203,27 +164,12 @@ static void mailslot_device_destroy( struct object *obj );
 
 static const struct object_ops mailslot_device_ops =
 {
-    sizeof(struct mailslot_device), /* size */
-    &device_type,                   /* type */
-    mailslot_device_dump,           /* dump */
-    no_add_queue,                   /* add_queue */
-    NULL,                           /* remove_queue */
-    NULL,                           /* signaled */
-    no_satisfied,                   /* satisfied */
-    no_signal,                      /* signal */
-    no_get_fd,                      /* get_fd */
-    default_get_sync,               /* get_sync */
-    default_map_access,             /* map_access */
-    default_get_sd,                 /* get_sd */
-    default_set_sd,                 /* set_sd */
-    default_get_full_name,          /* get_full_name */
-    mailslot_device_lookup_name,    /* lookup_name */
-    directory_link_name,            /* link_name */
-    default_unlink_name,            /* unlink_name */
-    mailslot_device_open_file,      /* open_file */
-    no_kernel_obj_list,             /* get_kernel_obj_list */
-    no_close_handle,                /* close_handle */
-    mailslot_device_destroy         /* destroy */
+    .size        = sizeof(struct mailslot_device),
+    .type        = &device_type,
+    .dump        = mailslot_device_dump,
+    .lookup_name = mailslot_device_lookup_name,
+    .open_file   = mailslot_device_open_file,
+    .destroy     = mailslot_device_destroy,
 };
 
 static void mailslot_device_file_dump( struct object *obj, int verbose );
@@ -234,43 +180,21 @@ static enum server_fd_type mailslot_device_file_get_fd_type( struct fd *fd );
 
 static const struct object_ops mailslot_device_file_ops =
 {
-    sizeof(struct mailslot_device_file),    /* size */
-    &file_type,                             /* type */
-    mailslot_device_file_dump,              /* dump */
-    NULL,                                   /* add_queue */
-    NULL,                                   /* remove_queue */
-    NULL,                                   /* signaled */
-    NULL,                                   /* satisfied */
-    no_signal,                              /* signal */
-    mailslot_device_file_get_fd,            /* get_fd */
-    default_fd_get_sync,                    /* get_sync */
-    default_map_access,                     /* map_access */
-    default_get_sd,                         /* get_sd */
-    default_set_sd,                         /* set_sd */
-    mailslot_device_file_get_full_name,     /* get_full_name */
-    no_lookup_name,                         /* lookup_name */
-    no_link_name,                           /* link_name */
-    NULL,                                   /* unlink_name */
-    no_open_file,                           /* open_file */
-    no_kernel_obj_list,                     /* get_kernel_obj_list */
-    no_close_handle,                        /* close_handle */
-    mailslot_device_file_destroy            /* destroy */
+    .size          = sizeof(struct mailslot_device_file),
+    .type          = &file_type,
+    .dump          = mailslot_device_file_dump,
+    .get_fd        = mailslot_device_file_get_fd,
+    .get_sync      = default_fd_get_sync,
+    .get_full_name = mailslot_device_file_get_full_name,
+    .destroy       = mailslot_device_file_destroy,
 };
 
 static const struct fd_ops mailslot_device_fd_ops =
 {
-    default_fd_get_poll_events,         /* get_poll_events */
-    default_poll_event,                 /* poll_event */
-    mailslot_device_file_get_fd_type,   /* get_fd_type */
-    no_fd_read,                         /* read */
-    no_fd_write,                        /* write */
-    no_fd_flush,                        /* flush */
-    default_fd_get_file_info,           /* get_file_info */
-    no_fd_get_volume_info,              /* get_volume_info */
-    default_fd_ioctl,                   /* ioctl */
-    default_fd_cancel_async,            /* cancel_async */
-    default_fd_queue_async,             /* queue_async */
-    default_fd_reselect_async           /* reselect_async */
+    .get_fd_type   = mailslot_device_file_get_fd_type,
+    .get_file_info = default_fd_get_file_info,
+    .ioctl         = default_fd_ioctl,
+    .queue_async   = default_fd_queue_async,
 };
 
 static struct mailslot_message *get_first_message( struct mailslot *mailslot )
@@ -545,7 +469,7 @@ static struct fd *mailslot_device_file_get_fd( struct object *obj )
 static WCHAR *mailslot_device_file_get_full_name( struct object *obj, data_size_t max, data_size_t *len )
 {
     struct mailslot_device_file *file = (struct mailslot_device_file *)obj;
-    WCHAR *ret = file->device->obj.ops->get_full_name( &file->device->obj, max, len );
+    WCHAR *ret = default_get_full_name( &file->device->obj, max, len );
     if (*len > max) set_error( STATUS_BUFFER_OVERFLOW );
     return ret;
 }
diff --git a/server/mapping.c b/server/mapping.c
index a53b6b68304b..8bb23fda6e65 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -63,27 +63,10 @@ static void ranges_destroy( struct object *obj );
 
 static const struct object_ops ranges_ops =
 {
-    sizeof(struct ranges),     /* size */
-    &no_type,                  /* type */
-    ranges_dump,               /* dump */
-    no_add_queue,              /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    no_get_full_name,          /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    no_link_name,              /* link_name */
-    NULL,                      /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    ranges_destroy             /* destroy */
+    .size    = sizeof(struct ranges),
+    .type    = &no_type,
+    .dump    = ranges_dump,
+    .destroy = ranges_destroy,
 };
 
 /* file backing the shared sections of a PE image mapping */
@@ -100,27 +83,10 @@ static void shared_map_destroy( struct object *obj );
 
 static const struct object_ops shared_map_ops =
 {
-    sizeof(struct shared_map), /* size */
-    &no_type,                  /* type */
-    shared_map_dump,           /* dump */
-    no_add_queue,              /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    no_get_full_name,          /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    no_link_name,              /* link_name */
-    NULL,                      /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    shared_map_destroy         /* destroy */
+    .size    = sizeof(struct shared_map),
+    .type    = &no_type,
+    .dump    = shared_map_dump,
+    .destroy = shared_map_destroy,
 };
 
 static struct list shared_map_list = LIST_INIT( shared_map_list );
@@ -178,43 +144,16 @@ static enum server_fd_type mapping_get_fd_type( struct fd *fd );
 
 static const struct object_ops mapping_ops =
 {
-    sizeof(struct mapping),      /* size */
-    &mapping_type,               /* type */
-    mapping_dump,                /* dump */
-    no_add_queue,                /* add_queue */
-    NULL,                        /* remove_queue */
-    NULL,                        /* signaled */
-    NULL,                        /* satisfied */
-    no_signal,                   /* signal */
-    mapping_get_fd,              /* get_fd */
-    default_get_sync,            /* get_sync */
-    default_map_access,          /* map_access */
-    default_get_sd,              /* get_sd */
-    default_set_sd,              /* set_sd */
-    default_get_full_name,       /* get_full_name */
-    no_lookup_name,              /* lookup_name */
-    directory_link_name,         /* link_name */
-    default_unlink_name,         /* unlink_name */
-    no_open_file,                /* open_file */
-    no_kernel_obj_list,          /* get_kernel_obj_list */
-    no_close_handle,             /* close_handle */
-    mapping_destroy              /* destroy */
+    .size    = sizeof(struct mapping),
+    .type    = &mapping_type,
+    .dump    = mapping_dump,
+    .get_fd  = mapping_get_fd,
+    .destroy = mapping_destroy,
 };
 
 static const struct fd_ops mapping_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    mapping_get_fd_type,          /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    no_fd_get_file_info,          /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    no_fd_ioctl,                  /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    no_fd_queue_async,            /* queue_async */
-    default_fd_reselect_async     /* reselect_async */
+    .get_fd_type = mapping_get_fd_type,
 };
 
 /* free address ranges for PE image mappings */
diff --git a/server/mutex.c b/server/mutex.c
index 5beffedd1508..2de5889d7871 100644
--- a/server/mutex.c
+++ b/server/mutex.c
@@ -65,27 +65,14 @@ static void mutex_sync_destroy( struct object *obj );
 
 static const struct object_ops mutex_sync_ops =
 {
-    sizeof(struct mutex_sync), /* size */
-    &no_type,                  /* type */
-    mutex_sync_dump,           /* dump */
-    add_queue,                 /* add_queue */
-    remove_queue,              /* remove_queue */
-    mutex_sync_signaled,       /* signaled */
-    mutex_sync_satisfied,      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    mutex_sync_destroy,        /* destroy */
+    .size         = sizeof(struct mutex_sync),
+    .type         = &no_type,
+    .dump         = mutex_sync_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .signaled     = mutex_sync_signaled,
+    .satisfied    = mutex_sync_satisfied,
+    .destroy      = mutex_sync_destroy,
 };
 
 /* grab a mutex for a given thread */
@@ -180,27 +167,12 @@ static void mutex_destroy( struct object *obj );
 
 static const struct object_ops mutex_ops =
 {
-    sizeof(struct mutex),      /* size */
-    &mutex_type,               /* type */
-    mutex_dump,                /* dump */
-    NULL,                      /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    mutex_signal,              /* signal */
-    no_get_fd,                 /* get_fd */
-    mutex_get_sync,            /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    mutex_destroy,             /* destroy */
+    .size     = sizeof(struct mutex),
+    .type     = &mutex_type,
+    .dump     = mutex_dump,
+    .signal   = mutex_signal,
+    .get_sync = mutex_get_sync,
+    .destroy  = mutex_destroy,
 };
 
 static struct mutex *create_mutex( struct object *root, const struct unicode_str *name,
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 13982d135816..92ad16a54df1 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -103,36 +103,33 @@ struct named_pipe_device_file
 };
 
 static void named_pipe_dump( struct object *obj, int verbose );
-static unsigned int named_pipe_map_access( struct object *obj, unsigned int access );
 static WCHAR *named_pipe_get_full_name( struct object *obj, data_size_t max, data_size_t *ret_len );
 static int named_pipe_link_name( struct object *obj, struct object_name *name, struct object *parent );
 static struct object *named_pipe_open_file( struct object *obj, unsigned int access,
                                             unsigned int sharing, unsigned int options );
 static void named_pipe_destroy( struct object *obj );
 
+static struct type_descr named_pipe_type =
+{
+    { NULL, 0 },                /* name */
+    STANDARD_RIGHTS_ALL,        /* valid_access */
+    {                           /* mapping */
+        STANDARD_RIGHTS_READ,
+        STANDARD_RIGHTS_WRITE | FILE_CREATE_PIPE_INSTANCE,
+        STANDARD_RIGHTS_EXECUTE,
+        STANDARD_RIGHTS_ALL
+    }
+};
+
 static const struct object_ops named_pipe_ops =
 {
-    sizeof(struct named_pipe),    /* size */
-    &no_type,                     /* type */
-    named_pipe_dump,              /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    named_pipe_map_access,        /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    named_pipe_get_full_name,     /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    named_pipe_link_name,         /* link_name */
-    default_unlink_name,          /* unlink_name */
-    named_pipe_open_file,         /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    named_pipe_destroy            /* destroy */
+    .size          = sizeof(struct named_pipe),
+    .type          = &named_pipe_type,
+    .dump          = named_pipe_dump,
+    .get_full_name = named_pipe_get_full_name,
+    .link_name     = named_pipe_link_name,
+    .open_file     = named_pipe_open_file,
+    .destroy       = named_pipe_destroy,
 };
 
 /* common server and client pipe end functions */
@@ -161,43 +158,30 @@ static void pipe_server_ioctl( struct fd *fd, ioctl_code_t code, struct async *a
 
 static const struct object_ops pipe_server_ops =
 {
-    sizeof(struct pipe_server),   /* size */
-    &file_type,                   /* type */
-    pipe_server_dump,             /* dump */
-    NULL,                         /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    pipe_end_get_fd,              /* get_fd */
-    default_fd_get_sync,          /* get_sync */
-    default_map_access,           /* map_access */
-    pipe_end_get_sd,              /* get_sd */
-    pipe_end_set_sd,              /* set_sd */
-    pipe_end_get_full_name,       /* get_full_name */
-    pipe_server_lookup_name,      /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    pipe_server_open_file,        /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    async_close_obj_handle,       /* close_handle */
-    pipe_server_destroy           /* destroy */
+    .size          = sizeof(struct pipe_server),
+    .type          = &file_type,
+    .dump          = pipe_server_dump,
+    .get_fd        = pipe_end_get_fd,
+    .get_sync      = default_fd_get_sync,
+    .get_sd        = pipe_end_get_sd,
+    .set_sd        = pipe_end_set_sd,
+    .get_full_name = pipe_end_get_full_name,
+    .lookup_name   = pipe_server_lookup_name,
+    .open_file     = pipe_server_open_file,
+    .close_handle  = async_close_obj_handle,
+    .destroy       = pipe_server_destroy,
 };
 
 static const struct fd_ops pipe_server_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    pipe_end_get_fd_type,         /* get_fd_type */
-    pipe_end_read,                /* read */
-    pipe_end_write,               /* write */
-    pipe_end_flush,               /* flush */
-    pipe_end_get_file_info,       /* get_file_info */
-    pipe_end_get_volume_info,     /* get_volume_info */
-    pipe_server_ioctl,            /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    no_fd_queue_async,            /* queue_async */
-    pipe_end_reselect_async       /* reselect_async */
+    .get_fd_type     = pipe_end_get_fd_type,
+    .read            = pipe_end_read,
+    .write           = pipe_end_write,
+    .flush           = pipe_end_flush,
+    .get_file_info   = pipe_end_get_file_info,
+    .get_volume_info = pipe_end_get_volume_info,
+    .ioctl           = pipe_server_ioctl,
+    .reselect_async  = pipe_end_reselect_async,
 };
 
 /* client end functions */
@@ -206,43 +190,28 @@ static void pipe_client_ioctl( struct fd *fd, ioctl_code_t code, struct async *a
 
 static const struct object_ops pipe_client_ops =
 {
-    sizeof(struct pipe_end),      /* size */
-    &file_type,                   /* type */
-    pipe_client_dump,             /* dump */
-    NULL,                         /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    pipe_end_get_fd,              /* get_fd */
-    default_fd_get_sync,          /* get_sync */
-    default_map_access,           /* map_access */
-    pipe_end_get_sd,              /* get_sd */
-    pipe_end_set_sd,              /* set_sd */
-    pipe_end_get_full_name,       /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    async_close_obj_handle,       /* close_handle */
-    pipe_end_destroy              /* destroy */
+    .size          = sizeof(struct pipe_end),
+    .type          = &file_type,
+    .dump          = pipe_client_dump,
+    .get_fd        = pipe_end_get_fd,
+    .get_sync      = default_fd_get_sync,
+    .get_sd        = pipe_end_get_sd,
+    .set_sd        = pipe_end_set_sd,
+    .get_full_name = pipe_end_get_full_name,
+    .close_handle  = async_close_obj_handle,
+    .destroy       = pipe_end_destroy,
 };
 
 static const struct fd_ops pipe_client_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    pipe_end_get_fd_type,         /* get_fd_type */
-    pipe_end_read,                /* read */
-    pipe_end_write,               /* write */
-    pipe_end_flush,               /* flush */
-    pipe_end_get_file_info,       /* get_file_info */
-    pipe_end_get_volume_info,     /* get_volume_info */
-    pipe_client_ioctl,            /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    no_fd_queue_async,            /* queue_async */
-    pipe_end_reselect_async       /* reselect_async */
+    .get_fd_type     = pipe_end_get_fd_type,
+    .read            = pipe_end_read,
+    .write           = pipe_end_write,
+    .flush           = pipe_end_flush,
+    .get_file_info   = pipe_end_get_file_info,
+    .get_volume_info = pipe_end_get_volume_info,
+    .ioctl           = pipe_client_ioctl,
+    .reselect_async  = pipe_end_reselect_async,
 };
 
 static void named_pipe_device_dump( struct object *obj, int verbose );
@@ -255,27 +224,13 @@ static void named_pipe_device_destroy( struct object *obj );
 
 static const struct object_ops named_pipe_device_ops =
 {
-    sizeof(struct named_pipe_device), /* size */
-    &device_type,                     /* type */
-    named_pipe_device_dump,           /* dump */
-    no_add_queue,                     /* add_queue */
-    NULL,                             /* remove_queue */
-    NULL,                             /* signaled */
-    no_satisfied,                     /* satisfied */
-    no_signal,                        /* signal */
-    no_get_fd,                        /* get_fd */
-    default_get_sync,                 /* get_sync */
-    default_map_access,               /* map_access */
-    default_get_sd,                   /* get_sd */
-    default_set_sd,                   /* set_sd */
-    named_pipe_device_get_full_name,  /* get_full_name */
-    named_pipe_device_lookup_name,    /* lookup_name */
-    directory_link_name,              /* link_name */
-    default_unlink_name,              /* unlink_name */
-    named_pipe_device_open_file,      /* open_file */
-    no_kernel_obj_list,               /* get_kernel_obj_list */
-    no_close_handle,                  /* close_handle */
-    named_pipe_device_destroy         /* destroy */
+    .size          = sizeof(struct named_pipe_device),
+    .type          = &device_type,
+    .dump          = named_pipe_device_dump,
+    .get_full_name = named_pipe_device_get_full_name,
+    .lookup_name   = named_pipe_device_lookup_name,
+    .open_file     = named_pipe_device_open_file,
+    .destroy       = named_pipe_device_destroy,
 };
 
 static void named_pipe_device_file_dump( struct object *obj, int verbose );
@@ -287,43 +242,21 @@ static void named_pipe_device_file_destroy( struct object *obj );
 
 static const struct object_ops named_pipe_device_file_ops =
 {
-    sizeof(struct named_pipe_device_file),   /* size */
-    &file_type,                              /* type */
-    named_pipe_device_file_dump,             /* dump */
-    NULL,                                    /* add_queue */
-    NULL,                                    /* remove_queue */
-    NULL,                                    /* signaled */
-    NULL,                                    /* satisfied */
-    no_signal,                               /* signal */
-    named_pipe_device_file_get_fd,           /* get_fd */
-    default_fd_get_sync,                     /* get_sync */
-    default_map_access,                      /* map_access */
-    default_get_sd,                          /* get_sd */
-    default_set_sd,                          /* set_sd */
-    named_pipe_device_file_get_full_name,    /* get_full_name */
-    no_lookup_name,                          /* lookup_name */
-    no_link_name,                            /* link_name */
-    NULL,                                    /* unlink_name */
-    no_open_file,                            /* open_file */
-    no_kernel_obj_list,                      /* get_kernel_obj_list */
-    no_close_handle,                         /* close_handle */
-    named_pipe_device_file_destroy           /* destroy */
+    .size          = sizeof(struct named_pipe_device_file),
+    .type          = &file_type,
+    .dump          = named_pipe_device_file_dump,
+    .get_fd        = named_pipe_device_file_get_fd,
+    .get_sync      = default_fd_get_sync,
+    .get_full_name = named_pipe_device_file_get_full_name,
+    .destroy       = named_pipe_device_file_destroy,
 };
 
 static const struct fd_ops named_pipe_device_fd_ops =
 {
-    default_fd_get_poll_events,              /* get_poll_events */
-    default_poll_event,                      /* poll_event */
-    named_pipe_device_file_get_fd_type,      /* get_fd_type */
-    no_fd_read,                              /* read */
-    no_fd_write,                             /* write */
-    no_fd_flush,                             /* flush */
-    default_fd_get_file_info,                /* get_file_info */
-    no_fd_get_volume_info,                   /* get_volume_info */
-    named_pipe_device_ioctl,                 /* ioctl */
-    default_fd_cancel_async,                 /* cancel_async */
-    default_fd_queue_async,                  /* queue_async */
-    default_fd_reselect_async                /* reselect_async */
+    .get_fd_type   = named_pipe_device_file_get_fd_type,
+    .get_file_info = default_fd_get_file_info,
+    .ioctl         = named_pipe_device_ioctl,
+    .queue_async   = default_fd_queue_async,
 };
 
 static void named_pipe_dir_dump( struct object *obj, int verbose );
@@ -338,43 +271,22 @@ static void named_pipe_dir_destroy( struct object *obj );
 
 static const struct object_ops named_pipe_dir_ops =
 {
-    sizeof(struct named_pipe_device_file),   /* size */
-    &file_type,                              /* type */
-    named_pipe_dir_dump,                     /* dump */
-    NULL,                                    /* add_queue */
-    NULL,                                    /* remove_queue */
-    NULL,                                    /* signaled */
-    NULL,                                    /* satisfied */
-    no_signal,                               /* signal */
-    named_pipe_dir_get_fd,                   /* get_fd */
-    default_fd_get_sync,                     /* get_sync */
-    default_map_access,                      /* map_access */
-    default_get_sd,                          /* get_sd */
-    default_set_sd,                          /* set_sd */
-    named_pipe_dir_get_full_name,            /* get_full_name */
-    named_pipe_dir_lookup_name,              /* lookup_name */
-    no_link_name,                            /* link_name */
-    NULL,                                    /* unlink_name */
-    named_pipe_dir_open_file,                /* open_file */
-    no_kernel_obj_list,                      /* get_kernel_obj_list */
-    no_close_handle,                         /* close_handle */
-    named_pipe_dir_destroy                   /* destroy */
+    .size          = sizeof(struct named_pipe_device_file),
+    .type          = &file_type,
+    .dump          = named_pipe_dir_dump,
+    .get_fd        = named_pipe_dir_get_fd,
+    .get_sync      = default_fd_get_sync,
+    .get_full_name = named_pipe_dir_get_full_name,
+    .lookup_name   = named_pipe_dir_lookup_name,
+    .open_file     = named_pipe_dir_open_file,
+    .destroy       = named_pipe_dir_destroy,
 };
 
 static const struct fd_ops named_pipe_dir_fd_ops =
 {
-    default_fd_get_poll_events,              /* get_poll_events */
-    default_poll_event,                      /* poll_event */
-    NULL,                                    /* get_fd_type */
-    no_fd_read,                              /* read */
-    no_fd_write,                             /* write */
-    no_fd_flush,                             /* flush */
-    default_fd_get_file_info,                /* get_file_info */
-    no_fd_get_volume_info,                   /* get_volume_info */
-    named_pipe_dir_ioctl,                    /* ioctl */
-    default_fd_cancel_async,                 /* cancel_async */
-    default_fd_queue_async,                  /* queue_async */
-    default_fd_reselect_async                /* reselect_async */
+    .get_file_info = default_fd_get_file_info,
+    .ioctl         = named_pipe_dir_ioctl,
+    .queue_async   = default_fd_queue_async,
 };
 
 static void named_pipe_dump( struct object *obj, int verbose )
@@ -382,15 +294,6 @@ static void named_pipe_dump( struct object *obj, int verbose )
     fputs( "Named pipe\n", stderr );
 }
 
-static unsigned int named_pipe_map_access( struct object *obj, unsigned int access )
-{
-    if (access & GENERIC_READ)    access |= STANDARD_RIGHTS_READ;
-    if (access & GENERIC_WRITE)   access |= STANDARD_RIGHTS_WRITE | FILE_CREATE_PIPE_INSTANCE;
-    if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE;
-    if (access & GENERIC_ALL)     access |= STANDARD_RIGHTS_ALL;
-    return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
-}
-
 static WCHAR *named_pipe_get_full_name( struct object *obj, data_size_t max, data_size_t *ret_len )
 {
     WCHAR *ret;
@@ -525,7 +428,7 @@ static struct object *pipe_server_open_file( struct object *obj, unsigned int ac
 {
     struct pipe_server *server = (struct pipe_server *)obj;
 
-    return server->pipe_end.pipe->obj.ops->open_file( &server->pipe_end.pipe->obj, access, sharing, options );
+    return named_pipe_open_file(  &server->pipe_end.pipe->obj, access, sharing, options );
 }
 
 static void pipe_server_destroy( struct object *obj )
@@ -642,7 +545,7 @@ static struct fd *named_pipe_device_file_get_fd( struct object *obj )
 static WCHAR *named_pipe_device_file_get_full_name( struct object *obj, data_size_t max, data_size_t *len )
 {
     struct named_pipe_device_file *file = (struct named_pipe_device_file *)obj;
-    return file->device->obj.ops->get_full_name( &file->device->obj, max, len );
+    return named_pipe_device_get_full_name( &file->device->obj, max, len );
 }
 
 static enum server_fd_type named_pipe_device_file_get_fd_type( struct fd *fd )
@@ -675,9 +578,9 @@ static WCHAR *named_pipe_dir_get_full_name( struct object *obj, data_size_t max,
 {
     struct named_pipe_device_file *dir = (struct named_pipe_device_file *)obj;
     data_size_t len;
-    char *device_name, *ret;
+    WCHAR *device_name, *ret;
 
-    device_name = (char *)dir->device->obj.ops->get_full_name( &dir->device->obj, max, &len );
+    device_name = named_pipe_device_get_full_name( &dir->device->obj, max, &len );
     if (!device_name) return NULL;
 
     len += sizeof(WCHAR);
@@ -687,11 +590,11 @@ static WCHAR *named_pipe_dir_get_full_name( struct object *obj, data_size_t max,
         free(device_name);
         return NULL;
     }
-    *(WCHAR *)(ret + len - sizeof(WCHAR)) = '\\';
+    ret[len / sizeof(WCHAR) - 1] = '\\';
 
     if (len > max) set_error( STATUS_BUFFER_OVERFLOW );
     *ret_len = len;
-    return (WCHAR *)ret;
+    return ret;
 }
 
 static struct object *named_pipe_dir_lookup_name( struct object *obj, struct unicode_str *name,
@@ -699,7 +602,7 @@ static struct object *named_pipe_dir_lookup_name( struct object *obj, struct uni
 {
     struct named_pipe_device_file *dir = (struct named_pipe_device_file *)obj;
     if (!name || !name->len) return NULL;  /* open the directory itself */
-    return dir->device->obj.ops->lookup_name( &dir->device->obj, name, attr, root );
+    return named_pipe_device_lookup_name( &dir->device->obj, name, attr, root );
 }
 
 static struct object *named_pipe_dir_open_file( struct object *obj, unsigned int access,
@@ -710,7 +613,8 @@ static struct object *named_pipe_dir_open_file( struct object *obj, unsigned int
     if (dir->fd)
     {
         /* Trying to open by (already opened) file object */
-        return no_open_file( obj, access, sharing, options );
+        set_error( STATUS_OBJECT_TYPE_MISMATCH );
+        return NULL;
     }
 
     /* Turn this "proto-object" into an actual file object */
@@ -917,7 +821,7 @@ static void pipe_end_get_file_info( struct fd *fd, obj_handle_t handle, unsigned
 static struct security_descriptor *pipe_end_get_sd( struct object *obj )
 {
     struct pipe_end *pipe_end = (struct pipe_end *) obj;
-    if (pipe_end->pipe) return default_get_sd( &pipe_end->pipe->obj );
+    if (pipe_end->pipe) return pipe_end->pipe->obj.sd;
     set_error( STATUS_PIPE_DISCONNECTED );
     return NULL;
 }
@@ -934,7 +838,7 @@ static int pipe_end_set_sd( struct object *obj, const struct security_descriptor
 static WCHAR *pipe_end_get_full_name( struct object *obj, data_size_t max, data_size_t *len )
 {
     struct pipe_end *pipe_end = (struct pipe_end *) obj;
-    return pipe_end->pipe->obj.ops->get_full_name( &pipe_end->pipe->obj, max, len );
+    return named_pipe_get_full_name( &pipe_end->pipe->obj, max, len );
 }
 
 static void pipe_end_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class )
diff --git a/server/object.c b/server/object.c
index e7e7b89ae50e..f1a75e8d4e5f 100644
--- a/server/object.c
+++ b/server/object.c
@@ -102,52 +102,16 @@ static void dump_reserve( struct object *obj, int verbose );
 
 static const struct object_ops apc_reserve_ops =
 {
-    sizeof(struct reserve),     /* size */
-    &apc_reserve_type,          /* type */
-    dump_reserve,               /* dump */
-    no_add_queue,               /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    no_satisfied,               /* satisfied */
-    no_signal,                  /* signal */
-    no_get_fd,                  /* get_fd */
-    default_get_sync,           /* get_sync */
-    default_map_access,         /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    default_get_full_name,      /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    directory_link_name,        /* link_name */
-    default_unlink_name,        /* unlink_name */
-    no_open_file,               /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    no_destroy                  /* destroy */
+    .size = sizeof(struct reserve),
+    .type = &apc_reserve_type,
+    .dump = dump_reserve,
 };
 
 static const struct object_ops completion_reserve_ops =
 {
-    sizeof(struct reserve),    /* size */
-    &completion_reserve_type,  /* type */
-    dump_reserve,              /* dump */
-    no_add_queue,              /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    no_satisfied,              /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    no_destroy                 /* destroy */
+    .size = sizeof(struct reserve),
+    .type = &completion_reserve_type,
+    .dump = dump_reserve,
 };
 
 #ifdef DEBUG_OBJECTS
@@ -339,7 +303,7 @@ struct object *lookup_named_object( struct object *root, const struct unicode_st
                                     unsigned int attr, struct unicode_str *name_left )
 {
     static int recursion_count;
-    struct object *obj, *parent;
+    struct object *parent;
     struct unicode_str name_tmp = *name, *ptr = &name_tmp;
 
     if (root)
@@ -376,8 +340,14 @@ struct object *lookup_named_object( struct object *root, const struct unicode_st
     recursion_count++;
     clear_error();
 
-    while ((obj = parent->ops->lookup_name( parent, ptr, attr, root )))
+    for (;;)
     {
+        struct object *obj = NULL;
+
+        if (parent->ops->lookup_name) obj = parent->ops->lookup_name( parent, ptr, attr, root );
+        else if (!ptr) set_error( STATUS_OBJECT_TYPE_MISMATCH );
+
+        if (!obj) break;
         /* move to the next element */
         release_object ( parent );
         parent = obj;
@@ -415,11 +385,14 @@ static struct object *create_object( struct object *parent, const struct object_
     if (sd && !default_set_sd( obj, sd, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
                                DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION ))
         goto failed;
-    if (!obj->ops->link_name( obj, name_ptr, parent )) goto failed;
-
-    name_ptr->obj = obj;
-    obj->name = name_ptr;
-    return obj;
+    if (obj->ops->link_name ?
+        obj->ops->link_name( obj, name_ptr, parent ) :
+        directory_link_name( obj, name_ptr, parent ))
+    {
+        name_ptr->obj = obj;
+        obj->name = name_ptr;
+        return obj;
+    }
 
 failed:
     if (obj) free_object( obj );
@@ -527,7 +500,8 @@ void unlink_named_object( struct object *obj )
 
     if (!name_ptr) return;
     obj->name = NULL;
-    obj->ops->unlink_name( obj, name_ptr );
+    if (obj->ops->unlink_name) obj->ops->unlink_name( obj, name_ptr );
+    else unlink_name( name_ptr );
     if (name_ptr->parent) release_object( name_ptr->parent );
     free( name_ptr );
 }
@@ -553,7 +527,7 @@ void release_object( void *ptr )
         assert( list_empty( &obj->wait_queue ));
         free_kernel_objects( obj );
         unlink_named_object( obj );
-        obj->ops->destroy( obj );
+        if (obj->ops->destroy) obj->ops->destroy( obj );
         free_object( obj );
     }
 }
@@ -617,44 +591,22 @@ struct namespace *create_namespace( unsigned int hash_size )
     return namespace;
 }
 
-/* functions for unimplemented/default object operations */
-
-int no_add_queue( struct object *obj, struct wait_queue_entry *entry )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return 0;
-}
-
-void no_satisfied( struct object *obj, struct wait_queue_entry *entry )
-{
-}
-
-int no_signal( struct object *obj, unsigned int access, int signal )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return 0;
-}
-
-struct fd *no_get_fd( struct object *obj )
+/* retrieve the file descriptor associated to an object, if any */
+struct fd *get_obj_fd( struct object *obj )
 {
+    if (obj->ops->get_fd) return obj->ops->get_fd( obj );
     set_error( STATUS_OBJECT_TYPE_MISMATCH );
     return NULL;
 }
 
-struct object *default_get_sync( struct object *obj )
+/* retrieve the sync object associated to an object, or the object itself */
+struct object *get_obj_sync( struct object *obj )
 {
+    if (obj->ops->get_sync) return obj->ops->get_sync( obj );
     return grab_object( obj );
 }
 
-unsigned int default_map_access( struct object *obj, unsigned int access )
-{
-    return map_access( access, &obj->ops->type->mapping );
-}
-
-struct security_descriptor *default_get_sd( struct object *obj )
-{
-    return obj->sd;
-}
+/* functions for unimplemented/default object operations */
 
 int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd,
                                 unsigned int set_info, struct token *token )
@@ -784,45 +736,6 @@ int default_set_sd( struct object *obj, const struct security_descriptor *sd,
     return set_sd_defaults_from_token( obj, sd, set_info, current->process->token );
 }
 
-WCHAR *no_get_full_name( struct object *obj, data_size_t max, data_size_t *ret_len )
-{
-    return NULL;
-}
-
-struct object *no_lookup_name( struct object *obj, struct unicode_str *name,
-                               unsigned int attr, struct object *root )
-{
-    if (!name) set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return NULL;
-}
-
-int no_link_name( struct object *obj, struct object_name *name, struct object *parent )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return 0;
-}
-
-void default_unlink_name( struct object *obj, struct object_name *name )
-{
-    list_remove( &name->entry );
-}
-
-struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing,
-                             unsigned int options )
-{
-    set_error( STATUS_OBJECT_TYPE_MISMATCH );
-    return NULL;
-}
-
-int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
-{
-    return 1;  /* ok to close */
-}
-
-void no_destroy( struct object *obj )
-{
-}
-
 static void dump_reserve( struct object *obj, int verbose )
 {
     struct reserve *reserve = (struct reserve *) obj;
diff --git a/server/object.h b/server/object.h
index 171ca2f8904d..a742431f7628 100644
--- a/server/object.h
+++ b/server/object.h
@@ -169,27 +169,11 @@ extern void release_object( void *obj );
 extern struct object *find_object( const struct namespace *namespace, const struct unicode_str *name,
                                    unsigned int attributes );
 extern struct object *find_object_index( const struct namespace *namespace, unsigned int index );
-extern int no_add_queue( struct object *obj, struct wait_queue_entry *entry );
-extern void no_satisfied( struct object *obj, struct wait_queue_entry *entry );
-extern int no_signal( struct object *obj, unsigned int access, int signal );
-extern struct fd *no_get_fd( struct object *obj );
-extern struct object *default_get_sync( struct object *obj );
-static inline struct object *get_obj_sync( struct object *obj ) { return obj->ops->get_sync( obj ); }
-extern unsigned int default_map_access( struct object *obj, unsigned int access );
-extern struct security_descriptor *default_get_sd( struct object *obj );
+extern struct fd *get_obj_fd( struct object *obj );
+extern struct object *get_obj_sync( struct object *obj );
 extern int default_set_sd( struct object *obj, const struct security_descriptor *sd, unsigned int set_info );
 extern int set_sd_defaults_from_token( struct object *obj, const struct security_descriptor *sd,
                                        unsigned int set_info, struct token *token );
-extern WCHAR *no_get_full_name( struct object *obj, data_size_t max, data_size_t *ret_len );
-extern struct object *no_lookup_name( struct object *obj, struct unicode_str *name,
-                                      unsigned int attributes, struct object *root );
-extern int no_link_name( struct object *obj, struct object_name *name, struct object *parent );
-extern void default_unlink_name( struct object *obj, struct object_name *name );
-extern struct object *no_open_file( struct object *obj, unsigned int access, unsigned int sharing,
-                                    unsigned int options );
-extern struct list *no_kernel_obj_list( struct object *obj );
-extern int no_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
-extern void no_destroy( struct object *obj );
 #ifdef DEBUG_OBJECTS
 extern void dump_objects(void);
 extern void close_objects(void);
@@ -210,6 +194,22 @@ static inline unsigned int map_access( unsigned int access, const struct generic
     return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
 }
 
+static inline unsigned int default_map_access( struct object *obj, unsigned int access )
+{
+    return map_access( access, &obj->ops->type->mapping );
+}
+
+static inline unsigned int map_obj_access( struct object *obj, unsigned int access )
+{
+    if (obj->ops->map_access) return obj->ops->map_access( obj, access );
+    return default_map_access( obj, access );
+}
+
+static inline void unlink_name( struct object_name *name )
+{
+    list_remove( &name->entry );
+}
+
 static inline void *mem_append( void *ptr, const void *src, data_size_t len )
 {
     if (!len) return ptr;
@@ -371,6 +371,7 @@ extern struct type_descr mapping_type;
 extern struct type_descr key_type;
 extern struct type_descr apc_reserve_type;
 extern struct type_descr completion_reserve_type;
+extern struct type_descr alpc_port_type;
 
 #define KEYEDEVENT_WAIT       0x0001
 #define KEYEDEVENT_WAKE       0x0002
diff --git a/server/process.c b/server/process.c
index 077dc42edc48..30c90b28c5cf 100644
--- a/server/process.c
+++ b/server/process.c
@@ -99,39 +99,19 @@ static void terminate_process( struct process *process, struct thread *skip, int
 
 static const struct object_ops process_ops =
 {
-    sizeof(struct process),      /* size */
-    &process_type,               /* type */
-    process_dump,                /* dump */
-    NULL,                        /* add_queue */
-    NULL,                        /* remove_queue */
-    NULL,                        /* signaled */
-    NULL,                        /* satisfied */
-    no_signal,                   /* signal */
-    no_get_fd,                   /* get_fd */
-    process_get_sync,            /* get_sync */
-    process_map_access,          /* map_access */
-    process_get_sd,              /* get_sd */
-    default_set_sd,              /* set_sd */
-    no_get_full_name,            /* get_full_name */
-    no_lookup_name,              /* lookup_name */
-    no_link_name,                /* link_name */
-    NULL,                        /* unlink_name */
-    no_open_file,                /* open_file */
-    process_get_kernel_obj_list, /* get_kernel_obj_list */
-    no_close_handle,             /* close_handle */
-    process_destroy              /* destroy */
+    .size                = sizeof(struct process),
+    .type                = &process_type,
+    .dump                = process_dump,
+    .get_sync            = process_get_sync,
+    .map_access          = process_map_access,
+    .get_sd              = process_get_sd,
+    .get_kernel_obj_list = process_get_kernel_obj_list,
+    .destroy             = process_destroy,
 };
 
 static const struct fd_ops process_fd_ops =
 {
-    NULL,                        /* get_poll_events */
-    process_poll_event,          /* poll_event */
-    NULL,                        /* flush */
-    NULL,                        /* get_fd_type */
-    NULL,                        /* ioctl */
-    NULL,                        /* queue_async */
-    NULL,                        /* reselect_async */
-    NULL                         /* cancel async */
+    .poll_event = process_poll_event,
 };
 
 /* process startup info */
@@ -152,27 +132,11 @@ static void startup_info_destroy( struct object *obj );
 
 static const struct object_ops startup_info_ops =
 {
-    sizeof(struct startup_info),   /* size */
-    &no_type,                      /* type */
-    startup_info_dump,             /* dump */
-    NULL,                          /* add_queue */
-    NULL,                          /* remove_queue */
-    NULL,                          /* signaled */
-    NULL,                          /* satisfied */
-    no_signal,                     /* signal */
-    no_get_fd,                     /* get_fd */
-    startup_info_get_sync,         /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    no_get_full_name,              /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    no_link_name,                  /* link_name */
-    NULL,                          /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    no_close_handle,               /* close_handle */
-    startup_info_destroy           /* destroy */
+    .size     = sizeof(struct startup_info),
+    .type     = &no_type,
+    .dump     = startup_info_dump,
+    .get_sync = startup_info_get_sync,
+    .destroy  = startup_info_destroy,
 };
 
 /* job object */
@@ -214,27 +178,12 @@ struct job
 
 static const struct object_ops job_ops =
 {
-    sizeof(struct job),            /* size */
-    &job_type,                     /* type */
-    job_dump,                      /* dump */
-    NULL,                          /* add_queue */
-    NULL,                          /* remove_queue */
-    NULL,                          /* signaled */
-    NULL,                          /* satisfied */
-    no_signal,                     /* signal */
-    no_get_fd,                     /* get_fd */
-    job_get_sync,                  /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    default_get_full_name,         /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    directory_link_name,           /* link_name */
-    default_unlink_name,           /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    job_close_handle,              /* close_handle */
-    job_destroy                    /* destroy */
+    .size         = sizeof(struct job),
+    .type         = &job_type,
+    .dump         = job_dump,
+    .get_sync     = job_get_sync,
+    .close_handle = job_close_handle,
+    .destroy      = job_destroy,
 };
 
 static struct job *create_job_object( struct object *root, const struct unicode_str *name,
diff --git a/server/protocol.def b/server/protocol.def
index 30235dfe5fb8..1399b694ed22 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -4323,3 +4323,13 @@ enum inproc_sync_type
     data_size_t         runtime_size;   /* size of client runtime data */
     VARARG(runtime,bytes);              /* client runtime data */
 @END
+
+
+/* Create a new ALPC object */
+@REQ(alpc_create_port)
+    unsigned int        flags;          /* flags in port attributes */
+    mem_size_t          max_msg_len;    /* max message length in port attributes */
+    VARARG(obj_attr,object_attributes); /* object attributes */
+@REPLY
+    obj_handle_t        handle;         /* handle to the ALPC port */
+@END
diff --git a/server/queue.c b/server/queue.c
index 437c4fa99713..b89a0dc5c6ee 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -160,65 +160,25 @@ static void timer_callback( void *private );
 
 static const struct object_ops msg_queue_ops =
 {
-    sizeof(struct msg_queue),  /* size */
-    &no_type,                  /* type */
-    msg_queue_dump,            /* dump */
-    NULL,                      /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    msg_queue_get_sync,        /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    no_get_full_name,          /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    no_link_name,              /* link_name */
-    NULL,                      /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    msg_queue_destroy          /* destroy */
+    .size     = sizeof(struct msg_queue),
+    .type     = &no_type,
+    .dump     = msg_queue_dump,
+    .get_sync = msg_queue_get_sync,
+    .destroy  = msg_queue_destroy,
 };
 
 static const struct fd_ops msg_queue_fd_ops =
 {
-    NULL,                        /* get_poll_events */
-    msg_queue_poll_event,        /* poll_event */
-    NULL,                        /* flush */
-    NULL,                        /* get_fd_type */
-    NULL,                        /* ioctl */
-    NULL,                        /* queue_async */
-    NULL,                        /* reselect_async */
-    NULL                         /* cancel async */
+    .poll_event = msg_queue_poll_event,
 };
 
 
 static const struct object_ops thread_input_ops =
 {
-    sizeof(struct thread_input),  /* size */
-    &no_type,                     /* type */
-    thread_input_dump,            /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    no_get_full_name,             /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    thread_input_destroy          /* destroy */
+    .size    = sizeof(struct thread_input),
+    .type    = &no_type,
+    .dump    = thread_input_dump,
+    .destroy = thread_input_destroy,
 };
 
 /* pointer to input structure of foreground thread */
diff --git a/server/registry.c b/server/registry.c
index 91b3265e8f76..6715738a2ee9 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -177,27 +177,17 @@ static void key_destroy( struct object *obj );
 
 static const struct object_ops key_ops =
 {
-    sizeof(struct key),      /* size */
-    &key_type,               /* type */
-    key_dump,                /* dump */
-    no_add_queue,            /* add_queue */
-    NULL,                    /* remove_queue */
-    NULL,                    /* signaled */
-    NULL,                    /* satisfied */
-    no_signal,               /* signal */
-    no_get_fd,               /* get_fd */
-    default_get_sync,        /* get_sync */
-    key_map_access,          /* map_access */
-    key_get_sd,              /* get_sd */
-    default_set_sd,          /* set_sd */
-    key_get_full_name,       /* get_full_name */
-    key_lookup_name,         /* lookup_name */
-    key_link_name,           /* link_name */
-    key_unlink_name,         /* unlink_name */
-    no_open_file,            /* open_file */
-    no_kernel_obj_list,      /* get_kernel_obj_list */
-    key_close_handle,        /* close_handle */
-    key_destroy              /* destroy */
+    .size          = sizeof(struct key),
+    .type          = &key_type,
+    .dump          = key_dump,
+    .map_access    = key_map_access,
+    .get_sd        = key_get_sd,
+    .get_full_name = key_get_full_name,
+    .lookup_name   = key_lookup_name,
+    .link_name     = key_link_name,
+    .unlink_name   = key_unlink_name,
+    .close_handle  = key_close_handle,
+    .destroy       = key_destroy,
 };
 
 
@@ -625,7 +615,7 @@ static void key_unlink_name( struct object *obj, struct object_name *name )
 
     if (parent->obj.ops != &key_ops)
     {
-        default_unlink_name( obj, name );
+        unlink_name( name );
         return;
     }
 
@@ -936,7 +926,7 @@ static void enum_key( struct key *key, int index, int info_class, struct enum_ke
     switch(info_class)
     {
     case KeyNameInformation:
-        if (!(fullname = key->obj.ops->get_full_name( &key->obj, ~0u, &namelen ))) return;
+        if (!(fullname = key_get_full_name( &key->obj, ~0u, &namelen ))) return;
         /* fall through */
     case KeyBasicInformation:
         classlen = 0; /* only return the name */
diff --git a/server/request.c b/server/request.c
index fd09ca2ccc42..8e0a579f0d6b 100644
--- a/server/request.c
+++ b/server/request.c
@@ -82,38 +82,15 @@ static void master_socket_poll_event( struct fd *fd, int event );
 
 static const struct object_ops master_socket_ops =
 {
-    sizeof(struct master_socket),  /* size */
-    &no_type,                      /* type */
-    master_socket_dump,            /* dump */
-    no_add_queue,                  /* add_queue */
-    NULL,                          /* remove_queue */
-    NULL,                          /* signaled */
-    NULL,                          /* satisfied */
-    no_signal,                     /* signal */
-    no_get_fd,                     /* get_fd */
-    default_get_sync,              /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    no_get_full_name,              /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    no_link_name,                  /* link_name */
-    NULL,                          /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    no_close_handle,               /* close_handle */
-    master_socket_destroy          /* destroy */
+    .size    = sizeof(struct master_socket),
+    .type    = &no_type,
+    .dump    = master_socket_dump,
+    .destroy = master_socket_destroy,
 };
 
 static const struct fd_ops master_socket_fd_ops =
 {
-    NULL,                          /* get_poll_events */
-    master_socket_poll_event,      /* poll_event */
-    NULL,                          /* flush */
-    NULL,                          /* get_fd_type */
-    NULL,                          /* ioctl */
-    NULL,                          /* queue_async */
-    NULL                           /* reselect_async */
+    .poll_event = master_socket_poll_event,
 };
 
 
diff --git a/server/request_handlers.h b/server/request_handlers.h
index 82797824f0a2..05287957ede0 100644
--- a/server/request_handlers.h
+++ b/server/request_handlers.h
@@ -314,6 +314,7 @@ DECL_HANDLER(d3dkmt_share_objects);
 DECL_HANDLER(d3dkmt_object_open_name);
 DECL_HANDLER(d3dkmt_mutex_acquire);
 DECL_HANDLER(d3dkmt_mutex_release);
+DECL_HANDLER(alpc_create_port);
 
 typedef void (*req_handler)( const void *req, void *reply );
 static const req_handler req_handlers[REQ_NB_REQUESTS] =
@@ -625,6 +626,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_d3dkmt_object_open_name,
     (req_handler)req_d3dkmt_mutex_acquire,
     (req_handler)req_d3dkmt_mutex_release,
+    (req_handler)req_alpc_create_port,
 };
 
 C_ASSERT( sizeof(abstime_t) == 8 );
@@ -2385,3 +2387,8 @@ C_ASSERT( offsetof(struct d3dkmt_mutex_release_request, key_value) == 20 );
 C_ASSERT( offsetof(struct d3dkmt_mutex_release_request, fence_value) == 24 );
 C_ASSERT( offsetof(struct d3dkmt_mutex_release_request, runtime_size) == 32 );
 C_ASSERT( sizeof(struct d3dkmt_mutex_release_request) == 40 );
+C_ASSERT( offsetof(struct alpc_create_port_request, flags) == 12 );
+C_ASSERT( offsetof(struct alpc_create_port_request, max_msg_len) == 16 );
+C_ASSERT( sizeof(struct alpc_create_port_request) == 24 );
+C_ASSERT( offsetof(struct alpc_create_port_reply, handle) == 8 );
+C_ASSERT( sizeof(struct alpc_create_port_reply) == 16 );
diff --git a/server/request_trace.h b/server/request_trace.h
index 497c88e6c2fe..50fa4a9644d0 100644
--- a/server/request_trace.h
+++ b/server/request_trace.h
@@ -3524,6 +3524,18 @@ static void dump_d3dkmt_mutex_release_request( const struct d3dkmt_mutex_release
     dump_varargs_bytes( ", runtime=", cur_size );
 }
 
+static void dump_alpc_create_port_request( const struct alpc_create_port_request *req )
+{
+    fprintf( stderr, " flags=%08x", req->flags );
+    dump_uint64( ", max_msg_len=", &req->max_msg_len );
+    dump_varargs_object_attributes( ", obj_attr=", cur_size );
+}
+
+static void dump_alpc_create_port_reply( const struct alpc_create_port_reply *req )
+{
+    fprintf( stderr, " handle=%04x", req->handle );
+}
+
 typedef void (*dump_func)( const void *req );
 
 static const dump_func req_dumpers[REQ_NB_REQUESTS] =
@@ -3835,6 +3847,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] =
     (dump_func)dump_d3dkmt_object_open_name_request,
     (dump_func)dump_d3dkmt_mutex_acquire_request,
     (dump_func)dump_d3dkmt_mutex_release_request,
+    (dump_func)dump_alpc_create_port_request,
 };
 
 static const dump_func reply_dumpers[REQ_NB_REQUESTS] =
@@ -4146,6 +4159,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] =
     (dump_func)dump_d3dkmt_object_open_name_reply,
     (dump_func)dump_d3dkmt_mutex_acquire_reply,
     NULL,
+    (dump_func)dump_alpc_create_port_reply,
 };
 
 static const char * const req_names[REQ_NB_REQUESTS] =
@@ -4457,6 +4471,7 @@ static const char * const req_names[REQ_NB_REQUESTS] =
     "d3dkmt_object_open_name",
     "d3dkmt_mutex_acquire",
     "d3dkmt_mutex_release",
+    "alpc_create_port",
 };
 
 static const struct
diff --git a/server/semaphore.c b/server/semaphore.c
index 4c36000a5ff0..af1a2b35694e 100644
--- a/server/semaphore.c
+++ b/server/semaphore.c
@@ -62,27 +62,13 @@ static void semaphore_sync_satisfied( struct object *obj, struct wait_queue_entr
 
 static const struct object_ops semaphore_sync_ops =
 {
-    sizeof(struct semaphore_sync), /* size */
-    &no_type,                      /* type */
-    semaphore_sync_dump,           /* dump */
-    add_queue,                     /* add_queue */
-    remove_queue,                  /* remove_queue */
-    semaphore_sync_signaled,       /* signaled */
-    semaphore_sync_satisfied,      /* satisfied */
-    no_signal,                     /* signal */
-    no_get_fd,                     /* get_fd */
-    default_get_sync,              /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    default_get_full_name,         /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    directory_link_name,           /* link_name */
-    default_unlink_name,           /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    no_close_handle,               /* close_handle */
-    no_destroy                     /* destroy */
+    .size         = sizeof(struct semaphore_sync),
+    .type         = &no_type,
+    .dump         = semaphore_sync_dump,
+    .add_queue    = add_queue,
+    .remove_queue = remove_queue,
+    .signaled     = semaphore_sync_signaled,
+    .satisfied    = semaphore_sync_satisfied,
 };
 
 static int release_semaphore( struct semaphore_sync *sem, unsigned int count,
@@ -154,27 +140,12 @@ static void semaphore_destroy( struct object *obj );
 
 static const struct object_ops semaphore_ops =
 {
-    sizeof(struct semaphore),      /* size */
-    &semaphore_type,               /* type */
-    semaphore_dump,                /* dump */
-    NULL,                          /* add_queue */
-    NULL,                          /* remove_queue */
-    NULL,                          /* signaled */
-    NULL,                          /* satisfied */
-    semaphore_signal,              /* signal */
-    no_get_fd,                     /* get_fd */
-    semaphore_get_sync,            /* get_sync */
-    default_map_access,            /* map_access */
-    default_get_sd,                /* get_sd */
-    default_set_sd,                /* set_sd */
-    default_get_full_name,         /* get_full_name */
-    no_lookup_name,                /* lookup_name */
-    directory_link_name,           /* link_name */
-    default_unlink_name,           /* unlink_name */
-    no_open_file,                  /* open_file */
-    no_kernel_obj_list,            /* get_kernel_obj_list */
-    no_close_handle,               /* close_handle */
-    semaphore_destroy,             /* destroy */
+    .size     = sizeof(struct semaphore),
+    .type     = &semaphore_type,
+    .dump     = semaphore_dump,
+    .signal   = semaphore_signal,
+    .get_sync = semaphore_get_sync,
+    .destroy  = semaphore_destroy,
 };
 
 static struct semaphore *create_semaphore( struct object *root, const struct unicode_str *name,
diff --git a/server/serial.c b/server/serial.c
index a8809fb36a8f..16bed950f1ed 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -84,43 +84,21 @@ struct serial
 
 static const struct object_ops serial_ops =
 {
-    sizeof(struct serial),        /* size */
-    &file_type,                   /* type */
-    serial_dump,                  /* dump */
-    NULL,                         /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    serial_get_fd,                /* get_fd */
-    default_fd_get_sync,          /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    no_get_full_name,             /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    serial_destroy                /* destroy */
+    .size     = sizeof(struct serial),
+    .type     = &file_type,
+    .dump     = serial_dump,
+    .get_fd   = serial_get_fd,
+    .get_sync = default_fd_get_sync,
+    .destroy  = serial_destroy,
 };
 
 static const struct fd_ops serial_fd_ops =
 {
-    default_fd_get_poll_events,   /* get_poll_events */
-    default_poll_event,           /* poll_event */
-    serial_get_fd_type,           /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    default_fd_get_file_info,     /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    serial_ioctl,                 /* ioctl */
-    default_fd_cancel_async,      /* cancel_async */
-    serial_queue_async,           /* queue_async */
-    serial_reselect_async         /* reselect_async */
+    .get_fd_type    = serial_get_fd_type,
+    .get_file_info  = default_fd_get_file_info,
+    .ioctl          = serial_ioctl,
+    .queue_async    = serial_queue_async,
+    .reselect_async = serial_reselect_async,
 };
 
 /* check if the given fd is a serial port */
diff --git a/server/signal.c b/server/signal.c
index 078951af6e41..0b38e23898db 100644
--- a/server/signal.c
+++ b/server/signal.c
@@ -56,40 +56,17 @@ static void handler_destroy( struct object *obj );
 
 static const struct object_ops handler_ops =
 {
-    sizeof(struct handler),   /* size */
-    &no_type,                 /* type */
-    handler_dump,             /* dump */
-    no_add_queue,             /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    no_get_fd,                /* get_fd */
-    default_get_sync,         /* get_sync */
-    default_map_access,       /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
-    no_get_full_name,         /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    no_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,          /* close_handle */
-    handler_destroy           /* destroy */
+    .size    = sizeof(struct handler),
+    .type    = &no_type,
+    .dump    = handler_dump,
+    .destroy = handler_destroy,
 };
 
 static void handler_poll_event( struct fd *fd, int event );
 
 static const struct fd_ops handler_fd_ops =
 {
-    NULL,                     /* get_poll_events */
-    handler_poll_event,       /* poll_event */
-    NULL,                     /* flush */
-    NULL,                     /* get_fd_type */
-    NULL,                     /* ioctl */
-    NULL,                     /* queue_async */
-    NULL                      /* reselect_async */
+    .poll_event = handler_poll_event,
 };
 
 static struct handler *handler_sighup;
diff --git a/server/sock.c b/server/sock.c
index fdc26bc22763..e3be1bbbae27 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -479,43 +479,24 @@ static void poll_socket( struct sock *poll_sock, struct async *async, int exclus
 
 static const struct object_ops sock_ops =
 {
-    sizeof(struct sock),          /* size */
-    &file_type,                   /* type */
-    sock_dump,                    /* dump */
-    NULL,                         /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    sock_get_fd,                  /* get_fd */
-    default_fd_get_sync,          /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    no_get_full_name,             /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    no_link_name,                 /* link_name */
-    NULL,                         /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    sock_close_handle,            /* close_handle */
-    sock_destroy                  /* destroy */
+    .size         = sizeof(struct sock),
+    .type         = &file_type,
+    .dump         = sock_dump,
+    .get_fd       = sock_get_fd,
+    .get_sync     = default_fd_get_sync,
+    .close_handle = sock_close_handle,
+    .destroy      = sock_destroy,
 };
 
 static const struct fd_ops sock_fd_ops =
 {
-    sock_get_poll_events,         /* get_poll_events */
-    sock_poll_event,              /* poll_event */
-    sock_get_fd_type,             /* get_fd_type */
-    no_fd_read,                   /* read */
-    no_fd_write,                  /* write */
-    no_fd_flush,                  /* flush */
-    default_fd_get_file_info,     /* get_file_info */
-    no_fd_get_volume_info,        /* get_volume_info */
-    sock_ioctl,                   /* ioctl */
-    sock_cancel_async,            /* cancel_async */
-    no_fd_queue_async,            /* queue_async */
-    sock_reselect_async           /* reselect_async */
+    .get_poll_events = sock_get_poll_events,
+    .poll_event      = sock_poll_event,
+    .get_fd_type     = sock_get_fd_type,
+    .get_file_info   = default_fd_get_file_info,
+    .ioctl           = sock_ioctl,
+    .cancel_async    = sock_cancel_async,
+    .reselect_async  = sock_reselect_async,
 };
 
 static int sockaddr_from_unix( const union unix_sockaddr *uaddr, struct WS_sockaddr *wsaddr, socklen_t wsaddrlen )
@@ -2742,6 +2723,11 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
             set_error( STATUS_INVALID_ADDRESS );
             return;
         }
+        if (sock->state == SOCK_UNCONNECTED) /* clear events */
+        {
+            sock->pending_events &= ~AFD_POLL_CONNECT_ERR;
+            sock->reported_events &= ~AFD_POLL_CONNECT_ERR;
+        }
         if (unix_addr.addr.sa_family == AF_INET && !memcmp( &unix_addr.in.sin_addr, magic_loopback_addr, 4 ))
             unix_addr.in.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
 
@@ -3699,43 +3685,17 @@ struct ifchange
 
 static const struct object_ops ifchange_ops =
 {
-    sizeof(struct ifchange), /* size */
-    &no_type,                /* type */
-    ifchange_dump,           /* dump */
-    no_add_queue,            /* add_queue */
-    NULL,                    /* remove_queue */
-    NULL,                    /* signaled */
-    no_satisfied,            /* satisfied */
-    no_signal,               /* signal */
-    ifchange_get_fd,         /* get_fd */
-    default_get_sync,        /* get_sync */
-    default_map_access,      /* map_access */
-    default_get_sd,          /* get_sd */
-    default_set_sd,          /* set_sd */
-    no_get_full_name,        /* get_full_name */
-    no_lookup_name,          /* lookup_name */
-    no_link_name,            /* link_name */
-    NULL,                    /* unlink_name */
-    no_open_file,            /* open_file */
-    no_kernel_obj_list,      /* get_kernel_obj_list */
-    no_close_handle,         /* close_handle */
-    ifchange_destroy         /* destroy */
+    .size    = sizeof(struct ifchange),
+    .type    = &no_type,
+    .dump    = ifchange_dump,
+    .get_fd  = ifchange_get_fd,
+    .destroy = ifchange_destroy,
 };
 
 static const struct fd_ops ifchange_fd_ops =
 {
-    ifchange_get_poll_events, /* get_poll_events */
-    ifchange_poll_event,      /* poll_event */
-    NULL,                     /* get_fd_type */
-    no_fd_read,               /* read */
-    no_fd_write,              /* write */
-    no_fd_flush,              /* flush */
-    no_fd_get_file_info,      /* get_file_info */
-    no_fd_get_volume_info,    /* get_volume_info */
-    no_fd_ioctl,              /* ioctl */
-    NULL,                     /* cancel_async */
-    NULL,                     /* queue_async */
-    NULL                      /* reselect_async */
+    .get_poll_events = ifchange_get_poll_events,
+    .poll_event      = ifchange_poll_event,
 };
 
 static void ifchange_dump( struct object *obj, int verbose )
@@ -3921,27 +3881,11 @@ static struct object *socket_device_open_file( struct object *obj, unsigned int
 
 static const struct object_ops socket_device_ops =
 {
-    sizeof(struct object),      /* size */
-    &device_type,               /* type */
-    socket_device_dump,         /* dump */
-    no_add_queue,               /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    no_satisfied,               /* satisfied */
-    no_signal,                  /* signal */
-    no_get_fd,                  /* get_fd */
-    default_get_sync,           /* get_sync */
-    default_map_access,         /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    default_get_full_name,      /* get_full_name */
-    socket_device_lookup_name,  /* lookup_name */
-    directory_link_name,        /* link_name */
-    default_unlink_name,        /* unlink_name */
-    socket_device_open_file,    /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    no_destroy                  /* destroy */
+    .size        = sizeof(struct object),
+    .type        = &device_type,
+    .dump        = socket_device_dump,
+    .lookup_name = socket_device_lookup_name,
+    .open_file   = socket_device_open_file,
 };
 
 static void socket_device_dump( struct object *obj, int verbose )
diff --git a/server/symlink.c b/server/symlink.c
index 0dc607e0571b..b732bf1d7c00 100644
--- a/server/symlink.c
+++ b/server/symlink.c
@@ -64,27 +64,11 @@ static void symlink_destroy( struct object *obj );
 
 static const struct object_ops symlink_ops =
 {
-    sizeof(struct symlink),       /* size */
-    &symlink_type,                /* type */
-    symlink_dump,                 /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    default_get_full_name,        /* get_full_name */
-    symlink_lookup_name,          /* lookup_name */
-    directory_link_name,          /* link_name */
-    default_unlink_name,          /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    no_close_handle,              /* close_handle */
-    symlink_destroy               /* destroy */
+    .size        = sizeof(struct symlink),
+    .type        = &symlink_type,
+    .dump        = symlink_dump,
+    .lookup_name = symlink_lookup_name,
+    .destroy     = symlink_destroy,
 };
 
 static void symlink_dump( struct object *obj, int verbose )
@@ -177,7 +161,10 @@ struct object *create_obj_symlink( struct object *root, const struct unicode_str
     data_size_t len;
     WCHAR *target_name;
 
-    if (!(target_name = target->ops->get_full_name( target, ~0u, &len )))
+    if (target->ops->get_full_name) target_name = target->ops->get_full_name( target, ~0u, &len );
+    else target_name = default_get_full_name( target, ~0u, &len );
+
+    if (!target_name)
     {
         set_error( STATUS_INVALID_PARAMETER );
         return NULL;
diff --git a/server/thread.c b/server/thread.c
index 19c928f7beed..f0f128ad4d65 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -94,34 +94,18 @@ struct thread_apc
     union apc_result    result;   /* call results once executed */
 };
 
-static void dump_thread_apc( struct object *obj, int verbose );
+static void thread_apc_dump( struct object *obj, int verbose );
 static struct object *thread_apc_get_sync( struct object *obj );
 static void thread_apc_destroy( struct object *obj );
 static void clear_apc_queue( struct list *queue );
 
 static const struct object_ops thread_apc_ops =
 {
-    sizeof(struct thread_apc),  /* size */
-    &no_type,                   /* type */
-    dump_thread_apc,            /* dump */
-    NULL,                       /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    NULL,                       /* satisfied */
-    no_signal,                  /* signal */
-    no_get_fd,                  /* get_fd */
-    thread_apc_get_sync,        /* get_sync */
-    default_map_access,         /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    no_get_full_name,           /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    no_link_name,               /* link_name */
-    NULL,                       /* unlink_name */
-    no_open_file,               /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    thread_apc_destroy          /* destroy */
+    .size     = sizeof(struct thread_apc),
+    .type     = &no_type,
+    .dump     = thread_apc_dump,
+    .get_sync = thread_apc_get_sync,
+    .destroy  = thread_apc_destroy,
 };
 
 
@@ -141,33 +125,17 @@ struct context
 /* flags for registers that always need to be set from the server side */
 static const unsigned int system_flags = SERVER_CTX_DEBUG_REGISTERS;
 
-static void dump_context( struct object *obj, int verbose );
+static void context_dump( struct object *obj, int verbose );
 static struct object *context_get_sync( struct object *obj );
 static void context_destroy( struct object *obj );
 
 static const struct object_ops context_ops =
 {
-    sizeof(struct context),     /* size */
-    &no_type,                   /* type */
-    dump_context,               /* dump */
-    NULL,                       /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    NULL,                       /* satisfied */
-    no_signal,                  /* signal */
-    no_get_fd,                  /* get_fd */
-    context_get_sync,           /* get_sync */
-    default_map_access,         /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    no_get_full_name,           /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    no_link_name,               /* link_name */
-    NULL,                       /* unlink_name */
-    no_open_file,               /* open_file */
-    no_kernel_obj_list,         /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    context_destroy,            /* destroy */
+    .size     = sizeof(struct context),
+    .type     = &no_type,
+    .dump     = context_dump,
+    .get_sync = context_get_sync,
+    .destroy  = context_destroy,
 };
 
 
@@ -188,47 +156,27 @@ struct type_descr thread_type =
     },
 };
 
-static void dump_thread( struct object *obj, int verbose );
+static void thread_dump( struct object *obj, int verbose );
 static struct object *thread_get_sync( struct object *obj );
 static unsigned int thread_map_access( struct object *obj, unsigned int access );
 static void thread_poll_event( struct fd *fd, int event );
 static struct list *thread_get_kernel_obj_list( struct object *obj );
-static void destroy_thread( struct object *obj );
+static void thread_destroy( struct object *obj );
 
 static const struct object_ops thread_ops =
 {
-    sizeof(struct thread),      /* size */
-    &thread_type,               /* type */
-    dump_thread,                /* dump */
-    NULL,                       /* add_queue */
-    NULL,                       /* remove_queue */
-    NULL,                       /* signaled */
-    NULL,                       /* satisfied */
-    no_signal,                  /* signal */
-    no_get_fd,                  /* get_fd */
-    thread_get_sync,            /* get_sync */
-    thread_map_access,          /* map_access */
-    default_get_sd,             /* get_sd */
-    default_set_sd,             /* set_sd */
-    no_get_full_name,           /* get_full_name */
-    no_lookup_name,             /* lookup_name */
-    no_link_name,               /* link_name */
-    NULL,                       /* unlink_name */
-    no_open_file,               /* open_file */
-    thread_get_kernel_obj_list, /* get_kernel_obj_list */
-    no_close_handle,            /* close_handle */
-    destroy_thread              /* destroy */
+    .size                = sizeof(struct thread),
+    .type                = &thread_type,
+    .dump                = thread_dump,
+    .get_sync            = thread_get_sync,
+    .map_access          = thread_map_access,
+    .get_kernel_obj_list = thread_get_kernel_obj_list,
+    .destroy             = thread_destroy,
 };
 
 static const struct fd_ops thread_fd_ops =
 {
-    NULL,                       /* get_poll_events */
-    thread_poll_event,          /* poll_event */
-    NULL,                       /* flush */
-    NULL,                       /* get_fd_type */
-    NULL,                       /* ioctl */
-    NULL,                       /* queue_async */
-    NULL                        /* reselect_async */
+    .poll_event = thread_poll_event,
 };
 
 static struct list thread_list = LIST_INIT(thread_list);
@@ -459,7 +407,7 @@ static inline int is_valid_address( client_ptr_t addr )
 
 
 /* dump a context on stdout for debugging purposes */
-static void dump_context( struct object *obj, int verbose )
+static void context_dump( struct object *obj, int verbose )
 {
     struct context *context = (struct context *)obj;
     assert( obj->ops == &context_ops );
@@ -651,7 +599,7 @@ static void cleanup_thread( struct thread *thread )
 }
 
 /* destroy a thread when its refcount is 0 */
-static void destroy_thread( struct object *obj )
+static void thread_destroy( struct object *obj )
 {
     struct thread *thread = (struct thread *)obj;
     assert( obj->ops == &thread_ops );
@@ -666,7 +614,7 @@ static void destroy_thread( struct object *obj )
 }
 
 /* dump a thread on stdout for debugging purposes */
-static void dump_thread( struct object *obj, int verbose )
+static void thread_dump( struct object *obj, int verbose )
 {
     struct thread *thread = (struct thread *)obj;
     assert( obj->ops == &thread_ops );
@@ -690,7 +638,7 @@ static unsigned int thread_map_access( struct object *obj, unsigned int access )
     return access;
 }
 
-static void dump_thread_apc( struct object *obj, int verbose )
+static void thread_apc_dump( struct object *obj, int verbose )
 {
     struct thread_apc *apc = (struct thread_apc *)obj;
     assert( obj->ops == &thread_apc_ops );
@@ -1028,7 +976,7 @@ void set_wait_status( struct wait_queue_entry *entry, int status )
 static void object_sync_satisfied( struct object *obj, struct wait_queue_entry *entry )
 {
     struct object *sync = get_obj_sync( obj );
-    sync->ops->satisfied( sync, entry );
+    if (sync->ops->satisfied) sync->ops->satisfied( sync, entry );
     release_object( sync );
 }
 
@@ -1042,7 +990,10 @@ static void object_sync_remove_queue( struct object *obj, struct wait_queue_entr
 static int object_sync_add_queue( struct object *obj, struct wait_queue_entry *entry )
 {
     struct object *sync = get_obj_sync( obj );
-    int ret = sync->ops->add_queue( sync, entry );
+    int ret = 0;
+
+    if (sync->ops->add_queue) ret = sync->ops->add_queue( sync, entry );
+    else set_error( STATUS_OBJECT_TYPE_MISMATCH );
     release_object( sync );
     return ret;
 }
@@ -1307,7 +1258,8 @@ static int signal_object( obj_handle_t handle )
     obj = get_handle_obj( current->process, handle, 0, NULL );
     if (obj)
     {
-        ret = obj->ops->signal( obj, get_handle_access( current->process, handle ), -1 );
+        if (obj->ops->signal) ret = obj->ops->signal( obj, get_handle_access( current->process, handle ), -1 );
+        else set_error( STATUS_OBJECT_TYPE_MISMATCH );
         release_object( obj );
     }
     return ret;
diff --git a/server/timer.c b/server/timer.c
index 4e3a14c4a18b..55eb67830627 100644
--- a/server/timer.c
+++ b/server/timer.c
@@ -69,27 +69,11 @@ static void timer_destroy( struct object *obj );
 
 static const struct object_ops timer_ops =
 {
-    sizeof(struct timer),      /* size */
-    &timer_type,               /* type */
-    timer_dump,                /* dump */
-    NULL,                      /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    timer_get_sync,            /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    default_set_sd,            /* set_sd */
-    default_get_full_name,     /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    directory_link_name,       /* link_name */
-    default_unlink_name,       /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    timer_destroy              /* destroy */
+    .size     = sizeof(struct timer),
+    .type     = &timer_type,
+    .dump     = timer_dump,
+    .get_sync = timer_get_sync,
+    .destroy  = timer_destroy,
 };
 
 
diff --git a/server/token.c b/server/token.c
index 886386748d5a..a8605a5f1727 100644
--- a/server/token.c
+++ b/server/token.c
@@ -138,27 +138,11 @@ static int token_set_sd( struct object *obj, const struct security_descriptor *s
 
 static const struct object_ops token_ops =
 {
-    sizeof(struct token),      /* size */
-    &token_type,               /* type */
-    token_dump,                /* dump */
-    no_add_queue,              /* add_queue */
-    NULL,                      /* remove_queue */
-    NULL,                      /* signaled */
-    NULL,                      /* satisfied */
-    no_signal,                 /* signal */
-    no_get_fd,                 /* get_fd */
-    default_get_sync,          /* get_sync */
-    default_map_access,        /* map_access */
-    default_get_sd,            /* get_sd */
-    token_set_sd,              /* set_sd */
-    no_get_full_name,          /* get_full_name */
-    no_lookup_name,            /* lookup_name */
-    no_link_name,              /* link_name */
-    NULL,                      /* unlink_name */
-    no_open_file,              /* open_file */
-    no_kernel_obj_list,        /* get_kernel_obj_list */
-    no_close_handle,           /* close_handle */
-    token_destroy              /* destroy */
+    .size    = sizeof(struct token),
+    .type    = &token_type,
+    .dump    = token_dump,
+    .set_sd  = token_set_sd,
+    .destroy = token_destroy,
 };
 
 static void token_dump( struct object *obj, int verbose )
@@ -1092,7 +1076,7 @@ int check_object_access(struct token *token, struct object *obj, unsigned int *a
     if (!token)
         token = current->token ? current->token : current->process->token;
 
-    mapping.all = obj->ops->map_access( obj, GENERIC_ALL );
+    mapping.all = map_obj_access( obj, GENERIC_ALL );
 
     if (!obj->sd)
     {
@@ -1100,9 +1084,9 @@ int check_object_access(struct token *token, struct object *obj, unsigned int *a
         return TRUE;
     }
 
-    mapping.read  = obj->ops->map_access( obj, GENERIC_READ );
-    mapping.write = obj->ops->map_access( obj, GENERIC_WRITE );
-    mapping.exec = obj->ops->map_access( obj, GENERIC_EXECUTE );
+    mapping.read  = map_obj_access( obj, GENERIC_READ );
+    mapping.write = map_obj_access( obj, GENERIC_WRITE );
+    mapping.exec  = map_obj_access( obj, GENERIC_EXECUTE );
 
     res = token_access_check( token, obj->sd, *access, NULL, NULL,
                               &mapping, access, &status ) == STATUS_SUCCESS &&
diff --git a/server/window.c b/server/window.c
index 73bad9007061..712432bb2ab3 100644
--- a/server/window.c
+++ b/server/window.c
@@ -99,27 +99,10 @@ static void window_destroy( struct object *obj );
 
 static const struct object_ops window_ops =
 {
-    sizeof(struct window),    /* size */
-    &no_type,                 /* type */
-    window_dump,              /* dump */
-    no_add_queue,             /* add_queue */
-    NULL,                     /* remove_queue */
-    NULL,                     /* signaled */
-    NULL,                     /* satisfied */
-    no_signal,                /* signal */
-    no_get_fd,                /* get_fd */
-    default_get_sync,         /* get_sync */
-    default_map_access,       /* map_access */
-    default_get_sd,           /* get_sd */
-    default_set_sd,           /* set_sd */
-    no_get_full_name,         /* get_full_name */
-    no_lookup_name,           /* lookup_name */
-    no_link_name,             /* link_name */
-    NULL,                     /* unlink_name */
-    no_open_file,             /* open_file */
-    no_kernel_obj_list,       /* get_kernel_obj_list */
-    no_close_handle,          /* close_handle */
-    window_destroy            /* destroy */
+    .size    = sizeof(struct window),
+    .type    = &no_type,
+    .dump    = window_dump,
+    .destroy = window_destroy,
 };
 
 /* flags that can be set by the client */
diff --git a/server/winstation.c b/server/winstation.c
index 4329f9f4384a..9657c112e483 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -69,27 +69,12 @@ struct type_descr winstation_type =
 
 static const struct object_ops winstation_ops =
 {
-    sizeof(struct winstation),    /* size */
-    &winstation_type,             /* type */
-    winstation_dump,              /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    default_get_full_name,        /* get_full_name */
-    winstation_lookup_name,       /* lookup_name */
-    directory_link_name,          /* link_name */
-    default_unlink_name,          /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    winstation_close_handle,      /* close_handle */
-    winstation_destroy            /* destroy */
+    .size         = sizeof(struct winstation),
+    .type         = &winstation_type,
+    .dump         = winstation_dump,
+    .lookup_name  = winstation_lookup_name,
+    .close_handle = winstation_close_handle,
+    .destroy      = winstation_destroy,
 };
 
 
@@ -110,27 +95,12 @@ struct type_descr desktop_type =
 
 static const struct object_ops desktop_ops =
 {
-    sizeof(struct desktop),       /* size */
-    &desktop_type,                /* type */
-    desktop_dump,                 /* dump */
-    no_add_queue,                 /* add_queue */
-    NULL,                         /* remove_queue */
-    NULL,                         /* signaled */
-    NULL,                         /* satisfied */
-    no_signal,                    /* signal */
-    no_get_fd,                    /* get_fd */
-    default_get_sync,             /* get_sync */
-    default_map_access,           /* map_access */
-    default_get_sd,               /* get_sd */
-    default_set_sd,               /* set_sd */
-    default_get_full_name,        /* get_full_name */
-    no_lookup_name,               /* lookup_name */
-    desktop_link_name,            /* link_name */
-    default_unlink_name,          /* unlink_name */
-    no_open_file,                 /* open_file */
-    no_kernel_obj_list,           /* get_kernel_obj_list */
-    desktop_close_handle,         /* close_handle */
-    desktop_destroy               /* destroy */
+    .size         = sizeof(struct desktop),
+    .type         = &desktop_type,
+    .dump         = desktop_dump,
+    .link_name    = desktop_link_name,
+    .close_handle = desktop_close_handle,
+    .destroy      = desktop_destroy,
 };
 
 /* create a winstation object */
