diff --git a/ANNOUNCE.md b/ANNOUNCE.md
index 1dd4f594aace..133d5726ebc2 100644
--- a/ANNOUNCE.md
+++ b/ANNOUNCE.md
@@ -1,13 +1,12 @@
-The Wine development release 11.5 is now available.
+The Wine development release 11.6 is now available.
 
 What's new in this release:
-  - C++ support in the build system.
-  - Bundled ICU libraries.
-  - Support for Syscall User Dispatch on Linux.
-  - A number of VBScript compatibility fixes.
+  - Beginnings of a revival of the Android driver.
+  - DLL load order heuristics to better support game mods.
+  - More VBScript compatibility fixes.
   - Various bug fixes.
 
-The source is available at <https://dl.winehq.org/wine/source/11.x/wine-11.5.tar.xz>
+The source is available at <https://dl.winehq.org/wine/source/11.x/wine-11.6.tar.xz>
 
 Binary packages for various distributions will be available
 from the respective [download sites][1].
@@ -19,310 +18,389 @@ 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.5/AUTHORS
+[3]: https://gitlab.winehq.org/wine/wine/-/raw/wine-11.6/AUTHORS
 
 ----------------------------------------------------------------
 
-### Bugs fixed in 11.5 (total 22):
-
- - #31047  unable to edit gedit's preferences
- - #35904  USB connection not recognized by Axon MultiClamp Commander 700B.
- - #42687  Evernote installation fails
- - #42811  PCG Tools Application fails to install
- - #48291  Multiple applications crash due to direct use of x86_64 SYSCALL instruction (Detroit: Become Human, Red Dead Redemption 2, Arknights: Endfield)
- - #50532  get_timezone_info doing binary search in the wrong way
- - #50636  Reading indexed bitmap wrongly returns 32bit instead of 8bit
- - #55037  vbscript: Colon on new line after Then fails
- - #58806  Smart quotes in code example misleads clang
- - #58963  Stratego (1997) fails to start with error message "Unable to 'CreateScalableFontResource()'"
- - #59138  Timelapse export failing in Clip Studio Paint
- - #59223  Sony Home Memories Throws Unrecoverable error during installation
- - #59314  Swift crashes on unimplemented function ADVAPI32.dll.SaferiIsExecutableFileType
- - #59361  MDI child window creation don't respect the window attribute (not WS_MAXIMIZEBOX)
- - #59460  bcrypt: Implement RSA-OAEP padding defaults (fixes Wallpaper Engine mobile sync)
- - #59474  File dialog crashes in .NET applications like UndertaleModTool
- - #59502  VOCALOID6 crashes on startup due to unimplemented wminet_utils stubs
- - #59504  jscript: GetScriptDispatch("") returns E_INVALIDARG instead of global dispatch
- - #59514  time()/localtime() performance has regressed significantly
- - #59531  CertCreateCertificateChainEngine fails with invalid argument in rustls-platform-verifier
- - #59541  replacing bass.dll with samp.dll causes freeze/black screen under wine . samp.dll works fine under windows
- - #59542  CEF crashes in dwrite when browsing The Verge (weird font file)
-
-### Changes since 11.4:
+### Bugs fixed in 11.6 (total 28):
+
+ - #7961   Bug in findfirst/findnext
+ - #26389  Win3.1 Notepad crashes when opening a large file
+ - #38874  Homesite+ (v5.5): Radiobutton in Find dialog not set properly when using keyboard shortcut (Alt+U)
+ - #42517  StarOffice51 Crash on File open
+ - #45289  Wine Crashes Some Programs If Compiled with AVX Support
+ - #49776  .NET application settings are never saved
+ - #51577  Google Earth Installer renders mostly black
+ - #52019  DigiCertUtil wrong window size
+ - #52741  Missing chakra.dll to run Minecraft Windows 10 Edition
+ - #55933  NSFW game 'Creature reaction inside the ship! 1.5' videos stop after looping a few times
+ - #56296  PDFSam Installer shows an empty language list
+ - #58043  Multiple applications won't run on Wine 10.3 because they think that there is a debugger running when there isn't (DVDFab, DCS World updater)
+ - #58146  HWiNFO 8.24 (latest): doesn't work unless winecfg is set to Windows 7
+ - #58690  fw_manager_IsPortAllowed is not implemented
+ - #59486  Treeview TVS_CHECKBOXES cycle all state images with non-zero index
+ - #59498  pdf-xchange editor v10.8.4.409 crashes at start.
+ - #59536  Missing WINHTTP_OPTION_SERVER_CERT_CHAIN_CONTEXT
+ - #59546  Commit 20b34866 breaks the list of on-line multiplayer servers for the game Mount & Blade: Warband
+ - #59548  Neko Project emulator no longer works with 96 kHz sampling rate (Gentoo Linux)
+ - #59551  Buhl Tax 2026 shows blank preview - crash on geometry creation
+ - #59553  ICU dlls cause some games to crash (Cyberpunk 2077)
+ - #59554  DOAXVV (DMM version) fails to start with network error
+ - #59559  Missing D3D11 Interop Functions needed for Gecko based browsers
+ - #59561  VICE: GTK version of x64sc.exe crashes at startup.
+ - #59563  printf does not support %Z
+ - #59573  Regression introduced by decompression support in winhttp
+ - #59576  EIZO ColorNavigator 6 crashes on unimplemented function mscms.dll.WcsGetCalibrationManagementState
+ - #59600  Regression on 11.5 - Diablo IV in game-menu shop no more reachable
+
+### Changes since 11.5:
 ```
-Akihiro Sagawa (3):
-      po: Update Japanese translation.
-      ole32/tests: Add more RegisterDragDrop tests after mismatched cleanup.
-      ole32: Relax COM initialization check in RegisterDragDrop.
-
-Alexandre Julliard (14):
-      gitlab: Use Buildah instead of Kaniko to build images.
-      makefiles: Add support for C++ sources.
-      configure: Check for C++17 support.
-      include: Import C++ headers from LLVM version 8.0.1.
-      comctl32/tests: Add some optional treeview messages.
-      makedep: Specify dll name when it can't be guessed from the spec file name.
-      makedep: Still build asm files if the subdir doesn't match a known platform.
-      makedep: Ignore internal static libraries that are disabled.
-      makedep: Don't ignore disabled libs specified with the -l flag.
-      libs: Import icucommon from upstream MS-ICU release 72.1.0.3.
-      libs: Import icui18n from upstream MS-ICU release 72.1.0.3.
-      unicode: Generate the ICU data file.
-      icu: Add dll.
-      ntdll: Disable syscall dispatch when loading a .so dll.
-
-Alistair Leslie-Hughes (6):
-      combase: Add RoFailFastWithErrorContext stub.
-      include: Fix PromptDataSource parameter type.
-      windows.ui.core.textinput: Fake success in ICoreInputView4::add_PrimaryViewHiding.
-      windows.ui.core.textinput: Return S_OK in ICoreInputView::TryHidePrimaryView.
-      windows.ui.core.textinput: Return S_OK in ICoreInputView::TryShowPrimaryView.
-      twinapi.appcore: Support Windows.ApplicationModel.DataTransfer.DataTransferManager.
-
-Andrew Nguyen (2):
-      wminet_utils: Implement Get.
-      wminet_utils: Implement CreateInstanceEnumWmi.
-
-Anton Baskanov (8):
-      dmsynth/tests: Add some polyphony tests.
-      dmsynth: Restore pre-2.4.3 fluidsynth note-cut behavior.
-      dmsynth: Put each channel into a separate channel group.
-      dsound: Calculate required_input more accurately.
-      dsound: Swap around the two nested loops in downsample.
-      dsound: Calculate firgain more accurately.
-      dsound: Transpose the FIR array to make the element access sequential.
-      dsound: Premultiply the input value by firgain and the interpolation weights in downsample.
-
-Bernhard Kölbl (8):
-      windows.media.speech/tests: Change a value check.
-      windows.media.speech/tests: Skip some voice tests on Windows 8.
-      windows.media.speech: Make sure voice provider is initialized before returning default voice.
-      windows.media.speech: Set pointer to NULL.
-      mf: Prevent invalid topologies from being started.
-      mfreadwrite/tests: Test IMFByteStream release behavior.
-      mfsrcsnk/tests: Test IMFByteStream release behavior.
-      mfsrcsnk: Move IMFByteStream release into IMFMediaSource_Shutdown().
-
-Brendan McGrath (18):
-      mf/tests: Test decoder node for MARKIN/MARKOUT attributes.
-      mf: Add MARKIN/MARKOUT attributes to decoder node.
-      mf/tests: Move logic for sending delayed samples to helper function.
-      mf/tests: Modify topology to start with no resolution.
-      mf/tests: Test MARKIN will result in a trimmed sample.
-      mf: Drop samples from transform if MARKIN_HERE is set.
-      mf: Trim samples from transform if MARKIN_HERE is set.
-      mf: Replace state variable with clock_state.
-      mf: Implement presentation time source for SAR.
-      mf: Check provided presentation clock has a time source.
-      mf: Implement Scrubbing in SAR.
-      mf: Discard samples prior to current seek time.
-      mf: Report seek time up until we render past this point.
-      mfmediaengine: Reset the sample requested flag on Stop.
-      mfmediaengine: Implement looping behaviour.
-      mfmediaengine: Keep the last presentation sample on flush.
-      mf: Handle ENDOFSEGMENT marker in SAR.
-      mfmediaengine: Implement scrubbing.
-
-Brendan Shanks (1):
-      server: On ARM64, only list 32-bit ARM as a supported architecture if the CPU supports it.
-
-Conor McCarthy (2):
-      winegstreamer: Do not copy the incorrect buffer.
-      win32u/d3dkmt: Close the wait handle with NtClose() in NtGdiDdDDIAcquireKeyedMutex2().
-
-Daniel Lehman (3):
-      mxsml3/tests: Add tests for put_text.
-      msxml3/tests: Skip put_text test for now.
-      msxml3: Don't add cloned doc to orphan list.
-
-Diego Colin (1):
-      comctl32: Fix some typos in the comments.
-
-Dmitry Timoshkov (3):
-      user32/tests: Make test_ShowWindow_mdichild() use real MDI child windows.
-      user32/tests: Test switching from a maximized MDI child to a child without WS_MAXIMIZEBOX.
-      user32: Respect WS_MAXIMIZEBOX of the MDI child being activated.
-
-Doug Johnson (1):
-      advapi32: Add SaferiIsExecutableFileType stub.
-
-Elizabeth Figura (8):
-      d3d9/tests: Test format conversion in StretchRect().
-      wined3d: Implement format conversion in the Vulkan blitter.
-      ddraw: Fix caps tracing in IDirectDraw7::GetCaps().
-      wined3d/vk: Implement fill mode.
-      wined3d/hlsl: Force branching in branches that guard pow().
-      ntdll: Implement syscall emulation on Linux using Syscall User Dispatch.
-      gdi32: Redirect system32 in CreateScalableFontResourceW().
-      gdi32: Redirect system32 in AddFontResourceEx().
-
-Eric Pouech (5):
-      kernelbase: Fix signature of TerminateProcess().
-      include: Add same guard features as SDK does.
-      include: Define struct _SECURITY_DESCRIPTOR*.
-      include: Move NT_TIB(32|64) definitions in winnt.h.
-      dbghelp/dwarf: Properly ignore Dwarf-5 compilation units.
-
-Francis De Brabandere (12):
-      vbscript: Split() should return an empty array for empty strings.
-      vbscript: Do not fail on colon-prefixed statements in If blocks.
-      vbscript: Allow empty Else blocks in If statements.
-      vbscript: Fix ElseIf and Else handling for inline and multi-line forms.
-      vbscript: Allow Me(Idx) to compile as a call to the default property.
-      vbscript: Return "Object required" error for non-dispatch types.
-      vbscript: Return proper error for For Each on non-collection types.
-      vbscript: Support calling named item objects with arguments.
-      vbscript: Report correct error character position for invalid parenthesized call.
-      vbscript: Map DISP_E_DIVBYZERO to VBScript error 11.
-      vbscript: Return type mismatch error for indexed assignment to non-array variables.
-      vbscript: Allow Const to be used before its declaration.
+Adam Markowski (3):
+      po: Update Polish translation.
+      po: Update Polish translation.
+      po: Update Polish translation.
+
+Akihiro Sagawa (5):
+      winegstreamer: Flush wg_transform buffers on seek in quartz_transform.c.
+      quartz/tests: Add more video format tests for MPEG-1 Splitter.
+      winegstreamer: Pass MPEG-1 video codec data to the GStreamer decoder.
+      winegstreamer: Increase the buffer count in the MPEG video output.
+      quartz/tests: Remove todo_wine from tests that succeed now.
+
+Alexandre Julliard (27):
+      configure: Warn when the C++ compiler is missing or not working.
+      gdi32: Also redirect path in RemoveFontResourceEx.
+      server: Add a helper function to trace a Unicode string.
+      server: Share more code between 32- and 64-bit PE data directory handling.
+      ntdll: Add a structure to return information about a PE mapping.
+      server: Return version resource in get_mapping_info for native dlls.
+      ntdll: Add heuristics to prefer native dll based on the version resource.
+      wtsapi32/tests: Skip processes that no longer exist.
+      ldap: Correctly grow the buffer on incomplete message.
+      configure: Require a PE compiler on 64-bit macOS.
+      configure: Stop using libunwind.
+      configure: Check for gradle on Android.
+      configure: Pass ANDROID_HOME when building the Android APK.
+      ntdll: Fix a printf format warning.
+      ntoskrnl: Update the security cookie once relocation are applied.
+      kernelbase: Update timezone data to version 2026a.
+      zlib: Import upstream release 1.3.2.
+      png: Import upstream release 1.6.56.
+      lcms2: Import upstream release 2.18.
+      ntdll: Move the prefix bootstrap check out of is_builtin_path().
+      ntdll: Pass the full PE mapping info to get_load_order().
+      ntdll: Also consider wow64 system directory for module load order.
+      ntdll: Only set the version resource child when found in version_find_key.
+      winecrt0: Add LGPL license exception.
+      msvcrt: Add LGPL license exception.
+      vcruntime140: Add LGPL license exception.
+      libs: Add LGPL license exception to the uuid libraries.
+
+Alistair Leslie-Hughes (3):
+      winhttp: Support Query option WINHTTP_OPTION_SECURITY_INFO.
+      ntdll: Correct last parameter of NtFlushVirtualMemory.
+      comctl32/imagelist: Allow for larger initial image count.
+
+Anton Baskanov (1):
+      dsound: Make i signed in downsample.
+
+Aurimas Fišeras (1):
+      po: Update Lithuanian translation.
+
+Bartosz Kosiorek (5):
+      gdiplus: Fix GdipGetImageBounds result in case Graphics is deleted.
+      gdiplus: Return InvalidParameter in GdipGetImageHorizontalResolution in case HEMF is missing.
+      gdiplus: Return InvalidParameter in GdipGetImageVerticalResolution in case HEMF is missing.
+      gdiplus: Return InvalidParameter in GdipGetImageWidth in case HEMF is missing.
+      gdiplus: Return InvalidParameter in GdipGetImageHeight in case HEMF is missing.
+
+Benoît Legat (2):
+      crypt32: Implement CERT_NCRYPT_KEY_HANDLE_PROP_ID support.
+      crypt32: Implement PFXExportCertStoreEx support.
+
+Bernhard Übelacker (2):
+      mmdevapi: Avoid copying more memory than reserved in validate_fmt (ASan).
+      d2d1: Allow value NULL in d2d_effect_SetInput.
+
+Brendan McGrath (7):
+      wmvcore: Test we can open a rawvideo wmv file.
+      winegstreamer: Place 'videoconvert' prior to 'deinterlace' element.
+      iyuv_32: Add stub dll.
+      iyuv_32/tests: Add test stub.
+      iyuv_32/tests: Test which formats are supported.
+      iyuv_32/tests: Add a decompression test.
+      iyuv_32/tests: Add a compression test.
+
+Brendan Shanks (4):
+      ntdll/tests: In wow64, factor the SYSTEM_INFORMATION_CLASS out of test_query_architectures().
+      ntdll/tests: Add tests for NtQuerySystemInformation(SystemSupportedProcessorArchitectures2).
+      ntdll: Implement NtQuerySystemInformation(SystemSupportedProcessorArchitectures2).
+      server: Add x86_64 as a supported machine on ARM64.
+
+Chris Kadar (1):
+      cabinet: Add stubs for compressor/decompressor.
+
+Connor McAdams (8):
+      dinput/tests: Fix occasional GameInput test crash.
+      dinput/tests: Fix incorrect index when removing child device.
+      include: Fix HID_STRING_ID_* definitions.
+      dinput/tests: Add tests for HID device indexed strings.
+      dinput/tests: Check child device serial, if provided, on remove.
+      dinput/tests: Cleanup every device key with winetest vendor.
+      dinput/tests: Test that guidInstance is stable across hotplugs.
+      dinput/tests: Add tests for dinput joystick guidInstance values.
+
+Conor McCarthy (6):
+      mf: Trace additional topology details.
+      mf/topology_loader: Do not create a new branch list containing downstreamm nodes.
+      mf/topology_loader: Delete unused struct connect_context.
+      mf/topology_loader: Load the branch up connection method only for source nodes.
+      mf: Specify the multithreaded queue for presentation clock callbacks.
+      mf: Specify the multithreaded queue for sample grabber timer callbacks.
+
+Dmitry Timoshkov (6):
+      advapi32/tests: Add some tests for LockServiceDatabase().
+      services: Add proper handle management to LockServiceDatabase() and UnlockServiceDatabase().
+      advapi32: Implement LockServiceDatabase() and UnlockServiceDatabase().
+      winedump: Fix building with PSDK compiler.
+      crypt32/tests: Add some tests for CertOpenSystemStore() with real provider handle.
+      crypt32: Add CERT_STORE_NO_CRYPT_RELEASE_FLAG to CertOpenStore() flags when called from CertOpenSystemStore().
+
+Elizabeth Figura (7):
+      wined3d/vk: Handle stretching and format conversion when resolving as well.
+      wined3d: Do not force the source into RB_RESOLVED for a non-colour blit.
+      wined3d: Separate a raw_blitter_supported() helper.
+      wined3d: Require matching sample counts for the raw blitter.
+      wined3d: Move RB_RESOLVED logic from texture2d_blt() to texture2d_blt_fbo().
+      wined3d: Explicitly handle raw resolve in the FBO blitter.
+      wined3d: Explicitly pass the RAW flag for d3d10+ resolve.
+
+Eric Pouech (6):
+      mfplat: Add stub for MFSerializeAttributesToStream.
+      mf: Add stub for MFCreateDeviceSource().
+      include: Add missing extern "C" wrappers.
+      include: Don't use C++ keywords.
+      wevtapi: Add stub for EvtRender.
+      advapi32: Add stub for AddConditionalAce().
+
+Francis De Brabandere (24):
+      vbscript: Implement IActiveScriptError::GetSourceLineText.
+      vbscript: Invoke default property when calling object variable with empty parens.
+      vbscript: Pass VT_DISPATCH as-is to Property Let without extracting default value.
+      wscript: Implement IActiveScriptSite::OnScriptError.
+      vbscript: Allow hex literals with excess leading zeros.
+      vbscript: Fix dot member access after line continuation.
+      vbscript: Add error code tests for compile errors.
+      vbscript: Improve some error codes in the compiler.
+      vbscript: Improve some error codes in the lexer.
+      vbscript: Improve some error codes in the parser.
+      vbscript: Implement GetRef.
+      vbscript: Fix crash in ReDim on uninitialized dynamic arrays.
+      vbscript: Return "Object required" error (424) instead of E_FAIL/E_NOTIMPL.
+      vbscript: Return correct error for array dimension mismatch and NULL array access.
+      vbscript: Return type mismatch when calling non-dispatch variable as statement.
+      vbscript: Fix chained array indexing on call expression results.
+      vbscript: Allow Not operator as operand of comparison expressions.
+      vbscript: Implement AscW and ChrW functions.
+      vbscript: Report proper errors for invalid date literals and line continuations.
+      vbscript/tests: Enable Empty Mod test that now passes.
+      vbscript: Implement Escape and Unescape functions.
+      vbscript: Implement the Erase statement.
+      vbscript: Implement Eval, Execute, and ExecuteGlobal.
+      vbscript: Return error 92 for uninitialized For loops.
 
 Georg Lehmann (1):
-      winevulkan: Update to VK spec version 1.4.346.
-
-Giovanni Mascellani (15):
-      winmm/tests: Skip format tests if there is no available audio device.
-      mmdevapi/tests: Drop some corner-case tests.
-      winmm/tests: Drop some corner-case tests.
-      winepulse.drv: Support 24-bit PCM formats.
-      winepulse.drv: Allow cbSize to be larger than 22 bytes for extensible wave formats.
-      winepulse.drv: Remove support for A-law and mu-law formats.
-      winepulse.drv: Remove support for 24-in-32 bits formats.
-      mmdevapi: Do not query for format support in spatial audio.
-      mmdevapi: Take the wave format validation code from the tests.
-      mmdevapi/tests: Further tweak some corner-case tests.
-      winmm/tests: Further tweak some corner-case tests.
-      winmm: Do not try to convert sample rate or channel count.
-      winmm: Hard code the list of supported formats.
-      wineoss.drv: Describe 24-bit samples with AFMT_S24_PACKED when not on FreeBSD.
-      wineoss.drv: Reject wave formats with invalid bits.
-
-Hans Leidekker (10):
-      winhttp/tests: Don't send more data than the receive buffer can hold.
-      winhttp: WinHttpQueryDataAvailable() fails before a response has been received.
-      winhttp: Don't report data available for certain response statuses, even if there is data.
-      winhttp: Clear response headers after do_authorization().
-      winhttp: Also do NTLM autorization when credentials are set between requests.
-      winhttp: Introduce a stream abstraction.
-      winhttp: Add decompression support.
-      include: Update definition of CERT_CHAIN_ENGINE_CONFIG.
-      crypt32: Trace CERT_CHAIN_ENGINE_CONFIG fields in CertCreateCertificateChainEngine().
-      hnetcfg: Improve fw_manager_IsPortAllowed() stub.
-
-Jacek Caban (11):
-      tools: Treat -windows-gnu target as an LLVM-based toolchain.
-      configure: Default to mingw mode on 32-bit ARM targets.
-      vcruntime140: Add new and delete operators implementation to CRT library.
-      vcruntime140: Add __type_info_root_node implementation.
-      vcruntime140: Add support for MSVC thread-safe constructor initialization.
-      vcruntime140: Add type_info vtbl to the import library.
-      libs: Import libc++ from upstream LLVM version 8.0.1.
-      libs: Import libunwind from upstream LLVM version 8.0.1.
-      libs: Import libc++abi from upstream LLVM version 8.0.1.
-      fluidsynth: Import upstream release 2.4.3.
-      winegcc: Add default C++ libraries when using msvcrt.
-
-Kun Yang (1):
-      comctl32/tests: Test creating an imagelist with an excessively large initial image count.
+      winevulkan: Update to VK spec version 1.4.347.
+
+Gijs Vermeulen (1):
+      mscms: Add WcsGetCalibrationManagementState stub.
+
+Hans Leidekker (16):
+      winhttp: Fix querying available data for chunked transfers.
+      winhttp: Trace more option values.
+      winhttp: Accept WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL on session handles.
+      include: Add missing WinHTTP defines.
+      winhttp: Print a fixme for unsupported flags in WinHttpOpen() and WinHttpOpenRequest().
+      winhttp: Introduce struct read_buffer.
+      winhttp: Always buffer response data.
+      winhttp: Fix a typo.
+      winhttp/tests: Get rid of workarounds for old Windows versions.
+      winhttp: Ignore unexpected content encodings.
+      winhttp: Don't trace content read / content length in read_data().
+      winhttp: Move web socket support to a separate file.
+      winhttp: Use public define for the web socket handle type.
+      winhttp: Move pending_sends and pending_receives to the socket structure.
+      crypt32: Also accept CERT_CHAIN_ENGINE_CONFIG without dwExclusiveFlags.
+      bcrypt: Handle SHA512 in key_asymmetric_verify().
+
+Jacek Caban (1):
+      configure: Build PE modules with build ID by default.
+
+José Luis Jiménez López (1):
+      quartz/tests/avisplit: Add tests for IMediaSeeking time formats.
+
+June Wilde (1):
+      include: Add windows.graphics.directx.direct3d11.interop.idl file.
+
+Kun Yang (2):
+      taskschd/tests: Add tests for ILogonTrigger.
+      taskschd: Add implementation of ILogonTrigger.
 
 Louis Lenders (1):
-      ole32: Add stub for CoRegisterActivationFilter.
-
-Marc-Aurel Zent (1):
-      winemac: Avoid matching scan code 0 in GetKeyNameText.
-
-Michael Green (1):
-      winhttp: Implement WINHTTP_OPTION_SERVER_CERT_CHAIN_CONTEXT.
-
-Nello De Gregoris (4):
-      server: Allow creating directory kernel objects.
-      ntoskrnl.exe/tests: Add tests for directory kernel objects.
-      ntoskrnl.exe: Implement FsRtlGetFileSize().
-      ntoskrnl.exe/tests: Add tests for FsRtlGetFileSize().
-
-Nikolay Sivov (4):
-      mfplay: Remove incorrect fixme for MFP_EVENT_TYPE_ERROR.
-      d2d1: Do not reference layer objects when recording to the command list.
-      msxml3/sax: Do not attempt to add default attributes for definitions without values.
-      dwrite: Handle zero-length name strings.
-
-Paul Gofman (9):
-      win32u: Set VendorId / DeviceId in DirectX registry key with correct size.
-      shell32: Return S_OK from IShellLinkW_fnSetPath for nonexistent paths.
-      shell32: Remove trailing backslash in IShellLinkW_fnSetPath().
-      wshom.ocx: Implement WshShortcut_get_TargetPath().
-      wshom.ocx: Load shell link in WshShortcut_Create().
-      include: Add IMFMediaEngineClassFactoryEx and IMFMediaEngineClassFactory2 definitions.
-      mfmediaengine: Add IMFMediaEngineClassFactoryEx interface.
-      server: Cache timezone bias adjustment in set_user_shared_data_time().
-      comctl32/static: Set HALFTONE StretchBlt mode in STATIC_PaintBitmapfn().
-
-Piotr Caban (3):
-      ntdll: Read last error from wow teb in unixlib RtlGetLastWin32Error.
-      user32/tests: Test static control extra window data access.
-      user32: Make static control internal data private.
-
-Piotr Pawłowski (1):
-      comctl32/treeview: Fixed missing redraw of item being unfocused.
-
-Robert Gerigk (4):
-      jscript: Treat empty string as NULL in GetScriptDispatch.
-      vbscript: Treat empty string as NULL in GetScriptDispatch.
-      windowscodecs: Implement IWICFormatConverter for BlackWhite pixel format.
-      hidclass.sys: Report correct device type for HID device objects.
-
-Rémi Bernon (5):
-      setupapi: Cleanup SetupDiGetClassDescription(Ex)(A|W) code style.
-      setupapi: Reimplement SetupDiGetClassDescriptionExW using cfgmgr32.
-      setupapi: Forward CM_Get_Device_Interface_List(_Size)(_Ex)(A|W) to cfgmgr32.
-      setupapi: Use CM_Locate_DevNode_ExW to allocate devnode.
-      setupapi: Use CM_Get_Device_IDW to get devnode device.
-
-Santino Mazza (2):
-      msvcrt: Fastfail if _CALL_REPORTFAULT is set.
-      msvcrt: Call abort at the end of _wassert.
-
-Stefan Dösinger (5):
-      d3d8: Build a valid box in d3d8_vertexbuffer_Lock.
-      d3d8: Build a valid box in d3d8_indexbuffer_Lock.
-      ddraw/tests: Fix vertex winding in test_ck_rgba.
-      ddraw/tests: Fix vertex winding in test_zenable.
-      ddraw/tests: Fix vertex winding in test_texture_wrong_caps.
-
-Sven Baars (1):
-      winegcc: Remove unused libgcc variable.
-
-Trent Waddington (3):
-      cmd: Ensure that for_ctrl->set is non-NULL at parse time.
-      findstr/tests: Add tests for start-of-word at start of line.
-      findstr: Support start word position \\< at start of line.
-
-Vitaly Lipatov (1):
-      taskschd: Implement IRepetitionPattern for trigger objects.
+      magnification: Add stub for MagInitialize.
+
+Maotong Zhang (3):
+      msi: Add ComboBox items, using value if text does not exist.
+      msi: The ComboBox defaults to displaying the value.
+      msi: ComboBox displays value on selection and falls back to text if missing.
+
+Mohamad Al-Jaf (4):
+      windows.devices.radios: Add stub dll.
+      windows.devices.radios: Add IRadioStatics stub.
+      windows.devices.radios: Implement IRadioStatics::GetRadiosAsync().
+      windows.devices.radios/tests: Add IRadioStatics::GetRadiosAsync() tests.
+
+Nikolay Sivov (24):
+      msxml3/tests: Add some more DOM tests.
+      msxml3/tests: Enable namespace:: axis test on Windows.
+      msxml3/tests: Remove alternative variants of saved output as acceptable test results.
+      msxml3/tests: Merge a test with existing get_xml() tests.
+      msxml3/tests: Add a test for immediate document children list.
+      d2d1/geometry: Check for null user transform when streaming.
+      msxml3/tests: Add ISupportErrorInfo tests for DOCTYPE nodes.
+      msxml3/tests: Add basic argument test for loadXML().
+      msxml3/tests: Add parentNode() test for attributes.
+      msxml3/tests: Add some cloneNode() tests for a document.
+      msxml3/tests: Use string comparison in more places.
+      msxml3/tests: Add another get_xml() test for namespace definitions.
+      msxml3/tests: Add some more appendChild() tests.
+      msxml3/tests: Remove some value testing macros.
+      msxml3/tests: Skip removeAttributeNode() tests on Wine.
+      msxml3/tests: Add another test for loadXML(NULL).
+      msxml3/tests: Move CDATA node tests to its own function.
+      msxml3/tests: Simplify setting string Variant values.
+      secur32/tests: Test required buffer size in case of SEC_E_INCOMPLETE_MESSAGE.
+      secur32/schannel: Fix returned required buffer size for incomplete messages in DecryptMessage().
+      secur32/tests: Use existing macro for a capability flag.
+      msxml3/tests: Add a test for reloading document with outstanding references.
+      odbc32: Map SQLColAttributes(SQL_COLUMN_UNSIGNED) to SQLColAttribute().
+      include: Fix SQLDriverConnectW() prototype.
+
+Olivia Ryan (11):
+      windows.web: Cleanup struct json_value.
+      windows.web: Use json_buffer struct & helper functions.
+      windows.web: Support escaped characters.
+      windows.web: Additional string parsing tests.
+      windows.web: Stub JsonArray runtime class.
+      windows.web: Support json array parsing.
+      windows.web: Add a IMap_HSTRING_IInspectable to json objects.
+      windows.web: Support json object parsing.
+      windows.web: Implement JsonArray element getters.
+      windows.web: Support boolean & number value creation.
+      windows.web: Implement JsonObject typed getters.
+
+Paul Gofman (6):
+      dwrite: Fix second chance fonts handling in fallback_map_characters().
+      dwrite: Move opentype_get_font_table() up.
+      dwrite: Fail loading unsupported COLRv1 fonts.
+      netprofm: Check adapter addresses instead of gateway to guess ipv6 internet connectivity.
+      ntdll: Do not keep next handler pointer outside of lock in call_vectored_handlers().
+      server: Do not return STATUS_ACCESS_DENIED from read_process_memory_vm() for zero read.
+
+Piotr Pawłowski (2):
+      comctl32/tests: Test cycling all state images from custom image list when toggling checkboxes.
+      comctl32/treeview: Cycle all state images from custom image list when toggling checkboxes.
+
+Reece Dunham (1):
+      mshtml: Doc typo fix.
+
+Rémi Bernon (20):
+      windows.web: Rename JsonObject class methods.
+      windows.web: Skip whitespace in json_buffer_take.
+      winex11: Update queue input time on WM_TAKE_FOCUS.
+      mf: Introduce a new topology_node_get_type helper.
+      winemac: Keep current user locale in the generated HKLs.
+      winewayland: Activate an IME HKL before sending IME updates.
+      winex11: Activate an IME HKL before sending IME updates.
+      imm32: Only notify the host IME for known IME HKLs.
+      include: Define _MAX_ENV in stdlib.h.
+      joy.cpl: Ignore unsupported DIPROP_AUTOCENTER.
+      dinput/tests: Move TLC count to the descriptor.
+      dinput/tests: Support starting multiple devices.
+      dinput/tests: Move fill_context call into hid_device_start.
+      cfgmgr32: Implement CM_Locate_DevNode(_Ex)(A|W) and CM_Get_Device_ID(_Size)(_Ex)(A|W).
+      cfgmgr32: Implement CM_Open_DevNode_Key(_Ex).
+      setupapi: Forward CM_Open_DevNode_Key(_Ex) to cfgmgr32.
+      cfgmgr32: Implement CM_Get_DevNode_Registry_Property(_Ex)(A|W).
+      setupapi: Forward CM_Get_DevNode_Registry_Property(_Ex)(A|W) to cfgmgr32.
+      winevulkan: Improve support for some recursive struct conversion.
+      winevulkan: Ignore VkPhysicalDeviceVulkan14Properties returnedonly.
+
+Stefan Dösinger (4):
+      ddraw/tests: Cap test_map_synchronisation to 64k vertices.
+      ddraw/tests: Fix nested designated initializers in test_caps().
+      d3d9/tests: Improve yuv_color_test() on Nvidia drivers.
+      ddraw/tests: Try harder to hide the window in test_window_style().
+
+Theodoros Chatzigiannakis (3):
+      msi: Handle padding bytes in table streams.
+      msi: Detect mismatched bytes_per_strref in table data.
+      msi/tests: Add regression tests for table stream padding and mismatched string refs.
+
+Trung Nguyen (2):
+      msvcrt: Add support for %Z printf specifier.
+      msvcrt/tests: Add tests for %Z printf specifier.
+
+Twaik Yont (5):
+      wineandroid: Update Android project for modern Gradle plugin.
+      wineandroid: Use BOOL for is_desktop flag.
+      wineandroid: Fix APK output path for recent Gradle.
+      ntdll: Disable userfaultfd support on Android.
+      wineandroid: Switch to AHardwareBuffer and raise minSdkVersion to 26.
+
+Vibhav Pant (10):
+      winebth.sys: Store GATT characteristic value cached by the Unix Bluetooth service on the PE driver.
+      winebth.sys: Update the cached GATT characteristic value on receiving a PropertiesChanged signal for a GATT characteristic value from BlueZ.
+      winebth.sys: Implement IOCTL_WINEBTH_GATT_SERVICE_READ_CHARACTERISITIC_VALUE.
+      bluetoothapis: Implement BluetoothGATTGetCharacteristicValue.
+      bluetoothapis/tests: Add tests for BluetoothGATTGetCharacteristicValue.
+      winebth.sys: Remove unneeded call to IoInvalidateDeviceRelations on radio removal.
+      winebth.sys: Don't add Bluetooth devices/entries from Unix if they already exist.
+      winebth.sys: Only make calls to BlueZ if it is available.
+      winebth.sys: Initialize and remove devices on BlueZ startup and shutdown respectively.
+      mountmgr.sys: Initialize threading support for DBus before calling DBus functions.
+
+Wolfgang Hartl (1):
+      oleaut32: Handle reference tables when processing SLTG records.
+
+Yongjie Yao (2):
+      user32/tests: Test the thread safety of NtUserRegisterClassExWOW and NtUserUnregisterClass.
+      win32u: Fixed thread safety issues with NtUserRegistClassExWOW and NtUserUnregisterClass.
+
+Yuxuan Shui (4):
+      crypt32: Don't access CERT_CHAIN_ENGINE_CONFIG::dwExclusiveFlags without checking size.
+      mfsrcsnk: Test how pixel aspect ratio metadata in an mp4 file are handled.
+      winedmo: Call avformat_find_stream_info for H264 streams missing aspect ratio.
+      ntoskrnl.exe/tests: Fix stack use-after-free of OVERLAPPED.
 
 Zhao Yi (2):
-      wbemprox: Correct IP address order when calling Win32_NetworkAdapterConfiguration.
-      wbemprox/tests: Test the IP address order obtained by calling Win32_NetworkAdapterConfiguration.
-
-Zhiyi Zhang (17):
-      wintypes: Return S_OK for api_information_statics_IsMethodPresent().
-      ninput/tests: Add tests for INTERACTION_CONTEXT_PROPERTY_INTERACTION_UI_FEEDBACK property.
-      ninput: Handle INTERACTION_CONTEXT_PROPERTY_INTERACTION_UI_FEEDBACK property.
-      ninput: Add BufferPointerPacketsInteractionContext() stub.
-      ninput: Implement getting and setting interaction configuration.
-      ninput/tests: Add tests for getting and setting interaction configuration.
-      ninput: Add GetStateInteractionContext() stub.
-      ninput: Add ProcessBufferedPacketsInteractionContext() stub.
-      shcore: Add RecordFeatureUsage() stub.
-      icuuc: Add dll.
-      icuin: Add dll.
-      comctl32/tests: Add more tests for TCS_OWNERDRAWFIXED.
-      comctl32/tab: Use a clip region to protect the tab item background.
-      icu/tests: Add initial tests.
-      user32: Add DelegateInput() stub.
-      user32: Add UndelegateInput() stub.
-      comctl32/imagelist: Limit the initial image count.
-
-Zhou Qiankang (1):
-      ntdll: Avoid expensive inverted DST check on get_timezone_info() cache hit path.
+      win32u: Fix deadlock when setting hdc_src to the window's self DC.
+      win32u/tests: Add tests for hdc_src is window's self dc when calling UpdateLayeredWindow.
+
+Zhiyi Zhang (15):
+      ninput: Add ordinal 2502.
+      include: Add some ALPC definitions.
+      ntdll/tests: Add AlpcGetHeaderSize() tests.
+      ntdll: Implement AlpcGetHeaderSize().
+      ntdll/tests: Add AlpcInitializeMessageAttribute() tests.
+      ntdll: Implement AlpcInitializeMessageAttribute().
+      ntdll/tests: Add AlpcGetMessageAttribute() tests.
+      ntdll: Implement AlpcGetMessageAttribute().
+      iertutil: Move CreateIUriBuilder() from urlmon.
+      iertutil: Move CreateUri() from urlmon.
+      iertutil: Move CreateUriWithFragment() from urlmon.
+      iertutil: Add PrivateCoInternetCombineIUri().
+      iertutil: Add PrivateCoInternetParseIUri().
+      urlmon: Add a wine_get_canonicalized_uri() helper.
+      iertutil: Move CUri coclass from urlmon.
 ```
diff --git a/AUTHORS b/AUTHORS
index 0b024a99c23d..9a4eba101df6 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -211,6 +211,7 @@ Benjamin Kramer
 Benjamin Mayes
 Ben Klein
 Ben Mayhew
+Benoît Legat
 Ben Peddell
 Ben Shefte
 Ben Taylor
@@ -314,6 +315,7 @@ Choe Hwanjin
 Chris Denton
 Chris Faherty
 Chris Green
+Chris Kadar
 Chris Morgan
 Chris Peterson
 Chris Robinson
@@ -959,6 +961,7 @@ Joris Huizer
 Joris van der Wel
 Jose Alonso
 Josef Meixner
+José Luis Jiménez López
 José Manuel Ferrer Ortiz
 Jose Marcos López Caravaca
 Joseph Kogut
@@ -993,6 +996,7 @@ Julio César Gázquez
 Julio E. Gonzalez P
 Julius Bettin
 Julius Schwartzenberg
+June Wilde
 Junichi Kuchinishi
 Juraj Hercek
 Juris Smotrovs
@@ -1407,6 +1411,7 @@ Oleh R. Nykyforchyn
 Oleksij Rempel
 Oliver Henning
 Oliver Stieber
+Olivia Ryan
 Olivier F. R. Dierick
 Olivier Houchard
 Olli-Pekka Wallin
@@ -1570,6 +1575,7 @@ Raul Dias
 Raul Fernandes
 Raul Metsma
 Ray Hinchliffe
+Reece Dunham
 Reece H. Dunn
 Reinhard Karcher
 Reinhold Gschweicher
@@ -1806,6 +1812,7 @@ Ted Percival
 Thanasis Papoutsidakis
 Theodore Dubois
 Theodore S. Hetke
+Theodoros Chatzigiannakis
 Thiago Barbato
 Thibault Payet
 Thierry Vermeylen
@@ -1879,6 +1886,7 @@ Trey Hunner
 Tristan Schmelcher
 Tristan Tarrant
 Troy Rollo
+Trung Nguyen
 Trygve Vea
 Tuomas Räsänen
 Twaik Yont
@@ -1964,6 +1972,7 @@ Wim Lewis
 Wino Rojo
 Witold Baryluk
 Wojciech Migda
+Wolfgang Hartl
 Wolfgang Schwotzer
 Wolfgang Thaller
 Wolfgang Walter
diff --git a/VERSION b/VERSION
index 0bb3e3947446..c7ed8d3e4af2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-Wine version 11.5
+Wine version 11.6
diff --git a/configure b/configure
index ac58d7c18747..0e23e5529691 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.72 for Wine 11.5.
+# Generated by GNU Autoconf 2.72 for Wine 11.6.
 #
 # Report bugs to <wine-devel@winehq.org>.
 #
@@ -603,8 +603,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='Wine'
 PACKAGE_TARNAME='wine'
-PACKAGE_VERSION='11.5'
-PACKAGE_STRING='Wine 11.5'
+PACKAGE_VERSION='11.6'
+PACKAGE_STRING='Wine 11.6'
 PACKAGE_BUGREPORT='wine-devel@winehq.org'
 PACKAGE_URL='https://www.winehq.org'
 
@@ -664,8 +664,6 @@ CAPI20_LIBS
 CAPI20_CFLAGS
 SDL2_LIBS
 SDL2_CFLAGS
-UNWIND_LIBS
-UNWIND_CFLAGS
 UDEV_LIBS
 UDEV_CFLAGS
 OSS4_LIBS
@@ -761,6 +759,8 @@ CXX_PE_CFLAGS
 CAPSTONE_PE_LIBS
 CAPSTONE_PE_CFLAGS
 MINGW_PKG_CONFIG
+ANDROID_HOME
+GRADLE
 WINELOADER_DEPENDS
 ac_ct_OBJC
 OBJCFLAGS
@@ -977,7 +977,6 @@ with_pulse
 with_sane
 with_sdl
 with_udev
-with_unwind
 with_usb
 with_v4l2
 with_vulkan
@@ -1237,6 +1236,7 @@ enable_ir50_32
 enable_irprops_cpl
 enable_itircl
 enable_itss
+enable_iyuv_32
 enable_joy_cpl
 enable_jscript
 enable_jsproxy
@@ -1538,6 +1538,7 @@ enable_winbrand
 enable_windows_applicationmodel
 enable_windows_devices_bluetooth
 enable_windows_devices_enumeration
+enable_windows_devices_radios
 enable_windows_devices_usb
 enable_windows_gaming_input
 enable_windows_gaming_ui_gamebar
@@ -1936,8 +1937,6 @@ ALSA_CFLAGS
 ALSA_LIBS
 UDEV_CFLAGS
 UDEV_LIBS
-UNWIND_CFLAGS
-UNWIND_LIBS
 SDL2_CFLAGS
 SDL2_LIBS
 CAPI20_CFLAGS
@@ -2500,7 +2499,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.5 to adapt to many kinds of systems.
+'configure' configures Wine 11.6 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -2570,7 +2569,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Wine 11.5:";;
+     short | recursive ) echo "Configuration of Wine 11.6:";;
    esac
   cat <<\_ACEOF
 
@@ -2627,8 +2626,6 @@ Optional Packages:
   --without-sane          do not use SANE (scanner support)
   --without-sdl           do not use SDL
   --without-udev          do not use udev (plug and play support)
-  --without-unwind        do not use the libunwind library (exception
-                          handling)
   --without-usb           do not use the libusb library
   --without-v4l2          do not use v4l2 (video capture)
   --without-vulkan        do not use Vulkan
@@ -2826,9 +2823,6 @@ Some influential environment variables:
   ALSA_LIBS   Linker flags for alsa, overriding pkg-config
   UDEV_CFLAGS C compiler flags for libudev, overriding pkg-config
   UDEV_LIBS   Linker flags for libudev, overriding pkg-config
-  UNWIND_CFLAGS
-              C compiler flags for libunwind, overriding pkg-config
-  UNWIND_LIBS Linker flags for libunwind, overriding pkg-config
   SDL2_CFLAGS C compiler flags for sdl2, overriding pkg-config
   SDL2_LIBS   Linker flags for sdl2, overriding pkg-config
   CAPI20_CFLAGS
@@ -2917,7 +2911,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Wine configure 11.5
+Wine configure 11.6
 generated by GNU Autoconf 2.72
 
 Copyright (C) 2023 Free Software Foundation, Inc.
@@ -3323,7 +3317,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.5, which was
+It was created by Wine $as_me 11.6, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4578,13 +4572,6 @@ then :
 fi
 
 
-# Check whether --with-unwind was given.
-if test ${with_unwind+y}
-then :
-  withval=$with_unwind;
-fi
-
-
 # Check whether --with-usb was given.
 if test ${with_usb+y}
 then :
@@ -8001,6 +7988,67 @@ printf "%s\n" "$res" >&6; }
           as_fn_append ${wine_arch}_CC " $res" ;;
     esac
 
+    if test "x$wine_arch" = xi386
+then :
+
+else case e in #(
+  e) as_wine_cv_seh_support=`printf "%s\n" "ac_cv_${wine_arch}_seh_support" | sed "$as_sed_sh"`
+
+               { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports SEH directives" >&5
+printf %s "checking whether $CC supports SEH directives... " >&6; }
+if eval test \${$as_wine_cv_seh_support+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+asm(".text\nac_test:\t.seh_proc ac_test\n\tnop\n\t.seh_stackalloc 16\n\t.seh_endprologue\n\t.seh_endproc");
+int
+main (void)
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+  eval "$as_wine_cv_seh_support=yes"
+else case e in #(
+  e) eval "$as_wine_cv_seh_support=no" ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
+esac
+fi
+eval ac_res=\$$as_wine_cv_seh_support
+	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
+               eval res=\$$as_wine_cv_seh_support
+
+               if test "x$res" = xyes
+then :
+
+else case e in #(
+  e) if test ${enable_archs+y}
+then :
+  as_fn_error $? "The $wine_arch PE cross-compiler doesn't support SEH directives.
+This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5
+fi
+                          continue ;;
+esac
+fi ;;
+esac
+fi
+
+    if test "x$wine_arch" = x$extra_arch
+then :
+
+else case e in #(
+  e) as_fn_append PE_ARCHS " $wine_arch" ;;
+esac
+fi
+
     as_wine_cv_crosscxx_cxx17=`printf "%s\n" "ac_cv_${wine_arch}_crosscxx_cxx17" | sed "$as_sed_sh"`
 
     { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++17 features" >&5
@@ -8802,86 +8850,27 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
     case "x$res" in
       x) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;;
+printf "%s\n" "none needed" >&6; }
+         enable_cplusplus="$enable_cplusplus,$wine_arch" ;;
       xno) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
 printf "%s\n" "unsupported" >&6; }
-           if test ${enable_archs+y}
-then :
-  as_fn_error $? "$wine_arch PE cross-compiler supporting C++17 not found.
-This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5
-fi
-           continue
-           ;;
+           as_fn_append wine_warnings "|$wine_arch PE cross-compiler supporting C++17 not found, some modules won't be built." ;;
       x*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $res" >&5
 printf "%s\n" "$res" >&6; }
-          as_fn_append ${wine_arch}_CXX " $res" ;;
+          as_fn_append ${wine_arch}_CXX " $res"
+          enable_cplusplus="$enable_cplusplus,$wine_arch" ;;
     esac
 
-    if test "x$wine_arch" = xi386
-then :
-
-else case e in #(
-  e) as_wine_cv_seh_support=`printf "%s\n" "ac_cv_${wine_arch}_seh_support" | sed "$as_sed_sh"`
-
-               { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports SEH directives" >&5
-printf %s "checking whether $CC supports SEH directives... " >&6; }
-if eval test \${$as_wine_cv_seh_support+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-asm(".text\nac_test:\t.seh_proc ac_test\n\tnop\n\t.seh_stackalloc 16\n\t.seh_endprologue\n\t.seh_endproc");
-int
-main (void)
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"
-then :
-  eval "$as_wine_cv_seh_support=yes"
-else case e in #(
-  e) eval "$as_wine_cv_seh_support=no" ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
-esac
-fi
-eval ac_res=\$$as_wine_cv_seh_support
-	       { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-printf "%s\n" "$ac_res" >&6; }
-               eval res=\$$as_wine_cv_seh_support
-
-               if test "x$res" = xyes
-then :
-
-else case e in #(
-  e) if test ${enable_archs+y}
-then :
-  as_fn_error $? "The $wine_arch PE cross-compiler doesn't support SEH directives.
-This is an error since --enable-archs=$wine_arch was requested." "$LINENO" 5
-fi
-                          continue ;;
-esac
-fi ;;
-esac
-fi
-
-    if test "x$wine_arch" = x$extra_arch
+    if test "x$res" = xno
 then :
-
+  eval "${wine_arch}_CXX="
 else case e in #(
-  e) as_fn_append PE_ARCHS " $wine_arch" ;;
+  e) case "$target" in
+                 *mingw*|*-windows-gnu) enable_cppabi="$enable_cppabi,$wine_arch" ;;
+               esac ;;
 esac
 fi
 
-    case "$target" in
-      *mingw*|*-windows-gnu) enable_cppabi="$enable_cppabi,$wine_arch" ;;
-    esac
-
     { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-fno-strict-aliasing" | sed "$as_sed_sh"`
 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fno-strict-aliasing" >&5
 printf %s "checking whether $CC supports -fno-strict-aliasing... " >&6; }
@@ -10365,7 +10354,7 @@ if eval test \"x\$"$as_ac_var"\" = x"yes"
 then :
   as_fn_append ${wine_arch}_EXTRACFLAGS " -Werror"
 fi }
-            test "x$enable_build_id" != xyes || as_fn_append ${wine_arch}_LDFLAGS " -Wl,--build-id"
+            test "x$enable_build_id" != xno && as_fn_append ${wine_arch}_LDFLAGS " -Wl,--build-id"
 
         eval ${wine_arch}_EXTRACXXFLAGS=\$${wine_arch}_EXTRACFLAGS
     { as_ac_var=`printf "%s\n" "ac_cv_${wine_arch}_cflags_-Wdeclaration-after-statement" | sed "$as_sed_sh"`
@@ -10538,9 +10527,9 @@ CPPFLAGS=$saved_CPPFLAGS
 CXXFLAGS=$saved_CXXFLAGS
 LDFLAGS=$saved_LDFLAGS
 
-case $HOST_ARCH in
-  arm|aarch64)
-    test "x$PE_ARCHS" != x || as_fn_error $? "PE cross-compilation is required for $HOST_ARCH, please install clang/llvm-dlltool/lld, or llvm-mingw." "$LINENO" 5
+case $HOST_ARCH-$host_os in
+  x86_64-darwin*|arm-*|aarch64-*)
+    test "x$PE_ARCHS" != x || as_fn_error $? "PE cross-compilation is required for $host, please install clang/llvm-dlltool/lld, or llvm-mingw." "$LINENO" 5
     DLLEXT="" ;;
   *)
     DLLEXT=".so"
@@ -13059,6 +13048,55 @@ printf "%s\n" "#define SONAME_LIBGLESV2 \"$ac_cv_lib_soname_GLESv2\"" >>confdefs
         ;;
 esac
 fi
+    # Extract the first word of "gradle", so it can be a program name with args.
+set dummy gradle; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_path_GRADLE+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) case $GRADLE in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GRADLE="$GRADLE" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+    ac_cv_path_GRADLE="$as_dir$ac_word$ac_exec_ext"
+    printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac ;;
+esac
+fi
+GRADLE=$ac_cv_path_GRADLE
+if test -n "$GRADLE"; then
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GRADLE" >&5
+printf "%s\n" "$GRADLE" >&6; }
+else
+  { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
+    test -n "$GRADLE" || as_fn_error $? "gradle is required for the Android build" "$LINENO" 5
+    ANDROID_HOME=$ANDROID_HOME
+
 
     if test "x$exec_prefix" = xNONE
     then
@@ -19891,134 +19929,6 @@ esac
 
 fi
 
-if test $HOST_ARCH = x86_64
-then
-  if test "x$with_unwind" != xno
-  then
-    rm -f conftest.err
-if ${UNWIND_CFLAGS:+false} :
-then :
-  if test ${PKG_CONFIG+y}
-then :
-  UNWIND_CFLAGS=`$PKG_CONFIG --cflags libunwind 2>conftest.err`
-fi
-fi
-
-if ${UNWIND_LIBS:+false} :
-then :
-  if test ${PKG_CONFIG+y}
-then :
-  UNWIND_LIBS=`$PKG_CONFIG --libs libunwind 2>/dev/null`
-fi
-fi
-
-UNWIND_LIBS=${UNWIND_LIBS:-"-lunwind"}
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: libunwind cflags: $UNWIND_CFLAGS" >&5
-printf "%s\n" "$as_me:${as_lineno-$LINENO}: libunwind libs: $UNWIND_LIBS" >&5
-if test -s conftest.err; then
-     printf %s "$as_me:${as_lineno-$LINENO}: libunwind errors: " >&5
-     cat conftest.err >&5
-fi
-rm -f conftest.err
-if test -n "$UNWIND_CFLAGS$UNWIND_LIBS"
-then :
-  ac_save_CPPFLAGS=$CPPFLAGS
-CPPFLAGS="$CPPFLAGS $UNWIND_CFLAGS"
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unw_step" >&5
-printf %s "checking for unw_step... " >&6; }
-if test ${wine_cv_have_unw_step+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-int
-main (void)
-{
-unw_cursor_t cursor; unw_step( &cursor );
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  wine_cv_have_unw_step="yes"
-else case e in #(
-  e) wine_cv_have_unw_step="no" ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_unw_step" >&5
-printf "%s\n" "$wine_cv_have_unw_step" >&6; }
-        if test "$wine_cv_have_unw_step" = no -a -n "$UNWIND_LIBS"
-        then
-            save_libs=$LIBS
-                        UNWIND_LIBS="-static-libgcc $UNWIND_LIBS"
-            LIBS="$UNWIND_LIBS $LIBS"
-            { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unw_step in libunwind" >&5
-printf %s "checking for unw_step in libunwind... " >&6; }
-if test ${wine_cv_have_libunwind_unw_step+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#define UNW_LOCAL_ONLY
-#include <libunwind.h>
-int
-main (void)
-{
-unw_cursor_t cursor; unw_step( &cursor );
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  wine_cv_have_libunwind_unw_step="yes"
-else case e in #(
-  e) wine_cv_have_libunwind_unw_step="no" ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext ;;
-esac
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $wine_cv_have_libunwind_unw_step" >&5
-printf "%s\n" "$wine_cv_have_libunwind_unw_step" >&6; }
-            LIBS=$save_libs
-        fi
-        test "$wine_cv_have_libunwind_unw_step" = yes || UNWIND_LIBS=""
-        if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" != xnono
-        then
-
-printf "%s\n" "#define HAVE_LIBUNWIND 1" >>confdefs.h
-
-        fi
-CPPFLAGS=$ac_save_CPPFLAGS
-fi
-
-  fi
-  case $host in
-  *-darwin*)
-    if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" = xnono
-then :
-  case "x$with_unwind" in
-  x)   as_fn_append wine_notices "|libunwind ${notice_platform}development files not found, stack unwinding won't work." ;;
-  xno) ;;
-  *)   as_fn_error $? "libunwind ${notice_platform}development files not found, stack unwinding won't work.
-This is an error since --with-unwind was requested." "$LINENO" 5 ;;
-esac
-
-fi ;;
-  esac
-fi
-
 if test "x$with_sdl" != "xno"
 then
     rm -f conftest.err
@@ -23318,8 +23228,6 @@ fi ;;
 esac
 
 
-enable_cppabi=${enable_cppabi:-no}
-enable_unwind=${enable_unwind:-$enable_cppabi}
 enable_vcruntime140_1=${enable_vcruntime140_1:-x86_64,arm64ec}
 
 if test -n "$PE_ARCHS"
@@ -23334,10 +23242,18 @@ else
     enable_wow64cpu=${enable_wow64cpu:-no}
     enable_xtajit64=${enable_xtajit64:-no}
     enable_compiler_rt=${enable_compiler_rt:-no}
-        enable_icu=${enable_icu:-no}
-    enable_dmsynth=${enable_dmsynth:-no}
 fi
 
+enable_cplusplus=${enable_cplusplus:-no}
+enable_cpp=${enable_cpp:-$enable_cplusplus}
+enable_cppabi=${enable_cppabi:-no}
+enable_unwind=${enable_unwind:-$enable_cppabi}
+enable_dmsynth=${enable_dmsynth:-$enable_cplusplus}
+enable_fluidsynth=${enable_fluidsynth:-$enable_cplusplus}
+enable_icu=${enable_icu:-$enable_cplusplus}
+enable_icucommon=${enable_icucommon:-$enable_cplusplus}
+enable_icui18n=${enable_icui18n:-$enable_cplusplus}
+
 enable_conhost=${enable_conhost:-$HOST_ARCH}
 enable_plugplay=${enable_plugplay:-$HOST_ARCH}
 enable_rpcss=${enable_rpcss:-$HOST_ARCH}
@@ -23754,6 +23670,8 @@ wine_fn_config_makefile dlls/irprops.cpl enable_irprops_cpl
 wine_fn_config_makefile dlls/itircl enable_itircl
 wine_fn_config_makefile dlls/itss enable_itss
 wine_fn_config_makefile dlls/itss/tests enable_tests
+wine_fn_config_makefile dlls/iyuv_32 enable_iyuv_32
+wine_fn_config_makefile dlls/iyuv_32/tests enable_tests
 wine_fn_config_makefile dlls/joy.cpl enable_joy_cpl
 wine_fn_config_makefile dlls/jscript enable_jscript
 wine_fn_config_makefile dlls/jscript/tests enable_tests
@@ -24241,6 +24159,8 @@ wine_fn_config_makefile dlls/windows.devices.bluetooth enable_windows_devices_bl
 wine_fn_config_makefile dlls/windows.devices.bluetooth/tests enable_tests
 wine_fn_config_makefile dlls/windows.devices.enumeration enable_windows_devices_enumeration
 wine_fn_config_makefile dlls/windows.devices.enumeration/tests enable_tests
+wine_fn_config_makefile dlls/windows.devices.radios enable_windows_devices_radios
+wine_fn_config_makefile dlls/windows.devices.radios/tests enable_tests
 wine_fn_config_makefile dlls/windows.devices.usb enable_windows_devices_usb
 wine_fn_config_makefile dlls/windows.devices.usb/tests enable_tests
 wine_fn_config_makefile dlls/windows.gaming.input enable_windows_gaming_input
@@ -24685,8 +24605,8 @@ dlls/ntdll/unix/version.c: dummy
 programs/winetest/build.rc: dummy
 	@build=\"STRINGTABLE { 1 \\\"\`GIT_DIR=${wine_srcdir}.git git rev-parse HEAD 2>/dev/null\`\\\" }\" && (echo \$\$build | cmp -s - \$@) || echo \$\$build >\$@ || (rm -f \$@ && exit 1)
 dlls/wineandroid.drv/wine-debug.apk: dlls/wineandroid.drv/build.gradle ${wine_srcdir}dlls/wineandroid.drv/AndroidManifest.xml ${wine_srcdir}dlls/wineandroid.drv/WineActivity.java ${wine_srcdir}dlls/wineandroid.drv/wine.svg
-	cd dlls/wineandroid.drv && gradle -q -Psrcdir=$srcdir assembleDebug
-	mv dlls/wineandroid.drv/build/outputs/apk/wine-debug.apk \$@"
+	cd dlls/wineandroid.drv && env ANDROID_HOME=\"\$(ANDROID_HOME)\" \$(GRADLE) -q -Psrcdir=$srcdir assembleDebug
+	mv dlls/wineandroid.drv/build/outputs/apk/debug/wine-debug.apk \$@"
 
 
 EXTERNAL_SUBDIRS="libs/capstone libs/c++ libs/c++abi libs/faudio libs/fluidsynth libs/gsm libs/icucommon libs/icui18n libs/jpeg libs/jxr libs/lcms2 libs/ldap libs/mpg123 libs/musl libs/png libs/tiff libs/tomcrypt libs/unwind libs/vkd3d libs/xml2 libs/xslt libs/zlib libs/compiler-rt"
@@ -25212,7 +25132,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.5, which was
+This file was extended by Wine $as_me 11.6, which was
 generated by GNU Autoconf 2.72.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -25272,7 +25192,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.5
+Wine config.status 11.6
 configured by $0, generated by GNU Autoconf 2.72,
   with options \\"\$ac_cs_config\\"
 
@@ -25578,6 +25498,8 @@ OBJC = $OBJC
 OBJCFLAGS = $OBJCFLAGS
 ac_ct_OBJC = $ac_ct_OBJC
 WINELOADER_DEPENDS = $WINELOADER_DEPENDS
+GRADLE = $GRADLE
+ANDROID_HOME = $ANDROID_HOME
 MINGW_PKG_CONFIG = $MINGW_PKG_CONFIG
 CAPSTONE_PE_CFLAGS = $CAPSTONE_PE_CFLAGS
 CAPSTONE_PE_LIBS = $CAPSTONE_PE_LIBS
@@ -25673,8 +25595,6 @@ OSS4_CFLAGS = $OSS4_CFLAGS
 OSS4_LIBS = $OSS4_LIBS
 UDEV_CFLAGS = $UDEV_CFLAGS
 UDEV_LIBS = $UDEV_LIBS
-UNWIND_CFLAGS = $UNWIND_CFLAGS
-UNWIND_LIBS = $UNWIND_LIBS
 SDL2_CFLAGS = $SDL2_CFLAGS
 SDL2_LIBS = $SDL2_LIBS
 CAPI20_CFLAGS = $CAPI20_CFLAGS
diff --git a/configure.ac b/configure.ac
index 89243b45be06..a3893fc4703b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -58,7 +58,6 @@ AC_ARG_WITH(pulse,     AS_HELP_STRING([--without-pulse],[do not use PulseAudio s
 AC_ARG_WITH(sane,      AS_HELP_STRING([--without-sane],[do not use SANE (scanner support)]))
 AC_ARG_WITH(sdl,       AS_HELP_STRING([--without-sdl],[do not use SDL]))
 AC_ARG_WITH(udev,      AS_HELP_STRING([--without-udev],[do not use udev (plug and play support)]))
-AC_ARG_WITH(unwind,    AS_HELP_STRING([--without-unwind],[do not use the libunwind library (exception handling)]))
 AC_ARG_WITH(usb,       AS_HELP_STRING([--without-usb],[do not use the libusb library]))
 AC_ARG_WITH(v4l2,      AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)]))
 AC_ARG_WITH(vulkan,    AS_HELP_STRING([--without-vulkan],[do not use Vulkan]))
@@ -545,6 +544,21 @@ This is an error since --enable-archs=$wine_arch was requested.])])
           AS_VAR_APPEND([${wine_arch}_CC],[" $res"]) ;;
     esac
 
+    AS_VAR_IF([wine_arch],[i386],[],
+              [AS_VAR_PUSHDEF([wine_cv_seh_support],[ac_cv_${wine_arch}_seh_support])
+               AC_CACHE_CHECK([whether $CC supports SEH directives], wine_cv_seh_support,
+                   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[asm(".text\nac_test:\t.seh_proc ac_test\n\tnop\n\t.seh_stackalloc 16\n\t.seh_endprologue\n\t.seh_endproc");]])],
+                                     [AS_VAR_SET([wine_cv_seh_support],[yes])],[AS_VAR_SET([wine_cv_seh_support],[no])]))
+               AS_VAR_COPY([res],[wine_cv_seh_support])
+               AS_VAR_POPDEF([wine_cv_seh_support])
+               AS_VAR_IF([res],[yes],[],
+                         [AS_VAR_SET_IF([enable_archs],
+                             [AC_MSG_ERROR([The $wine_arch PE cross-compiler doesn't support SEH directives.
+This is an error since --enable-archs=$wine_arch was requested.])])
+                          continue])])
+
+    AS_VAR_IF([wine_arch],[$extra_arch],[],[AS_VAR_APPEND([PE_ARCHS],[" $wine_arch"])])
+
     AS_VAR_PUSHDEF([wine_cv_crosscxx_cxx17],[ac_cv_${wine_arch}_crosscxx_cxx17])
     AC_MSG_CHECKING([for $CXX option to enable C++17 features])
     AC_LANG_PUSH([C++])
@@ -563,35 +577,19 @@ This is an error since --enable-archs=$wine_arch was requested.])])
     AC_LANG_POP([C++])
     AS_VAR_POPDEF([wine_cv_crosscxx_cxx17])
     case "x$res" in
-      x) AC_MSG_RESULT([none needed]) ;;
+      x) AC_MSG_RESULT([none needed])
+         enable_cplusplus="$enable_cplusplus,$wine_arch" ;;
       xno) AC_MSG_RESULT([unsupported])
-           AS_VAR_SET_IF([enable_archs],
-                [AC_MSG_ERROR([$wine_arch PE cross-compiler supporting C++17 not found.
-This is an error since --enable-archs=$wine_arch was requested.])])
-           continue
-           ;;
+           WINE_WARNING([$wine_arch PE cross-compiler supporting C++17 not found, some modules won't be built.]) ;;
       x*) AC_MSG_RESULT([$res])
-          AS_VAR_APPEND([${wine_arch}_CXX],[" $res"]) ;;
+          AS_VAR_APPEND([${wine_arch}_CXX],[" $res"])
+          enable_cplusplus="$enable_cplusplus,$wine_arch" ;;
     esac
 
-    AS_VAR_IF([wine_arch],[i386],[],
-              [AS_VAR_PUSHDEF([wine_cv_seh_support],[ac_cv_${wine_arch}_seh_support])
-               AC_CACHE_CHECK([whether $CC supports SEH directives], wine_cv_seh_support,
-                   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[asm(".text\nac_test:\t.seh_proc ac_test\n\tnop\n\t.seh_stackalloc 16\n\t.seh_endprologue\n\t.seh_endproc");]])],
-                                     [AS_VAR_SET([wine_cv_seh_support],[yes])],[AS_VAR_SET([wine_cv_seh_support],[no])]))
-               AS_VAR_COPY([res],[wine_cv_seh_support])
-               AS_VAR_POPDEF([wine_cv_seh_support])
-               AS_VAR_IF([res],[yes],[],
-                         [AS_VAR_SET_IF([enable_archs],
-                             [AC_MSG_ERROR([The $wine_arch PE cross-compiler doesn't support SEH directives.
-This is an error since --enable-archs=$wine_arch was requested.])])
-                          continue])])
-
-    AS_VAR_IF([wine_arch],[$extra_arch],[],[AS_VAR_APPEND([PE_ARCHS],[" $wine_arch"])])
-
-    case "$target" in
-      *mingw*|*-windows-gnu) enable_cppabi="$enable_cppabi,$wine_arch" ;;
-    esac
+    AS_VAR_IF([res],[no],[AS_VAR_SET([${wine_arch}_CXX],[])],
+              [case "$target" in
+                 *mingw*|*-windows-gnu) enable_cppabi="$enable_cppabi,$wine_arch" ;;
+               esac])
 
     WINE_TRY_PE_CFLAGS([-fno-strict-aliasing])
     dnl clang needs to be told to fail on unknown options
@@ -678,7 +676,7 @@ This is an error since --enable-archs=$wine_arch was requested.])])
     test "x$enable_werror" != xyes || WINE_TRY_PE_CFLAGS([-Werror])
     dnl clang for PE target wants -build-id (and not --build-id as gcc/mingw or clang in unix target)
     dnl don't bother testing flags, compilation will fail afterwards
-    test "x$enable_build_id" != xyes || AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--build-id"])
+    test "x$enable_build_id" != xno && AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--build-id"])
 
     dnl Options that differ between C and C++
     AS_VAR_COPY([${wine_arch}_EXTRACXXFLAGS],[${wine_arch}_EXTRACFLAGS])
@@ -696,9 +694,9 @@ CPPFLAGS=$saved_CPPFLAGS
 CXXFLAGS=$saved_CXXFLAGS
 LDFLAGS=$saved_LDFLAGS
 
-case $HOST_ARCH in
-  arm|aarch64)
-    test "x$PE_ARCHS" != x || AC_MSG_ERROR([PE cross-compilation is required for $HOST_ARCH, please install clang/llvm-dlltool/lld, or llvm-mingw.])
+case $HOST_ARCH-$host_os in
+  x86_64-darwin*|arm-*|aarch64-*)
+    test "x$PE_ARCHS" != x || AC_MSG_ERROR([PE cross-compilation is required for $host, please install clang/llvm-dlltool/lld, or llvm-mingw.])
     DLLEXT="" ;;
   *)
     AC_SUBST(DLLEXT,".so")
@@ -1055,6 +1053,9 @@ case $host_os in
     WINE_TRY_CFLAGS([-Wl,--rosegment], [WINEPRELOADER_LDFLAGS="$WINEPRELOADER_LDFLAGS -Wl,--rosegment"])
 
     WINE_CHECK_SONAME(GLESv2,glFlush)
+    AC_PATH_PROG([GRADLE], [gradle])
+    test -n "$GRADLE" || AC_MSG_ERROR([gradle is required for the Android build])
+    AC_SUBST([ANDROID_HOME],[$ANDROID_HOME])
 
     if test "x$exec_prefix" = xNONE
     then
@@ -1826,44 +1827,6 @@ fi
 WINE_NOTICE_WITH(udev,[test "x$UDEV_LIBS" = "x"],
                  [libudev ${notice_platform}development files not found, plug and play won't be supported.])
 
-dnl **** Check for libunwind ****
-if test $HOST_ARCH = x86_64
-then
-  if test "x$with_unwind" != xno
-  then
-    WINE_PACKAGE_FLAGS(UNWIND,[libunwind],[-lunwind],,,
-       [AC_CACHE_CHECK([for unw_step],wine_cv_have_unw_step,
-           [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define UNW_LOCAL_ONLY
-#include <libunwind.h>]],
-                [[unw_cursor_t cursor; unw_step( &cursor );]])],
-                [wine_cv_have_unw_step="yes"],[wine_cv_have_unw_step="no"])])
-        if test "$wine_cv_have_unw_step" = no -a -n "$UNWIND_LIBS"
-        then
-            save_libs=$LIBS
-            dnl Force static libgcc, libunwind breaks libgcc_s unwinding
-            UNWIND_LIBS="-static-libgcc $UNWIND_LIBS"
-            LIBS="$UNWIND_LIBS $LIBS"
-            AC_CACHE_CHECK([for unw_step in libunwind],wine_cv_have_libunwind_unw_step,
-               [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#define UNW_LOCAL_ONLY
-#include <libunwind.h>]],
-                    [[unw_cursor_t cursor; unw_step( &cursor );]])],
-                    [wine_cv_have_libunwind_unw_step="yes"],
-                    [wine_cv_have_libunwind_unw_step="no"])])
-            LIBS=$save_libs
-        fi
-        test "$wine_cv_have_libunwind_unw_step" = yes || UNWIND_LIBS=""
-        if test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" != xnono
-        then
-            AC_DEFINE(HAVE_LIBUNWIND,1,[Define to 1 if you have the 'unwind' library (-lunwind).])
-        fi])
-  fi
-  case $host in
-  *-darwin*)
-    WINE_NOTICE_WITH(unwind,[test "x$wine_cv_have_unw_step$wine_cv_have_libunwind_unw_step" = xnono],
-                     [libunwind ${notice_platform}development files not found, stack unwinding won't work.]) ;;
-  esac
-fi
-
 dnl **** Check for libSDL2 ****
 if test "x$with_sdl" != "xno"
 then
@@ -2433,8 +2396,6 @@ esac
 
 dnl *** Check for modules to disable by default
 
-enable_cppabi=${enable_cppabi:-no}
-enable_unwind=${enable_unwind:-$enable_cppabi}
 enable_vcruntime140_1=${enable_vcruntime140_1:-x86_64,arm64ec}
 
 if test -n "$PE_ARCHS"
@@ -2449,11 +2410,19 @@ else
     enable_wow64cpu=${enable_wow64cpu:-no}
     enable_xtajit64=${enable_xtajit64:-no}
     enable_compiler_rt=${enable_compiler_rt:-no}
-    dnl Disable modules that need C++
-    enable_icu=${enable_icu:-no}
-    enable_dmsynth=${enable_dmsynth:-no}
 fi
 
+dnl Disable modules that need C++
+enable_cplusplus=${enable_cplusplus:-no}
+enable_cpp=${enable_cpp:-$enable_cplusplus}
+enable_cppabi=${enable_cppabi:-no}
+enable_unwind=${enable_unwind:-$enable_cppabi}
+enable_dmsynth=${enable_dmsynth:-$enable_cplusplus}
+enable_fluidsynth=${enable_fluidsynth:-$enable_cplusplus}
+enable_icu=${enable_icu:-$enable_cplusplus}
+enable_icucommon=${enable_icucommon:-$enable_cplusplus}
+enable_icui18n=${enable_icui18n:-$enable_cplusplus}
+
 dnl Disable some programs for other PE archs
 enable_conhost=${enable_conhost:-$HOST_ARCH}
 enable_plugplay=${enable_plugplay:-$HOST_ARCH}
@@ -2875,6 +2844,8 @@ WINE_CONFIG_MAKEFILE(dlls/irprops.cpl)
 WINE_CONFIG_MAKEFILE(dlls/itircl)
 WINE_CONFIG_MAKEFILE(dlls/itss)
 WINE_CONFIG_MAKEFILE(dlls/itss/tests)
+WINE_CONFIG_MAKEFILE(dlls/iyuv_32)
+WINE_CONFIG_MAKEFILE(dlls/iyuv_32/tests)
 WINE_CONFIG_MAKEFILE(dlls/joy.cpl)
 WINE_CONFIG_MAKEFILE(dlls/jscript)
 WINE_CONFIG_MAKEFILE(dlls/jscript/tests)
@@ -3362,6 +3333,8 @@ WINE_CONFIG_MAKEFILE(dlls/windows.devices.bluetooth)
 WINE_CONFIG_MAKEFILE(dlls/windows.devices.bluetooth/tests)
 WINE_CONFIG_MAKEFILE(dlls/windows.devices.enumeration)
 WINE_CONFIG_MAKEFILE(dlls/windows.devices.enumeration/tests)
+WINE_CONFIG_MAKEFILE(dlls/windows.devices.radios)
+WINE_CONFIG_MAKEFILE(dlls/windows.devices.radios/tests)
 WINE_CONFIG_MAKEFILE(dlls/windows.devices.usb)
 WINE_CONFIG_MAKEFILE(dlls/windows.devices.usb/tests)
 WINE_CONFIG_MAKEFILE(dlls/windows.gaming.input)
@@ -3837,8 +3810,8 @@ WINE_APPEND_RULE(
 programs/winetest/build.rc: dummy
 	@build=\"STRINGTABLE { 1 \\\"\`GIT_DIR=${wine_srcdir}.git git rev-parse HEAD 2>/dev/null\`\\\" }\" && (echo \$\$build | cmp -s - \$[@]) || echo \$\$build >\$[@] || (rm -f \$[@] && exit 1)
 dlls/wineandroid.drv/wine-debug.apk: dlls/wineandroid.drv/build.gradle ${wine_srcdir}dlls/wineandroid.drv/AndroidManifest.xml ${wine_srcdir}dlls/wineandroid.drv/WineActivity.java ${wine_srcdir}dlls/wineandroid.drv/wine.svg
-	cd dlls/wineandroid.drv && gradle -q -Psrcdir=$srcdir assembleDebug
-	mv dlls/wineandroid.drv/build/outputs/apk/wine-debug.apk \$[@]])
+	cd dlls/wineandroid.drv && env ANDROID_HOME=\"\$(ANDROID_HOME)\" \$(GRADLE) -q -Psrcdir=$srcdir assembleDebug
+	mv dlls/wineandroid.drv/build/outputs/apk/debug/wine-debug.apk \$[@]])
 
 dnl Misc rules
 
diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in
index d1f9e9996cce..53abe476bde6 100644
--- a/dlls/advapi32/Makefile.in
+++ b/dlls/advapi32/Makefile.in
@@ -15,4 +15,5 @@ SOURCES = \
 	registry.c \
 	security.c \
 	service.c \
+	svcctl.idl \
 	wmi.c
diff --git a/dlls/advapi32/advapi32.spec b/dlls/advapi32/advapi32.spec
index d8b67d608521..273f382c5e6a 100644
--- a/dlls/advapi32/advapi32.spec
+++ b/dlls/advapi32/advapi32.spec
@@ -25,7 +25,7 @@
 @ stdcall -import AddAuditAccessAce(ptr long long ptr long long)
 @ stdcall -import AddAuditAccessAceEx(ptr long long long ptr long long)
 @ stdcall -import AddAuditAccessObjectAce(ptr long long long ptr ptr ptr long long)
-# @ stub AddConditionalAce
+@ stdcall AddConditionalAce(ptr long long long long ptr wstr ptr)
 @ stdcall -import AddMandatoryAce(ptr long long long ptr)
 # @ stub AddUsersToEncryptedFile
 # @ stub AddUsersToEncryptedFileEx
diff --git a/dlls/advapi32/security.c b/dlls/advapi32/security.c
index 55be004cef33..8310a4a45ba2 100644
--- a/dlls/advapi32/security.c
+++ b/dlls/advapi32/security.c
@@ -3221,3 +3221,14 @@ DWORD WINAPI LookupSecurityDescriptorPartsW(TRUSTEEW *owner, TRUSTEEW *group, UL
           access_list, audit_count, audit_list, descriptor);
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
+
+/******************************************************************************
+ * AddConditionalAce [ADVAPI32.@]
+ */
+BOOL WINAPI AddConditionalAce(PACL acl, DWORD ace_revision, DWORD ace_flags, UCHAR ace_type,
+                               DWORD access_mask, PSID sid, PWCHAR condition, DWORD *length)
+{
+    FIXME("(%p %lx %lx %x %lx %p %s %p) stub\n", acl, ace_revision, ace_flags, ace_type,
+           access_mask, sid, debugstr_w(condition), length);
+    return FALSE;
+}
diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index e6b243a46f4c..bcf92d7f5d45 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -24,20 +24,65 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winsvc.h"
+#include "svcctl.h"
 #include "wine/debug.h"
+#include "wine/exception.h"
 
 #include "advapi32_misc.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(service);
 
+static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr )
+{
+    return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode );
+}
+
+static DWORD map_exception_code( DWORD exception_code )
+{
+    switch (exception_code)
+    {
+    case RPC_X_NULL_REF_POINTER:
+        return ERROR_INVALID_ADDRESS;
+    case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
+    case RPC_X_BYTE_COUNT_TOO_SMALL:
+        return ERROR_INVALID_PARAMETER;
+    case RPC_S_INVALID_BINDING:
+    case RPC_X_SS_IN_NULL_CONTEXT:
+        return ERROR_INVALID_HANDLE;
+    default:
+        return exception_code;
+    }
+}
+
 /******************************************************************************
  * LockServiceDatabase  [ADVAPI32.@]
  */
 SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager )
 {
-    /* this function is a no-op in Vista and above */
+    SC_LOCK handle = NULL;
+    DWORD err;
+
     TRACE("%p\n", manager);
-    return (SC_LOCK)0xdeadbeef;
+
+    if (!manager)
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return NULL;
+    }
+
+    __TRY
+    {
+        err = svcctl_LockServiceDatabase( manager, &handle );
+    }
+    __EXCEPT(rpc_filter)
+    {
+        err = map_exception_code( GetExceptionCode() );
+    }
+    __ENDTRY
+
+    if (!err) return handle;
+    SetLastError( err );
+    return 0;
 }
 
 /******************************************************************************
@@ -45,9 +90,35 @@ SC_LOCK WINAPI LockServiceDatabase( SC_HANDLE manager )
  */
 BOOL WINAPI UnlockServiceDatabase( SC_LOCK lock )
 {
-    /* this function is a no-op in Vista and above */
+    DWORD err;
+
     TRACE("%p\n", lock);
-    return TRUE;
+
+    if (!lock)
+    {
+        SetLastError( ERROR_INVALID_SERVICE_LOCK );
+        return FALSE;
+    }
+
+    __TRY
+    {
+        err = svcctl_UnlockServiceDatabase( &lock );
+    }
+    __EXCEPT(rpc_filter)
+    {
+        err = GetExceptionCode();
+
+        if (err == ERROR_INVALID_HANDLE)
+            err = ERROR_INVALID_SERVICE_LOCK;
+        else
+            err = map_exception_code( err );
+    }
+    __ENDTRY
+
+    if (!err) return TRUE;
+    SetLastError( err );
+    return FALSE;
+
 }
 
 /******************************************************************************
@@ -423,3 +494,97 @@ BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
     *lpServicesReturned = 0;
     return TRUE;
 }
+
+static handle_t rpc_wstr_bind( RPC_WSTR str )
+{
+    WCHAR transport[] = SVCCTL_TRANSPORT;
+    WCHAR endpoint[] = SVCCTL_ENDPOINT;
+    RPC_WSTR binding_str;
+    RPC_STATUS status;
+    handle_t rpc_handle;
+
+    status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str );
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcStringBindingComposeW failed, error %ld\n", status);
+        return NULL;
+    }
+
+    status = RpcBindingFromStringBindingW( binding_str, &rpc_handle );
+    RpcStringFreeW( &binding_str );
+
+    if (status != RPC_S_OK)
+    {
+        ERR("Couldn't connect to services.exe, error %ld\n", status);
+        return NULL;
+    }
+
+    return rpc_handle;
+}
+
+static handle_t rpc_cstr_bind(RPC_CSTR str)
+{
+    RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
+    RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
+    RPC_CSTR binding_str;
+    RPC_STATUS status;
+    handle_t rpc_handle;
+
+    status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str );
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcStringBindingComposeA failed, error %ld\n", status);
+        return NULL;
+    }
+
+    status = RpcBindingFromStringBindingA( binding_str, &rpc_handle );
+    RpcStringFreeA( &binding_str );
+
+    if (status != RPC_S_OK)
+    {
+        ERR("Couldn't connect to services.exe, error %ld\n", status);
+        return NULL;
+    }
+
+    return rpc_handle;
+}
+
+handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name )
+{
+    return rpc_cstr_bind( (RPC_CSTR)name );
+}
+
+void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h )
+{
+    RpcBindingFree( &h );
+}
+
+handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name )
+{
+    return rpc_wstr_bind( (RPC_WSTR)name );
+}
+
+void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h )
+{
+    RpcBindingFree( &h );
+}
+
+handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name )
+{
+    return rpc_wstr_bind( (RPC_WSTR)name );
+}
+
+void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h )
+{
+    RpcBindingFree( &h );
+}
+
+void  __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
+{
+    return malloc(len);
+}
+
+void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
+{
+    free(ptr);
+}
diff --git a/dlls/advapi32/svcctl.idl b/dlls/advapi32/svcctl.idl
new file mode 100644
index 000000000000..b1bc8545d787
--- /dev/null
+++ b/dlls/advapi32/svcctl.idl
@@ -0,0 +1,3 @@
+#pragma makedep client
+
+#include "wine/svcctl.idl"
diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c
index fe25013bfabc..33ff25d6f199 100644
--- a/dlls/advapi32/tests/service.c
+++ b/dlls/advapi32/tests/service.c
@@ -3023,6 +3023,58 @@ static void test_EventLog(void)
     CloseServiceHandle(scm_handle);
 }
 
+static void test_LockServiceDatabase(void)
+{
+    static const struct
+    {
+        DWORD access, error;
+    } td[] =
+    {
+        { 0, ERROR_ACCESS_DENIED },
+        { SC_MANAGER_CONNECT, ERROR_ACCESS_DENIED },
+        { SC_MANAGER_LOCK, 0 }
+    };
+    SC_HANDLE hscm;
+    SC_LOCK lock;
+    int i, ret;
+
+    for (i = 0; i < ARRAY_SIZE(td); i++)
+    {
+        winetest_push_context("%d", i);
+
+        hscm = OpenSCManagerW(NULL, NULL, td[i].access);
+        if (!hscm)
+        {
+            skip("OpenSCManager(%08lx) error %lu, skipping the tests\n", td[i].access, GetLastError());
+            break;
+        }
+
+        SetLastError(0xdeadbeef);
+        lock = LockServiceDatabase(hscm);
+        if (!td[i].error)
+        {
+            ok(lock != NULL, "LockServiceDatabase() error %lu\n", GetLastError());
+            SetLastError(0xdeadbeef);
+            ret = UnlockServiceDatabase(lock);
+            ok(ret, "UnlockServiceDatabase() error %lu\n", GetLastError());
+        }
+        else
+        {
+            ok(!lock, "LockServiceDatabase() should fail\n");
+            ok(td[i].error == GetLastError(), "got %lu\n", GetLastError());
+        }
+
+        SetLastError(0xdeadbeef);
+        ret = UnlockServiceDatabase(lock);
+        ok(!ret, "UnlockServiceDatabase() should fail\n");
+        ok(GetLastError() == ERROR_INVALID_SERVICE_LOCK, "got %lu\n", GetLastError());
+
+        winetest_pop_context();
+    }
+
+    CloseServiceHandle(hscm);
+}
+
 static DWORD WINAPI ctrl_handler(DWORD ctl, DWORD type, void *data, void *user)
 {
     HANDLE evt = user;
@@ -3110,6 +3162,7 @@ START_TEST(service)
     test_get_displayname();
     test_get_servicekeyname();
     test_query_svc();
+    test_LockServiceDatabase();
 
     /* Services may start or stop between enumeration calls, leading to
      * inconsistencies and failures. So we may need a couple attempts.
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c
index 06d7299c6dab..e8c6b6dd8026 100644
--- a/dlls/bcrypt/gnutls.c
+++ b/dlls/bcrypt/gnutls.c
@@ -2359,6 +2359,7 @@ static NTSTATUS key_asymmetric_verify( void *args )
         case 20: hash_alg = GNUTLS_DIG_SHA1; break;
         case 32: hash_alg = GNUTLS_DIG_SHA256; break;
         case 48: hash_alg = GNUTLS_DIG_SHA384; break;
+        case 64: hash_alg = GNUTLS_DIG_SHA512; break;
 
         default:
             FIXME( "hash size %u not yet supported\n", params->hash_len );
diff --git a/dlls/bluetoothapis/bluetoothapis.spec b/dlls/bluetoothapis/bluetoothapis.spec
index 9d171a18013f..6a4af0ad34e0 100644
--- a/dlls/bluetoothapis/bluetoothapis.spec
+++ b/dlls/bluetoothapis/bluetoothapis.spec
@@ -34,7 +34,7 @@
 @ stub BluetoothGATTAbortReliableWrite
 @ stub BluetoothGATTBeginReliableWrite
 @ stub BluetoothGATTEndReliableWrite
-@ stub BluetoothGATTGetCharacteristicValue
+@ stdcall BluetoothGATTGetCharacteristicValue(ptr ptr long ptr ptr long)
 @ stdcall BluetoothGATTGetCharacteristics(ptr ptr long ptr ptr long)
 @ stub BluetoothGATTGetDescriptorValue
 @ stub BluetoothGATTGetDescriptors
diff --git a/dlls/bluetoothapis/gatt.c b/dlls/bluetoothapis/gatt.c
index 38cd8a1694ef..225d95a57498 100644
--- a/dlls/bluetoothapis/gatt.c
+++ b/dlls/bluetoothapis/gatt.c
@@ -1,7 +1,7 @@
 /*
  * BLE Generic Attribute Profile (GATT) APIs
  *
- * Copyright 2025 Vibhav Pant
+ * Copyright 2025-2026 Vibhav Pant
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -144,3 +144,73 @@ HRESULT WINAPI BluetoothGATTGetCharacteristics( HANDLE device, BTH_LE_GATT_SERVI
         return HRESULT_FROM_WIN32( ERROR_INVALID_USER_BUFFER );
     return S_OK;
 }
+
+HRESULT WINAPI BluetoothGATTGetCharacteristicValue( HANDLE device, BTH_LE_GATT_CHARACTERISTIC *chrc, ULONG size,
+                                                    BTH_LE_GATT_CHARACTERISTIC_VALUE *val, USHORT *actual, ULONG flags )
+{
+    struct winebth_gatt_service_read_characterisitic_value_params *params;
+    DWORD bytes, outsize, err;
+    OVERLAPPED ovl = {0};
+    HRESULT ret;
+
+   TRACE( "(%p, %p, %lu, %p, %p, %#lx)\n", device, chrc, size, val, actual, flags );
+
+    if (!device)
+        return E_HANDLE;
+    if (!chrc || !(size || val || actual) || (size && size < sizeof( *val )))
+        return E_INVALIDARG;
+    if (size && !val)
+        return E_POINTER;
+    outsize = size ? offsetof( struct winebth_gatt_service_read_characterisitic_value_params,
+                               buf[size - offsetof( BTH_LE_GATT_CHARACTERISTIC_VALUE, Data )] )
+                   : sizeof( *params );
+
+    if (!(params = calloc( 1, outsize )))
+        return HRESULT_FROM_WIN32( ERROR_NO_SYSTEM_RESOURCES );
+
+    /* FIXME: Figure out what native does when both flags are set. */
+    if (flags & BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE)
+        params->from_device = 1;
+    if (flags & BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE)
+        params->from_device = 0;
+
+    params->uuid = chrc->CharacteristicUuid;
+    params->handle = chrc->AttributeHandle;
+    ovl.hEvent = CreateEventW( NULL, TRUE, FALSE, NULL );
+    err = ERROR_SUCCESS;
+    if (!DeviceIoControl( device, IOCTL_WINEBTH_GATT_SERVICE_READ_CHARACTERISITIC_VALUE, params, sizeof( *params ),
+                          params, outsize, &bytes, &ovl ))
+    {
+        err = GetLastError();
+        if (err == ERROR_IO_PENDING)
+        {
+            err = ERROR_SUCCESS;
+            if (!GetOverlappedResult( device, &ovl, &bytes, TRUE ))
+                err = GetLastError();
+        }
+    }
+    CloseHandle( ovl.hEvent );
+
+    if (err)
+    {
+        free( params );
+        return HRESULT_FROM_WIN32( err == ERROR_PRIVILEGE_NOT_HELD ? ERROR_INVALID_ACCESS : err );
+    }
+
+    ret = S_OK;
+    *actual = max( offsetof( BTH_LE_GATT_CHARACTERISTIC_VALUE, Data[params->size] ), sizeof( *val ) );
+    if (val)
+    {
+        if (size >= params->size)
+        {
+            val->DataSize = params->size;
+            memcpy( val->Data, params->buf, params->size );
+        }
+        else
+            ret = HRESULT_FROM_WIN32( ERROR_INVALID_USER_BUFFER );
+    }
+    else
+        ret = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
+    free( params );
+    return ret;
+}
diff --git a/dlls/bluetoothapis/tests/gatt.c b/dlls/bluetoothapis/tests/gatt.c
index d442ab21f673..58c0f4263839 100644
--- a/dlls/bluetoothapis/tests/gatt.c
+++ b/dlls/bluetoothapis/tests/gatt.c
@@ -1,7 +1,7 @@
 /*
  * Tests for Bluetooth GATT methods
  *
- * Copyright 2025 Vibhav Pant
+ * Copyright 2025-2026 Vibhav Pant
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -118,6 +118,80 @@ static const char *debugstr_BTH_LE_GATT_CHARACTERISTIC( const BTH_LE_GATT_CHARAC
                              chrc->IsIndicatable, chrc->HasExtendedProperties );
 }
 
+static BTH_LE_GATT_CHARACTERISTIC_VALUE *get_characteristic_value( int line, HANDLE service, BTH_LE_GATT_CHARACTERISTIC *chrc, ULONG flags )
+{
+    BTH_LE_GATT_CHARACTERISTIC_VALUE *val;
+    USHORT actual;
+    HRESULT ret;
+    ULONG size;
+
+    ret = BluetoothGATTGetCharacteristicValue( service, chrc, 0, NULL, &actual, flags );
+    ok_( __FILE__, line )( HRESULT_CODE( ret ) == ERROR_MORE_DATA, "%lu != %d\n", HRESULT_CODE( ret ), ERROR_MORE_DATA );
+    if (FAILED( ret ) && HRESULT_CODE( ret ) != ERROR_MORE_DATA)
+        return NULL;
+
+    size = actual;
+    val = calloc( 1, size );
+    ret = BluetoothGATTGetCharacteristicValue( service, chrc, size, val, &actual, flags );
+    ok_( __FILE__, line )( ret == S_OK, "BluetoothGATTGetCharacteristicValue failed: %#lx\n", ret );
+    if (FAILED( ret ))
+    {
+        free( val );
+        return NULL;
+    }
+    ok_( __FILE__, line )( actual == size, "%u != %lu\n", actual, size );
+    return val;
+}
+
+static void test_service_BluetoothGATTGetCharacteristicValue( HANDLE service, BTH_LE_GATT_CHARACTERISTIC *chrc )
+{
+    BTH_LE_GATT_CHARACTERISTIC_VALUE *val1, *val2;
+    char buf[5];
+    USHORT actual = 0;
+    HRESULT ret;
+
+    ret = BluetoothGATTGetCharacteristicValue( NULL, NULL, 0, NULL, NULL, 0 );
+    ok( HRESULT_CODE( ret ) == ERROR_INVALID_HANDLE, "%lu != %d\n", HRESULT_CODE( ret ), ERROR_INVALID_HANDLE );
+    ret = BluetoothGATTGetCharacteristicValue( service, NULL, 0, NULL, NULL, 0 );
+    ok( HRESULT_CODE( ret ) == ERROR_INVALID_PARAMETER, "%lu != %d\n", HRESULT_CODE ( ret ), ERROR_INVALID_PARAMETER );
+    ret = BluetoothGATTGetCharacteristicValue( service, NULL, 0, NULL, &actual, 0 );
+    ok( HRESULT_CODE( ret ) == ERROR_INVALID_PARAMETER, "%lu != %d\n", HRESULT_CODE ( ret ), ERROR_INVALID_PARAMETER );
+    ret = BluetoothGATTGetCharacteristicValue( service, chrc, 0, NULL, NULL, 0 );
+    ok( HRESULT_CODE( ret ) == ERROR_INVALID_PARAMETER, "%lu != %d\n", HRESULT_CODE ( ret ), ERROR_INVALID_PARAMETER );
+    ret = BluetoothGATTGetCharacteristicValue( service, chrc, sizeof( buf ), (void *)&buf, &actual, 0 );
+    ok( HRESULT_CODE( ret ) == ERROR_INVALID_PARAMETER, "%lu != %d\n", HRESULT_CODE( ret ), ERROR_INVALID_PARAMETER );
+    ret = BluetoothGATTGetCharacteristicValue( service, chrc, 100, NULL, NULL, 0 );
+    ok( ret == E_POINTER, "%#lx != %#lx\n", ret, E_POINTER );
+    ret = BluetoothGATTGetCharacteristicValue( service, chrc, 100, NULL, &actual, 0 );
+    ok( ret == E_POINTER, "%#lx != %#lx\n", ret, E_POINTER );
+
+    if (!chrc->IsReadable)
+    {
+        ret = BluetoothGATTGetCharacteristicValue( service, chrc, 0, NULL, &actual, 0 );
+        ok( HRESULT_CODE( ret ) == ERROR_INVALID_ACCESS, "%lu != %d\n", HRESULT_CODE( ret ), ERROR_INVALID_ACCESS );
+        return;
+    }
+
+    val1 = get_characteristic_value( __LINE__, service, chrc, 0 );
+    if (val1)
+        trace( "value: %lu bytes\n", val1->DataSize );
+    free( val1 );
+
+    val1 = get_characteristic_value( __LINE__, service, chrc, BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE );
+    val2 = get_characteristic_value( __LINE__, service, chrc, BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE );
+    if (val1 && val2)
+    {
+        ok( val1->DataSize == val2->DataSize, "%lu != %lu\n", val1->DataSize, val2->DataSize );
+        if (val1->DataSize == val2->DataSize)
+            ok( !memcmp( val1->Data, val2->Data, val1->DataSize ),
+                "Cached value does not match value previously read from device.\n" );
+    }
+    else
+        skip( "Couldn't read characteristic value.\n" );
+    free( val1 );
+    free( val2 );
+}
+
 static void test_service_BluetoothGATTGetCharacteristics( HANDLE service, const BTH_LE_GATT_CHARACTERISTIC *chars, USHORT len )
 {
     HRESULT ret;
@@ -204,7 +278,13 @@ static void test_BluetoothGATTGetCharacteristics( HANDLE device, HANDLE service,
     ok( ret == S_OK, "BluetoothGATTGetCharacteristics failed: %#lx\n", ret );
 
     for (i = 0; i < actual; i++)
-        trace( "characteristic %u: %s\n", i, debugstr_BTH_LE_GATT_CHARACTERISTIC( &buf[i] ) );
+    {
+        winetest_push_context( "characteristic %u", i );
+        trace( "%s\n", debugstr_BTH_LE_GATT_CHARACTERISTIC( &buf[i] ) );
+        if (service)
+            test_service_BluetoothGATTGetCharacteristicValue( service, &buf[i] );
+        winetest_pop_context();
+    }
 
     if (service)
         test_service_BluetoothGATTGetCharacteristics( service, buf, actual );
diff --git a/dlls/cabinet/Makefile.in b/dlls/cabinet/Makefile.in
index b5876e7c95c0..d852a95b42b1 100644
--- a/dlls/cabinet/Makefile.in
+++ b/dlls/cabinet/Makefile.in
@@ -8,5 +8,6 @@ VER_PRODUCTVERSION      = 5,0,2147,1
 
 SOURCES = \
 	cabinet_main.c \
+	compressapi.c \
 	fci.c \
 	fdi.c
diff --git a/dlls/cabinet/cabinet.spec b/dlls/cabinet/cabinet.spec
index c3b12eaf8cbd..e744fb5daf84 100644
--- a/dlls/cabinet/cabinet.spec
+++ b/dlls/cabinet/cabinet.spec
@@ -12,3 +12,9 @@
 22 cdecl FDICopy(long ptr ptr long ptr ptr ptr)
 23 cdecl FDIDestroy(long)
 24 cdecl FDITruncateCabinet(long ptr long)
+30 stdcall CreateCompressor(long ptr ptr)
+33 stdcall Compress(ptr ptr long ptr long ptr)
+35 stdcall CloseCompressor(ptr)
+40 stdcall CreateDecompressor(long ptr ptr)
+43 stdcall Decompress(ptr ptr long ptr long ptr)
+45 stdcall CloseDecompressor(ptr)
diff --git a/dlls/cabinet/compressapi.c b/dlls/cabinet/compressapi.c
new file mode 100644
index 000000000000..9d3464ded8cb
--- /dev/null
+++ b/dlls/cabinet/compressapi.c
@@ -0,0 +1,98 @@
+/*
+ * Compression API
+ *
+ * Copyright 2026 Chris Kadar
+ *
+ * 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 "compressapi.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(cabinet);
+
+/***********************************************************************
+ *		CreateCompressor (CABINET.30)
+ */
+BOOL WINAPI CreateCompressor( DWORD algorithm, COMPRESS_ALLOCATION_ROUTINES *routines, COMPRESSOR_HANDLE *handle )
+{
+    FIXME("algo (%lu) stub\n", algorithm);
+    return TRUE;
+}
+
+/***********************************************************************
+ *		Compress (CABINET.33)
+ */
+BOOL WINAPI Compress( COMPRESSOR_HANDLE handle, const VOID *data, SIZE_T data_size,
+                      VOID *buffer, SIZE_T buffer_size, SIZE_T *compressed_data_size )
+{
+    FIXME("stub\n");
+
+    *compressed_data_size = data_size;
+
+    if( buffer_size < data_size )
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return FALSE;
+    }
+    memcpy(buffer, data, data_size);
+    return TRUE;
+}
+
+/***********************************************************************
+ *		CloseCompressor  (CABINET.35)
+ */
+BOOL WINAPI CloseCompressor( COMPRESSOR_HANDLE handle )
+{
+    FIXME("stub\n");
+    return TRUE;
+}
+
+/***********************************************************************
+ *		CreateDecompressor (CABINET.40)
+ */
+BOOL WINAPI CreateDecompressor( DWORD algorithm, COMPRESS_ALLOCATION_ROUTINES *routines, DECOMPRESSOR_HANDLE *handle )
+{
+    FIXME("algo (%lu) stub\n", algorithm);
+    return TRUE;
+}
+
+/***********************************************************************
+ *		Decompress (CABINET.43)
+ */
+BOOL WINAPI Decompress( DECOMPRESSOR_HANDLE handle, const VOID *data, SIZE_T data_size,
+                        VOID *buffer, SIZE_T buffer_size, SIZE_T *decompressed_data_size)
+{
+    FIXME("stub\n");
+
+    *decompressed_data_size = data_size;
+
+    if( buffer_size < data_size )
+    {
+        SetLastError( ERROR_INSUFFICIENT_BUFFER );
+        return FALSE;
+    }
+    memcpy(buffer, data, data_size);
+    return TRUE;
+}
+
+/***********************************************************************
+ *		CloseCompressor  (CABINET.45)
+ */
+BOOL WINAPI CloseDecompressor( DECOMPRESSOR_HANDLE handle )
+{
+    FIXME("stub\n");
+    return TRUE;
+}
diff --git a/dlls/cfgmgr32/cfgmgr32.c b/dlls/cfgmgr32/cfgmgr32.c
index ff179295f027..280f10dd4db7 100644
--- a/dlls/cfgmgr32/cfgmgr32.c
+++ b/dlls/cfgmgr32/cfgmgr32.c
@@ -96,9 +96,14 @@ static HKEY cache_root_key( HKEY root, const WCHAR *key, const WCHAR **path )
 
 static LSTATUS open_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey )
 {
+    LSTATUS err;
+
     if ((root = cache_root_key( root, key, &key )) == (HKEY)-1) return ERROR_FILE_NOT_FOUND;
     if (open) return RegOpenKeyExW( root, key, 0, access, hkey );
-    return RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL );
+
+    err = RegCreateKeyExW( root, key, 0, NULL, 0, access, NULL, hkey, NULL );
+    if (err == ERROR_CHILD_MUST_BE_VOLATILE) err = RegCreateKeyExW( root, key, 0, NULL, REG_OPTION_VOLATILE, access, NULL, hkey, NULL );
+    return err;
 }
 
 static LSTATUS query_value( HKEY hkey, const WCHAR *value, WCHAR *buffer, DWORD len )
@@ -106,6 +111,13 @@ static LSTATUS query_value( HKEY hkey, const WCHAR *value, WCHAR *buffer, DWORD
     return RegQueryValueExW( hkey, value, NULL, NULL, (BYTE *)buffer, &len );
 }
 
+static LSTATUS open_enum_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey )
+{
+    WCHAR path[MAX_PATH];
+    swprintf( path, ARRAY_SIZE(path), L"%s%s", enum_rootW, key );
+    return open_key( root, path, access, open, hkey );
+}
+
 static LSTATUS open_class_key( HKEY root, const WCHAR *key, REGSAM access, BOOL open, HKEY *hkey )
 {
     WCHAR path[MAX_PATH];
@@ -528,6 +540,172 @@ static LSTATUS get_device_interface_property_keys( const struct device_interface
     return err;
 }
 
+struct device
+{
+    WCHAR enumerator[MAX_PATH];
+    WCHAR device[MAX_PATH];
+    WCHAR instance[MAX_PATH];
+};
+
+static LSTATUS init_device( struct device *dev, const WCHAR *name )
+{
+    WCHAR *tmp;
+
+    dev->enumerator[0] = dev->device[0] = dev->instance[0] = 0;
+    tmp = lstrcpynW( dev->enumerator, name, ARRAY_SIZE(dev->enumerator) );
+    if (!(tmp = wcschr( dev->enumerator, '\\' ))) return ERROR_INVALID_DATA;
+
+    *tmp++ = 0;
+    wcscpy( dev->device, tmp );
+    if ((tmp = wcschr( dev->device, '\\' ))) *tmp++ = 0;
+    if (tmp) wcscpy( dev->instance, tmp );
+
+    return ERROR_SUCCESS;
+}
+
+static LSTATUS open_device_key( HKEY root, const struct device *dev, REGSAM access, BOOL open, HKEY *hkey )
+{
+    WCHAR path[MAX_PATH];
+    UINT len;
+
+    len = swprintf( path, ARRAY_SIZE(path), L"%s", dev->enumerator );
+    if (*dev->device) len += swprintf( path + len, ARRAY_SIZE(path) - len, L"\\%s", dev->device );
+    if (*dev->instance) len += swprintf( path + len, ARRAY_SIZE(path) - len, L"\\%s", dev->instance );
+
+    return open_enum_key( root, path, access, open, hkey );
+}
+
+static const struct property_desc device_properties[] =
+{
+    /* ansi-compatible CM_DRP properties */
+    { &DEVPKEY_Device_DeviceDesc,                   DEVPROP_TYPE_STRING,                        L"DeviceDesc" },
+    { &DEVPKEY_Device_HardwareIds,                  DEVPROP_TYPE_STRING_LIST,                   L"HardwareId" },
+    { &DEVPKEY_Device_CompatibleIds,                DEVPROP_TYPE_STRING_LIST,                   L"CompatibleIDs" },
+    { &DEVPKEY_Device_Service,                      DEVPROP_TYPE_STRING,                        L"Service" },
+    { &DEVPKEY_Device_Class,                        DEVPROP_TYPE_STRING,                        L"Class" },
+    { &DEVPKEY_Device_ClassGuid,                    DEVPROP_TYPE_GUID,                          L"ClassGuid" },
+    { &DEVPKEY_Device_Driver,                       DEVPROP_TYPE_STRING,                        L"Driver" },
+    { &DEVPKEY_Device_ConfigFlags,                  DEVPROP_TYPE_UINT32,                        L"ConfigFlags" },
+    { &DEVPKEY_Device_Manufacturer,                 DEVPROP_TYPE_STRING,                        L"Mfg" },
+    { &DEVPKEY_Device_FriendlyName,                 DEVPROP_TYPE_STRING,                        L"FriendlyName" },
+    { &DEVPKEY_Device_LocationInfo,                 DEVPROP_TYPE_STRING,                        L"LocationInformation" },
+    { &DEVPKEY_Device_PDOName,                      DEVPROP_TYPE_STRING,                        L"PDOName" },
+    { &DEVPKEY_Device_Capabilities,                 DEVPROP_TYPE_UINT32,                        L"Capabilities" },
+    { &DEVPKEY_Device_UINumber,                     DEVPROP_TYPE_UINT32,                        L"UINumber" },
+    { &DEVPKEY_Device_UpperFilters,                 DEVPROP_TYPE_STRING_LIST,                   L"UpperFilters" },
+    { &DEVPKEY_Device_LowerFilters,                 DEVPROP_TYPE_STRING_LIST,                   L"LowerFilters" },
+    { &DEVPKEY_Device_BusTypeGuid,                  DEVPROP_TYPE_GUID,                          L"BusTypeGuid" },
+    { &DEVPKEY_Device_LegacyBusType,                DEVPROP_TYPE_UINT32,                        L"LegacyBusType" },
+    { &DEVPKEY_Device_BusNumber,                    DEVPROP_TYPE_UINT32,                        L"BusNumber" },
+    { &DEVPKEY_Device_EnumeratorName,               DEVPROP_TYPE_STRING,                        L"EnumeratorName" },
+    { &DEVPKEY_Device_Security,                     DEVPROP_TYPE_SECURITY_DESCRIPTOR,           L"Security" },
+    { &DEVPKEY_Device_SecuritySDS,                  DEVPROP_TYPE_SECURITY_DESCRIPTOR_STRING,    L"SecuritySDS" },
+    { &DEVPKEY_Device_DevType,                      DEVPROP_TYPE_UINT32,                        L"DevType" },
+    { &DEVPKEY_Device_Exclusive,                    DEVPROP_TYPE_BOOLEAN,                       L"Exclusive" },
+    { &DEVPKEY_Device_Characteristics,              DEVPROP_TYPE_UINT32,                        L"Characteristics" },
+    { &DEVPKEY_Device_Address,                      DEVPROP_TYPE_UINT32,                        L"Address" },
+    { &DEVPKEY_Device_UINumberDescFormat,           DEVPROP_TYPE_STRING,                        L"UINumberDescFormat" },
+    { &DEVPKEY_Device_PowerData,                    DEVPROP_TYPE_BINARY,                        L"PowerData" },
+    { &DEVPKEY_Device_RemovalPolicy,                DEVPROP_TYPE_UINT32,                        L"RemovalPolicy" },
+    { &DEVPKEY_Device_RemovalPolicyDefault,         DEVPROP_TYPE_UINT32,                        L"RemovalPolicyDefault" },
+    { &DEVPKEY_Device_RemovalPolicyOverride,        DEVPROP_TYPE_UINT32,                        L"RemovalPolicyOverride" },
+    { &DEVPKEY_Device_InstallState,                 DEVPROP_TYPE_UINT32,                        L"InstallState" },
+    { &DEVPKEY_Device_LocationPaths,                DEVPROP_TYPE_STRING_LIST,                   L"LocationPaths" },
+    { &DEVPKEY_Device_BaseContainerId,              DEVPROP_TYPE_GUID,                          L"BaseContainerId" },
+};
+
+static LSTATUS query_device_property( HKEY hkey, struct property *prop )
+{
+    for (UINT i = 0; i < ARRAY_SIZE(device_properties); i++)
+    {
+        const struct property_desc *desc = device_properties + i;
+        if (memcmp( desc->key, &prop->key, sizeof(prop->key) )) continue;
+        if (!desc->name) return query_property( hkey, L"Properties\\", desc->type, prop );
+        return query_named_property( hkey, desc->name, desc->type, prop );
+    }
+
+    if (!memcmp( &DEVPKEY_Device_DeviceDesc, &prop->key, sizeof(prop->key.fmtid) ))
+    {
+        FIXME( "property %#lx not implemented\n", prop->key.pid - 1 );
+        return ERROR_UNKNOWN_PROPERTY;
+    }
+
+    return query_property( hkey, L"Properties\\", DEVPROP_TYPE_EMPTY, prop );
+}
+
+static LSTATUS get_device_property( HKEY root, const struct device *dev, struct property *prop )
+{
+    LSTATUS err;
+    HKEY hkey;
+
+    if (!(err = open_device_key( root, dev, KEY_QUERY_VALUE, TRUE, &hkey )))
+    {
+        err = query_device_property( hkey, prop );
+        RegCloseKey( hkey );
+    }
+
+    if (err && err != ERROR_MORE_DATA) *prop->size = 0;
+    return err;
+}
+
+static CRITICAL_SECTION devnode_cs;
+static CRITICAL_SECTION_DEBUG devnode_cs_debug = {
+    0, 0, &devnode_cs,
+    { &devnode_cs_debug.ProcessLocksList,
+      &devnode_cs_debug.ProcessLocksList },
+    0, 0, { (DWORD_PTR)(__FILE__ ": devnode_cs") }
+};
+static CRITICAL_SECTION devnode_cs = { &devnode_cs_debug, -1, 0, 0, 0, 0 };
+
+/* tree of the devnodes which have been accessed */
+static struct device *devnodes;
+static UINT devnodes_count, devnodes_capacity;
+
+/* devnode_cs must be held */
+static DEVINST devnodes_lookup( const struct device *dev )
+{
+    for (DEVINST i = 0; i < devnodes_count; ++i)
+    {
+        if (wcsicmp( devnodes[i].enumerator, dev->enumerator )) continue;
+        if (wcsicmp( devnodes[i].device, dev->device )) continue;
+        if (!wcsicmp( devnodes[i].instance, dev->instance )) return i + 1;
+    }
+
+    return 0;
+}
+
+/* devnode_cs must be held */
+static LSTATUS devnodes_append( const struct device *dev, DEVINST *node )
+{
+    if (devnodes_count == devnodes_capacity)
+    {
+        UINT capacity = max( 256, devnodes_capacity * 3 / 2 );
+        struct device *tmp;
+
+        if (capacity <= devnodes_capacity || !(tmp = realloc( devnodes, capacity * sizeof(*devnodes) ))) return ERROR_OUTOFMEMORY;
+        memset( tmp + devnodes_capacity, 0, (capacity - devnodes_capacity) * sizeof(*devnodes) );
+        devnodes_capacity = capacity;
+        devnodes = tmp;
+    }
+
+    devnodes[devnodes_count] = *dev;
+    *node = ++devnodes_count; /* index 0 is reserved */
+
+    return ERROR_SUCCESS;
+}
+
+static LSTATUS devnode_get_device( DEVINST node, struct device *dev )
+{
+    LSTATUS err = ERROR_SUCCESS;
+
+    EnterCriticalSection( &devnode_cs );
+    if (!node || node > devnodes_count) err = ERROR_NO_SUCH_DEVICE;
+    else *dev = devnodes[node - 1];
+    LeaveCriticalSection( &devnode_cs );
+
+    return err;
+}
+
 static CONFIGRET map_error( LSTATUS err )
 {
     switch (err)
@@ -544,6 +722,17 @@ static CONFIGRET map_error( LSTATUS err )
     }
 }
 
+static CONFIGRET map_error_node( LSTATUS err )
+{
+    switch (err)
+    {
+    case ERROR_INVALID_DATA: return CR_INVALID_DEVNODE;
+    case ERROR_NOT_FOUND: return CR_NO_SUCH_DEVNODE;
+    case ERROR_FILE_NOT_FOUND: return CR_NO_SUCH_DEVNODE;
+    default: return map_error( err );
+    }
+}
+
 /***********************************************************************
  *           CM_MapCrToWin32Err (cfgmgr32.@)
  */
@@ -1080,3 +1269,258 @@ CONFIGRET WINAPI CM_Get_Device_Interface_Property_KeysW( const WCHAR *iface, DEV
 {
     return CM_Get_Device_Interface_Property_Keys_ExW( iface, keys, count, flags, NULL );
 }
+
+/***********************************************************************
+ *           CM_Locate_DevNode_ExW (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Locate_DevNode_ExW( DEVINST *node, DEVINSTID_W instance_id, ULONG flags, HMACHINE machine )
+{
+    const WCHAR *instance = instance_id && *instance_id ? instance_id : L"HTREE\\ROOT\\0";
+    struct device dev;
+    LSTATUS err;
+    HKEY hkey;
+
+    TRACE( "node %p, instance_id %s, flags %#lx, machine %p\n", node, debugstr_w(instance_id), flags, machine );
+    if (machine) FIXME( "machine %p not implemented!\n", machine );
+    if (flags) FIXME( "flags %#lx not implemented!\n", flags );
+    if (!node) return CR_INVALID_POINTER;
+    *node = 0;
+
+    if (init_device( &dev, instance )) return CR_INVALID_DEVICE_ID;
+
+    EnterCriticalSection( &devnode_cs );
+
+    if ((*node = devnodes_lookup( &dev ))) err = ERROR_SUCCESS;
+    else if (!(err = open_device_key( HKEY_LOCAL_MACHINE, &dev, KEY_ALL_ACCESS, TRUE, &hkey )))
+    {
+        err = devnodes_append( &dev, node );
+        RegCloseKey( hkey );
+    }
+
+    LeaveCriticalSection( &devnode_cs );
+
+    return map_error_node( err );
+}
+
+/***********************************************************************
+ *           CM_Locate_DevNode_ExA (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Locate_DevNode_ExA( DEVINST *node, DEVINSTID_A instance_idA, ULONG flags, HMACHINE machine )
+{
+    WCHAR instance_idW[MAX_PATH];
+
+    TRACE( "node %p, instance_idA %s, flags %#lx, machine %p\n", node, debugstr_a(instance_idA), flags, machine );
+
+    if (instance_idA) MultiByteToWideChar( CP_ACP, 0, instance_idA, -1, instance_idW, ARRAY_SIZE(instance_idW) );
+    return CM_Locate_DevNode_ExW( node, instance_idA ? instance_idW : NULL, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Locate_DevNodeW (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Locate_DevNodeW( DEVINST *node, DEVINSTID_W instance_id, ULONG flags )
+{
+    return CM_Locate_DevNode_ExW( node, instance_id, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Locate_DevNodeA (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Locate_DevNodeA( DEVINST *node, DEVINSTID_A instance_id, ULONG flags )
+{
+    return CM_Locate_DevNode_ExA( node, instance_id, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Get_Device_ID_Size_Ex (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_ID_Size_Ex( ULONG *len, DEVINST node, ULONG flags, HMACHINE machine )
+{
+    struct device dev;
+
+    TRACE( "len %p, node %#lx, flags %#lx, machine %p\n", len, node, flags, machine );
+    if (machine) FIXME( "machine %p not implemented!\n", machine );
+    if (flags) FIXME( "flags %#lx not implemented!\n", flags );
+
+    if (!len) return CR_INVALID_POINTER;
+    if (devnode_get_device( node, &dev )) return CR_INVALID_DEVNODE;
+
+    *len = wcslen( dev.enumerator );
+    if (*dev.device) *len += 1 + wcslen( dev.device );
+    if (*dev.instance) *len += 1 + wcslen( dev.instance );
+
+    return CR_SUCCESS;
+}
+
+/***********************************************************************
+ *           CM_Get_Device_ID_Size (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_ID_Size( ULONG *len, DEVINST node, ULONG flags )
+{
+    return CM_Get_Device_ID_Size_Ex( len, node, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Get_Device_ID_ExW (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_ID_ExW( DEVINST node, WCHAR *buffer, ULONG len, ULONG flags, HMACHINE machine )
+{
+    WCHAR path[MAX_PATH];
+    struct device dev;
+    ULONG path_len;
+
+    TRACE( "node %#lx, buffer %p, len %lu, flags %#lx, machine %p\n", node, buffer, len, flags, machine );
+    if (machine) FIXME( "machine %p not implemented!\n", machine );
+    if (flags) FIXME( "flags %#lx not implemented!\n", flags );
+
+    if (!buffer) return CR_INVALID_POINTER;
+    if (devnode_get_device( node, &dev )) return CR_INVALID_DEVNODE;
+
+    path_len = swprintf( path, ARRAY_SIZE(path), L"%s", dev.enumerator );
+    if (*dev.device) path_len += swprintf( path + path_len, ARRAY_SIZE(path) - path_len, L"\\%s", dev.device );
+    if (*dev.instance) path_len += swprintf( path + path_len, ARRAY_SIZE(path) - path_len, L"\\%s", dev.instance );
+
+    if (path_len > len) return CR_BUFFER_SMALL;
+    memcpy( buffer, path, (path_len + 1) * sizeof(WCHAR) );
+
+    return CR_SUCCESS;
+}
+
+/***********************************************************************
+ *           CM_Get_Device_ID_ExA (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_ID_ExA( DEVINST node, char *bufferA, ULONG len, ULONG flags, HMACHINE machine )
+{
+    WCHAR *bufferW;
+    CONFIGRET ret;
+
+    bufferW = bufferA ? malloc( len * sizeof(WCHAR) ) : NULL;
+    ret = CM_Get_Device_ID_ExW( node, bufferA ? bufferW : NULL, len, flags, machine );
+    if (!ret && bufferA && len && !WideCharToMultiByte( CP_ACP, 0, bufferW, len, bufferA, len, 0, 0 ))
+    {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) ret = CR_BUFFER_SMALL;
+        else ret = CR_FAILURE;
+    }
+    free( bufferW );
+
+    return ret;
+}
+
+/***********************************************************************
+ *           CM_Get_Device_IDW (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_IDW( DEVINST node, WCHAR *buffer, ULONG len, ULONG flags )
+{
+    return CM_Get_Device_ID_ExW( node, buffer, len, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Get_Device_IDA (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_Device_IDA( DEVINST node, char *buffer, ULONG len, ULONG flags )
+{
+    return CM_Get_Device_ID_ExA( node, buffer, len, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Open_DevNode_Key_Ex (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Open_DevNode_Key_Ex( DEVINST node, REGSAM access, ULONG profile, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine )
+{
+    BOOL open = disposition == RegDisposition_OpenExisting;
+    HKEY root = HKEY_LOCAL_MACHINE, dev_key;
+    struct device dev;
+    LSTATUS err;
+
+    TRACE( "node %#lx, access %#lx, profile %lu, disposition %#lx, hkey %p, flags %#lx, machine %p\n", node, access, profile, disposition, hkey, flags, machine );
+    if (machine) FIXME( "machine %p not implemented!\n", machine );
+
+    if (devnode_get_device( node, &dev )) return CR_NO_SUCH_DEVNODE;
+    if ((flags & (CM_REGISTRY_USER | CM_REGISTRY_CONFIG)) == (CM_REGISTRY_USER | CM_REGISTRY_CONFIG)) return CR_INVALID_FLAG;
+
+    if (flags & CM_REGISTRY_CONFIG) root = HKEY_CURRENT_CONFIG;
+    else if (flags & CM_REGISTRY_USER) root = HKEY_CURRENT_USER;
+
+    if (flags & CM_REGISTRY_SOFTWARE)
+    {
+        WCHAR driver[MAX_PATH];
+        DWORD len = sizeof(driver);
+
+        if ((err = open_device_key( HKEY_LOCAL_MACHINE, &dev, access, open, &dev_key ))) return map_error( err );
+        if (RegQueryValueExW( dev_key, L"Driver", NULL, NULL, (BYTE *)driver, &len )) err = ERROR_NOT_FOUND;
+        RegCloseKey( dev_key );
+
+        if (!err) err = open_class_key( root, driver, access, open, hkey );
+        return map_error( err );
+    }
+
+    if (root != HKEY_LOCAL_MACHINE) return map_error( open_device_key( root, &dev, access, open, hkey ) );
+
+    if ((err = open_device_key( root, &dev, access, open, &dev_key ))) return map_error( err );
+    err = open_key( dev_key, L"Device Parameters", access, open, hkey );
+    RegCloseKey( dev_key );
+
+    return map_error( err );
+}
+
+/***********************************************************************
+ *           CM_Open_DevNode_Key (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Open_DevNode_Key( DEVINST node, REGSAM access, ULONG profile, REGDISPOSITION disposition, HKEY *hkey, ULONG flags )
+{
+    return CM_Open_DevNode_Key_Ex( node, access, profile, disposition, hkey, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Get_DevNode_Registry_Property_ExW (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_DevNode_Registry_Property_ExW( DEVINST node, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine )
+{
+    struct property prop;
+    struct device dev;
+    LSTATUS err;
+
+    TRACE( "node %#lx, property %#lx, type %p, buffer %p, len %p, flags %#lx, machine %p\n", node, property, type, buffer, len, flags, machine );
+    if (machine) FIXME( "machine %p not implemented!\n", machine );
+    if (flags) FIXME( "flags %#lx not implemented!\n", flags );
+
+    if (devnode_get_device( node, &dev )) return CR_INVALID_DEVNODE;
+    if ((err = init_registry_property( &prop, &DEVPKEY_Device_DeviceDesc, property, type, buffer, len, FALSE ))) return map_error( err );
+
+    return map_error( get_device_property( HKEY_LOCAL_MACHINE, &dev, &prop ) );
+}
+
+/***********************************************************************
+ *           CM_Get_DevNode_Registry_Property_ExA (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_DevNode_Registry_Property_ExA( DEVINST node, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine )
+{
+    struct property prop;
+    struct device dev;
+    LSTATUS err;
+
+    TRACE( "node %#lx, property %#lx, type %p, buffer %p, len %p, flags %#lx, machine %p\n", node, property, type, buffer, len, flags, machine );
+    if (machine) FIXME( "machine %p not implemented!\n", machine );
+    if (flags) FIXME( "flags %#lx not implemented!\n", flags );
+
+    if (devnode_get_device( node, &dev )) return CR_INVALID_DEVNODE;
+    if ((err = init_registry_property( &prop, &DEVPKEY_Device_DeviceDesc, property, type, buffer, len, TRUE ))) return map_error( err );
+
+    return map_error( get_device_property( HKEY_LOCAL_MACHINE, &dev, &prop ) );
+}
+
+/***********************************************************************
+ *           CM_Get_DevNode_Registry_PropertyW (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_DevNode_Registry_PropertyW( DEVINST node, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags )
+{
+    return CM_Get_DevNode_Registry_Property_ExW( node, property, type, buffer, len, flags, NULL );
+}
+
+/***********************************************************************
+ *           CM_Get_DevNode_Registry_PropertyA (cfgmgr32.@)
+ */
+CONFIGRET WINAPI CM_Get_DevNode_Registry_PropertyA( DEVINST node, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags )
+{
+    return CM_Get_DevNode_Registry_Property_ExA( node, property, type, buffer, len, flags, NULL );
+}
diff --git a/dlls/cfgmgr32/cfgmgr32.spec b/dlls/cfgmgr32/cfgmgr32.spec
index 2aee10c26729..9f5ed24ebf06 100644
--- a/dlls/cfgmgr32/cfgmgr32.spec
+++ b/dlls/cfgmgr32/cfgmgr32.spec
@@ -88,16 +88,16 @@
 @ stdcall CM_Get_DevNode_Property_ExW(long ptr ptr ptr ptr long ptr) setupapi.CM_Get_DevNode_Property_ExW
 @ stub CM_Get_DevNode_Property_Keys
 @ stub CM_Get_DevNode_Property_Keys_Ex
-@ stdcall CM_Get_DevNode_Registry_PropertyA(long long ptr ptr ptr long) setupapi.CM_Get_DevNode_Registry_PropertyA
-@ stdcall CM_Get_DevNode_Registry_PropertyW(long long ptr ptr ptr long) setupapi.CM_Get_DevNode_Registry_PropertyW
-@ stdcall CM_Get_DevNode_Registry_Property_ExA(long long ptr ptr ptr long ptr) setupapi.CM_Get_DevNode_Registry_Property_ExA
-@ stdcall CM_Get_DevNode_Registry_Property_ExW(long long ptr ptr ptr long ptr) setupapi.CM_Get_DevNode_Registry_Property_ExW
+@ stdcall CM_Get_DevNode_Registry_PropertyA(long long ptr ptr ptr long)
+@ stdcall CM_Get_DevNode_Registry_PropertyW(long long ptr ptr ptr long)
+@ stdcall CM_Get_DevNode_Registry_Property_ExA(long long ptr ptr ptr long ptr)
+@ stdcall CM_Get_DevNode_Registry_Property_ExW(long long ptr ptr ptr long ptr)
 @ stdcall CM_Get_DevNode_Status(ptr ptr long long) setupapi.CM_Get_DevNode_Status
 @ stdcall CM_Get_DevNode_Status_Ex(ptr ptr long long ptr) setupapi.CM_Get_DevNode_Status_Ex
-@ stdcall CM_Get_Device_IDA(ptr ptr long long) setupapi.CM_Get_Device_IDA
-@ stdcall CM_Get_Device_IDW(ptr ptr long long) setupapi.CM_Get_Device_IDW
-@ stdcall CM_Get_Device_ID_ExA(ptr ptr long long ptr) setupapi.CM_Get_Device_ID_ExA
-@ stdcall CM_Get_Device_ID_ExW(ptr ptr long long ptr) setupapi.CM_Get_Device_ID_ExW
+@ stdcall CM_Get_Device_IDA(ptr ptr long long)
+@ stdcall CM_Get_Device_IDW(ptr ptr long long)
+@ stdcall CM_Get_Device_ID_ExA(ptr ptr long long ptr)
+@ stdcall CM_Get_Device_ID_ExW(ptr ptr long long ptr)
 @ stdcall CM_Get_Device_ID_ListA(str ptr long long) setupapi.CM_Get_Device_ID_ListA
 @ stdcall CM_Get_Device_ID_ListW(wstr ptr long long) setupapi.CM_Get_Device_ID_ListW
 @ stdcall CM_Get_Device_ID_List_ExA(str ptr long long ptr) setupapi.CM_Get_Device_ID_List_ExA
@@ -106,8 +106,8 @@
 @ stdcall CM_Get_Device_ID_List_SizeW(ptr wstr long) setupapi.CM_Get_Device_ID_List_SizeW
 @ stdcall CM_Get_Device_ID_List_Size_ExA(ptr str long ptr) setupapi.CM_Get_Device_ID_List_Size_ExA
 @ stdcall CM_Get_Device_ID_List_Size_ExW(ptr wstr long ptr) setupapi.CM_Get_Device_ID_List_Size_ExW
-@ stdcall CM_Get_Device_ID_Size(ptr ptr long) setupapi.CM_Get_Device_ID_Size
-@ stub CM_Get_Device_ID_Size_Ex
+@ stdcall CM_Get_Device_ID_Size(ptr ptr long)
+@ stdcall CM_Get_Device_ID_Size_Ex(ptr ptr long ptr)
 @ stdcall CM_Get_Device_Interface_AliasA(str ptr ptr ptr long) setupapi.CM_Get_Device_Interface_AliasA
 @ stdcall CM_Get_Device_Interface_AliasW(wstr ptr ptr ptr long) setupapi.CM_Get_Device_Interface_AliasW
 @ stub CM_Get_Device_Interface_Alias_ExA
@@ -164,10 +164,10 @@
 @ stub CM_Is_Dock_Station_Present_Ex
 @ stub CM_Is_Version_Available
 @ stub CM_Is_Version_Available_Ex
-@ stdcall CM_Locate_DevNodeA(ptr str long) setupapi.CM_Locate_DevNodeA
-@ stdcall CM_Locate_DevNodeW(ptr wstr long) setupapi.CM_Locate_DevNodeW
-@ stdcall CM_Locate_DevNode_ExA(ptr str long long) setupapi.CM_Locate_DevNode_ExA
-@ stdcall CM_Locate_DevNode_ExW(ptr wstr long long) setupapi.CM_Locate_DevNode_ExW
+@ stdcall CM_Locate_DevNodeA(ptr str long)
+@ stdcall CM_Locate_DevNodeW(ptr wstr long)
+@ stdcall CM_Locate_DevNode_ExA(ptr str long long)
+@ stdcall CM_Locate_DevNode_ExW(ptr wstr long long)
 @ stub CM_MapCrToSpErr
 @ stdcall CM_MapCrToWin32Err(long long)
 @ stub CM_Merge_Range_List
@@ -180,8 +180,8 @@
 @ stdcall CM_Open_Class_KeyW(ptr wstr long long ptr long)
 @ stdcall CM_Open_Class_Key_ExA(ptr str long long ptr long ptr)
 @ stdcall CM_Open_Class_Key_ExW(ptr wstr long long ptr long ptr)
-@ stdcall CM_Open_DevNode_Key(long long long long ptr long) setupapi.CM_Open_DevNode_Key
-@ stub CM_Open_DevNode_Key_Ex
+@ stdcall CM_Open_DevNode_Key(long long long long ptr long)
+@ stdcall CM_Open_DevNode_Key_Ex(long long long long ptr long ptr)
 @ stdcall CM_Open_Device_Interface_KeyA(str long long ptr long)
 @ stdcall CM_Open_Device_Interface_KeyW(wstr long long ptr long)
 @ stdcall CM_Open_Device_Interface_Key_ExA(str long long ptr long ptr)
diff --git a/dlls/cfgmgr32/tests/cfgmgr32.c b/dlls/cfgmgr32/tests/cfgmgr32.c
index 7c6fa283f50a..8fe2b9e72414 100644
--- a/dlls/cfgmgr32/tests/cfgmgr32.c
+++ b/dlls/cfgmgr32/tests/cfgmgr32.c
@@ -86,6 +86,8 @@ static const WCHAR *guid_string( const GUID *guid, WCHAR *buffer, UINT length )
     return buffer;
 }
 
+static DEVINST next_devinst = 1;
+
 static void test_CM_MapCrToWin32Err(void)
 {
     unsigned int i;
@@ -2251,8 +2253,8 @@ static BOOL compare_unicode_string( const UNICODE_STRING *string, const WCHAR *e
            !wcsnicmp( string->Buffer, expect, string->Length / sizeof(WCHAR) );
 }
 
-#define check_object_name( a, b ) _check_object_name( __LINE__, a, b )
-static void _check_object_name( unsigned line, HANDLE handle, const WCHAR *expected_name )
+#define check_object_name( a, b ) check_object_name_( __LINE__, a, b, FALSE )
+static void check_object_name_( unsigned line, HANDLE handle, const WCHAR *expected_name, BOOL todo )
 {
     char buffer[1024];
     UNICODE_STRING *str = (UNICODE_STRING *)buffer, expect;
@@ -2265,6 +2267,7 @@ static void _check_object_name( unsigned line, HANDLE handle, const WCHAR *expec
     status = NtQueryObject( handle, ObjectNameInformation, buffer, sizeof(buffer), &len );
     ok_(__FILE__, line)( status == STATUS_SUCCESS, "NtQueryObject failed %lx\n", status );
     ok_(__FILE__, line)( len >= sizeof(OBJECT_NAME_INFORMATION) + str->Length, "unexpected len %lu\n", len );
+    todo_wine_if(todo)
     ok_(__FILE__, line)( compare_unicode_string( str, expected_name ), "got %s, expected %s\n",
                          debugstr_w(str->Buffer), debugstr_w(expected_name) );
 }
@@ -2889,6 +2892,431 @@ static void test_CM_Open_Device_Interface_Key(void)
     }
 }
 
+static void test_CM_Locate_DevNode(void)
+{
+    WCHAR iface[4096], path[MAX_PATH], instance_id[MAX_PATH];
+    DEVINST node, root = 0;
+    DWORD size, type, len;
+    CONFIGRET ret;
+    GUID guid;
+
+    ret = CM_Locate_DevNodeW( NULL, (WCHAR *)L"INVALID", 0 );
+    ok_x4( ret, ==, CR_INVALID_POINTER );
+
+    ret = CM_Get_Device_ID_Size( &len, 0, 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+    ret = CM_Get_Device_ID_Size( &len, 1, 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+    ret = CM_Get_Device_ID_Size( &len, 2, 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, NULL, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_x4( node, ==, next_devinst );
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, (WCHAR *)L"", 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_x4( node, ==, next_devinst );
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, (WCHAR *)L"HTREE\\ROOT\\0", 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_x4( node, ==, next_devinst );
+    if (node == next_devinst) root = next_devinst++;
+
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, (WCHAR *)L"INVALID", 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVICE_ID );
+    ok_x4( node, ==, 0 );
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, (WCHAR *)L"WINETEST\\WINETEST\\0123456", 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_DEVNODE );
+    ok_x4( node, ==, 0 );
+
+    guid = GUID_DEVINTERFACE_HID;
+    ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, ARRAY_SIZE(iface), CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
+    if (broken( !*iface ))
+    {
+        skip( "No HID device present, skipping tests\n" );
+        return;
+    }
+    ok_x4( ret, ==, CR_SUCCESS );
+    size = sizeof(instance_id);
+    ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( type, ==, DEVPROP_TYPE_STRING );
+
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, instance_id, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( node, ==, next_devinst );
+
+    wcslwr( instance_id );
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, instance_id, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( node, ==, next_devinst );
+
+    wcsupr( instance_id );
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, instance_id, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( node, ==, next_devinst );
+    if (node == next_devinst) next_devinst++;
+
+
+    ret = CM_Get_Device_ID_Size( &len, 0, 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+
+    len = 0xdeadbeef;
+    ret = CM_Get_Device_ID_Size( &len, root, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( len, ==, 12 );
+    len = 0xdeadbeef;
+    ret = CM_Get_Device_ID_Size( &len, node, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( len, ==, wcslen( instance_id ) );
+
+
+    ret = CM_Get_Device_IDW( 0, path, ARRAY_SIZE(path), 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+    ret = CM_Get_Device_IDW( root, path, 0, 0 );
+    todo_wine ok_x4( ret, ==, CR_INVALID_POINTER );
+    ret = CM_Get_Device_IDW( root, NULL, ARRAY_SIZE(path), 0 );
+    ok_x4( ret, ==, CR_INVALID_POINTER );
+
+    memset( path, 0xcd, sizeof(path) );
+    ret = CM_Get_Device_IDW( root, path, ARRAY_SIZE(path), 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_wcs( L"HTREE\\ROOT\\0", path );
+
+    memset( path, 0xcd, sizeof(path) );
+    ret = CM_Get_Device_IDW( node, path, ARRAY_SIZE(path), 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_wcs( instance_id, path );
+}
+
+static void test_CM_Open_DevNode_Key(void)
+{
+    WCHAR iface[4096], driver[MAX_PATH], path[MAX_PATH], instance_id[MAX_PATH];
+    UNICODE_STRING user;
+    DWORD size, type;
+    CONFIGRET ret;
+    DEVINST node;
+    GUID guid;
+    HKEY hkey;
+
+    RtlFormatCurrentUserKeyPath( &user );
+
+    guid = GUID_DEVINTERFACE_HID;
+    ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, ARRAY_SIZE(iface), CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
+    if (broken( !*iface ))
+    {
+        skip( "No HID device present, skipping tests\n" );
+        return;
+    }
+    ok_x4( ret, ==, CR_SUCCESS );
+    size = sizeof(instance_id);
+    ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( type, ==, DEVPROP_TYPE_STRING );
+
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, instance_id, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( node, ==, next_devinst - 1 );
+
+    size = ARRAY_SIZE(driver);
+    swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Enum\\%s", instance_id );
+    ret = RegGetValueW( HKEY_LOCAL_MACHINE, path, L"Driver", RRF_RT_ANY, NULL, (BYTE *)driver, &size );
+    ok_u4( ret, ==, ERROR_SUCCESS );
+
+
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_HARDWARE );
+    ok_x4( ret, ==, CR_SUCCESS );
+    swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Enum\\%s\\Device Parameters", instance_id );
+    check_object_name( hkey, path );
+    RegCloseKey( hkey );
+
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_USER );
+    ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY );
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_USER );
+    ok_x4( ret, ==, CR_SUCCESS );
+    swprintf( path, ARRAY_SIZE(path), L"%s\\System\\CurrentControlSet\\Enum\\%s", user.Buffer, instance_id );
+    check_object_name( hkey, path );
+    RegCloseKey( hkey );
+    swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Enum\\%s", instance_id );
+    RegDeleteKeyW( HKEY_CURRENT_USER, path );
+
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_CONFIG );
+    ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY );
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_CONFIG );
+    ok_x4( ret, ==, CR_SUCCESS );
+    swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Hardware Profiles\\0001\\System\\CurrentControlSet\\Enum\\%s", instance_id );
+    check_object_name_( __LINE__, hkey, path, TRUE );
+    RegCloseKey( hkey );
+    swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Enum\\%s", instance_id );
+    RegDeleteKeyW( HKEY_CURRENT_CONFIG, path );
+
+
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE );
+    ok_x4( ret, ==, CR_SUCCESS );
+    swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Control\\Class\\%s", driver );
+    check_object_name( hkey, path );
+    RegCloseKey( hkey );
+
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_USER );
+    ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY );
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_USER );
+    ok_x4( ret, ==, CR_SUCCESS );
+    swprintf( path, ARRAY_SIZE(path), L"%s\\System\\CurrentControlSet\\Control\\Class\\%s", user.Buffer, driver );
+    check_object_name( hkey, path );
+    RegCloseKey( hkey );
+    swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Control\\Class\\%s", driver );
+    RegDeleteKeyW( HKEY_CURRENT_USER, path );
+
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenExisting, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG );
+    ok_x4( ret, ==, CR_NO_SUCH_REGISTRY_KEY );
+    ret = CM_Open_DevNode_Key( node, KEY_QUERY_VALUE, 0, RegDisposition_OpenAlways, &hkey, CM_REGISTRY_SOFTWARE | CM_REGISTRY_CONFIG );
+    ok_x4( ret, ==, CR_SUCCESS );
+    swprintf( path, ARRAY_SIZE(path), L"\\REGISTRY\\MACHINE\\SYSTEM\\ControlSet001\\Hardware Profiles\\0001\\System\\CurrentControlSet\\Control\\Class\\%s", driver );
+    check_object_name_( __LINE__, hkey, path, TRUE );
+    RegCloseKey( hkey );
+    swprintf( path, ARRAY_SIZE(path), L"System\\CurrentControlSet\\Control\\Class\\%s", driver );
+    RegDeleteKeyW( HKEY_CURRENT_CONFIG, path );
+
+
+    RtlFreeUnicodeString( &user );
+}
+
+static void test_CM_Get_DevNode_Registry_Property(void)
+{
+    WCHAR iface[4096], instance_id[MAX_PATH], buffer[MAX_PATH];
+    DWORD size, type, len;
+    CONFIGRET ret;
+    DEVINST node;
+    GUID guid;
+
+
+    guid = GUID_DEVINTERFACE_HID;
+    ret = CM_Get_Device_Interface_ListW( &guid, NULL, iface, ARRAY_SIZE(iface), CM_GET_DEVICE_INTERFACE_LIST_PRESENT );
+    if (broken( !*iface ))
+    {
+        skip( "No HID device present, skipping tests\n" );
+        return;
+    }
+    ok_x4( ret, ==, CR_SUCCESS );
+    size = sizeof(instance_id);
+    ret = CM_Get_Device_Interface_PropertyW( iface, &DEVPKEY_Device_InstanceId, &type, (BYTE *)instance_id, &size, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_x4( type, ==, DEVPROP_TYPE_STRING );
+
+    node = 0xdeadbeef;
+    ret = CM_Locate_DevNodeW( &node, instance_id, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_x4( node, ==, 2 );
+
+
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( 0, CM_DRP_CLASSGUID, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASSGUID, NULL, NULL, NULL, 0 );
+    ok_x4( ret, ==, CR_INVALID_POINTER );
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASSGUID, &type, buffer, NULL, 0 );
+    ok_x4( ret, ==, CR_INVALID_POINTER );
+    len = 1;
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASSGUID, &type, NULL, &len, 0 );
+    ok_x4( ret, ==, CR_INVALID_POINTER );
+
+    len = 0;
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASSGUID, &type, NULL, &len, 0 );
+    ok_x4( ret, ==, CR_BUFFER_SMALL );
+    ok_x4( len, ==, 78 );
+    len = 1;
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASSGUID, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_BUFFER_SMALL );
+    ok_x4( len, ==, 78 );
+
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( 10, CM_DRP_CLASSGUID, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_INVALID_DEVNODE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, 0, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_INVALID_PROPERTY );
+
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_DEVICEDESC, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_SZ );
+    ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_HARDWAREID, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_MULTI_SZ );
+    ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_COMPATIBLEIDS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_MULTI_SZ );
+    ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_SERVICE, &type, buffer, &len, 0 );
+    ok( ret == CR_NO_SUCH_VALUE || ret == CR_SUCCESS, "got ret == %#lx\n", ret );
+    ok( type == 0xdeadbeef || type == REG_SZ, "got type == %#lx\n", type );
+    ok( len == 0 || len == 14, "got len == %#lx\n", len );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_SZ );
+    ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CLASSGUID, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_SZ );
+    ok_u4( len, ==, 78 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_DRIVER, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_SZ );
+    ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CONFIGFLAGS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_SUCCESS );
+    ok_u4( type, ==, REG_DWORD );
+    ok_u4( len, ==, 4 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_MFG, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_SZ );
+    todo_wine ok_u4( len, >, 1 );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_FRIENDLYNAME, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_LOCATION_INFORMATION, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    ok_u4( type, ==, 0xdeadbeef );
+    ok_u4( len, ==, 0 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_SZ );
+    todo_wine ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CAPABILITIES, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_UI_NUMBER, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_UPPERFILTERS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_LOWERFILTERS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_BUSTYPEGUID, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_BINARY );
+    todo_wine ok_u4( len, ==, 16 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_LEGACYBUSTYPE, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_BUSNUMBER, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_ENUMERATOR_NAME, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_SZ );
+    todo_wine ok_u4( len, >, 1 );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_SECURITY, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_SECURITY_SDS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_DEVTYPE, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_EXCLUSIVE, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_CHARACTERISTICS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_ADDRESS, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_UI_NUMBER_DESC_FORMAT, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_DEVICE_POWER_DATA, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_BINARY );
+    todo_wine ok_u4( len, >, 1 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_REMOVAL_POLICY, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_REMOVAL_POLICY_HW_DEFAULT, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_REMOVAL_POLICY_OVERRIDE, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_INSTALL_STATE, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_DWORD );
+    todo_wine ok_u4( len, ==, 4 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_LOCATION_PATHS, &type, buffer, &len, 0 );
+    ok_x4( ret, ==, CR_NO_SUCH_VALUE );
+    ok_u4( type, ==, 0xdeadbeef );
+    ok_u4( len, ==, 0 );
+    type = 0xdeadbeef;
+    len = sizeof(buffer);
+    ret = CM_Get_DevNode_Registry_PropertyW( node, CM_DRP_BASE_CONTAINERID, &type, buffer, &len, 0 );
+    todo_wine ok_x4( ret, ==, CR_SUCCESS );
+    todo_wine ok_u4( type, ==, REG_SZ );
+    todo_wine ok_u4( len, ==, 78 );
+}
+
 static void test_CM_Get_Class_Property_Keys(void)
 {
     GUID guid = GUID_DEVCLASS_HIDCLASS;
@@ -2947,6 +3375,7 @@ START_TEST(cfgmgr32)
     pDevFindProperty = (void *)GetProcAddress(mod, "DevFindProperty");
 
     test_CM_MapCrToWin32Err();
+    test_CM_Locate_DevNode();
     test_CM_Enumerate_Classes();
     test_CM_Enumerate_Enumerators();
     test_CM_Get_Class_Key_Name();
@@ -2962,6 +3391,8 @@ START_TEST(cfgmgr32)
     test_CM_Get_Device_Interface_Property_setupapi();
     test_CM_Get_Device_ID_List();
     test_CM_Register_Notification();
+    test_CM_Open_DevNode_Key();
+    test_CM_Get_DevNode_Registry_Property();
     test_DevGetObjects();
     test_DevCreateObjectQuery();
     test_DevGetObjectProperties_invalid();
diff --git a/dlls/comctl32/imagelist.c b/dlls/comctl32/imagelist.c
index 6650e3db04bf..781643545fd1 100644
--- a/dlls/comctl32/imagelist.c
+++ b/dlls/comctl32/imagelist.c
@@ -3664,7 +3664,9 @@ static HRESULT WINAPI ImageListImpl_Initialize(IImageList2 *iface, INT cx, INT c
     }
 
     /* Some applications mistakenly use a very large initial image count. Limit it to something reasonable */
-    initial = min(initial, 256);
+    if (initial > USHRT_MAX)
+        WARN("Image count has been truncated\n");
+    initial = min(initial, USHRT_MAX);
 
     himl->cx        = cx;
     himl->cy        = cy;
diff --git a/dlls/comctl32/tests/treeview.c b/dlls/comctl32/tests/treeview.c
index 5c99534383b8..997efa01a9df 100644
--- a/dlls/comctl32/tests/treeview.c
+++ b/dlls/comctl32/tests/treeview.c
@@ -39,6 +39,11 @@ static HTHEME (WINAPI *pGetWindowTheme)(HWND);
 static BOOL (WINAPI *pIsThemeBackgroundPartiallyTransparent)(HTHEME, int, int);
 
 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);
+
+static HIMAGELIST (WINAPI *pImageList_Create)(int, int, UINT, int, int);
+static BOOL (WINAPI *pImageList_Destroy)(HIMAGELIST);
+static int (WINAPI *pImageList_Add)(HIMAGELIST, HBITMAP, HBITMAP);
+
 static const char *TEST_CALLBACK_TEXT = "callback_text";
 
 static TVITEMA g_item_expanding, g_item_expanded;
@@ -2565,6 +2570,67 @@ static void test_htreeitem_layout(BOOL is_version_6)
     DestroyWindow(hTree);
 }
 
+/* Create a 3-state (unchecked/checked/indeterminate) image list */
+static HIMAGELIST setup_3state_imagelist(HWND wndTree)
+{
+    int itemHeight;
+    HDC dc; HBITMAP bmp;
+    RECT rcDraw;
+    const HBRUSH brush = (HBRUSH)GetStockObject(DC_BRUSH);
+    HIMAGELIST images;
+    HGDIOBJ restore;
+
+    if (wndTree == NULL) return NULL;
+    itemHeight = (int)SendMessageA(wndTree, TVM_GETITEMHEIGHT, 0, 0);
+    if ( itemHeight <= 0 ) return NULL;
+    dc = GetDC(wndTree);
+    if ( dc == NULL ) return NULL;
+    bmp = CreateCompatibleBitmap(dc, itemHeight, itemHeight);
+    ReleaseDC(wndTree, dc);
+    if ( bmp == NULL ) return NULL;
+
+    images = pImageList_Create(itemHeight, itemHeight, ILC_COLORDDB, 0, 5);
+    if ( images == NULL ) return NULL;
+
+    dc = CreateCompatibleDC(NULL);
+    if ( dc == NULL )
+    {
+        pImageList_Destroy(images);
+        return NULL;
+    }
+
+    rcDraw.left = 0; rcDraw.top = 0; rcDraw.right = itemHeight; rcDraw.bottom = itemHeight;
+
+    SetDCBrushColor(dc, GetSysColor(COLOR_WINDOW));
+
+    restore = SelectObject(dc, bmp);
+    FillRect(dc, &rcDraw, brush);
+    SelectObject(dc, restore);
+    pImageList_Add(images, bmp, NULL);
+
+    restore = SelectObject(dc, bmp);
+    FillRect(dc, &rcDraw, brush);
+    DrawFrameControl(dc, &rcDraw, DFC_BUTTON, DFCS_BUTTONCHECK);
+    SelectObject(dc, restore);
+    pImageList_Add(images, bmp, NULL);
+
+    restore = SelectObject(dc, bmp);
+    FillRect(dc, &rcDraw, brush);
+    DrawFrameControl(dc, &rcDraw, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_CHECKED);
+    SelectObject(dc, restore);
+    pImageList_Add(images, bmp, NULL);
+
+    restore = SelectObject(dc, bmp);
+    FillRect(dc, &rcDraw, brush);
+    DrawFrameControl(dc, &rcDraw, DFC_BUTTON, DFCS_BUTTONCHECK | DFCS_CHECKED | DFCS_BUTTON3STATE);
+    SelectObject(dc, restore);
+    pImageList_Add(images, bmp, NULL);
+
+    DeleteDC(dc);
+
+    return images;
+}
+
 static void test_TVS_CHECKBOXES(void)
 {
     HIMAGELIST himl, himl2;
@@ -2747,6 +2813,79 @@ static void test_TVS_CHECKBOXES(void)
     himl = (HIMAGELIST)SendMessageA(hTree, TVM_GETIMAGELIST, TVSIL_STATE, 0);
     ok(himl != NULL, "got %p\n", himl);
 
+    /*
+    Check cycling item states with default image list
+    1 >> 2 >> 1
+    */
+
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    item.state = INDEXTOSTATEIMAGEMASK(1);
+    ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(hTree,TVM_SELECTITEM,TVGN_CARET,(LPARAM)hChild);
+    expect(TRUE, ret);
+
+    SendMessageA(hTree, WM_KEYDOWN, VK_SPACE, 0);
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok((item.state&TVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2), "item.state=%x\n", item.state);
+
+    SendMessageA(hTree, WM_KEYDOWN, VK_SPACE, 0);
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok((item.state&TVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(1), "item.state=%x\n", item.state);
+
+    /*
+    Check cycling item states with 3-state image list
+    1 >> 2 >> 3 >> 1
+    */
+
+    himl2 = setup_3state_imagelist(hTree);
+    ok(himl2 != NULL, "setup_3state_imagelist: %p\n", himl2);
+
+    himl = (HIMAGELIST)SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl2);
+    ok(himl != NULL, "got %p\n", himl);
+
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    item.state = INDEXTOSTATEIMAGEMASK(1);
+    ret = SendMessageA(hTree, TVM_SETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+
+    ret = SendMessageA(hTree,TVM_SELECTITEM,TVGN_CARET,(LPARAM)hChild);
+    expect(TRUE, ret);
+
+    SendMessageA(hTree, WM_KEYDOWN, VK_SPACE, 0);
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok((item.state&TVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(2), "item.state=%x\n", item.state);
+
+    SendMessageA(hTree, WM_KEYDOWN, VK_SPACE, 0);
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok((item.state&TVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(3), "item.state=%x\n", item.state);
+
+    SendMessageA(hTree, WM_KEYDOWN, VK_SPACE, 0);
+    item.hItem = hChild;
+    item.mask = TVIF_STATE;
+    ret = SendMessageA(hTree, TVM_GETITEMA, 0, (LPARAM)&item);
+    expect(TRUE, ret);
+    ok((item.state&TVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK(1), "item.state=%x\n", item.state);
+
+    himl = (HIMAGELIST)SendMessageA(hTree, TVM_SETIMAGELIST, TVSIL_STATE, (LPARAM)himl);
+    ok(himl == himl2, "got %p\n", himl);
+    pImageList_Destroy(himl2);
+
     DestroyWindow(hTree);
 }
 
@@ -3192,6 +3331,9 @@ static void init_functions(void)
 
 #define X(module, f) p##f = (void*)GetProcAddress(module, #f);
     X(hComCtl32, InitCommonControlsEx);
+    X(hComCtl32, ImageList_Create);
+    X(hComCtl32, ImageList_Destroy);
+    X(hComCtl32, ImageList_Add);
 
     X(hUxtheme, GetWindowTheme);
     X(hUxtheme, IsThemeBackgroundPartiallyTransparent);
diff --git a/dlls/comctl32/treeview.c b/dlls/comctl32/treeview.c
index f93ee069dc15..6332040b7f57 100644
--- a/dlls/comctl32/treeview.c
+++ b/dlls/comctl32/treeview.c
@@ -2342,21 +2342,30 @@ TREEVIEW_ToggleItemState(const TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item)
 {
     if (infoPtr->dwStyle & TVS_CHECKBOXES)
     {
-	static const unsigned int state_table[] = { 0, 2, 1 };
+        unsigned int state, stateImage, numStates;
 
-	unsigned int state;
+        /* Toggle item state cycles through images other than zero, if image list with more state images is set */
+        numStates = 0;
+        if ( infoPtr->himlState ) numStates = ImageList_GetImageCount(infoPtr->himlState);
+        if ( numStates < 3 ) numStates = 3;
 
-	state = STATEIMAGEINDEX(item->state);
-	TRACE("state: 0x%x\n", state);
-	item->state &= ~TVIS_STATEIMAGEMASK;
+        state = item->state;
+        stateImage = STATEIMAGEINDEX(state);
+        TRACE("stateImage: 0x%x\n", stateImage);
+        state &= ~TVIS_STATEIMAGEMASK;
 
-	if (state < 3)
-	    state = state_table[state];
+        if ( stateImage > 0 )
+        {
+            ++ stateImage;
+            if ( stateImage >= numStates ) stateImage = 1;
+        }
 
-	item->state |= INDEXTOSTATEIMAGEMASK(state);
+        state |= INDEXTOSTATEIMAGEMASK(stateImage);
 
-	TRACE("state: 0x%x\n", state);
-	TREEVIEW_Invalidate(infoPtr, item);
+        TRACE("stateImage: 0x%x\n", stateImage);
+
+        item->state = state;
+        TREEVIEW_Invalidate(infoPtr, item);
     }
 }
 
diff --git a/dlls/crypt32/Makefile.in b/dlls/crypt32/Makefile.in
index 7f35b0e41644..9af443bfb36d 100644
--- a/dlls/crypt32/Makefile.in
+++ b/dlls/crypt32/Makefile.in
@@ -2,7 +2,7 @@ EXTRADEFS = -D_CRYPT32_
 MODULE    = crypt32.dll
 UNIXLIB   = crypt32.so
 IMPORTLIB = crypt32
-IMPORTS   = user32 advapi32 bcrypt
+IMPORTS   = user32 advapi32 bcrypt ncrypt
 DELAYIMPORTS = cryptnet
 UNIX_LIBS    = $(SECURITY_LIBS)
 UNIX_CFLAGS  = $(GNUTLS_CFLAGS)
diff --git a/dlls/crypt32/cert.c b/dlls/crypt32/cert.c
index 11e436b48c7e..085174561129 100644
--- a/dlls/crypt32/cert.c
+++ b/dlls/crypt32/cert.c
@@ -652,8 +652,38 @@ BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT pCertContext,
         ret = CertContext_GetProperty(cert,
          CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
         if (ret)
-            ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
-             sizeof(keyContext.hCryptProv));
+        {
+            if (keyContext.dwKeySpec == CERT_NCRYPT_KEY_SPEC)
+            {
+                SetLastError(CRYPT_E_NOT_FOUND);
+                ret = FALSE;
+            }
+            else
+                ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
+                 sizeof(keyContext.hCryptProv));
+        }
+        break;
+    }
+    case CERT_NCRYPT_KEY_HANDLE_PROP_ID:
+    {
+        CERT_KEY_CONTEXT keyContext;
+        DWORD size = sizeof(keyContext);
+
+        ret = CertContext_GetProperty(cert,
+         CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
+        if (ret)
+        {
+            if (keyContext.dwKeySpec != CERT_NCRYPT_KEY_SPEC)
+            {
+                SetLastError(CRYPT_E_NOT_FOUND);
+                ret = FALSE;
+            }
+            else
+                ret = CertContext_CopyParam(pvData, pcbData, &keyContext.hCryptProv,
+                 sizeof(keyContext.hCryptProv));
+        }
+        else
+            SetLastError(CRYPT_E_NOT_FOUND);
         break;
     }
     case CERT_KEY_PROV_INFO_PROP_ID:
@@ -838,6 +868,23 @@ static BOOL CertContext_SetProperty(cert_t *cert, DWORD dwPropId,
              0, &keyContext);
             break;
         }
+        case CERT_NCRYPT_KEY_HANDLE_PROP_ID:
+        {
+            CERT_KEY_CONTEXT keyContext;
+
+            if (!pvData)
+            {
+                ContextPropertyList_RemoveProperty(cert->base.properties,
+                 CERT_KEY_CONTEXT_PROP_ID);
+                ret = TRUE;
+                break;
+            }
+            keyContext.cbSize = sizeof(keyContext);
+            keyContext.hCryptProv = *(const HCRYPTPROV *)pvData;
+            keyContext.dwKeySpec = CERT_NCRYPT_KEY_SPEC;
+            ret = CertContext_SetKeyContextProperty(cert->base.properties, &keyContext);
+            break;
+        }
         default:
             FIXME("%ld: stub\n", dwPropId);
             ret = FALSE;
diff --git a/dlls/crypt32/chain.c b/dlls/crypt32/chain.c
index 6e0e55b9e5a4..f3c97c3588fb 100644
--- a/dlls/crypt32/chain.c
+++ b/dlls/crypt32/chain.c
@@ -221,6 +221,22 @@ typedef struct _CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT
     DWORD       CycleDetectionModulus;
 } CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT;
 
+typedef struct _CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_FLAGS
+{
+    DWORD       cbSize;
+    HCERTSTORE  hRestrictedRoot;
+    HCERTSTORE  hRestrictedTrust;
+    HCERTSTORE  hRestrictedOther;
+    DWORD       cAdditionalStore;
+    HCERTSTORE *rghAdditionalStore;
+    DWORD       dwFlags;
+    DWORD       dwUrlRetrievalTimeout;
+    DWORD       MaximumCachedCertificates;
+    DWORD       CycleDetectionModulus;
+    HCERTSTORE  hExclusiveRoot;
+    HCERTSTORE  hExclusiveTrustedPeople;
+} CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_FLAGS;
+
 BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
  HCERTCHAINENGINE *phChainEngine)
 {
@@ -236,17 +252,23 @@ BOOL WINAPI CertCreateCertificateChainEngine(PCERT_CHAIN_ENGINE_CONFIG pConfig,
     TRACE("dwUrlRetrievalTimeout %lu\n", pConfig->dwUrlRetrievalTimeout);
     TRACE("MaximumCachedCertificates %lu\n", pConfig->MaximumCachedCertificates);
     TRACE("CycleDetectionModulus %lu\n", pConfig->CycleDetectionModulus);
-    TRACE("hExclusiveRoot %p\n", pConfig->hExclusiveRoot);
-    TRACE("hExclusiveTrustedPeople %p\n", pConfig->hExclusiveTrustedPeople);
-    TRACE("dwExclusiveFlags %lx\n", pConfig->dwExclusiveFlags);
-    if (pConfig->dwExclusiveFlags) FIXME("dwExclusiveFlags %lx not supported\n", pConfig->dwExclusiveFlags);
-
-    if (pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT)
-     && pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG))
+    if (pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_ROOT) &&
+        pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG_NO_EXCLUSIVE_FLAGS) &&
+        pConfig->cbSize != sizeof(CERT_CHAIN_ENGINE_CONFIG))
     {
         SetLastError(E_INVALIDARG);
         return FALSE;
     }
+
+    if (pConfig->cbSize == sizeof(CERT_CHAIN_ENGINE_CONFIG))
+    {
+        TRACE("hExclusiveRoot %p\n", pConfig->hExclusiveRoot);
+        TRACE("hExclusiveTrustedPeople %p\n", pConfig->hExclusiveTrustedPeople);
+        TRACE("dwExclusiveFlags %lx\n", pConfig->dwExclusiveFlags);
+        if (pConfig->dwExclusiveFlags)
+            FIXME("dwExclusiveFlags %lx not supported\n", pConfig->dwExclusiveFlags);
+    }
+
     ret = CRYPT_CheckRestrictedRoot(pConfig->hRestrictedRoot);
     if (!ret)
     {
diff --git a/dlls/crypt32/crypt32_private.h b/dlls/crypt32/crypt32_private.h
index 17253bde6955..7b6bdfa9df77 100644
--- a/dlls/crypt32/crypt32_private.h
+++ b/dlls/crypt32/crypt32_private.h
@@ -513,6 +513,17 @@ struct enum_root_certs_params
     DWORD *needed;
 };
 
+struct export_cert_store_params
+{
+    const BYTE *cert_data;
+    DWORD       cert_size;
+    const BYTE *key_blob;
+    DWORD       key_blob_size;
+    const WCHAR *password;
+    BYTE        *pfx_data;
+    DWORD       *pfx_size;
+};
+
 enum unix_funcs
 {
     unix_process_attach,
@@ -522,6 +533,7 @@ enum unix_funcs
     unix_import_store_cert,
     unix_close_cert_store,
     unix_enum_root_certs,
+    unix_export_cert_store,
     unix_funcs_count,
 };
 
diff --git a/dlls/crypt32/pfx.c b/dlls/crypt32/pfx.c
index a833fd42366a..3a86fce3165c 100644
--- a/dlls/crypt32/pfx.c
+++ b/dlls/crypt32/pfx.c
@@ -22,6 +22,8 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wincrypt.h"
+#include "bcrypt.h"
+#include "ncrypt.h"
 #include "snmp.h"
 #include "crypt32_private.h"
 
@@ -241,9 +243,217 @@ BOOL WINAPI PFXExportCertStore( HCERTSTORE store, CRYPT_DATA_BLOB *pfx, const WC
     return PFXExportCertStoreEx( store, pfx, password, NULL, flags );
 }
 
+static void reverse_bytes( const BYTE *src, BYTE *dst, DWORD len )
+{
+    DWORD i;
+    for (i = 0; i < len; i++) dst[i] = src[len - i - 1];
+}
+
+static BYTE *export_capi_key( HCRYPTPROV prov, DWORD key_spec, DWORD *out_size )
+{
+    HCRYPTKEY hkey;
+    BYTE *capi_blob = NULL, *bcrypt_blob = NULL;
+    DWORD capi_size, bitlen, mod_len, prime_len, pos, out_pos;
+    BLOBHEADER *hdr;
+    RSAPUBKEY *rsakey;
+    BCRYPT_RSAKEY_BLOB *rsa_hdr;
+
+    if (!CryptGetUserKey( prov, key_spec, &hkey ))
+    {
+        WARN( "CryptGetUserKey failed %08lx\n", GetLastError() );
+        return NULL;
+    }
+
+    /* Query size. */
+    capi_size = 0;
+    if (!CryptExportKey( hkey, 0, PRIVATEKEYBLOB, 0, NULL, &capi_size ))
+    {
+        WARN( "CryptExportKey size query failed %08lx\n", GetLastError() );
+        CryptDestroyKey( hkey );
+        return NULL;
+    }
+
+    capi_blob = CryptMemAlloc( capi_size );
+    if (!capi_blob)
+    {
+        CryptDestroyKey( hkey );
+        return NULL;
+    }
+
+    if (!CryptExportKey( hkey, 0, PRIVATEKEYBLOB, 0, capi_blob, &capi_size ))
+    {
+        WARN( "CryptExportKey failed %08lx\n", GetLastError() );
+        CryptMemFree( capi_blob );
+        CryptDestroyKey( hkey );
+        return NULL;
+    }
+    CryptDestroyKey( hkey );
+
+    hdr = (BLOBHEADER *)capi_blob;
+    rsakey = (RSAPUBKEY *)(hdr + 1);
+    bitlen = rsakey->bitlen;
+    mod_len = bitlen / 8;
+    prime_len = bitlen / 16;
+
+    /* Build BCRYPT_RSAFULLPRIVATE_BLOB. */
+    *out_size = sizeof(BCRYPT_RSAKEY_BLOB) + sizeof(rsakey->pubexp) + mod_len * 2 + prime_len * 5;
+    bcrypt_blob = CryptMemAlloc( *out_size );
+    if (!bcrypt_blob)
+    {
+        CryptMemFree( capi_blob );
+        return NULL;
+    }
+
+    rsa_hdr = (BCRYPT_RSAKEY_BLOB *)bcrypt_blob;
+    rsa_hdr->Magic = BCRYPT_RSAFULLPRIVATE_MAGIC;
+    rsa_hdr->BitLength = bitlen;
+    rsa_hdr->cbPublicExp = sizeof(rsakey->pubexp);
+    rsa_hdr->cbModulus = mod_len;
+    rsa_hdr->cbPrime1 = prime_len;
+    rsa_hdr->cbPrime2 = prime_len;
+
+    out_pos = sizeof(BCRYPT_RSAKEY_BLOB);
+    /* PublicExp (big-endian). */
+    reverse_bytes( (const BYTE *)&rsakey->pubexp, bcrypt_blob + out_pos, sizeof(rsakey->pubexp) );
+    out_pos += sizeof(rsakey->pubexp);
+
+    /* CAPI data starts after BLOBHEADER + RSAPUBKEY. */
+    pos = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY);
+
+    /* Modulus */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, mod_len );
+    pos += mod_len; out_pos += mod_len;
+    /* Prime1 */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, prime_len );
+    pos += prime_len; out_pos += prime_len;
+    /* Prime2 */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, prime_len );
+    pos += prime_len; out_pos += prime_len;
+    /* Exponent1 */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, prime_len );
+    pos += prime_len; out_pos += prime_len;
+    /* Exponent2 */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, prime_len );
+    pos += prime_len; out_pos += prime_len;
+    /* Coefficient */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, prime_len );
+    pos += prime_len; out_pos += prime_len;
+    /* PrivateExponent */
+    reverse_bytes( capi_blob + pos, bcrypt_blob + out_pos, mod_len );
+
+    CryptMemFree( capi_blob );
+    return bcrypt_blob;
+}
+
 BOOL WINAPI PFXExportCertStoreEx( HCERTSTORE store, CRYPT_DATA_BLOB *pfx, const WCHAR *password, void *reserved,
                                   DWORD flags )
 {
-    FIXME( "(%p, %p, %p, %p, %08lx): stub\n", store, pfx, password, reserved, flags );
-    return FALSE;
+    const CERT_CONTEXT *cert;
+    CERT_KEY_CONTEXT key_ctx;
+    struct export_cert_store_params params;
+    DWORD key_ctx_size, key_blob_size;
+    BYTE *key_blob = NULL;
+    SECURITY_STATUS sec_status;
+    NTSTATUS status;
+    BOOL ret = FALSE;
+
+    TRACE( "(%p, %p, %p, %p, %08lx)\n", store, pfx, password, reserved, flags );
+
+    if (!store || !pfx)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+
+    /* Find the first certificate in the store (may be NULL for empty stores). */
+    cert = CertEnumCertificatesInStore( store, NULL );
+
+    /* Get the private key if EXPORT_PRIVATE_KEYS is requested. */
+    if (cert && (flags & EXPORT_PRIVATE_KEYS))
+    {
+        key_ctx_size = sizeof(key_ctx);
+        if (!CertGetCertificateContextProperty( cert, CERT_KEY_CONTEXT_PROP_ID, &key_ctx, &key_ctx_size ))
+        {
+            WARN( "no key context on certificate, error %08lx\n", GetLastError() );
+            if (flags & REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)
+            {
+                SetLastError( NTE_NOT_FOUND );
+                CertFreeCertificateContext( cert );
+                return FALSE;
+            }
+        }
+        else if (key_ctx.dwKeySpec == CERT_NCRYPT_KEY_SPEC)
+        {
+            /* Query key blob size first. */
+            sec_status = NCryptExportKey( key_ctx.hCryptProv, 0, BCRYPT_RSAFULLPRIVATE_BLOB, NULL,
+                                          NULL, 0, &key_blob_size, 0 );
+            if (sec_status)
+            {
+                WARN( "NCryptExportKey size query failed %08lx\n", sec_status );
+                SetLastError( sec_status );
+                CertFreeCertificateContext( cert );
+                return FALSE;
+            }
+
+            key_blob = CryptMemAlloc( key_blob_size );
+            if (!key_blob)
+            {
+                SetLastError( ERROR_OUTOFMEMORY );
+                CertFreeCertificateContext( cert );
+                return FALSE;
+            }
+
+            sec_status = NCryptExportKey( key_ctx.hCryptProv, 0, BCRYPT_RSAFULLPRIVATE_BLOB, NULL,
+                                          key_blob, key_blob_size, &key_blob_size, 0 );
+            if (sec_status)
+            {
+                WARN( "NCryptExportKey failed %08lx\n", sec_status );
+                SetLastError( sec_status );
+                CryptMemFree( key_blob );
+                CertFreeCertificateContext( cert );
+                return FALSE;
+            }
+        }
+        else if (key_ctx.dwKeySpec == AT_KEYEXCHANGE || key_ctx.dwKeySpec == AT_SIGNATURE)
+        {
+            key_blob = export_capi_key( key_ctx.hCryptProv, key_ctx.dwKeySpec, &key_blob_size );
+            if (!key_blob)
+            {
+                WARN( "failed to export CAPI key\n" );
+                if (flags & REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)
+                {
+                    SetLastError( NTE_NOT_FOUND );
+                    CertFreeCertificateContext( cert );
+                    return FALSE;
+                }
+            }
+        }
+        else
+        {
+            FIXME( "dwKeySpec %lu not supported\n", key_ctx.dwKeySpec );
+            if (flags & REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)
+            {
+                SetLastError( NTE_NOT_FOUND );
+                CertFreeCertificateContext( cert );
+                return FALSE;
+            }
+        }
+    }
+
+    params.cert_data     = cert ? cert->pbCertEncoded : NULL;
+    params.cert_size     = cert ? cert->cbCertEncoded : 0;
+    params.key_blob      = key_blob;
+    params.key_blob_size = key_blob ? key_blob_size : 0;
+    params.password      = password;
+    params.pfx_data      = pfx->pbData;
+    params.pfx_size      = &pfx->cbData;
+    status = CRYPT32_CALL( export_cert_store, &params );
+    if (status == STATUS_BUFFER_TOO_SMALL) status = STATUS_SUCCESS;
+    else if (status) WARN( "unix export_cert_store failed %08lx\n", status );
+    else ret = TRUE;
+
+    CryptMemFree( key_blob );
+    CertFreeCertificateContext( cert );
+    SetLastError( RtlNtStatusToDosError( status ) );
+    return ret;
 }
diff --git a/dlls/crypt32/store.c b/dlls/crypt32/store.c
index 54b16ab8fa1b..ac17a3d4768d 100644
--- a/dlls/crypt32/store.c
+++ b/dlls/crypt32/store.c
@@ -948,7 +948,7 @@ HCERTSTORE WINAPI CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv,
         return 0;
     }
     return CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, hProv,
-     CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
+     CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_NO_CRYPT_RELEASE_FLAG, szSubSystemProtocol);
 }
 
 HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
@@ -960,7 +960,7 @@ HCERTSTORE WINAPI CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv,
         return 0;
     }
     return CertOpenStore(CERT_STORE_PROV_SYSTEM_W, 0, hProv,
-     CERT_SYSTEM_STORE_CURRENT_USER, szSubSystemProtocol);
+     CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_NO_CRYPT_RELEASE_FLAG, szSubSystemProtocol);
 }
 
 PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(HCERTSTORE hCertStore, PCCERT_CONTEXT pPrev)
diff --git a/dlls/crypt32/tests/cert.c b/dlls/crypt32/tests/cert.c
index aeab4c02713b..f8d1c37b63c4 100644
--- a/dlls/crypt32/tests/cert.c
+++ b/dlls/crypt32/tests/cert.c
@@ -529,6 +529,95 @@ static void testCertProperties(void)
      GetLastError());
     ok(keyContext.hCryptProv == 0, "Expected no hCryptProv\n");
 
+    /* Remove the key context so we start fresh for NCrypt tests */
+    ret = CertSetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID,
+     0, NULL);
+    ok(ret, "CertSetCertificateContextProperty failed: %08lx\n", GetLastError());
+
+    /* Test CERT_NCRYPT_KEY_HANDLE_PROP_ID (78) */
+    /* Getting it when no key context is set should fail */
+    size = sizeof(HCRYPTPROV);
+    SetLastError(0xdeadbeef);
+    ret = CertGetCertificateContextProperty(context,
+     CERT_NCRYPT_KEY_HANDLE_PROP_ID, NULL, &size);
+    ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
+     "Expected CRYPT_E_NOT_FOUND, got %08lx\n", GetLastError());
+
+    /* Set an NCrypt key handle via property 78 */
+    {
+        HCRYPTPROV_OR_NCRYPT_KEY_HANDLE ncryptHandle = 0xBEEF1234;
+        HCRYPTPROV_OR_NCRYPT_KEY_HANDLE retrievedHandle = 0;
+
+        ret = CertSetCertificateContextProperty(context,
+         CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, &ncryptHandle);
+        ok(ret, "CertSetCertificateContextProperty failed: %08lx\n", GetLastError());
+
+        /* Verify the key context was set with CERT_NCRYPT_KEY_SPEC */
+        size = sizeof(keyContext);
+        keyContext.hCryptProv = keyContext.dwKeySpec = 0;
+        ret = CertGetCertificateContextProperty(context,
+         CERT_KEY_CONTEXT_PROP_ID, &keyContext, &size);
+        ok(ret, "CertGetCertificateContextProperty failed: %08lx\n", GetLastError());
+        ok(keyContext.hCryptProv != 0,
+         "Expected non-zero hCryptProv, got 0\n");
+        ok(keyContext.dwKeySpec == CERT_NCRYPT_KEY_SPEC,
+         "Expected dwKeySpec CERT_NCRYPT_KEY_SPEC, got %lx\n", keyContext.dwKeySpec);
+
+        /* Get the NCrypt handle back via property 78 */
+        size = sizeof(retrievedHandle);
+        ret = CertGetCertificateContextProperty(context,
+         CERT_NCRYPT_KEY_HANDLE_PROP_ID, &retrievedHandle, &size);
+        ok(ret, "CertGetCertificateContextProperty failed: %08lx\n", GetLastError());
+        ok(retrievedHandle == keyContext.hCryptProv,
+         "Expected handle %Ix, got %Ix\n", keyContext.hCryptProv, retrievedHandle);
+        ok(size == sizeof(retrievedHandle),
+         "Expected size %Iu, got %lu\n", sizeof(retrievedHandle), size);
+
+        /* Getting CERT_KEY_PROV_HANDLE_PROP_ID should fail since this is an NCrypt key */
+        size = sizeof(retrievedHandle);
+        SetLastError(0xdeadbeef);
+        ret = CertGetCertificateContextProperty(context,
+         CERT_KEY_PROV_HANDLE_PROP_ID, &retrievedHandle, &size);
+        ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
+         "Expected CRYPT_E_NOT_FOUND for CAPI handle on NCrypt key, got %08lx\n",
+         GetLastError());
+
+        /* Delete the NCrypt key handle by setting property 78 to NULL */
+        ret = CertSetCertificateContextProperty(context,
+         CERT_NCRYPT_KEY_HANDLE_PROP_ID, 0, NULL);
+        ok(ret, "CertSetCertificateContextProperty failed: %08lx\n", GetLastError());
+
+        /* Verify it was deleted */
+        size = sizeof(retrievedHandle);
+        SetLastError(0xdeadbeef);
+        ret = CertGetCertificateContextProperty(context,
+         CERT_NCRYPT_KEY_HANDLE_PROP_ID, &retrievedHandle, &size);
+        ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
+         "Expected CRYPT_E_NOT_FOUND after delete, got %08lx\n", GetLastError());
+    }
+
+    /* Test that CERT_NCRYPT_KEY_HANDLE_PROP_ID fails for non-NCrypt key contexts */
+    keyContext.cbSize = sizeof(keyContext);
+    keyContext.hCryptProv = 0xCAFE;
+    keyContext.dwKeySpec = AT_KEYEXCHANGE;
+    ret = CertSetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID,
+     0, &keyContext);
+    ok(ret, "CertSetCertificateContextProperty failed: %08lx\n", GetLastError());
+    {
+        HCRYPTPROV_OR_NCRYPT_KEY_HANDLE retrievedHandle = 0xdeadbeef;
+
+        size = sizeof(retrievedHandle);
+        SetLastError(0xdeadbeef);
+        ret = CertGetCertificateContextProperty(context,
+         CERT_NCRYPT_KEY_HANDLE_PROP_ID, &retrievedHandle, &size);
+        ok(!ret && GetLastError() == CRYPT_E_NOT_FOUND,
+         "Expected CRYPT_E_NOT_FOUND for CAPI key, got %08lx\n", GetLastError());
+    }
+    /* Clean up */
+    ret = CertSetCertificateContextProperty(context, CERT_KEY_CONTEXT_PROP_ID,
+     0, NULL);
+    ok(ret, "CertSetCertificateContextProperty failed: %08lx\n", GetLastError());
+
     /* According to MSDN the subject key id can be stored as a property,
      * as a subject key extension, or as the SHA1 hash of the public key,
      * but this cert has none of them:
diff --git a/dlls/crypt32/tests/store.c b/dlls/crypt32/tests/store.c
index 678d4810d8ba..10b861675ca8 100644
--- a/dlls/crypt32/tests/store.c
+++ b/dlls/crypt32/tests/store.c
@@ -2064,6 +2064,9 @@ static void testSerializedStore(void)
 static void testCertOpenSystemStore(void)
 {
     HCERTSTORE store;
+    HCRYPTPROV prov;
+    BOOL ret;
+    DWORD size, pp_type;
 
     store = CertOpenSystemStoreW(0, NULL);
     ok(!store && GetLastError() == E_INVALIDARG,
@@ -2079,6 +2082,22 @@ static void testCertOpenSystemStore(void)
     CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0,
      CERT_SYSTEM_STORE_CURRENT_USER | CERT_STORE_DELETE_FLAG, L"Bogus");
     RegDeleteKeyW(HKEY_CURRENT_USER, L"Software\\Microsoft\\SystemCertificates\\Bogus");
+
+    ret = CryptAcquireContextA(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+    ok(ret, "CryptAcquireContext failed: %08lx\n", GetLastError());
+
+    store = CertOpenSystemStoreW(prov, L"My");
+    ok(store != 0, "CertOpenSystemStore failed: %08lx\n", GetLastError());
+
+    size = sizeof(pp_type);
+    pp_type = 0xdeadbeef;
+    ret = CryptGetProvParam(prov, PP_PROVTYPE, (BYTE *)&pp_type, &size, 0);
+    ok(ret, "CryptGetProvParam failed: %08lx\n", GetLastError());
+    ok(pp_type == PROV_RSA_FULL, "got %lu\n", pp_type);
+
+    CertCloseStore(store, 0);
+    ret = CryptReleaseContext(prov, 0);
+    ok(ret, "CryptReleaseContext: %08lx\n", GetLastError());
 }
 
 static const struct
@@ -3522,6 +3541,170 @@ static void test_PFXImportCertStore(void)
     CertCloseStore( store, 0 );
 }
 
+static void test_PFXExportCertStoreEx(void)
+{
+    HCERTSTORE store, store2;
+    CRYPT_DATA_BLOB pfx, exported;
+    const CERT_CONTEXT *cert, *cert2;
+    DWORD count, size;
+    BOOL ret;
+
+    /* Test NULL parameters. */
+    SetLastError( 0xdeadbeef );
+    ret = PFXExportCertStoreEx( NULL, NULL, NULL, NULL, 0 );
+    ok( !ret, "expected failure\n" );
+    ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %lx\n", GetLastError() );
+
+    exported.pbData = NULL;
+    exported.cbData = 0;
+
+    SetLastError( 0xdeadbeef );
+    ret = PFXExportCertStoreEx( NULL, &exported, NULL, NULL, 0 );
+    ok( !ret, "expected failure\n" );
+    ok( GetLastError() == ERROR_INVALID_PARAMETER, "got %lx\n", GetLastError() );
+
+    /* Empty store succeeds (produces a valid but empty PFX). */
+    store = CertOpenStore( CERT_STORE_PROV_MEMORY, 0, 0, 0, NULL );
+    ok( store != NULL, "CertOpenStore failed %lx\n", GetLastError() );
+
+    exported.pbData = NULL;
+    exported.cbData = 0;
+    ret = PFXExportCertStoreEx( store, &exported, NULL, NULL, 0 );
+    ok( ret, "PFXExportCertStoreEx empty store size query failed %lx\n", GetLastError() );
+    ok( exported.cbData > 0, "expected nonzero size\n" );
+    CertCloseStore( store, 0 );
+
+    /* Import pfxdata (cert + private key), then export without private key. */
+    pfx.pbData = (BYTE *)pfxdata;
+    pfx.cbData = sizeof(pfxdata);
+    store = PFXImportCertStore( &pfx, NULL, CRYPT_EXPORTABLE | CRYPT_USER_KEYSET | PKCS12_NO_PERSIST_KEY );
+    ok( store != NULL, "PFXImportCertStore failed %lx\n", GetLastError() );
+
+    /* Size query. */
+    exported.pbData = NULL;
+    exported.cbData = 0;
+    ret = PFXExportCertStoreEx( store, &exported, L"test", NULL, 0 );
+    ok( ret, "PFXExportCertStoreEx size query failed %lx\n", GetLastError() );
+    ok( exported.cbData > 0, "expected nonzero size\n" );
+
+    /* Buffer too small. */
+    exported.pbData = HeapAlloc( GetProcessHeap(), 0, exported.cbData );
+    ok( exported.pbData != NULL, "HeapAlloc failed\n" );
+    size = exported.cbData;
+    exported.cbData = 1;
+    SetLastError( 0xdeadbeef );
+    ret = PFXExportCertStoreEx( store, &exported, L"test", NULL, 0 );
+    ok( !ret, "PFXExportCertStoreEx failed %lx\n", GetLastError() );
+    ok( GetLastError() == ERROR_SUCCESS, "got %lx\n", GetLastError() );
+    exported.cbData = size;
+
+    /* Actual export. */
+    exported.pbData = HeapAlloc( GetProcessHeap(), 0, exported.cbData );
+    ok( exported.pbData != NULL, "HeapAlloc failed\n" );
+    ret = PFXExportCertStoreEx( store, &exported, L"test", NULL, 0 );
+    ok( ret, "PFXExportCertStoreEx failed %lx\n", GetLastError() );
+
+    /* Verify exported blob is valid PFX. */
+    ret = PFXIsPFXBlob( &exported );
+    ok( ret, "exported blob is not valid PFX\n" );
+
+    /* Re-import and verify certificate round-trip. */
+    store2 = PFXImportCertStore( &exported, L"test", PKCS12_NO_PERSIST_KEY );
+    ok( store2 != NULL, "PFXImportCertStore of exported data failed %lx\n", GetLastError() );
+    if (store2)
+    {
+        count = countCertsInStore( store2 );
+        ok( count == 1, "expected 1 cert, got %lu\n", count );
+
+        cert = CertFindCertificateInStore( store, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL );
+        cert2 = CertFindCertificateInStore( store2, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL );
+        ok( cert != NULL && cert2 != NULL, "failed to find certs\n" );
+        if (cert && cert2)
+        {
+            ok( cert->cbCertEncoded == cert2->cbCertEncoded,
+                "cert size mismatch: %lu vs %lu\n", cert->cbCertEncoded, cert2->cbCertEncoded );
+            ok( !memcmp( cert->pbCertEncoded, cert2->pbCertEncoded, cert->cbCertEncoded ),
+                "cert data mismatch\n" );
+        }
+        if (cert) CertFreeCertificateContext( cert );
+        if (cert2) CertFreeCertificateContext( cert2 );
+        CertCloseStore( store2, 0 );
+    }
+    HeapFree( GetProcessHeap(), 0, exported.pbData );
+
+    /* Export with EXPORT_PRIVATE_KEYS. */
+    exported.pbData = NULL;
+    exported.cbData = 0;
+    ret = PFXExportCertStoreEx( store, &exported, L"test", NULL, EXPORT_PRIVATE_KEYS );
+    ok( ret, "PFXExportCertStoreEx size query failed %lx\n", GetLastError() );
+    ok( exported.cbData > 0, "expected nonzero size\n" );
+
+    exported.pbData = HeapAlloc( GetProcessHeap(), 0, exported.cbData );
+    ok( exported.pbData != NULL, "HeapAlloc failed\n" );
+    ret = PFXExportCertStoreEx( store, &exported, L"test", NULL, EXPORT_PRIVATE_KEYS );
+    ok( ret, "PFXExportCertStoreEx with EXPORT_PRIVATE_KEYS failed %lx\n", GetLastError() );
+
+    ret = PFXIsPFXBlob( &exported );
+    ok( ret, "exported blob with private key is not valid PFX\n" );
+
+    /* Re-import with private key and verify it's present. */
+    store2 = PFXImportCertStore( &exported, L"test", PKCS12_NO_PERSIST_KEY );
+    ok( store2 != NULL, "PFXImportCertStore failed %lx\n", GetLastError() );
+    if (store2)
+    {
+        CERT_KEY_CONTEXT key;
+        DWORD size;
+
+        cert2 = CertFindCertificateInStore( store2, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, NULL );
+        ok( cert2 != NULL, "no cert in re-imported store %lx\n", GetLastError() );
+        if (cert2)
+        {
+            size = sizeof(key);
+            ret = CertGetCertificateContextProperty( cert2, CERT_KEY_CONTEXT_PROP_ID, &key, &size );
+            ok( ret, "no key context on re-imported cert %lx\n", GetLastError() );
+            if (ret)
+            {
+                ok( key.hCryptProv != 0, "expected non-zero hCryptProv\n" );
+            }
+            CertFreeCertificateContext( cert2 );
+        }
+        CertCloseStore( store2, 0 );
+    }
+    HeapFree( GetProcessHeap(), 0, exported.pbData );
+
+    /* Test cert-only export (import pfx_cert_only which has no private key). */
+    CertCloseStore( store, 0 );
+    pfx.pbData = (BYTE *)pfx_cert_only;
+    pfx.cbData = sizeof(pfx_cert_only);
+    store = PFXImportCertStore( &pfx, L"", 0 );
+    ok( store != NULL, "PFXImportCertStore failed %lx\n", GetLastError() );
+
+    exported.pbData = NULL;
+    exported.cbData = 0;
+    ret = PFXExportCertStoreEx( store, &exported, L"", NULL, 0 );
+    ok( ret, "PFXExportCertStoreEx cert-only size query failed %lx\n", GetLastError() );
+    ok( exported.cbData > 0, "expected nonzero size\n" );
+
+    exported.pbData = HeapAlloc( GetProcessHeap(), 0, exported.cbData );
+    ret = PFXExportCertStoreEx( store, &exported, L"", NULL, 0 );
+    ok( ret, "PFXExportCertStoreEx cert-only failed %lx\n", GetLastError() );
+
+    ret = PFXIsPFXBlob( &exported );
+    ok( ret, "cert-only exported blob is not valid PFX\n" );
+
+    store2 = PFXImportCertStore( &exported, L"", 0 );
+    ok( store2 != NULL, "PFXImportCertStore of cert-only export failed %lx\n", GetLastError() );
+    if (store2)
+    {
+        count = countCertsInStore( store2 );
+        ok( count == 1, "expected 1 cert, got %lu\n", count );
+        CertCloseStore( store2, 0 );
+    }
+    HeapFree( GetProcessHeap(), 0, exported.pbData );
+
+    CertCloseStore( store, 0 );
+}
+
 static void test_CryptQueryObject(void)
 {
     CRYPT_DATA_BLOB pfx;
@@ -3586,5 +3769,6 @@ START_TEST(store)
 
     test_I_UpdateStore();
     test_PFXImportCertStore();
+    test_PFXExportCertStoreEx();
     test_CryptQueryObject();
 }
diff --git a/dlls/crypt32/unixlib.c b/dlls/crypt32/unixlib.c
index 5cfc54bf0262..8a3755f4bde0 100644
--- a/dlls/crypt32/unixlib.c
+++ b/dlls/crypt32/unixlib.c
@@ -41,6 +41,7 @@
 #include "winbase.h"
 #include "winternl.h"
 #include "wincrypt.h"
+#include "bcrypt.h"
 #include "crypt32_private.h"
 #include "wine/debug.h"
 
@@ -65,10 +66,15 @@ MAKE_FUNCPTR(gnutls_pkcs12_bag_get_count);
 MAKE_FUNCPTR(gnutls_pkcs12_bag_get_data);
 MAKE_FUNCPTR(gnutls_pkcs12_bag_get_type);
 MAKE_FUNCPTR(gnutls_pkcs12_bag_init);
+MAKE_FUNCPTR(gnutls_pkcs12_bag_set_crt);
+MAKE_FUNCPTR(gnutls_pkcs12_bag_set_privkey);
 MAKE_FUNCPTR(gnutls_pkcs12_deinit);
+MAKE_FUNCPTR(gnutls_pkcs12_export2);
+MAKE_FUNCPTR(gnutls_pkcs12_generate_mac2);
 MAKE_FUNCPTR(gnutls_pkcs12_get_bag);
 MAKE_FUNCPTR(gnutls_pkcs12_import);
 MAKE_FUNCPTR(gnutls_pkcs12_init);
+MAKE_FUNCPTR(gnutls_pkcs12_set_bag);
 MAKE_FUNCPTR(gnutls_pkcs12_verify_mac);
 MAKE_FUNCPTR(gnutls_x509_crt_deinit);
 MAKE_FUNCPTR(gnutls_x509_crt_export);
@@ -78,6 +84,7 @@ MAKE_FUNCPTR(gnutls_x509_privkey_deinit);
 MAKE_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2);
 MAKE_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2);
 MAKE_FUNCPTR(gnutls_x509_privkey_import_pkcs8);
+MAKE_FUNCPTR(gnutls_x509_privkey_import_rsa_raw);
 MAKE_FUNCPTR(gnutls_x509_privkey_init);
 #undef MAKE_FUNCPTR
 
@@ -125,10 +132,15 @@ static NTSTATUS process_attach( void *args )
     LOAD_FUNCPTR(gnutls_pkcs12_bag_get_data)
     LOAD_FUNCPTR(gnutls_pkcs12_bag_get_type)
     LOAD_FUNCPTR(gnutls_pkcs12_bag_init)
+    LOAD_FUNCPTR(gnutls_pkcs12_bag_set_crt)
+    LOAD_FUNCPTR(gnutls_pkcs12_bag_set_privkey)
     LOAD_FUNCPTR(gnutls_pkcs12_deinit)
+    LOAD_FUNCPTR(gnutls_pkcs12_export2)
+    LOAD_FUNCPTR(gnutls_pkcs12_generate_mac2)
     LOAD_FUNCPTR(gnutls_pkcs12_get_bag)
     LOAD_FUNCPTR(gnutls_pkcs12_import)
     LOAD_FUNCPTR(gnutls_pkcs12_init)
+    LOAD_FUNCPTR(gnutls_pkcs12_set_bag)
     LOAD_FUNCPTR(gnutls_pkcs12_verify_mac)
     LOAD_FUNCPTR(gnutls_x509_crt_deinit)
     LOAD_FUNCPTR(gnutls_x509_crt_export)
@@ -138,6 +150,7 @@ static NTSTATUS process_attach( void *args )
     LOAD_FUNCPTR(gnutls_x509_privkey_export_rsa_raw2)
     LOAD_FUNCPTR(gnutls_x509_privkey_get_pk_algorithm2)
     LOAD_FUNCPTR(gnutls_x509_privkey_import_pkcs8)
+    LOAD_FUNCPTR(gnutls_x509_privkey_import_rsa_raw)
     LOAD_FUNCPTR(gnutls_x509_privkey_init)
 #undef LOAD_FUNCPTR
 
@@ -521,6 +534,127 @@ static NTSTATUS close_cert_store( void *args )
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS export_cert_store( void *args )
+{
+    struct export_cert_store_params *params = args;
+    gnutls_pkcs12_t p12 = NULL;
+    gnutls_pkcs12_bag_t cert_bag = NULL, key_bag = NULL;
+    gnutls_x509_crt_t crt = NULL;
+    gnutls_x509_privkey_t key = NULL;
+    gnutls_datum_t out = { NULL, 0 };
+    char *pwd = NULL;
+    int ret;
+    NTSTATUS status = STATUS_INVALID_PARAMETER;
+
+    if (!libgnutls_handle) return STATUS_DLL_NOT_FOUND;
+
+    if (params->password && !(pwd = password_to_ascii( params->password )))
+        return STATUS_NO_MEMORY;
+
+    /* Create cert bag (always initialized, even for empty stores). */
+    if ((ret = pgnutls_pkcs12_bag_init( &cert_bag )) < 0) goto error;
+
+    /* Import the certificate if provided. */
+    if (params->cert_data && params->cert_size)
+    {
+        if ((ret = pgnutls_x509_crt_init( &crt )) < 0) goto error;
+        {
+            gnutls_datum_t cert_datum = { (unsigned char *)params->cert_data, params->cert_size };
+            if ((ret = pgnutls_x509_crt_import( crt, &cert_datum, GNUTLS_X509_FMT_DER )) < 0) goto error;
+        }
+        if ((ret = pgnutls_pkcs12_bag_set_crt( cert_bag, crt )) < 0) goto error;
+    }
+
+    /* Import private key from BCRYPT_RSAKEY_BLOB if provided. */
+    if (params->key_blob && params->key_blob_size)
+    {
+        const BCRYPT_RSAKEY_BLOB *hdr = (const BCRYPT_RSAKEY_BLOB *)params->key_blob;
+        const BYTE *ptr = params->key_blob + sizeof(*hdr);
+        gnutls_datum_t m, e, d, p, q, u;
+
+        if (hdr->Magic != BCRYPT_RSAFULLPRIVATE_MAGIC)
+        {
+            WARN( "unexpected key blob magic %08lx\n", (unsigned long)hdr->Magic );
+            status = STATUS_INVALID_PARAMETER;
+            goto done;
+        }
+
+        /* Layout after header: PublicExp, Modulus, Prime1, Prime2, Exponent1, Exponent2, Coefficient, PrivateExponent */
+        e.data = (unsigned char *)ptr;                    e.size = hdr->cbPublicExp;
+        ptr += hdr->cbPublicExp;
+        m.data = (unsigned char *)ptr;                    m.size = hdr->cbModulus;
+        ptr += hdr->cbModulus;
+        p.data = (unsigned char *)ptr;                    p.size = hdr->cbPrime1;
+        ptr += hdr->cbPrime1;
+        q.data = (unsigned char *)ptr;                    q.size = hdr->cbPrime2;
+        ptr += hdr->cbPrime2;
+        /* Skip Exponent1 and Exponent2 - GnuTLS computes them. */
+        ptr += hdr->cbPrime1;  /* Exponent1 */
+        ptr += hdr->cbPrime2;  /* Exponent2 */
+        u.data = (unsigned char *)ptr;                    u.size = hdr->cbPrime1;
+        ptr += hdr->cbPrime1;
+        d.data = (unsigned char *)ptr;                    d.size = hdr->cbModulus;
+
+        if ((ret = pgnutls_x509_privkey_init( &key )) < 0) goto error;
+        if ((ret = pgnutls_x509_privkey_import_rsa_raw( key, &m, &e, &d, &p, &q, &u )) < 0)
+        {
+            pgnutls_x509_privkey_deinit( key );
+            key = NULL;
+            goto error;
+        }
+
+        /* Create key bag. */
+        if ((ret = pgnutls_pkcs12_bag_init( &key_bag )) < 0) goto error;
+        if ((ret = pgnutls_pkcs12_bag_set_privkey( key_bag, key, pwd ? pwd : "", 0 )) < 0) goto error;
+    }
+
+    /* Build PKCS#12. */
+    if ((ret = pgnutls_pkcs12_init( &p12 )) < 0) goto error;
+    if ((ret = pgnutls_pkcs12_set_bag( p12, cert_bag )) < 0) goto error;
+    if (key_bag)
+    {
+        if ((ret = pgnutls_pkcs12_set_bag( p12, key_bag )) < 0) goto error;
+    }
+
+    /* Generate MAC. */
+    if ((ret = pgnutls_pkcs12_generate_mac2( p12, GNUTLS_MAC_SHA256, pwd ? pwd : "" )) < 0) goto error;
+
+    /* Export. */
+    if ((ret = pgnutls_pkcs12_export2( p12, GNUTLS_X509_FMT_DER, &out )) < 0) goto error;
+
+    if (!params->pfx_data)
+    {
+        /* Size query. */
+        *params->pfx_size = out.size + 8;
+        status = STATUS_SUCCESS;
+    }
+    else if (*params->pfx_size < out.size)
+    {
+        *params->pfx_size = out.size + 8;
+        status = STATUS_BUFFER_TOO_SMALL;
+    }
+    else
+    {
+        memcpy( params->pfx_data, out.data, out.size );
+        *params->pfx_size = out.size;
+        status = STATUS_SUCCESS;
+    }
+    goto done;
+
+error:
+    pgnutls_perror( ret );
+    status = STATUS_INVALID_PARAMETER;
+done:
+    free( out.data );
+    if (p12) pgnutls_pkcs12_deinit( p12 );
+    if (key_bag) pgnutls_pkcs12_bag_deinit( key_bag );
+    if (cert_bag) pgnutls_pkcs12_bag_deinit( cert_bag );
+    if (key) pgnutls_x509_privkey_deinit( key );
+    if (crt) pgnutls_x509_crt_deinit( crt );
+    free( pwd );
+    return status;
+}
+
 #else /* SONAME_LIBGNUTLS */
 
 static NTSTATUS process_attach( void *args ) { return STATUS_SUCCESS; }
@@ -529,6 +663,7 @@ static NTSTATUS open_cert_store( void *args ) { return STATUS_DLL_NOT_FOUND; }
 static NTSTATUS import_store_key( void *args ) { return STATUS_DLL_NOT_FOUND; }
 static NTSTATUS import_store_cert( void *args ) { return STATUS_DLL_NOT_FOUND; }
 static NTSTATUS close_cert_store( void *args ) { return STATUS_DLL_NOT_FOUND; }
+static NTSTATUS export_cert_store( void *args ) { return STATUS_DLL_NOT_FOUND; }
 
 #endif /* SONAME_LIBGNUTLS */
 
@@ -860,6 +995,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     import_store_cert,
     close_cert_store,
     enum_root_certs,
+    export_cert_store,
 };
 
 C_ASSERT( ARRAYSIZE(__wine_unix_call_funcs) == unix_funcs_count );
@@ -956,6 +1092,33 @@ static NTSTATUS wow64_enum_root_certs( void *args )
     return enum_root_certs( &params );
 }
 
+static NTSTATUS wow64_export_cert_store( void *args )
+{
+    struct
+    {
+        PTR32 cert_data;
+        DWORD cert_size;
+        PTR32 key_blob;
+        DWORD key_blob_size;
+        PTR32 password;
+        PTR32 pfx_data;
+        PTR32 pfx_size;
+    } const *params32 = args;
+
+    struct export_cert_store_params params =
+    {
+        ULongToPtr( params32->cert_data ),
+        params32->cert_size,
+        ULongToPtr( params32->key_blob ),
+        params32->key_blob_size,
+        ULongToPtr( params32->password ),
+        ULongToPtr( params32->pfx_data ),
+        ULongToPtr( params32->pfx_size )
+    };
+
+    return export_cert_store( &params );
+}
+
 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
 {
     process_attach,
@@ -965,6 +1128,7 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
     wow64_import_store_cert,
     close_cert_store,
     wow64_enum_root_certs,
+    wow64_export_cert_store,
 };
 
 C_ASSERT( ARRAYSIZE(__wine_unix_call_wow64_funcs) == unix_funcs_count );
diff --git a/dlls/d2d1/effect.c b/dlls/d2d1/effect.c
index b66fe7315239..286fae95e9c4 100644
--- a/dlls/d2d1/effect.c
+++ b/dlls/d2d1/effect.c
@@ -2807,7 +2807,8 @@ static void STDMETHODCALLTYPE d2d_effect_SetInput(ID2D1Effect *iface, UINT32 ind
     if (index >= effect->input_count)
         return;
 
-    ID2D1Image_AddRef(input);
+    if (input)
+        ID2D1Image_AddRef(input);
     if (effect->inputs[index])
         ID2D1Image_Release(effect->inputs[index]);
     effect->inputs[index] = input;
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c
index 8ed81c5d8dca..68de4c2193c5 100644
--- a/dlls/d2d1/geometry.c
+++ b/dlls/d2d1/geometry.c
@@ -6291,7 +6291,8 @@ static void d2d_transformed_geometry_stream(struct d2d_geometry *geometry,
 {
     D2D_MATRIX_3X2_F m = geometry->transform;
 
-    d2d_matrix_multiply(&m, transform);
+    if (transform)
+        d2d_matrix_multiply(&m, transform);
     d2d_geometry_stream(geometry->u.transformed.src_geometry, &m, sink);
 }
 
diff --git a/dlls/d2d1/tests/d2d1.c b/dlls/d2d1/tests/d2d1.c
index 2d64e8440f4e..c01c6eefde43 100644
--- a/dlls/d2d1/tests/d2d1.c
+++ b/dlls/d2d1/tests/d2d1.c
@@ -11559,6 +11559,7 @@ static void test_colour_space(BOOL d3d11)
 
 static void test_geometry_group(BOOL d3d11)
 {
+    ID2D1TransformedGeometry *transformed_geometry;
     struct d2d1_test_context ctx;
     ID2D1Geometry *geometries[2];
     ID2D1GeometryGroup *group;
@@ -11646,8 +11647,23 @@ static void test_geometry_group(BOOL d3d11)
             rect.left, rect.top, rect.right, rect.bottom);
 
     ID2D1GeometryGroup_Release(group);
-    ID2D1PathGeometry_Release(path);
 
+    /* Group using transformed geometry */
+    set_matrix_identity(&matrix);
+    scale_matrix(&matrix, 2.0f, 4.0f);
+    hr = ID2D1Factory_CreateTransformedGeometry(ctx.factory, (ID2D1Geometry *)path, &matrix,
+            &transformed_geometry);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    hr = ID2D1Factory_CreateGeometryGroup(ctx.factory, D2D1_FILL_MODE_ALTERNATE,
+            (ID2D1Geometry **)&transformed_geometry, 1, &group);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    ID2D1GeometryGroup_Release(group);
+
+    ID2D1TransformedGeometry_Release(transformed_geometry);
+
+    ID2D1PathGeometry_Release(path);
     release_test_context(&ctx);
 }
 
@@ -12065,6 +12081,13 @@ static void test_builtin_effect(BOOL d3d11)
             ok(image_a == NULL, "Got unexpected image_a %p.\n", image_a);
             winetest_pop_context();
         }
+
+        /* Test setting NULL bitmap */
+        image_a = (ID2D1Image *)0xdeadbeef;
+        ID2D1Effect_SetInput(effect, 0, (ID2D1Image *)NULL, FALSE);
+        ID2D1Effect_GetInput(effect, 0, &image_a);
+        ok(image_a == NULL, "Got unexpected image_a %p.\n", image_a);
+
         ID2D1Bitmap_Release(bitmap);
 
         ID2D1Effect_Release(effect);
diff --git a/dlls/d3d11/device.c b/dlls/d3d11/device.c
index c4e7c55cde37..e1a846698e67 100644
--- a/dlls/d3d11/device.c
+++ b/dlls/d3d11/device.c
@@ -1521,7 +1521,7 @@ static void STDMETHODCALLTYPE d3d11_device_context_ResolveSubresource(ID3D11Devi
     wined3d_format = wined3dformat_from_dxgi_format(format);
     wined3d_device_context_resolve_sub_resource(context->wined3d_context,
             wined3d_dst_resource, dst_subresource_idx,
-            wined3d_src_resource, src_subresource_idx, wined3d_format);
+            wined3d_src_resource, src_subresource_idx, WINED3D_BLT_RAW, wined3d_format);
 }
 
 static void STDMETHODCALLTYPE d3d11_device_context_ExecuteCommandList(ID3D11DeviceContext4 *iface,
@@ -6233,7 +6233,7 @@ static void STDMETHODCALLTYPE d3d10_device_ResolveSubresource(ID3D10Device1 *ifa
     wined3d_format = wined3dformat_from_dxgi_format(format);
     wined3d_device_context_resolve_sub_resource(device->immediate_context.wined3d_context,
             wined3d_dst_resource, dst_subresource_idx,
-            wined3d_src_resource, src_subresource_idx, wined3d_format);
+            wined3d_src_resource, src_subresource_idx, WINED3D_BLT_RAW, wined3d_format);
 }
 
 static void STDMETHODCALLTYPE d3d10_device_VSGetConstantBuffers(ID3D10Device1 *iface,
diff --git a/dlls/d3d8/device.c b/dlls/d3d8/device.c
index b5bf370790af..036c60edc375 100644
--- a/dlls/d3d8/device.c
+++ b/dlls/d3d8/device.c
@@ -1985,7 +1985,7 @@ static void resolve_depth_buffer(struct d3d8_device *device)
     d3d8_dsv = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_dsv);
 
     wined3d_device_context_resolve_sub_resource(device->immediate_context, dst_resource, 0,
-            wined3d_rendertarget_view_get_resource(wined3d_dsv), d3d8_dsv->sub_resource_idx, desc.format);
+            wined3d_rendertarget_view_get_resource(wined3d_dsv), d3d8_dsv->sub_resource_idx, 0, desc.format);
 }
 
 static HRESULT WINAPI d3d8_device_SetRenderState(IDirect3DDevice8 *iface,
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c
index 5f59d10079dc..20b7255f52fd 100644
--- a/dlls/d3d9/device.c
+++ b/dlls/d3d9/device.c
@@ -2615,7 +2615,7 @@ static void resolve_depth_buffer(struct d3d9_device *device)
     d3d9_dsv = wined3d_rendertarget_view_get_sub_resource_parent(wined3d_dsv);
 
     wined3d_device_context_resolve_sub_resource(device->immediate_context, dst_resource, 0,
-            wined3d_rendertarget_view_get_resource(wined3d_dsv), d3d9_dsv->sub_resource_idx, desc.format);
+            wined3d_rendertarget_view_get_resource(wined3d_dsv), d3d9_dsv->sub_resource_idx, 0, desc.format);
 }
 
 static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_SetRenderState(IDirect3DDevice9Ex *iface,
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c
index 29f7a45637fd..e070210c6d18 100644
--- a/dlls/d3d9/tests/visual.c
+++ b/dlls/d3d9/tests/visual.c
@@ -12851,7 +12851,24 @@ static void yuv_color_test(void)
         /* A pixel is effectively 16 bit large, but two pixels are stored together, so the minimum size is 2x1.
          * However, Nvidia Windows drivers have problems with 2x1 YUY2/UYVY surfaces, so use a 4x1 surface and
          * fill the second block with dummy data. If the surface has a size of 2x1, those drivers ignore the
-         * second luminance value, resulting in an incorrect color in the right pixel. */
+         * second luminance value, resulting in an incorrect color in the right pixel.
+         *
+         * What appears to be happening at least on Nvidia is that the driver internally loads the 4x1
+         * YUV surface into a 2x1 ARGB surface - and not a 4x1 RG surface - and then makes a filtering
+         * decision based on the 2x1 vs destination size. The chroma channels from two adjacent, but
+         * supposedly independent pixels, get averaged together. So store the same chroma in the left
+         * (tested) and right (ignored) blocks.
+         *
+         * Nvidia, but also some VM drivers insist on doing linear filtering although we asked for point
+         * filtering. Be careful when reading the results and use the pixel centers. In the future we may
+         * want to add tests for the filtered pixels as well. Blitting to a 4x1 destination doesn't work
+         * properly either on Nvidia, for the 4x1->2x1 map reason outlined above. Blitting a 4x1 YUV source
+         * to a 2x1 destination applies minification filters after YUV->RGB conversion, which we don't want
+         * either.
+         *
+         * Unfortunately different implementations(Windows-Nvidia and Mac-AMD tested) interpret some colors
+         * vastly differently, so we need a max diff of 18. */
+
         hr = IDirect3DDevice9_CreateOffscreenPlainSurface(device, 4, 1, test_data[i].format,
                 D3DPOOL_DEFAULT, &surface, NULL);
         ok(SUCCEEDED(hr), "Failed to create surface, hr %#lx.\n", hr);
@@ -12860,7 +12877,16 @@ static void yuv_color_test(void)
         hr = IDirect3DSurface9_LockRect(surface, &lr, NULL, 0);
         ok(SUCCEEDED(hr), "Failed to lock surface, hr %#lx.\n", hr);
         ((DWORD *)lr.pBits)[0] = test_data[i].in;
-        ((DWORD *)lr.pBits)[1] = 0x00800080;
+        if (test_data[i].format == D3DFMT_UYVY)
+        {
+            ((DWORD *)lr.pBits)[1] = 0xff000000;
+            ((DWORD *)lr.pBits)[1] |= test_data[i].in & 0x00ff00ff;
+        }
+        else
+        {
+            ((DWORD*)lr.pBits)[1] = 0x00ff0000;
+            ((DWORD*)lr.pBits)[1] |= test_data[i].in & 0xff00ff00;
+        }
         hr = IDirect3DSurface9_UnlockRect(surface);
         ok(SUCCEEDED(hr), "Failed to unlock surface, hr %#lx.\n", hr);
 
@@ -12869,12 +12895,6 @@ static void yuv_color_test(void)
         hr = IDirect3DDevice9_StretchRect(device, surface, NULL, target, NULL, D3DTEXF_POINT);
         ok(SUCCEEDED(hr), "Failed to draw surface onto backbuffer, hr %#lx.\n", hr);
 
-        /* Some Windows drivers (mostly Nvidia, but also some VM drivers) insist on doing linear filtering
-         * although we asked for point filtering. Be careful when reading the results and use the pixel
-         * centers. In the future we may want to add tests for the filtered pixels as well.
-         *
-         * Unfortunately different implementations(Windows-Nvidia and Mac-AMD tested) interpret some colors
-         * vastly differently, so we need a max diff of 18. */
         color = getPixelColor(device, 1, 240);
         ok(color_match(color, test_data[i].left, 18),
                 "Input 0x%08x: Got color 0x%08x for pixel 1/1, expected 0x%08x, format %s.\n",
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 80b3b60c7166..2e2f7e62483f 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -2664,6 +2664,7 @@ static void test_window_style(void)
     RECT fullscreen_rect, r;
     HWND window, window2;
     IDirectDraw *ddraw;
+    unsigned int i;
     HRESULT hr;
     ULONG ref;
     BOOL ret;
@@ -2874,10 +2875,19 @@ static void test_window_style(void)
     ok(tmp & WS_VISIBLE, "Expected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
     ok(tmp & WS_EX_TOPMOST, "Expected WS_EX_TOPMOST.\n");
-    ret = ShowWindow(window, SW_HIDE);
-    ok(ret, "ShowWindow failed, error %#lx.\n", GetLastError());
-    ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
-    ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+    for (i = 0; i < 5; ++i)
+    {
+        /* Try a few times to hide the window. Something in Win11 26H1 shows it again and makes it
+         * topmost. This is in addition to the ddraw periodic check below, which only makes it
+         * topmost but not visible */
+        ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
+        ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+        tmp = GetWindowLongA(window, GWL_STYLE);
+        if (!(tmp & WS_VISIBLE))
+            break;
+        Sleep(100);
+    }
+    ok(i < 5, "Failed to hide the window.\n");
     tmp = GetWindowLongA(window, GWL_STYLE);
     ok(!(tmp & WS_VISIBLE), "Got unexpected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
@@ -14409,7 +14419,10 @@ static void test_caps(void)
         {
             .dwSize = sizeof(DDSURFACEDESC),
             .dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT,
-            .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
+            .ddsCaps =
+            {
+                .dwCaps = DDSCAPS_ZBUFFER,
+            },
             .dwZBufferBitDepth = depth_caps[i].depth,
             .dwWidth = 64,
             .dwHeight = 64,
@@ -14496,7 +14509,10 @@ static void test_caps(void)
             {
                 .dwSize = sizeof(DDSURFACEDESC),
                 .dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT,
-                .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
+                .ddsCaps =
+                {
+                    .dwCaps = DDSCAPS_ZBUFFER,
+                },
                 .dwZBufferBitDepth = depth_caps[i].depth,
                 .dwWidth = 64,
                 .dwHeight = 64,
diff --git a/dlls/ddraw/tests/ddraw2.c b/dlls/ddraw/tests/ddraw2.c
index 6377ff51052f..114b297d239a 100644
--- a/dlls/ddraw/tests/ddraw2.c
+++ b/dlls/ddraw/tests/ddraw2.c
@@ -2745,6 +2745,7 @@ static void test_window_style(void)
     RECT fullscreen_rect, r;
     HWND window, window2;
     IDirectDraw2 *ddraw;
+    unsigned int i;
     HRESULT hr;
     ULONG ref;
     BOOL ret;
@@ -2955,10 +2956,19 @@ static void test_window_style(void)
     ok(tmp & WS_VISIBLE, "Expected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
     ok(tmp & WS_EX_TOPMOST, "Expected WS_EX_TOPMOST.\n");
-    ret = ShowWindow(window, SW_HIDE);
-    ok(ret, "ShowWindow failed, error %#lx.\n", GetLastError());
-    ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
-    ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+    for (i = 0; i < 5; ++i)
+    {
+        /* Try a few times to hide the window. Something in Win11 26H1 shows it again and makes it
+         * topmost. This is in addition to the ddraw periodic check below, which only makes it
+         * topmost but not visible */
+        ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
+        ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+        tmp = GetWindowLongA(window, GWL_STYLE);
+        if (!(tmp & WS_VISIBLE))
+            break;
+        Sleep(100);
+    }
+    ok(i < 5, "Failed to hide the window.\n");
     tmp = GetWindowLongA(window, GWL_STYLE);
     ok(!(tmp & WS_VISIBLE), "Got unexpected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
@@ -15423,7 +15433,10 @@ static void test_caps(void)
         {
             .dwSize = sizeof(DDSURFACEDESC),
             .dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT,
-            .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
+            .ddsCaps =
+            {
+                .dwCaps = DDSCAPS_ZBUFFER,
+            },
             .dwZBufferBitDepth = depth_caps[i].depth,
             .dwWidth = 64,
             .dwHeight = 64,
@@ -15516,7 +15529,10 @@ static void test_caps(void)
             {
                 .dwSize = sizeof(DDSURFACEDESC),
                 .dwFlags = DDSD_CAPS | DDSD_ZBUFFERBITDEPTH | DDSD_WIDTH | DDSD_HEIGHT,
-                .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
+                .ddsCaps =
+                {
+                    .dwCaps = DDSCAPS_ZBUFFER,
+                },
                 .dwZBufferBitDepth = depth_caps[i].depth,
                 .dwWidth = 64,
                 .dwHeight = 64,
diff --git a/dlls/ddraw/tests/ddraw4.c b/dlls/ddraw/tests/ddraw4.c
index 1e9a964d86d9..285b36f54c62 100644
--- a/dlls/ddraw/tests/ddraw4.c
+++ b/dlls/ddraw/tests/ddraw4.c
@@ -2985,6 +2985,7 @@ static void test_window_style(void)
     RECT fullscreen_rect, r;
     HWND window, window2;
     IDirectDraw4 *ddraw;
+    unsigned int i;
     HRESULT hr;
     ULONG ref;
     BOOL ret;
@@ -3195,10 +3196,19 @@ static void test_window_style(void)
     ok(tmp & WS_VISIBLE, "Expected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
     ok(tmp & WS_EX_TOPMOST, "Expected WS_EX_TOPMOST.\n");
-    ret = ShowWindow(window, SW_HIDE);
-    ok(ret, "ShowWindow failed, error %#lx.\n", GetLastError());
-    ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
-    ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+    for (i = 0; i < 5; ++i)
+    {
+        /* Try a few times to hide the window. Something in Win11 26H1 shows it again and makes it
+         * topmost. This is in addition to the ddraw periodic check below, which only makes it
+         * topmost but not visible */
+        ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
+        ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+        tmp = GetWindowLongA(window, GWL_STYLE);
+        if (!(tmp & WS_VISIBLE))
+            break;
+        Sleep(100);
+    }
+    ok(i < 5, "Failed to hide the window.\n");
     tmp = GetWindowLongA(window, GWL_STYLE);
     ok(!(tmp & WS_VISIBLE), "Got unexpected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
@@ -16376,6 +16386,7 @@ static void test_map_synchronisation(void)
     IDirect3DVertexBuffer *buffer;
     IDirect3DViewport3 *viewport;
     D3DVERTEXBUFFERDESC vb_desc;
+    BOOL small_buffer = FALSE;
     IDirect3DDevice3 *device;
     BOOL unsynchronised, ret;
     IDirectDrawSurface4 *rt;
@@ -16518,7 +16529,17 @@ static void test_map_synchronisation(void)
     for (i = 0; i < ARRAY_SIZE(tests); ++i)
     {
         hr = IDirect3D3_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0, NULL);
-        ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#lx.\n", hr);
+        ok(SUCCEEDED(hr) || hr == D3DERR_TOOMANYVERTICES, "Failed to create vertex buffer, hr %#lx.\n", hr);
+        /* D3DDEVICEDESC.dwMaxVertexCount is a thing (in ddraw4 and earlier), but ignored by runtime and
+         * drivers. The 64k limit is likely due to the 16 bit indices used by d3d <= 7. */
+        if (hr == D3DERR_TOOMANYVERTICES && vb_desc.dwNumVertices >= 65535)
+        {
+            trace("Test draw needs more than 64k vertices, test results might be flaky.\n");
+            small_buffer = TRUE;
+            vb_desc.dwNumVertices = 65534;
+            hr = IDirect3D3_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0, NULL);
+            ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#lx.\n", hr);
+        }
         hr = IDirect3DVertexBuffer_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&quads, NULL);
         ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#lx.\n", hr);
         for (j = 0; j < vb_desc.dwNumVertices / 4; ++j)
@@ -16547,6 +16568,7 @@ static void test_map_synchronisation(void)
 
         colour = get_surface_color(rt, 320, 240);
         unsynchronised = compare_color(colour, 0x00ffff00, 1);
+        flaky_if(small_buffer && tests[i].unsynchronised)
         ok(tests[i].unsynchronised == unsynchronised, "Expected %s map for flags %#x.\n",
                 tests[i].unsynchronised ? "unsynchronised" : "synchronised", tests[i].flags);
 
@@ -18164,11 +18186,17 @@ static void test_caps(void)
         {
             .dwSize = sizeof(DDSURFACEDESC2),
             .dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT,
-            .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
-            .ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT),
-            .ddpfPixelFormat.dwFlags = DDPF_ZBUFFER,
-            .ddpfPixelFormat.dwZBufferBitDepth = depth_caps[i].depth,
-            .ddpfPixelFormat.dwZBitMask = depth_caps[i].mask,
+            .ddsCaps =
+            {
+                .dwCaps = DDSCAPS_ZBUFFER,
+            },
+            .ddpfPixelFormat =
+            {
+                .dwSize = sizeof(DDPIXELFORMAT),
+                .dwFlags = DDPF_ZBUFFER,
+                .dwZBufferBitDepth = depth_caps[i].depth,
+                .dwZBitMask = depth_caps[i].mask,
+            },
             .dwWidth = 64,
             .dwHeight = 64,
         };
@@ -18260,11 +18288,17 @@ static void test_caps(void)
             {
                 .dwSize = sizeof(DDSURFACEDESC2),
                 .dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT,
-                .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
-                .ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT),
-                .ddpfPixelFormat.dwFlags = DDPF_ZBUFFER,
-                .ddpfPixelFormat.dwZBufferBitDepth = depth_caps[i].depth,
-                .ddpfPixelFormat.dwZBitMask = depth_caps[i].mask,
+                .ddsCaps =
+                {
+                    .dwCaps = DDSCAPS_ZBUFFER,
+                },
+                .ddpfPixelFormat =
+                {
+                    .dwSize = sizeof(DDPIXELFORMAT),
+                    .dwFlags = DDPF_ZBUFFER,
+                    .dwZBufferBitDepth = depth_caps[i].depth,
+                    .dwZBitMask = depth_caps[i].mask,
+                },
                 .dwWidth = 64,
                 .dwHeight = 64,
             };
diff --git a/dlls/ddraw/tests/ddraw7.c b/dlls/ddraw/tests/ddraw7.c
index 7a3c96fa3151..e8487283ead9 100644
--- a/dlls/ddraw/tests/ddraw7.c
+++ b/dlls/ddraw/tests/ddraw7.c
@@ -2747,6 +2747,7 @@ static void test_window_style(void)
     RECT fullscreen_rect, r;
     HWND window, window2;
     IDirectDraw7 *ddraw;
+    unsigned int i;
     HRESULT hr;
     ULONG ref;
     BOOL ret;
@@ -2957,10 +2958,19 @@ static void test_window_style(void)
     ok(tmp & WS_VISIBLE, "Expected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
     ok(tmp & WS_EX_TOPMOST, "Expected WS_EX_TOPMOST.\n");
-    ret = ShowWindow(window, SW_HIDE);
-    ok(ret, "ShowWindow failed, error %#lx.\n", GetLastError());
-    ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
-    ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+    for (i = 0; i < 5; ++i)
+    {
+        /* Try a few times to hide the window. Something in Win11 26H1 shows it again and makes it
+         * topmost. This is in addition to the ddraw periodic check below, which only makes it
+         * topmost but not visible */
+        ret = SetWindowPos(window, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_HIDEWINDOW);
+        ok(ret, "SetWindowPos failed, error %#lx.\n", GetLastError());
+        tmp = GetWindowLongA(window, GWL_STYLE);
+        if (!(tmp & WS_VISIBLE))
+            break;
+        Sleep(100);
+    }
+    ok(i < 5, "Failed to hide the window.\n");
     tmp = GetWindowLongA(window, GWL_STYLE);
     ok(!(tmp & WS_VISIBLE), "Got unexpected WS_VISIBLE.\n");
     tmp = GetWindowLongA(window, GWL_EXSTYLE);
@@ -15937,6 +15947,7 @@ static void test_map_synchronisation(void)
     unsigned int colour, i, j, tri_count;
     IDirect3DVertexBuffer7 *buffer;
     D3DVERTEXBUFFERDESC vb_desc;
+    BOOL small_buffer = FALSE;
     IDirect3DDevice7 *device;
     BOOL unsynchronised, ret;
     IDirectDrawSurface7 *rt;
@@ -16084,7 +16095,15 @@ static void test_map_synchronisation(void)
     for (i = 0; i < ARRAY_SIZE(tests); ++i)
     {
         hr = IDirect3D7_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0);
-        ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#lx.\n", hr);
+        ok(SUCCEEDED(hr) || hr == D3DERR_TOOMANYVERTICES, "Failed to create vertex buffer, hr %#lx.\n", hr);
+        if (hr == D3DERR_TOOMANYVERTICES && vb_desc.dwNumVertices >= 65535)
+        {
+            trace("Test draw needs more than 64k vertices, test results might be flaky.\n");
+            small_buffer = TRUE;
+            vb_desc.dwNumVertices = 65534;
+            hr = IDirect3D7_CreateVertexBuffer(d3d, &vb_desc, &buffer, 0);
+            ok(SUCCEEDED(hr), "Failed to create vertex buffer, hr %#lx.\n", hr);
+        }
         hr = IDirect3DVertexBuffer7_Lock(buffer, DDLOCK_DISCARDCONTENTS, (void **)&quads, NULL);
         ok(SUCCEEDED(hr), "Failed to lock vertex buffer, hr %#lx.\n", hr);
         for (j = 0; j < vb_desc.dwNumVertices / 4; ++j)
@@ -16113,6 +16132,7 @@ static void test_map_synchronisation(void)
 
         colour = get_surface_color(rt, 320, 240);
         unsynchronised = compare_color(colour, 0x00ffff00, 1);
+        flaky_if(small_buffer && tests[i].unsynchronised)
         ok(tests[i].unsynchronised == unsynchronised, "Expected %s map for flags %#x.\n",
                 tests[i].unsynchronised ? "unsynchronised" : "synchronised", tests[i].flags);
 
@@ -18307,11 +18327,17 @@ static void test_caps(void)
         {
             .dwSize = sizeof(DDSURFACEDESC2),
             .dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT,
-            .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
-            .ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT),
-            .ddpfPixelFormat.dwFlags = DDPF_ZBUFFER,
-            .ddpfPixelFormat.dwZBufferBitDepth = depth_caps[i].depth,
-            .ddpfPixelFormat.dwZBitMask = depth_caps[i].mask,
+            .ddsCaps =
+            {
+                .dwCaps = DDSCAPS_ZBUFFER,
+            },
+            .ddpfPixelFormat =
+            {
+                .dwSize = sizeof(DDPIXELFORMAT),
+                .dwFlags = DDPF_ZBUFFER,
+                .dwZBufferBitDepth = depth_caps[i].depth,
+                .dwZBitMask = depth_caps[i].mask,
+            },
             .dwWidth = 64,
             .dwHeight = 64,
         };
@@ -18394,11 +18420,17 @@ static void test_caps(void)
         {
             .dwSize = sizeof(DDSURFACEDESC2),
             .dwFlags = DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT,
-            .ddsCaps.dwCaps = DDSCAPS_ZBUFFER,
-            .ddpfPixelFormat.dwSize = sizeof(DDPIXELFORMAT),
-            .ddpfPixelFormat.dwFlags = DDPF_ZBUFFER,
-            .ddpfPixelFormat.dwZBufferBitDepth = depth_caps[i].depth,
-            .ddpfPixelFormat.dwZBitMask = depth_caps[i].mask,
+            .ddsCaps =
+            {
+                .dwCaps = DDSCAPS_ZBUFFER,
+            },
+            .ddpfPixelFormat =
+            {
+                .dwSize = sizeof(DDPIXELFORMAT),
+                .dwFlags = DDPF_ZBUFFER,
+                .dwZBufferBitDepth = depth_caps[i].depth,
+                .dwZBitMask = depth_caps[i].mask,
+            },
             .dwWidth = 64,
             .dwHeight = 64,
         };
diff --git a/dlls/dinput/tests/device8.c b/dlls/dinput/tests/device8.c
index 85c0b79d70e6..ceed0573510a 100644
--- a/dlls/dinput/tests/device8.c
+++ b/dlls/dinput/tests/device8.c
@@ -1704,9 +1704,8 @@ static void test_hid_mouse(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
-    if (!hid_device_start_( &desc, 1, 5000 /* needs a long timeout on Win7 */ )) goto done;
+    if (!hid_device_start( &desc, 1 )) goto done;
 
     swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x", desc.attributes.VendorID,
               desc.attributes.ProductID );
@@ -1950,7 +1949,6 @@ static void test_hid_touch_screen(void)
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
     desc.expect_size = sizeof(expect_max_count);
     memcpy( desc.expect, &expect_max_count, sizeof(expect_max_count) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
 
@@ -2124,7 +2122,6 @@ static void test_hid_touch_screen(void)
     desc.is_polled = TRUE;
     desc.input_size = sizeof(touch_release);
     memcpy( desc.input, &touch_release, sizeof(touch_release) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
 
@@ -3201,9 +3198,8 @@ static void test_hid_keyboard(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
-    if (!hid_device_start_( &desc, 1, 5000 /* needs a long timeout on Win7 */ )) goto done;
+    if (!hid_device_start( &desc, 1 )) goto done;
 
     swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x", desc.attributes.VendorID,
               desc.attributes.ProductID );
diff --git a/dlls/dinput/tests/dinput_test.h b/dlls/dinput/tests/dinput_test.h
index d19e1868d764..ae3416c4ba78 100644
--- a/dlls/dinput/tests/dinput_test.h
+++ b/dlls/dinput/tests/dinput_test.h
@@ -51,8 +51,8 @@ extern const WCHAR expect_path_end[];
 extern HINSTANCE instance;
 extern BOOL localized; /* object names get translated */
 
-#define hid_device_start( a, b ) hid_device_start_( a, b, 1000 )
-BOOL hid_device_start_( struct hid_device_desc *desc, UINT count, DWORD timeout );
+#define hid_device_start( a, b ) hid_device_start_( __FILE__, __LINE__, a, b, 1000 )
+BOOL hid_device_start_( const char *file, int line, struct hid_device_desc *desc, UINT count, DWORD timeout );
 void hid_device_stop( struct hid_device_desc *desc, UINT count );
 BOOL bus_device_start(void);
 void bus_device_stop(void);
@@ -64,12 +64,10 @@ void cleanup_registry_keys(void);
 void dinput_test_init_( const char *file, int line );
 void dinput_test_exit(void);
 
+HRESULT dinput_test_create_device_instance( DWORD version, const GUID *guid_inst, IDirectInputDevice8W **device );
 HRESULT dinput_test_create_device( DWORD version, DIDEVICEINSTANCEW *devinst, IDirectInputDevice8W **device );
 DWORD WINAPI dinput_test_device_thread( void *stop_event );
 
-#define fill_context( a, b ) fill_context_( __FILE__, __LINE__, a, b )
-void fill_context_( const char *file, int line, char *buffer, SIZE_T size );
-
 #define check_member_( file, line, val, exp, fmt, member )                                         \
     ok_(file, line)( (val).member == (exp).member, "got " #member " " fmt "\n", (val).member )
 #define check_member( val, exp, fmt, member )                                                      \
diff --git a/dlls/dinput/tests/driver_bus.c b/dlls/dinput/tests/driver_bus.c
index e8338e497118..5a78df986f33 100644
--- a/dlls/dinput/tests/driver_bus.c
+++ b/dlls/dinput/tests/driver_bus.c
@@ -505,6 +505,10 @@ struct phys_device
     struct device base;
     struct func_device *fdo; /* parent FDO */
 
+    WCHAR vendor_str[64];
+    WCHAR product_str[64];
+    WCHAR serial_str[64];
+
     WCHAR instance_id[MAX_PATH];
     WCHAR device_id[MAX_PATH];
     IRP *pending_remove;
@@ -563,7 +567,7 @@ static NTSTATUS remove_child_device( struct func_device *impl, DEVICE_OBJECT *de
     for (i = 0; i < impl->devices->Count; ++i)
         if (impl->devices->Objects[i] == device) break;
     if (i == impl->devices->Count) status = STATUS_NOT_FOUND;
-    else impl->devices->Objects[i] = impl->devices->Objects[impl->devices->Count--];
+    else impl->devices->Objects[i] = impl->devices->Objects[--impl->devices->Count];
     KeReleaseSpinLock( &impl->base.lock, irql );
 
     return status;
@@ -600,11 +604,12 @@ static DEVICE_OBJECT *find_child_device( struct func_device *impl, struct hid_de
 
     KeAcquireSpinLock( &impl->base.lock, &irql );
     devices = impl->devices->Objects;
-    for (i = 0; i < impl->devices->Count; ++i)
+    for (i = 0; !device && i < impl->devices->Count; ++i)
     {
-        struct phys_device *phys = pdo_from_DEVICE_OBJECT( (device = devices[i]) );
-        if (!wcscmp( phys->device_id, device_id )) break;
-        else device = NULL;
+        struct phys_device *phys = pdo_from_DEVICE_OBJECT( devices[i] );
+        if (wcscmp( phys->device_id, device_id )) continue;
+        if (*desc->serial_str && wcscmp( phys->serial_str, desc->serial_str )) continue;
+        device = devices[i];
     }
     KeReleaseSpinLock( &impl->base.lock, irql );
 
@@ -903,11 +908,16 @@ static NTSTATUS create_child_pdo( DEVICE_OBJECT *device, struct hid_device_desc
 
     impl = pdo_from_DEVICE_OBJECT( child );
     KeInitializeSpinLock( &impl->base.lock );
+
+    wcscpy( impl->vendor_str, *desc->vendor_str ? desc->vendor_str : L"WineTest" );
+    wcscpy( impl->product_str, *desc->product_str ? desc->product_str : L"Wine Test" );
+    wcscpy( impl->serial_str, *desc->serial_str ? desc->serial_str : L"0&0000&0" );
+
     swprintf( impl->device_id, MAX_PATH, L"WINETEST\\VID_%04X&PID_%04X", desc->attributes.VendorID,
               desc->attributes.ProductID );
     /* use a different device ID so that driver cache select the polled driver */
     if (desc->is_polled) wcscat( impl->device_id, L"&POLL" );
-    swprintf( impl->instance_id, MAX_PATH, L"0&0000&0" );
+    swprintf( impl->instance_id, MAX_PATH, L"%s", impl->serial_str );
     impl->base.is_phys = TRUE;
     impl->fdo = fdo;
 
@@ -1238,10 +1248,41 @@ static NTSTATUS pdo_internal_ioctl( DEVICE_OBJECT *device, IRP *irp )
     }
 
     case IOCTL_HID_GET_STRING:
-        memcpy( irp->UserBuffer, L"Wine Test", sizeof(L"Wine Test") );
-        irp->IoStatus.Information = sizeof(L"Wine Test");
-        status = STATUS_SUCCESS;
+    {
+        UINT index = (UINT_PTR)stack->Parameters.DeviceIoControl.Type3InputBuffer & 0xffff;
+        UINT lcid = ((UINT_PTR)stack->Parameters.DeviceIoControl.Type3InputBuffer) >> 16;
+
+        todo_wine ok( lcid, "Unexpected LCID %#x.\n", lcid );
+        if (winetest_debug > 1)
+            trace( "%s: device %p, code %#lx %s, lcid %#x, idx %#x.\n", __func__, device, code, debugstr_ioctl(code),
+                    lcid, index );
+        switch (index)
+        {
+        case HID_STRING_ID_IMANUFACTURER:
+            irp->IoStatus.Information = (wcslen( impl->vendor_str ) + 1) * sizeof(WCHAR);
+            memcpy( irp->UserBuffer, impl->vendor_str, irp->IoStatus.Information );
+            status = STATUS_SUCCESS;
+            break;
+
+        case HID_STRING_ID_IPRODUCT:
+            irp->IoStatus.Information = (wcslen( impl->product_str ) + 1) * sizeof(WCHAR);
+            memcpy( irp->UserBuffer, impl->product_str, irp->IoStatus.Information );
+            status = STATUS_SUCCESS;
+            break;
+
+        case HID_STRING_ID_ISERIALNUMBER:
+            irp->IoStatus.Information = (wcslen(impl->serial_str) + 1) * sizeof(WCHAR);
+            memcpy( irp->UserBuffer, impl->serial_str, irp->IoStatus.Information );
+            status = STATUS_SUCCESS;
+            break;
+
+        default:
+            ok(0, "Unknown string type %#x.\n", index);
+            status = STATUS_NOT_IMPLEMENTED;
+            break;
+        }
         break;
+    }
 
     case IOCTL_GET_PHYSICAL_DESCRIPTOR:
         irp->IoStatus.Information = 0;
diff --git a/dlls/dinput/tests/driver_hid.c b/dlls/dinput/tests/driver_hid.c
index 7b20af07493c..5d92c8b230a5 100644
--- a/dlls/dinput/tests/driver_hid.c
+++ b/dlls/dinput/tests/driver_hid.c
@@ -57,8 +57,6 @@ static void check_device( DEVICE_OBJECT *device )
 
     ok( device == impl->expect_hid_fdo, "got device %p\n", device );
     ok( device->DriverObject == expect_driver, "got DriverObject %p\n", device->DriverObject );
-    if (!device->NextDevice) ok( device == impl->expect_hid_fdo, "got device %p\n", device );
-    else ok( device->NextDevice == impl->expect_hid_fdo, "got NextDevice %p\n", device->NextDevice );
     ok( !device->AttachedDevice, "got AttachedDevice %p\n", device->AttachedDevice );
 
     ok( ext->MiniDeviceExtension == impl->expect_hid_ext, "got MiniDeviceExtension %p\n", ext->MiniDeviceExtension );
diff --git a/dlls/dinput/tests/driver_hid.h b/dlls/dinput/tests/driver_hid.h
index 8ba01d14b1eb..941e72967190 100644
--- a/dlls/dinput/tests/driver_hid.h
+++ b/dlls/dinput/tests/driver_hid.h
@@ -79,12 +79,16 @@ struct hid_device_desc
 {
     BOOL is_polled;
     BOOL use_report_id;
+    UINT tlc_count;
 
     DWORD report_descriptor_len;
     char report_descriptor_buf[MAX_HID_DESCRIPTOR_LEN];
 
     HIDP_CAPS caps;
     HID_DEVICE_ATTRIBUTES attributes;
+    WCHAR vendor_str[64];
+    WCHAR product_str[64];
+    WCHAR serial_str[64];
 
     ULONG input_size;
     struct hid_expect input[64];
diff --git a/dlls/dinput/tests/force_feedback.c b/dlls/dinput/tests/force_feedback.c
index 69a521b0e47a..1de2321fcc51 100644
--- a/dlls/dinput/tests/force_feedback.c
+++ b/dlls/dinput/tests/force_feedback.c
@@ -3424,7 +3424,6 @@ static BOOL test_force_feedback_joystick( DWORD version )
 
     desc.report_descriptor_len = sizeof(report_descriptor);
     memcpy( desc.report_descriptor_buf, report_descriptor, sizeof(report_descriptor) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
@@ -4321,7 +4320,6 @@ static BOOL test_force_feedback_six_axes(void)
 
     desc.report_descriptor_len = sizeof(report_descriptor);
     memcpy( desc.report_descriptor_buf, report_descriptor, sizeof(report_descriptor) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
@@ -5310,7 +5308,6 @@ static void test_device_managed_effect(void)
     memcpy( desc.report_descriptor_buf, report_descriptor, sizeof(report_descriptor) );
     desc.expect_size = sizeof(expect_pool);
     memcpy( desc.expect, expect_pool, sizeof(expect_pool) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done;
@@ -7268,7 +7265,6 @@ static void test_windows_gaming_input(void)
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
     desc.expect_size = sizeof(expect_init);
     memcpy( desc.expect, expect_init, sizeof(expect_init) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     ret = WaitForSingleObject( controller_added.event, 5000 );
diff --git a/dlls/dinput/tests/hid.c b/dlls/dinput/tests/hid.c
index c9cdb649f26e..7c42ac54f748 100644
--- a/dlls/dinput/tests/hid.c
+++ b/dlls/dinput/tests/hid.c
@@ -711,54 +711,80 @@ BOOL bus_device_start(void)
     return ret || GetLastError() == ERROR_SERVICE_ALREADY_RUNNING;
 }
 
-void hid_device_stop( struct hid_device_desc *desc, UINT count )
+static void fill_context( const char *file, int line, char *buffer, SIZE_T size )
 {
-    HANDLE control;
-    DWORD ret, i;
-
-    control = CreateFileW( L"\\\\?\\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0,
-                           NULL, OPEN_EXISTING, 0, NULL );
-    ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() );
-    ret = sync_ioctl( control, IOCTL_WINETEST_REMOVE_DEVICE, desc, sizeof(*desc), NULL, 0, 5000 );
-    ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() );
-    CloseHandle( control );
-
-    if (!ret) return;
+    const char *source_file;
+    source_file = strrchr( file, '/' );
+    if (!source_file) source_file = strrchr( file, '\\' );
+    if (!source_file) source_file = file;
+    else source_file++;
+    snprintf( buffer, size, "%s:%d", source_file, line );
+}
 
-    ret = WaitForSingleObject( device_removed, 5000 );
-    ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+static void hid_device_remove( HANDLE control, struct hid_device_desc *desc, UINT count )
+{
+    DWORD ret;
 
-    for (i = 0; i < count; ++i)
+    for (UINT i = 0; i < count; i++)
     {
-        ret = WaitForSingleObject( device_removed, i > 0 ? 500 : 5000 );
+        ret = sync_ioctl( control, IOCTL_WINETEST_REMOVE_DEVICE, desc + i, sizeof(*desc), NULL, 0, 5000 );
+        ok( ret || GetLastError() == ERROR_FILE_NOT_FOUND, "IOCTL_WINETEST_REMOVE_DEVICE failed, last error %lu\n", GetLastError() );
+        if (!ret) continue;
+
+        ret = WaitForSingleObject( device_removed, 5000 );
         ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+
+        for (UINT j = 0; j < (desc->tlc_count ? desc->tlc_count : 1); ++j)
+        {
+            ret = WaitForSingleObject( device_removed, j > 0 ? 500 : 5000 );
+            ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+        }
     }
 }
 
-BOOL hid_device_start_( struct hid_device_desc *desc, UINT count, DWORD timeout )
+void hid_device_stop( struct hid_device_desc *desc, UINT count )
+{
+    HANDLE control = CreateFileW( L"\\\\?\\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0,
+                                  NULL, OPEN_EXISTING, 0, NULL );
+    ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() );
+    hid_device_remove( control, desc, count );
+    CloseHandle( control );
+}
+
+BOOL hid_device_start_( const char *file, int line, struct hid_device_desc *desc, UINT count, DWORD timeout )
 {
     HANDLE control;
-    DWORD ret, i;
+    DWORD ret = 0;
 
     control = CreateFileW( L"\\\\?\\root#winetest#0#{deadbeef-29ef-4538-a5fd-b69573a362c0}", 0, 0,
                            NULL, OPEN_EXISTING, 0, NULL );
     ok( control != INVALID_HANDLE_VALUE, "CreateFile failed, error %lu\n", GetLastError() );
-    ret = sync_ioctl( control, IOCTL_WINETEST_CREATE_DEVICE, desc, sizeof(*desc), NULL, 0, 5000 );
-    ok( ret, "IOCTL_WINETEST_CREATE_DEVICE failed, last error %lu\n", GetLastError() );
-    CloseHandle( control );
 
-    ret = WaitForSingleObject( device_added, 5000 );
-    ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+    for (UINT i = 0; i < count; i++)
+    {
+        fill_context( file, line, desc[i].context, ARRAY_SIZE(desc[i].context) );
 
-    if (ret) return FALSE;
+        ret = sync_ioctl( control, IOCTL_WINETEST_CREATE_DEVICE, desc + i, sizeof(*desc), NULL, 0, 5000 );
+        ok( ret, "IOCTL_WINETEST_CREATE_DEVICE failed, last error %lu\n", GetLastError() );
 
-    for (i = 0; i < count; ++i)
-    {
-        ret = WaitForSingleObject( device_added, timeout );
+        ret = WaitForSingleObject( device_added, 5000 );
         ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+
+        if (ret)
+        {
+            hid_device_remove( control, desc, i );
+            break;
+        }
+
+        for (UINT j = 0; j < (desc->tlc_count ? desc->tlc_count : 1); ++j)
+        {
+            ret = WaitForSingleObject( device_added, timeout );
+            ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+        }
     }
 
-    return TRUE;
+    CloseHandle( control );
+    return !ret;
 }
 
 #define check_hidp_caps( a, b ) check_hidp_caps_( __LINE__, a, b )
@@ -923,16 +949,6 @@ BOOL sync_ioctl_( const char *file, int line, HANDLE device, DWORD code, void *i
     return ret;
 }
 
-void fill_context_( const char *file, int line, char *buffer, SIZE_T size )
-{
-    const char *source_file;
-    source_file = strrchr( file, '/' );
-    if (!source_file) source_file = strrchr( file, '\\' );
-    if (!source_file) source_file = file;
-    else source_file++;
-    snprintf( buffer, size, "%s:%d", source_file, line );
-}
-
 void set_hid_expect_( const char *file, int line, HANDLE device, struct hid_device_desc *desc,
                       struct hid_expect *expect, DWORD expect_size )
 {
@@ -943,7 +959,7 @@ void set_hid_expect_( const char *file, int line, HANDLE device, struct hid_devi
     if (desc) memcpy( buffer, desc, sizeof(*desc) );
     else memset( buffer, 0, sizeof(*desc) );
 
-    fill_context_( file, line, buffer + sizeof(*desc), ARRAY_SIZE(buffer) - sizeof(*desc) );
+    fill_context( file, line, buffer + sizeof(*desc), ARRAY_SIZE(buffer) - sizeof(*desc) );
     size = sizeof(*desc) + strlen( buffer + sizeof(*desc) ) + 1;
     ret = sync_ioctl_( file, line, device, IOCTL_WINETEST_HID_SET_CONTEXT, buffer, size, NULL, 0, 5000 );
     ok_(file, line)( ret, "IOCTL_WINETEST_HID_SET_CONTEXT failed, last error %lu\n", GetLastError() );
@@ -987,7 +1003,7 @@ void send_hid_input_( const char *file, int line, HANDLE device, struct hid_devi
     if (desc) memcpy( buffer, desc, sizeof(*desc) );
     else memset( buffer, 0, sizeof(*desc) );
 
-    fill_context_( file, line, buffer + sizeof(*desc), ARRAY_SIZE(buffer) - sizeof(*desc) );
+    fill_context( file, line, buffer + sizeof(*desc), ARRAY_SIZE(buffer) - sizeof(*desc) );
     size = sizeof(*desc) + strlen( buffer + sizeof(*desc) ) + 1;
     ret = sync_ioctl_( file, line, device, IOCTL_WINETEST_HID_SET_CONTEXT, buffer, size, NULL, 0, 5000 );
     ok_(file, line)( ret, "IOCTL_WINETEST_HID_SET_CONTEXT failed, last error %lu\n", GetLastError() );
@@ -2713,10 +2729,10 @@ static void test_hidp( HANDLE file, HANDLE async_file, int report_id, BOOL polle
     HidD_FreePreparsedData( preparsed_data );
 }
 
-static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *expect_caps, WORD vid, WORD pid )
+static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *expect_caps, struct hid_device_desc *desc )
 {
+    WCHAR device_path[MAX_PATH], buffer[1024];
     ULONG count, poll_freq, out_len;
-    WCHAR device_path[MAX_PATH];
     HANDLE file, async_file;
     DWORD ret;
 
@@ -2730,7 +2746,7 @@ static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *exp
         ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
     }
 
-    swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x", vid, pid );
+    swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x", desc->attributes.VendorID, desc->attributes.ProductID );
     ret = find_hid_device_path( device_path );
     ok( ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
 
@@ -2738,6 +2754,16 @@ static void test_hid_device( DWORD report_id, DWORD polled, const HIDP_CAPS *exp
                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
     ok( file != INVALID_HANDLE_VALUE, "got error %lu\n", GetLastError() );
 
+    ret = HidD_GetManufacturerString( file, buffer, ARRAY_SIZE(buffer) );
+    ok( ret, "HidD_GetManufacturerString failed last error %lu\n", GetLastError() );
+    ok( !wcscmp( desc->vendor_str, buffer ), "HidD_GetManufacturerString returned %s\n", debugstr_w(buffer) );
+    ret = HidD_GetProductString( file, buffer, ARRAY_SIZE(buffer) );
+    ok( ret, "HidD_GetProductString failed last error %lu\n", GetLastError() );
+    ok( !wcscmp( desc->product_str, buffer ), "HidD_GetProductString returned %s\n", debugstr_w(buffer) );
+    ret = HidD_GetSerialNumberString( file, buffer, ARRAY_SIZE(buffer) );
+    ok( ret, "HidD_GetSerialNumberString failed last error %lu\n", GetLastError() );
+    ok( !wcscmp( desc->serial_str, buffer ), "HidD_GetSerialNumberString returned %s\n", debugstr_w(buffer) );
+
     count = 0xdeadbeef;
     SetLastError( 0xdeadbeef );
     ret = HidD_GetNumInputBuffers( file, &count );
@@ -3150,15 +3176,17 @@ static void test_hid_driver( DWORD report_id, DWORD polled )
         .use_report_id = report_id,
         .caps = caps,
         .attributes = default_attributes,
+        .vendor_str = L"Wine",
+        .product_str = L"Test Device",
+        .serial_str = L"0&1234&5",
     };
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
     desc.input_size = polled ? sizeof(expect_in) : 0;
     memcpy( desc.input, &expect_in, sizeof(expect_in) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
-    if (hid_device_start( &desc, 1 )) test_hid_device( report_id, polled, &caps, desc.attributes.VendorID, desc.attributes.ProductID );
+    if (hid_device_start( &desc, 1 )) test_hid_device( report_id, polled, &caps, &desc );
     hid_device_stop( &desc, 1 );
 }
 
@@ -3565,7 +3593,6 @@ static void test_hidp_kdr(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
 
@@ -3587,13 +3614,27 @@ done:
     hid_device_stop( &desc, 1 );
 }
 
+static void cleanup_registry_tree( HKEY root, const WCHAR *path )
+{
+    WCHAR buf[MAX_PATH];
+    HKEY hkey;
+
+    RegCreateKeyExW( root, path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hkey, NULL );
+    for (ULONG i = 0, size = ARRAY_SIZE(buf); !RegEnumKeyExW( hkey, i, buf, &size, NULL, NULL, NULL, NULL ); i++, size = ARRAY_SIZE(buf))
+    {
+        if (wcsnicmp( buf, L"VID_1209", 8 )) continue;
+        RegDeleteTreeW( hkey, buf );
+        i = -1;
+    }
+    RegCloseKey( hkey );
+}
+
 void cleanup_registry_keys(void)
 {
     static const WCHAR joystick_oem_path[] = L"System\\CurrentControlSet\\Control\\MediaProperties\\"
                                               "PrivateProperties\\Joystick\\OEM";
     static const WCHAR dinput_path[] = L"System\\CurrentControlSet\\Control\\MediaProperties\\"
                                        "PrivateProperties\\DirectInput";
-    HKEY root_key;
 
     /* These keys are automatically created by DInput and they store the
        list of supported force-feedback effects. OEM drivers are supposed
@@ -3603,21 +3644,10 @@ void cleanup_registry_keys(void)
        We need to clean them up, or DInput will not refresh the list of
        effects from the PID report changes.
     */
-    RegCreateKeyExW( HKEY_CURRENT_USER, joystick_oem_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL );
-    RegDeleteTreeW( root_key, expect_vidpid_str );
-    RegCloseKey( root_key );
-
-    RegCreateKeyExW( HKEY_CURRENT_USER, dinput_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL );
-    RegDeleteTreeW( root_key, expect_vidpid_str );
-    RegCloseKey( root_key );
-
-    RegCreateKeyExW( HKEY_LOCAL_MACHINE, joystick_oem_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL );
-    RegDeleteTreeW( root_key, expect_vidpid_str );
-    RegCloseKey( root_key );
-
-    RegCreateKeyExW( HKEY_LOCAL_MACHINE, dinput_path, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &root_key, NULL );
-    RegDeleteTreeW( root_key, expect_vidpid_str );
-    RegCloseKey( root_key );
+    cleanup_registry_tree( HKEY_CURRENT_USER, joystick_oem_path );
+    cleanup_registry_tree( HKEY_CURRENT_USER, dinput_path );
+    cleanup_registry_tree( HKEY_LOCAL_MACHINE, joystick_oem_path );
+    cleanup_registry_tree( HKEY_LOCAL_MACHINE, dinput_path );
 }
 
 static LRESULT CALLBACK monitor_wndproc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
@@ -3875,7 +3905,6 @@ DWORD WINAPI dinput_test_device_thread( void *stop_event )
 
     desc.report_descriptor_len = sizeof(gamepad_desc);
     memcpy( desc.report_descriptor_buf, gamepad_desc, sizeof(gamepad_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     hid_device_start( &desc, 1 );
     ret = WaitForSingleObject( stop_event, 5000 );
@@ -4025,6 +4054,7 @@ static void test_hid_multiple_tlc(void)
 
     struct hid_device_desc desc =
     {
+        .tlc_count = 2,
         .caps = { .InputReportByteLength = 7 },
         .attributes = default_attributes,
     };
@@ -4139,9 +4169,8 @@ static void test_hid_multiple_tlc(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
-    if (!hid_device_start( &desc, 2 )) goto done;
+    if (!hid_device_start( &desc, 1 )) goto done;
 
     swprintf( device_path, MAX_PATH, L"\\\\?\\hid#vid_%04x&pid_%04x&col01", desc.attributes.VendorID,
               desc.attributes.ProductID );
@@ -4195,7 +4224,7 @@ static void test_hid_multiple_tlc(void)
     ok( !ret, "Failed to find HID device matching %s\n", debugstr_w( device_path ) );
 
 done:
-    hid_device_stop( &desc, 2 );
+    hid_device_stop( &desc, 1 );
 }
 
 START_TEST( hid )
diff --git a/dlls/dinput/tests/hotplug.c b/dlls/dinput/tests/hotplug.c
index ce44bae754cf..10a3051e8ce8 100644
--- a/dlls/dinput/tests/hotplug.c
+++ b/dlls/dinput/tests/hotplug.c
@@ -154,9 +154,9 @@ static BOOL test_input_lost( DWORD version )
         .dwData = UINT_MAX,
     };
 
-    DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)};
+    DIDEVICEINSTANCEW devinst = {.dwSize = sizeof(DIDEVICEINSTANCEW)}, devinst2 = devinst;
+    IDirectInputDevice8W *device = NULL, *device2;
     DIDEVICEOBJECTDATA objdata[32] = {{0}};
-    IDirectInputDevice8W *device = NULL;
     ULONG ref, count, size;
     DIJOYSTATE2 state;
     HRESULT hr;
@@ -167,7 +167,6 @@ static BOOL test_input_lost( DWORD version )
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
@@ -209,7 +208,6 @@ static BOOL test_input_lost( DWORD version )
     hr = IDirectInputDevice8_Unacquire( device );
     ok( hr == DI_NOEFFECT, "Unacquire returned: %#lx\n", hr );
 
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
     hid_device_start( &desc, 1 );
 
     hr = IDirectInputDevice8_Acquire( device );
@@ -220,6 +218,15 @@ static BOOL test_input_lost( DWORD version )
     ref = IDirectInputDevice8_Release( device );
     ok( ref == 0, "Release returned %ld\n", ref );
 
+    /* Test guidInstance across hotplugs. It should remain the same. */
+    hr = dinput_test_create_device( version, &devinst2, &device2 );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( !!device2, "device2 is NULL.\n" );
+    todo_wine ok( !memcmp( &devinst.guidInstance, &devinst2.guidInstance, sizeof(GUID) ),
+                  "Unexpected guidInstance.\n" );
+    ref = IDirectInputDevice8_Release( device2 );
+    ok( ref == 0, "Release returned %ld\n", ref );
+
 done:
     hid_device_stop( &desc, 1 );
     cleanup_registry_keys();
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c
index eab4a7ff7e8d..5b2ca8fe66dc 100644
--- a/dlls/dinput/tests/joystick8.c
+++ b/dlls/dinput/tests/joystick8.c
@@ -302,6 +302,39 @@ static BOOL CALLBACK enum_device_count( const DIDEVICEINSTANCEW *devinst, void *
     return DIENUM_CONTINUE;
 }
 
+struct dinput
+{
+    DWORD version;
+    union
+    {
+        IDirectInput8W *di8;
+        IDirectInputW *di;
+    };
+};
+
+static HRESULT dinput_create( struct dinput *di )
+{
+    return di->version < 0x0800 ? DirectInputCreateEx( instance, di->version, &IID_IDirectInput2W, (void **)&di->di, NULL )
+                                : DirectInput8Create( instance, di->version, &IID_IDirectInput8W, (void **)&di->di, NULL );
+}
+
+static ULONG dinput_release( struct dinput *di )
+{
+    return di->version < 0x0800 ? IDirectInput_Release( di->di ) : IDirectInput8_Release( di->di8 );
+}
+
+static HRESULT dinput_enum_devices( struct dinput *di, LPDIENUMDEVICESCALLBACKW callback, void *context )
+{
+    return di->version < 0x0800 ? IDirectInput_EnumDevices( di->di, 0, callback, context, DIEDFL_ALLDEVICES )
+                                : IDirectInput8_EnumDevices( di->di8, DI8DEVCLASS_ALL, callback, context, DIEDFL_ALLDEVICES );
+}
+
+static HRESULT dinput_create_device( struct dinput *di, const GUID *guid, IDirectInputDevice8W **device )
+{
+    return di->version < 0x0800 ? IDirectInput_CreateDevice( di->di, guid, (IDirectInputDeviceW **)device, NULL )
+                                : IDirectInput8_CreateDevice( di->di8, guid, device, NULL );
+}
+
 static void check_dinput_devices( DWORD version, DIDEVICEINSTANCEW *devinst )
 {
     DIPROPDWORD prop_dword =
@@ -1918,7 +1951,6 @@ static void test_simple_joystick( DWORD version )
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( version, &devinst, &device ))) goto done;
@@ -3742,7 +3774,6 @@ static BOOL test_device_types( DWORD version )
         desc.caps = device_desc[i].hid_caps;
         desc.report_descriptor_len = device_desc[i].report_desc_len;
         memcpy( desc.report_descriptor_buf, device_desc[i].report_desc_buf, device_desc[i].report_desc_len );
-        fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
         if (!hid_device_start( &desc, 1 ))
         {
@@ -4212,7 +4243,6 @@ static void test_many_axes_joystick(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done;
@@ -4480,7 +4510,6 @@ static void test_driving_wheel_axes(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     if (FAILED(hr = dinput_test_create_device( DIRECTINPUT_VERSION, &devinst, &device ))) goto done;
@@ -4715,7 +4744,6 @@ static void test_winmm_joystick(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
 
@@ -5139,7 +5167,6 @@ static void test_windows_gaming_input(void)
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     if (!hid_device_start( &desc, 1 )) goto done;
     res = WaitForSingleObject( controller_added.event, 5000 );
@@ -5250,7 +5277,6 @@ static void test_windows_gaming_input(void)
 
     desc.report_descriptor_len = sizeof(wheel_threepedals_desc);
     memcpy( desc.report_descriptor_buf, wheel_threepedals_desc, sizeof(wheel_threepedals_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     controller_added.event = CreateEventW( NULL, FALSE, FALSE, NULL );
     ok( !!controller_added.event, "CreateEventW failed, error %lu\n", GetLastError() );
@@ -5319,6 +5345,7 @@ static void test_game_input(void)
     HMODULE gameinput = LoadLibraryW( L"gameinput.dll" );
     HRESULT (WINAPI *pGameInputCreate)( v0_IGameInput **out );
     v0_IGameInput *gi0;
+    HRESULT hr;
 
     if (!gameinput || !(pGameInputCreate = (void *)GetProcAddress( gameinput, "GameInputCreate" )))
     {
@@ -5327,8 +5354,9 @@ static void test_game_input(void)
     }
 
     gi0 = (void *)0xdeadbeef;
-    todo_wine ok_hr( S_OK, pGameInputCreate( &gi0 ) );
-    if (gi0 != (void *)0xdeadbeef) ok_ret( 0, v0_IGameInput_Release( gi0 ) );
+    hr = pGameInputCreate( &gi0 );
+    todo_wine ok( hr == S_OK || broken(hr == E_NOTIMPL), "Unexpected hr %#lx.\n", hr );
+    if (gi0 && gi0 != (void *)0xdeadbeef) ok_ret( 0, v0_IGameInput_Release( gi0 ) );
 }
 
 static HANDLE rawinput_device_added, rawinput_device_removed, rawinput_event;
@@ -5467,7 +5495,6 @@ static void test_rawinput( char **argv )
 
     desc.report_descriptor_len = sizeof(report_desc);
     memcpy( desc.report_descriptor_buf, report_desc, sizeof(report_desc) );
-    fill_context( desc.context, ARRAY_SIZE(desc.context) );
 
     rawinput_device_added = CreateSemaphoreW( NULL, 0, LONG_MAX, NULL );
     ok( !!rawinput_device_added, "CreateSemaphoreW failed, error %lu\n", GetLastError() );
@@ -5979,6 +6006,484 @@ static void test_rawinput_desktop( const char *path, BOOL input )
     DestroyWindow( hwnd );
 }
 
+static BOOL CALLBACK find_test_device_instances( const DIDEVICEINSTANCEW *devinst, void *context )
+{
+    GUID **instance = context;
+
+    if (LOWORD(devinst->guidProduct.Data1) == LOWORD(EXPECT_VIDPID))
+    {
+        **instance = devinst->guidInstance;
+        (*instance)++;
+    }
+
+    return DIENUM_CONTINUE;
+}
+
+#define check_device_hid_serial( a, b ) check_device_hid_serial_( __LINE__, a, b )
+static void check_device_hid_serial_( int line, IDirectInputDevice8W *device, const WCHAR *expect )
+{
+    DIPROPGUIDANDPATH prop_guid_path =
+    {
+        .diph =
+        {
+            .dwSize = sizeof(DIPROPGUIDANDPATH),
+            .dwHeaderSize = sizeof(DIPROPHEADER),
+            .dwHow = DIPH_DEVICE,
+        },
+    };
+    WCHAR device_id[MAX_PATH] = {0};
+    HANDLE file_handle;
+    HRESULT hr;
+    BOOL ret;
+
+    hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph );
+    ok_(__FILE__, line)( hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+    file_handle = CreateFileW( prop_guid_path.wszPath, FILE_READ_ACCESS | FILE_WRITE_ACCESS,
+                               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
+    ok_(__FILE__, line)( file_handle != INVALID_HANDLE_VALUE, "Got error %lu.\n", GetLastError() );
+
+    ret = HidD_GetSerialNumberString( file_handle, device_id, ARRAY_SIZE(device_id) );
+    ok_(__FILE__, line)( ret, "Failed to get HID serial number string.\n" );
+    ok_(__FILE__, line)( !wcscmp( expect, device_id ), "Unexpected device serial %s.\n", debugstr_w(device_id) );
+
+    CloseHandle( file_handle );
+}
+
+static void test_joystick_instance_guid( DWORD version )
+{
+#include "psh_hid_macros.h"
+    static const unsigned char report_desc[] =
+    {
+        USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC),
+        USAGE(1, HID_USAGE_GENERIC_JOYSTICK),
+        COLLECTION(1, Application),
+            USAGE(1, HID_USAGE_GENERIC_JOYSTICK),
+            COLLECTION(1, Physical),
+                USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON),
+                USAGE_MINIMUM(1, 1),
+                USAGE_MAXIMUM(1, 6),
+                LOGICAL_MINIMUM(1, 0),
+                LOGICAL_MAXIMUM(1, 1),
+                PHYSICAL_MINIMUM(1, 0),
+                PHYSICAL_MAXIMUM(1, 1),
+                REPORT_SIZE(1, 1),
+                REPORT_COUNT(1, 8),
+                INPUT(1, Data|Var|Abs),
+            END_COLLECTION,
+        END_COLLECTION,
+    };
+    C_ASSERT( sizeof(report_desc) < MAX_HID_DESCRIPTOR_LEN );
+#include "pop_hid_macros.h"
+    struct hid_device_desc descs[4] =
+    {
+#define MAKE_ATTR( pid) { sizeof(HID_DEVICE_ATTRIBUTES), LOWORD(EXPECT_VIDPID), pid, 0x0100 }
+#define MAKE_DESC( pid, serial ) {.use_report_id = TRUE, .caps = {.InputReportByteLength = 1}, .attributes = MAKE_ATTR( pid ), .serial_str = serial}
+        MAKE_DESC( 0x0001, L"1&2345&6" ),
+        MAKE_DESC( 0x0001, L"2&7812&1" ),
+        MAKE_DESC( 0x0002, L"3&4580&7" ),
+        MAKE_DESC( 0x0002, L"4&5880&3" ),
+#undef MAKE_DESC
+#undef MAKE_ATTR
+    };
+    const GUID instance_uuid_init = {0x00000000, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x00, 'D', 'E', 'S', 'T'}};
+    struct dinput di = {.version = version}, di2 = {.version = version};
+    GUID expect_instances[4], instances[64], *instances_end;
+    IDirectInputDevice8W *device;
+    HRESULT hr;
+    ULONG ref;
+
+    winetest_push_context( "%#lx", version );
+    cleanup_registry_keys();
+
+    if (FAILED(hr = dinput_create( &di )))
+    {
+        win_skip( "DirectInput8Create returned %#lx\n", hr );
+        return;
+    }
+
+    for (UINT i = 0; i < ARRAY_SIZE(descs); i++)
+    {
+        descs[i].report_descriptor_len = sizeof(report_desc);
+        memcpy( descs[i].report_descriptor_buf, report_desc, sizeof(report_desc) );
+    }
+
+    if (!hid_device_start( descs, ARRAY_SIZE(descs) )) goto done;
+
+    /* Enumerate all devices, each with a unique guidInstance. */
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 4, "Unexpected count %Iu.\n", instances_end - instances );
+
+    for (UINT i = 0; i < instances_end - instances; i++)
+    {
+        winetest_push_context( "device %d", i );
+
+        hr = dinput_create_device( &di, &instances[i], &device );
+        ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+        expect_instances[i] = instances[i];
+
+        check_device_hid_serial( device, descs[i].serial_str );
+
+        IDirectInputDevice8_Release( device );
+        winetest_pop_context();
+    }
+
+    /*
+     * Delete the existing registry keys, this will result in a new set of
+     * guidInstance values being generated on the next call to EnumDevices().
+     */
+    cleanup_registry_keys();
+
+    /*
+     * EnumDevices() hasn't been called yet, guidInstance values are still
+     * valid.
+     */
+    for (UINT i = 0; i < instances_end - instances; i++)
+    {
+        winetest_push_context( "device %d", i );
+
+        hr = dinput_create_device( &di, &expect_instances[i], &device );
+        ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+
+        check_device_hid_serial( device, descs[i].serial_str );
+
+        IDirectInputDevice8_Release( device );
+        winetest_pop_context();
+    }
+
+    /* The cache is module-local, other dinput version will fail to find
+     * the devices, but it doesn't cause the list to be refreshed.
+     */
+    di2.version = 0x0500;
+    hr = dinput_create( &di2 );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+
+    hr = dinput_create_device( &di2, &expect_instances[0], &device );
+    if (version == 0x800) todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+    else ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr))
+    {
+        check_device_hid_serial( device, descs[0].serial_str );
+        IDirectInputDevice8_Release( device );
+    }
+
+    ref = dinput_release( &di2 );
+    ok( ref == 0, "Release returned %ld\n", ref );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    check_device_hid_serial( device, descs[0].serial_str );
+    IDirectInputDevice8_Release( device );
+
+
+    /*
+     * Call EnumDevices(), a new set of guidInstance values and registry entries
+     * will be created.
+     */
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 4, "Unexpected count %Iu.\n", instances_end - instances );
+
+    for (UINT i = 0; i < instances_end - instances; i++)
+    {
+        winetest_push_context( "device %d", i );
+
+        todo_wine ok( !IsEqualGUID( &expect_instances[i], &instances[i] ),
+                      "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) );
+
+        /* Old guidInstance no longer works. */
+        hr = dinput_create_device( &di, &expect_instances[i], &device );
+        todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+        if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+        expect_instances[i] = instances[i];
+
+        /* New guidInstance, same device. */
+        hr = dinput_create_device( &di, &instances[i], &device );
+        ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+
+        check_device_hid_serial( device, descs[i].serial_str );
+
+        IDirectInputDevice8_Release( device );
+        winetest_pop_context();
+    }
+
+
+    /* Opening a device with an unknown instance GUID will cause a refresh
+     * of the device list, the same was as calling EnumDevices.
+     */
+    cleanup_registry_keys();
+
+    instances[0] = instance_uuid_init;
+    instances[0].Data1 = 0xdeadbeef;
+    instances[0].Data2 = 0xdead;
+    instances[0].Data3 = 0xbeef;
+    hr = dinput_create_device( &di, &instances[0], &device );
+    ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 4, "Unexpected count %Iu.\n", instances_end - instances );
+    memcpy( expect_instances, instances, 4 * sizeof(*instances) );
+
+
+    /* Opening a device with an unknown product GUID will cause a refresh
+     * of the device list, the same was as calling EnumDevices.
+     */
+    cleanup_registry_keys();
+
+    instances[0] = expect_guid_product;
+    instances[0].Data1 = MAKELONG( LOWORD(EXPECT_VIDPID), 0x0003 );
+    hr = dinput_create_device( &di, &instances[0], &device );
+    ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 4, "Unexpected count %Iu.\n", instances_end - instances );
+    memcpy( expect_instances, instances, 4 * sizeof(*instances) );
+
+
+    /* Opening a cached device that has been unplugged fails but does
+     * not invalidate the cache, and other cached devices stay valid.
+     */
+    cleanup_registry_keys();
+    hid_device_stop( &descs[0], 1 );
+
+    hr = dinput_create_device( &di, &instances[1], &device );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    check_device_hid_serial( device, descs[1].serial_str );
+    IDirectInputDevice8_Release( device );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+    hr = dinput_create_device( &di, &instances[1], &device );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    check_device_hid_serial( device, descs[1].serial_str );
+    IDirectInputDevice8_Release( device );
+
+    hid_device_start( &descs[0], 1 );
+
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 4, "Unexpected count %Iu.\n", instances_end - instances );
+    memcpy( expect_instances, instances, 4 * sizeof(*instances) );
+
+
+    /*
+     * Stop devices 0 and 2. After enumeration, their guidInstance values will
+     * be assigned to devices 1 and 3.
+     */
+    hid_device_stop( &descs[0], 1 );
+    hid_device_stop( &descs[2], 1 );
+
+    /* Stopped devices should return E_FAIL. */
+    hr = dinput_create_device( &di, &instances[0], &device );
+    todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+    hr = dinput_create_device( &di, &instances[2], &device );
+    todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+    /* After calling EnumDevices(), guidInstance values will be reassigned. */
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 2, "Unexpected count %Iu.\n", instances_end - instances );
+
+    for (UINT i = 0; i < instances_end - instances; i++)
+    {
+        const unsigned int expected_joystick = !i ? 1 : 3;
+
+        winetest_push_context( "device %d", i );
+
+        todo_wine ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ),
+                      "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) );
+        hr = dinput_create_device( &di, &instances[i], &device );
+        ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+
+        check_device_hid_serial( device, descs[expected_joystick].serial_str );
+
+        IDirectInputDevice8_Release( device );
+        winetest_pop_context();
+    }
+
+    /*
+     * Restart devices 0 and 2, they should get their old guidInstance values
+     * back after another call to EnumDevices().
+     */
+    hid_device_start( &descs[0], 1 );
+    hid_device_start( &descs[2], 1 );
+
+    for (UINT i = 0; i < instances_end - instances; i++)
+    {
+        const unsigned int expected_joystick = !i ? 1 : 3;
+
+        winetest_push_context( "device %d", i );
+
+        todo_wine ok( IsEqualGUID( &expect_instances[expected_joystick - 1], &instances[i] ),
+                      "Unexpected instance %s.\n", debugstr_guid( &instances[i] ) );
+        hr = dinput_create_device( &di, &instances[i], &device );
+        ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+
+        check_device_hid_serial( device, descs[expected_joystick].serial_str );
+
+        IDirectInputDevice8_Release( device );
+        winetest_pop_context();
+    }
+
+    /* guidInstance values are all back to what they were. */
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances + 4, "Unexpected count %Iu.\n", instances_end - instances );
+
+    for (UINT i = 0; i < instances_end - instances; i++)
+    {
+        winetest_push_context( "device %d", i );
+
+        todo_wine_if( !(i & 0x1) )
+        ok( IsEqualGUID( &expect_instances[i], &instances[i] ),
+            "Unexpected guidInstance %s.\n", debugstr_guid( &instances[i] ) );
+
+        hr = dinput_create_device( &di, &instances[i], &device );
+        ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+
+        check_device_hid_serial( device, descs[i].serial_str );
+
+        IDirectInputDevice8_Release( device );
+        winetest_pop_context();
+    }
+
+    /* Stop all devices. */
+    hid_device_stop( descs, ARRAY_SIZE(descs) );
+
+
+    /*
+     * Call EnumDevices() with all devices stopped. Test behavior of device
+     * creation without calling EnumDevices() with the devices present
+     * beforehand.
+     */
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances, "Unexpected count %Iu.\n", instances_end - instances );
+
+    for (UINT i = 0; i < ARRAY_SIZE(descs); i++)
+    {
+        winetest_push_context( "device %d", i );
+
+        hr = dinput_create_device( &di, &expect_instances[i], &device );
+        ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+
+        /*
+         * Start the joystick device. This will succeed, even without having
+         * called EnumDevices() beforehand.
+         */
+        hid_device_start( &descs[i], 1 );
+
+        hr = dinput_create_device( &di, &expect_instances[i], &device );
+        todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+        if (SUCCEEDED(hr))
+        {
+            check_device_hid_serial( device, descs[i].serial_str );
+            IDirectInputDevice8_Release( device );
+        }
+        hid_device_stop( &descs[i], 1 );
+
+        hr = dinput_create_device( &di, &expect_instances[i], &device );
+        todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+        if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+        hid_device_start( &descs[i], 1 );
+        winetest_pop_context();
+    }
+
+    hid_device_stop( descs, ARRAY_SIZE(descs) );
+
+
+    /* Reset device list. */
+    instances_end = instances;
+    hr = dinput_enum_devices( &di, find_test_device_instances, &instances_end );
+    ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    ok( instances_end == instances, "Unexpected count %Iu.\n", instances_end - instances );
+
+
+    /*
+     * Start device 0, create a device with guidInstance 0.
+     * Stop device 0.
+     * Start device 1, attempt to create a device with guidInstance 1.
+     * Fails.
+     * Try to create a device with guidInstance 0, which is now associated
+     * with device 1.
+     */
+    hid_device_start( &descs[0], 1 );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr))
+    {
+        check_device_hid_serial( device, descs[0].serial_str );
+        IDirectInputDevice8_Release( device );
+    }
+    hid_device_stop( &descs[0], 1 );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+
+    /* Start device 1. */
+    hid_device_start( &descs[1], 1 );
+
+    /*
+     * This still fails with E_FAIL, as expect_instances[0] is still associated
+     * with device 0.
+     */
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_Release( device );
+
+    /*
+     * expect_instances[1] is not currently associated with a device, which
+     * means attempting to use this GUID results in what seems to be an
+     * internal call to EnumDevices(). With device 0 currently stopped,
+     * expect_instances[0] gets reassigned to device 1.
+     */
+    hr = dinput_create_device( &di, &expect_instances[1], &device );
+    ok( hr == DIERR_DEVICENOTREG, "Unexpected hr %#lx.\n", hr );
+
+    hr = dinput_create_device( &di, &expect_instances[0], &device );
+    todo_wine ok( hr == DI_OK, "Unexpected hr %#lx.\n", hr );
+    if (SUCCEEDED(hr))
+    {
+        check_device_hid_serial( device, descs[1].serial_str );
+        IDirectInputDevice8_Release( device );
+    }
+    hid_device_stop( &descs[1], 1 );
+
+
+done:
+    ref = dinput_release( &di );
+    ok( ref == 0, "Release returned %ld\n", ref );
+    cleanup_registry_keys();
+    winetest_pop_context();
+}
+
 START_TEST( joystick8 )
 {
     char **argv;
@@ -6006,6 +6511,10 @@ START_TEST( joystick8 )
         test_simple_joystick( 0x700 );
         test_simple_joystick( 0x800 );
 
+        test_joystick_instance_guid( 0x500 );
+        test_joystick_instance_guid( 0x700 );
+        test_joystick_instance_guid( 0x800 );
+
         test_many_axes_joystick();
         test_driving_wheel_axes();
         test_rawinput( argv );
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 43a9a8c4f919..b4032f5a6f03 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -330,7 +330,7 @@ static void downsample(LONG64 freq_adjust_num, LONG64 freq_adjust_den, LONG64 fr
         float input_value0 = (1.0f - rem) * input_value;
         float input_value1 = rem * input_value;
 
-        UINT i;
+        int i;
         for (i = 0; i < fir_width; ++i)
             output[opos + i] += fir[idx + i] * input_value0 + fir[idx + fir_width + i] * input_value1;
     }
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index db8e7f8ffd87..f6c2fe8146e0 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -2553,14 +2553,13 @@ static HRESULT fallback_map_characters(const struct dwrite_fontfallback *fallbac
         if (SUCCEEDED(create_matching_font(mapping->collection ? mapping->collection : fallback->systemcollection,
                 mapping->families[i], weight, style, stretch, &IID_IDWriteFont3, (void **)&font)))
         {
-            if (!(mapped = fallback_font_get_supported_length(font, source, position, mapped)))
+            if (!(*ret_length = fallback_font_get_supported_length(font, source, position, mapped)))
             {
                 IDWriteFont3_Release(font);
                 continue;
             }
 
             *ret_font = (IDWriteFont *)font;
-            *ret_length = mapped;
             *scale = mapping->scale;
 
             return S_OK;
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c
index 7b95ead9f55e..9adeeb64ebf3 100644
--- a/dlls/dwrite/opentype.c
+++ b/dlls/dwrite/opentype.c
@@ -1335,6 +1335,90 @@ static DWORD table_read_dword(const struct dwrite_fonttable *table, unsigned int
     return ptr ? *ptr : 0;
 }
 
+HRESULT opentype_try_get_font_table(const struct file_stream_desc *stream_desc, UINT32 tag, const void **table_data,
+    void **table_context, UINT32 *table_size, BOOL *found)
+{
+    void *table_directory_context, *sfnt_context;
+    const struct ot_table_record *table_record = NULL;
+    const struct ot_table_dir *table_dir = NULL;
+    UINT32 table_offset = 0;
+    UINT16 table_count;
+    HRESULT hr;
+
+    if (found) *found = FALSE;
+    if (table_size) *table_size = 0;
+
+    *table_data = NULL;
+    *table_context = NULL;
+
+    if (stream_desc->face_type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION)
+    {
+        const struct ttc_header *ttc_header;
+        void * ttc_context;
+
+        hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&ttc_header, 0,
+                sizeof(*ttc_header), &ttc_context);
+        if (SUCCEEDED(hr))
+        {
+            if (stream_desc->face_index >= GET_BE_DWORD(ttc_header->num_fonts))
+                hr = E_INVALIDARG;
+            else
+            {
+                table_offset = GET_BE_DWORD(ttc_header->offsets[stream_desc->face_index]);
+                hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_dir, table_offset,
+                        sizeof(*table_dir), &sfnt_context);
+            }
+            IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, ttc_context);
+        }
+    }
+    else
+        hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_dir, 0,
+                sizeof(*table_dir), &sfnt_context);
+
+    if (FAILED(hr))
+        return hr;
+
+    table_count = GET_BE_WORD(table_dir->numTables);
+    table_offset += sizeof(*table_dir);
+
+    IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, sfnt_context);
+
+    hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_record, table_offset,
+            table_count * sizeof(*table_record), &table_directory_context);
+    if (hr == S_OK)
+    {
+        UINT16 i;
+
+        for (i = 0; i < table_count; ++i)
+        {
+            if (table_record->tag == tag)
+            {
+                UINT32 offset = GET_BE_DWORD(table_record->offset);
+                UINT32 length = GET_BE_DWORD(table_record->length);
+
+                if (found)
+                    *found = TRUE;
+                if (table_size)
+                    *table_size = length;
+                hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, table_data, offset,
+                        length, table_context);
+                break;
+            }
+            table_record++;
+        }
+
+        IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_directory_context);
+    }
+
+    return hr;
+}
+
+static HRESULT opentype_get_font_table(const struct file_stream_desc *stream_desc, UINT32 tag,
+        struct dwrite_fonttable *table)
+{
+    return opentype_try_get_font_table(stream_desc, tag, (const void **)&table->data, &table->context, &table->size, &table->exists);
+}
+
 BOOL is_face_type_supported(DWRITE_FONT_FACE_TYPE type)
 {
     return (type == DWRITE_FONT_FACE_TYPE_CFF) ||
@@ -1372,6 +1456,9 @@ static HRESULT opentype_ttc_analyzer(IDWriteFontFileStream *stream, UINT32 *font
 static HRESULT opentype_ttf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
     DWRITE_FONT_FACE_TYPE *face_type)
 {
+    struct file_stream_desc stream_desc = { .stream = stream };
+    const struct colr_header *colr_header;
+    struct dwrite_fonttable colr;
     const DWORD *header;
     void *context;
     HRESULT hr;
@@ -1380,15 +1467,25 @@ static HRESULT opentype_ttf_analyzer(IDWriteFontFileStream *stream, UINT32 *font
     if (FAILED(hr))
         return hr;
 
-    if (GET_BE_DWORD(*header) == 0x10000) {
-        *font_count = 1;
-        *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
-        *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
-    }
+    if (GET_BE_DWORD(*header) == 0x10000)
+        stream_desc.face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
 
     IDWriteFontFileStream_ReleaseFileFragment(stream, context);
 
-    return *file_type != DWRITE_FONT_FILE_TYPE_UNKNOWN ? S_OK : S_FALSE;
+    if (stream_desc.face_type != DWRITE_FONT_FACE_TYPE_TRUETYPE)
+        return S_FALSE;
+
+    opentype_get_font_table(&stream_desc, MS_COLR_TAG, &colr);
+    if (colr.data && (colr_header = table_read_ensure(&colr, 0, sizeof(*header)))
+            && colr_header->version && !colr_header->num_baseglyph_records)
+    {
+        FIXME("COLR version %d, skipping font.\n", GET_BE_WORD(colr_header->version));
+        return S_FALSE;
+    }
+    *font_count = 1;
+    *file_type = DWRITE_FONT_FILE_TYPE_TRUETYPE;
+    *face_type = DWRITE_FONT_FACE_TYPE_TRUETYPE;
+    return S_OK;
 }
 
 static HRESULT opentype_otf_analyzer(IDWriteFontFileStream *stream, UINT32 *font_count, DWRITE_FONT_FILE_TYPE *file_type,
@@ -1526,90 +1623,6 @@ HRESULT opentype_analyze_font(IDWriteFontFileStream *stream, BOOL *supported, DW
     return S_OK;
 }
 
-HRESULT opentype_try_get_font_table(const struct file_stream_desc *stream_desc, UINT32 tag, const void **table_data,
-    void **table_context, UINT32 *table_size, BOOL *found)
-{
-    void *table_directory_context, *sfnt_context;
-    const struct ot_table_record *table_record = NULL;
-    const struct ot_table_dir *table_dir = NULL;
-    UINT32 table_offset = 0;
-    UINT16 table_count;
-    HRESULT hr;
-
-    if (found) *found = FALSE;
-    if (table_size) *table_size = 0;
-
-    *table_data = NULL;
-    *table_context = NULL;
-
-    if (stream_desc->face_type == DWRITE_FONT_FACE_TYPE_OPENTYPE_COLLECTION)
-    {
-        const struct ttc_header *ttc_header;
-        void * ttc_context;
-
-        hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&ttc_header, 0,
-                sizeof(*ttc_header), &ttc_context);
-        if (SUCCEEDED(hr))
-        {
-            if (stream_desc->face_index >= GET_BE_DWORD(ttc_header->num_fonts))
-                hr = E_INVALIDARG;
-            else
-            {
-                table_offset = GET_BE_DWORD(ttc_header->offsets[stream_desc->face_index]);
-                hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_dir, table_offset,
-                        sizeof(*table_dir), &sfnt_context);
-            }
-            IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, ttc_context);
-        }
-    }
-    else
-        hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_dir, 0,
-                sizeof(*table_dir), &sfnt_context);
-
-    if (FAILED(hr))
-        return hr;
-
-    table_count = GET_BE_WORD(table_dir->numTables);
-    table_offset += sizeof(*table_dir);
-
-    IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, sfnt_context);
-
-    hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, (const void **)&table_record, table_offset,
-            table_count * sizeof(*table_record), &table_directory_context);
-    if (hr == S_OK)
-    {
-        UINT16 i;
-
-        for (i = 0; i < table_count; ++i)
-        {
-            if (table_record->tag == tag)
-            {
-                UINT32 offset = GET_BE_DWORD(table_record->offset);
-                UINT32 length = GET_BE_DWORD(table_record->length);
-
-                if (found)
-                    *found = TRUE;
-                if (table_size)
-                    *table_size = length;
-                hr = IDWriteFontFileStream_ReadFileFragment(stream_desc->stream, table_data, offset,
-                        length, table_context);
-                break;
-            }
-            table_record++;
-        }
-
-        IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, table_directory_context);
-    }
-
-    return hr;
-}
-
-static HRESULT opentype_get_font_table(const struct file_stream_desc *stream_desc, UINT32 tag,
-        struct dwrite_fonttable *table)
-{
-    return opentype_try_get_font_table(stream_desc, tag, (const void **)&table->data, &table->context, &table->size, &table->exists);
-}
-
 /**********
  * CMAP
  **********/
diff --git a/dlls/gdi32/tests/font.c b/dlls/gdi32/tests/font.c
index 81bc5a2f77c1..c56180b1ce6c 100644
--- a/dlls/gdi32/tests/font.c
+++ b/dlls/gdi32/tests/font.c
@@ -7998,7 +7998,7 @@ static void test_add_font_path(void)
         todo_wine ok( !wcscmp( path, L"C:\\WINDOWS\\SYSTEM32\\WINETEST_FONT.TTF" ),
             "got %s\n", debugstr_w( path ));
         ret = RemoveFontResourceExA( "winetest_font.ttf", 0, NULL );
-        todo_wine ok( ret, "got error %lu\n", GetLastError() );
+        ok( ret, "got error %lu\n", GetLastError() );
     }
 
     ret = DeleteFileA( system32_path );
diff --git a/dlls/gdi32/text.c b/dlls/gdi32/text.c
index 52fac7838016..0b58abe8ce15 100644
--- a/dlls/gdi32/text.c
+++ b/dlls/gdi32/text.c
@@ -2530,6 +2530,27 @@ static void redirect_path( UNICODE_STRING *path )
 #endif
 }
 
+static BOOL get_system_dir_path( UNICODE_STRING *path, const WCHAR *str )
+{
+    WCHAR *system_dir;
+
+    if (!(system_dir = malloc( (MAX_PATH + 1 + wcslen( str )) * sizeof(WCHAR) ))) return FALSE;
+    GetSystemDirectoryW( system_dir, MAX_PATH );
+    wcscat( system_dir, L"\\" );
+    wcscat( system_dir, str );
+    if (!RtlDosPathNameToNtPathName_U( system_dir, path, NULL, NULL ))
+    {
+        free( system_dir );
+        return FALSE;
+    }
+
+    /* Windows does not redirect the path here, which is presumably a bug.
+     * Stratego (1997) tries to create a font resource in system32
+     * and fails on 64-bit Windows. */
+    redirect_path( path );
+    return TRUE;
+}
+
 static int add_font_resource( const WCHAR *str, DWORD flags, void *dv )
 {
     UNICODE_STRING nt_name;
@@ -2542,26 +2563,11 @@ static int add_font_resource( const WCHAR *str, DWORD flags, void *dv )
     if (!ret && !wcschr( str, '\\' ))
     {
         /* try as system font */
-        WCHAR *system_dir;
 
         if ((ret = NtGdiAddFontResourceW( str, wcslen( str ) + 1, 1, flags, 0, dv )))
             return ret;
 
-        if (!(system_dir = malloc( (MAX_PATH + 1 + wcslen( str )) * sizeof(WCHAR) )))
-            return 0;
-        GetSystemDirectoryW( system_dir, MAX_PATH + 1 + wcslen( str ));
-        wcscat( system_dir, L"\\" );
-        wcscat( system_dir, str );
-        if (!RtlDosPathNameToNtPathName_U( system_dir, &nt_name, NULL, NULL ))
-        {
-            free( system_dir );
-            return 0;
-        }
-
-        /* Windows does not redirect the path here, which is presumably a bug.
-         * Stratego (1997) tries to create a font resource in system32
-         * and fails on 64-bit Windows. */
-        redirect_path( &nt_name );
+        if (!get_system_dir_path( &nt_name, str )) return 0;
 
         ret = NtGdiAddFontResourceW( nt_name.Buffer, nt_name.Length / sizeof(WCHAR) + 1,
                                      1, flags, 0, dv );
@@ -2602,21 +2608,12 @@ static int remove_font_resource( const WCHAR *str, DWORD flags, void *dv )
     if (!ret && !wcschr( str, '\\' ))
     {
         /* try as system font */
-        WCHAR *system_dir;
 
         if ((ret = NtGdiRemoveFontResourceW( str, wcslen( str ) + 1, 1, flags, 0, dv )))
             return ret;
 
-        if (!(system_dir = malloc( (MAX_PATH + 1 + wcslen( str )) * sizeof(WCHAR) )))
-            return 0;
-        GetSystemDirectoryW( system_dir, MAX_PATH + 1 + wcslen( str ));
-        wcscat( system_dir, L"\\" );
-        wcscat( system_dir, str );
-        if (!RtlDosPathNameToNtPathName_U( system_dir, &nt_name, NULL, NULL ))
-        {
-            free( system_dir );
-            return 0;
-        }
+        if (!get_system_dir_path( &nt_name, str )) return 0;
+
         ret = NtGdiRemoveFontResourceW( nt_name.Buffer, nt_name.Length / sizeof(WCHAR) + 1,
                                         1, flags, 0, dv );
         RtlFreeUnicodeString( &nt_name );
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 035db159d5bc..d8a63a1d39af 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -2223,8 +2223,12 @@ GpStatus WINGDIPAPI GdipGetImageHeight(GpImage *image, UINT *height)
         return InvalidParameter;
 
     if(image->type == ImageTypeMetafile)
+    {
+        if(!((GpMetafile*)image)->hemf)
+            return InvalidParameter;
         *height = units_to_pixels(((GpMetafile*)image)->bounds.Height, ((GpMetafile*)image)->unit,
                                   image->yres, ((GpMetafile*)image)->printer_display);
+    }
     else if(image->type == ImageTypeBitmap)
         *height = ((GpBitmap*)image)->height;
     else
@@ -2243,6 +2247,9 @@ GpStatus WINGDIPAPI GdipGetImageHorizontalResolution(GpImage *image, REAL *res)
     if(!image || !res)
         return InvalidParameter;
 
+    if((image->type == ImageTypeMetafile) && !((GpMetafile*)image)->hemf)
+        return InvalidParameter;
+
     *res = image->xres;
 
     TRACE("(%p) <-- %0.2f\n", image, *res);
@@ -2318,6 +2325,9 @@ GpStatus WINGDIPAPI GdipGetImageVerticalResolution(GpImage *image, REAL *res)
     if(!image || !res)
         return InvalidParameter;
 
+    if((image->type == ImageTypeMetafile) && !((GpMetafile*)image)->hemf)
+        return InvalidParameter;
+
     *res = image->yres;
 
     TRACE("(%p) <-- %0.2f\n", image, *res);
@@ -2333,8 +2343,12 @@ GpStatus WINGDIPAPI GdipGetImageWidth(GpImage *image, UINT *width)
         return InvalidParameter;
 
     if(image->type == ImageTypeMetafile)
+    {
+        if(!((GpMetafile*)image)->hemf)
+            return InvalidParameter;
         *width = units_to_pixels(((GpMetafile*)image)->bounds.Width, ((GpMetafile*)image)->unit,
                                  image->xres, ((GpMetafile*)image)->printer_display);
+    }
     else if(image->type == ImageTypeBitmap)
         *width = ((GpBitmap*)image)->width;
     else
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index a786297a40bf..20adc83b95f6 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -1709,8 +1709,8 @@ GpStatus METAFILE_GraphicsDeleted(GpMetafile* metafile)
 
                 af_min->X = fmin(af_min->X, gdi_bounds_rc.left);
                 af_min->Y = fmin(af_min->Y, gdi_bounds_rc.top);
-                af_max->X = fmax(af_max->X, gdi_bounds_rc.right);
-                af_max->Y = fmax(af_max->Y, gdi_bounds_rc.bottom);
+                af_max->X = fmax(af_max->X, gdi_bounds_rc.right + 1);
+                af_max->Y = fmax(af_max->Y, gdi_bounds_rc.bottom + 1);
             }
 
             bounds_rc.left = floorf(metafile->auto_frame_min.X * x_scale);
diff --git a/dlls/gdiplus/tests/metafile.c b/dlls/gdiplus/tests/metafile.c
index 401b3ea6bac4..9ee052b23d3e 100644
--- a/dlls/gdiplus/tests/metafile.c
+++ b/dlls/gdiplus/tests/metafile.c
@@ -1427,8 +1427,7 @@ static void test_nullframerect(void) {
     expect(UnitPixel, unit);
     expectf_(20.0, bounds.X, 0.05);
     expectf_(25.0, bounds.Y, 0.05);
-    expectf_(55.0, bounds.Width, 1.00);
-    todo_wine expectf_(55.0, bounds.Width, 0.05);
+    expectf_(55.0, bounds.Width, 0.05);
     expectf_(85.0, bounds.Height, 0.05);
 
     stat = GdipDisposeImage((GpImage*)metafile);
@@ -1478,16 +1477,16 @@ static void test_pagetransform(void)
         return;
 
     stat = GdipGetImageHorizontalResolution((GpImage*)metafile, &dpix);
-    todo_wine expect(InvalidParameter, stat);
+    expect(InvalidParameter, stat);
 
     stat = GdipGetImageVerticalResolution((GpImage*)metafile, &dpiy);
-    todo_wine expect(InvalidParameter, stat);
+    expect(InvalidParameter, stat);
 
     stat = GdipGetImageWidth((GpImage*)metafile, &width);
-    todo_wine expect(InvalidParameter, stat);
+    expect(InvalidParameter, stat);
 
     stat = GdipGetImageHeight((GpImage*)metafile, &height);
-    todo_wine expect(InvalidParameter, stat);
+    expect(InvalidParameter, stat);
 
     stat = GdipGetImageGraphicsContext((GpImage*)metafile, &graphics);
     expect(Ok, stat);
diff --git a/dlls/iertutil/Makefile.in b/dlls/iertutil/Makefile.in
index ba633d5ee729..769dea3cea6b 100644
--- a/dlls/iertutil/Makefile.in
+++ b/dlls/iertutil/Makefile.in
@@ -1,6 +1,9 @@
 MODULE = iertutil.dll
-IMPORTS = combase
+IMPORTLIB = iertutil
+IMPORTS = ole32 oleaut32 rpcrt4 shlwapi combase
 
 SOURCES = \
 	classes.idl \
-	main.c
+	iertutil_classes.idl \
+	main.c \
+	uri.c
diff --git a/dlls/iertutil/iertutil.spec b/dlls/iertutil/iertutil.spec
index 20a8bfa98eae..b156844ade01 100644
--- a/dlls/iertutil/iertutil.spec
+++ b/dlls/iertutil/iertutil.spec
@@ -1,3 +1,9 @@
+@ stdcall CreateIUriBuilder(ptr long long ptr)
+@ stdcall CreateUri(wstr long long ptr)
+@ stdcall CreateUriWithFragment(wstr wstr long long ptr)
 @ stdcall -private DllCanUnloadNow()
 @ stdcall -private DllGetActivationFactory(ptr ptr)
 @ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall PrivateCoInternetCombineIUri(ptr ptr long ptr long)
+@ stdcall PrivateCoInternetParseIUri(ptr long long ptr long ptr long)
+@ stdcall wine_get_canonicalized_uri(ptr)
diff --git a/dlls/iertutil/iertutil_classes.idl b/dlls/iertutil/iertutil_classes.idl
new file mode 100644
index 000000000000..61beaa42869b
--- /dev/null
+++ b/dlls/iertutil/iertutil_classes.idl
@@ -0,0 +1,31 @@
+/*
+ * COM classes for iertutil.dll
+ *
+ * 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
+ */
+
+#pragma makedep header
+#pragma makedep register
+
+import "urlmon.idl";
+
+[
+    helpstring("CUri"),
+    threading(apartment),
+    uuid(df2fce13-25ec-45bb-9d4c-cecd47c2430c)
+]
+coclass CUri {interface IUri;}
diff --git a/dlls/iertutil/main.c b/dlls/iertutil/main.c
index 70f8d4dcb990..fd6dd3c93729 100644
--- a/dlls/iertutil/main.c
+++ b/dlls/iertutil/main.c
@@ -17,6 +17,7 @@
  */
 
 #include "private.h"
+#include "iertutil_classes.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(iertutil);
 
@@ -390,9 +391,89 @@ static struct iertutil iertutil =
     1
 };
 
+typedef struct
+{
+    IClassFactory IClassFactory_iface;
+    HRESULT (*pfnCreateInstance)(IUnknown *pUnkOuter, LPVOID *ppObj);
+} ClassFactory;
+
+static inline ClassFactory *impl_from_IClassFactory(IClassFactory *iface)
+{
+    return CONTAINING_RECORD(iface, ClassFactory, IClassFactory_iface);
+}
+
+static HRESULT WINAPI CF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IClassFactory))
+    {
+        *ppv = iface;
+        return S_OK;
+    }
+
+    WARN("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI CF_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+
+static ULONG WINAPI CF_Release(IClassFactory *iface)
+{
+    return 1;
+}
+
+static HRESULT WINAPI CF_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid,
+                                        void **ppv)
+{
+    ClassFactory *This = impl_from_IClassFactory(iface);
+    IUnknown *unk;
+    HRESULT hr;
+
+    TRACE("(%p)->(%p %s %p)\n", iface, outer, debugstr_guid(riid), ppv);
+
+    *ppv = NULL;
+
+    if (outer && !IsEqualGUID(riid, &IID_IUnknown))
+        return CLASS_E_NOAGGREGATION;
+
+    hr = This->pfnCreateInstance(outer, (void **)&unk);
+    if (FAILED(hr))
+        return hr;
+
+    hr = IUnknown_QueryInterface(unk, riid, ppv);
+    IUnknown_Release(unk);
+    return hr;
+}
+
+static HRESULT WINAPI CF_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    TRACE("(%d)\n", dolock);
+    return S_OK;
+}
+
+static const IClassFactoryVtbl ClassFactoryVtbl =
+{
+    CF_QueryInterface,
+    CF_AddRef,
+    CF_Release,
+    CF_CreateInstance,
+    CF_LockServer
+};
+
+static ClassFactory CUriCF = {{&ClassFactoryVtbl}, Uri_Construct};
+
 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID riid, void **out)
 {
-    FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid), debugstr_guid(riid), out);
+    TRACE("clsid %s, riid %s, out %p.\n", debugstr_guid(clsid), debugstr_guid(riid), out);
+
+    if (IsEqualGUID(clsid, &CLSID_CUri))
+        return IClassFactory_QueryInterface(&CUriCF.IClassFactory_iface, riid, out);
+
+    FIXME("%s: no class found.\n", debugstr_guid(clsid));
     return CLASS_E_CLASSNOTAVAILABLE;
 }
 
diff --git a/dlls/iertutil/private.h b/dlls/iertutil/private.h
index 80b36886a7a1..5c416aba80a2 100644
--- a/dlls/iertutil/private.h
+++ b/dlls/iertutil/private.h
@@ -22,7 +22,6 @@
 #include <stdarg.h>
 
 #define COBJMACROS
-#include "initguid.h"
 #include "windef.h"
 #include "winbase.h"
 #include "winstring.h"
@@ -72,4 +71,6 @@
     DEFINE_IINSPECTABLE_(pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, \
                          &impl->base_iface)
 
+extern HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj);
+
 #endif /* __WINE_IERTUTIL_PRIVATE_H */
diff --git a/dlls/iertutil/uri.c b/dlls/iertutil/uri.c
new file mode 100644
index 000000000000..bdf9f104e42d
--- /dev/null
+++ b/dlls/iertutil/uri.c
@@ -0,0 +1,6945 @@
+/*
+ * Copyright 2010 Jacek Caban for CodeWeavers
+ * Copyright 2010 Thomas Mullaly
+ *
+ * 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 <limits.h>
+#include <stdarg.h>
+#include <wchar.h>
+
+#define COBJMACROS
+
+#include "initguid.h"
+#include "private.h"
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "ole2.h"
+#include "urlmon.h"
+#include "wininet.h"
+#include "wine/debug.h"
+
+#define NO_SHLWAPI_REG
+#include "shlwapi.h"
+
+#include "strsafe.h"
+#include "winternl.h"
+#include "inaddr.h"
+#include "in6addr.h"
+#include "ip2string.h"
+#include "iertutil_classes.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(iertutil);
+
+#define URI_DISPLAY_NO_ABSOLUTE_URI      0x1
+#define URI_DISPLAY_NO_DEFAULT_PORT_AUTH 0x2
+
+#define ALLOW_NULL_TERM_SCHEME           0x01
+#define ALLOW_NULL_TERM_USER_NAME        0x02
+#define ALLOW_NULL_TERM_PASSWORD         0x04
+#define ALLOW_BRACKETLESS_IP_LITERAL     0x08
+#define SKIP_IP_FUTURE_CHECK             0x10
+#define IGNORE_PORT_DELIMITER            0x20
+
+#define RAW_URI_FORCE_PORT_DISP          0x1
+#define RAW_URI_CONVERT_TO_DOS_PATH      0x2
+
+#define COMBINE_URI_FORCE_FLAG_USE       0x1
+
+static const IID IID_IUriObj = {0x4b364760,0x9f51,0x11df,{0x98,0x1c,0x08,0x00,0x20,0x0c,0x9a,0x66}};
+
+typedef struct {
+    IUri                IUri_iface;
+    IUriBuilderFactory  IUriBuilderFactory_iface;
+    IPersistStream      IPersistStream_iface;
+    IMarshal            IMarshal_iface;
+
+    LONG ref;
+
+    BSTR            raw_uri;
+
+    /* Information about the canonicalized URI's buffer. */
+    WCHAR           *canon_uri;
+    DWORD           canon_size;
+    DWORD           canon_len;
+    BOOL            display_modifiers;
+    DWORD           create_flags;
+
+    INT             scheme_start;
+    DWORD           scheme_len;
+    URL_SCHEME      scheme_type;
+
+    INT             userinfo_start;
+    DWORD           userinfo_len;
+    INT             userinfo_split;
+
+    INT             host_start;
+    DWORD           host_len;
+    Uri_HOST_TYPE   host_type;
+
+    INT             port_offset;
+    DWORD           port;
+    BOOL            has_port;
+
+    INT             authority_start;
+    DWORD           authority_len;
+
+    INT             domain_offset;
+
+    INT             path_start;
+    DWORD           path_len;
+    INT             extension_offset;
+
+    INT             query_start;
+    DWORD           query_len;
+
+    INT             fragment_start;
+    DWORD           fragment_len;
+} Uri;
+
+typedef struct {
+    IUriBuilder IUriBuilder_iface;
+    LONG ref;
+
+    Uri *uri;
+    DWORD modified_props;
+
+    WCHAR   *fragment;
+    DWORD   fragment_len;
+
+    WCHAR   *host;
+    DWORD   host_len;
+
+    WCHAR   *password;
+    DWORD   password_len;
+
+    WCHAR   *path;
+    DWORD   path_len;
+
+    BOOL    has_port;
+    DWORD   port;
+
+    WCHAR   *query;
+    DWORD   query_len;
+
+    WCHAR   *scheme;
+    DWORD   scheme_len;
+
+    WCHAR   *username;
+    DWORD   username_len;
+} UriBuilder;
+
+typedef struct {
+    BSTR            uri;
+
+    BOOL            is_relative;
+    BOOL            is_opaque;
+    BOOL            has_implicit_scheme;
+    BOOL            has_implicit_ip;
+    UINT            implicit_ipv4;
+    BOOL            must_have_path;
+
+    const WCHAR     *scheme;
+    DWORD           scheme_len;
+    URL_SCHEME      scheme_type;
+
+    const WCHAR     *username;
+    DWORD           username_len;
+
+    const WCHAR     *password;
+    DWORD           password_len;
+
+    const WCHAR     *host;
+    DWORD           host_len;
+    Uri_HOST_TYPE   host_type;
+
+    IN6_ADDR        ipv6_address;
+
+    BOOL            has_port;
+    const WCHAR     *port;
+    DWORD           port_len;
+    DWORD           port_value;
+
+    const WCHAR     *path;
+    DWORD           path_len;
+
+    const WCHAR     *query;
+    DWORD           query_len;
+
+    const WCHAR     *fragment;
+    DWORD           fragment_len;
+} parse_data;
+
+static const CHAR hexDigits[] = "0123456789ABCDEF";
+
+/* List of scheme types/scheme names that are recognized by the IUri interface as of IE 7. */
+static const struct {
+    URL_SCHEME  scheme;
+    WCHAR       scheme_name[16];
+} recognized_schemes[] = {
+    {URL_SCHEME_FTP,            L"ftp"},
+    {URL_SCHEME_HTTP,           L"http"},
+    {URL_SCHEME_GOPHER,         L"gopher"},
+    {URL_SCHEME_MAILTO,         L"mailto"},
+    {URL_SCHEME_NEWS,           L"news"},
+    {URL_SCHEME_NNTP,           L"nntp"},
+    {URL_SCHEME_TELNET,         L"telnet"},
+    {URL_SCHEME_WAIS,           L"wais"},
+    {URL_SCHEME_FILE,           L"file"},
+    {URL_SCHEME_MK,             L"mk"},
+    {URL_SCHEME_HTTPS,          L"https"},
+    {URL_SCHEME_SHELL,          L"shell"},
+    {URL_SCHEME_SNEWS,          L"snews"},
+    {URL_SCHEME_LOCAL,          L"local"},
+    {URL_SCHEME_JAVASCRIPT,     L"javascript"},
+    {URL_SCHEME_VBSCRIPT,       L"vbscript"},
+    {URL_SCHEME_ABOUT,          L"about"},
+    {URL_SCHEME_RES,            L"res"},
+    {URL_SCHEME_MSSHELLROOTED,  L"ms-shell-rooted"},
+    {URL_SCHEME_MSSHELLIDLIST,  L"ms-shell-idlist"},
+    {URL_SCHEME_MSHELP,         L"hcp"},
+    {URL_SCHEME_WILDCARD,       L"*"}
+};
+
+/* List of default ports Windows recognizes. */
+static const struct {
+    URL_SCHEME  scheme;
+    USHORT      port;
+} default_ports[] = {
+    {URL_SCHEME_FTP,    21},
+    {URL_SCHEME_HTTP,   80},
+    {URL_SCHEME_GOPHER, 70},
+    {URL_SCHEME_NNTP,   119},
+    {URL_SCHEME_TELNET, 23},
+    {URL_SCHEME_WAIS,   210},
+    {URL_SCHEME_HTTPS,  443},
+};
+
+/* List of 3-character top level domain names Windows seems to recognize.
+ * There might be more, but, these are the only ones I've found so far.
+ */
+static const struct {
+    WCHAR tld_name[4];
+} recognized_tlds[] = {
+    {L"com"},
+    {L"edu"},
+    {L"gov"},
+    {L"int"},
+    {L"mil"},
+    {L"net"},
+    {L"org"}
+};
+
+static Uri *get_uri_obj(IUri *uri)
+{
+    Uri *ret;
+    HRESULT hres;
+
+    hres = IUri_QueryInterface(uri, &IID_IUriObj, (void**)&ret);
+    return SUCCEEDED(hres) ? ret : NULL;
+}
+
+/* Wine internal export for urlmon.dll for getting the canonicalized URI from an IUri */
+const WCHAR * WINAPI wine_get_canonicalized_uri(IUri *uri)
+{
+    const Uri *obj = get_uri_obj(uri);
+    return obj ? obj->canon_uri : NULL;
+}
+
+static inline BOOL is_alpha(WCHAR val) {
+    return ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'));
+}
+
+static inline BOOL is_num(WCHAR val) {
+    return (val >= '0' && val <= '9');
+}
+
+static inline BOOL is_drive_path(const WCHAR *str) {
+    return (is_alpha(str[0]) && (str[1] == ':' || str[1] == '|'));
+}
+
+static inline BOOL is_unc_path(const WCHAR *str) {
+    return (str[0] == '\\' && str[1] == '\\');
+}
+
+static inline BOOL is_forbidden_dos_path_char(WCHAR val) {
+    return (val == '>' || val == '<' || val == '\"');
+}
+
+/* A URI is implicitly a file path if it begins with
+ * a drive letter (e.g. X:) or starts with "\\" (UNC path).
+ */
+static inline BOOL is_implicit_file_path(const WCHAR *str) {
+    return (is_unc_path(str) || (is_alpha(str[0]) && str[1] == ':'));
+}
+
+/* Checks if the URI is a hierarchical URI. A hierarchical
+ * URI is one that has "//" after the scheme.
+ */
+static BOOL check_hierarchical(const WCHAR **ptr) {
+    const WCHAR *start = *ptr;
+
+    if(**ptr != '/')
+        return FALSE;
+
+    ++(*ptr);
+    if(**ptr != '/') {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    return TRUE;
+}
+
+/* unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~" */
+static inline BOOL is_unreserved(WCHAR val) {
+    return (is_alpha(val) || is_num(val) || val == '-' || val == '.' ||
+            val == '_' || val == '~');
+}
+
+/* sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
+ *               / "*" / "+" / "," / ";" / "="
+ */
+static inline BOOL is_subdelim(WCHAR val) {
+    return (val == '!' || val == '$' || val == '&' ||
+            val == '\'' || val == '(' || val == ')' ||
+            val == '*' || val == '+' || val == ',' ||
+            val == ';' || val == '=');
+}
+
+/* gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@" */
+static inline BOOL is_gendelim(WCHAR val) {
+    return (val == ':' || val == '/' || val == '?' ||
+            val == '#' || val == '[' || val == ']' ||
+            val == '@');
+}
+
+/* Characters that delimit the end of the authority
+ * section of a URI. Sometimes a '\\' is considered
+ * an authority delimiter.
+ */
+static inline BOOL is_auth_delim(WCHAR val, BOOL acceptSlash) {
+    return (val == '#' || val == '/' || val == '?' ||
+            val == '\0' || (acceptSlash && val == '\\'));
+}
+
+/* reserved = gen-delims / sub-delims */
+static inline BOOL is_reserved(WCHAR val) {
+    return (is_subdelim(val) || is_gendelim(val));
+}
+
+static inline BOOL is_hexdigit(WCHAR val) {
+    return ((val >= 'a' && val <= 'f') ||
+            (val >= 'A' && val <= 'F') ||
+            (val >= '0' && val <= '9'));
+}
+
+static inline BOOL is_path_delim(URL_SCHEME scheme, WCHAR val) {
+    return (!val || (val == '#' && scheme != URL_SCHEME_FILE) || val == '?');
+}
+
+static inline BOOL is_slash(WCHAR c)
+{
+    return c == '/' || c == '\\';
+}
+
+static inline BOOL is_ascii(WCHAR c)
+{
+    return c < 0x80;
+}
+
+static BOOL is_default_port(URL_SCHEME scheme, DWORD port) {
+    DWORD i;
+
+    for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
+        if(default_ports[i].scheme == scheme && default_ports[i].port)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+/* List of schemes types Windows seems to expect to be hierarchical. */
+static inline BOOL is_hierarchical_scheme(URL_SCHEME type) {
+    return(type == URL_SCHEME_HTTP || type == URL_SCHEME_FTP ||
+           type == URL_SCHEME_GOPHER || type == URL_SCHEME_NNTP ||
+           type == URL_SCHEME_TELNET || type == URL_SCHEME_WAIS ||
+           type == URL_SCHEME_FILE || type == URL_SCHEME_HTTPS ||
+           type == URL_SCHEME_RES);
+}
+
+/* Checks if 'flags' contains an invalid combination of Uri_CREATE flags. */
+static inline BOOL has_invalid_flag_combination(DWORD flags) {
+    return((flags & Uri_CREATE_DECODE_EXTRA_INFO && flags & Uri_CREATE_NO_DECODE_EXTRA_INFO) ||
+           (flags & Uri_CREATE_CANONICALIZE && flags & Uri_CREATE_NO_CANONICALIZE) ||
+           (flags & Uri_CREATE_CRACK_UNKNOWN_SCHEMES && flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES) ||
+           (flags & Uri_CREATE_PRE_PROCESS_HTML_URI && flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI) ||
+           (flags & Uri_CREATE_IE_SETTINGS && flags & Uri_CREATE_NO_IE_SETTINGS));
+}
+
+/* Applies each default Uri_CREATE flags to 'flags' if it
+ * doesn't cause a flag conflict.
+ */
+static void apply_default_flags(DWORD *flags) {
+    if(!(*flags & Uri_CREATE_NO_CANONICALIZE))
+        *flags |= Uri_CREATE_CANONICALIZE;
+    if(!(*flags & Uri_CREATE_NO_DECODE_EXTRA_INFO))
+        *flags |= Uri_CREATE_DECODE_EXTRA_INFO;
+    if(!(*flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES))
+        *flags |= Uri_CREATE_CRACK_UNKNOWN_SCHEMES;
+    if(!(*flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI))
+        *flags |= Uri_CREATE_PRE_PROCESS_HTML_URI;
+    if(!(*flags & Uri_CREATE_IE_SETTINGS))
+        *flags |= Uri_CREATE_NO_IE_SETTINGS;
+}
+
+/* Determines if the URI is hierarchical using the information already parsed into
+ * data and using the current location of parsing in the URI string.
+ *
+ * Windows considers a URI hierarchical if one of the following is true:
+ *  A.) It's a wildcard scheme.
+ *  B.) It's an implicit file scheme.
+ *  C.) It's a known hierarchical scheme and it has two '\\' after the scheme name.
+ *      (the '\\' will be converted into "//" during canonicalization).
+ *  D.) "//" appears after the scheme name (or at the beginning if no scheme is given).
+ */
+static inline BOOL is_hierarchical_uri(const WCHAR **ptr, const parse_data *data) {
+    const WCHAR *start = *ptr;
+
+    if(data->scheme_type == URL_SCHEME_WILDCARD)
+        return TRUE;
+    else if(data->scheme_type == URL_SCHEME_FILE && data->has_implicit_scheme)
+        return TRUE;
+    else if(is_hierarchical_scheme(data->scheme_type) && (*ptr)[0] == '\\' && (*ptr)[1] == '\\') {
+        *ptr += 2;
+        return TRUE;
+    } else if(data->scheme_type != URL_SCHEME_MAILTO && check_hierarchical(ptr))
+        return TRUE;
+
+    *ptr = start;
+    return FALSE;
+}
+
+/* Taken from dlls/jscript/lex.c */
+static int hex_to_int(WCHAR val) {
+    if(val >= '0' && val <= '9')
+        return val - '0';
+    else if(val >= 'a' && val <= 'f')
+        return val - 'a' + 10;
+    else if(val >= 'A' && val <= 'F')
+        return val - 'A' + 10;
+
+    return -1;
+}
+
+/* Helper function for converting a percent encoded string
+ * representation of a WCHAR value into its actual WCHAR value. If
+ * the two characters following the '%' aren't valid hex values then
+ * this function returns the NULL character.
+ *
+ * E.g.
+ *  "%2E" will result in '.' being returned by this function.
+ */
+static WCHAR decode_pct_val(const WCHAR *ptr) {
+    WCHAR ret = '\0';
+
+    if(*ptr == '%' && is_hexdigit(*(ptr + 1)) && is_hexdigit(*(ptr + 2))) {
+        INT a = hex_to_int(*(ptr + 1));
+        INT b = hex_to_int(*(ptr + 2));
+
+        ret = a << 4;
+        ret += b;
+    }
+
+    return ret;
+}
+
+/* Helper function for percent encoding a given character
+ * and storing the encoded value into a given buffer (dest).
+ *
+ * It's up to the calling function to ensure that there is
+ * at least enough space in 'dest' for the percent encoded
+ * value to be stored (so dest + 3 spaces available).
+ */
+static inline void pct_encode_val(WCHAR val, WCHAR *dest) {
+    dest[0] = '%';
+    dest[1] = hexDigits[(val >> 4) & 0xf];
+    dest[2] = hexDigits[val & 0xf];
+}
+
+/* Attempts to parse the domain name from the host.
+ *
+ * This function also includes the Top-level Domain (TLD) name
+ * of the host when it tries to find the domain name. If it finds
+ * a valid domain name it will assign 'domain_start' the offset
+ * into 'host' where the domain name starts.
+ *
+ * It's implied that if there is a domain name its range is:
+ * [host+domain_start, host+host_len).
+ */
+static void find_domain_name(const WCHAR *host, DWORD host_len,
+                             INT *domain_start) {
+    const WCHAR *last_tld, *sec_last_tld, *end, *p;
+
+    end = host+host_len-1;
+
+    *domain_start = -1;
+
+    /* There has to be at least enough room for a '.' followed by a
+     * 3-character TLD for a domain to even exist in the host name.
+     */
+    if(host_len < 4)
+        return;
+
+    for (last_tld = sec_last_tld = NULL, p = host; p <= end; p++)
+    {
+        if (*p == '.')
+        {
+            sec_last_tld = last_tld;
+            last_tld = p;
+        }
+    }
+    if(!last_tld)
+        /* http://hostname -> has no domain name. */
+        return;
+
+    if(!sec_last_tld) {
+        /* If the '.' is at the beginning of the host there
+         * has to be at least 3 characters in the TLD for it
+         * to be valid.
+         *  Ex: .com -> .com as the domain name.
+         *      .co  -> has no domain name.
+         */
+        if(last_tld-host == 0) {
+            if(end-(last_tld-1) < 3)
+                return;
+        } else if(last_tld-host == 3) {
+            DWORD i;
+
+            /* If there are three characters in front of last_tld and
+             * they are on the list of recognized TLDs, then this
+             * host doesn't have a domain (since the host only contains
+             * a TLD name.
+             *  Ex: edu.uk -> has no domain name.
+             *      foo.uk -> foo.uk as the domain name.
+             */
+            for(i = 0; i < ARRAY_SIZE(recognized_tlds); ++i) {
+                if(!StrCmpNIW(host, recognized_tlds[i].tld_name, 3))
+                    return;
+            }
+        } else if(last_tld-host < 3)
+        {
+            /* Anything less than 3 ASCII characters is considered part
+             * of the TLD name.
+             *  Ex: ak.uk -> Has no domain name.
+             */
+            for(p = host; p < last_tld; p++) {
+                if(!is_ascii(*p))
+                    break;
+            }
+
+            if(p == last_tld)
+                return;
+        }
+
+        /* Otherwise the domain name is the whole host name. */
+        *domain_start = 0;
+    } else if(end+1-last_tld > 3) {
+        /* If the last_tld has more than 3 characters, then it's automatically
+         * considered the TLD of the domain name.
+         *  Ex: www.winehq.org.uk.test -> uk.test as the domain name.
+         */
+        *domain_start = (sec_last_tld+1)-host;
+    } else if(last_tld - (sec_last_tld+1) < 4) {
+        DWORD i;
+        /* If the sec_last_tld is 3 characters long it HAS to be on the list of
+         * recognized to still be considered part of the TLD name, otherwise
+         * it's considered the domain name.
+         *  Ex: www.google.com.uk -> google.com.uk as the domain name.
+         *      www.google.foo.uk -> foo.uk as the domain name.
+         */
+        if(last_tld - (sec_last_tld+1) == 3) {
+            for(i = 0; i < ARRAY_SIZE(recognized_tlds); ++i) {
+                if(!StrCmpNIW(sec_last_tld+1, recognized_tlds[i].tld_name, 3)) {
+                    for (p = sec_last_tld; p > host; p--) if (p[-1] == '.') break;
+                    *domain_start = p - host;
+                    TRACE("Found domain name %s\n", debugstr_wn(host+*domain_start,
+                                                        (host+host_len)-(host+*domain_start)));
+                    return;
+                }
+            }
+
+            *domain_start = (sec_last_tld+1)-host;
+        } else {
+            /* Since the sec_last_tld is less than 3 characters it's considered
+             * part of the TLD.
+             *  Ex: www.google.fo.uk -> google.fo.uk as the domain name.
+             */
+            for (p = sec_last_tld; p > host; p--) if (p[-1] == '.') break;
+            *domain_start = p - host;
+        }
+    } else {
+        /* The second to last TLD has more than 3 characters making it
+         * the domain name.
+         *  Ex: www.google.test.us -> test.us as the domain name.
+         */
+        *domain_start = (sec_last_tld+1)-host;
+    }
+
+    TRACE("Found domain name %s\n", debugstr_wn(host+*domain_start,
+                                        (host+host_len)-(host+*domain_start)));
+}
+
+/* Removes the dot segments from a hierarchical URIs path component. This
+ * function performs the removal in place.
+ *
+ * This function returns the new length of the path string.
+ */
+static DWORD remove_dot_segments(WCHAR *path, DWORD path_len) {
+    WCHAR *out = path;
+    const WCHAR *in = out;
+    const WCHAR *end = out + path_len;
+    DWORD len;
+
+    while(in < end) {
+        /* Move the first path segment in the input buffer to the end of
+         * the output buffer, and any subsequent characters up to, including
+         * the next "/" character (if any) or the end of the input buffer.
+         */
+        while(in < end && !is_slash(*in))
+            *out++ = *in++;
+        if(in == end)
+            break;
+        *out++ = *in++;
+
+        while(in < end) {
+            if(*in != '.')
+                break;
+
+            /* Handle ending "/." */
+            if(in + 1 == end) {
+                ++in;
+                break;
+            }
+
+            /* Handle "/./" */
+            if(is_slash(in[1])) {
+                in += 2;
+                continue;
+            }
+
+            /* If we don't have "/../" or ending "/.." */
+            if(in[1] != '.' || (in + 2 != end && !is_slash(in[2])))
+                break;
+
+            /* Find the slash preceding out pointer and move out pointer to it */
+            if(out > path+1 && is_slash(*--out))
+                --out;
+            while(out > path && !is_slash(*(--out)));
+            if(is_slash(*out))
+                ++out;
+            in += 2;
+            if(in != end)
+                ++in;
+        }
+    }
+
+    len = out - path;
+    TRACE("(%p %ld): Path after dot segments removed %s len=%ld\n", path, path_len,
+        debugstr_wn(path, len), len);
+    return len;
+}
+
+/* Attempts to find the file extension in a given path. */
+static INT find_file_extension(const WCHAR *path, DWORD path_len) {
+    const WCHAR *end;
+
+    for(end = path+path_len-1; end >= path && *end != '/' && *end != '\\'; --end) {
+        if(*end == '.')
+            return end-path;
+    }
+
+    return -1;
+}
+
+/* Removes all the leading and trailing white spaces or
+ * control characters from the URI and removes all control
+ * characters inside of the URI string.
+ */
+static BSTR pre_process_uri(LPCWSTR uri) {
+    const WCHAR *start, *end, *ptr;
+    WCHAR *ptr2;
+    DWORD len;
+    BSTR ret;
+
+    start = uri;
+    /* Skip leading controls and whitespace. */
+    while(*start && (iswcntrl(*start) || iswspace(*start))) ++start;
+
+    /* URI consisted only of control/whitespace. */
+    if(!*start)
+        return SysAllocStringLen(NULL, 0);
+
+    end = start + lstrlenW(start);
+    while(--end > start && (iswcntrl(*end) || iswspace(*end)));
+
+    len = ++end - start;
+    for(ptr = start; ptr < end; ptr++) {
+        if(iswcntrl(*ptr))
+            len--;
+    }
+
+    ret = SysAllocStringLen(NULL, len);
+    if(!ret)
+        return NULL;
+
+    for(ptr = start, ptr2=ret; ptr < end; ptr++) {
+        if(!iswcntrl(*ptr))
+            *ptr2++ = *ptr;
+    }
+
+    return ret;
+}
+
+/* Converts an IPv4 address in numerical form into its fully qualified
+ * string form. This function returns the number of characters written
+ * to 'dest'. If 'dest' is NULL this function will return the number of
+ * characters that would have been written.
+ *
+ * It's up to the caller to ensure there's enough space in 'dest' for the
+ * address.
+ */
+static DWORD ui2ipv4(WCHAR *dest, UINT address) {
+    DWORD ret = 0;
+    UCHAR digits[4];
+
+    digits[0] = (address >> 24) & 0xff;
+    digits[1] = (address >> 16) & 0xff;
+    digits[2] = (address >> 8) & 0xff;
+    digits[3] = address & 0xff;
+
+    if(!dest) {
+        WCHAR tmp[16];
+        ret = swprintf(tmp, ARRAY_SIZE(tmp), L"%u.%u.%u.%u", digits[0], digits[1], digits[2], digits[3]);
+    } else
+        ret = swprintf(dest, 16, L"%u.%u.%u.%u", digits[0], digits[1], digits[2], digits[3]);
+
+    return ret;
+}
+
+static DWORD ui2str(WCHAR *dest, UINT value) {
+    DWORD ret = 0;
+
+    if(!dest) {
+        WCHAR tmp[11];
+        ret = swprintf(tmp, ARRAY_SIZE(tmp), L"%u", value);
+    } else
+        ret = swprintf(dest, 11, L"%u", value);
+
+    return ret;
+}
+
+/* Checks if the characters pointed to by 'ptr' are
+ * a percent encoded data octet.
+ *
+ * pct-encoded = "%" HEXDIG HEXDIG
+ */
+static BOOL check_pct_encoded(const WCHAR **ptr) {
+    const WCHAR *start = *ptr;
+
+    if(**ptr != '%')
+        return FALSE;
+
+    ++(*ptr);
+    if(!is_hexdigit(**ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    if(!is_hexdigit(**ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    return TRUE;
+}
+
+/* dec-octet   = DIGIT                 ; 0-9
+ *             / %x31-39 DIGIT         ; 10-99
+ *             / "1" 2DIGIT            ; 100-199
+ *             / "2" %x30-34 DIGIT     ; 200-249
+ *             / "25" %x30-35          ; 250-255
+ */
+static BOOL check_dec_octet(const WCHAR **ptr) {
+    const WCHAR *c1, *c2, *c3;
+
+    c1 = *ptr;
+    /* A dec-octet must be at least 1 digit long. */
+    if(*c1 < '0' || *c1 > '9')
+        return FALSE;
+
+    ++(*ptr);
+
+    c2 = *ptr;
+    /* Since the 1-digit requirement was met, it doesn't
+     * matter if this is a DIGIT value, it's considered a
+     * dec-octet.
+     */
+    if(*c2 < '0' || *c2 > '9')
+        return TRUE;
+
+    ++(*ptr);
+
+    c3 = *ptr;
+    /* Same explanation as above. */
+    if(*c3 < '0' || *c3 > '9')
+        return TRUE;
+
+    /* Anything > 255 isn't a valid IP dec-octet. */
+    if(*c1 >= '2' && *c2 >= '5' && *c3 >= '5') {
+        *ptr = c1;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    return TRUE;
+}
+
+/* Checks if there is an implicit IPv4 address in the host component of the URI.
+ * The max value of an implicit IPv4 address is UINT_MAX.
+ *
+ *  Ex:
+ *      "234567" would be considered an implicit IPv4 address.
+ */
+static BOOL check_implicit_ipv4(const WCHAR **ptr, UINT *val) {
+    const WCHAR *start = *ptr;
+    ULONGLONG ret = 0;
+    *val = 0;
+
+    while(is_num(**ptr)) {
+        ret = ret*10 + (**ptr - '0');
+
+        if(ret > UINT_MAX) {
+            *ptr = start;
+            return FALSE;
+        }
+        ++(*ptr);
+    }
+
+    if(*ptr == start)
+        return FALSE;
+
+    *val = ret;
+    return TRUE;
+}
+
+/* Checks if the string contains an IPv4 address.
+ *
+ * This function has a strict mode or a non-strict mode of operation
+ * When 'strict' is set to FALSE this function will return TRUE if
+ * the string contains at least 'dec-octet "." dec-octet' since partial
+ * IPv4 addresses will be normalized out into full IPv4 addresses. When
+ * 'strict' is set this function expects there to be a full IPv4 address.
+ *
+ * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+ */
+static BOOL check_ipv4address(const WCHAR **ptr, BOOL strict) {
+    const WCHAR *start = *ptr;
+
+    if(!check_dec_octet(ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    if(**ptr != '.') {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    if(!check_dec_octet(ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    if(**ptr != '.') {
+        if(strict) {
+            *ptr = start;
+            return FALSE;
+        } else
+            return TRUE;
+    }
+
+    ++(*ptr);
+    if(!check_dec_octet(ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    if(**ptr != '.') {
+        if(strict) {
+            *ptr = start;
+            return FALSE;
+        } else
+            return TRUE;
+    }
+
+    ++(*ptr);
+    if(!check_dec_octet(ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    /* Found a four digit ip address. */
+    return TRUE;
+}
+/* Tries to parse the scheme name of the URI.
+ *
+ * scheme = ALPHA *(ALPHA | NUM | '+' | '-' | '.') as defined by RFC 3896.
+ * NOTE: Windows accepts a number as the first character of a scheme.
+ */
+static BOOL parse_scheme_name(const WCHAR **ptr, parse_data *data, DWORD extras) {
+    const WCHAR *start = *ptr;
+
+    data->scheme = NULL;
+    data->scheme_len = 0;
+
+    while(**ptr) {
+        if(**ptr == '*' && *ptr == start) {
+            /* Might have found a wildcard scheme. If it is the next
+             * char has to be a ':' for it to be a valid URI
+             */
+            ++(*ptr);
+            break;
+        } else if(!is_num(**ptr) && !is_alpha(**ptr) && **ptr != '+' &&
+           **ptr != '-' && **ptr != '.')
+            break;
+
+        (*ptr)++;
+    }
+
+    if(*ptr == start)
+        return FALSE;
+
+    /* Schemes must end with a ':' */
+    if(**ptr != ':' && !((extras & ALLOW_NULL_TERM_SCHEME) && !**ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    data->scheme = start;
+    data->scheme_len = *ptr - start;
+
+    ++(*ptr);
+    return TRUE;
+}
+
+/* Tries to deduce the corresponding URL_SCHEME for the given URI. Stores
+ * the deduced URL_SCHEME in data->scheme_type.
+ */
+static BOOL parse_scheme_type(parse_data *data) {
+    /* If there's scheme data then see if it's a recognized scheme. */
+    if(data->scheme && data->scheme_len) {
+        DWORD i;
+
+        for(i = 0; i < ARRAY_SIZE(recognized_schemes); ++i) {
+            if(lstrlenW(recognized_schemes[i].scheme_name) == data->scheme_len) {
+                /* Has to be a case insensitive compare. */
+                if(!StrCmpNIW(recognized_schemes[i].scheme_name, data->scheme, data->scheme_len)) {
+                    data->scheme_type = recognized_schemes[i].scheme;
+                    return TRUE;
+                }
+            }
+        }
+
+        /* If we get here it means it's not a recognized scheme. */
+        data->scheme_type = URL_SCHEME_UNKNOWN;
+        return TRUE;
+    } else if(data->is_relative) {
+        /* Relative URI's have no scheme. */
+        data->scheme_type = URL_SCHEME_UNKNOWN;
+        return TRUE;
+    } else {
+        /* Should never reach here! what happened... */
+        FIXME("(%p): Unable to determine scheme type for URI %s\n", data, debugstr_w(data->uri));
+        return FALSE;
+    }
+}
+
+/* Tries to parse (or deduce) the scheme_name of a URI. If it can't
+ * parse a scheme from the URI it will try to deduce the scheme_name and scheme_type
+ * using the flags specified in 'flags' (if any). Flags that affect how this function
+ * operates are the Uri_CREATE_ALLOW_* flags.
+ *
+ * All parsed/deduced information will be stored in 'data' when the function returns.
+ *
+ * Returns TRUE if it was able to successfully parse the information.
+ */
+static BOOL parse_scheme(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
+    /* First check to see if the uri could implicitly be a file path. */
+    if(is_implicit_file_path(*ptr)) {
+        if(flags & Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME) {
+            data->scheme = L"file";
+            data->scheme_len = lstrlenW(L"file");
+            data->has_implicit_scheme = TRUE;
+
+            TRACE("(%p %p %lx): URI is an implicit file path.\n", ptr, data, flags);
+        } else {
+            /* Windows does not consider anything that can implicitly be a file
+             * path to be a valid URI if the ALLOW_IMPLICIT_FILE_SCHEME flag is not set...
+             */
+            TRACE("(%p %p %lx): URI is implicitly a file path, but, the ALLOW_IMPLICIT_FILE_SCHEME flag wasn't set.\n",
+                    ptr, data, flags);
+            return FALSE;
+        }
+    } else if(!parse_scheme_name(ptr, data, extras)) {
+        /* No scheme was found, this means it could be:
+         *      a) an implicit Wildcard scheme
+         *      b) a relative URI
+         *      c) an invalid URI.
+         */
+        if(flags & Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME) {
+            data->scheme = L"*";
+            data->scheme_len = lstrlenW(L"*");
+            data->has_implicit_scheme = TRUE;
+
+            TRACE("(%p %p %lx): URI is an implicit wildcard scheme.\n", ptr, data, flags);
+        } else if (flags & Uri_CREATE_ALLOW_RELATIVE) {
+            data->is_relative = TRUE;
+            TRACE("(%p %p %lx): URI is relative.\n", ptr, data, flags);
+        } else {
+            TRACE("(%p %p %lx): Malformed URI found. Unable to deduce scheme name.\n", ptr, data, flags);
+            return FALSE;
+        }
+    }
+
+    if(!data->is_relative)
+        TRACE("(%p %p %lx): Found scheme=%s scheme_len=%ld\n", ptr, data, flags,
+                debugstr_wn(data->scheme, data->scheme_len), data->scheme_len);
+
+    if(!parse_scheme_type(data))
+        return FALSE;
+
+    TRACE("(%p %p %lx): Assigned %d as the URL_SCHEME.\n", ptr, data, flags, data->scheme_type);
+    return TRUE;
+}
+
+static BOOL parse_username(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
+    data->username = *ptr;
+
+    while(**ptr != ':' && **ptr != '@') {
+        if(**ptr == '%') {
+            if(!check_pct_encoded(ptr)) {
+                if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+                    *ptr = data->username;
+                    data->username = NULL;
+                    return FALSE;
+                }
+            } else
+                continue;
+        } else if(extras & ALLOW_NULL_TERM_USER_NAME && !**ptr)
+            break;
+        else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
+            *ptr = data->username;
+            data->username = NULL;
+            return FALSE;
+        }
+
+        ++(*ptr);
+    }
+
+    data->username_len = *ptr - data->username;
+    return TRUE;
+}
+
+static BOOL parse_password(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
+    data->password = *ptr;
+
+    while(**ptr != '@') {
+        if(**ptr == '%') {
+            if(!check_pct_encoded(ptr)) {
+                if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+                    *ptr = data->password;
+                    data->password = NULL;
+                    return FALSE;
+                }
+            } else
+                continue;
+        } else if(extras & ALLOW_NULL_TERM_PASSWORD && !**ptr)
+            break;
+        else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
+            *ptr = data->password;
+            data->password = NULL;
+            return FALSE;
+        }
+
+        ++(*ptr);
+    }
+
+    data->password_len = *ptr - data->password;
+    return TRUE;
+}
+
+/* Parses the userinfo part of the URI (if it exists). The userinfo field of
+ * a URI can consist of "username:password@", or just "username@".
+ *
+ * RFC def:
+ * userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
+ *
+ * NOTES:
+ *  1)  If there is more than one ':' in the userinfo part of the URI Windows
+ *      uses the first occurrence of ':' to delimit the username and password
+ *      components.
+ *
+ *      ex:
+ *          ftp://user:pass:word@winehq.org
+ *
+ *      would yield "user" as the username and "pass:word" as the password.
+ *
+ *  2)  Windows allows any character to appear in the "userinfo" part of
+ *      a URI, as long as it's not an authority delimiter character set.
+ */
+static void parse_userinfo(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    const WCHAR *start = *ptr;
+
+    if(!parse_username(ptr, data, flags, 0)) {
+        TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
+        return;
+    }
+
+    if(**ptr == ':') {
+        ++(*ptr);
+        if(!parse_password(ptr, data, flags, 0)) {
+            *ptr = start;
+            data->username = NULL;
+            data->username_len = 0;
+            TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
+            return;
+        }
+    }
+
+    if(**ptr != '@') {
+        *ptr = start;
+        data->username = NULL;
+        data->username_len = 0;
+        data->password = NULL;
+        data->password_len = 0;
+
+        TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
+        return;
+    }
+
+    if(data->username)
+        TRACE("(%p %p %lx): Found username %s len=%ld.\n", ptr, data, flags,
+            debugstr_wn(data->username, data->username_len), data->username_len);
+
+    if(data->password)
+        TRACE("(%p %p %lx): Found password %s len=%ld.\n", ptr, data, flags,
+            debugstr_wn(data->password, data->password_len), data->password_len);
+
+    ++(*ptr);
+}
+
+/* Attempts to parse a port from the URI.
+ *
+ * NOTES:
+ *  Windows seems to have a cap on what the maximum value
+ *  for a port can be. The max value is USHORT_MAX.
+ *
+ * port = *DIGIT
+ */
+static BOOL parse_port(const WCHAR **ptr, parse_data *data) {
+    UINT port = 0;
+    data->port = *ptr;
+
+    while(!is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
+        if(!is_num(**ptr)) {
+            *ptr = data->port;
+            data->port = NULL;
+            return FALSE;
+        }
+
+        port = port*10 + (**ptr-'0');
+
+        if(port > USHRT_MAX) {
+            *ptr = data->port;
+            data->port = NULL;
+            return FALSE;
+        }
+
+        ++(*ptr);
+    }
+
+    data->has_port = TRUE;
+    data->port_value = port;
+    data->port_len = *ptr - data->port;
+
+    TRACE("(%p %p): Found port %s len=%ld value=%lu\n", ptr, data,
+        debugstr_wn(data->port, data->port_len), data->port_len, data->port_value);
+    return TRUE;
+}
+
+/* Attempts to parse a IPv4 address from the URI.
+ *
+ * NOTES:
+ *  Windows normalizes IPv4 addresses, This means there are three
+ *  possibilities for the URI to contain an IPv4 address.
+ *      1)  A well formed address (ex. 192.2.2.2).
+ *      2)  A partially formed address. For example "192.0" would
+ *          normalize to "192.0.0.0" during canonicalization.
+ *      3)  An implicit IPv4 address. For example "256" would
+ *          normalize to "0.0.1.0" during canonicalization. Also
+ *          note that the maximum value for an implicit IP address
+ *          is UINT_MAX, if the value in the URI exceeds this then
+ *          it is not considered an IPv4 address.
+ */
+static BOOL parse_ipv4address(const WCHAR **ptr, parse_data *data) {
+    const BOOL is_unknown = data->scheme_type == URL_SCHEME_UNKNOWN;
+    data->host = *ptr;
+
+    if(!check_ipv4address(ptr, FALSE)) {
+        if(!check_implicit_ipv4(ptr, &data->implicit_ipv4)) {
+            TRACE("(%p %p): URI didn't contain anything looking like an IPv4 address.\n", ptr, data);
+            *ptr = data->host;
+            data->host = NULL;
+            return FALSE;
+        } else
+            data->has_implicit_ip = TRUE;
+    }
+
+    data->host_len = *ptr - data->host;
+    data->host_type = Uri_HOST_IPV4;
+
+    /* Check if what we found is the only part of the host name (if it isn't
+     * we don't have an IPv4 address).
+     */
+    if(**ptr == ':') {
+        ++(*ptr);
+        if(!parse_port(ptr, data)) {
+            *ptr = data->host;
+            data->host = NULL;
+            return FALSE;
+        }
+    } else if(!is_auth_delim(**ptr, !is_unknown)) {
+        /* Found more data which belongs to the host, so this isn't an IPv4. */
+        *ptr = data->host;
+        data->host = NULL;
+        data->has_implicit_ip = FALSE;
+        return FALSE;
+    }
+
+    TRACE("(%p %p): IPv4 address found. host=%s host_len=%ld host_type=%d\n",
+        ptr, data, debugstr_wn(data->host, data->host_len),
+        data->host_len, data->host_type);
+    return TRUE;
+}
+
+/* Attempts to parse the reg-name from the URI.
+ *
+ * Because of the way Windows handles ':' this function also
+ * handles parsing the port.
+ *
+ * reg-name = *( unreserved / pct-encoded / sub-delims )
+ *
+ * NOTE:
+ *  Windows allows everything, but, the characters in "auth_delims" and ':'
+ *  to appear in a reg-name, unless it's an unknown scheme type then ':' is
+ *  allowed to appear (even if a valid port isn't after it).
+ *
+ *  Windows doesn't like host names which start with '[' and end with ']'
+ *  and don't contain a valid IP literal address in between them.
+ *
+ *  On Windows if a '[' is encountered in the host name the ':' no longer
+ *  counts as a delimiter until you reach the next ']' or an "authority delimiter".
+ *
+ *  A reg-name CAN be empty.
+ */
+static BOOL parse_reg_name(const WCHAR **ptr, parse_data *data, DWORD extras) {
+    const BOOL has_start_bracket = **ptr == '[';
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+    const BOOL is_res = data->scheme_type == URL_SCHEME_RES;
+    BOOL inside_brackets = has_start_bracket;
+
+    /* res URIs don't have ports. */
+    BOOL ignore_col = (extras & IGNORE_PORT_DELIMITER) || is_res;
+
+    /* We have to be careful with file schemes. */
+    if(data->scheme_type == URL_SCHEME_FILE) {
+        /* This is because an implicit file scheme could be "C:\\test" and it
+         * would trick this function into thinking the host is "C", when after
+         * canonicalization the host would end up being an empty string. A drive
+         * path can also have a '|' instead of a ':' after the drive letter.
+         */
+        if(is_drive_path(*ptr)) {
+            /* Regular old drive paths have no host type (or host name). */
+            data->host_type = Uri_HOST_UNKNOWN;
+            data->host = *ptr;
+            data->host_len = 0;
+            return TRUE;
+        } else if(is_unc_path(*ptr))
+            /* Skip past the "\\" of a UNC path. */
+            *ptr += 2;
+    }
+
+    data->host = *ptr;
+
+    /* For res URIs, everything before the first '/' is
+     * considered the host.
+     */
+    while((!is_res && !is_auth_delim(**ptr, known_scheme)) ||
+          (is_res && **ptr && **ptr != '/')) {
+        if(**ptr == ':' && !ignore_col) {
+            /* We can ignore ':' if we are inside brackets.*/
+            if(!inside_brackets) {
+                const WCHAR *tmp = (*ptr)++;
+
+                /* Attempt to parse the port. */
+                if(!parse_port(ptr, data)) {
+                    /* Windows expects there to be a valid port for known scheme types. */
+                    if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+                        *ptr = data->host;
+                        data->host = NULL;
+                        TRACE("(%p %p %lx): Expected valid port\n", ptr, data, extras);
+                        return FALSE;
+                    } else
+                        /* Windows gives up on trying to parse a port when it
+                         * encounters an invalid port.
+                         */
+                        ignore_col = TRUE;
+                } else {
+                    data->host_len = tmp - data->host;
+                    break;
+                }
+            }
+        } else if(**ptr == '%' && (known_scheme && !is_res)) {
+            /* Has to be a legit % encoded value. */
+            if(!check_pct_encoded(ptr)) {
+                *ptr = data->host;
+                data->host = NULL;
+                return FALSE;
+            } else
+                continue;
+        } else if(is_res && is_forbidden_dos_path_char(**ptr)) {
+            *ptr = data->host;
+            data->host = NULL;
+            return FALSE;
+        } else if(**ptr == ']')
+            inside_brackets = FALSE;
+        else if(**ptr == '[')
+            inside_brackets = TRUE;
+
+        ++(*ptr);
+    }
+
+    if(has_start_bracket) {
+        /* Make sure the last character of the host wasn't a ']'. */
+        if(*(*ptr-1) == ']') {
+            TRACE("(%p %p %lx): Expected an IP literal inside of the host\n", ptr, data, extras);
+            *ptr = data->host;
+            data->host = NULL;
+            return FALSE;
+        }
+    }
+
+    /* Don't overwrite our length if we found a port earlier. */
+    if(!data->port)
+        data->host_len = *ptr - data->host;
+
+    /* If the host is empty, then it's an unknown host type. */
+    if(data->host_len == 0 || is_res)
+        data->host_type = Uri_HOST_UNKNOWN;
+    else {
+        unsigned int i;
+
+        data->host_type = Uri_HOST_DNS;
+
+        for(i = 0; i < data->host_len; i++) {
+            if(!is_ascii(data->host[i])) {
+                data->host_type = Uri_HOST_IDN;
+                break;
+            }
+        }
+    }
+
+    TRACE("(%p %p %lx): Parsed reg-name. host=%s len=%ld type=%d\n", ptr, data, extras,
+          debugstr_wn(data->host, data->host_len), data->host_len, data->host_type);
+    return TRUE;
+}
+
+/* Attempts to parse an IPv6 address out of the URI.
+ *
+ * IPv6address =                               6( h16 ":" ) ls32
+ *                /                       "::" 5( h16 ":" ) ls32
+ *                / [               h16 ] "::" 4( h16 ":" ) ls32
+ *                / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ *                / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ *                / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
+ *                / [ *4( h16 ":" ) h16 ] "::"              ls32
+ *                / [ *5( h16 ":" ) h16 ] "::"              h16
+ *                / [ *6( h16 ":" ) h16 ] "::"
+ *
+ * ls32        = ( h16 ":" h16 ) / IPv4address
+ *             ; least-significant 32 bits of address.
+ *
+ * h16         = 1*4HEXDIG
+ *             ; 16 bits of address represented in hexadecimal.
+ */
+static BOOL parse_ipv6address(const WCHAR **ptr, parse_data *data) {
+    const WCHAR *terminator;
+
+    if(RtlIpv6StringToAddressW(*ptr, &terminator, &data->ipv6_address))
+        return FALSE;
+    if(*terminator != ']' && !is_auth_delim(*terminator, data->scheme_type != URL_SCHEME_UNKNOWN))
+        return FALSE;
+
+    *ptr = terminator;
+    data->host_type = Uri_HOST_IPV6;
+    return TRUE;
+}
+
+/*  IPvFuture  = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) */
+static BOOL parse_ipvfuture(const WCHAR **ptr, parse_data *data) {
+    const WCHAR *start = *ptr;
+
+    /* IPvFuture has to start with a 'v' or 'V'. */
+    if(**ptr != 'v' && **ptr != 'V')
+        return FALSE;
+
+    /* Following the v there must be at least 1 hex digit. */
+    ++(*ptr);
+    if(!is_hexdigit(**ptr)) {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    while(is_hexdigit(**ptr))
+        ++(*ptr);
+
+    /* End of the hexdigit sequence must be a '.' */
+    if(**ptr != '.') {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    if(!is_unreserved(**ptr) && !is_subdelim(**ptr) && **ptr != ':') {
+        *ptr = start;
+        return FALSE;
+    }
+
+    ++(*ptr);
+    while(is_unreserved(**ptr) || is_subdelim(**ptr) || **ptr == ':')
+        ++(*ptr);
+
+    data->host_type = Uri_HOST_UNKNOWN;
+
+    TRACE("(%p %p): Parsed IPvFuture address %s len=%d\n", ptr, data,
+          debugstr_wn(start, *ptr-start), (int)(*ptr-start));
+
+    return TRUE;
+}
+
+/* IP-literal = "[" ( IPv6address / IPvFuture  ) "]" */
+static BOOL parse_ip_literal(const WCHAR **ptr, parse_data *data, DWORD extras) {
+    data->host = *ptr;
+
+    if(**ptr != '[' && !(extras & ALLOW_BRACKETLESS_IP_LITERAL)) {
+        data->host = NULL;
+        return FALSE;
+    } else if(**ptr == '[')
+        ++(*ptr);
+
+    if(!parse_ipv6address(ptr, data)) {
+        if(extras & SKIP_IP_FUTURE_CHECK || !parse_ipvfuture(ptr, data)) {
+            *ptr = data->host;
+            data->host = NULL;
+            return FALSE;
+        }
+    }
+
+    if(**ptr != ']' && !(extras & ALLOW_BRACKETLESS_IP_LITERAL)) {
+        *ptr = data->host;
+        data->host = NULL;
+        return FALSE;
+    } else if(!**ptr && extras & ALLOW_BRACKETLESS_IP_LITERAL) {
+        /* The IP literal didn't contain brackets and was followed by
+         * a NULL terminator, so no reason to even check the port.
+         */
+        data->host_len = *ptr - data->host;
+        return TRUE;
+    }
+
+    ++(*ptr);
+    if(**ptr == ':') {
+        ++(*ptr);
+        /* If a valid port is not found, then let it trickle down to
+         * parse_reg_name.
+         */
+        if(!parse_port(ptr, data)) {
+            *ptr = data->host;
+            data->host = NULL;
+            return FALSE;
+        }
+    } else
+        data->host_len = *ptr - data->host;
+
+    return TRUE;
+}
+
+/* Parses the host information from the URI.
+ *
+ * host = IP-literal / IPv4address / reg-name
+ */
+static BOOL parse_host(const WCHAR **ptr, parse_data *data, DWORD extras) {
+    if(!parse_ip_literal(ptr, data, extras)) {
+        if(!parse_ipv4address(ptr, data)) {
+            if(!parse_reg_name(ptr, data, extras)) {
+                TRACE("(%p %p %lx): Malformed URI, Unknown host type.\n",  ptr, data, extras);
+                return FALSE;
+            }
+        }
+    }
+
+    return TRUE;
+}
+
+/* Parses the authority information from the URI.
+ *
+ * authority   = [ userinfo "@" ] host [ ":" port ]
+ */
+static BOOL parse_authority(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    parse_userinfo(ptr, data, flags);
+
+    /* Parsing the port will happen during one of the host parsing
+     * routines (if the URI has a port).
+     */
+    if(!parse_host(ptr, data, 0))
+        return FALSE;
+
+    return TRUE;
+}
+
+/* Attempts to parse the path information of a hierarchical URI. */
+static BOOL parse_path_hierarchical(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    const WCHAR *start = *ptr;
+    const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
+
+    if(is_path_delim(data->scheme_type, **ptr)) {
+        if(data->scheme_type == URL_SCHEME_WILDCARD && !data->must_have_path) {
+            data->path = NULL;
+            data->path_len = 0;
+        } else if(!(flags & Uri_CREATE_NO_CANONICALIZE)) {
+            /* If the path component is empty, then a '/' is added. */
+            data->path = L"/";
+            data->path_len = 1;
+        }
+    } else {
+        while(!is_path_delim(data->scheme_type, **ptr)) {
+            if(**ptr == '%' && data->scheme_type != URL_SCHEME_UNKNOWN && !is_file) {
+                if(!check_pct_encoded(ptr)) {
+                    *ptr = start;
+                    return FALSE;
+                } else
+                    continue;
+            } else if(is_forbidden_dos_path_char(**ptr) && is_file &&
+                      (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+                /* File schemes with USE_DOS_PATH set aren't allowed to have
+                 * a '<' or '>' or '\"' appear in them.
+                 */
+                *ptr = start;
+                return FALSE;
+            } else if(**ptr == '\\') {
+                /* Not allowed to have a backslash if NO_CANONICALIZE is set
+                 * and the scheme is known type (but not a file scheme).
+                 */
+                if(flags & Uri_CREATE_NO_CANONICALIZE) {
+                    if(data->scheme_type != URL_SCHEME_FILE &&
+                       data->scheme_type != URL_SCHEME_UNKNOWN) {
+                        *ptr = start;
+                        return FALSE;
+                    }
+                }
+            }
+
+            ++(*ptr);
+        }
+
+        /* The only time a URI doesn't have a path is when
+         * the NO_CANONICALIZE flag is set and the raw URI
+         * didn't contain one.
+         */
+        if(*ptr == start) {
+            data->path = NULL;
+            data->path_len = 0;
+        } else {
+            data->path = start;
+            data->path_len = *ptr - start;
+        }
+    }
+
+    if(data->path)
+        TRACE("(%p %p %lx): Parsed path %s len=%ld\n", ptr, data, flags,
+            debugstr_wn(data->path, data->path_len), data->path_len);
+    else
+        TRACE("(%p %p %lx): The URI contained no path\n", ptr, data, flags);
+
+    return TRUE;
+}
+
+/* Parses the path of an opaque URI (much less strict than the parser
+ * for a hierarchical URI).
+ *
+ * NOTE:
+ *  Windows allows invalid % encoded data to appear in opaque URI paths
+ *  for unknown scheme types.
+ *
+ *  File schemes with USE_DOS_PATH set aren't allowed to have '<', '>', or '\"'
+ *  appear in them.
+ */
+static BOOL parse_path_opaque(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+    const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
+    const BOOL is_mailto = data->scheme_type == URL_SCHEME_MAILTO;
+
+    if (is_mailto && (*ptr)[0] == '/' && (*ptr)[1] == '/')
+    {
+        if ((*ptr)[2]) data->path = *ptr + 2;
+        else data->path = NULL;
+    }
+    else
+        data->path = *ptr;
+
+    while(!is_path_delim(data->scheme_type, **ptr)) {
+        if(**ptr == '%' && known_scheme) {
+            if(!check_pct_encoded(ptr)) {
+                *ptr = data->path;
+                data->path = NULL;
+                return FALSE;
+            } else
+                continue;
+        } else if(is_forbidden_dos_path_char(**ptr) && is_file &&
+                  (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+            *ptr = data->path;
+            data->path = NULL;
+            return FALSE;
+        }
+
+        ++(*ptr);
+    }
+
+    if (data->path) data->path_len = *ptr - data->path;
+    TRACE("(%p %p %lx): Parsed opaque URI path %s len=%ld\n", ptr, data, flags,
+        debugstr_wn(data->path, data->path_len), data->path_len);
+    return TRUE;
+}
+
+/* Determines how the URI should be parsed after the scheme information.
+ *
+ * If the scheme is followed by "//", then it is treated as a hierarchical URI
+ * which then the authority and path information will be parsed out. Otherwise, the
+ * URI will be treated as an opaque URI which the authority information is not parsed
+ * out.
+ *
+ * RFC 3896 definition of hier-part:
+ *
+ * hier-part   = "//" authority path-abempty
+ *                 / path-absolute
+ *                 / path-rootless
+ *                 / path-empty
+ *
+ * MSDN opaque URI definition:
+ *  scheme ":" path [ "#" fragment ]
+ *
+ * NOTES:
+ *  If the URI is of an unknown scheme type and has a "//" following the scheme then it
+ *  is treated as a hierarchical URI, but, if the CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is
+ *  set then it is considered an opaque URI regardless of what follows the scheme information
+ *  (per MSDN documentation).
+ */
+static BOOL parse_hierpart(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    const WCHAR *start = *ptr;
+
+    data->must_have_path = FALSE;
+
+    /* For javascript: URIs, simply set everything as a path */
+    if(data->scheme_type == URL_SCHEME_JAVASCRIPT) {
+        data->path = *ptr;
+        data->path_len = lstrlenW(*ptr);
+        data->is_opaque = TRUE;
+        *ptr += data->path_len;
+        return TRUE;
+    }
+
+    /* Checks if the authority information needs to be parsed. */
+    if(is_hierarchical_uri(ptr, data)) {
+        /* Only treat it as a hierarchical URI if the scheme_type is known or
+         * the Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is not set.
+         */
+        if(data->scheme_type != URL_SCHEME_UNKNOWN ||
+           !(flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES)) {
+            TRACE("(%p %p %lx): Treating URI as an hierarchical URI.\n", ptr, data, flags);
+            data->is_opaque = FALSE;
+
+            if(data->scheme_type == URL_SCHEME_WILDCARD && !data->has_implicit_scheme) {
+                if(**ptr == '/' && *(*ptr+1) == '/') {
+                    data->must_have_path = TRUE;
+                    *ptr += 2;
+                }
+            }
+
+            /* TODO: Handle hierarchical URI's, parse authority then parse the path. */
+            if(!parse_authority(ptr, data, flags))
+                return FALSE;
+
+            return parse_path_hierarchical(ptr, data, flags);
+        } else
+            /* Reset ptr to its starting position so opaque path parsing
+             * begins at the correct location.
+             */
+            *ptr = start;
+    }
+
+    /* If it reaches here, then the URI will be treated as an opaque
+     * URI.
+     */
+
+    TRACE("(%p %p %lx): Treating URI as an opaque URI.\n", ptr, data, flags);
+
+    data->is_opaque = TRUE;
+    if(!parse_path_opaque(ptr, data, flags))
+        return FALSE;
+
+    return TRUE;
+}
+
+/* Attempts to parse the query string from the URI.
+ *
+ * NOTES:
+ *  If NO_DECODE_EXTRA_INFO flag is set, then invalid percent encoded
+ *  data is allowed to appear in the query string. For unknown scheme types
+ *  invalid percent encoded data is allowed to appear regardless.
+ */
+static BOOL parse_query(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+
+    if(**ptr != '?') {
+        TRACE("(%p %p %lx): URI didn't contain a query string.\n", ptr, data, flags);
+        return TRUE;
+    }
+
+    data->query = *ptr;
+
+    ++(*ptr);
+    while(**ptr && **ptr != '#') {
+        if(**ptr == '%' && known_scheme &&
+           !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
+            if(!check_pct_encoded(ptr)) {
+                *ptr = data->query;
+                data->query = NULL;
+                return FALSE;
+            } else
+                continue;
+        }
+
+        ++(*ptr);
+    }
+
+    data->query_len = *ptr - data->query;
+
+    TRACE("(%p %p %lx): Parsed query string %s len=%ld\n", ptr, data, flags,
+        debugstr_wn(data->query, data->query_len), data->query_len);
+    return TRUE;
+}
+
+/* Attempts to parse the fragment from the URI.
+ *
+ * NOTES:
+ *  If NO_DECODE_EXTRA_INFO flag is set, then invalid percent encoded
+ *  data is allowed to appear in the query string. For unknown scheme types
+ *  invalid percent encoded data is allowed to appear regardless.
+ */
+static BOOL parse_fragment(const WCHAR **ptr, parse_data *data, DWORD flags) {
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+
+    if(**ptr != '#') {
+        TRACE("(%p %p %lx): URI didn't contain a fragment.\n", ptr, data, flags);
+        return TRUE;
+    }
+
+    data->fragment = *ptr;
+
+    ++(*ptr);
+    while(**ptr) {
+        if(**ptr == '%' && known_scheme &&
+           !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
+            if(!check_pct_encoded(ptr)) {
+                *ptr = data->fragment;
+                data->fragment = NULL;
+                return FALSE;
+            } else
+                continue;
+        }
+
+        ++(*ptr);
+    }
+
+    data->fragment_len = *ptr - data->fragment;
+
+    TRACE("(%p %p %lx): Parsed fragment %s len=%ld\n", ptr, data, flags,
+        debugstr_wn(data->fragment, data->fragment_len), data->fragment_len);
+    return TRUE;
+}
+
+/* Parses and validates the components of the specified by data->uri
+ * and stores the information it parses into 'data'.
+ *
+ * Returns TRUE if it successfully parsed the URI. False otherwise.
+ */
+static BOOL parse_uri(parse_data *data, DWORD flags) {
+    const WCHAR *ptr;
+    const WCHAR **pptr;
+
+    ptr = data->uri;
+    pptr = &ptr;
+
+    TRACE("(%p %lx): BEGINNING TO PARSE URI %s.\n", data, flags, debugstr_w(data->uri));
+
+    if(!parse_scheme(pptr, data, flags, 0))
+        return FALSE;
+
+    if(!parse_hierpart(pptr, data, flags))
+        return FALSE;
+
+    if(!parse_query(pptr, data, flags))
+        return FALSE;
+
+    if(!parse_fragment(pptr, data, flags))
+        return FALSE;
+
+    TRACE("(%p %lx): FINISHED PARSING URI.\n", data, flags);
+    return TRUE;
+}
+
+static BOOL canonicalize_username(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    const WCHAR *ptr;
+
+    if(!data->username) {
+        uri->userinfo_start = -1;
+        return TRUE;
+    }
+
+    uri->userinfo_start = uri->canon_len;
+    for(ptr = data->username; ptr < data->username+data->username_len; ++ptr) {
+        if(*ptr == '%') {
+            /* Only decode % encoded values for known scheme types. */
+            if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+                /* See if the value really needs decoding. */
+                WCHAR val = decode_pct_val(ptr);
+                if(is_unreserved(val)) {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = val;
+
+                    ++uri->canon_len;
+
+                    /* Move pass the hex characters. */
+                    ptr += 2;
+                    continue;
+                }
+            }
+        } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr) && *ptr != '\\') {
+            /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
+             * is NOT set.
+             */
+            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
+                if(!computeOnly)
+                    pct_encode_val(*ptr, uri->canon_uri + uri->canon_len);
+
+                uri->canon_len += 3;
+                continue;
+            }
+        }
+
+        if(!computeOnly)
+            /* Nothing special, so just copy the character over. */
+            uri->canon_uri[uri->canon_len] = *ptr;
+        ++uri->canon_len;
+    }
+
+    return TRUE;
+}
+
+static BOOL canonicalize_password(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    const WCHAR *ptr;
+
+    if(!data->password) {
+        uri->userinfo_split = -1;
+        return TRUE;
+    }
+
+    if(uri->userinfo_start == -1)
+        /* Has a password, but, doesn't have a username. */
+        uri->userinfo_start = uri->canon_len;
+
+    uri->userinfo_split = uri->canon_len - uri->userinfo_start;
+
+    /* Add the ':' to the userinfo component. */
+    if(!computeOnly)
+        uri->canon_uri[uri->canon_len] = ':';
+    ++uri->canon_len;
+
+    for(ptr = data->password; ptr < data->password+data->password_len; ++ptr) {
+        if(*ptr == '%') {
+            /* Only decode % encoded values for known scheme types. */
+            if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+                /* See if the value really needs decoding. */
+                WCHAR val = decode_pct_val(ptr);
+                if(is_unreserved(val)) {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = val;
+
+                    ++uri->canon_len;
+
+                    /* Move pass the hex characters. */
+                    ptr += 2;
+                    continue;
+                }
+            }
+        } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr) && *ptr != '\\') {
+            /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
+             * is NOT set.
+             */
+            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
+                if(!computeOnly)
+                    pct_encode_val(*ptr, uri->canon_uri + uri->canon_len);
+
+                uri->canon_len += 3;
+                continue;
+            }
+        }
+
+        if(!computeOnly)
+            /* Nothing special, so just copy the character over. */
+            uri->canon_uri[uri->canon_len] = *ptr;
+        ++uri->canon_len;
+    }
+
+    return TRUE;
+}
+
+/* Canonicalizes the userinfo of the URI represented by the parse_data.
+ *
+ * Canonicalization of the userinfo is a simple process. If there are any percent
+ * encoded characters that fall in the "unreserved" character set, they are decoded
+ * to their actual value. If a character is not in the "unreserved" or "reserved" sets
+ * then it is percent encoded. Other than that the characters are copied over without
+ * change.
+ */
+static BOOL canonicalize_userinfo(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    uri->userinfo_start = uri->userinfo_split = -1;
+    uri->userinfo_len = 0;
+
+    if(!data->username && !data->password)
+        /* URI doesn't have userinfo, so nothing to do here. */
+        return TRUE;
+
+    if(!canonicalize_username(data, uri, flags, computeOnly))
+        return FALSE;
+
+    if(!canonicalize_password(data, uri, flags, computeOnly))
+        return FALSE;
+
+    uri->userinfo_len = uri->canon_len - uri->userinfo_start;
+    if(!computeOnly)
+        TRACE("(%p %p %lx %d): Canonicalized userinfo, userinfo_start=%d, userinfo=%s, userinfo_split=%d userinfo_len=%ld.\n",
+                data, uri, flags, computeOnly, uri->userinfo_start, debugstr_wn(uri->canon_uri + uri->userinfo_start, uri->userinfo_len),
+                uri->userinfo_split, uri->userinfo_len);
+
+    /* Now insert the '@' after the userinfo. */
+    if(!computeOnly)
+        uri->canon_uri[uri->canon_len] = '@';
+    ++uri->canon_len;
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize a reg_name.
+ *
+ * Things that happen:
+ *  1)  If Uri_CREATE_NO_CANONICALIZE flag is not set, then the reg_name is
+ *      lower cased. Unless it's an unknown scheme type, which case it's
+ *      no lower cased regardless.
+ *
+ *  2)  Unreserved % encoded characters are decoded for known
+ *      scheme types.
+ *
+ *  3)  Forbidden characters are % encoded as long as
+ *      Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS flag is not set and
+ *      it isn't an unknown scheme type.
+ *
+ *  4)  If it's a file scheme and the host is "localhost" it's removed.
+ *
+ *  5)  If it's a file scheme and Uri_CREATE_FILE_USE_DOS_PATH is set,
+ *      then the UNC path characters are added before the host name.
+ */
+static BOOL canonicalize_reg_name(const parse_data *data, Uri *uri,
+                                  DWORD flags, BOOL computeOnly) {
+    const WCHAR *ptr;
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+
+    if(data->scheme_type == URL_SCHEME_FILE &&
+       data->host_len == lstrlenW(L"localhost")) {
+        if(!StrCmpNIW(data->host, L"localhost", data->host_len)) {
+            uri->host_start = -1;
+            uri->host_len = 0;
+            uri->host_type = Uri_HOST_UNKNOWN;
+            return TRUE;
+        }
+    }
+
+    if(data->scheme_type == URL_SCHEME_FILE && flags & Uri_CREATE_FILE_USE_DOS_PATH) {
+        if(!computeOnly) {
+            uri->canon_uri[uri->canon_len] = '\\';
+            uri->canon_uri[uri->canon_len+1] = '\\';
+        }
+        uri->canon_len += 2;
+        uri->authority_start = uri->canon_len;
+    }
+
+    uri->host_start = uri->canon_len;
+
+    for(ptr = data->host; ptr < data->host+data->host_len; ++ptr) {
+        if(*ptr == '%' && known_scheme) {
+            WCHAR val = decode_pct_val(ptr);
+            if(is_unreserved(val)) {
+                /* If NO_CANONICALIZE is not set, then windows lower cases the
+                 * decoded value.
+                 */
+                if(!(flags & Uri_CREATE_NO_CANONICALIZE) && iswupper(val)) {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = towlower(val);
+                } else {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = val;
+                }
+                ++uri->canon_len;
+
+                /* Skip past the % encoded character. */
+                ptr += 2;
+                continue;
+            } else {
+                /* Just copy the % over. */
+                if(!computeOnly)
+                    uri->canon_uri[uri->canon_len] = *ptr;
+                ++uri->canon_len;
+            }
+        } else if(*ptr == '\\') {
+            /* Only unknown scheme types could have made it here with a '\\' in the host name. */
+            if(!computeOnly)
+                uri->canon_uri[uri->canon_len] = *ptr;
+            ++uri->canon_len;
+        } else if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) && is_ascii(*ptr) &&
+                  !is_unreserved(*ptr) && !is_reserved(*ptr) && known_scheme) {
+            if(!computeOnly) {
+                pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
+
+                /* The percent encoded value gets lower cased also. */
+                if(!(flags & Uri_CREATE_NO_CANONICALIZE)) {
+                    uri->canon_uri[uri->canon_len+1] = towlower(uri->canon_uri[uri->canon_len+1]);
+                    uri->canon_uri[uri->canon_len+2] = towlower(uri->canon_uri[uri->canon_len+2]);
+                }
+            }
+
+            uri->canon_len += 3;
+        } else {
+            if(!computeOnly) {
+                if(!(flags & Uri_CREATE_NO_CANONICALIZE) && known_scheme)
+                    uri->canon_uri[uri->canon_len] = towlower(*ptr);
+                else
+                    uri->canon_uri[uri->canon_len] = *ptr;
+            }
+
+            ++uri->canon_len;
+        }
+    }
+
+    uri->host_len = uri->canon_len - uri->host_start;
+
+    if(!computeOnly)
+        TRACE("(%p %p %lx %d): Canonicalize reg_name=%s len=%ld\n", data, uri, flags,
+            computeOnly, debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
+            uri->host_len);
+
+    if(!computeOnly)
+        find_domain_name(uri->canon_uri+uri->host_start, uri->host_len,
+            &(uri->domain_offset));
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize an implicit IPv4 address. */
+static BOOL canonicalize_implicit_ipv4address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    uri->host_start = uri->canon_len;
+
+    TRACE("%u\n", data->implicit_ipv4);
+    /* For unknown scheme types Windows doesn't convert
+     * the value into an IP address, but it still considers
+     * it an IPv4 address.
+     */
+    if(data->scheme_type == URL_SCHEME_UNKNOWN) {
+        if(!computeOnly)
+            memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
+        uri->canon_len += data->host_len;
+    } else {
+        if(!computeOnly)
+            uri->canon_len += ui2ipv4(uri->canon_uri+uri->canon_len, data->implicit_ipv4);
+        else
+            uri->canon_len += ui2ipv4(NULL, data->implicit_ipv4);
+    }
+
+    uri->host_len = uri->canon_len - uri->host_start;
+    uri->host_type = Uri_HOST_IPV4;
+
+    if(!computeOnly)
+        TRACE("%p %p %lx %d): Canonicalized implicit IP address=%s len=%ld\n",
+            data, uri, flags, computeOnly,
+            debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
+            uri->host_len);
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize an IPv4 address.
+ *
+ * If the parse_data represents a URI that has an implicit IPv4 address
+ * (ex. http://256/, this function will convert 256 into 0.0.1.0). If
+ * the implicit IP address exceeds the value of UINT_MAX (maximum value
+ * for an IPv4 address) it's canonicalized as if it were a reg-name.
+ *
+ * If the parse_data contains a partial or full IPv4 address it normalizes it.
+ * A partial IPv4 address is something like "192.0" and would be normalized to
+ * "192.0.0.0". With a full (or partial) IPv4 address like "192.002.01.003" would
+ * be normalized to "192.2.1.3".
+ *
+ * NOTES:
+ *  Windows ONLY normalizes IPv4 address for known scheme types (one that isn't
+ *  URL_SCHEME_UNKNOWN). For unknown scheme types, it simply copies the data from
+ *  the original URI into the canonicalized URI, but, it still recognizes URI's
+ *  host type as HOST_IPV4.
+ */
+static BOOL canonicalize_ipv4address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    if(data->has_implicit_ip)
+        return canonicalize_implicit_ipv4address(data, uri, flags, computeOnly);
+    else {
+        uri->host_start = uri->canon_len;
+
+        /* Windows only normalizes for known scheme types. */
+        if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+            /* parse_data contains a partial or full IPv4 address, so normalize it. */
+            DWORD i, octetDigitCount = 0, octetCount = 0;
+            BOOL octetHasDigit = FALSE;
+
+            for(i = 0; i < data->host_len; ++i) {
+                if(data->host[i] == '0' && !octetHasDigit) {
+                    /* Can ignore leading zeros if:
+                     *  1) It isn't the last digit of the octet.
+                     *  2) i+1 != data->host_len
+                     *  3) i+1 != '.'
+                     */
+                    if(octetDigitCount == 2 ||
+                       i+1 == data->host_len ||
+                       data->host[i+1] == '.') {
+                        if(!computeOnly)
+                            uri->canon_uri[uri->canon_len] = data->host[i];
+                        ++uri->canon_len;
+                        TRACE("Adding zero\n");
+                    }
+                } else if(data->host[i] == '.') {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = data->host[i];
+                    ++uri->canon_len;
+
+                    octetDigitCount = 0;
+                    octetHasDigit = FALSE;
+                    ++octetCount;
+                } else {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = data->host[i];
+                    ++uri->canon_len;
+
+                    ++octetDigitCount;
+                    octetHasDigit = TRUE;
+                }
+            }
+
+            /* Make sure the canonicalized IP address has 4 dec-octets.
+             * If doesn't add "0" ones until there is 4;
+             */
+            for( ; octetCount < 3; ++octetCount) {
+                if(!computeOnly) {
+                    uri->canon_uri[uri->canon_len] = '.';
+                    uri->canon_uri[uri->canon_len+1] = '0';
+                }
+
+                uri->canon_len += 2;
+            }
+        } else {
+            /* Windows doesn't normalize addresses in unknown schemes. */
+            if(!computeOnly)
+                memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
+            uri->canon_len += data->host_len;
+        }
+
+        uri->host_len = uri->canon_len - uri->host_start;
+        if(!computeOnly)
+            TRACE("(%p %p %lx %d): Canonicalized IPv4 address, ip=%s len=%ld\n",
+                data, uri, flags, computeOnly,
+                debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
+                uri->host_len);
+    }
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize the IPv6 address of the URI.
+ *
+ * Multiple things happen during the canonicalization of an IPv6 address:
+ *  1)  Any leading zero's in a h16 component are removed.
+ *      Ex: [0001:0022::] -> [1:22::]
+ *
+ *  2)  The longest sequence of zero h16 components are compressed
+ *      into a "::" (elision). If there's a tie, the first is chosen.
+ *
+ *      Ex: [0:0:0:0:1:6:7:8]   -> [::1:6:7:8]
+ *          [0:0:0:0:1:2::]     -> [::1:2:0:0]
+ *          [0:0:1:2:0:0:7:8]   -> [::1:2:0:0:7:8]
+ *
+ *  3)  If an IPv4 address is attached to the IPv6 address, it's
+ *      also normalized.
+ *      Ex: [::001.002.022.000] -> [::1.2.22.0]
+ *
+ *  4)  If an elision is present, but, only represents one h16 component
+ *      it's expanded.
+ *
+ *      Ex: [1::2:3:4:5:6:7] -> [1:0:2:3:4:5:6:7]
+ *
+ *  5)  If the IPv6 address contains an IPv4 address and there exists
+ *      at least 1 non-zero h16 component the IPv4 address is converted
+ *      into two h16 components, otherwise it's normalized and kept as is.
+ *
+ *      Ex: [::192.200.003.4]       -> [::192.200.3.4]
+ *          [ffff::192.200.003.4]   -> [ffff::c0c8:3041]
+ *
+ * NOTE:
+ *  For unknown scheme types Windows simply copies the address over without any
+ *  changes.
+ *
+ *  IPv4 address can be included in an elision if all its components are 0's.
+ */
+static BOOL canonicalize_ipv6address(const parse_data *data, Uri *uri,
+                                     DWORD flags, BOOL computeOnly) {
+    uri->host_start = uri->canon_len;
+
+    if(data->scheme_type == URL_SCHEME_UNKNOWN) {
+        if(!computeOnly)
+            memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
+        uri->canon_len += data->host_len;
+    } else {
+        WCHAR buffer[46];
+        ULONG size = ARRAY_SIZE(buffer);
+
+        if(computeOnly) {
+            RtlIpv6AddressToStringExW(&data->ipv6_address, 0, 0, buffer, &size);
+            uri->canon_len += size + 1;
+        } else {
+            uri->canon_uri[uri->canon_len++] = '[';
+            RtlIpv6AddressToStringExW(&data->ipv6_address, 0, 0, uri->canon_uri + uri->canon_len, &size);
+            uri->canon_len += size - 1;
+            uri->canon_uri[uri->canon_len++] = ']';
+        }
+    }
+
+    uri->host_len = uri->canon_len - uri->host_start;
+
+    if(!computeOnly)
+        TRACE("(%p %p %lx %d): Canonicalized IPv6 address %s, len=%ld\n", data, uri, flags,
+            computeOnly, debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
+            uri->host_len);
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize the host of the URI (if any). */
+static BOOL canonicalize_host(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    uri->host_start = -1;
+    uri->host_len = 0;
+    uri->domain_offset = -1;
+
+    if(data->host) {
+        switch(data->host_type) {
+        case Uri_HOST_DNS:
+            uri->host_type = Uri_HOST_DNS;
+            if(!canonicalize_reg_name(data, uri, flags, computeOnly))
+                return FALSE;
+
+            break;
+        case Uri_HOST_IPV4:
+            uri->host_type = Uri_HOST_IPV4;
+            if(!canonicalize_ipv4address(data, uri, flags, computeOnly))
+                return FALSE;
+
+            break;
+        case Uri_HOST_IPV6:
+            if(!canonicalize_ipv6address(data, uri, flags, computeOnly))
+                return FALSE;
+
+            uri->host_type = Uri_HOST_IPV6;
+            break;
+
+        case Uri_HOST_IDN:
+            uri->host_type = Uri_HOST_IDN;
+            if(!canonicalize_reg_name(data, uri, flags, computeOnly))
+                return FALSE;
+
+            break;
+        case Uri_HOST_UNKNOWN:
+            if(data->host_len > 0 || data->scheme_type != URL_SCHEME_FILE) {
+                uri->host_start = uri->canon_len;
+
+                /* Nothing happens to unknown host types. */
+                if(!computeOnly)
+                    memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
+                uri->canon_len += data->host_len;
+                uri->host_len = data->host_len;
+            }
+
+            uri->host_type = Uri_HOST_UNKNOWN;
+            break;
+        default:
+            FIXME("(%p %p %lx %d): Canonicalization for host type %d not supported.\n", data,
+                    uri, flags, computeOnly, data->host_type);
+            return FALSE;
+       }
+   }
+
+   return TRUE;
+}
+
+static BOOL canonicalize_port(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    BOOL has_default_port = FALSE;
+    USHORT default_port = 0;
+    DWORD i;
+
+    uri->port_offset = -1;
+
+    /* Check if the scheme has a default port. */
+    for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
+        if(default_ports[i].scheme == data->scheme_type) {
+            has_default_port = TRUE;
+            default_port = default_ports[i].port;
+            break;
+        }
+    }
+
+    uri->has_port = data->has_port || has_default_port;
+
+    /* Possible cases:
+     *  1)  Has a port which is the default port.
+     *  2)  Has a port (not the default).
+     *  3)  Doesn't have a port, but, scheme has a default port.
+     *  4)  No port.
+     */
+    if(has_default_port && data->has_port && data->port_value == default_port) {
+        /* If it's the default port and this flag isn't set, don't do anything. */
+        if(flags & Uri_CREATE_NO_CANONICALIZE) {
+            uri->port_offset = uri->canon_len-uri->authority_start;
+            if(!computeOnly)
+                uri->canon_uri[uri->canon_len] = ':';
+            ++uri->canon_len;
+
+            if(data->port) {
+                /* Copy the original port over. */
+                if(!computeOnly)
+                    memcpy(uri->canon_uri+uri->canon_len, data->port, data->port_len*sizeof(WCHAR));
+                uri->canon_len += data->port_len;
+            } else {
+                if(!computeOnly)
+                    uri->canon_len += ui2str(uri->canon_uri+uri->canon_len, data->port_value);
+                else
+                    uri->canon_len += ui2str(NULL, data->port_value);
+            }
+        }
+
+        uri->port = default_port;
+    } else if(data->has_port) {
+        uri->port_offset = uri->canon_len-uri->authority_start;
+        if(!computeOnly)
+            uri->canon_uri[uri->canon_len] = ':';
+        ++uri->canon_len;
+
+        if(flags & Uri_CREATE_NO_CANONICALIZE && data->port) {
+            /* Copy the original over without changes. */
+            if(!computeOnly)
+                memcpy(uri->canon_uri+uri->canon_len, data->port, data->port_len*sizeof(WCHAR));
+            uri->canon_len += data->port_len;
+        } else {
+            if(!computeOnly)
+                uri->canon_len += ui2str(uri->canon_uri+uri->canon_len, data->port_value);
+            else
+                uri->canon_len += ui2str(NULL, data->port_value);
+        }
+
+        uri->port = data->port_value;
+    } else if(has_default_port)
+        uri->port = default_port;
+
+    return TRUE;
+}
+
+/* Canonicalizes the authority of the URI represented by the parse_data. */
+static BOOL canonicalize_authority(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    uri->authority_start = uri->canon_len;
+    uri->authority_len = 0;
+
+    if(!canonicalize_userinfo(data, uri, flags, computeOnly))
+        return FALSE;
+
+    if(!canonicalize_host(data, uri, flags, computeOnly))
+        return FALSE;
+
+    if(!canonicalize_port(data, uri, flags, computeOnly))
+        return FALSE;
+
+    if(uri->host_start != -1 || (data->is_relative && (data->password || data->username)))
+        uri->authority_len = uri->canon_len - uri->authority_start;
+    else
+        uri->authority_start = -1;
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize the path of a hierarchical URI.
+ *
+ * Things that happen:
+ *  1). Forbidden characters are percent encoded, unless the NO_ENCODE_FORBIDDEN
+ *      flag is set or it's a file URI. Forbidden characters are always encoded
+ *      for file schemes regardless and forbidden characters are never encoded
+ *      for unknown scheme types.
+ *
+ *  2). For known scheme types '\\' are changed to '/'.
+ *
+ *  3). Percent encoded, unreserved characters are decoded to their actual values.
+ *      Unless the scheme type is unknown. For file schemes any percent encoded
+ *      character in the unreserved or reserved set is decoded.
+ *
+ *  4). For File schemes if the path is starts with a drive letter and doesn't
+ *      start with a '/' then one is appended.
+ *      Ex: file://c:/test.mp3 -> file:///c:/test.mp3
+ *
+ *  5). Dot segments are removed from the path for all scheme types
+ *      unless NO_CANONICALIZE flag is set. Dot segments aren't removed
+ *      for wildcard scheme types.
+ *
+ * NOTES:
+ *      file://c:/test%20test   -> file:///c:/test%2520test
+ *      file://c:/test%3Etest   -> file:///c:/test%253Etest
+ * if Uri_CREATE_FILE_USE_DOS_PATH is not set:
+ *      file:///c:/test%20test  -> file:///c:/test%20test
+ *      file:///c:/test%test    -> file:///c:/test%25test
+ */
+static DWORD canonicalize_path_hierarchical(const WCHAR *path, DWORD path_len, URL_SCHEME scheme_type, BOOL has_host, DWORD flags,
+        BOOL is_implicit_scheme, WCHAR *ret_path) {
+    const BOOL known_scheme = scheme_type != URL_SCHEME_UNKNOWN;
+    const BOOL is_file = scheme_type == URL_SCHEME_FILE;
+    const BOOL is_res = scheme_type == URL_SCHEME_RES;
+    const WCHAR *ptr;
+    BOOL escape_pct = FALSE;
+    DWORD len = 0;
+
+    if(!path)
+        return 0;
+
+    ptr = path;
+
+    if(is_file && !has_host) {
+        /* Check if a '/' needs to be appended for the file scheme. */
+        if(path_len > 1 && is_drive_path(ptr) && !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+            if(ret_path)
+                ret_path[len] = '/';
+            len++;
+            escape_pct = TRUE;
+        } else if(*ptr == '/') {
+            if(!(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+                /* Copy the extra '/' over. */
+                if(ret_path)
+                    ret_path[len] = '/';
+                len++;
+            }
+            ++ptr;
+        }
+
+        if(is_drive_path(ptr)) {
+            if(ret_path) {
+                ret_path[len] = *ptr;
+                /* If there's a '|' after the drive letter, convert it to a ':'. */
+                ret_path[len+1] = ':';
+            }
+            ptr += 2;
+            len += 2;
+        }
+    }
+
+    if(!is_file && *path && *path != '/') {
+        /* Prepend a '/' to the path if it doesn't have one. */
+        if(ret_path)
+            ret_path[len] = '/';
+        len++;
+    }
+
+    for(; ptr < path+path_len; ++ptr) {
+        BOOL do_default_action = TRUE;
+
+        if(*ptr == '%' && !is_res) {
+            const WCHAR *tmp = ptr;
+            WCHAR val;
+
+            /* Check if the % represents a valid encoded char, or if it needs encoding. */
+            BOOL force_encode = !check_pct_encoded(&tmp) && is_file && !(flags&Uri_CREATE_FILE_USE_DOS_PATH);
+            val = decode_pct_val(ptr);
+
+            if(force_encode || escape_pct) {
+                /* Escape the percent sign in the file URI. */
+                if(ret_path)
+                    pct_encode_val(*ptr, ret_path+len);
+                len += 3;
+                do_default_action = FALSE;
+            } else if((is_unreserved(val) && known_scheme) ||
+                      (is_file && !is_implicit_scheme && (is_unreserved(val) || is_reserved(val) ||
+                      (val && flags&Uri_CREATE_FILE_USE_DOS_PATH && !is_forbidden_dos_path_char(val))))) {
+                if(ret_path)
+                    ret_path[len] = val;
+                len++;
+
+                ptr += 2;
+                continue;
+            }
+        } else if(*ptr == '/' && is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+            /* Convert the '/' back to a '\\'. */
+            if(ret_path)
+                ret_path[len] = '\\';
+            len++;
+            do_default_action = FALSE;
+        } else if(*ptr == '\\' && known_scheme) {
+            if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH))) {
+                /* Convert '\\' into a '/'. */
+                if(ret_path)
+                    ret_path[len] = '/';
+                len++;
+                do_default_action = FALSE;
+            }
+        } else if(known_scheme && !is_res && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr) &&
+                  (!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) || is_file)) {
+            if(!is_file || !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+                /* Escape the forbidden character. */
+                if(ret_path)
+                    pct_encode_val(*ptr, ret_path+len);
+                len += 3;
+                do_default_action = FALSE;
+            }
+        }
+
+        if(do_default_action) {
+            if(ret_path)
+                ret_path[len] = *ptr;
+            len++;
+        }
+    }
+
+    /* Removing the dot segments only happens when it's not in
+     * computeOnly mode and it's not a wildcard scheme. File schemes
+     * with USE_DOS_PATH set don't get dot segments removed.
+     */
+    if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) &&
+       scheme_type != URL_SCHEME_WILDCARD) {
+        if(!(flags & Uri_CREATE_NO_CANONICALIZE) && ret_path) {
+            /* Remove the dot segments (if any) and reset everything to the new
+             * correct length.
+             */
+            len = remove_dot_segments(ret_path, len);
+        }
+    }
+
+    if(ret_path)
+        TRACE("Canonicalized path %s len=%ld\n", debugstr_wn(ret_path, len), len);
+    return len;
+}
+
+/* Attempts to canonicalize the path for an opaque URI.
+ *
+ * For known scheme types:
+ *  1)  forbidden characters are percent encoded if
+ *      NO_ENCODE_FORBIDDEN_CHARACTERS isn't set.
+ *
+ *  2)  Percent encoded, unreserved characters are decoded
+ *      to their actual values, for known scheme types.
+ *
+ *  3)  '\\' are changed to '/' for known scheme types
+ *      except for mailto schemes.
+ *
+ *  4)  For file schemes, if USE_DOS_PATH is set all '/'
+ *      are converted to backslashes.
+ *
+ *  5)  For file schemes, if USE_DOS_PATH isn't set all '\'
+ *      are converted to forward slashes.
+ */
+static BOOL canonicalize_path_opaque(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    const WCHAR *ptr;
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+    const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
+    const BOOL is_mk = data->scheme_type == URL_SCHEME_MK;
+
+    if(!data->path) {
+        uri->path_start = -1;
+        uri->path_len = 0;
+        return TRUE;
+    }
+
+    uri->path_start = uri->canon_len;
+
+    if(is_mk){
+        /* hijack this flag for SCHEME_MK to tell the function when to start
+         * converting slashes */
+        flags |= Uri_CREATE_FILE_USE_DOS_PATH;
+    }
+
+    /* For javascript: URIs, simply copy path part without any canonicalization */
+    if(data->scheme_type == URL_SCHEME_JAVASCRIPT) {
+        if(!computeOnly)
+            memcpy(uri->canon_uri+uri->canon_len, data->path, data->path_len*sizeof(WCHAR));
+        uri->path_len = data->path_len;
+        uri->canon_len += data->path_len;
+        return TRUE;
+    }
+
+    /* Windows doesn't allow a "//" to appear after the scheme
+     * of a URI, if it's an opaque URI.
+     */
+    if(data->scheme && *(data->path) == '/' && *(data->path+1) == '/') {
+        /* So it inserts a "/." before the "//" if it exists. */
+        if(!computeOnly) {
+            uri->canon_uri[uri->canon_len] = '/';
+            uri->canon_uri[uri->canon_len+1] = '.';
+        }
+
+        uri->canon_len += 2;
+    }
+
+    for(ptr = data->path; ptr < data->path+data->path_len; ++ptr) {
+        BOOL do_default_action = TRUE;
+
+        if(*ptr == '%' && known_scheme) {
+            WCHAR val = decode_pct_val(ptr);
+
+            if(is_unreserved(val)) {
+                if(!computeOnly)
+                    uri->canon_uri[uri->canon_len] = val;
+                ++uri->canon_len;
+
+                ptr += 2;
+                continue;
+            }
+        } else if(*ptr == '/' && is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+            if(!computeOnly)
+                uri->canon_uri[uri->canon_len] = '\\';
+            ++uri->canon_len;
+            do_default_action = FALSE;
+        } else if(*ptr == '\\') {
+            if((data->is_relative || is_mk || is_file) && !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
+                /* Convert to a '/'. */
+                if(!computeOnly)
+                    uri->canon_uri[uri->canon_len] = '/';
+                ++uri->canon_len;
+                do_default_action = FALSE;
+            }
+        } else if(is_mk && *ptr == ':' && ptr + 1 < data->path + data->path_len && *(ptr + 1) == ':') {
+            flags &= ~Uri_CREATE_FILE_USE_DOS_PATH;
+        } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr) &&
+                  !(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
+            if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH))) {
+                if(!computeOnly)
+                    pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
+                uri->canon_len += 3;
+                do_default_action = FALSE;
+            }
+        }
+
+        if(do_default_action) {
+            if(!computeOnly)
+                uri->canon_uri[uri->canon_len] = *ptr;
+            ++uri->canon_len;
+        }
+    }
+
+    if(is_mk && !computeOnly && !(flags & Uri_CREATE_NO_CANONICALIZE)) {
+        DWORD new_len = remove_dot_segments(uri->canon_uri + uri->path_start,
+                                            uri->canon_len - uri->path_start);
+        uri->canon_len = uri->path_start + new_len;
+    }
+
+    uri->path_len = uri->canon_len - uri->path_start;
+
+    if(!computeOnly)
+        TRACE("(%p %p %lx %d): Canonicalized opaque URI path %s len=%ld\n", data, uri, flags, computeOnly,
+            debugstr_wn(uri->canon_uri+uri->path_start, uri->path_len), uri->path_len);
+    return TRUE;
+}
+
+/* Determines how the URI represented by the parse_data should be canonicalized.
+ *
+ * Essentially, if the parse_data represents an hierarchical URI then it calls
+ * canonicalize_authority and the canonicalization functions for the path. If the
+ * URI is opaque it canonicalizes the path of the URI.
+ */
+static BOOL canonicalize_hierpart(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    if(!data->is_opaque || (data->is_relative && (data->password || data->username))) {
+        /* "//" is only added for non-wildcard scheme types.
+         *
+         * A "//" is only added to a relative URI if it has a
+         * host or port component (this only happens if a IUriBuilder
+         * is generating an IUri).
+         */
+        if((data->is_relative && (data->host || data->has_port)) ||
+           (!data->is_relative && data->scheme_type != URL_SCHEME_WILDCARD)) {
+            if(data->scheme_type == URL_SCHEME_WILDCARD)
+                FIXME("Here\n");
+
+            if(!computeOnly) {
+                INT pos = uri->canon_len;
+
+                uri->canon_uri[pos] = '/';
+                uri->canon_uri[pos+1] = '/';
+           }
+           uri->canon_len += 2;
+        }
+
+        if(!canonicalize_authority(data, uri, flags, computeOnly))
+            return FALSE;
+
+        if(data->is_relative && (data->password || data->username)) {
+            if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
+                return FALSE;
+        } else {
+            if(!computeOnly)
+                uri->path_start = uri->canon_len;
+            uri->path_len = canonicalize_path_hierarchical(data->path, data->path_len, data->scheme_type, data->host_len != 0,
+                    flags, data->has_implicit_scheme, computeOnly ? NULL : uri->canon_uri+uri->canon_len);
+            uri->canon_len += uri->path_len;
+            if(!computeOnly && !uri->path_len)
+                uri->path_start = -1;
+        }
+    } else {
+        /* Opaque URI's don't have an authority. */
+        uri->userinfo_start = uri->userinfo_split = -1;
+        uri->userinfo_len = 0;
+        uri->host_start = -1;
+        uri->host_len = 0;
+        uri->host_type = Uri_HOST_UNKNOWN;
+        uri->has_port = FALSE;
+        uri->authority_start = -1;
+        uri->authority_len = 0;
+        uri->domain_offset = -1;
+        uri->port_offset = -1;
+
+        if(is_hierarchical_scheme(data->scheme_type)) {
+            DWORD i;
+
+            /* Absolute URIs aren't displayed for known scheme types
+             * which should be hierarchical URIs.
+             */
+            uri->display_modifiers |= URI_DISPLAY_NO_ABSOLUTE_URI;
+
+            /* Windows also sets the port for these (if they have one). */
+            for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
+                if(data->scheme_type == default_ports[i].scheme) {
+                    uri->has_port = TRUE;
+                    uri->port = default_ports[i].port;
+                    break;
+                }
+            }
+        }
+
+        if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
+            return FALSE;
+    }
+
+    if(uri->path_start > -1 && !computeOnly)
+        /* Finding file extensions happens for both types of URIs. */
+        uri->extension_offset = find_file_extension(uri->canon_uri+uri->path_start, uri->path_len);
+    else
+        uri->extension_offset = -1;
+
+    return TRUE;
+}
+
+/* Attempts to canonicalize the query string of the URI.
+ *
+ * Things that happen:
+ *  1)  For known scheme types forbidden characters
+ *      are percent encoded, unless the NO_DECODE_EXTRA_INFO flag is set
+ *      or NO_ENCODE_FORBIDDEN_CHARACTERS is set.
+ *
+ *  2)  For known scheme types, percent encoded, unreserved characters
+ *      are decoded as long as the NO_DECODE_EXTRA_INFO flag isn't set.
+ */
+static BOOL canonicalize_query(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    const WCHAR *ptr, *end;
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+
+    if(!data->query) {
+        uri->query_start = -1;
+        uri->query_len = 0;
+        return TRUE;
+    }
+
+    uri->query_start = uri->canon_len;
+
+    end = data->query+data->query_len;
+    for(ptr = data->query; ptr < end; ++ptr) {
+        if(*ptr == '%') {
+            if(known_scheme && !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
+                WCHAR val = decode_pct_val(ptr);
+                if(is_unreserved(val)) {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = val;
+                    ++uri->canon_len;
+
+                    ptr += 2;
+                    continue;
+                }
+            }
+        } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr)) {
+            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) &&
+               !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
+                if(!computeOnly)
+                    pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
+                uri->canon_len += 3;
+                continue;
+            }
+        }
+
+        if(!computeOnly)
+            uri->canon_uri[uri->canon_len] = *ptr;
+        ++uri->canon_len;
+    }
+
+    uri->query_len = uri->canon_len - uri->query_start;
+
+    if(!computeOnly)
+        TRACE("(%p %p %lx %d): Canonicalized query string %s len=%ld\n", data, uri, flags,
+            computeOnly, debugstr_wn(uri->canon_uri+uri->query_start, uri->query_len),
+            uri->query_len);
+    return TRUE;
+}
+
+static BOOL canonicalize_fragment(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    const WCHAR *ptr, *end;
+    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
+
+    if(!data->fragment) {
+        uri->fragment_start = -1;
+        uri->fragment_len = 0;
+        return TRUE;
+    }
+
+    uri->fragment_start = uri->canon_len;
+
+    end = data->fragment + data->fragment_len;
+    for(ptr = data->fragment; ptr < end; ++ptr) {
+        if(*ptr == '%') {
+            if(known_scheme && !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
+                WCHAR val = decode_pct_val(ptr);
+                if(is_unreserved(val)) {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = val;
+                    ++uri->canon_len;
+
+                    ptr += 2;
+                    continue;
+                }
+            }
+        } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr)) {
+            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) &&
+               !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
+                if(!computeOnly)
+                    pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
+                uri->canon_len += 3;
+                continue;
+            }
+        }
+
+        if(!computeOnly)
+            uri->canon_uri[uri->canon_len] = *ptr;
+        ++uri->canon_len;
+    }
+
+    uri->fragment_len = uri->canon_len - uri->fragment_start;
+
+    if(!computeOnly)
+        TRACE("(%p %p %lx %d): Canonicalized fragment %s len=%ld\n", data, uri, flags,
+            computeOnly, debugstr_wn(uri->canon_uri+uri->fragment_start, uri->fragment_len),
+            uri->fragment_len);
+    return TRUE;
+}
+
+/* Canonicalizes the scheme information specified in the parse_data using the specified flags. */
+static BOOL canonicalize_scheme(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    uri->scheme_start = -1;
+    uri->scheme_len = 0;
+
+    if(!data->scheme) {
+        /* The only type of URI that doesn't have to have a scheme is a relative
+         * URI.
+         */
+        if(!data->is_relative) {
+            FIXME("(%p %p %lx): Unable to determine the scheme type of %s.\n", data,
+                    uri, flags, debugstr_w(data->uri));
+            return FALSE;
+        }
+    } else {
+        if(!computeOnly) {
+            DWORD i;
+            INT pos = uri->canon_len;
+
+            for(i = 0; i < data->scheme_len; ++i) {
+                /* Scheme name must be lower case after canonicalization. */
+                uri->canon_uri[i + pos] = towlower(data->scheme[i]);
+            }
+
+            uri->canon_uri[i + pos] = ':';
+            uri->scheme_start = pos;
+
+            TRACE("(%p %p %lx): Canonicalized scheme=%s, len=%ld.\n", data, uri, flags,
+                    debugstr_wn(uri->canon_uri+uri->scheme_start,  data->scheme_len), data->scheme_len);
+        }
+
+        /* This happens in both computation modes. */
+        uri->canon_len += data->scheme_len + 1;
+        uri->scheme_len = data->scheme_len;
+    }
+    return TRUE;
+}
+
+/* Computes what the length of the URI specified by the parse_data will be
+ * after canonicalization occurs using the specified flags.
+ *
+ * This function will return a non-zero value indicating the length of the canonicalized
+ * URI, or -1 on error.
+ */
+static int compute_canonicalized_length(const parse_data *data, DWORD flags) {
+    Uri uri;
+
+    memset(&uri, 0, sizeof(Uri));
+
+    TRACE("(%p %lx): Beginning to compute canonicalized length for URI %s\n", data, flags,
+            debugstr_w(data->uri));
+
+    if(!canonicalize_scheme(data, &uri, flags, TRUE)) {
+        ERR("(%p %lx): Failed to compute URI scheme length.\n", data, flags);
+        return -1;
+    }
+
+    if(!canonicalize_hierpart(data, &uri, flags, TRUE)) {
+        ERR("(%p %lx): Failed to compute URI hierpart length.\n", data, flags);
+        return -1;
+    }
+
+    if(!canonicalize_query(data, &uri, flags, TRUE)) {
+        ERR("(%p %lx): Failed to compute query string length.\n", data, flags);
+        return -1;
+    }
+
+    if(!canonicalize_fragment(data, &uri, flags, TRUE)) {
+        ERR("(%p %lx): Failed to compute fragment length.\n", data, flags);
+        return -1;
+    }
+
+    TRACE("(%p %lx): Finished computing canonicalized URI length. length=%ld\n", data, flags, uri.canon_len);
+
+    return uri.canon_len;
+}
+
+/* Canonicalizes the URI data specified in the parse_data, using the given flags. If the
+ * canonicalization succeeds it will store all the canonicalization information
+ * in the pointer to the Uri.
+ *
+ * To canonicalize a URI this function first computes what the length of the URI
+ * specified by the parse_data will be. Once this is done it will then perform the actual
+ * canonicalization of the URI.
+ */
+static HRESULT canonicalize_uri(const parse_data *data, Uri *uri, DWORD flags) {
+    INT len;
+
+    uri->canon_uri = NULL;
+    uri->canon_size = uri->canon_len = 0;
+
+    TRACE("(%p %p %lx): beginning to canonicalize URI %s.\n", data, uri, flags, debugstr_w(data->uri));
+
+    /* First try to compute the length of the URI. */
+    len = compute_canonicalized_length(data, flags);
+    if(len == -1) {
+        ERR("(%p %p %lx): Could not compute the canonicalized length of %s.\n", data, uri, flags,
+                debugstr_w(data->uri));
+        return E_INVALIDARG;
+    }
+
+    uri->canon_uri = malloc((len + 1) * sizeof(WCHAR));
+    if(!uri->canon_uri)
+        return E_OUTOFMEMORY;
+
+    uri->canon_size = len;
+    if(!canonicalize_scheme(data, uri, flags, FALSE)) {
+        ERR("(%p %p %lx): Unable to canonicalize the scheme of the URI.\n", data, uri, flags);
+        return E_INVALIDARG;
+    }
+    uri->scheme_type = data->scheme_type;
+
+    if(!canonicalize_hierpart(data, uri, flags, FALSE)) {
+        ERR("(%p %p %lx): Unable to canonicalize the hierpart of the URI\n", data, uri, flags);
+        return E_INVALIDARG;
+    }
+
+    if(!canonicalize_query(data, uri, flags, FALSE)) {
+        ERR("(%p %p %lx): Unable to canonicalize query string of the URI.\n",
+            data, uri, flags);
+        return E_INVALIDARG;
+    }
+
+    if(!canonicalize_fragment(data, uri, flags, FALSE)) {
+        ERR("(%p %p %lx): Unable to canonicalize fragment of the URI.\n",
+            data, uri, flags);
+        return E_INVALIDARG;
+    }
+
+    /* There's a possibility we didn't use all the space we allocated
+     * earlier.
+     */
+    if(uri->canon_len < uri->canon_size) {
+        /* This happens if the URI is hierarchical and dot
+         * segments were removed from its path.
+         */
+        WCHAR *tmp = realloc(uri->canon_uri, (uri->canon_len + 1) * sizeof(WCHAR));
+        if(!tmp)
+            return E_OUTOFMEMORY;
+
+        uri->canon_uri = tmp;
+        uri->canon_size = uri->canon_len;
+    }
+
+    uri->canon_uri[uri->canon_len] = '\0';
+    TRACE("(%p %p %lx): finished canonicalizing the URI. uri=%s\n", data, uri, flags, debugstr_w(uri->canon_uri));
+
+    return S_OK;
+}
+
+static HRESULT get_builder_component(LPWSTR *component, DWORD *component_len,
+                                     LPCWSTR source, DWORD source_len,
+                                     LPCWSTR *output, DWORD *output_len)
+{
+    if(!output_len) {
+        if(output)
+            *output = NULL;
+        return E_POINTER;
+    }
+
+    if(!output) {
+        *output_len = 0;
+        return E_POINTER;
+    }
+
+    if(!(*component) && source) {
+        /* Allocate 'component', and copy the contents from 'source'
+         * into the new allocation.
+         */
+        *component = malloc((source_len + 1) * sizeof(WCHAR));
+        if(!(*component))
+            return E_OUTOFMEMORY;
+
+        memcpy(*component, source, source_len*sizeof(WCHAR));
+        (*component)[source_len] = '\0';
+        *component_len = source_len;
+    }
+
+    *output = *component;
+    *output_len = *component_len;
+    return *output ? S_OK : S_FALSE;
+}
+
+/* Allocates 'component' and copies the string from 'new_value' into 'component'.
+ * If 'prefix' is set and 'new_value' isn't NULL, then it checks if 'new_value'
+ * starts with 'prefix'. If it doesn't then 'prefix' is prepended to 'component'.
+ *
+ * If everything is successful, then will set 'success_flag' in 'flags'.
+ */
+static HRESULT set_builder_component(LPWSTR *component, DWORD *component_len, LPCWSTR new_value,
+                                     WCHAR prefix, DWORD *flags, DWORD success_flag)
+{
+    free(*component);
+
+    if(!new_value) {
+        *component = NULL;
+        *component_len = 0;
+    } else {
+        BOOL add_prefix = FALSE;
+        DWORD len = lstrlenW(new_value);
+        DWORD pos = 0;
+
+        if(prefix && *new_value != prefix) {
+            add_prefix = TRUE;
+            *component = malloc((len + 2) * sizeof(WCHAR));
+        } else
+            *component = malloc((len + 1) * sizeof(WCHAR));
+
+        if(!(*component))
+            return E_OUTOFMEMORY;
+
+        if(add_prefix)
+            (*component)[pos++] = prefix;
+
+        memcpy(*component+pos, new_value, (len+1)*sizeof(WCHAR));
+        *component_len = len+pos;
+    }
+
+    *flags |= success_flag;
+    return S_OK;
+}
+
+static void reset_builder(UriBuilder *builder) {
+    if(builder->uri)
+        IUri_Release(&builder->uri->IUri_iface);
+    builder->uri = NULL;
+
+    free(builder->fragment);
+    builder->fragment = NULL;
+    builder->fragment_len = 0;
+
+    free(builder->host);
+    builder->host = NULL;
+    builder->host_len = 0;
+
+    free(builder->password);
+    builder->password = NULL;
+    builder->password_len = 0;
+
+    free(builder->path);
+    builder->path = NULL;
+    builder->path_len = 0;
+
+    free(builder->query);
+    builder->query = NULL;
+    builder->query_len = 0;
+
+    free(builder->scheme);
+    builder->scheme = NULL;
+    builder->scheme_len = 0;
+
+    free(builder->username);
+    builder->username = NULL;
+    builder->username_len = 0;
+
+    builder->has_port = FALSE;
+    builder->port = 0;
+    builder->modified_props = 0;
+}
+
+static HRESULT validate_scheme_name(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    const WCHAR *component;
+    const WCHAR *ptr;
+    const WCHAR **pptr;
+    DWORD expected_len;
+
+    if(builder->scheme) {
+        ptr = builder->scheme;
+        expected_len = builder->scheme_len;
+    } else if(builder->uri && builder->uri->scheme_start > -1) {
+        ptr = builder->uri->canon_uri+builder->uri->scheme_start;
+        expected_len = builder->uri->scheme_len;
+    } else {
+        ptr = L"";
+        expected_len = 0;
+    }
+
+    component = ptr;
+    pptr = &ptr;
+    if(parse_scheme(pptr, data, flags, ALLOW_NULL_TERM_SCHEME) &&
+       data->scheme_len == expected_len) {
+        if(data->scheme)
+            TRACE("(%p %p %lx): Found valid scheme component %s len=%ld.\n", builder, data, flags,
+               debugstr_wn(data->scheme, data->scheme_len), data->scheme_len);
+    } else {
+        TRACE("(%p %p %lx): Invalid scheme component found %s.\n", builder, data, flags,
+            debugstr_wn(component, expected_len));
+        return INET_E_INVALID_URL;
+   }
+
+    return S_OK;
+}
+
+static HRESULT validate_username(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    const WCHAR *ptr;
+    const WCHAR **pptr;
+    DWORD expected_len;
+
+    if(builder->username) {
+        ptr = builder->username;
+        expected_len = builder->username_len;
+    } else if(!(builder->modified_props & Uri_HAS_USER_NAME) && builder->uri &&
+              builder->uri->userinfo_start > -1 && builder->uri->userinfo_split != 0) {
+        /* Just use the username from the base Uri. */
+        data->username = builder->uri->canon_uri+builder->uri->userinfo_start;
+        data->username_len = (builder->uri->userinfo_split > -1) ?
+                                        builder->uri->userinfo_split : builder->uri->userinfo_len;
+        ptr = NULL;
+    } else {
+        ptr = NULL;
+        expected_len = 0;
+    }
+
+    if(ptr) {
+        const WCHAR *component = ptr;
+        pptr = &ptr;
+        if(parse_username(pptr, data, flags, ALLOW_NULL_TERM_USER_NAME) &&
+           data->username_len == expected_len)
+            TRACE("(%p %p %lx): Found valid username component %s len=%ld.\n", builder, data, flags,
+                debugstr_wn(data->username, data->username_len), data->username_len);
+        else {
+            TRACE("(%p %p %lx): Invalid username component found %s.\n", builder, data, flags,
+                debugstr_wn(component, expected_len));
+            return INET_E_INVALID_URL;
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT validate_password(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    const WCHAR *ptr;
+    const WCHAR **pptr;
+    DWORD expected_len;
+
+    if(builder->password) {
+        ptr = builder->password;
+        expected_len = builder->password_len;
+    } else if(!(builder->modified_props & Uri_HAS_PASSWORD) && builder->uri &&
+              builder->uri->userinfo_split > -1) {
+        data->password = builder->uri->canon_uri+builder->uri->userinfo_start+builder->uri->userinfo_split+1;
+        data->password_len = builder->uri->userinfo_len-builder->uri->userinfo_split-1;
+        ptr = NULL;
+    } else {
+        ptr = NULL;
+        expected_len = 0;
+    }
+
+    if(ptr) {
+        const WCHAR *component = ptr;
+        pptr = &ptr;
+        if(parse_password(pptr, data, flags, ALLOW_NULL_TERM_PASSWORD) &&
+           data->password_len == expected_len)
+            TRACE("(%p %p %lx): Found valid password component %s len=%ld.\n", builder, data, flags,
+                debugstr_wn(data->password, data->password_len), data->password_len);
+        else {
+            TRACE("(%p %p %lx): Invalid password component found %s.\n", builder, data, flags,
+                debugstr_wn(component, expected_len));
+            return INET_E_INVALID_URL;
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT validate_userinfo(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    HRESULT hr;
+
+    hr = validate_username(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    hr = validate_password(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    return S_OK;
+}
+
+static HRESULT validate_host(const UriBuilder *builder, parse_data *data) {
+    const WCHAR *ptr;
+    const WCHAR **pptr;
+    DWORD expected_len;
+
+    if(builder->host) {
+        ptr = builder->host;
+        expected_len = builder->host_len;
+    } else if(!(builder->modified_props & Uri_HAS_HOST) && builder->uri && builder->uri->host_start > -1) {
+        ptr = builder->uri->canon_uri + builder->uri->host_start;
+        expected_len = builder->uri->host_len;
+    } else
+        ptr = NULL;
+
+    if(ptr) {
+        const WCHAR *component = ptr;
+        DWORD extras = ALLOW_BRACKETLESS_IP_LITERAL|IGNORE_PORT_DELIMITER|SKIP_IP_FUTURE_CHECK;
+        pptr = &ptr;
+
+        if(parse_host(pptr, data, extras) && data->host_len == expected_len)
+            TRACE("(%p %p): Found valid host name %s len=%ld type=%d.\n", builder, data,
+                debugstr_wn(data->host, data->host_len), data->host_len, data->host_type);
+        else {
+            TRACE("(%p %p): Invalid host name found %s.\n", builder, data,
+                debugstr_wn(component, expected_len));
+            return INET_E_INVALID_URL;
+        }
+    }
+
+    return S_OK;
+}
+
+static void setup_port(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    if(builder->modified_props & Uri_HAS_PORT) {
+        if(builder->has_port) {
+            data->has_port = TRUE;
+            data->port_value = builder->port;
+        }
+    } else if(builder->uri && builder->uri->has_port) {
+        data->has_port = TRUE;
+        data->port_value = builder->uri->port;
+    }
+
+    if(data->has_port)
+        TRACE("(%p %p %lx): Using %lu as port for IUri.\n", builder, data, flags, data->port_value);
+}
+
+static HRESULT validate_path(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    const WCHAR *ptr = NULL;
+    const WCHAR *component;
+    const WCHAR **pptr;
+    DWORD expected_len;
+    BOOL check_len = TRUE;
+    BOOL valid = FALSE;
+
+    if(builder->path) {
+        ptr = builder->path;
+        expected_len = builder->path_len;
+    } else if(!(builder->modified_props & Uri_HAS_PATH) &&
+              builder->uri && builder->uri->path_start > -1) {
+        ptr = builder->uri->canon_uri+builder->uri->path_start;
+        expected_len = builder->uri->path_len;
+    } else {
+        ptr = L"";
+        check_len = FALSE;
+        expected_len = -1;
+    }
+
+    component = ptr;
+    pptr = &ptr;
+
+    /* How the path is validated depends on what type of
+     * URI it is.
+     */
+    valid = data->is_opaque ?
+        parse_path_opaque(pptr, data, flags) : parse_path_hierarchical(pptr, data, flags);
+
+    if(!valid || (check_len && expected_len != data->path_len)) {
+        TRACE("(%p %p %lx): Invalid path component %s.\n", builder, data, flags,
+            debugstr_wn(component, expected_len) );
+        return INET_E_INVALID_URL;
+    }
+
+    TRACE("(%p %p %lx): Valid path component %s len=%ld.\n", builder, data, flags,
+        debugstr_wn(data->path, data->path_len), data->path_len);
+
+    return S_OK;
+}
+
+static HRESULT validate_query(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    const WCHAR *ptr = NULL;
+    const WCHAR **pptr;
+    DWORD expected_len;
+
+    if(builder->query) {
+        ptr = builder->query;
+        expected_len = builder->query_len;
+    } else if(!(builder->modified_props & Uri_HAS_QUERY) && builder->uri &&
+              builder->uri->query_start > -1) {
+        ptr = builder->uri->canon_uri+builder->uri->query_start;
+        expected_len = builder->uri->query_len;
+    }
+
+    if(ptr) {
+        const WCHAR *component = ptr;
+        pptr = &ptr;
+
+        if(parse_query(pptr, data, flags) && expected_len == data->query_len)
+            TRACE("(%p %p %lx): Valid query component %s len=%ld.\n", builder, data, flags,
+                debugstr_wn(data->query, data->query_len), data->query_len);
+        else {
+            TRACE("(%p %p %lx): Invalid query component %s.\n", builder, data, flags,
+                debugstr_wn(component, expected_len));
+            return INET_E_INVALID_URL;
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT validate_fragment(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    const WCHAR *ptr = NULL;
+    const WCHAR **pptr;
+    DWORD expected_len;
+
+    if(builder->fragment) {
+        ptr = builder->fragment;
+        expected_len = builder->fragment_len;
+    } else if(!(builder->modified_props & Uri_HAS_FRAGMENT) && builder->uri &&
+              builder->uri->fragment_start > -1) {
+        ptr = builder->uri->canon_uri+builder->uri->fragment_start;
+        expected_len = builder->uri->fragment_len;
+    }
+
+    if(ptr) {
+        const WCHAR *component = ptr;
+        pptr = &ptr;
+
+        if(parse_fragment(pptr, data, flags) && expected_len == data->fragment_len)
+            TRACE("(%p %p %lx): Valid fragment component %s len=%ld.\n", builder, data, flags,
+                debugstr_wn(data->fragment, data->fragment_len), data->fragment_len);
+        else {
+            TRACE("(%p %p %lx): Invalid fragment component %s.\n", builder, data, flags,
+                debugstr_wn(component, expected_len));
+            return INET_E_INVALID_URL;
+        }
+    }
+
+    return S_OK;
+}
+
+static HRESULT validate_components(const UriBuilder *builder, parse_data *data, DWORD flags) {
+    HRESULT hr;
+
+    memset(data, 0, sizeof(parse_data));
+
+    TRACE("(%p %p %lx): Beginning to validate builder components.\n", builder, data, flags);
+
+    hr = validate_scheme_name(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    /* Extra validation for file schemes. */
+    if(data->scheme_type == URL_SCHEME_FILE) {
+        if((builder->password || (builder->uri && builder->uri->userinfo_split > -1)) ||
+           (builder->username || (builder->uri && builder->uri->userinfo_start > -1))) {
+            TRACE("(%p %p %lx): File schemes can't contain a username or password.\n",
+                builder, data, flags);
+            return INET_E_INVALID_URL;
+        }
+    }
+
+    hr = validate_userinfo(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    hr = validate_host(builder, data);
+    if(FAILED(hr))
+        return hr;
+
+    setup_port(builder, data, flags);
+
+    /* The URI is opaque if it doesn't have an authority component. */
+    if(!data->is_relative)
+        data->is_opaque = !data->username && !data->password && !data->host && !data->has_port
+            && data->scheme_type != URL_SCHEME_FILE;
+    else
+        data->is_opaque = !data->host && !data->has_port;
+
+    hr = validate_path(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    hr = validate_query(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    hr = validate_fragment(builder, data, flags);
+    if(FAILED(hr))
+        return hr;
+
+    TRACE("(%p %p %lx): Finished validating builder components.\n", builder, data, flags);
+
+    return S_OK;
+}
+
+static HRESULT compare_file_paths(const Uri *a, const Uri *b, BOOL *ret)
+{
+    WCHAR *canon_path_a, *canon_path_b;
+    DWORD len_a, len_b;
+
+    if(!a->path_len) {
+        *ret = !b->path_len;
+        return S_OK;
+    }
+
+    if(!b->path_len) {
+        *ret = FALSE;
+        return S_OK;
+    }
+
+    /* Fast path */
+    if(a->path_len == b->path_len && !wcsnicmp(a->canon_uri+a->path_start, b->canon_uri+b->path_start, a->path_len)) {
+        *ret = TRUE;
+        return S_OK;
+    }
+
+    len_a = canonicalize_path_hierarchical(a->canon_uri+a->path_start, a->path_len, a->scheme_type, FALSE, 0, FALSE, NULL);
+    len_b = canonicalize_path_hierarchical(b->canon_uri+b->path_start, b->path_len, b->scheme_type, FALSE, 0, FALSE, NULL);
+
+    canon_path_a = malloc(len_a * sizeof(WCHAR));
+    if(!canon_path_a)
+        return E_OUTOFMEMORY;
+    canon_path_b = malloc(len_b * sizeof(WCHAR));
+    if(!canon_path_b) {
+        free(canon_path_a);
+        return E_OUTOFMEMORY;
+    }
+
+    len_a = canonicalize_path_hierarchical(a->canon_uri+a->path_start, a->path_len, a->scheme_type, FALSE, 0, FALSE, canon_path_a);
+    len_b = canonicalize_path_hierarchical(b->canon_uri+b->path_start, b->path_len, b->scheme_type, FALSE, 0, FALSE, canon_path_b);
+
+    *ret = len_a == len_b && !wcsnicmp(canon_path_a, canon_path_b, len_a);
+
+    free(canon_path_a);
+    free(canon_path_b);
+    return S_OK;
+}
+
+/* Checks if the two Uri's are logically equivalent. It's a simple
+ * comparison, since they are both of type Uri, and it can access
+ * the properties of each Uri directly without the need to go
+ * through the "IUri_Get*" interface calls.
+ */
+static HRESULT compare_uris(const Uri *a, const Uri *b, BOOL *ret) {
+    const BOOL known_scheme = a->scheme_type != URL_SCHEME_UNKNOWN;
+    const BOOL are_hierarchical = a->authority_start > -1 && b->authority_start > -1;
+    HRESULT hres;
+
+    *ret = FALSE;
+
+    if(a->scheme_type != b->scheme_type)
+        return S_OK;
+
+    /* Only compare the scheme names (if any) if their unknown scheme types. */
+    if(!known_scheme) {
+        if((a->scheme_start > -1 && b->scheme_start > -1) &&
+           (a->scheme_len == b->scheme_len)) {
+            /* Make sure the schemes are the same. */
+            if(StrCmpNW(a->canon_uri+a->scheme_start, b->canon_uri+b->scheme_start, a->scheme_len))
+                return S_OK;
+        } else if(a->scheme_len != b->scheme_len)
+            /* One of the Uri's has a scheme name, while the other doesn't. */
+            return S_OK;
+    }
+
+    /* If they have a userinfo component, perform case sensitive compare. */
+    if((a->userinfo_start > -1 && b->userinfo_start > -1) &&
+       (a->userinfo_len == b->userinfo_len)) {
+        if(StrCmpNW(a->canon_uri+a->userinfo_start, b->canon_uri+b->userinfo_start, a->userinfo_len))
+            return S_OK;
+    } else if(a->userinfo_len != b->userinfo_len)
+        /* One of the Uri's had a userinfo, while the other one doesn't. */
+        return S_OK;
+
+    /* Check if they have a host name. */
+    if((a->host_start > -1 && b->host_start > -1) &&
+       (a->host_len == b->host_len)) {
+        /* Perform a case insensitive compare if they are a known scheme type. */
+        if(known_scheme) {
+            if(StrCmpNIW(a->canon_uri+a->host_start, b->canon_uri+b->host_start, a->host_len))
+                return S_OK;
+        } else if(StrCmpNW(a->canon_uri+a->host_start, b->canon_uri+b->host_start, a->host_len))
+            return S_OK;
+    } else if(a->host_len != b->host_len)
+        /* One of the Uri's had a host, while the other one didn't. */
+        return S_OK;
+
+    if(a->has_port && b->has_port) {
+        if(a->port != b->port)
+            return S_OK;
+    } else if(a->has_port || b->has_port)
+        /* One had a port, while the other one didn't. */
+        return S_OK;
+
+    /* Windows is weird with how it handles paths. For example
+     * One URI could be "http://google.com" (after canonicalization)
+     * and one could be "http://google.com/" and the IsEqual function
+     * would still evaluate to TRUE, but, only if they are both hierarchical
+     * URIs.
+     */
+    if(a->scheme_type == URL_SCHEME_FILE) {
+        BOOL cmp;
+
+        hres = compare_file_paths(a, b, &cmp);
+        if(FAILED(hres) || !cmp)
+            return hres;
+    } else if((a->path_start > -1 && b->path_start > -1) &&
+       (a->path_len == b->path_len)) {
+        if(StrCmpNW(a->canon_uri+a->path_start, b->canon_uri+b->path_start, a->path_len))
+            return S_OK;
+    } else if(are_hierarchical && a->path_len == -1 && b->path_len == 0) {
+        if(*(a->canon_uri+a->path_start) != '/')
+            return S_OK;
+    } else if(are_hierarchical && b->path_len == 1 && a->path_len == 0) {
+        if(*(b->canon_uri+b->path_start) != '/')
+            return S_OK;
+    } else if(a->path_len != b->path_len)
+        return S_OK;
+
+    /* Compare the query strings of the two URIs. */
+    if((a->query_start > -1 && b->query_start > -1) &&
+       (a->query_len == b->query_len)) {
+        if(StrCmpNW(a->canon_uri+a->query_start, b->canon_uri+b->query_start, a->query_len))
+            return S_OK;
+    } else if(a->query_len != b->query_len)
+        return S_OK;
+
+    if((a->fragment_start > -1 && b->fragment_start > -1) &&
+       (a->fragment_len == b->fragment_len)) {
+        if(StrCmpNW(a->canon_uri+a->fragment_start, b->canon_uri+b->fragment_start, a->fragment_len))
+            return S_OK;
+    } else if(a->fragment_len != b->fragment_len)
+        return S_OK;
+
+    /* If we get here, the two URIs are equivalent. */
+    *ret = TRUE;
+    return S_OK;
+}
+
+static void convert_to_dos_path(const WCHAR *path, DWORD path_len,
+                                WCHAR *output, DWORD *output_len)
+{
+    const WCHAR *ptr = path;
+
+    if(path_len > 3 && *ptr == '/' && is_drive_path(path+1))
+        /* Skip over the leading / before the drive path. */
+        ++ptr;
+
+    for(; ptr < path+path_len; ++ptr) {
+        if(*ptr == '/') {
+            if(output)
+                *output++ = '\\';
+            (*output_len)++;
+        } else {
+            if(output)
+                *output++ = *ptr;
+            (*output_len)++;
+        }
+    }
+}
+
+/* Generates a raw uri string using the parse_data. */
+static DWORD generate_raw_uri(const parse_data *data, BSTR uri, DWORD flags) {
+    DWORD length = 0;
+
+    if(data->scheme) {
+        if(uri) {
+            memcpy(uri, data->scheme, data->scheme_len*sizeof(WCHAR));
+            uri[data->scheme_len] = ':';
+        }
+        length += data->scheme_len+1;
+    }
+
+    if(!data->is_opaque) {
+        /* For the "//" which appears before the authority component. */
+        if(uri) {
+            uri[length] = '/';
+            uri[length+1] = '/';
+        }
+        length += 2;
+
+        /* Check if we need to add the "\\" before the host name
+         * of a UNC server name in a DOS path.
+         */
+        if(flags & RAW_URI_CONVERT_TO_DOS_PATH &&
+           data->scheme_type == URL_SCHEME_FILE && data->host) {
+            if(uri) {
+                uri[length] = '\\';
+                uri[length+1] = '\\';
+            }
+            length += 2;
+        }
+    }
+
+    if(data->username) {
+        if(uri)
+            memcpy(uri+length, data->username, data->username_len*sizeof(WCHAR));
+        length += data->username_len;
+    }
+
+    if(data->password) {
+        if(uri) {
+            uri[length] = ':';
+            memcpy(uri+length+1, data->password, data->password_len*sizeof(WCHAR));
+        }
+        length += data->password_len+1;
+    }
+
+    if(data->password || data->username) {
+        if(uri)
+            uri[length] = '@';
+        ++length;
+    }
+
+    if(data->host) {
+        /* IPv6 addresses get the brackets added around them if they don't already
+         * have them.
+         */
+        const BOOL add_brackets = data->host_type == Uri_HOST_IPV6 && *(data->host) != '[';
+        if(add_brackets) {
+            if(uri)
+                uri[length] = '[';
+            ++length;
+        }
+
+        if(uri)
+            memcpy(uri+length, data->host, data->host_len*sizeof(WCHAR));
+        length += data->host_len;
+
+        if(add_brackets) {
+            if(uri)
+                uri[length] = ']';
+            length++;
+        }
+    }
+
+    if(data->has_port) {
+        /* The port isn't included in the raw uri if it's the default
+         * port for the scheme type.
+         */
+        DWORD i;
+        BOOL is_default = FALSE;
+
+        for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
+            if(data->scheme_type == default_ports[i].scheme &&
+               data->port_value == default_ports[i].port)
+                is_default = TRUE;
+        }
+
+        if(!is_default || flags & RAW_URI_FORCE_PORT_DISP) {
+            if(uri)
+                uri[length] = ':';
+            ++length;
+
+            if(uri)
+                length += ui2str(uri+length, data->port_value);
+            else
+                length += ui2str(NULL, data->port_value);
+        }
+    }
+
+    /* Check if a '/' should be added before the path for hierarchical URIs. */
+    if(!data->is_opaque && data->path && *(data->path) != '/') {
+        if(uri)
+            uri[length] = '/';
+        ++length;
+    }
+
+    if(data->path) {
+        if(!data->is_opaque && data->scheme_type == URL_SCHEME_FILE &&
+           flags & RAW_URI_CONVERT_TO_DOS_PATH) {
+            DWORD len = 0;
+
+            if(uri)
+                convert_to_dos_path(data->path, data->path_len, uri+length, &len);
+            else
+                convert_to_dos_path(data->path, data->path_len, NULL, &len);
+
+            length += len;
+        } else {
+            if(uri)
+                memcpy(uri+length, data->path, data->path_len*sizeof(WCHAR));
+            length += data->path_len;
+        }
+    }
+
+    if(data->query) {
+        if(uri)
+            memcpy(uri+length, data->query, data->query_len*sizeof(WCHAR));
+        length += data->query_len;
+    }
+
+    if(data->fragment) {
+        if(uri)
+            memcpy(uri+length, data->fragment, data->fragment_len*sizeof(WCHAR));
+        length += data->fragment_len;
+    }
+
+    if(uri)
+        TRACE("(%p %p): Generated raw uri=%s len=%ld\n", data, uri, debugstr_wn(uri, length), length);
+    else
+        TRACE("(%p %p): Computed raw uri len=%ld\n", data, uri, length);
+
+    return length;
+}
+
+static HRESULT generate_uri(const UriBuilder *builder, const parse_data *data, Uri *uri, DWORD flags) {
+    HRESULT hr;
+    DWORD length = generate_raw_uri(data, NULL, 0);
+    uri->raw_uri = SysAllocStringLen(NULL, length);
+    if(!uri->raw_uri)
+        return E_OUTOFMEMORY;
+
+    generate_raw_uri(data, uri->raw_uri, 0);
+
+    hr = canonicalize_uri(data, uri, flags);
+    if(FAILED(hr)) {
+        if(hr == E_INVALIDARG)
+            return INET_E_INVALID_URL;
+        return hr;
+    }
+
+    uri->create_flags = flags;
+    return S_OK;
+}
+
+static inline Uri* impl_from_IUri(IUri *iface)
+{
+    return CONTAINING_RECORD(iface, Uri, IUri_iface);
+}
+
+static inline void destroy_uri_obj(Uri *This)
+{
+    SysFreeString(This->raw_uri);
+    free(This->canon_uri);
+    free(This);
+}
+
+static HRESULT WINAPI Uri_QueryInterface(IUri *iface, REFIID riid, void **ppv)
+{
+    Uri *This = impl_from_IUri(iface);
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+        *ppv = &This->IUri_iface;
+    }else if(IsEqualGUID(&IID_IUri, riid)) {
+        TRACE("(%p)->(IID_IUri %p)\n", This, ppv);
+        *ppv = &This->IUri_iface;
+    }else if(IsEqualGUID(&IID_IUriBuilderFactory, riid)) {
+        TRACE("(%p)->(IID_IUriBuilderFactory %p)\n", This, ppv);
+        *ppv = &This->IUriBuilderFactory_iface;
+    }else if(IsEqualGUID(&IID_IPersistStream, riid)) {
+        TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
+        *ppv = &This->IPersistStream_iface;
+    }else if(IsEqualGUID(&IID_IMarshal, riid)) {
+        TRACE("(%p)->(IID_IMarshal %p)\n", This, ppv);
+        *ppv = &This->IMarshal_iface;
+    }else if(IsEqualGUID(&IID_IUriObj, riid)) {
+        TRACE("(%p)->(IID_IUriObj %p)\n", This, ppv);
+        *ppv = This;
+        return S_OK;
+    }else {
+        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI Uri_AddRef(IUri *iface)
+{
+    Uri *This = impl_from_IUri(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI Uri_Release(IUri *iface)
+{
+    Uri *This = impl_from_IUri(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+
+    if(!ref)
+        destroy_uri_obj(This);
+
+    return ref;
+}
+
+static HRESULT WINAPI Uri_GetPropertyBSTR(IUri *iface, Uri_PROPERTY uriProp, BSTR *pbstrProperty, DWORD dwFlags)
+{
+    Uri *This = impl_from_IUri(iface);
+    HRESULT hres;
+    TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pbstrProperty, dwFlags);
+
+    if(!This->create_flags)
+        return E_UNEXPECTED;
+    if(!pbstrProperty)
+        return E_POINTER;
+
+    if(uriProp > Uri_PROPERTY_STRING_LAST) {
+        /* It only returns S_FALSE for the ZONE property... */
+        if(uriProp == Uri_PROPERTY_ZONE) {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            if(!(*pbstrProperty))
+                return E_OUTOFMEMORY;
+            return S_FALSE;
+        }
+
+        *pbstrProperty = NULL;
+        return E_INVALIDARG;
+    }
+
+    if(dwFlags != 0 && dwFlags != Uri_DISPLAY_NO_FRAGMENT && dwFlags != Uri_PUNYCODE_IDN_HOST
+       && dwFlags != Uri_DISPLAY_IDN_HOST)
+        return E_INVALIDARG;
+
+    if((dwFlags == Uri_DISPLAY_NO_FRAGMENT && uriProp != Uri_PROPERTY_DISPLAY_URI)
+       || (dwFlags == Uri_PUNYCODE_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
+           && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST)
+       || (dwFlags == Uri_DISPLAY_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
+           && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST))
+        return E_INVALIDARG;
+
+    switch(uriProp) {
+    case Uri_PROPERTY_ABSOLUTE_URI:
+        if(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI) {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+        /* Uri_PUNYCODE_IDN_HOST doesn't remove user info containing only "@" and ":@" */
+        else if (dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1) {
+            unsigned int punycode_host_len;
+
+            punycode_host_len = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
+            *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-This->host_len+punycode_host_len);
+            hres = S_OK;
+            if(*pbstrProperty) {
+                memcpy(*pbstrProperty, This->canon_uri, This->host_start*sizeof(WCHAR));
+                IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, *pbstrProperty+This->host_start, punycode_host_len);
+                memcpy(*pbstrProperty+This->host_start+punycode_host_len,
+                       This->canon_uri+This->host_start+This->host_len,
+                       (This->canon_len-This->host_start-This->host_len)*sizeof(WCHAR));
+            }
+        } else {
+            if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1) {
+                if(This->userinfo_len == 0) {
+                    /* Don't include the '@' after the userinfo component. */
+                    *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-1);
+                    hres = S_OK;
+                    if(*pbstrProperty) {
+                        /* Copy everything before it. */
+                        memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
+
+                        /* And everything after it. */
+                        memcpy(*pbstrProperty+This->userinfo_start, This->canon_uri+This->userinfo_start+1,
+                               (This->canon_len-This->userinfo_start-1)*sizeof(WCHAR));
+                    }
+                } else if(This->userinfo_split == 0 && This->userinfo_len == 1) {
+                    /* Don't include the ":@" */
+                    *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-2);
+                    hres = S_OK;
+                    if(*pbstrProperty) {
+                        memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
+                        memcpy(*pbstrProperty+This->userinfo_start, This->canon_uri+This->userinfo_start+2,
+                               (This->canon_len-This->userinfo_start-2)*sizeof(WCHAR));
+                    }
+                } else {
+                    *pbstrProperty = SysAllocString(This->canon_uri);
+                    hres = S_OK;
+                }
+            } else {
+                *pbstrProperty = SysAllocString(This->canon_uri);
+                hres = S_OK;
+            }
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_AUTHORITY:
+        if(This->authority_start > -1) {
+            if(This->port_offset > -1 && is_default_port(This->scheme_type, This->port) &&
+               This->display_modifiers & URI_DISPLAY_NO_DEFAULT_PORT_AUTH)
+                /* Don't include the port in the authority component. */
+                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->authority_start, This->port_offset);
+            else
+                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->authority_start, This->authority_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_DISPLAY_URI:
+        /* The Display URI contains everything except for the userinfo for known
+         * scheme types.
+         */
+        if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1) {
+            unsigned int length = This->canon_len-This->userinfo_len;
+
+            /* Skip fragment if Uri_DISPLAY_NO_FRAGMENT is specified */
+            if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
+                length -= This->fragment_len;
+
+            *pbstrProperty = SysAllocStringLen(NULL, length);
+
+            if(*pbstrProperty) {
+                /* Copy everything before the userinfo over. */
+                memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
+
+                /* Copy everything after the userinfo over. */
+                length -= This->userinfo_start+1;
+                memcpy(*pbstrProperty+This->userinfo_start,
+                   This->canon_uri+This->userinfo_start+This->userinfo_len+1, length*sizeof(WCHAR));
+            }
+        } else {
+            unsigned int length = This->canon_len;
+
+            /* Skip fragment if Uri_DISPLAY_NO_FRAGMENT is specified */
+            if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
+                length -= This->fragment_len;
+
+            *pbstrProperty = SysAllocStringLen(This->canon_uri, length);
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+        else
+            hres = S_OK;
+
+        break;
+    case Uri_PROPERTY_DOMAIN:
+        if(This->domain_offset > -1) {
+            if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN) {
+                unsigned int punycode_length;
+
+                punycode_length = IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset,
+                                             This->host_len-This->domain_offset, NULL, 0);
+                *pbstrProperty = SysAllocStringLen(NULL, punycode_length);
+                if (*pbstrProperty)
+                    IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset,
+                               This->host_len-This->domain_offset, *pbstrProperty, punycode_length);
+            } else {
+                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start+This->domain_offset,
+                                                   This->host_len-This->domain_offset);
+            }
+
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_EXTENSION:
+        if(This->extension_offset > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start+This->extension_offset,
+                                               This->path_len-This->extension_offset);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_FRAGMENT:
+        if(This->fragment_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->fragment_start, This->fragment_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_HOST:
+        if(This->host_start > -1) {
+            /* The '[' and ']' aren't included for IPv6 addresses. */
+            if(This->host_type == Uri_HOST_IPV6)
+                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start+1, This->host_len-2);
+            else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN) {
+                unsigned int punycode_length;
+
+                punycode_length = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
+                *pbstrProperty = SysAllocStringLen(NULL, punycode_length);
+                if (*pbstrProperty)
+                    IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, *pbstrProperty, punycode_length);
+            }
+            else
+                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start, This->host_len);
+
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_PASSWORD:
+        if(This->userinfo_split > -1) {
+            *pbstrProperty = SysAllocStringLen(
+                This->canon_uri+This->userinfo_start+This->userinfo_split+1,
+                This->userinfo_len-This->userinfo_split-1);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            return E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_PATH:
+        if(This->path_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start, This->path_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_PATH_AND_QUERY:
+        if(This->path_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start, This->path_len+This->query_len);
+            hres = S_OK;
+        } else if(This->query_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->query_start, This->query_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_QUERY:
+        if(This->query_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->query_start, This->query_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_RAW_URI:
+        *pbstrProperty = SysAllocString(This->raw_uri);
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+        else
+            hres = S_OK;
+        break;
+    case Uri_PROPERTY_SCHEME_NAME:
+        if(This->scheme_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri + This->scheme_start, This->scheme_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_USER_INFO:
+        if(This->userinfo_start > -1) {
+            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->userinfo_start, This->userinfo_len);
+            hres = S_OK;
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            hres = E_OUTOFMEMORY;
+
+        break;
+    case Uri_PROPERTY_USER_NAME:
+        if(This->userinfo_start > -1 && This->userinfo_split != 0) {
+            /* If userinfo_split is set, that means a password exists
+             * so the username is only from userinfo_start to userinfo_split.
+             */
+            if(This->userinfo_split > -1) {
+                *pbstrProperty = SysAllocStringLen(This->canon_uri + This->userinfo_start, This->userinfo_split);
+                hres = S_OK;
+            } else {
+                *pbstrProperty = SysAllocStringLen(This->canon_uri + This->userinfo_start, This->userinfo_len);
+                hres = S_OK;
+            }
+        } else {
+            *pbstrProperty = SysAllocStringLen(NULL, 0);
+            hres = S_FALSE;
+        }
+
+        if(!(*pbstrProperty))
+            return E_OUTOFMEMORY;
+
+        break;
+    default:
+        FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pbstrProperty, dwFlags);
+        hres = E_NOTIMPL;
+    }
+
+    return hres;
+}
+
+static HRESULT WINAPI Uri_GetPropertyLength(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
+{
+    Uri *This = impl_from_IUri(iface);
+    HRESULT hres;
+    TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pcchProperty, dwFlags);
+
+    if(!This->create_flags)
+        return E_UNEXPECTED;
+    if(!pcchProperty)
+        return E_INVALIDARG;
+
+    /* Can only return a length for a property if it's a string. */
+    if(uriProp > Uri_PROPERTY_STRING_LAST)
+        return E_INVALIDARG;
+
+    if(dwFlags != 0 && dwFlags != Uri_DISPLAY_NO_FRAGMENT && dwFlags != Uri_PUNYCODE_IDN_HOST
+       && dwFlags != Uri_DISPLAY_IDN_HOST) {
+        *pcchProperty = 0;
+        return E_INVALIDARG;
+    }
+
+    switch(uriProp) {
+    case Uri_PROPERTY_ABSOLUTE_URI:
+        if(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI) {
+            *pcchProperty = 0;
+            hres = S_FALSE;
+        }
+        /* Uri_PUNYCODE_IDN_HOST doesn't remove user info containing only "@" and ":@" */
+        else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1) {
+            unsigned int punycode_host_len = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
+            *pcchProperty = This->canon_len - This->host_len + punycode_host_len;
+            hres = S_OK;
+        } else {
+            if(This->scheme_type != URL_SCHEME_UNKNOWN) {
+                if(This->userinfo_start > -1 && This->userinfo_len == 0)
+                    /* Don't include the '@' in the length. */
+                    *pcchProperty = This->canon_len-1;
+                else if(This->userinfo_start > -1 && This->userinfo_len == 1 &&
+                        This->userinfo_split == 0)
+                    /* Don't include the ":@" in the length. */
+                    *pcchProperty = This->canon_len-2;
+                else
+                    *pcchProperty = This->canon_len;
+            } else
+                *pcchProperty = This->canon_len;
+
+            hres = S_OK;
+        }
+
+        break;
+    case Uri_PROPERTY_AUTHORITY:
+        if(This->port_offset > -1 &&
+           This->display_modifiers & URI_DISPLAY_NO_DEFAULT_PORT_AUTH &&
+           is_default_port(This->scheme_type, This->port))
+            /* Only count up until the port in the authority. */
+            *pcchProperty = This->port_offset;
+        else
+            *pcchProperty = This->authority_len;
+        hres = (This->authority_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_DISPLAY_URI:
+        if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1)
+            *pcchProperty = This->canon_len-This->userinfo_len-1;
+        else
+            *pcchProperty = This->canon_len;
+
+        if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
+            *pcchProperty -= This->fragment_len;
+
+        hres = S_OK;
+        break;
+    case Uri_PROPERTY_DOMAIN:
+        if(This->domain_offset > -1) {
+            if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN)
+                *pcchProperty = IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset, This->host_len-This->domain_offset, NULL, 0);
+            else
+                *pcchProperty = This->host_len - This->domain_offset;
+        }
+        else
+            *pcchProperty = 0;
+
+        hres = (This->domain_offset > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_EXTENSION:
+        if(This->extension_offset > -1) {
+            *pcchProperty = This->path_len - This->extension_offset;
+            hres = S_OK;
+        } else {
+            *pcchProperty = 0;
+            hres = S_FALSE;
+        }
+
+        break;
+    case Uri_PROPERTY_FRAGMENT:
+        *pcchProperty = This->fragment_len;
+        hres = (This->fragment_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_HOST:
+        *pcchProperty = This->host_len;
+
+        /* '[' and ']' aren't included in the length. */
+        if(This->host_type == Uri_HOST_IPV6)
+            *pcchProperty -= 2;
+        else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1)
+            *pcchProperty = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
+
+        hres = (This->host_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_PASSWORD:
+        *pcchProperty = (This->userinfo_split > -1) ? This->userinfo_len-This->userinfo_split-1 : 0;
+        hres = (This->userinfo_split > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_PATH:
+        *pcchProperty = This->path_len;
+        hres = (This->path_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_PATH_AND_QUERY:
+        *pcchProperty = This->path_len+This->query_len;
+        hres = (This->path_start > -1 || This->query_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_QUERY:
+        *pcchProperty = This->query_len;
+        hres = (This->query_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_RAW_URI:
+        *pcchProperty = SysStringLen(This->raw_uri);
+        hres = S_OK;
+        break;
+    case Uri_PROPERTY_SCHEME_NAME:
+        *pcchProperty = This->scheme_len;
+        hres = (This->scheme_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_USER_INFO:
+        *pcchProperty = This->userinfo_len;
+        hres = (This->userinfo_start > -1) ? S_OK : S_FALSE;
+        break;
+    case Uri_PROPERTY_USER_NAME:
+        *pcchProperty = (This->userinfo_split > -1) ? This->userinfo_split : This->userinfo_len;
+        if(This->userinfo_split == 0)
+            hres = S_FALSE;
+        else
+            hres = (This->userinfo_start > -1) ? S_OK : S_FALSE;
+        break;
+    default:
+        FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pcchProperty, dwFlags);
+        hres = E_NOTIMPL;
+    }
+
+    if(hres == S_OK
+       && ((dwFlags == Uri_DISPLAY_NO_FRAGMENT && uriProp != Uri_PROPERTY_DISPLAY_URI)
+            || (dwFlags == Uri_PUNYCODE_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
+                && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST)
+            || (dwFlags == Uri_DISPLAY_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
+                && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST))) {
+        *pcchProperty = 0;
+        hres = E_INVALIDARG;
+    }
+
+    return hres;
+}
+
+static HRESULT WINAPI Uri_GetPropertyDWORD(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
+{
+    Uri *This = impl_from_IUri(iface);
+    HRESULT hres;
+
+    TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pcchProperty, dwFlags);
+
+    if(!This->create_flags)
+        return E_UNEXPECTED;
+    if(!pcchProperty)
+        return E_INVALIDARG;
+
+    /* Microsoft's implementation for the ZONE property of a URI seems to be lacking...
+     * From what I can tell, instead of checking which URLZONE the URI belongs to it
+     * simply assigns URLZONE_INVALID and returns E_NOTIMPL. This also applies to the GetZone
+     * function.
+     */
+    if(uriProp == Uri_PROPERTY_ZONE) {
+        *pcchProperty = URLZONE_INVALID;
+        return E_NOTIMPL;
+    }
+
+    if(uriProp < Uri_PROPERTY_DWORD_START) {
+        *pcchProperty = 0;
+        return E_INVALIDARG;
+    }
+
+    switch(uriProp) {
+    case Uri_PROPERTY_HOST_TYPE:
+        *pcchProperty = This->host_type;
+        hres = S_OK;
+        break;
+    case Uri_PROPERTY_PORT:
+        if(!This->has_port) {
+            *pcchProperty = 0;
+            hres = S_FALSE;
+        } else {
+            *pcchProperty = This->port;
+            hres = S_OK;
+        }
+
+        break;
+    case Uri_PROPERTY_SCHEME:
+        *pcchProperty = This->scheme_type;
+        hres = S_OK;
+        break;
+    default:
+        FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pcchProperty, dwFlags);
+        hres = E_NOTIMPL;
+    }
+
+    return hres;
+}
+
+static HRESULT WINAPI Uri_HasProperty(IUri *iface, Uri_PROPERTY uriProp, BOOL *pfHasProperty)
+{
+    Uri *This = impl_from_IUri(iface);
+
+    TRACE("(%p %s)->(%d %p)\n", This, debugstr_w(This->canon_uri), uriProp, pfHasProperty);
+
+    if(!pfHasProperty)
+        return E_INVALIDARG;
+
+    switch(uriProp) {
+    case Uri_PROPERTY_ABSOLUTE_URI:
+        *pfHasProperty = !(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI);
+        break;
+    case Uri_PROPERTY_AUTHORITY:
+        *pfHasProperty = This->authority_start > -1;
+        break;
+    case Uri_PROPERTY_DISPLAY_URI:
+        *pfHasProperty = TRUE;
+        break;
+    case Uri_PROPERTY_DOMAIN:
+        *pfHasProperty = This->domain_offset > -1;
+        break;
+    case Uri_PROPERTY_EXTENSION:
+        *pfHasProperty = This->extension_offset > -1;
+        break;
+    case Uri_PROPERTY_FRAGMENT:
+        *pfHasProperty = This->fragment_start > -1;
+        break;
+    case Uri_PROPERTY_HOST:
+        *pfHasProperty = This->host_start > -1;
+        break;
+    case Uri_PROPERTY_PASSWORD:
+        *pfHasProperty = This->userinfo_split > -1;
+        break;
+    case Uri_PROPERTY_PATH:
+        *pfHasProperty = This->path_start > -1;
+        break;
+    case Uri_PROPERTY_PATH_AND_QUERY:
+        *pfHasProperty = (This->path_start > -1 || This->query_start > -1);
+        break;
+    case Uri_PROPERTY_QUERY:
+        *pfHasProperty = This->query_start > -1;
+        break;
+    case Uri_PROPERTY_RAW_URI:
+        *pfHasProperty = TRUE;
+        break;
+    case Uri_PROPERTY_SCHEME_NAME:
+        *pfHasProperty = This->scheme_start > -1;
+        break;
+    case Uri_PROPERTY_USER_INFO:
+        *pfHasProperty = This->userinfo_start > -1;
+        break;
+    case Uri_PROPERTY_USER_NAME:
+        if(This->userinfo_split == 0)
+            *pfHasProperty = FALSE;
+        else
+            *pfHasProperty = This->userinfo_start > -1;
+        break;
+    case Uri_PROPERTY_HOST_TYPE:
+        *pfHasProperty = TRUE;
+        break;
+    case Uri_PROPERTY_PORT:
+        *pfHasProperty = This->has_port;
+        break;
+    case Uri_PROPERTY_SCHEME:
+        *pfHasProperty = TRUE;
+        break;
+    case Uri_PROPERTY_ZONE:
+        *pfHasProperty = FALSE;
+        break;
+    default:
+        FIXME("(%p)->(%d %p): Unsupported property type.\n", This, uriProp, pfHasProperty);
+        return E_NOTIMPL;
+    }
+
+    return S_OK;
+}
+
+static HRESULT WINAPI Uri_GetAbsoluteUri(IUri *iface, BSTR *pstrAbsoluteUri)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrAbsoluteUri);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_ABSOLUTE_URI, pstrAbsoluteUri, 0);
+}
+
+static HRESULT WINAPI Uri_GetAuthority(IUri *iface, BSTR *pstrAuthority)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrAuthority);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_AUTHORITY, pstrAuthority, 0);
+}
+
+static HRESULT WINAPI Uri_GetDisplayUri(IUri *iface, BSTR *pstrDisplayUri)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrDisplayUri);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_DISPLAY_URI, pstrDisplayUri, 0);
+}
+
+static HRESULT WINAPI Uri_GetDomain(IUri *iface, BSTR *pstrDomain)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrDomain);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_DOMAIN, pstrDomain, 0);
+}
+
+static HRESULT WINAPI Uri_GetExtension(IUri *iface, BSTR *pstrExtension)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrExtension);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_EXTENSION, pstrExtension, 0);
+}
+
+static HRESULT WINAPI Uri_GetFragment(IUri *iface, BSTR *pstrFragment)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrFragment);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_FRAGMENT, pstrFragment, 0);
+}
+
+static HRESULT WINAPI Uri_GetHost(IUri *iface, BSTR *pstrHost)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrHost);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_HOST, pstrHost, 0);
+}
+
+static HRESULT WINAPI Uri_GetPassword(IUri *iface, BSTR *pstrPassword)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrPassword);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PASSWORD, pstrPassword, 0);
+}
+
+static HRESULT WINAPI Uri_GetPath(IUri *iface, BSTR *pstrPath)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrPath);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PATH, pstrPath, 0);
+}
+
+static HRESULT WINAPI Uri_GetPathAndQuery(IUri *iface, BSTR *pstrPathAndQuery)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrPathAndQuery);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PATH_AND_QUERY, pstrPathAndQuery, 0);
+}
+
+static HRESULT WINAPI Uri_GetQuery(IUri *iface, BSTR *pstrQuery)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrQuery);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_QUERY, pstrQuery, 0);
+}
+
+static HRESULT WINAPI Uri_GetRawUri(IUri *iface, BSTR *pstrRawUri)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrRawUri);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_RAW_URI, pstrRawUri, 0);
+}
+
+static HRESULT WINAPI Uri_GetSchemeName(IUri *iface, BSTR *pstrSchemeName)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrSchemeName);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_SCHEME_NAME, pstrSchemeName, 0);
+}
+
+static HRESULT WINAPI Uri_GetUserInfo(IUri *iface, BSTR *pstrUserInfo)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrUserInfo);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_USER_INFO, pstrUserInfo, 0);
+}
+
+static HRESULT WINAPI Uri_GetUserName(IUri *iface, BSTR *pstrUserName)
+{
+    TRACE("(%p)->(%p)\n", iface, pstrUserName);
+    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_USER_NAME, pstrUserName, 0);
+}
+
+static HRESULT WINAPI Uri_GetHostType(IUri *iface, DWORD *pdwHostType)
+{
+    TRACE("(%p)->(%p)\n", iface, pdwHostType);
+    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_HOST_TYPE, pdwHostType, 0);
+}
+
+static HRESULT WINAPI Uri_GetPort(IUri *iface, DWORD *pdwPort)
+{
+    TRACE("(%p)->(%p)\n", iface, pdwPort);
+    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_PORT, pdwPort, 0);
+}
+
+static HRESULT WINAPI Uri_GetScheme(IUri *iface, DWORD *pdwScheme)
+{
+    TRACE("(%p)->(%p)\n", iface, pdwScheme);
+    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_SCHEME, pdwScheme, 0);
+}
+
+static HRESULT WINAPI Uri_GetZone(IUri *iface, DWORD *pdwZone)
+{
+    TRACE("(%p)->(%p)\n", iface, pdwZone);
+    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_ZONE,pdwZone, 0);
+}
+
+static HRESULT WINAPI Uri_GetProperties(IUri *iface, DWORD *pdwProperties)
+{
+    Uri *This = impl_from_IUri(iface);
+    TRACE("(%p %s)->(%p)\n", This, debugstr_w(This->canon_uri), pdwProperties);
+
+    if(!This->create_flags)
+        return E_UNEXPECTED;
+    if(!pdwProperties)
+        return E_INVALIDARG;
+
+    /* All URIs have these. */
+    *pdwProperties = Uri_HAS_DISPLAY_URI|Uri_HAS_RAW_URI|Uri_HAS_SCHEME|Uri_HAS_HOST_TYPE;
+
+    if(!(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI))
+        *pdwProperties |= Uri_HAS_ABSOLUTE_URI;
+
+    if(This->scheme_start > -1)
+        *pdwProperties |= Uri_HAS_SCHEME_NAME;
+
+    if(This->authority_start > -1) {
+        *pdwProperties |= Uri_HAS_AUTHORITY;
+        if(This->userinfo_start > -1) {
+            *pdwProperties |= Uri_HAS_USER_INFO;
+            if(This->userinfo_split != 0)
+                *pdwProperties |= Uri_HAS_USER_NAME;
+        }
+        if(This->userinfo_split > -1)
+            *pdwProperties |= Uri_HAS_PASSWORD;
+        if(This->host_start > -1)
+            *pdwProperties |= Uri_HAS_HOST;
+        if(This->domain_offset > -1)
+            *pdwProperties |= Uri_HAS_DOMAIN;
+    }
+
+    if(This->has_port)
+        *pdwProperties |= Uri_HAS_PORT;
+    if(This->path_start > -1)
+        *pdwProperties |= Uri_HAS_PATH|Uri_HAS_PATH_AND_QUERY;
+    if(This->query_start > -1)
+        *pdwProperties |= Uri_HAS_QUERY|Uri_HAS_PATH_AND_QUERY;
+
+    if(This->extension_offset > -1)
+        *pdwProperties |= Uri_HAS_EXTENSION;
+
+    if(This->fragment_start > -1)
+        *pdwProperties |= Uri_HAS_FRAGMENT;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI Uri_IsEqual(IUri *iface, IUri *pUri, BOOL *pfEqual)
+{
+    Uri *This = impl_from_IUri(iface);
+    Uri *other;
+
+    TRACE("(%p %s)->(%p %p)\n", This, debugstr_w(This->canon_uri), pUri, pfEqual);
+
+    if(!This->create_flags)
+        return E_UNEXPECTED;
+    if(!pfEqual)
+        return E_POINTER;
+
+    if(!pUri) {
+        *pfEqual = FALSE;
+
+        /* For some reason Windows returns S_OK here... */
+        return S_OK;
+    }
+
+    /* Try to convert it to a Uri (allows for a more simple comparison). */
+    if(!(other = get_uri_obj(pUri))) {
+        FIXME("(%p)->(%p %p) No support for unknown IUri's yet.\n", iface, pUri, pfEqual);
+        return E_NOTIMPL;
+    }
+
+    TRACE("comparing to %s\n", debugstr_w(other->canon_uri));
+    return compare_uris(This, other, pfEqual);
+}
+
+static const IUriVtbl UriVtbl = {
+    Uri_QueryInterface,
+    Uri_AddRef,
+    Uri_Release,
+    Uri_GetPropertyBSTR,
+    Uri_GetPropertyLength,
+    Uri_GetPropertyDWORD,
+    Uri_HasProperty,
+    Uri_GetAbsoluteUri,
+    Uri_GetAuthority,
+    Uri_GetDisplayUri,
+    Uri_GetDomain,
+    Uri_GetExtension,
+    Uri_GetFragment,
+    Uri_GetHost,
+    Uri_GetPassword,
+    Uri_GetPath,
+    Uri_GetPathAndQuery,
+    Uri_GetQuery,
+    Uri_GetRawUri,
+    Uri_GetSchemeName,
+    Uri_GetUserInfo,
+    Uri_GetUserName,
+    Uri_GetHostType,
+    Uri_GetPort,
+    Uri_GetScheme,
+    Uri_GetZone,
+    Uri_GetProperties,
+    Uri_IsEqual
+};
+
+static inline Uri* impl_from_IUriBuilderFactory(IUriBuilderFactory *iface)
+{
+    return CONTAINING_RECORD(iface, Uri, IUriBuilderFactory_iface);
+}
+
+static HRESULT WINAPI UriBuilderFactory_QueryInterface(IUriBuilderFactory *iface, REFIID riid, void **ppv)
+{
+    Uri *This = impl_from_IUriBuilderFactory(iface);
+    return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
+}
+
+static ULONG WINAPI UriBuilderFactory_AddRef(IUriBuilderFactory *iface)
+{
+    Uri *This = impl_from_IUriBuilderFactory(iface);
+    return IUri_AddRef(&This->IUri_iface);
+}
+
+static ULONG WINAPI UriBuilderFactory_Release(IUriBuilderFactory *iface)
+{
+    Uri *This = impl_from_IUriBuilderFactory(iface);
+    return IUri_Release(&This->IUri_iface);
+}
+
+static HRESULT WINAPI UriBuilderFactory_CreateIUriBuilder(IUriBuilderFactory *iface,
+                                                          DWORD dwFlags,
+                                                          DWORD_PTR dwReserved,
+                                                          IUriBuilder **ppIUriBuilder)
+{
+    Uri *This = impl_from_IUriBuilderFactory(iface);
+    TRACE("(%p)->(%08lx %08Ix %p)\n", This, dwFlags, dwReserved, ppIUriBuilder);
+
+    if(!ppIUriBuilder)
+        return E_POINTER;
+
+    if(dwFlags || dwReserved) {
+        *ppIUriBuilder = NULL;
+        return E_INVALIDARG;
+    }
+
+    return CreateIUriBuilder(NULL, 0, 0, ppIUriBuilder);
+}
+
+static HRESULT WINAPI UriBuilderFactory_CreateInitializedIUriBuilder(IUriBuilderFactory *iface,
+                                                                     DWORD dwFlags,
+                                                                     DWORD_PTR dwReserved,
+                                                                     IUriBuilder **ppIUriBuilder)
+{
+    Uri *This = impl_from_IUriBuilderFactory(iface);
+    TRACE("(%p)->(%08lx %08Ix %p)\n", This, dwFlags, dwReserved, ppIUriBuilder);
+
+    if(!ppIUriBuilder)
+        return E_POINTER;
+
+    if(dwFlags || dwReserved) {
+        *ppIUriBuilder = NULL;
+        return E_INVALIDARG;
+    }
+
+    return CreateIUriBuilder(&This->IUri_iface, 0, 0, ppIUriBuilder);
+}
+
+static const IUriBuilderFactoryVtbl UriBuilderFactoryVtbl = {
+    UriBuilderFactory_QueryInterface,
+    UriBuilderFactory_AddRef,
+    UriBuilderFactory_Release,
+    UriBuilderFactory_CreateIUriBuilder,
+    UriBuilderFactory_CreateInitializedIUriBuilder
+};
+
+static inline Uri* impl_from_IPersistStream(IPersistStream *iface)
+{
+    return CONTAINING_RECORD(iface, Uri, IPersistStream_iface);
+}
+
+static HRESULT WINAPI PersistStream_QueryInterface(IPersistStream *iface, REFIID riid, void **ppvObject)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    return IUri_QueryInterface(&This->IUri_iface, riid, ppvObject);
+}
+
+static ULONG WINAPI PersistStream_AddRef(IPersistStream *iface)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    return IUri_AddRef(&This->IUri_iface);
+}
+
+static ULONG WINAPI PersistStream_Release(IPersistStream *iface)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    return IUri_Release(&This->IUri_iface);
+}
+
+static HRESULT WINAPI PersistStream_GetClassID(IPersistStream *iface, CLSID *pClassID)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    TRACE("(%p)->(%p)\n", This, pClassID);
+
+    if(!pClassID)
+        return E_INVALIDARG;
+
+    *pClassID = CLSID_CUri;
+    return S_OK;
+}
+
+static HRESULT WINAPI PersistStream_IsDirty(IPersistStream *iface)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    TRACE("(%p)\n", This);
+    return S_FALSE;
+}
+
+struct persist_uri {
+    DWORD size;
+    DWORD unk1[2];
+    DWORD create_flags;
+    DWORD unk2[3];
+    DWORD fields_no;
+    BYTE data[1];
+};
+
+static HRESULT WINAPI PersistStream_Load(IPersistStream *iface, IStream *pStm)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    struct persist_uri *data;
+    parse_data parse;
+    DWORD size;
+    HRESULT hr;
+
+    TRACE("(%p)->(%p)\n", This, pStm);
+
+    if(This->create_flags)
+        return E_UNEXPECTED;
+    if(!pStm)
+        return E_INVALIDARG;
+
+    hr = IStream_Read(pStm, &size, sizeof(DWORD), NULL);
+    if(FAILED(hr))
+        return hr;
+    data = malloc(size);
+    if(!data)
+        return E_OUTOFMEMORY;
+    hr = IStream_Read(pStm, data->unk1, size-sizeof(DWORD)-2, NULL);
+    if(FAILED(hr)) {
+        free(data);
+        return hr;
+    }
+
+    if(size < sizeof(struct persist_uri)) {
+        free(data);
+        return S_OK;
+    }
+
+    if(*(DWORD*)data->data != Uri_PROPERTY_RAW_URI) {
+        free(data);
+        ERR("Can't find raw_uri\n");
+        return E_UNEXPECTED;
+    }
+
+    This->raw_uri = SysAllocString((WCHAR*)(data->data+sizeof(DWORD)*2));
+    if(!This->raw_uri) {
+        free(data);
+        return E_OUTOFMEMORY;
+    }
+    This->create_flags = data->create_flags;
+    free(data);
+    TRACE("%lx %s\n", This->create_flags, debugstr_w(This->raw_uri));
+
+    memset(&parse, 0, sizeof(parse_data));
+    parse.uri = This->raw_uri;
+    if(!parse_uri(&parse, This->create_flags)) {
+        SysFreeString(This->raw_uri);
+        This->create_flags = 0;
+        return E_UNEXPECTED;
+    }
+
+    hr = canonicalize_uri(&parse, This, This->create_flags);
+    if(FAILED(hr)) {
+        SysFreeString(This->raw_uri);
+        This->create_flags = 0;
+        return hr;
+    }
+
+    return S_OK;
+}
+
+static inline BYTE* persist_stream_add_strprop(Uri *This, BYTE *p, DWORD type, DWORD len, WCHAR *data)
+{
+    len *= sizeof(WCHAR);
+    *(DWORD*)p = type;
+    p += sizeof(DWORD);
+    *(DWORD*)p = len+sizeof(WCHAR);
+    p += sizeof(DWORD);
+    memcpy(p, data, len);
+    p += len;
+    *(WCHAR*)p = 0;
+    return p+sizeof(WCHAR);
+}
+
+static inline void persist_stream_save(Uri *This, IStream *pStm, BOOL marshal, struct persist_uri *data)
+{
+    BYTE *p = NULL;
+
+    data->create_flags = This->create_flags;
+
+    if(This->create_flags) {
+        data->fields_no = 1;
+        p = persist_stream_add_strprop(This, data->data, Uri_PROPERTY_RAW_URI,
+                SysStringLen(This->raw_uri), This->raw_uri);
+    }
+    if(This->scheme_type!=URL_SCHEME_HTTP && This->scheme_type!=URL_SCHEME_HTTPS
+            && This->scheme_type!=URL_SCHEME_FTP)
+        return;
+
+    if(This->fragment_len) {
+        data->fields_no++;
+        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_FRAGMENT,
+                This->fragment_len, This->canon_uri+This->fragment_start);
+    }
+
+    if(This->host_len) {
+        data->fields_no++;
+        if(This->host_type == Uri_HOST_IPV6)
+            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_HOST,
+                    This->host_len-2, This->canon_uri+This->host_start+1);
+        else
+            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_HOST,
+                    This->host_len, This->canon_uri+This->host_start);
+    }
+
+    if(This->userinfo_split > -1) {
+        data->fields_no++;
+        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PASSWORD,
+                This->userinfo_len-This->userinfo_split-1,
+                This->canon_uri+This->userinfo_start+This->userinfo_split+1);
+    }
+
+    if(This->path_len) {
+        data->fields_no++;
+        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PATH,
+                This->path_len, This->canon_uri+This->path_start);
+    } else if(marshal) {
+        WCHAR no_path = '/';
+        data->fields_no++;
+        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PATH, 1, &no_path);
+    }
+
+    if(This->has_port) {
+        data->fields_no++;
+        *(DWORD*)p = Uri_PROPERTY_PORT;
+        p += sizeof(DWORD);
+        *(DWORD*)p = sizeof(DWORD);
+        p += sizeof(DWORD);
+        *(DWORD*)p = This->port;
+        p += sizeof(DWORD);
+    }
+
+    if(This->query_len) {
+        data->fields_no++;
+        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_QUERY,
+                This->query_len, This->canon_uri+This->query_start);
+    }
+
+    if(This->scheme_len) {
+        data->fields_no++;
+        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_SCHEME_NAME,
+                This->scheme_len, This->canon_uri+This->scheme_start);
+    }
+
+    if(This->userinfo_start>-1 && This->userinfo_split!=0) {
+        data->fields_no++;
+        if(This->userinfo_split > -1)
+            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_USER_NAME,
+                    This->userinfo_split, This->canon_uri+This->userinfo_start);
+        else
+            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_USER_NAME,
+                    This->userinfo_len, This->canon_uri+This->userinfo_start);
+    }
+}
+
+static HRESULT WINAPI PersistStream_Save(IPersistStream *iface, IStream *pStm, BOOL fClearDirty)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    struct persist_uri *data;
+    ULARGE_INTEGER size;
+    HRESULT hres;
+
+    TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
+
+    if(!pStm)
+        return E_INVALIDARG;
+
+    hres = IPersistStream_GetSizeMax(&This->IPersistStream_iface, &size);
+    if(FAILED(hres))
+        return hres;
+
+    data = calloc(1, size.u.LowPart);
+    if(!data)
+        return E_OUTOFMEMORY;
+    data->size = size.u.LowPart;
+    persist_stream_save(This, pStm, FALSE, data);
+
+    hres = IStream_Write(pStm, data, data->size-2, NULL);
+    free(data);
+    return hres;
+}
+
+static HRESULT WINAPI PersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *pcbSize)
+{
+    Uri *This = impl_from_IPersistStream(iface);
+    TRACE("(%p)->(%p)\n", This, pcbSize);
+
+    if(!pcbSize)
+        return E_INVALIDARG;
+
+    pcbSize->u.LowPart = 2+sizeof(struct persist_uri);
+    pcbSize->u.HighPart = 0;
+    if(This->create_flags)
+        pcbSize->u.LowPart += (SysStringLen(This->raw_uri)+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    else /* there's no place for fields no */
+        pcbSize->u.LowPart -= sizeof(DWORD);
+    if(This->scheme_type!=URL_SCHEME_HTTP && This->scheme_type!=URL_SCHEME_HTTPS
+            && This->scheme_type!=URL_SCHEME_FTP)
+        return S_OK;
+
+    if(This->fragment_len)
+        pcbSize->u.LowPart += (This->fragment_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    if(This->host_len) {
+        if(This->host_type == Uri_HOST_IPV6)
+            pcbSize->u.LowPart += (This->host_len-1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+        else
+            pcbSize->u.LowPart += (This->host_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    }
+    if(This->userinfo_split > -1)
+        pcbSize->u.LowPart += (This->userinfo_len-This->userinfo_split)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    if(This->path_len)
+        pcbSize->u.LowPart += (This->path_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    if(This->has_port)
+        pcbSize->u.LowPart += 3*sizeof(DWORD);
+    if(This->query_len)
+        pcbSize->u.LowPart += (This->query_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    if(This->scheme_len)
+        pcbSize->u.LowPart += (This->scheme_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    if(This->userinfo_start>-1 && This->userinfo_split!=0) {
+        if(This->userinfo_split > -1)
+            pcbSize->u.LowPart += (This->userinfo_split+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+        else
+            pcbSize->u.LowPart += (This->userinfo_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
+    }
+    return S_OK;
+}
+
+static const IPersistStreamVtbl PersistStreamVtbl = {
+    PersistStream_QueryInterface,
+    PersistStream_AddRef,
+    PersistStream_Release,
+    PersistStream_GetClassID,
+    PersistStream_IsDirty,
+    PersistStream_Load,
+    PersistStream_Save,
+    PersistStream_GetSizeMax
+};
+
+static inline Uri* impl_from_IMarshal(IMarshal *iface)
+{
+    return CONTAINING_RECORD(iface, Uri, IMarshal_iface);
+}
+
+static HRESULT WINAPI Marshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    return IUri_QueryInterface(&This->IUri_iface, riid, ppvObject);
+}
+
+static ULONG WINAPI Marshal_AddRef(IMarshal *iface)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    return IUri_AddRef(&This->IUri_iface);
+}
+
+static ULONG WINAPI Marshal_Release(IMarshal *iface)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    return IUri_Release(&This->IUri_iface);
+}
+
+static HRESULT WINAPI Marshal_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
+        DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    TRACE("(%p)->(%s %p %lx %p %lx %p)\n", This, debugstr_guid(riid), pv,
+            dwDestContext, pvDestContext, mshlflags, pCid);
+
+    if(!pCid || (dwDestContext!=MSHCTX_LOCAL && dwDestContext!=MSHCTX_NOSHAREDMEM
+                && dwDestContext!=MSHCTX_INPROC))
+        return E_INVALIDARG;
+
+    *pCid = CLSID_CUri;
+    return S_OK;
+}
+
+struct inproc_marshal_uri {
+    DWORD size;
+    DWORD mshlflags;
+    DWORD unk[4]; /* process identifier? */
+    Uri *uri;
+};
+
+static HRESULT WINAPI Marshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
+        DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    ULARGE_INTEGER size;
+    HRESULT hres;
+    TRACE("(%p)->(%s %p %lx %p %lx %p)\n", This, debugstr_guid(riid), pv,
+            dwDestContext, pvDestContext, mshlflags, pSize);
+
+    if(!pSize || (dwDestContext!=MSHCTX_LOCAL && dwDestContext!=MSHCTX_NOSHAREDMEM
+                && dwDestContext!=MSHCTX_INPROC))
+        return E_INVALIDARG;
+
+    if(dwDestContext == MSHCTX_INPROC) {
+        *pSize = sizeof(struct inproc_marshal_uri);
+        return S_OK;
+    }
+
+    hres = IPersistStream_GetSizeMax(&This->IPersistStream_iface, &size);
+    if(FAILED(hres))
+        return hres;
+    if(!This->path_len && (This->scheme_type==URL_SCHEME_HTTP
+                || This->scheme_type==URL_SCHEME_HTTPS
+                || This->scheme_type==URL_SCHEME_FTP))
+        size.u.LowPart += 3*sizeof(DWORD);
+    *pSize = size.u.LowPart+2*sizeof(DWORD);
+    return S_OK;
+}
+
+static HRESULT WINAPI Marshal_MarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid,
+        void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    DWORD *data;
+    DWORD size;
+    HRESULT hres;
+
+    TRACE("(%p)->(%p %s %p %lx %p %lx)\n", This, pStm, debugstr_guid(riid), pv,
+            dwDestContext, pvDestContext, mshlflags);
+
+    if(!pStm || mshlflags!=MSHLFLAGS_NORMAL || (dwDestContext!=MSHCTX_LOCAL
+                && dwDestContext!=MSHCTX_NOSHAREDMEM && dwDestContext!=MSHCTX_INPROC))
+        return E_INVALIDARG;
+
+    if(dwDestContext == MSHCTX_INPROC) {
+        struct inproc_marshal_uri data;
+
+        data.size = sizeof(data);
+        data.mshlflags = MSHCTX_INPROC;
+        data.unk[0] = 0;
+        data.unk[1] = 0;
+        data.unk[2] = 0;
+        data.unk[3] = 0;
+        data.uri = This;
+
+        hres = IStream_Write(pStm, &data, data.size, NULL);
+        if(FAILED(hres))
+            return hres;
+
+        IUri_AddRef(&This->IUri_iface);
+        return S_OK;
+    }
+
+    hres = IMarshal_GetMarshalSizeMax(iface, riid, pv, dwDestContext,
+            pvDestContext, mshlflags, &size);
+    if(FAILED(hres))
+        return hres;
+
+    data = calloc(1, size);
+    if(!data)
+        return E_OUTOFMEMORY;
+
+    data[0] = size;
+    data[1] = dwDestContext;
+    data[2] = size-2*sizeof(DWORD);
+    persist_stream_save(This, pStm, TRUE, (struct persist_uri*)(data+2));
+
+    hres = IStream_Write(pStm, data, data[0]-2, NULL);
+    free(data);
+    return hres;
+}
+
+static HRESULT WINAPI Marshal_UnmarshalInterface(IMarshal *iface,
+        IStream *pStm, REFIID riid, void **ppv)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    DWORD header[2];
+    HRESULT hres;
+
+    TRACE("(%p)->(%p %s %p)\n", This, pStm, debugstr_guid(riid), ppv);
+
+    if(This->create_flags)
+        return E_UNEXPECTED;
+    if(!pStm || !riid || !ppv)
+        return E_INVALIDARG;
+
+    hres = IStream_Read(pStm, header, sizeof(header), NULL);
+    if(FAILED(hres))
+        return hres;
+
+    if(header[1]!=MSHCTX_LOCAL && header[1]!=MSHCTX_NOSHAREDMEM
+            && header[1]!=MSHCTX_INPROC)
+        return E_UNEXPECTED;
+
+    if(header[1] == MSHCTX_INPROC) {
+        struct inproc_marshal_uri data;
+        parse_data parse;
+
+        hres = IStream_Read(pStm, data.unk, sizeof(data)-2*sizeof(DWORD), NULL);
+        if(FAILED(hres))
+            return hres;
+
+        This->raw_uri = SysAllocString(data.uri->raw_uri);
+        if(!This->raw_uri) {
+            return E_OUTOFMEMORY;
+        }
+
+        memset(&parse, 0, sizeof(parse_data));
+        parse.uri = This->raw_uri;
+
+        if(!parse_uri(&parse, data.uri->create_flags))
+            return E_INVALIDARG;
+
+        hres = canonicalize_uri(&parse, This, data.uri->create_flags);
+        if(FAILED(hres))
+            return hres;
+
+        This->create_flags = data.uri->create_flags;
+        IUri_Release(&data.uri->IUri_iface);
+
+        return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
+    }
+
+    hres = IPersistStream_Load(&This->IPersistStream_iface, pStm);
+    if(FAILED(hres))
+        return hres;
+
+    return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
+}
+
+static HRESULT WINAPI Marshal_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    LARGE_INTEGER off;
+    DWORD header[2];
+    HRESULT hres;
+
+    TRACE("(%p)->(%p)\n", This, pStm);
+
+    if(!pStm)
+        return E_INVALIDARG;
+
+    hres = IStream_Read(pStm, header, 2*sizeof(DWORD), NULL);
+    if(FAILED(hres))
+        return hres;
+
+    if(header[1] == MSHCTX_INPROC) {
+        struct inproc_marshal_uri data;
+
+        hres = IStream_Read(pStm, data.unk, sizeof(data)-2*sizeof(DWORD), NULL);
+        if(FAILED(hres))
+            return hres;
+
+        IUri_Release(&data.uri->IUri_iface);
+        return S_OK;
+    }
+
+    off.u.LowPart = header[0]-sizeof(header)-2;
+    off.u.HighPart = 0;
+    return IStream_Seek(pStm, off, STREAM_SEEK_CUR, NULL);
+}
+
+static HRESULT WINAPI Marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved)
+{
+    Uri *This = impl_from_IMarshal(iface);
+    TRACE("(%p)->(%lx)\n", This, dwReserved);
+    return S_OK;
+}
+
+static const IMarshalVtbl MarshalVtbl = {
+    Marshal_QueryInterface,
+    Marshal_AddRef,
+    Marshal_Release,
+    Marshal_GetUnmarshalClass,
+    Marshal_GetMarshalSizeMax,
+    Marshal_MarshalInterface,
+    Marshal_UnmarshalInterface,
+    Marshal_ReleaseMarshalData,
+    Marshal_DisconnectObject
+};
+
+HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
+{
+    Uri *ret = calloc(1, sizeof(Uri));
+
+    TRACE("(%p %p)\n", pUnkOuter, ppobj);
+
+    *ppobj = ret;
+    if(!ret)
+        return E_OUTOFMEMORY;
+
+    ret->IUri_iface.lpVtbl = &UriVtbl;
+    ret->IUriBuilderFactory_iface.lpVtbl = &UriBuilderFactoryVtbl;
+    ret->IPersistStream_iface.lpVtbl = &PersistStreamVtbl;
+    ret->IMarshal_iface.lpVtbl = &MarshalVtbl;
+    ret->ref = 1;
+
+    *ppobj = &ret->IUri_iface;
+    return S_OK;
+}
+
+/***********************************************************************
+ *           CreateUri (iertutil.@)
+ *
+ * Creates a new IUri object using the URI represented by pwzURI. This function
+ * parses and validates the components of pwzURI and then canonicalizes the
+ * parsed components.
+ *
+ * PARAMS
+ *  pwzURI      [I] The URI to parse, validate, and canonicalize.
+ *  dwFlags     [I] Flags which can affect how the parsing/canonicalization is performed.
+ *  dwReserved  [I] Reserved (not used).
+ *  ppURI       [O] The resulting IUri after parsing/canonicalization occurs.
+ *
+ * RETURNS
+ *  Success: Returns S_OK. ppURI contains the pointer to the newly allocated IUri.
+ *  Failure: E_INVALIDARG if there are invalid flag combinations in dwFlags, or an
+ *           invalid parameter, or pwzURI doesn't represent a valid URI.
+ *           E_OUTOFMEMORY if any memory allocation fails.
+ *
+ * NOTES
+ *  Default flags:
+ *      Uri_CREATE_CANONICALIZE, Uri_CREATE_DECODE_EXTRA_INFO, Uri_CREATE_CRACK_UNKNOWN_SCHEMES,
+ *      Uri_CREATE_PRE_PROCESS_HTML_URI, Uri_CREATE_NO_IE_SETTINGS.
+ */
+HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI)
+{
+    const DWORD supported_flags = Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME|
+        Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|Uri_CREATE_NO_CANONICALIZE|Uri_CREATE_CANONICALIZE|
+        Uri_CREATE_DECODE_EXTRA_INFO|Uri_CREATE_NO_DECODE_EXTRA_INFO|Uri_CREATE_CRACK_UNKNOWN_SCHEMES|
+        Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES|Uri_CREATE_PRE_PROCESS_HTML_URI|Uri_CREATE_NO_PRE_PROCESS_HTML_URI|
+        Uri_CREATE_NO_IE_SETTINGS|Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS|Uri_CREATE_FILE_USE_DOS_PATH;
+    Uri *ret;
+    HRESULT hr;
+    parse_data data;
+
+    TRACE("(%s %lx %Ix %p)\n", debugstr_w(pwzURI), dwFlags, dwReserved, ppURI);
+
+    if(!ppURI)
+        return E_INVALIDARG;
+
+    if(!pwzURI) {
+        *ppURI = NULL;
+        return E_INVALIDARG;
+    }
+
+    /* Check for invalid flags. */
+    if(has_invalid_flag_combination(dwFlags)) {
+        *ppURI = NULL;
+        return E_INVALIDARG;
+    }
+
+    /* Currently unsupported. */
+    if(dwFlags & ~supported_flags)
+        FIXME("Ignoring unsupported flag(s) %lx\n", dwFlags & ~supported_flags);
+
+    hr = Uri_Construct(NULL, (void**)&ret);
+    if(FAILED(hr)) {
+        *ppURI = NULL;
+        return hr;
+    }
+
+    /* Explicitly set the default flags if it doesn't cause a flag conflict. */
+    apply_default_flags(&dwFlags);
+
+    /* Pre process the URI, unless told otherwise. */
+    if(!(dwFlags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI))
+        ret->raw_uri = pre_process_uri(pwzURI);
+    else
+        ret->raw_uri = SysAllocString(pwzURI);
+
+    if(!ret->raw_uri) {
+        free(ret);
+        return E_OUTOFMEMORY;
+    }
+
+    memset(&data, 0, sizeof(parse_data));
+    data.uri = ret->raw_uri;
+
+    /* Validate and parse the URI into its components. */
+    if(!parse_uri(&data, dwFlags)) {
+        /* Encountered an unsupported or invalid URI */
+        IUri_Release(&ret->IUri_iface);
+        *ppURI = NULL;
+        return E_INVALIDARG;
+    }
+
+    /* Canonicalize the URI. */
+    hr = canonicalize_uri(&data, ret, dwFlags);
+    if(FAILED(hr)) {
+        IUri_Release(&ret->IUri_iface);
+        *ppURI = NULL;
+        return hr;
+    }
+
+    ret->create_flags = dwFlags;
+
+    *ppURI = &ret->IUri_iface;
+    return S_OK;
+}
+
+/***********************************************************************
+ *           CreateUriWithFragment (iertutil.@)
+ *
+ * Creates a new IUri object. This is almost the same as CreateUri, expect that
+ * it allows you to explicitly specify a fragment (pwzFragment) for pwzURI.
+ *
+ * PARAMS
+ *  pwzURI      [I] The URI to parse and perform canonicalization on.
+ *  pwzFragment [I] The explicit fragment string which should be added to pwzURI.
+ *  dwFlags     [I] The flags which will be passed to CreateUri.
+ *  dwReserved  [I] Reserved (not used).
+ *  ppURI       [O] The resulting IUri after parsing/canonicalization.
+ *
+ * RETURNS
+ *  Success: S_OK. ppURI contains the pointer to the newly allocated IUri.
+ *  Failure: E_INVALIDARG if pwzURI already contains a fragment and pwzFragment
+ *           isn't NULL. Will also return E_INVALIDARG for the same reasons as
+ *           CreateUri will. E_OUTOFMEMORY if any allocation fails.
+ */
+HRESULT WINAPI CreateUriWithFragment(LPCWSTR pwzURI, LPCWSTR pwzFragment, DWORD dwFlags,
+                                     DWORD_PTR dwReserved, IUri **ppURI)
+{
+    HRESULT hres;
+    TRACE("(%s %s %lx %Ix %p)\n", debugstr_w(pwzURI), debugstr_w(pwzFragment), dwFlags, dwReserved, ppURI);
+
+    if(!ppURI)
+        return E_INVALIDARG;
+
+    if(!pwzURI) {
+        *ppURI = NULL;
+        return E_INVALIDARG;
+    }
+
+    /* Check if a fragment should be appended to the URI string. */
+    if(pwzFragment) {
+        WCHAR *uriW;
+        DWORD uri_len, frag_len;
+        BOOL add_pound;
+
+        /* Check if the original URI already has a fragment component. */
+        if(StrChrW(pwzURI, '#')) {
+            *ppURI = NULL;
+            return E_INVALIDARG;
+        }
+
+        uri_len = lstrlenW(pwzURI);
+        frag_len = lstrlenW(pwzFragment);
+
+        /* If the fragment doesn't start with a '#', one will be added. */
+        add_pound = *pwzFragment != '#';
+
+        if(add_pound)
+            uriW = malloc((uri_len + frag_len + 2) * sizeof(WCHAR));
+        else
+            uriW = malloc((uri_len + frag_len + 1) * sizeof(WCHAR));
+
+        if(!uriW)
+            return E_OUTOFMEMORY;
+
+        memcpy(uriW, pwzURI, uri_len*sizeof(WCHAR));
+        if(add_pound)
+            uriW[uri_len++] = '#';
+        memcpy(uriW+uri_len, pwzFragment, (frag_len+1)*sizeof(WCHAR));
+
+        hres = CreateUri(uriW, dwFlags, 0, ppURI);
+
+        free(uriW);
+    } else
+        /* A fragment string wasn't specified, so just forward the call. */
+        hres = CreateUri(pwzURI, dwFlags, 0, ppURI);
+
+    return hres;
+}
+
+static HRESULT build_uri(const UriBuilder *builder, IUri **uri, DWORD create_flags,
+                         DWORD use_orig_flags, DWORD encoding_mask)
+{
+    HRESULT hr;
+    parse_data data;
+    Uri *ret;
+
+    if(!uri)
+        return E_POINTER;
+
+    if(encoding_mask && (!builder->uri || builder->modified_props)) {
+        *uri = NULL;
+        return E_NOTIMPL;
+    }
+
+    /* Decide what flags should be used when creating the Uri. */
+    if((use_orig_flags & UriBuilder_USE_ORIGINAL_FLAGS) && builder->uri)
+        create_flags = builder->uri->create_flags;
+    else {
+        if(has_invalid_flag_combination(create_flags)) {
+            *uri = NULL;
+            return E_INVALIDARG;
+        }
+
+        /* Set the default flags if they don't cause a conflict. */
+        apply_default_flags(&create_flags);
+    }
+
+    /* Return the base IUri if no changes have been made and the create_flags match. */
+    if(builder->uri && !builder->modified_props && builder->uri->create_flags == create_flags) {
+        *uri = &builder->uri->IUri_iface;
+        IUri_AddRef(*uri);
+        return S_OK;
+    }
+
+    hr = validate_components(builder, &data, create_flags);
+    if(FAILED(hr)) {
+        *uri = NULL;
+        return hr;
+    }
+
+    hr = Uri_Construct(NULL, (void**)&ret);
+    if(FAILED(hr)) {
+        *uri = NULL;
+        return hr;
+    }
+
+    hr = generate_uri(builder, &data, ret, create_flags);
+    if(FAILED(hr)) {
+        IUri_Release(&ret->IUri_iface);
+        *uri = NULL;
+        return hr;
+    }
+
+    *uri = &ret->IUri_iface;
+    return S_OK;
+}
+
+static inline UriBuilder* impl_from_IUriBuilder(IUriBuilder *iface)
+{
+    return CONTAINING_RECORD(iface, UriBuilder, IUriBuilder_iface);
+}
+
+static HRESULT WINAPI UriBuilder_QueryInterface(IUriBuilder *iface, REFIID riid, void **ppv)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
+        *ppv = &This->IUriBuilder_iface;
+    }else if(IsEqualGUID(&IID_IUriBuilder, riid)) {
+        TRACE("(%p)->(IID_IUriBuilder %p)\n", This, ppv);
+        *ppv = &This->IUriBuilder_iface;
+    }else {
+        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI UriBuilder_AddRef(IUriBuilder *iface)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI UriBuilder_Release(IUriBuilder *iface)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+
+    if(!ref) {
+        if(This->uri) IUri_Release(&This->uri->IUri_iface);
+        free(This->fragment);
+        free(This->host);
+        free(This->password);
+        free(This->path);
+        free(This->query);
+        free(This->scheme);
+        free(This->username);
+        free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI UriBuilder_CreateUriSimple(IUriBuilder *iface,
+                                                 DWORD        dwAllowEncodingPropertyMask,
+                                                 DWORD_PTR    dwReserved,
+                                                 IUri       **ppIUri)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    HRESULT hr;
+    TRACE("(%p)->(%ld %Id %p)\n", This, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
+
+    hr = build_uri(This, ppIUri, 0, UriBuilder_USE_ORIGINAL_FLAGS, dwAllowEncodingPropertyMask);
+    if(hr == E_NOTIMPL)
+        FIXME("(%p)->(%ld %Id %p)\n", This, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
+    return hr;
+}
+
+static HRESULT WINAPI UriBuilder_CreateUri(IUriBuilder *iface,
+                                           DWORD        dwCreateFlags,
+                                           DWORD        dwAllowEncodingPropertyMask,
+                                           DWORD_PTR    dwReserved,
+                                           IUri       **ppIUri)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    HRESULT hr;
+    TRACE("(%p)->(0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
+
+    if(dwCreateFlags == -1)
+        hr = build_uri(This, ppIUri, 0, UriBuilder_USE_ORIGINAL_FLAGS, dwAllowEncodingPropertyMask);
+    else
+        hr = build_uri(This, ppIUri, dwCreateFlags, 0, dwAllowEncodingPropertyMask);
+
+    if(hr == E_NOTIMPL)
+        FIXME("(%p)->(0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
+    return hr;
+}
+
+static HRESULT WINAPI UriBuilder_CreateUriWithFlags(IUriBuilder *iface,
+                                         DWORD        dwCreateFlags,
+                                         DWORD        dwUriBuilderFlags,
+                                         DWORD        dwAllowEncodingPropertyMask,
+                                         DWORD_PTR    dwReserved,
+                                         IUri       **ppIUri)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    HRESULT hr;
+    TRACE("(%p)->(0x%08lx 0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwUriBuilderFlags,
+        dwAllowEncodingPropertyMask, dwReserved, ppIUri);
+
+    hr = build_uri(This, ppIUri, dwCreateFlags, dwUriBuilderFlags, dwAllowEncodingPropertyMask);
+    if(hr == E_NOTIMPL)
+        FIXME("(%p)->(0x%08lx 0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwUriBuilderFlags,
+            dwAllowEncodingPropertyMask, dwReserved, ppIUri);
+    return hr;
+}
+
+static HRESULT WINAPI  UriBuilder_GetIUri(IUriBuilder *iface, IUri **ppIUri)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p)\n", This, ppIUri);
+
+    if(!ppIUri)
+        return E_POINTER;
+
+    if(This->uri) {
+        IUri *uri = &This->uri->IUri_iface;
+        IUri_AddRef(uri);
+        *ppIUri = uri;
+    } else
+        *ppIUri = NULL;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI UriBuilder_SetIUri(IUriBuilder *iface, IUri *pIUri)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p)\n", This, pIUri);
+
+    if(pIUri) {
+        Uri *uri;
+
+        if((uri = get_uri_obj(pIUri))) {
+            /* Only reset the builder if its Uri isn't the same as
+             * the Uri passed to the function.
+             */
+            if(This->uri != uri) {
+                reset_builder(This);
+
+                This->uri = uri;
+                if(uri->has_port)
+                    This->port = uri->port;
+
+                IUri_AddRef(pIUri);
+            }
+        } else {
+            FIXME("(%p)->(%p) Unknown IUri types not supported yet.\n", This, pIUri);
+            return E_NOTIMPL;
+        }
+    } else if(This->uri)
+        /* Only reset the builder if its Uri isn't NULL. */
+        reset_builder(This);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI UriBuilder_GetFragment(IUriBuilder *iface, DWORD *pcchFragment, LPCWSTR *ppwzFragment)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchFragment, ppwzFragment);
+
+    if(!This->uri || This->uri->fragment_start == -1 || This->modified_props & Uri_HAS_FRAGMENT)
+        return get_builder_component(&This->fragment, &This->fragment_len, NULL, 0, ppwzFragment, pcchFragment);
+    else
+        return get_builder_component(&This->fragment, &This->fragment_len, This->uri->canon_uri+This->uri->fragment_start,
+                                     This->uri->fragment_len, ppwzFragment, pcchFragment);
+}
+
+static HRESULT WINAPI UriBuilder_GetHost(IUriBuilder *iface, DWORD *pcchHost, LPCWSTR *ppwzHost)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchHost, ppwzHost);
+
+    if(!This->uri || This->uri->host_start == -1 || This->modified_props & Uri_HAS_HOST)
+        return get_builder_component(&This->host, &This->host_len, NULL, 0, ppwzHost, pcchHost);
+    else {
+        if(This->uri->host_type == Uri_HOST_IPV6)
+            /* Don't include the '[' and ']' around the address. */
+            return get_builder_component(&This->host, &This->host_len, This->uri->canon_uri+This->uri->host_start+1,
+                                         This->uri->host_len-2, ppwzHost, pcchHost);
+        else
+            return get_builder_component(&This->host, &This->host_len, This->uri->canon_uri+This->uri->host_start,
+                                         This->uri->host_len, ppwzHost, pcchHost);
+    }
+}
+
+static HRESULT WINAPI UriBuilder_GetPassword(IUriBuilder *iface, DWORD *pcchPassword, LPCWSTR *ppwzPassword)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchPassword, ppwzPassword);
+
+    if(!This->uri || This->uri->userinfo_split == -1 || This->modified_props & Uri_HAS_PASSWORD)
+        return get_builder_component(&This->password, &This->password_len, NULL, 0, ppwzPassword, pcchPassword);
+    else {
+        const WCHAR *start = This->uri->canon_uri+This->uri->userinfo_start+This->uri->userinfo_split+1;
+        DWORD len = This->uri->userinfo_len-This->uri->userinfo_split-1;
+        return get_builder_component(&This->password, &This->password_len, start, len, ppwzPassword, pcchPassword);
+    }
+}
+
+static HRESULT WINAPI UriBuilder_GetPath(IUriBuilder *iface, DWORD *pcchPath, LPCWSTR *ppwzPath)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchPath, ppwzPath);
+
+    if(!This->uri || This->uri->path_start == -1 || This->modified_props & Uri_HAS_PATH)
+        return get_builder_component(&This->path, &This->path_len, NULL, 0, ppwzPath, pcchPath);
+    else
+        return get_builder_component(&This->path, &This->path_len, This->uri->canon_uri+This->uri->path_start,
+                                     This->uri->path_len, ppwzPath, pcchPath);
+}
+
+static HRESULT WINAPI UriBuilder_GetPort(IUriBuilder *iface, BOOL *pfHasPort, DWORD *pdwPort)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pfHasPort, pdwPort);
+
+    if(!pfHasPort) {
+        if(pdwPort)
+            *pdwPort = 0;
+        return E_POINTER;
+    }
+
+    if(!pdwPort) {
+        *pfHasPort = FALSE;
+        return E_POINTER;
+    }
+
+    *pfHasPort = This->has_port;
+    *pdwPort = This->port;
+    return S_OK;
+}
+
+static HRESULT WINAPI UriBuilder_GetQuery(IUriBuilder *iface, DWORD *pcchQuery, LPCWSTR *ppwzQuery)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchQuery, ppwzQuery);
+
+    if(!This->uri || This->uri->query_start == -1 || This->modified_props & Uri_HAS_QUERY)
+        return get_builder_component(&This->query, &This->query_len, NULL, 0, ppwzQuery, pcchQuery);
+    else
+        return get_builder_component(&This->query, &This->query_len, This->uri->canon_uri+This->uri->query_start,
+                                     This->uri->query_len, ppwzQuery, pcchQuery);
+}
+
+static HRESULT WINAPI UriBuilder_GetSchemeName(IUriBuilder *iface, DWORD *pcchSchemeName, LPCWSTR *ppwzSchemeName)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchSchemeName, ppwzSchemeName);
+
+    if(!This->uri || This->uri->scheme_start == -1 || This->modified_props & Uri_HAS_SCHEME_NAME)
+        return get_builder_component(&This->scheme, &This->scheme_len, NULL, 0, ppwzSchemeName, pcchSchemeName);
+    else
+        return get_builder_component(&This->scheme, &This->scheme_len, This->uri->canon_uri+This->uri->scheme_start,
+                                     This->uri->scheme_len, ppwzSchemeName, pcchSchemeName);
+}
+
+static HRESULT WINAPI UriBuilder_GetUserName(IUriBuilder *iface, DWORD *pcchUserName, LPCWSTR *ppwzUserName)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p %p)\n", This, pcchUserName, ppwzUserName);
+
+    if(!This->uri || This->uri->userinfo_start == -1 || This->uri->userinfo_split == 0 ||
+       This->modified_props & Uri_HAS_USER_NAME)
+        return get_builder_component(&This->username, &This->username_len, NULL, 0, ppwzUserName, pcchUserName);
+    else {
+        const WCHAR *start = This->uri->canon_uri+This->uri->userinfo_start;
+
+        /* Check if there's a password in the userinfo section. */
+        if(This->uri->userinfo_split > -1)
+            /* Don't include the password. */
+            return get_builder_component(&This->username, &This->username_len, start,
+                                         This->uri->userinfo_split, ppwzUserName, pcchUserName);
+        else
+            return get_builder_component(&This->username, &This->username_len, start,
+                                         This->uri->userinfo_len, ppwzUserName, pcchUserName);
+    }
+}
+
+static HRESULT WINAPI UriBuilder_SetFragment(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+    return set_builder_component(&This->fragment, &This->fragment_len, pwzNewValue, '#',
+                                 &This->modified_props, Uri_HAS_FRAGMENT);
+}
+
+static HRESULT WINAPI UriBuilder_SetHost(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+
+    /* Host name can't be set to NULL. */
+    if(!pwzNewValue)
+        return E_INVALIDARG;
+
+    return set_builder_component(&This->host, &This->host_len, pwzNewValue, 0,
+                                 &This->modified_props, Uri_HAS_HOST);
+}
+
+static HRESULT WINAPI UriBuilder_SetPassword(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+    return set_builder_component(&This->password, &This->password_len, pwzNewValue, 0,
+                                 &This->modified_props, Uri_HAS_PASSWORD);
+}
+
+static HRESULT WINAPI UriBuilder_SetPath(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+    return set_builder_component(&This->path, &This->path_len, pwzNewValue, 0,
+                                 &This->modified_props, Uri_HAS_PATH);
+}
+
+static HRESULT WINAPI UriBuilder_SetPort(IUriBuilder *iface, BOOL fHasPort, DWORD dwNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%d %ld)\n", This, fHasPort, dwNewValue);
+
+    This->has_port = fHasPort;
+    This->port = dwNewValue;
+    This->modified_props |= Uri_HAS_PORT;
+    return S_OK;
+}
+
+static HRESULT WINAPI UriBuilder_SetQuery(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+    return set_builder_component(&This->query, &This->query_len, pwzNewValue, '?',
+                                 &This->modified_props, Uri_HAS_QUERY);
+}
+
+static HRESULT WINAPI UriBuilder_SetSchemeName(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+
+    /* Only set the scheme name if it's not NULL or empty. */
+    if(!pwzNewValue || !*pwzNewValue)
+        return E_INVALIDARG;
+
+    return set_builder_component(&This->scheme, &This->scheme_len, pwzNewValue, 0,
+                                 &This->modified_props, Uri_HAS_SCHEME_NAME);
+}
+
+static HRESULT WINAPI UriBuilder_SetUserName(IUriBuilder *iface, LPCWSTR pwzNewValue)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
+    return set_builder_component(&This->username, &This->username_len, pwzNewValue, 0,
+                                 &This->modified_props, Uri_HAS_USER_NAME);
+}
+
+static HRESULT WINAPI UriBuilder_RemoveProperties(IUriBuilder *iface, DWORD dwPropertyMask)
+{
+    const DWORD accepted_flags = Uri_HAS_AUTHORITY|Uri_HAS_DOMAIN|Uri_HAS_EXTENSION|Uri_HAS_FRAGMENT|Uri_HAS_HOST|
+                                 Uri_HAS_PASSWORD|Uri_HAS_PATH|Uri_HAS_PATH_AND_QUERY|Uri_HAS_QUERY|
+                                 Uri_HAS_USER_INFO|Uri_HAS_USER_NAME;
+
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(0x%08lx)\n", This, dwPropertyMask);
+
+    if(dwPropertyMask & ~accepted_flags)
+        return E_INVALIDARG;
+
+    if(dwPropertyMask & Uri_HAS_FRAGMENT)
+        UriBuilder_SetFragment(iface, NULL);
+
+    /* Even though you can't set the host name to NULL or an
+     * empty string, you can still remove it... for some reason.
+     */
+    if(dwPropertyMask & Uri_HAS_HOST)
+        set_builder_component(&This->host, &This->host_len, NULL, 0,
+                              &This->modified_props, Uri_HAS_HOST);
+
+    if(dwPropertyMask & Uri_HAS_PASSWORD)
+        UriBuilder_SetPassword(iface, NULL);
+
+    if(dwPropertyMask & Uri_HAS_PATH)
+        UriBuilder_SetPath(iface, NULL);
+
+    if(dwPropertyMask & Uri_HAS_PORT)
+        UriBuilder_SetPort(iface, FALSE, 0);
+
+    if(dwPropertyMask & Uri_HAS_QUERY)
+        UriBuilder_SetQuery(iface, NULL);
+
+    if(dwPropertyMask & Uri_HAS_USER_NAME)
+        UriBuilder_SetUserName(iface, NULL);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI UriBuilder_HasBeenModified(IUriBuilder *iface, BOOL *pfModified)
+{
+    UriBuilder *This = impl_from_IUriBuilder(iface);
+    TRACE("(%p)->(%p)\n", This, pfModified);
+
+    if(!pfModified)
+        return E_POINTER;
+
+    *pfModified = This->modified_props > 0;
+    return S_OK;
+}
+
+static const IUriBuilderVtbl UriBuilderVtbl = {
+    UriBuilder_QueryInterface,
+    UriBuilder_AddRef,
+    UriBuilder_Release,
+    UriBuilder_CreateUriSimple,
+    UriBuilder_CreateUri,
+    UriBuilder_CreateUriWithFlags,
+    UriBuilder_GetIUri,
+    UriBuilder_SetIUri,
+    UriBuilder_GetFragment,
+    UriBuilder_GetHost,
+    UriBuilder_GetPassword,
+    UriBuilder_GetPath,
+    UriBuilder_GetPort,
+    UriBuilder_GetQuery,
+    UriBuilder_GetSchemeName,
+    UriBuilder_GetUserName,
+    UriBuilder_SetFragment,
+    UriBuilder_SetHost,
+    UriBuilder_SetPassword,
+    UriBuilder_SetPath,
+    UriBuilder_SetPort,
+    UriBuilder_SetQuery,
+    UriBuilder_SetSchemeName,
+    UriBuilder_SetUserName,
+    UriBuilder_RemoveProperties,
+    UriBuilder_HasBeenModified,
+};
+
+/***********************************************************************
+ *           CreateIUriBuilder (iertutil.@)
+ */
+HRESULT WINAPI CreateIUriBuilder(IUri *pIUri, DWORD dwFlags, DWORD_PTR dwReserved, IUriBuilder **ppIUriBuilder)
+{
+    UriBuilder *ret;
+
+    TRACE("(%p %lx %Ix %p)\n", pIUri, dwFlags, dwReserved, ppIUriBuilder);
+
+    if(!ppIUriBuilder)
+        return E_POINTER;
+
+    ret = calloc(1, sizeof(UriBuilder));
+    if(!ret)
+        return E_OUTOFMEMORY;
+
+    ret->IUriBuilder_iface.lpVtbl = &UriBuilderVtbl;
+    ret->ref = 1;
+
+    if(pIUri) {
+        Uri *uri;
+
+        if((uri = get_uri_obj(pIUri))) {
+            if(!uri->create_flags) {
+                free(ret);
+                return E_UNEXPECTED;
+            }
+            IUri_AddRef(pIUri);
+            ret->uri = uri;
+
+            if(uri->has_port)
+                /* Windows doesn't set 'has_port' to TRUE in this case. */
+                ret->port = uri->port;
+
+        } else {
+            free(ret);
+            *ppIUriBuilder = NULL;
+            FIXME("(%p %lx %Ix %p): Unknown IUri types not supported yet.\n", pIUri, dwFlags,
+                  dwReserved, ppIUriBuilder);
+            return E_NOTIMPL;
+        }
+    }
+
+    *ppIUriBuilder = &ret->IUriBuilder_iface;
+    return S_OK;
+}
+
+/* Merges the base path with the relative path and stores the resulting path
+ * and path len in 'result' and 'result_len'.
+ */
+static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative,
+                           DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags)
+{
+    const WCHAR *end = NULL;
+    DWORD base_copy_len = 0;
+    WCHAR *ptr;
+
+    if(base_len) {
+        if(data->scheme_type == URL_SCHEME_MK && *relative == '/') {
+            /* Find '::' segment */
+            for(end = base; end < base+base_len-1; end++) {
+                if(end[0] == ':' && end[1] == ':') {
+                    end++;
+                    break;
+                }
+            }
+
+            /* If not found, try finding the end of @xxx: */
+            if(end == base+base_len-1)
+                end = *base == '@' ? wmemchr(base, ':', base_len) : NULL;
+        }else {
+            /* Find the characters that will be copied over from the base path. */
+            for (end = base + base_len - 1; end >= base; end--) if (*end == '/') break;
+            if(end < base && data->scheme_type == URL_SCHEME_FILE)
+                /* Try looking for a '\\'. */
+                for (end = base + base_len - 1; end >= base; end--) if (*end == '\\') break;
+        }
+    }
+
+    if (end) base_copy_len = (end+1)-base;
+    *result = malloc((base_copy_len + relative_len + 1) * sizeof(WCHAR));
+
+    if(!(*result)) {
+        *result_len = 0;
+        return E_OUTOFMEMORY;
+    }
+
+    ptr = *result;
+    memcpy(ptr, base, base_copy_len*sizeof(WCHAR));
+    ptr += base_copy_len;
+
+    memcpy(ptr, relative, relative_len*sizeof(WCHAR));
+    ptr += relative_len;
+    *ptr = '\0';
+
+    *result_len = (ptr-*result);
+    TRACE("ret %s\n", debugstr_wn(*result, *result_len));
+    return S_OK;
+}
+
+static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, DWORD extras) {
+    Uri *ret;
+    HRESULT hr;
+    parse_data data;
+    Uri *proc_uri = base;
+    DWORD create_flags = 0, len = 0;
+
+    memset(&data, 0, sizeof(parse_data));
+
+    /* Base case is when the relative Uri has a scheme name,
+     * if it does, then 'result' will contain the same data
+     * as the relative Uri.
+     */
+    if(relative->scheme_start > -1) {
+        data.uri = SysAllocString(relative->raw_uri);
+        if(!data.uri) {
+            *result = NULL;
+            return E_OUTOFMEMORY;
+        }
+
+        parse_uri(&data, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME);
+
+        hr = Uri_Construct(NULL, (void**)&ret);
+        if(FAILED(hr)) {
+            *result = NULL;
+            return hr;
+        }
+
+        if(extras & COMBINE_URI_FORCE_FLAG_USE) {
+            if(flags & URL_DONT_SIMPLIFY)
+                create_flags |= Uri_CREATE_NO_CANONICALIZE;
+            if(flags & URL_DONT_UNESCAPE_EXTRA_INFO)
+                create_flags |= Uri_CREATE_NO_DECODE_EXTRA_INFO;
+        }
+
+        ret->raw_uri = data.uri;
+        hr = canonicalize_uri(&data, ret, create_flags);
+        if(FAILED(hr)) {
+            IUri_Release(&ret->IUri_iface);
+            *result = NULL;
+            return hr;
+        }
+
+        apply_default_flags(&create_flags);
+        ret->create_flags = create_flags;
+
+        *result = &ret->IUri_iface;
+    } else {
+        WCHAR *path = NULL;
+        DWORD raw_flags = 0;
+
+        if(base->scheme_start > -1) {
+            data.scheme = base->canon_uri+base->scheme_start;
+            data.scheme_len = base->scheme_len;
+            data.scheme_type = base->scheme_type;
+        } else {
+            data.is_relative = TRUE;
+            data.scheme_type = URL_SCHEME_UNKNOWN;
+            create_flags |= Uri_CREATE_ALLOW_RELATIVE;
+        }
+
+        if(relative->authority_start > -1)
+            proc_uri = relative;
+
+        if(proc_uri->authority_start > -1) {
+            if(proc_uri->userinfo_start > -1 && proc_uri->userinfo_split != 0) {
+                data.username = proc_uri->canon_uri+proc_uri->userinfo_start;
+                data.username_len = (proc_uri->userinfo_split > -1) ? proc_uri->userinfo_split : proc_uri->userinfo_len;
+            }
+
+            if(proc_uri->userinfo_split > -1) {
+                data.password = proc_uri->canon_uri+proc_uri->userinfo_start+proc_uri->userinfo_split+1;
+                data.password_len = proc_uri->userinfo_len-proc_uri->userinfo_split-1;
+            }
+
+            if(proc_uri->host_start > -1) {
+                const WCHAR *host = proc_uri->canon_uri+proc_uri->host_start;
+                parse_host(&host, &data, 0);
+            }
+
+            if(proc_uri->has_port) {
+                data.has_port = TRUE;
+                data.port_value = proc_uri->port;
+            }
+        } else if(base->scheme_type != URL_SCHEME_FILE)
+            data.is_opaque = TRUE;
+
+        if(proc_uri == relative || relative->path_start == -1 || !relative->path_len) {
+            if(proc_uri->path_start > -1) {
+                data.path = proc_uri->canon_uri+proc_uri->path_start;
+                data.path_len = proc_uri->path_len;
+            } else if(!data.is_opaque) {
+                /* Just set the path as a '/' if the base didn't have
+                 * one and if it's a hierarchical URI.
+                 */
+                data.path = L"/";
+                data.path_len = 1;
+            }
+
+            if(relative->query_start > -1)
+                proc_uri = relative;
+
+            if(proc_uri->query_start > -1) {
+                data.query = proc_uri->canon_uri+proc_uri->query_start;
+                data.query_len = proc_uri->query_len;
+            }
+        } else {
+            const WCHAR *ptr, **pptr;
+            DWORD path_offset = 0, path_len = 0;
+
+            /* There's two possibilities on what will happen to the path component
+             * of the result IUri. First, if the relative path begins with a '/'
+             * then the resulting path will just be the relative path. Second, if
+             * relative path doesn't begin with a '/' then the base path and relative
+             * path are merged together.
+             */
+            if(relative->path_len && *(relative->canon_uri+relative->path_start) == '/' && data.scheme_type != URL_SCHEME_MK) {
+                WCHAR *tmp = NULL;
+                BOOL copy_drive_path = FALSE;
+
+                /* If the relative IUri's path starts with a '/', then we
+                 * don't use the base IUri's path. Unless the base IUri
+                 * is a file URI, in which case it uses the drive path of
+                 * the base IUri (if it has any) in the new path.
+                 */
+                if(base->scheme_type == URL_SCHEME_FILE) {
+                    if(base->path_len > 3 && *(base->canon_uri+base->path_start) == '/' &&
+                       is_drive_path(base->canon_uri+base->path_start+1)) {
+                        path_len += 3;
+                        copy_drive_path = TRUE;
+                    }
+                }
+
+                path_len += relative->path_len;
+
+                path = malloc((path_len + 1) * sizeof(WCHAR));
+                if(!path) {
+                    *result = NULL;
+                    return E_OUTOFMEMORY;
+                }
+
+                tmp = path;
+
+                /* Copy the base paths, drive path over. */
+                if(copy_drive_path) {
+                    memcpy(tmp, base->canon_uri+base->path_start, 3*sizeof(WCHAR));
+                    tmp += 3;
+                }
+
+                memcpy(tmp, relative->canon_uri+relative->path_start, relative->path_len*sizeof(WCHAR));
+                path[path_len] = '\0';
+            } else {
+                /* Merge the base path with the relative path. */
+                hr = merge_paths(&data, base->canon_uri+base->path_start, base->path_len,
+                                 relative->canon_uri+relative->path_start, relative->path_len,
+                                 &path, &path_len, flags);
+                if(FAILED(hr)) {
+                    *result = NULL;
+                    return hr;
+                }
+
+                /* If the resulting IUri is a file URI, the drive path isn't
+                 * reduced out when the dot segments are removed.
+                 */
+                if(path_len >= 3 && data.scheme_type == URL_SCHEME_FILE && !data.host) {
+                    if(*path == '/' && is_drive_path(path+1))
+                        path_offset = 2;
+                    else if(is_drive_path(path))
+                        path_offset = 1;
+                }
+            }
+
+            /* Check if the dot segments need to be removed from the path. */
+            if(!(flags & URL_DONT_SIMPLIFY) && !data.is_opaque) {
+                DWORD offset = (path_offset > 0) ? path_offset+1 : 0;
+                DWORD new_len = remove_dot_segments(path+offset,path_len-offset);
+
+                if(new_len != path_len) {
+                    WCHAR *tmp = realloc(path, (offset + new_len + 1) * sizeof(WCHAR));
+                    if(!tmp) {
+                        free(path);
+                        *result = NULL;
+                        return E_OUTOFMEMORY;
+                    }
+
+                    tmp[new_len+offset] = '\0';
+                    path = tmp;
+                    path_len = new_len+offset;
+                }
+            }
+
+            if(relative->query_start > -1) {
+                data.query = relative->canon_uri+relative->query_start;
+                data.query_len = relative->query_len;
+            }
+
+            /* Make sure the path component is valid. */
+            ptr = path;
+            pptr = &ptr;
+            if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) ||
+               (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) {
+                free(path);
+                *result = NULL;
+                return E_INVALIDARG;
+            }
+        }
+
+        if(relative->fragment_start > -1) {
+            data.fragment = relative->canon_uri+relative->fragment_start;
+            data.fragment_len = relative->fragment_len;
+        }
+
+        if(flags & URL_DONT_SIMPLIFY)
+            raw_flags |= RAW_URI_FORCE_PORT_DISP;
+        if(flags & URL_FILE_USE_PATHURL)
+            raw_flags |= RAW_URI_CONVERT_TO_DOS_PATH;
+
+        len = generate_raw_uri(&data, data.uri, raw_flags);
+        data.uri = SysAllocStringLen(NULL, len);
+        if(!data.uri) {
+            free(path);
+            *result = NULL;
+            return E_OUTOFMEMORY;
+        }
+
+        generate_raw_uri(&data, data.uri, raw_flags);
+
+        hr = Uri_Construct(NULL, (void**)&ret);
+        if(FAILED(hr)) {
+            SysFreeString(data.uri);
+            free(path);
+            *result = NULL;
+            return hr;
+        }
+
+        if(flags & URL_DONT_SIMPLIFY)
+            create_flags |= Uri_CREATE_NO_CANONICALIZE;
+        if(flags & URL_FILE_USE_PATHURL)
+            create_flags |= Uri_CREATE_FILE_USE_DOS_PATH;
+
+        ret->raw_uri = data.uri;
+        hr = canonicalize_uri(&data, ret, create_flags);
+        if(FAILED(hr)) {
+            IUri_Release(&ret->IUri_iface);
+            *result = NULL;
+            return hr;
+        }
+
+        if(flags & URL_DONT_SIMPLIFY)
+            ret->display_modifiers |= URI_DISPLAY_NO_DEFAULT_PORT_AUTH;
+
+        apply_default_flags(&create_flags);
+        ret->create_flags = create_flags;
+        *result = &ret->IUri_iface;
+
+        free(path);
+    }
+
+    return S_OK;
+}
+
+static HRESULT parse_canonicalize(const Uri *uri, DWORD flags, LPWSTR output,
+                                  DWORD output_len, DWORD *result_len)
+{
+    const WCHAR *ptr = NULL;
+    WCHAR *path = NULL;
+    const WCHAR **pptr;
+    DWORD len = 0;
+    BOOL reduce_path;
+
+    /* URL_UNESCAPE only has effect if none of the URL_ESCAPE flags are set. */
+    const BOOL allow_unescape = !(flags & URL_ESCAPE_UNSAFE) &&
+                                !(flags & URL_ESCAPE_SPACES_ONLY) &&
+                                !(flags & URL_ESCAPE_PERCENT);
+
+
+    /* Check if the dot segments need to be removed from the
+     * path component.
+     */
+    if(uri->scheme_start > -1 && uri->path_start > -1) {
+        ptr = uri->canon_uri+uri->scheme_start+uri->scheme_len+1;
+        pptr = &ptr;
+    }
+    reduce_path = !(flags & URL_DONT_SIMPLIFY) &&
+                  ptr && check_hierarchical(pptr);
+
+    for(ptr = uri->canon_uri; ptr < uri->canon_uri+uri->canon_len; ++ptr) {
+        BOOL do_default_action = TRUE;
+
+        /* Keep track of the path if we need to remove dot segments from
+         * it later.
+         */
+        if(reduce_path && !path && ptr == uri->canon_uri+uri->path_start)
+            path = output+len;
+
+        /* Check if it's time to reduce the path. */
+        if(reduce_path && ptr == uri->canon_uri+uri->path_start+uri->path_len) {
+            DWORD current_path_len = (output+len) - path;
+            DWORD new_path_len = remove_dot_segments(path, current_path_len);
+
+            /* Update the current length. */
+            len -= (current_path_len-new_path_len);
+            reduce_path = FALSE;
+        }
+
+        if(*ptr == '%') {
+            const WCHAR decoded = decode_pct_val(ptr);
+            if(decoded) {
+                if(allow_unescape && (flags & URL_UNESCAPE)) {
+                    if(len < output_len)
+                        output[len] = decoded;
+                    len++;
+                    ptr += 2;
+                    do_default_action = FALSE;
+                }
+            }
+
+            /* See if %'s needed to encoded. */
+            if(do_default_action && (flags & URL_ESCAPE_PERCENT)) {
+                if(len + 3 < output_len)
+                    pct_encode_val(*ptr, output+len);
+                len += 3;
+                do_default_action = FALSE;
+            }
+        } else if(*ptr == ' ') {
+            if((flags & URL_ESCAPE_SPACES_ONLY) &&
+               !(flags & URL_ESCAPE_UNSAFE)) {
+                if(len + 3 < output_len)
+                    pct_encode_val(*ptr, output+len);
+                len += 3;
+                do_default_action = FALSE;
+            }
+        } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr)) {
+            if(flags & URL_ESCAPE_UNSAFE) {
+                if(len + 3 < output_len)
+                    pct_encode_val(*ptr, output+len);
+                len += 3;
+                do_default_action = FALSE;
+            }
+        }
+
+        if(do_default_action) {
+            if(len < output_len)
+                output[len] = *ptr;
+            len++;
+        }
+    }
+
+    /* Sometimes the path is the very last component of the IUri, so
+     * see if the dot segments need to be reduced now.
+     */
+    if(reduce_path && path) {
+        DWORD current_path_len = (output+len) - path;
+        DWORD new_path_len = remove_dot_segments(path, current_path_len);
+
+        /* Update the current length. */
+        len -= (current_path_len-new_path_len);
+    }
+
+    if(len < output_len)
+        output[len] = 0;
+    else
+        output[output_len-1] = 0;
+
+    /* The null terminator isn't included in the length. */
+    *result_len = len;
+    if(len >= output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    return S_OK;
+}
+
+static HRESULT parse_friendly(IUri *uri, LPWSTR output, DWORD output_len,
+                              DWORD *result_len)
+{
+    HRESULT hr;
+    DWORD display_len;
+    BSTR display;
+
+    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_DISPLAY_URI, &display_len, 0);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    *result_len = display_len;
+    if(display_len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    hr = IUri_GetDisplayUri(uri, &display);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    memcpy(output, display, (display_len+1)*sizeof(WCHAR));
+    SysFreeString(display);
+    return S_OK;
+}
+
+static HRESULT parse_rootdocument(const Uri *uri, LPWSTR output, DWORD output_len,
+                                  DWORD *result_len)
+{
+    static const WCHAR colon_slashesW[] = {':','/','/'};
+
+    WCHAR *ptr;
+    DWORD len = 0;
+
+    /* Windows only returns the root document if the URI has an authority
+     * and it's not an unknown scheme type or a file scheme type.
+     */
+    if(uri->authority_start == -1 ||
+       uri->scheme_type == URL_SCHEME_UNKNOWN ||
+       uri->scheme_type == URL_SCHEME_FILE) {
+        *result_len = 0;
+        if(!output_len)
+            return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+        output[0] = 0;
+        return S_OK;
+    }
+
+    len = uri->scheme_len+uri->authority_len;
+    /* For the "://" and '/' which will be added. */
+    len += 4;
+
+    if(len+1 > output_len) {
+        *result_len = len;
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+    }
+
+    ptr = output;
+    memcpy(ptr, uri->canon_uri+uri->scheme_start, uri->scheme_len*sizeof(WCHAR));
+
+    /* Add the "://". */
+    ptr += uri->scheme_len;
+    memcpy(ptr, colon_slashesW, sizeof(colon_slashesW));
+
+    /* Add the authority. */
+    ptr += ARRAY_SIZE(colon_slashesW);
+    memcpy(ptr, uri->canon_uri+uri->authority_start, uri->authority_len*sizeof(WCHAR));
+
+    /* Add the '/' after the authority. */
+    ptr += uri->authority_len;
+    *ptr = '/';
+    ptr[1] = 0;
+
+    *result_len = len;
+    return S_OK;
+}
+
+static HRESULT parse_document(const Uri *uri, LPWSTR output, DWORD output_len,
+                              DWORD *result_len)
+{
+    DWORD len = 0;
+
+    /* It has to be a known scheme type, but, it can't be a file
+     * scheme. It also has to hierarchical.
+     */
+    if(uri->scheme_type == URL_SCHEME_UNKNOWN ||
+       uri->scheme_type == URL_SCHEME_FILE ||
+       uri->authority_start == -1) {
+        *result_len = 0;
+        if(output_len < 1)
+            return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+        output[0] = 0;
+        return S_OK;
+    }
+
+    if(uri->fragment_start > -1)
+        len = uri->fragment_start;
+    else
+        len = uri->canon_len;
+
+    *result_len = len;
+    if(len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    memcpy(output, uri->canon_uri, len*sizeof(WCHAR));
+    output[len] = 0;
+    return S_OK;
+}
+
+static HRESULT parse_path_from_url(const Uri *uri, LPWSTR output, DWORD output_len,
+                                   DWORD *result_len)
+{
+    const WCHAR *path_ptr;
+    WCHAR buffer[INTERNET_MAX_URL_LENGTH+1];
+    WCHAR *ptr;
+
+    if(uri->scheme_type != URL_SCHEME_FILE) {
+        *result_len = 0;
+        if(output_len > 0)
+            output[0] = 0;
+        return E_INVALIDARG;
+    }
+
+    ptr = buffer;
+    if(uri->host_start > -1) {
+        static const WCHAR slash_slashW[] = {'\\','\\'};
+
+        memcpy(ptr, slash_slashW, sizeof(slash_slashW));
+        ptr += ARRAY_SIZE(slash_slashW);
+        memcpy(ptr, uri->canon_uri+uri->host_start, uri->host_len*sizeof(WCHAR));
+        ptr += uri->host_len;
+    }
+
+    path_ptr = uri->canon_uri+uri->path_start;
+    if(uri->path_len > 3 && *path_ptr == '/' && is_drive_path(path_ptr+1))
+        /* Skip past the '/' in front of the drive path. */
+        ++path_ptr;
+
+    for(; path_ptr < uri->canon_uri+uri->path_start+uri->path_len; ++path_ptr, ++ptr) {
+        BOOL do_default_action = TRUE;
+
+        if(*path_ptr == '%') {
+            const WCHAR decoded = decode_pct_val(path_ptr);
+            if(decoded) {
+                *ptr = decoded;
+                path_ptr += 2;
+                do_default_action = FALSE;
+            }
+        } else if(*path_ptr == '/') {
+            *ptr = '\\';
+            do_default_action = FALSE;
+        }
+
+        if(do_default_action)
+            *ptr = *path_ptr;
+    }
+
+    *ptr = 0;
+
+    *result_len = ptr-buffer;
+    if(*result_len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    memcpy(output, buffer, (*result_len+1)*sizeof(WCHAR));
+    return S_OK;
+}
+
+static HRESULT parse_url_from_path(IUri *uri, LPWSTR output, DWORD output_len,
+                                   DWORD *result_len)
+{
+    HRESULT hr;
+    BSTR received;
+    DWORD len = 0;
+
+    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_ABSOLUTE_URI, &len, 0);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    *result_len = len;
+    if(len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    hr = IUri_GetAbsoluteUri(uri, &received);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    memcpy(output, received, (len+1)*sizeof(WCHAR));
+    SysFreeString(received);
+
+    return S_OK;
+}
+
+static HRESULT parse_schema(IUri *uri, LPWSTR output, DWORD output_len,
+                            DWORD *result_len)
+{
+    HRESULT hr;
+    DWORD len;
+    BSTR received;
+
+    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_SCHEME_NAME, &len, 0);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    *result_len = len;
+    if(len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    hr = IUri_GetSchemeName(uri, &received);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    memcpy(output, received, (len+1)*sizeof(WCHAR));
+    SysFreeString(received);
+
+    return S_OK;
+}
+
+static HRESULT parse_site(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
+{
+    HRESULT hr;
+    DWORD len;
+    BSTR received;
+
+    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_HOST, &len, 0);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    *result_len = len;
+    if(len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    hr = IUri_GetHost(uri, &received);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    memcpy(output, received, (len+1)*sizeof(WCHAR));
+    SysFreeString(received);
+
+    return S_OK;
+}
+
+static HRESULT parse_domain(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
+{
+    HRESULT hr;
+    DWORD len;
+    BSTR received;
+
+    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_DOMAIN, &len, 0);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    *result_len = len;
+    if(len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    hr = IUri_GetDomain(uri, &received);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    memcpy(output, received, (len+1)*sizeof(WCHAR));
+    SysFreeString(received);
+
+    return S_OK;
+}
+
+static HRESULT parse_anchor(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
+{
+    HRESULT hr;
+    DWORD len;
+    BSTR received;
+
+    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_FRAGMENT, &len, 0);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    *result_len = len;
+    if(len+1 > output_len)
+        return STRSAFE_E_INSUFFICIENT_BUFFER;
+
+    hr = IUri_GetFragment(uri, &received);
+    if(FAILED(hr)) {
+        *result_len = 0;
+        return hr;
+    }
+
+    memcpy(output, received, (len+1)*sizeof(WCHAR));
+    SysFreeString(received);
+
+    return S_OK;
+}
+
+/***********************************************************************
+ *           PrivateCoInternetCombineIUri (iertutil.@)
+ */
+HRESULT WINAPI PrivateCoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri,
+                                            DWORD dwCombineFlags, IUri **ppCombinedUri,
+                                            DWORD_PTR dwReserved)
+{
+    Uri *relative, *base;
+
+    TRACE("(%p %p %lx %p %Ix)\n", pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
+
+    if (!ppCombinedUri)
+        return E_INVALIDARG;
+
+    if (!pBaseUri || !pRelativeUri)
+    {
+        *ppCombinedUri = NULL;
+        return E_INVALIDARG;
+    }
+
+    relative = get_uri_obj(pRelativeUri);
+    base = get_uri_obj(pBaseUri);
+    if (!relative || !base)
+    {
+        *ppCombinedUri = NULL;
+        FIXME("(%p %p %lx %p %Ix) Unknown IUri types not supported yet.\n", pBaseUri, pRelativeUri,
+              dwCombineFlags, ppCombinedUri, dwReserved);
+        return E_NOTIMPL;
+    }
+
+    return combine_uri(base, relative, dwCombineFlags, ppCombinedUri, dwReserved);
+}
+
+/***********************************************************************
+ *           PrivateCoInternetParseIUri (iertutil.@)
+ */
+HRESULT WINAPI PrivateCoInternetParseIUri(IUri *pIUri, PARSEACTION ParseAction, DWORD dwFlags,
+                                          LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult,
+                                          DWORD_PTR dwReserved)
+{
+    HRESULT hr;
+    Uri *uri;
+
+    TRACE("(%p %d %lx %p %ld %p %Ix)\n", pIUri, ParseAction, dwFlags, pwzResult, cchResult,
+          pcchResult, dwReserved);
+
+    if (!pcchResult)
+        return E_POINTER;
+
+    if (!pwzResult || !pIUri)
+    {
+        *pcchResult = 0;
+        return E_INVALIDARG;
+    }
+
+    if (!(uri = get_uri_obj(pIUri)))
+    {
+        *pcchResult = 0;
+        FIXME("(%p %d %lx %p %ld %p %Ix) Unknown IUri's not supported for this action.\n", pIUri,
+              ParseAction, dwFlags, pwzResult, cchResult, pcchResult, dwReserved);
+        return E_NOTIMPL;
+    }
+
+    switch (ParseAction)
+    {
+    case PARSE_CANONICALIZE:
+        hr = parse_canonicalize(uri, dwFlags, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_FRIENDLY:
+        hr = parse_friendly(pIUri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_ROOTDOCUMENT:
+        hr = parse_rootdocument(uri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_DOCUMENT:
+        hr = parse_document(uri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_PATH_FROM_URL:
+        hr = parse_path_from_url(uri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_URL_FROM_PATH:
+        hr = parse_url_from_path(pIUri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_SCHEMA:
+        hr = parse_schema(pIUri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_SITE:
+        hr = parse_site(pIUri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_DOMAIN:
+        hr = parse_domain(pIUri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_LOCATION:
+    case PARSE_ANCHOR:
+        hr = parse_anchor(pIUri, pwzResult, cchResult, pcchResult);
+        break;
+    case PARSE_SECURITY_URL:
+    case PARSE_MIME:
+    case PARSE_SERVER:
+    case PARSE_SECURITY_DOMAIN:
+        *pcchResult = 0;
+        hr = E_FAIL;
+        break;
+    default:
+        *pcchResult = 0;
+        hr = E_NOTIMPL;
+        FIXME("(%p %d %lx %p %ld %p %Ix) Partial stub.\n", pIUri, ParseAction, dwFlags, pwzResult,
+              cchResult, pcchResult, dwReserved);
+    }
+
+    return hr;
+}
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c
index 65f46f205508..9e6c96537c86 100644
--- a/dlls/imm32/ime.c
+++ b/dlls/imm32/ime.c
@@ -23,6 +23,35 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(imm);
 
+static BOOL is_ime_hkl( HKL hkl )
+{
+    /* See https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values#input-method-editors */
+    switch (HIWORD(hkl))
+    {
+    case MAKELANGID(LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_BENGALI, SUBLANG_BENGALI_INDIA): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): return TRUE;
+    case MAKELANGID(LANG_GUJARATI, SUBLANG_GUJARATI_INDIA): return TRUE;
+    case MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA): return TRUE;
+    case MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN): return TRUE;
+    case MAKELANGID(LANG_KANNADA, SUBLANG_KANNADA_INDIA): return TRUE;
+    case MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN): return TRUE;
+    case MAKELANGID(LANG_MALAYALAM, SUBLANG_MALAYALAM_INDIA): return TRUE;
+    case MAKELANGID(LANG_MARATHI, SUBLANG_MARATHI_INDIA): return TRUE;
+    case MAKELANGID(LANG_NEPALI, SUBLANG_NEPALI_NEPAL): return TRUE;
+    case MAKELANGID(LANG_ODIA, SUBLANG_ODIA_INDIA): return TRUE;
+    case MAKELANGID(LANG_PUNJABI, SUBLANG_PUNJABI_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA): return TRUE;
+    case MAKELANGID(LANG_TELUGU, SUBLANG_TELUGU_INDIA): return TRUE;
+    case MAKELANGID(LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM): return TRUE;
+    case MAKELANGID(LANG_YI, SUBLANG_YI_PRC): return TRUE;
+    default: return (HIWORD(hkl) & 0xe000) == 0xe000;
+    }
+}
+
 struct ime_private
 {
     BOOL in_composition;
@@ -517,6 +546,8 @@ BOOL WINAPI ImeProcessKey( HIMC himc, UINT vkey, LPARAM lparam, BYTE *state )
 
     TRACE( "himc %p, vkey %#x, lparam %#Ix, state %p\n", himc, vkey, lparam, state );
 
+    if (!is_ime_hkl( GetKeyboardLayout( 0 ) )) return FALSE;
+
     if (!(ctx = ImmLockIMC( himc ))) return FALSE;
     ret = NtUserMessageCall( ctx->hWnd, WINE_IME_PROCESS_KEY, vkey, lparam, &params,
                              NtUserImeDriverCall, FALSE );
@@ -536,6 +567,8 @@ UINT WINAPI ImeToAsciiEx( UINT vkey, UINT vsc, BYTE *state, TRANSMSGLIST *msgs,
     TRACE( "vkey %#x, vsc %#x, state %p, msgs %p, flags %#x, himc %p\n",
            vkey, vsc, state, msgs, flags, himc );
 
+    if (!is_ime_hkl( GetKeyboardLayout( 0 ) )) return 0;
+
     if (!(ctx = ImmLockIMC( himc ))) return 0;
     if (!(compstr = ImmLockIMCC( ctx->hCompStr ))) goto done;
     size = max( compstr->dwSize, sizeof(COMPOSITIONSTRING) );
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c
index 5e6d847fed27..c4d1404f3ea5 100644
--- a/dlls/imm32/tests/imm32.c
+++ b/dlls/imm32/tests/imm32.c
@@ -35,8 +35,6 @@
 
 #include "ime_test.h"
 
-static const BOOL is_win64 = sizeof(void *) > sizeof(int);
-
 static const char *debugstr_wm_ime( UINT msg )
 {
     switch (msg)
@@ -7059,7 +7057,6 @@ static void test_ImmTranslateMessage( BOOL kbd_char_first )
             .hkl = expect_ime, .himc = default_himc, .func = IME_TO_ASCII_EX,
             /* FIXME what happened to kbd_char_first here!? */
             .to_ascii_ex = {.vkey = 'Q', .vsc = 0xc010},
-            .todo_value = kbd_char_first && is_win64,
         },
         {0},
     };
diff --git a/dlls/iyuv_32/Makefile.in b/dlls/iyuv_32/Makefile.in
new file mode 100644
index 000000000000..6b9b11569b1b
--- /dev/null
+++ b/dlls/iyuv_32/Makefile.in
@@ -0,0 +1,5 @@
+MODULE       = iyuv_32.dll
+IMPORTS      = user32 mfplat ole32
+
+SOURCES = \
+	iyuv.c
diff --git a/dlls/iyuv_32/iyuv.c b/dlls/iyuv_32/iyuv.c
new file mode 100644
index 000000000000..e114fde50e02
--- /dev/null
+++ b/dlls/iyuv_32/iyuv.c
@@ -0,0 +1,191 @@
+/*
+ * iyuv Video "Decoder"
+ * Copyright 2026 Brendan McGrath 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 "windef.h"
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+
+#include "commdlg.h"
+#include "initguid.h"
+#include "vfw.h"
+#include "wmcodecdsp.h"
+
+#include "wine/debug.h"
+
+#define COBJMACROS
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mfidl.h"
+#include "mftransform.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(iyuv_32);
+
+static HINSTANCE IYUV_32_module;
+
+static LRESULT IYUV_Open(const ICINFO *icinfo)
+{
+    FIXME("DRV_OPEN %p\n", icinfo);
+
+    return 0;
+}
+
+static LRESULT IYUV_DecompressQuery(const BITMAPINFOHEADER *in, const BITMAPINFOHEADER *out)
+{
+    FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out);
+
+    return ICERR_UNSUPPORTED;
+}
+
+static LRESULT IYUV_DecompressGetFormat(BITMAPINFOHEADER *in, BITMAPINFOHEADER *out)
+{
+    FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out);
+
+    return ICERR_UNSUPPORTED;
+}
+
+static LRESULT IYUV_DecompressBegin(IMFTransform *transform, const BITMAPINFOHEADER *in, const BITMAPINFOHEADER *out)
+{
+    FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", transform, in, out);
+
+    return ICERR_UNSUPPORTED;
+}
+
+static LRESULT IYUV_Decompress(IMFTransform *transform, const ICDECOMPRESS *params)
+{
+    FIXME("ICM_DECOMPRESS %p %p\n", transform, params);
+
+    return ICERR_UNSUPPORTED;
+}
+
+static LRESULT IYUV_GetInfo(ICINFO *icinfo, DWORD size)
+{
+    FIXME("ICM_GETINFO %p %lu\n", icinfo, size);
+
+    return ICERR_UNSUPPORTED;
+}
+
+/***********************************************************************
+ *              DriverProc (IYUV_32.@)
+ */
+LRESULT WINAPI IYUV_DriverProc(DWORD_PTR driver_id, HDRVR hdrvr, UINT msg, LPARAM param1, LPARAM param2)
+{
+    IMFTransform *transform = (IMFTransform *)driver_id;
+    LRESULT r = ICERR_UNSUPPORTED;
+
+    TRACE("%Id %p %04x %08Ix %08Ix\n", driver_id, hdrvr, msg, param1, param2);
+
+    switch (msg)
+    {
+    case DRV_LOAD:
+        TRACE("DRV_LOAD\n");
+        r = TRUE;
+        break;
+
+    case DRV_OPEN:
+        r = IYUV_Open((ICINFO *)param2);
+        break;
+
+    case DRV_CLOSE:
+        TRACE("DRV_CLOSE\n");
+        if (transform)
+            IMFTransform_Release(transform);
+        r = TRUE;
+        break;
+
+    case DRV_ENABLE:
+    case DRV_DISABLE:
+    case DRV_FREE:
+        break;
+
+    case ICM_GETINFO:
+        r = IYUV_GetInfo((ICINFO *)param1, (DWORD)param2);
+        break;
+
+    case ICM_DECOMPRESS_QUERY:
+        r = IYUV_DecompressQuery((BITMAPINFOHEADER *)param1, (BITMAPINFOHEADER *)param2);
+        break;
+
+    case ICM_DECOMPRESS_GET_FORMAT:
+        r = IYUV_DecompressGetFormat((BITMAPINFOHEADER *)param1, (BITMAPINFOHEADER *)param2);
+        break;
+
+    case ICM_DECOMPRESS_GET_PALETTE:
+        FIXME("ICM_DECOMPRESS_GET_PALETTE\n");
+        break;
+
+    case ICM_DECOMPRESS:
+        r = IYUV_Decompress(transform, (ICDECOMPRESS *)param1);
+        break;
+
+    case ICM_DECOMPRESS_BEGIN:
+        r = IYUV_DecompressBegin(transform, (BITMAPINFOHEADER *)param1, (BITMAPINFOHEADER *)param2);
+        break;
+
+    case ICM_DECOMPRESS_END:
+        r = ICERR_OK;
+        break;
+
+    case ICM_DECOMPRESSEX_QUERY:
+    case ICM_DECOMPRESSEX_BEGIN:
+    case ICM_DECOMPRESSEX:
+    case ICM_DECOMPRESSEX_END:
+        /* unsupported */
+        break;
+
+    case ICM_COMPRESS_QUERY:
+        r = ICERR_BADFORMAT;
+        /* fall through */
+    case ICM_COMPRESS_GET_FORMAT:
+    case ICM_COMPRESS_END:
+    case ICM_COMPRESS:
+        FIXME("compression not implemented\n");
+        break;
+
+    case ICM_CONFIGURE:
+        break;
+
+    default:
+        FIXME("Unknown message: %04x %Id %Id\n", msg, param1, param2);
+    }
+
+    return r;
+}
+
+/***********************************************************************
+ *              DllMain
+ */
+BOOL WINAPI DllMain(HINSTANCE module, DWORD reason, LPVOID reserved)
+{
+    TRACE("(%p,%lu,%p)\n", module, reason, reserved);
+
+    switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+        DisableThreadLibraryCalls(module);
+        IYUV_32_module = module;
+        break;
+    }
+    return TRUE;
+}
diff --git a/dlls/iyuv_32/iyuv_32.spec b/dlls/iyuv_32/iyuv_32.spec
new file mode 100644
index 000000000000..a0c64b966965
--- /dev/null
+++ b/dlls/iyuv_32/iyuv_32.spec
@@ -0,0 +1 @@
+@ stdcall -private DriverProc(long long long long long) IYUV_DriverProc
diff --git a/dlls/iyuv_32/tests/Makefile.in b/dlls/iyuv_32/tests/Makefile.in
new file mode 100644
index 000000000000..7d47050a25b2
--- /dev/null
+++ b/dlls/iyuv_32/tests/Makefile.in
@@ -0,0 +1,6 @@
+TESTDLL   = iyuv_32.dll
+IMPORTS   = msvfw32
+
+SOURCES = \
+	iyuv_32.c \
+	resource.rc
diff --git a/dlls/iyuv_32/tests/i420frame.bmp b/dlls/iyuv_32/tests/i420frame.bmp
new file mode 100755
index 0000000000000000000000000000000000000000..acebee03e4d77aa6f5720df1c0b0bc04940c67fe
GIT binary patch
literal 50742
zcmeI*u}wlz6vyG~297{tqYJzN=q+fitSy|u5r`95QMiev3%G!V4#0bt6QMqoCtSaO
zatY=Y!jCV(7>w)tY1{rb#qDjJ$2f1j_p7#wd$H5?;}^%<Wm&qT0Rs#$zyJdbFu(u<
z3^2d|0}L=Qu7Nhs-O+#n1{h#~0R|XgfB^;=V1NMz7#P<;?=3zd<Y>SE0}L?000Rs#
zzyJdbFu(u<42)`^%`HCv<7mJD0}L?000Rs#zyJdbFu(u<42)`E-<IxZzyJdbFu(u<
z3^2d|0}L?000Rt+YoN7#cQjyt0R|XgfB^;=V1NMz7+`<_2F5iIzx;_mZF4kWfB^;=
zV1NMz7+`<_1{h#~0R~1j5dQ@}o|>Zp0}L?000Rs#zyJdbFu(u<3@|XNfp1el0R@T*
ze3}9ZC{R@3-4swjfuaIiQ$PU)iV8fL0tzTlRA6HYD4;-5fjd(`0R@T*T$=(4C{R@3
z#nJ*rFU!Sz+nuEaCQA!^SX$u0(gMGh7D(URTvXspfmcflT+9z@MGy4G(gI(W7WlEW
Oz_X<V&b+<-`^yLU=LZe|

literal 0
HcmV?d00001

diff --git a/dlls/iyuv_32/tests/iyuv_32.c b/dlls/iyuv_32/tests/iyuv_32.c
new file mode 100644
index 000000000000..97572411e6e9
--- /dev/null
+++ b/dlls/iyuv_32/tests/iyuv_32.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2026 Brendan McGrath 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 <windef.h>
+#include <wingdi.h>
+
+#include "wine/test.h"
+#include <vfw.h>
+
+#define FOURCC_I420 mmioFOURCC('I', '4', '2', '0')
+#define FOURCC_IYUV mmioFOURCC('I', 'Y', 'U', 'V')
+
+#pragma pack(push, 2)
+struct bmp_header
+{
+    char magic[2];
+    DWORD length;
+    DWORD reserved;
+    DWORD offset;
+};
+#pragma pack(pop)
+
+typedef UINT32 (*yuv_to_bgr32_converter)(WORD x, WORD y, WORD stride, WORD height, const BYTE *data);
+
+static void write_bitmap_to_file(const BITMAPINFOHEADER *bitmap_header, const BYTE *data, HANDLE output)
+{
+    struct bmp_header header =
+    {
+        .magic = "BM",
+        .length = sizeof(header) + sizeof(*bitmap_header) + bitmap_header->biSizeImage,
+        .offset = sizeof(header) + sizeof(*bitmap_header),
+    };
+    DWORD written;
+    BOOL ret;
+
+    ret = WriteFile(output, &header, sizeof(header), &written, NULL);
+    ok(ret, "WriteFile failed, error %lu\n", GetLastError());
+    ok(written == sizeof(header), "written %lu bytes\n", written);
+    ret = WriteFile(output, bitmap_header, sizeof(*bitmap_header), &written, NULL);
+    ok(ret, "WriteFile failed, error %lu\n", GetLastError());
+    ok(written == sizeof(*bitmap_header), "written %lu bytes\n", written);
+    ret = WriteFile(output, data, bitmap_header->biSizeImage, &written, NULL);
+    ok(ret, "WriteFile failed, error %lu\n", GetLastError());
+    ok(written == bitmap_header->biSizeImage, "written %lu bytes\n", written);
+}
+
+static HANDLE open_temp_file(const WCHAR *output_filename)
+{
+    WCHAR path[MAX_PATH];
+    HANDLE output;
+
+    GetTempPathW(ARRAY_SIZE(path), path);
+    lstrcatW(path, output_filename);
+
+    output = CreateFileW(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
+    ok(output != INVALID_HANDLE_VALUE, "CreateFileW failed, error %lu\n", GetLastError());
+
+    trace("created %s\n", debugstr_w(path));
+
+    return output;
+}
+
+static void write_bitmap(const BITMAPINFOHEADER *bitmap_header, const BYTE *data, const WCHAR *output_filename)
+{
+    HANDLE output;
+
+    output = open_temp_file(output_filename);
+    write_bitmap_to_file(bitmap_header, data, output);
+
+    CloseHandle(output);
+}
+
+static void convert_yuv_and_write_bitmap(const BITMAPINFOHEADER *bitmap_header, const BYTE *data,
+                                         yuv_to_bgr32_converter convert, const WCHAR *output_filename)
+{
+    BITMAPINFOHEADER bgr32_header;
+    UINT32 *bgr32_ptr;
+    BYTE *bgr32_data;
+    HANDLE output;
+    DWORD written;
+    WORD x, y;
+    BOOL ret;
+
+    bgr32_header = *bitmap_header;
+    bgr32_header.biBitCount = 32;
+    bgr32_header.biCompression = BI_RGB;
+    bgr32_header.biSizeImage = bgr32_header.biWidth * bgr32_header.biHeight * bgr32_header.biBitCount / 8;
+    bgr32_header.biHeight = -bitmap_header->biHeight;
+    bgr32_data = malloc(bgr32_header.biSizeImage);
+
+    output = open_temp_file(output_filename);
+    bgr32_ptr = (UINT32 *)bgr32_data;
+    for (y = 0; y < bitmap_header->biWidth; y++)
+        for (x = 0; x < bitmap_header->biHeight; x++)
+            *bgr32_ptr++ = convert(x, y, bitmap_header->biWidth, bitmap_header->biHeight, data);
+
+    write_bitmap_to_file(&bgr32_header, (BYTE *)bgr32_data, output);
+    ret = WriteFile(output, data, bitmap_header->biSizeImage, &written, NULL);
+    ok(ret, "WriteFile failed, error %lu\n", GetLastError());
+    ok(written == bitmap_header->biSizeImage, "written %lu bytes\n", written);
+
+    free(bgr32_data);
+    CloseHandle(output);
+}
+
+#define CLAMP(x) ((x) > 255 ? 255 : (x) < 0 ? 0 : (x))
+
+static UINT32 convert_yuv_to_bgr32(INT y, INT u, INT v)
+{
+    const INT y_offset = 16;
+    const INT uv_offset = 128;
+    const INT adj = 1024;
+    const INT c1 = 1.164 * adj + .5;
+    const INT c2 = 1.596 * adj + .5;
+    const INT c3 = 0.391 * adj + .5;
+    const INT c4 = 0.813 * adj + .5;
+    const INT c5 = 2.018 * adj + .5;
+
+    INT r, g, b;
+
+    y -= y_offset;
+    u -= uv_offset;
+    v -= uv_offset;
+
+    r = CLAMP((c1 * y + c2 * v) / adj);
+    g = CLAMP((c1 * y - c4 * v - c3 * u) / adj);
+    b = CLAMP((c1 * y + c5 * u) / adj);
+
+    return 0xff000000 | r << 16 | g << 8 | b;
+}
+
+static UINT32 convert_i420_to_bgr32(WORD x, WORD y, WORD stride, WORD height, const BYTE *data)
+{
+    WORD uv_offset, u_offset, v_offset;
+    BYTE yuv_y, yuv_u, yuv_v;
+
+    u_offset = height * stride;
+    v_offset = u_offset * 5 / 4;
+    uv_offset = (y / 2) * stride / 2 + x / 2;
+
+    yuv_y = data[y * stride + x];
+    yuv_u = data[u_offset + uv_offset];
+    yuv_v = data[v_offset + uv_offset];
+
+    return convert_yuv_to_bgr32(yuv_y, yuv_u, yuv_v);
+}
+
+static void test_formats(DWORD handler)
+{
+    BITMAPINFOHEADER in = {.biSize = sizeof(BITMAPINFOHEADER)};
+    BITMAPINFOHEADER out = {.biSize = sizeof(BITMAPINFOHEADER)};
+    ICINFO info;
+    LRESULT lr;
+    DWORD res;
+    HIC hic;
+
+    in.biCompression = handler;
+
+    hic = ICLocate(ICTYPE_VIDEO, handler, &in, NULL, ICMODE_DECOMPRESS);
+    ok(!hic, "Should fail to open codec without width and/or height.\n");
+
+    in.biWidth = 320;
+    in.biHeight = 240;
+
+    hic = ICLocate(ICTYPE_VIDEO, handler, &in, NULL, ICMODE_DECOMPRESS);
+    ok(!!hic, "Failed to open codec.\n");
+
+    lr = ICGetInfo(hic, &info, sizeof(info));
+    ok(lr == sizeof(info), "Got %Id.\n", lr);
+    ok(info.dwSize == sizeof(info), "Got size %lu.\n", info.dwSize);
+    ok(info.fccType == ICTYPE_VIDEO, "Got type %#lx.\n", info.fccType);
+    ok(info.fccHandler == FOURCC_IYUV, "Got handler %#lx.\n", info.fccHandler);
+    ok(info.dwFlags == 0, "Got flags %#lx.\n", info.dwFlags);
+    ok(info.dwVersion == 0, "Got version %#lx.\n", info.dwVersion);
+    ok(info.dwVersionICM == ICVERSION, "Got ICM version %#lx.\n", info.dwVersionICM);
+
+    res = ICDecompressQuery(hic, &in, NULL);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    res = ICDecompressGetFormat(hic, &in, NULL);
+    ok(res == sizeof(BITMAPINFOHEADER), "Got %ld.\n", res);
+
+    res = ICDecompressGetFormat(hic, &in, &out);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    ok(out.biSize == sizeof(BITMAPINFOHEADER), "Got size %lu.\n", out.biSize);
+    ok(out.biWidth == 320, "Got width %ld.\n", out.biWidth);
+    ok(out.biHeight == 240, "Got height %ld.\n", out.biHeight);
+    ok(out.biPlanes == 1, "Got %u planes.\n", out.biPlanes);
+    ok(out.biBitCount == 24, "Got depth %u.\n", out.biBitCount);
+    ok(out.biCompression == BI_RGB, "Got compression %#lx.\n", out.biCompression);
+    ok(out.biSizeImage == 320 * 240 * 3, "Got image size %lu.\n", out.biSizeImage);
+    ok(!out.biXPelsPerMeter, "Got horizontal resolution %ld.\n", out.biXPelsPerMeter);
+    ok(!out.biYPelsPerMeter, "Got vertical resolution %ld.\n", out.biYPelsPerMeter);
+    ok(!out.biClrUsed, "Got %lu used colours.\n", out.biClrUsed);
+    ok(!out.biClrImportant, "Got %lu important colours.\n", out.biClrImportant);
+
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    out.biHeight = -240;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biHeight = -480;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biHeight = 480;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biWidth = 640;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biWidth = 160;
+    out.biHeight = 120;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biWidth = 320;
+    out.biHeight = 240;
+    out.biBitCount = 8;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    out.biBitCount = 16;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    out.biBitCount = 32;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biBitCount = 16;
+    out.biCompression = BI_BITFIELDS;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biCompression = mmioFOURCC('C', 'L', 'J', 'R');
+    out.biBitCount = 8;
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    out.biBitCount = 16;
+    out.biCompression = mmioFOURCC('U', 'Y', 'V', 'Y');
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+    out.biCompression = mmioFOURCC('Y', 'U', 'Y', '2');
+    res = ICDecompressQuery(hic, &in, &out);
+    ok(res == ICERR_BADFORMAT, "Got %ld.\n", res);
+
+    res = ICDecompressEnd(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    out.biCompression = BI_RGB;
+    out.biBitCount = 24;
+    res = ICDecompressBegin(hic, &in, &out);
+    todo_wine
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    res = ICDecompressEnd(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    lr = ICDecompressExQuery(hic, 0, &in, NULL, 0, 0, 320, 240, NULL, NULL, 0, 0, 0, 0);
+    ok(lr == ICERR_UNSUPPORTED, "Got %Id.\n", lr);
+
+    lr = ICDecompressExBegin(hic, 0, &in, NULL, 0, 0, 320, 240, &out, NULL, 20, 20, 320, 240);
+    ok(lr == ICERR_UNSUPPORTED, "Got %Id.\n", lr);
+    lr = ICDecompressExEnd(hic);
+    ok(lr == ICERR_UNSUPPORTED, "Got %Id.\n", lr);
+
+    res = ICClose(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+}
+
+static void test_decompress(DWORD handler)
+{
+    static const DWORD width = 96, height = 96;
+
+    const struct bmp_header *expect_rgb_header;
+    const BYTE *expect_rgb_data;
+    BYTE rgb_data[96 * 96 * 3];
+    DWORD res, diff;
+    BYTE *i420_data;
+    HRSRC resource;
+    HIC hic;
+
+    BITMAPINFOHEADER i420_info =
+    {
+        .biSize = sizeof(i420_info),
+        .biWidth = width,
+        .biHeight = height,
+        .biPlanes = 1,
+        .biBitCount = 12,
+        .biCompression = handler,
+    };
+
+    BITMAPINFOHEADER rgb_info =
+    {
+        .biSize = sizeof(rgb_info),
+        .biWidth = width,
+        .biHeight = height,
+        .biPlanes = 1,
+        .biBitCount = 24,
+        .biCompression = BI_RGB,
+        .biSizeImage = sizeof(rgb_data),
+    };
+
+    resource = FindResourceW(NULL, L"i420frame.bmp", (const WCHAR *)RT_RCDATA);
+    i420_data = LockResource(LoadResource(GetModuleHandleW(NULL), resource));
+    i420_data += *(DWORD *)(i420_data + 2);
+    i420_info.biSizeImage = SizeofResource(GetModuleHandleW(NULL), resource);
+
+    hic = ICOpen(ICTYPE_VIDEO, handler, ICMODE_DECOMPRESS);
+    ok(!!hic, "Failed to open codec.\n");
+
+    res = ICDecompressBegin(hic, &i420_info, &rgb_info);
+    todo_wine
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    if (res != ICERR_OK)
+        goto skip_decompression_tests;
+
+    res = ICDecompress(hic, 0, &i420_info, i420_data, &rgb_info, rgb_data);
+    todo_wine
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    res = ICDecompressEnd(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    write_bitmap(&rgb_info, rgb_data, L"rgb24frame_flip.bmp");
+
+    resource = FindResourceW(NULL, L"rgb24frame_flip.bmp", (const WCHAR *)RT_RCDATA);
+    expect_rgb_header = ((const struct bmp_header *)LockResource(LoadResource(GetModuleHandleW(NULL), resource)));
+    expect_rgb_data = (const BYTE *)((uintptr_t)expect_rgb_header + expect_rgb_header->offset);
+
+    diff = 0;
+    for (unsigned int i = 0; i < rgb_info.biSizeImage; ++i)
+        diff += abs((int)rgb_data[i] - (int)expect_rgb_data[i]);
+    diff = diff * 100 / 256 / rgb_info.biSizeImage;
+    todo_wine
+    ok(diff == 0, "Got %lu%% difference.\n", diff);
+
+skip_decompression_tests:
+    res = ICClose(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+}
+
+static void test_compress(DWORD handler)
+{
+    const struct bmp_header *expect_i420_header;
+    const struct bmp_header *rgb_header;
+    const BITMAPINFOHEADER *rgb_info;
+    BYTE i420_data[96 * 96 * 3 / 2];
+    const BYTE *expect_i420_data;
+    BITMAPINFOHEADER i420_info;
+    DWORD res, flags, diff;
+    const BYTE *rgb_data;
+    HRSRC resource;
+    HIC hic;
+
+    hic = ICOpen(ICTYPE_VIDEO, handler, ICMODE_COMPRESS);
+    ok(!!hic, "Failed to open codec.\n");
+
+    resource = FindResourceW(NULL, L"rgb24frame_flip.bmp", (const WCHAR *)RT_RCDATA);
+    rgb_header = ((const struct bmp_header *)LockResource(LoadResource(GetModuleHandleW(NULL), resource)));
+    rgb_info = (const BITMAPINFOHEADER *)(rgb_header + 1);
+    rgb_data = (const BYTE *)(rgb_info + 1);
+
+    res = ICCompressQuery(hic, rgb_info, NULL);
+    todo_wine
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    if (res != ICERR_OK)
+        goto skip_compression_tests;
+
+    res = ICCompressGetSize(hic, rgb_info, NULL);
+    ok(res == rgb_info->biWidth * rgb_info->biHeight * 3, "Got %ld.\n", res);
+
+    res = ICCompressGetFormatSize(hic, rgb_info);
+    ok(res == sizeof(BITMAPINFOHEADER), "Got %ld.\n", res);
+
+    memset(&i420_info, 0xcc, sizeof(i420_info));
+    res = ICCompressGetFormat(hic, rgb_info, &i420_info);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    ok(i420_info.biSize == sizeof(BITMAPINFOHEADER), "Got size %lu.\n", i420_info.biSize);
+    ok(i420_info.biWidth == 96, "Got width %ld.\n", i420_info.biWidth);
+    ok(i420_info.biHeight == 96, "Got height %ld.\n", i420_info.biHeight);
+    ok(i420_info.biPlanes == 1, "Got %u planes.\n", i420_info.biPlanes);
+    ok(i420_info.biBitCount == 24, "Got depth %u.\n", i420_info.biBitCount);
+    ok(i420_info.biCompression == FOURCC_IYUV, "Got compression %#lx.\n", i420_info.biCompression);
+    ok(i420_info.biSizeImage == rgb_info->biWidth * rgb_info->biHeight * 3, "Got image size %lu.\n",
+       i420_info.biSizeImage);
+    ok(!i420_info.biXPelsPerMeter, "Got horizontal resolution %ld.\n", i420_info.biXPelsPerMeter);
+    ok(!i420_info.biYPelsPerMeter, "Got vertical resolution %ld.\n", i420_info.biYPelsPerMeter);
+    ok(!i420_info.biClrUsed, "Got %lu used colours.\n", i420_info.biClrUsed);
+    ok(!i420_info.biClrImportant, "Got %lu important colours.\n", i420_info.biClrImportant);
+
+    res = ICCompressQuery(hic, rgb_info, &i420_info);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    res = ICCompressBegin(hic, rgb_info, &i420_info);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    memset(i420_data, 0xcd, sizeof(i420_data));
+    res = ICCompress(hic, ICCOMPRESS_KEYFRAME, &i420_info, i420_data, (BITMAPINFOHEADER *)rgb_info, (void *)rgb_data,
+                     NULL, &flags, 1, 0, 0, NULL, NULL);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+    ok(flags == AVIIF_KEYFRAME, "got flags %#lx\n", flags);
+    ok(i420_info.biSizeImage == sizeof(i420_data), "Got size %ld.\n", i420_info.biSizeImage);
+    res = ICCompressEnd(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+
+    convert_yuv_and_write_bitmap(&i420_info, i420_data, convert_i420_to_bgr32, L"i420frame.bmp");
+
+    resource = FindResourceW(NULL, L"i420frame.bmp", (const WCHAR *)RT_RCDATA);
+    expect_i420_header = ((const struct bmp_header *)LockResource(LoadResource(GetModuleHandleW(NULL), resource)));
+    expect_i420_data = (const BYTE *)((uintptr_t)expect_i420_header + expect_i420_header->length);
+
+    diff = 0;
+    for (unsigned int i = 0; i < i420_info.biSizeImage; ++i)
+        diff += abs((int)i420_data[i] - (int)expect_i420_data[i]);
+    diff = diff * 100 / 256 / i420_info.biSizeImage;
+    ok(diff == 0, "Got %lu%% difference.\n", diff);
+
+skip_compression_tests:
+    res = ICClose(hic);
+    ok(res == ICERR_OK, "Got %ld.\n", res);
+}
+
+START_TEST(iyuv_32)
+{
+    static const DWORD handler[] = {FOURCC_IYUV, FOURCC_I420};
+    BITMAPINFOHEADER in =
+    {
+        .biSize = sizeof(BITMAPINFOHEADER),
+        .biCompression = FOURCC_I420,
+        .biPlanes = 1,
+        .biWidth = 96,
+        .biHeight = 96,
+        .biSizeImage = 96 * 96 * 3 / 2,
+    };
+    HIC hic;
+    int i;
+
+    hic = ICLocate(ICTYPE_VIDEO, FOURCC_I420, &in, NULL, ICMODE_DECOMPRESS);
+    todo_wine
+    ok(!!hic, "Failed to locate iyuv codec\n");
+    if (!hic)
+        return;
+    ICClose(hic);
+
+    for (i = 0; i < ARRAY_SIZE(handler); i++)
+    {
+        winetest_push_context("handler %.4s", (char *)&handler[i]);
+        test_formats(handler[i]);
+        test_decompress(handler[i]);
+        test_compress(handler[i]);
+        winetest_pop_context();
+    }
+}
diff --git a/dlls/iyuv_32/tests/resource.rc b/dlls/iyuv_32/tests/resource.rc
new file mode 100644
index 000000000000..d963e8121055
--- /dev/null
+++ b/dlls/iyuv_32/tests/resource.rc
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2026 Brendan McGrath 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 "windef.h"
+
+/* Generated with: */
+/*  ffmpeg -f lavfi -i pal100bars=size=96x96 \
+ *      -vf transpose -pix_fmt bgr24 -frames:v 1 \
+ *      rgb24frame_flip.bmp */
+/* @makedep: rgb24frame_flip.bmp */
+rgb24frame_flip.bmp RCDATA rgb24frame_flip.bmp
+
+/* Generated by running the compression test on Windows */
+/* @makedep: i420frame.bmp */
+i420frame.bmp RCDATA i420frame.bmp
diff --git a/dlls/iyuv_32/tests/rgb24frame_flip.bmp b/dlls/iyuv_32/tests/rgb24frame_flip.bmp
new file mode 100644
index 0000000000000000000000000000000000000000..7795fcf3989b8bf6594935c15eedf22829f14229
GIT binary patch
literal 27702
zcmeI&F%f_;5Cp)(1rktz0D3$i0RLSG8Hk3j_U8U4nRHv{IQKhW_OZ7y*PJEmIE~Er
z|6&s$K!5-N0t5&UAV7dXrNEOY0RjXF5FkK+009C72owk;O$iVnK!5-N0t5&UAV8o%
zpyg2l1PBlyK!5-N0t5&UC=l@bkN^P!1PBlyK!5-N0t9LVdXEwyK!5-N0t5&UAV7dX
ofk0YQ0t5&UAV7cs0RjXF5GWAnLVy4P0t5&UAV7cs0RklgFIzyKZ~y=R

literal 0
HcmV?d00001

diff --git a/dlls/joy.cpl/dinput.c b/dlls/joy.cpl/dinput.c
index 8838b0ffa1c3..579eccac43a9 100644
--- a/dlls/joy.cpl/dinput.c
+++ b/dlls/joy.cpl/dinput.c
@@ -252,7 +252,7 @@ static BOOL CALLBACK enum_devices( const DIDEVICEINSTANCEW *instance, void *cont
     if (SUCCEEDED(hr)) hr = IDirectInputDevice8_SetDataFormat( entry->device, &c_dfDIJoystick2 );
     if (SUCCEEDED(hr)) hr = IDirectInputDevice8_SetCooperativeLevel( entry->device, GetAncestor( dialog_hwnd, GA_ROOT ),
                                                                      DISCL_BACKGROUND | DISCL_EXCLUSIVE );
-    if (SUCCEEDED(hr)) hr = IDirectInputDevice8_SetProperty( entry->device, DIPROP_AUTOCENTER, &ac_prop.diph );
+    if (SUCCEEDED(hr)) IDirectInputDevice8_SetProperty( entry->device, DIPROP_AUTOCENTER, &ac_prop.diph );
 
     if (SUCCEEDED(hr)) list_add_tail( &devices, &entry->entry );
     else
diff --git a/dlls/kernelbase/kernelbase.rgs b/dlls/kernelbase/kernelbase.rgs
index 0a01ee5580f3..1258f75d6cb7 100644
--- a/dlls/kernelbase/kernelbase.rgs
+++ b/dlls/kernelbase/kernelbase.rgs
@@ -766,7 +766,35 @@ HKLM
                             val 'MUI_Dlt' = s '@tzres.dll,-32129'
                             val 'MUI_Std' = s '@tzres.dll,-32128'
                             val 'Std' = s 'E. Europe Standard Time'
-                            val 'TZI' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                            val 'TZI' = b 88ffffff00000000c4ffffff00000a0000000500040000000000000000000300000005000300000000000000
+                            'Dynamic DST'
+                            {
+                                val '2000' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2001' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2002' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2003' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2004' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2005' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2006' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2007' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2008' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2009' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2010' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2011' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2012' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2013' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2014' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2015' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2016' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2017' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2018' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2019' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2020' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2021' = b 88ffffff00000000c4ffffff00000a0000000500030000000000000000000300000005000200000000000000
+                                val '2022' = b 88ffffff00000000c4ffffff00000a0000000500040000000000000000000300000005000300000000000000
+                                val 'FirstEntry' = d 2000
+                                val 'LastEntry' = d 2022
+                            }
                         }
                         'E. South America Standard Time'
                         {
diff --git a/dlls/kernelbase/memory.c b/dlls/kernelbase/memory.c
index 1dd029169f55..85e596f9d80b 100644
--- a/dlls/kernelbase/memory.c
+++ b/dlls/kernelbase/memory.c
@@ -122,7 +122,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH DiscardVirtualMemory( void *addr, SIZE_T size )
  */
 BOOL WINAPI DECLSPEC_HOTPATCH FlushViewOfFile( const void *base, SIZE_T size )
 {
-    NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, 0 );
+    NTSTATUS status = NtFlushVirtualMemory( GetCurrentProcess(), &base, &size, NULL );
 
     if (status == STATUS_NOT_MAPPED_DATA) status = STATUS_SUCCESS;
     return set_ntstatus( status );
diff --git a/dlls/magnification/magnification.spec b/dlls/magnification/magnification.spec
index 79fcc76add24..07a1509b4dd0 100644
--- a/dlls/magnification/magnification.spec
+++ b/dlls/magnification/magnification.spec
@@ -8,7 +8,7 @@
 @ stub MagGetWindowFilterList
 @ stub MagGetWindowSource
 @ stub MagGetWindowTransform
-@ stub MagInitialize
+@ stdcall MagInitialize()
 @ stub MagSetColorEffect
 @ stub MagSetFullscreenColorEffect
 @ stub MagSetFullscreenTransform
diff --git a/dlls/magnification/main.c b/dlls/magnification/main.c
index 2bd7c8ebc4c3..2ee5081811d6 100644
--- a/dlls/magnification/main.c
+++ b/dlls/magnification/main.c
@@ -25,3 +25,11 @@ BOOL WINAPI MagUninitialize(void)
     FIXME("stub!\n");
     return TRUE;
 }
+
+BOOL WINAPI MagInitialize(void)
+{
+    FIXME("stub!\n");
+
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
diff --git a/dlls/mf/clock.c b/dlls/mf/clock.c
index b13faaf44c97..219ef4384e2a 100644
--- a/dlls/mf/clock.c
+++ b/dlls/mf/clock.c
@@ -1037,7 +1037,9 @@ static ULONG WINAPI present_clock_sink_callback_Release(IMFAsyncCallback *iface)
 
 static HRESULT WINAPI present_clock_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
 {
-    return E_NOTIMPL;
+    *flags = 0;
+    *queue = MFASYNC_CALLBACK_QUEUE_MULTITHREADED;
+    return S_OK;
 }
 
 static HRESULT WINAPI present_clock_sink_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
diff --git a/dlls/mf/main.c b/dlls/mf/main.c
index 537db3174cf3..3aa81f4b454a 100644
--- a/dlls/mf/main.c
+++ b/dlls/mf/main.c
@@ -36,6 +36,189 @@ WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
 
 extern const GUID CLSID_FileSchemePlugin;
 
+struct guid_def
+{
+    const GUID *guid;
+    const char *name;
+};
+
+static int __cdecl debug_compare_guid(const void *a, const void *b)
+{
+    const GUID *guid = a;
+    const struct guid_def *guid_def = b;
+    return memcmp(guid, guid_def->guid, sizeof(*guid));
+}
+
+/* copied from mfplat module */
+const char *debugstr_mf_guid(const GUID *guid)
+{
+    static const struct guid_def guid_defs[] =
+    {
+#define X(g) { &(g), #g }
+        X(MFAudioFormat_ADTS),
+        X(MFAudioFormat_PCM),
+        X(MFAudioFormat_PCM_HDCP),
+        X(MFAudioFormat_Float),
+        X(MFAudioFormat_DTS),
+        X(MFAudioFormat_DRM),
+        X(MFAudioFormat_MSP1),
+        X(MFAudioFormat_Vorbis),
+        X(MFAudioFormat_AAC),
+        X(MFVideoFormat_RGB24),
+        X(MFVideoFormat_ARGB32),
+        X(MFVideoFormat_RGB32),
+        X(MFVideoFormat_RGB565),
+        X(MFVideoFormat_RGB555),
+        X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID),
+        X(MFT_CATEGORY_MULTIPLEXER),
+        X(MFVideoFormat_A2R10G10B10),
+        X(MFT_CATEGORY_VIDEO_EFFECT),
+        X(MFMediaType_Script),
+        X(MFMediaType_Image),
+        X(MFMediaType_HTML),
+        X(MFMediaType_Binary),
+        X(MFVideoFormat_MPEG2),
+        X(MFMediaType_FileTransfer),
+        X(MFVideoFormat_RGB8),
+        X(MFAudioFormat_Dolby_AC3),
+        X(MFVideoFormat_L8),
+        X(MFAudioFormat_LPCM),
+        X(MFVideoFormat_420O),
+        X(MFVideoFormat_AI44),
+        X(MFVideoFormat_AV1),
+        X(MFVideoFormat_AYUV),
+        X(MFVideoFormat_H263),
+        X(MFVideoFormat_H264),
+        X(MFVideoFormat_H265),
+        X(MFVideoFormat_HEVC),
+        X(MFVideoFormat_HEVC_ES),
+        X(MFT_CATEGORY_AUDIO_EFFECT),
+        X(MFVideoFormat_I420),
+        X(MFVideoFormat_IYUV),
+        X(MFT_CATEGORY_VIDEO_DECODER),
+        X(MFVideoFormat_M4S2),
+        X(MFVideoFormat_MJPG),
+        X(MFVideoFormat_MP43),
+        X(MFVideoFormat_MP4S),
+        X(MFVideoFormat_MP4V),
+        X(MFVideoFormat_MPG1),
+        X(MFVideoFormat_MSS1),
+        X(MFVideoFormat_MSS2),
+        X(MFVideoFormat_NV11),
+        X(MFVideoFormat_NV12),
+        X(MFVideoFormat_ORAW),
+        X(MFAudioFormat_Opus),
+        X(MFAudioFormat_MPEG),
+        X(MFVideoFormat_D16),
+        X(MFVideoFormat_P010),
+        X(MFVideoFormat_P016),
+        X(MFVideoFormat_P210),
+        X(MFVideoFormat_P216),
+        X(MFVideoFormat_L16),
+        X(MFAudioFormat_MP3),
+        X(MFVideoFormat_UYVY),
+        X(MFVideoFormat_VP10),
+        X(MFVideoFormat_VP80),
+        X(MFVideoFormat_VP90),
+        X(MFVideoFormat_WMV1),
+        X(MFVideoFormat_WMV2),
+        X(MFVideoFormat_WMV3),
+        X(MFVideoFormat_WVC1),
+        X(MFT_CATEGORY_OTHER),
+        X(MFVideoFormat_Y210),
+        X(MFVideoFormat_Y216),
+        X(MFVideoFormat_Y410),
+        X(MFVideoFormat_Y416),
+        X(MFVideoFormat_Y41P),
+        X(MFVideoFormat_Y41T),
+        X(MFVideoFormat_Y42T),
+        X(MFVideoFormat_YUY2),
+        X(MFVideoFormat_YV12),
+        X(MFVideoFormat_YVU9),
+        X(MFVideoFormat_YVYU),
+        X(MFAudioFormat_WMAudioV8),
+        X(MFAudioFormat_ALAC),
+        X(MFAudioFormat_AMR_NB),
+        X(MFMediaType_Audio),
+        X(MFAudioFormat_WMAudioV9),
+        X(MFAudioFormat_AMR_WB),
+        X(MFAudioFormat_WMAudio_Lossless),
+        X(MFAudioFormat_AMR_WP),
+        X(MFAudioFormat_WMASPDIF),
+        X(MFVideoFormat_DV25),
+        X(MFVideoFormat_DV50),
+        X(MFVideoFormat_DVC),
+        X(MFVideoFormat_DVH1),
+        X(MFVideoFormat_DVHD),
+        X(MFVideoFormat_DVSD),
+        X(MFVideoFormat_DVSL),
+        X(MFVideoFormat_A16B16G16R16F),
+        X(MFVideoFormat_v210),
+        X(MFVideoFormat_v216),
+        X(MFVideoFormat_v410),
+        X(MFMediaType_Video),
+        X(MFAudioFormat_AAC_HDCP),
+        X(MFT_CATEGORY_DEMULTIPLEXER),
+        X(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID),
+        X(MFT_CATEGORY_VIDEO_ENCODER),
+        X(MFAudioFormat_Dolby_AC3_HDCP),
+        X(MFMediaType_Subtitle),
+        X(MFMediaType_Stream),
+        X(MFAudioFormat_Dolby_AC3_SPDIF),
+        X(MFAudioFormat_Float_SpatialObjects),
+        X(MFMediaType_SAMI),
+        X(MFAudioFormat_ADTS_HDCP),
+        X(MFAudioFormat_FLAC),
+        X(MFAudioFormat_Dolby_DDPlus),
+        X(MFMediaType_MultiplexedFrames),
+        X(MFT_CATEGORY_AUDIO_DECODER),
+        X(MFAudioFormat_Base_HDCP),
+        X(MFT_CATEGORY_AUDIO_ENCODER),
+        X(MFVideoFormat_Base_HDCP),
+        X(MFVideoFormat_H264_HDCP),
+        X(MFVideoFormat_HEVC_HDCP),
+        X(MFMediaType_Default),
+        X(MFMediaType_Protected),
+        X(MFVideoFormat_H264_ES),
+        X(MFMediaType_Perception),
+        X(MFT_CATEGORY_VIDEO_PROCESSOR),
+#undef X
+    };
+    struct guid_def *ret = NULL;
+
+    if (guid)
+        ret = bsearch(guid, guid_defs, ARRAY_SIZE(guid_defs), sizeof(*guid_defs), debug_compare_guid);
+
+    return ret ? wine_dbg_sprintf("%s", ret->name) : wine_dbgstr_guid(guid);
+}
+
+const char *debugstr_media_type(IMFMediaType *media_type)
+{
+    UINT channels, sps;
+    GUID subtype = {0};
+    UINT64 frame_size;
+
+    if (!media_type)
+        return "{null}";
+
+    IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
+
+    if (SUCCEEDED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)) && frame_size)
+    {
+        return wine_dbg_sprintf("{%p %s %ux%u}", media_type, debugstr_mf_guid(&subtype), (UINT)(frame_size >> 32), (UINT32)frame_size);
+    }
+    else if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, &channels)) && channels)
+    {
+        if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &sps)))
+            return wine_dbg_sprintf("{%p %s %u-ch %u}", media_type, debugstr_mf_guid(&subtype), channels, sps);
+        return wine_dbg_sprintf("{%p %s %u-ch}", media_type, debugstr_mf_guid(&subtype), channels);
+    }
+    else
+    {
+        return wine_dbg_sprintf("{%p %s ?}", media_type, debugstr_mf_guid(&subtype));
+    }
+}
+
 struct activate_object
 {
     IMFActivate IMFActivate_iface;
@@ -772,6 +955,18 @@ HRESULT WINAPI MFEnumDeviceSources(IMFAttributes *attributes, IMFActivate ***sou
     return E_INVALIDARG;
 }
 
+/***********************************************************************
+ *      MFCreateDeviceSource (mf.@)
+ */
+HRESULT WINAPI MFCreateDeviceSource(IMFAttributes *attributes, IMFMediaSource **source)
+{
+    FIXME("%p %p: stub!\n", attributes, source);
+
+    if (!attributes || !source) return E_INVALIDARG;
+    *source = NULL;
+    return E_NOTIMPL;
+}
+
 struct simple_type_handler
 {
     IMFMediaTypeHandler IMFMediaTypeHandler_iface;
diff --git a/dlls/mf/mf.spec b/dlls/mf/mf.spec
index de607f1d3222..2b5b088f2f5f 100644
--- a/dlls/mf/mf.spec
+++ b/dlls/mf/mf.spec
@@ -30,7 +30,7 @@
 @ stub MFCreateByteCacheFile
 @ stub MFCreateCacheManager
 @ stub MFCreateCredentialCache
-@ stub MFCreateDeviceSource
+@ stdcall MFCreateDeviceSource(ptr ptr)
 @ stub MFCreateDeviceSourceActivate
 @ stub MFCreateDrmNetNDSchemePlugin
 @ stub MFCreateFileBlockMap
diff --git a/dlls/mf/mf_private.h b/dlls/mf/mf_private.h
index 1f2ef17a8c9f..0658db1de15c 100644
--- a/dlls/mf/mf_private.h
+++ b/dlls/mf/mf_private.h
@@ -113,12 +113,15 @@ static inline const char *debugstr_propvar(const PROPVARIANT *v)
     }
 }
 
+extern const char *debugstr_media_type(IMFMediaType *media_type);
+
 extern HRESULT file_scheme_handler_construct(REFIID riid, void **obj);
 extern HRESULT urlmon_scheme_handler_construct(REFIID riid, void **obj);
 
 extern BOOL mf_is_sample_copier_transform(IMFTransform *transform);
 extern BOOL mf_is_sar_sink(IMFMediaSink *sink);
 extern HRESULT create_topology(TOPOID id, IMFTopology **topology);
+extern MF_TOPOLOGY_TYPE topology_node_get_type(IMFTopologyNode *node);
 extern HRESULT topology_node_get_object(IMFTopologyNode *node, REFIID riid, void **obj);
 extern HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaTypeHandler **handler);
 extern HRESULT topology_node_init_media_type(IMFTopologyNode *node, DWORD stream, BOOL output, IMFMediaType **type);
diff --git a/dlls/mf/samplegrabber.c b/dlls/mf/samplegrabber.c
index 09ea06f39ebf..5f2c28d254b3 100644
--- a/dlls/mf/samplegrabber.c
+++ b/dlls/mf/samplegrabber.c
@@ -729,7 +729,9 @@ static ULONG WINAPI sample_grabber_stream_timer_callback_Release(IMFAsyncCallbac
 static HRESULT WINAPI sample_grabber_stream_timer_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags,
         DWORD *queue)
 {
-    return E_NOTIMPL;
+    *flags = 0;
+    *queue = MFASYNC_CALLBACK_QUEUE_MULTITHREADED;
+    return S_OK;
 }
 
 static HRESULT WINAPI sample_grabber_stream_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
diff --git a/dlls/mf/session.c b/dlls/mf/session.c
index e6407934fddc..db837c369d7d 100644
--- a/dlls/mf/session.c
+++ b/dlls/mf/session.c
@@ -567,7 +567,6 @@ static void session_set_topo_status(struct media_session *session, HRESULT statu
 
 static HRESULT session_bind_output_nodes(IMFTopology *topology)
 {
-    MF_TOPOLOGY_TYPE node_type;
     IMFStreamSink *stream_sink;
     IMFMediaSink *media_sink;
     WORD node_count = 0, i;
@@ -584,7 +583,7 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
         if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
             break;
 
-        if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)) || node_type != MF_TOPOLOGY_OUTPUT_NODE)
+        if (topology_node_get_type(node) != MF_TOPOLOGY_OUTPUT_NODE)
         {
             IMFTopologyNode_Release(node);
             continue;
@@ -632,7 +631,6 @@ static HRESULT session_bind_output_nodes(IMFTopology *topology)
 
 static HRESULT session_init_media_types(IMFTopology *topology)
 {
-    MF_TOPOLOGY_TYPE node_type;
     WORD node_count, i, j;
     IMFTopologyNode *node;
     IMFMediaType *type;
@@ -648,8 +646,7 @@ static HRESULT session_init_media_types(IMFTopology *topology)
             break;
 
         if (FAILED(hr = IMFTopologyNode_GetInputCount(node, &input_count))
-                || FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type))
-                || node_type != MF_TOPOLOGY_OUTPUT_NODE)
+                || topology_node_get_type(node) != MF_TOPOLOGY_OUTPUT_NODE)
         {
             IMFTopologyNode_Release(node);
             continue;
@@ -827,7 +824,6 @@ static void release_topo_node(struct topo_node *node)
 static void session_shutdown_current_topology(struct media_session *session)
 {
     unsigned int shutdown, force_shutdown;
-    MF_TOPOLOGY_TYPE node_type;
     IMFStreamSink *stream_sink;
     IMFTopology *topology;
     IMFTopologyNode *node;
@@ -843,8 +839,7 @@ static void session_shutdown_current_topology(struct media_session *session)
 
     while (SUCCEEDED(IMFTopology_GetNode(topology, idx++, &node)))
     {
-        if (SUCCEEDED(IMFTopologyNode_GetNodeType(node, &node_type)) &&
-                node_type == MF_TOPOLOGY_OUTPUT_NODE)
+        if (topology_node_get_type(node) == MF_TOPOLOGY_OUTPUT_NODE)
         {
             shutdown = 1;
             IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_NOSHUTDOWN_ON_REMOVE, &shutdown);
@@ -1888,7 +1883,6 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod
     if (!(topo_node = calloc(1, sizeof(*topo_node))))
         return E_OUTOFMEMORY;
 
-    IMFTopologyNode_GetNodeType(node, &topo_node->type);
     IMFTopologyNode_GetTopoNodeID(node, &topo_node->node_id);
     topo_node->node = node;
     IMFTopologyNode_AddRef(topo_node->node);
@@ -1896,7 +1890,7 @@ static HRESULT session_append_node(struct media_session *session, IMFTopologyNod
     if (SUCCEEDED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_MARKIN_HERE, &value)) && value)
         topo_node->flags |= TOPO_NODE_MARKIN_HERE;
 
-    switch (topo_node->type)
+    switch ((topo_node->type = topology_node_get_type(node)))
     {
         case MF_TOPOLOGY_OUTPUT_NODE:
             topo_node->u.sink.notify_cb.lpVtbl = &node_sample_allocator_cb_vtbl;
@@ -2338,7 +2332,6 @@ static HRESULT session_check_stream_descriptor(IMFPresentationDescriptor *pd, IM
 
 static HRESULT session_check_topology(IMFTopology *topology)
 {
-    MF_TOPOLOGY_TYPE node_type;
     IMFTopologyNode *node;
     WORD node_count, i;
     HRESULT hr;
@@ -2355,13 +2348,7 @@ static HRESULT session_check_topology(IMFTopology *topology)
         if (FAILED(hr = IMFTopology_GetNode(topology, i, &node)))
             break;
 
-        if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)))
-        {
-            IMFTopologyNode_Release(node);
-            break;
-        }
-
-        switch (node_type)
+        switch (topology_node_get_type(node))
         {
             case MF_TOPOLOGY_SOURCESTREAM_NODE:
             {
diff --git a/dlls/mf/topology.c b/dlls/mf/topology.c
index 572d4d426d39..48df8a6ec8b7 100644
--- a/dlls/mf/topology.c
+++ b/dlls/mf/topology.c
@@ -1645,7 +1645,6 @@ static HRESULT WINAPI topology_node_GetInputPrefType(IMFTopologyNode *iface, DWO
 static HRESULT WINAPI topology_node_CloneFrom(IMFTopologyNode *iface, IMFTopologyNode *src_node)
 {
     struct topology_node *node = impl_from_IMFTopologyNode(iface);
-    MF_TOPOLOGY_TYPE node_type;
     IMFMediaType *mediatype;
     IUnknown *object;
     DWORD count, i;
@@ -1654,10 +1653,7 @@ static HRESULT WINAPI topology_node_CloneFrom(IMFTopologyNode *iface, IMFTopolog
 
     TRACE("%p, %p.\n", iface, src_node);
 
-    if (FAILED(hr = IMFTopologyNode_GetNodeType(src_node, &node_type)))
-        return hr;
-
-    if (node->node_type != node_type)
+    if (node->node_type != topology_node_get_type(src_node))
         return MF_E_INVALIDREQUEST;
 
     if (FAILED(hr = IMFTopologyNode_GetTopoNodeID(src_node, &topoid)))
@@ -1783,6 +1779,20 @@ static HRESULT create_topology_node(MF_TOPOLOGY_TYPE node_type, struct topology_
     return S_OK;
 }
 
+MF_TOPOLOGY_TYPE topology_node_get_type(IMFTopologyNode *node)
+{
+    MF_TOPOLOGY_TYPE type;
+    HRESULT hr;
+
+    if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &type)))
+    {
+        ERR("Failed to get node type, hr %#lx.\n", hr);
+        return -1;
+    }
+
+    return type;
+}
+
 HRESULT topology_node_get_object(IMFTopologyNode *node, REFIID riid, void **obj)
 {
     IUnknown *unk;
@@ -2013,10 +2023,7 @@ HRESULT topology_node_get_type_handler(IMFTopologyNode *node, DWORD stream,
     IMFTransform *transform;
     HRESULT hr;
 
-    if (FAILED(hr = IMFTopologyNode_GetNodeType(node, &node_type)))
-        return hr;
-
-    switch (node_type)
+    switch ((node_type = topology_node_get_type(node)))
     {
         case MF_TOPOLOGY_OUTPUT_NODE:
             if (output || stream)
diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c
index 012e519af8a5..05f999fcaec0 100644
--- a/dlls/mf/topology_loader.c
+++ b/dlls/mf/topology_loader.c
@@ -92,7 +92,6 @@ struct topoloader_context
 
 static HRESULT topology_loader_clone_node(struct topoloader_context *context, IMFTopologyNode *node, IMFTopologyNode **clone)
 {
-    MF_TOPOLOGY_TYPE node_type;
     HRESULT hr;
     TOPOID id;
 
@@ -100,9 +99,7 @@ static HRESULT topology_loader_clone_node(struct topoloader_context *context, IM
         return hr;
     if (SUCCEEDED(hr = IMFTopology_GetNodeByID(context->output_topology, id, clone)))
         return hr;
-
-    IMFTopologyNode_GetNodeType(node, &node_type);
-    if (FAILED(hr = MFCreateTopologyNode(node_type, clone)))
+    if (FAILED(hr = MFCreateTopologyNode(topology_node_get_type(node), clone)))
         return hr;
 
     hr = IMFTopologyNode_CloneFrom(*clone, node);
@@ -124,18 +121,6 @@ struct transform_output_type
     IMFActivate *activate;
 };
 
-struct connect_context
-{
-    struct topoloader_context *context;
-    IMFTopologyNode *upstream_node;
-    IMFTopologyNode *sink;
-    IMFMediaTypeHandler *sink_handler;
-    unsigned int output_index;
-    unsigned int input_index;
-    GUID converter_category;
-    GUID decoder_category;
-};
-
 struct topology_branch
 {
     struct
@@ -147,9 +132,23 @@ struct topology_branch
     struct list entry;
 };
 
+static const char *debugstr_topology_type(MF_TOPOLOGY_TYPE type)
+{
+    switch (type)
+    {
+        case MF_TOPOLOGY_OUTPUT_NODE: return "sink";
+        case MF_TOPOLOGY_SOURCESTREAM_NODE: return "source";
+        case MF_TOPOLOGY_TRANSFORM_NODE: return "transform";
+        case MF_TOPOLOGY_TEE_NODE: return "tee";
+        default: return "unknown";
+    }
+}
+
 static const char *debugstr_topology_branch(struct topology_branch *branch)
 {
-    return wine_dbg_sprintf("%p:%lu to %p:%lu", branch->up.node, branch->up.stream, branch->down.node, branch->down.stream);
+    return wine_dbg_sprintf("%s %p:%lu to %s %p:%lu", debugstr_topology_type(topology_node_get_type(branch->up.node)),
+            branch->up.node, branch->up.stream, debugstr_topology_type(topology_node_get_type(branch->down.node)),
+            branch->down.node, branch->down.stream);
 }
 
 static HRESULT topology_branch_create(IMFTopologyNode *source, DWORD source_stream,
@@ -282,8 +281,8 @@ static HRESULT topology_branch_connect_indirect(IMFTopology *topology, MF_CONNEC
     GUID category, guid;
     HRESULT hr;
 
-    TRACE("topology %p, method_mask %#x, branch %s, up_type %p, down_type %p.\n",
-            topology, method_mask, debugstr_topology_branch(branch), up_type, down_type);
+    TRACE("topology %p, method_mask %#x, branch %s, up_type %s, down_type %s.\n", topology, method_mask,
+            debugstr_topology_branch(branch), debugstr_media_type(up_type), debugstr_media_type(down_type));
 
     if (FAILED(hr = IMFMediaType_GetMajorType(up_type, &input_info.guidMajorType)))
         return hr;
@@ -417,13 +416,12 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME
 {
     IMFMediaTypeHandler *down_handler;
     IMFMediaType *down_type = NULL;
-    MF_TOPOLOGY_TYPE type;
     UINT32 method;
     DWORD flags;
     HRESULT hr;
 
-    TRACE("topology %p, method_mask %#x, branch %s, up_type %p.\n",
-            topology, method_mask, debugstr_topology_branch(branch), up_type);
+    TRACE("topology %p, method_mask %#x, branch %s, up_type %s.\n",
+            topology, method_mask, debugstr_topology_branch(branch), debugstr_media_type(up_type));
 
     if (FAILED(IMFTopologyNode_GetUINT32(branch->down.node, &MF_TOPONODE_CONNECT_METHOD, &method)))
         method = MF_CONNECT_ALLOW_DECODER;
@@ -434,16 +432,16 @@ static HRESULT topology_branch_connect_down(IMFTopology *topology, MF_CONNECT_ME
     if (SUCCEEDED(hr = get_first_supported_media_type(down_handler, &down_type))
             && IMFMediaType_IsEqual(up_type, down_type, &flags) == S_OK)
     {
-        TRACE("Connecting branch %s with current type %p.\n", debugstr_topology_branch(branch), up_type);
+        TRACE("Connecting branch %s with current type %s.\n", debugstr_topology_branch(branch), debugstr_media_type(up_type));
         hr = IMFTopologyNode_ConnectOutput(branch->up.node, branch->up.stream, branch->down.node, branch->down.stream);
         goto done;
     }
 
     if (SUCCEEDED(hr = IMFMediaTypeHandler_IsMediaTypeSupported(down_handler, up_type, NULL)))
     {
-        TRACE("Connected branch %s with upstream type %p.\n", debugstr_topology_branch(branch), up_type);
+        TRACE("Connected branch %s with upstream type %s.\n", debugstr_topology_branch(branch), debugstr_media_type(up_type));
 
-        if (SUCCEEDED(IMFTopologyNode_GetNodeType(branch->down.node, &type)) && type == MF_TOPOLOGY_TRANSFORM_NODE
+        if (topology_node_get_type(branch->down.node) == MF_TOPOLOGY_TRANSFORM_NODE
                 && FAILED(hr = IMFMediaTypeHandler_SetCurrentMediaType(down_handler, up_type)))
             WARN("Failed to set transform node media type, hr %#lx\n", hr);
 
@@ -496,16 +494,18 @@ static HRESULT topology_branch_foreach_up_types(IMFTopology *topology, MF_CONNEC
 static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD method_mask,
         struct topology_branch *branch, BOOL enumerate_source_types)
 {
-    UINT32 method;
     HRESULT hr;
 
     TRACE("topology %p, method_mask %#x, branch %s.\n", topology, method_mask, debugstr_topology_branch(branch));
 
-    if (FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &method)))
-        method = MF_CONNECT_DIRECT;
-
     if (enumerate_source_types)
     {
+        UINT32 method;
+
+        if (topology_node_get_type(branch->up.node) != MF_TOPOLOGY_SOURCESTREAM_NODE
+                || FAILED(IMFTopologyNode_GetUINT32(branch->up.node, &MF_TOPONODE_CONNECT_METHOD, &method)))
+            method = MF_CONNECT_DIRECT;
+
         if (method & MF_CONNECT_RESOLVE_INDEPENDENT_OUTPUTTYPES)
             hr = topology_branch_foreach_up_types(topology, method_mask & MF_CONNECT_ALLOW_DECODER, branch);
         else
@@ -540,25 +540,19 @@ static HRESULT topology_branch_connect(IMFTopology *topology, MF_CONNECT_METHOD
 static HRESULT topology_loader_resolve_branches(struct topoloader_context *context, struct list *branches,
         BOOL enumerate_source_types)
 {
-    struct list new_branches = LIST_INIT(new_branches);
     struct topology_branch *branch, *next;
-    MF_TOPOLOGY_TYPE node_type;
     HRESULT hr = S_OK;
 
     LIST_FOR_EACH_ENTRY_SAFE(branch, next, branches, struct topology_branch, entry)
     {
         list_remove(&branch->entry);
 
-        if (FAILED(hr = topology_node_list_branches(branch->down.node, &new_branches)))
-            WARN("Failed to list branches from branch %s\n", debugstr_topology_branch(branch));
-        else if (FAILED(hr = IMFTopologyNode_GetNodeType(branch->up.node, &node_type)))
-            WARN("Failed to get source node type for branch %s\n", debugstr_topology_branch(branch));
-        else if (FAILED(hr = topology_branch_clone_nodes(context, branch)))
+        if (FAILED(hr = topology_branch_clone_nodes(context, branch)))
             WARN("Failed to clone nodes for branch %s\n", debugstr_topology_branch(branch));
         else
         {
             hr = topology_branch_connect(context->output_topology, MF_CONNECT_ALLOW_DECODER, branch, enumerate_source_types);
-            if (hr == MF_E_INVALIDMEDIATYPE && !enumerate_source_types && node_type == MF_TOPOLOGY_TRANSFORM_NODE)
+            if (hr == MF_E_INVALIDMEDIATYPE && !enumerate_source_types && topology_node_get_type(branch->up.node) == MF_TOPOLOGY_TRANSFORM_NODE)
                 hr = topology_branch_connect(context->output_topology, MF_CONNECT_ALLOW_DECODER, branch, TRUE);
         }
 
@@ -567,7 +561,6 @@ static HRESULT topology_loader_resolve_branches(struct topoloader_context *conte
             break;
     }
 
-    list_move_tail(branches, &new_branches);
     return hr;
 }
 
@@ -757,7 +750,6 @@ static HRESULT topology_loader_connect_d3d_aware_sink(struct topoloader_context
 static void topology_loader_resolve_complete(struct topoloader_context *context)
 {
     MFTOPOLOGY_DXVA_MODE dxva_mode;
-    MF_TOPOLOGY_TYPE node_type;
     IMFTopologyNode *node;
     WORD i, node_count;
     HRESULT hr;
@@ -771,22 +763,23 @@ static void topology_loader_resolve_complete(struct topoloader_context *context)
     {
         if (SUCCEEDED(IMFTopology_GetNode(context->output_topology, i, &node)))
         {
-            IMFTopologyNode_GetNodeType(node, &node_type);
-
-            if (node_type == MF_TOPOLOGY_OUTPUT_NODE)
+            switch (topology_node_get_type(node))
             {
-                /* Set MF_TOPONODE_STREAMID for all outputs. */
-                if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL)))
-                    IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0);
-
-                if (FAILED(hr = topology_loader_connect_d3d_aware_sink(context, node, dxva_mode)))
-                    WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr);
-            }
-            else if (node_type == MF_TOPOLOGY_SOURCESTREAM_NODE)
-            {
-                /* Set MF_TOPONODE_MEDIASTART for all sources. */
-                if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_MEDIASTART, NULL)))
-                    IMFTopologyNode_SetUINT64(node, &MF_TOPONODE_MEDIASTART, 0);
+                case MF_TOPOLOGY_OUTPUT_NODE:
+                    /* Set MF_TOPONODE_STREAMID for all outputs. */
+                    if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_STREAMID, NULL)))
+                        IMFTopologyNode_SetUINT32(node, &MF_TOPONODE_STREAMID, 0);
+
+                    if (FAILED(hr = topology_loader_connect_d3d_aware_sink(context, node, dxva_mode)))
+                        WARN("Failed to connect D3D-aware input, hr %#lx.\n", hr);
+                    break;
+                case MF_TOPOLOGY_SOURCESTREAM_NODE:
+                    /* Set MF_TOPONODE_MEDIASTART for all sources. */
+                    if (FAILED(IMFTopologyNode_GetItem(node, &MF_TOPONODE_MEDIASTART, NULL)))
+                        IMFTopologyNode_SetUINT64(node, &MF_TOPONODE_MEDIASTART, 0);
+                    break;
+                default:
+                    ;
             }
 
             IMFTopologyNode_Release(node);
@@ -802,7 +795,6 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
     struct topology_branch *branch, *next;
     UINT32 enumerate_source_types;
     IMFTopology *output_topology;
-    MF_TOPOLOGY_TYPE node_type;
     IMFTopologyNode *node;
     unsigned short i = 0;
     IMFStreamSink *sink;
@@ -823,9 +815,7 @@ static HRESULT WINAPI topology_loader_Load(IMFTopoLoader *iface, IMFTopology *in
     */
     while (SUCCEEDED(IMFTopology_GetNode(input_topology, i++, &node)))
     {
-        IMFTopologyNode_GetNodeType(node, &node_type);
-
-        switch (node_type)
+        switch (topology_node_get_type(node))
         {
             case MF_TOPOLOGY_OUTPUT_NODE:
                 if (SUCCEEDED(hr = IMFTopologyNode_GetObject(node, &object)))
diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index 01d9d2ddd898..da9dce416ba9 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -9501,3 +9501,21 @@ HRESULT WINAPI MFCreatePathFromURL(const WCHAR *url, WCHAR **ret_path)
     memcpy(*ret_path, path, (length + 1) * sizeof(*path));
     return S_OK;
 }
+
+/***********************************************************************
+ *      MFSerializeAttributesToStream (mfplat.@)
+ */
+HRESULT WINAPI MFSerializeAttributesToStream(IMFAttributes *attr, DWORD options, IStream *stream)
+{
+    FIXME("%p %lx %p: stub!\n", attr, options, stream);
+    return E_NOTIMPL;
+}
+
+/***********************************************************************
+ *      MFDeserializeAttributesFromStream (mfplat.@)
+ */
+HRESULT WINAPI MFDeserializeAttributesFromStream(IMFAttributes *attr, DWORD options, IStream *stream)
+{
+    FIXME("%p %lx %p: stub!\n", attr, options, stream);
+    return E_NOTIMPL;
+}
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec
index 7b356f9f4579..229230cd8992 100644
--- a/dlls/mfplat/mfplat.spec
+++ b/dlls/mfplat/mfplat.spec
@@ -84,7 +84,7 @@
 @ stdcall MFCreateVideoMediaTypeFromVideoInfoHeader(ptr long long long long int64 ptr ptr)
 @ stdcall MFCreateVideoSampleAllocatorEx(ptr ptr)
 @ stdcall MFCreateWaveFormatExFromMFMediaType(ptr ptr ptr long)
-@ stub MFDeserializeAttributesFromStream
+@ stdcall MFDeserializeAttributesFromStream(ptr long ptr)
 @ stub MFDeserializeEvent
 @ stub MFDeserializeMediaTypeFromStream
 @ stub MFDeserializePresentationDescriptor
@@ -149,7 +149,7 @@
 @ stdcall MFRemovePeriodicCallback(long) rtworkq.RtwqRemovePeriodicCallback
 @ stdcall MFScheduleWorkItem(ptr ptr int64 ptr)
 @ stdcall MFScheduleWorkItemEx(ptr int64 ptr) rtworkq.RtwqScheduleWorkItem
-@ stub MFSerializeAttributesToStream
+@ stdcall MFSerializeAttributesToStream(ptr long ptr)
 @ stub MFSerializeEvent
 @ stub MFSerializeMediaTypeToStream
 @ stub MFSerializePresentationDescriptor
diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c
index cc7b090d0745..af44a074ea75 100644
--- a/dlls/mfsrcsnk/tests/mfsrcsnk.c
+++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c
@@ -831,6 +831,88 @@ static void test_thinning(void)
     IMFMediaSource_Release(source);
 }
 
+static void test_mp4_extra_metadata(void)
+{
+    IMFPresentationDescriptor *presentation_descriptor;
+    IMFStreamDescriptor *stream_descriptor;
+    IMFMediaTypeHandler *type_handler;
+    IMFMediaType *media_type;
+    IMFMediaSource *source;
+    IMFByteStream *stream;
+    DWORD stream_count;
+    UINT64 value64;
+    BOOL selected;
+    HRESULT hr;
+
+    /* Some metadata are duplicated at multiple levels in a mp4. Notably, the pixel aspect ratio
+     * is defined in both: 1) the pasp atom, and 2) the avcC atom.
+     * This test checks how they are treated by the byte stream handler. For example: are they both
+     * parsed? Which one takes precedence if both are present? */
+
+    /* 1. has no pasp atom. Aspect ratio set to 3:4 in the SPS contained by the avcC atom. */
+    stream = create_resource_byte_stream(L"test_metadata.mp4");
+    hr = create_source(&CLSID_MPEG4ByteStreamHandlerPlugin, stream, &source);
+    IMFByteStream_Release(stream);
+
+    if (FAILED(hr))
+    {
+        win_skip("Failed to create MPEG4 source: %#lx.\n", hr);
+        return;
+    }
+
+    hr = IMFMediaSource_CreatePresentationDescriptor(source, &presentation_descriptor);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IMFPresentationDescriptor_GetStreamDescriptorCount(presentation_descriptor, &stream_count);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(stream_count == 1, "Unexpected stream count %lu.\n", stream_count);
+    hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(presentation_descriptor, 0, &selected, &stream_descriptor);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IMFStreamDescriptor_GetMediaTypeHandler(stream_descriptor, &type_handler);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IMFMediaTypeHandler_GetCurrentMediaType(type_handler, &media_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    value64 = 0xdeadbeef;
+    hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64);
+    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine ok(value64 == 0x300000004, "Unexpected aspect ratio %#I64x.\n", value64);
+    IMFMediaType_Release(media_type);
+    IMFMediaTypeHandler_Release(type_handler);
+    IMFStreamDescriptor_Release(stream_descriptor);
+    IMFPresentationDescriptor_Release(presentation_descriptor);
+    hr = IMFMediaSource_Shutdown(source);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IMFMediaSource_Release(source);
+
+    /* 2. has pasp atom. Aspect ratio set to 3:4 in the SPS, and 15:16 in the pasp. */
+    stream = create_resource_byte_stream(L"test_metadata2.mp4");
+    hr = create_source(&CLSID_MPEG4ByteStreamHandlerPlugin, stream, &source);
+    IMFByteStream_Release(stream);
+
+    hr = IMFMediaSource_CreatePresentationDescriptor(source, &presentation_descriptor);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IMFPresentationDescriptor_GetStreamDescriptorCount(presentation_descriptor, &stream_count);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(stream_count == 1, "Unexpected stream count %lu.\n", stream_count);
+    hr = IMFPresentationDescriptor_GetStreamDescriptorByIndex(presentation_descriptor, 0, &selected, &stream_descriptor);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IMFStreamDescriptor_GetMediaTypeHandler(stream_descriptor, &type_handler);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IMFMediaTypeHandler_GetCurrentMediaType(type_handler, &media_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    value64 = 0xdeadbeef;
+    hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64);
+    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    /* pasp takes precedence */
+    todo_wine ok(value64 == 0xf00000010, "Unexpected aspect ratio: %#I64x.\n", value64);
+    IMFMediaType_Release(media_type);
+    IMFMediaTypeHandler_Release(type_handler);
+    IMFStreamDescriptor_Release(stream_descriptor);
+    IMFPresentationDescriptor_Release(presentation_descriptor);
+    hr = IMFMediaSource_Shutdown(source);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IMFMediaSource_Release(source);
+}
+
 static void test_end_of_presentation(void)
 {
     IMFPresentationDescriptor *pd;
@@ -960,6 +1042,7 @@ START_TEST(mfsrcsnk)
 
     test_wave_sink();
     test_thinning();
+    test_mp4_extra_metadata();
     test_end_of_presentation();
     test_release();
 
diff --git a/dlls/mfsrcsnk/tests/resource.rc b/dlls/mfsrcsnk/tests/resource.rc
index 7b3a6532f0a3..89d92ea32413 100644
--- a/dlls/mfsrcsnk/tests/resource.rc
+++ b/dlls/mfsrcsnk/tests/resource.rc
@@ -29,3 +29,18 @@
  */
 /* @makedep: test_thinning.avi */
 test_thinning.avi RCDATA test_thinning.avi
+
+/* Generated with:
+  ffmpeg -filter_complex "smptebars=s=64x64[vout]" -map "[vout]" -t 0.25 -r 25 -vcodec h264 \
+  -brand mp42 -aspect 3:4 -an test.mp4
+
+  Then, manually remove the pasp atom from the generated mp4 file.
+ */
+/* @makedep: test_metadata.mp4 */
+test_metadata.mp4 RCDATA test_metadata.mp4
+
+/* Same as above, but instead of removing the pasp, it's modify to have an aspect ratio of 15:16
+ * (it was 3:4 originally)
+ */
+/* @makedep: test_metadata2.mp4 */
+test_metadata2.mp4 RCDATA test_metadata2.mp4
diff --git a/dlls/mfsrcsnk/tests/test_metadata.mp4 b/dlls/mfsrcsnk/tests/test_metadata.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..9619569ed4b554a0c8a98bfef25a02c0fb1d73d1
GIT binary patch
literal 1832
zcmZWqdu$X%7@y;yR#GJaq=>Z)71RK|?ruvd#kIYbS`aFf2E<^p%<j(JZEyE>yF2aO
zAwp3TKq5hmAV{Es7$gKM#`mkB@DBw-K%|0CUPV;+!-PbH^P6i=N}0>f_xpa|YrdJ?
zIfM`nv7}=;B@#jd5SNB$OQb~;0gDI?oMP#OA%wEyhEBn!Eo)FJwfRiVr7tgZP5*fP
z#8bHIp}(#qq|y>xh&9`#SWLs|0icTN=G4>{mf+z0YOv{41D|T!Nt!goup|h@g_0mm
z0y4swQ(jaQkH-ToP{%e&EMU9gBAz!8VU`I#w!;iN=9OcOs6>-R?9z~2jCHD-wicDe
za-m$nBu31nM`a;VTrMO;u^3xaj?e`5npHrPvEwBn6lTTMWicQ?5KP!I5>!`sMiC+u
zm&C$U7E7@faczqz5GrEkQqwd%KxK(CU1I>WCQBAz2}ECP$EYlc6Gah+h{qJiiy991
z=t<DzD0V31Q6?8km_=NO@MH;_wjCuAP?QWOV$U=*SWAWwaLi5D&<u+(z78YCsB02%
z0$w$nU6NEZ+j0m4U4t!RE-_+|0vuh!eL^m=s0W*+Dozrxp+jv|Av$q*7pkHf#N$N_
zm!|uQQzIN<D%fm?#+0z_fVGEoAT&yokXx1}3B6FUj2Nic(`bxp%}g#4_%dC>x74Lx
z1j1cS`M+ImcQsjaL)cPbUwK=g$Wn1Yz)idvSqPK@ba>*lBni263J@Nnj$DEb2M!5d
z2slH?MVjFJ`Dvn7gnSir<xA-4<8M!pSKJiFZ)}~jG&Rzy(boD`9Qo>(v(GIUaiIO$
zl4a{(*wJxc_tx&0TeH!*gTcC+X9k<Y=3JU|U`g?;2d$~^j``kqX!p#a=RXPPqvP9Z
zx7R<W9w|In-JH^PsZ|#ns=VV*y)xoP{lSVwW`1YGn@+{1j&<9tb+0vi@k~Kkr_z4c
zY}B>m(SHhlII!xo!(-mK=XCDQ-1FzQH~tj9aB=UD6aL!M)%)w791_2r*YJCO{x^%H
zRN>F>4f}k<xO{2Fo@4tf!awF1uipQFZ$#6E+4cwZug~~y^QZ|s?X9aD+^or6<JvnP
zueq}I^xDH}Yj?Z9eD%^L`$F%}`}*%wxmWh>-Jy?v>xll2oi{hPt8r@O!WU0A&NMI0
zPx(Lk^UUzN>-B%^YJ0x)=&_S+HwMjnWdF(&A8z<}Sd_36ox$r*EL+Y$_u!_nX6>@<
z>@?m|l~|LS8|2uxg|Mp83o3iC)(DvM_Xao789RfKjkB_=Q+Iy~7sXM_wp+krS}hSB
zWS`;h2IVU9!BO>LZ&$!@n-QVPzP@*2@E))b-nb~3o@LQ=&Au5j_-fzKG?}qv4E^*<
z&hv>s$al@s4FUjLdjG!Q4n;X=-nZNjjfv={n?^A4OD%(YrEd?s+96Pew^;oXp|N_8
zEl-E<CldfNr`a_zNLZo|zH`+Cyv1W)W`p_C*YMjLBp>}+0j3gu(?Rlwk2^hj_*?VH
zR0@<b$Xe~w(csjtXml9l?yhMMr#euFZ`5+%fHs8u2qTmg{B7Fa4j;;jTt0iKpabGY
zdW?A>`QWv(`2P%yO6?X89JdYRJjlVlGNW^q^Xa&Z-*D)<Z(iV09&lRPyQdcCdUK<R
cU|Za4;{tg9MUXlDo}r*aZp{YC2hSn=2bx&sKmY&$

literal 0
HcmV?d00001

diff --git a/dlls/mfsrcsnk/tests/test_metadata2.mp4 b/dlls/mfsrcsnk/tests/test_metadata2.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..be4f6a7eb1d47721751982331bd32c22de128465
GIT binary patch
literal 1848
zcmZWpZEO@p7@q4vsicYlq=>Z)2x@>{cekaK;@VzIEeI7#17b8;W_RcAwzqq`-JSOC
z5TU3EAkiR35F}7R3=)DB<F{f#;SU8vK%|1A@>N8IA0{RuobOzFQp#Lrp67kukNMgg
zgb)s~q+>ZH5<*#sqv6>SY0*UBB0>YES~_6}p`5s(Q;2EH9+*mPI$d+=%L`pIK3+HJ
zB<_0P&npS3v;-Go&2}jk({x4vq@udHHMNB$IJlr1d^*)2rrLIrCJiwx2|{t9BuJA%
zj4<Yu7Zt_h@jwgAW1A!vu-$MGuN#Ok%Y+!)VTK*^%CSaNqRAq5X-F={I#o?ui^^iT
zP%dB+BWBX0vXCe)7ZRdaj4dihXaal9DzGWo@sf}VqvGna7!V){25cD#sw=#r2pNh?
zVqq$arC5u&wnY?36)|(EX&N4|vP7A#F(6u#B@3_wqA#{%RF=d^qKHGpV~XQN4Tnec
z6lii3I~4LLlM5xxA}(ZjvV=|Bj*<u%N=6g0XBrx;B_jwp=BDS+42v+n4kN~>YZ3?o
zT{W9sl2kO?atH%kgCk-tF=9{x0$svmLN2kW2ZyC9P7=7G!`!MubmH(`sETS3k56K_
zG`+7lHNp|5g3oqnObOc#czZ+#Qlm5pwPk6t&`TA|h=GYcjmD_f%;XY*FViLbNL}hh
zAl=oJ|F_Hit|n`42wN(gE8i9vvQ!)pa1-B*ECfn{I=pZiNkT523WCR|BbQ*qflGo9
z0`3rMktVo*ew(NjAzuYu`67Dq*xM836*q(l8(QZsO^vi_v^D+}NA~`F_SuCa4z&Nh
zWZAmsw|Csry`}r5)*N*1V6g7S>A~i(xtAs%SW-OuerwvhW4`wt+BIwF`A-7+==j#!
zZS{|+M+y&CH>b3nYSqPtD(~16FORrhf3RYaS<u<=rc<%8W9?RJ?Q0ERJT<ngQ)wSG
z2X$?K_@A*q99Z?);W2OAc`9#5-uZLe8h;93xVUG?aewWp>iu<(4~bvSZ}_dC;Oj+F
zs_@Kv!#-a>zCc>B`{@3P@Q=C1tM}gL8_~3Wj{QOX>odRGG-~1wd&}wuH+xFg`1a06
zYp!fLwdSze+THFiU%hn6zR>&gzxwNB-j#iOw(Aq#I-<X0=g-UQYMfU2^b02%XPK84
zr2HTKae8>&wff(8wmnz+?a>o$*9XpjX#dLNAFls*Sd_5ioxy95EnCk2?!k@Y%-Ur+
zIcdJRD)CBcUXXL&X2PmQFRbk0S|f0--xb_QXYL3_Hq6ecPTlb-JQQav+in4mX|+Uj
zz&_324aQaEgRAPJ-fDp37AHcLePeIu5S<l;FD?qMXIL~nXWt4Lezk9ETFiJdj(&C}
z*ZIIZ${J+p1_6RCz5l-84Mn+V{x>`hjfv={n`SWZM=is9(YF^q?GPBlTde+t&^W!v
zm#@SBCzAk}+w7Vc5SHj$>M_*>zT0D7=79OqH}lsUkhgwY0i_atGXQz#?e>Ts{pL6_
zl>(y-s#g1SG&uDO8XX4Q)iwRWR0rztjau%@YD376FhbeEU#IWs@S*I;<+F#zc0k_U
z4)GkoA)G@W=`rR3^2X=Rh9l*?QoE^x#(e|04mh|MGd4H5p3cj}4Tn?cTNiYc51N*a
j?wN~gy|vLK@Gb83aRA+a5iqx39||_q)@(rDcn#q{j%(+X

literal 0
HcmV?d00001

diff --git a/dlls/mmdevapi/client.c b/dlls/mmdevapi/client.c
index 4c23905aad81..d7e05a68215a 100644
--- a/dlls/mmdevapi/client.c
+++ b/dlls/mmdevapi/client.c
@@ -360,12 +360,14 @@ skip:
 
 HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible)
 {
-    WAVEFORMATEXTENSIBLE fmt2 = *fmt;
+    WAVEFORMATEXTENSIBLE fmt2;
     HRESULT ret;
 
     /* Reduce non-extensible formats to extensible ones. */
-    if (fmt2.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+    if (fmt->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
     {
+        fmt2.Format = fmt->Format;
+
         switch (fmt2.Format.wFormatTag)
         {
             case WAVE_FORMAT_PCM: fmt2.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break;
@@ -380,10 +382,14 @@ HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible)
         fmt2.Samples.wValidBitsPerSample = fmt2.Format.wBitsPerSample;
         fmt2.Format.cbSize = sizeof(fmt2) - sizeof(fmt2.Format);
     }
+    else
+    {
+        if (fmt->Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format))
+            return E_INVALIDARG;
+        fmt2 = *fmt;
+    }
 
-    if (fmt2.Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format))
-        ret = E_INVALIDARG;
-    else if (fmt2.Format.nChannels == 0 || fmt2.Format.nSamplesPerSec == 0)
+    if (fmt2.Format.nChannels == 0 || fmt2.Format.nSamplesPerSec == 0)
         ret = E_INVALIDARG;
     else if (fmt2.Format.nBlockAlign != fmt2.Format.nChannels * fmt2.Format.wBitsPerSample / 8)
         ret = E_INVALIDARG;
diff --git a/dlls/mmdevapi/tests/render.c b/dlls/mmdevapi/tests/render.c
index 60428711d931..b8b35610cce3 100644
--- a/dlls/mmdevapi/tests/render.c
+++ b/dlls/mmdevapi/tests/render.c
@@ -790,12 +790,14 @@ void fill_wave_formats(const WAVEFORMATEXTENSIBLE *base_fmt)
 /* Identical to dlls/mmdevapi/client.c. */
 HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible)
 {
-    WAVEFORMATEXTENSIBLE fmt2 = *fmt;
+    WAVEFORMATEXTENSIBLE fmt2;
     HRESULT ret;
 
     /* Reduce non-extensible formats to extensible ones. */
-    if (fmt2.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+    if (fmt->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
     {
+        fmt2.Format = fmt->Format;
+
         switch (fmt2.Format.wFormatTag)
         {
             case WAVE_FORMAT_PCM: fmt2.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; break;
@@ -810,10 +812,14 @@ HRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL compatible)
         fmt2.Samples.wValidBitsPerSample = fmt2.Format.wBitsPerSample;
         fmt2.Format.cbSize = sizeof(fmt2) - sizeof(fmt2.Format);
     }
+    else
+    {
+        if (fmt->Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format))
+            return E_INVALIDARG;
+        fmt2 = *fmt;
+    }
 
-    if (fmt2.Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format))
-        ret = E_INVALIDARG;
-    else if (fmt2.Format.nChannels == 0 || fmt2.Format.nSamplesPerSec == 0)
+    if (fmt2.Format.nChannels == 0 || fmt2.Format.nSamplesPerSec == 0)
         ret = E_INVALIDARG;
     else if (fmt2.Format.nBlockAlign != fmt2.Format.nChannels * fmt2.Format.wBitsPerSample / 8)
         ret = E_INVALIDARG;
diff --git a/dlls/mountmgr.sys/dbus.c b/dlls/mountmgr.sys/dbus.c
index 99f37a396d0b..7d0f542c9756 100644
--- a/dlls/mountmgr.sys/dbus.c
+++ b/dlls/mountmgr.sys/dbus.c
@@ -60,6 +60,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
     DO_FUNC(dbus_error_init); \
     DO_FUNC(dbus_error_is_set); \
     DO_FUNC(dbus_free_string_array); \
+    DO_FUNC(dbus_threads_init_default); \
     DO_FUNC(dbus_message_get_args); \
     DO_FUNC(dbus_message_get_interface); \
     DO_FUNC(dbus_message_get_member); \
@@ -551,6 +552,7 @@ void run_dbus_loop(void)
 
     if (!load_dbus_functions()) return;
 
+    p_dbus_threads_init_default();
     p_dbus_error_init( &error );
     if (!(connection = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error )))
     {
@@ -591,6 +593,7 @@ static DBusConnection *get_dhcp_connection(void)
     if (!dhcp_connection)
     {
         DBusError error;
+        p_dbus_threads_init_default();
         p_dbus_error_init( &error );
         if (!(dhcp_connection = p_dbus_bus_get_private( DBUS_BUS_SYSTEM, &error )))
         {
diff --git a/dlls/mscms/mscms.spec b/dlls/mscms/mscms.spec
index c15359c133f5..ec14db72d629 100644
--- a/dlls/mscms/mscms.spec
+++ b/dlls/mscms/mscms.spec
@@ -90,7 +90,7 @@
 @ stub WcsDisassociateColorProfileFromDevice
 @ stub WcsEnumColorProfiles
 @ stdcall WcsEnumColorProfilesSize(long ptr ptr)
-@ stub WcsGetCalibrationManagementState
+@ stdcall WcsGetCalibrationManagementState(ptr)
 @ stdcall WcsGetDefaultColorProfile(long wstr long long long long wstr)
 @ stdcall WcsGetDefaultColorProfileSize(long wstr long long long ptr)
 @ stdcall WcsGetDefaultRenderingIntent(long ptr)
diff --git a/dlls/mscms/stub.c b/dlls/mscms/stub.c
index 05c2919566ea..bd5eebb70a30 100644
--- a/dlls/mscms/stub.c
+++ b/dlls/mscms/stub.c
@@ -199,3 +199,13 @@ BOOL WINAPI UnregisterCMMW( PCWSTR machine, DWORD id )
 
     return TRUE;
 }
+
+BOOL WINAPI WcsGetCalibrationManagementState( BOOL *is_enabled )
+{
+    FIXME( "( %p ) stub\n", is_enabled );
+
+    if (is_enabled)
+        *is_enabled = TRUE;
+
+    return TRUE;
+}
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c
index cfe2acb4fe0a..39fe7c353846 100644
--- a/dlls/mshtml/htmlevent.c
+++ b/dlls/mshtml/htmlevent.c
@@ -108,7 +108,7 @@ typedef struct {
 #define EVENT_CANCELABLE         0x0008
 /* Event may have default handler (so we always have to register Gecko listener). */
 #define EVENT_HASDEFAULTHANDLERS 0x0020
-/* Ecent is not supported properly, print FIXME message when it's used. */
+/* Event is not supported properly, print FIXME message when it's used. */
 #define EVENT_FIXME              0x0040
 
 /* mouse event flags for fromElement and toElement implementation */
diff --git a/dlls/msi/dialog.c b/dlls/msi/dialog.c
index a228f138966d..a19a30619d18 100644
--- a/dlls/msi/dialog.c
+++ b/dlls/msi/dialog.c
@@ -1363,6 +1363,8 @@ static LRESULT WINAPI MSIComboBox_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
     struct msi_combobox_info *info;
     LRESULT r;
     DWORD j;
+    LPWSTR value, text = NULL;
+    INT index, len;
 
     TRACE( "%p %04x %#Ix %#Ix\n", hWnd, msg, wParam, lParam );
 
@@ -1374,6 +1376,31 @@ static LRESULT WINAPI MSIComboBox_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LP
 
     switch (msg)
     {
+    case WM_COMMAND:
+        if (HIWORD(wParam) == CBN_SELCHANGE)
+        {
+            index = SendMessageW( hWnd, CB_GETCURSEL, 0, 0 );
+            if (index != CB_ERR)
+            {
+                value = (LPWSTR)SendMessageW( hWnd, CB_GETITEMDATA, index, 0 );
+                if (value) SetWindowTextW( hWnd, value );
+                else
+                {
+                    len = (INT)SendMessageW( hWnd, CB_GETLBTEXTLEN, index, 0 );
+                    if (len != CB_ERR && len >= 0)
+                    {
+                        text = (LPWSTR)malloc( (len + 1) * sizeof(WCHAR) );
+                        if (text)
+                        {
+                            SendMessageW( hWnd, CB_GETLBTEXT, index, (LPARAM)text );
+                            SetWindowTextW( hWnd, text );
+                            free( text );
+                        }
+                    }
+                }
+            }
+        }
+        break;
     case WM_NCDESTROY:
         for (j = 0; j < info->num_items; j++)
             free( info->items[j] );
@@ -1397,7 +1424,7 @@ static UINT combobox_add_item( MSIRECORD *rec, void *param )
 
     info->items[info->addpos_items] = wcsdup( value );
 
-    pos = SendMessageW( info->hwnd, CB_ADDSTRING, 0, (LPARAM)text );
+    pos = SendMessageW( info->hwnd, CB_ADDSTRING, 0, (LPARAM)(text ? text : value) );
     SendMessageW( info->hwnd, CB_SETITEMDATA, pos, (LPARAM)info->items[info->addpos_items] );
     info->addpos_items++;
 
@@ -1510,7 +1537,8 @@ static UINT dialog_combobox_handler( msi_dialog *dialog, struct control *control
 static void dialog_combobox_update( msi_dialog *dialog, struct control *control )
 {
     struct msi_combobox_info *info;
-    LPWSTR value, tmp;
+    LPWSTR value, tmp, text = NULL;
+    INT len;
     DWORD j;
 
     info = GetPropW( control->hwnd, L"MSIDATA" );
@@ -1524,21 +1552,31 @@ static void dialog_combobox_update( msi_dialog *dialog, struct control *control
 
     for (j = 0; j < info->num_items; j++)
     {
-        tmp = (LPWSTR) SendMessageW( control->hwnd, CB_GETITEMDATA, j, 0 );
-        if (!wcscmp( value, tmp ))
-            break;
-    }
+        tmp = (LPWSTR)SendMessageW( control->hwnd, CB_GETITEMDATA, j, 0 );
+        if (!tmp)
+        {
+            len = (INT)SendMessageW( control->hwnd, CB_GETLBTEXTLEN, j, 0 );
+            if (len != CB_ERR && len >= 0)
+            {
+                text = (LPWSTR)malloc( (len + 1) * sizeof(WCHAR) );
+                if (text)
+                SendMessageW( control->hwnd, CB_GETLBTEXT, j, (LPARAM)text );
+            }
+        }
 
-    if (j < info->num_items)
-    {
-        SendMessageW( control->hwnd, CB_SETCURSEL, j, 0 );
-    }
-    else
-    {
-        SendMessageW( control->hwnd, CB_SETCURSEL, -1, 0 );
-        SetWindowTextW( control->hwnd, value );
+        if ((tmp && !wcscmp( value, tmp )) || (text && !wcscmp( value, text )))
+        {
+            SendMessageW( control->hwnd, CB_SETCURSEL, j, 0 );
+            SetWindowTextW( control->hwnd, tmp ? tmp : text );
+            free( value );
+            if (text) free( text );
+            return;
+        }
+        if (text) free( text );
     }
 
+    SendMessageW( control->hwnd, CB_SETCURSEL, -1, 0 );
+    SetWindowTextW( control->hwnd, value );
     free( value );
 }
 
diff --git a/dlls/msi/table.c b/dlls/msi/table.c
index 6031dd9c8058..897df0697227 100644
--- a/dlls/msi/table.c
+++ b/dlls/msi/table.c
@@ -394,11 +394,12 @@ static UINT table_get_row_size( MSIDATABASE *db, const struct column_info *cols,
 static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg )
 {
     BYTE *rawdata = NULL;
-    UINT rawsize = 0, i, j, row_size, row_size_mem;
+    UINT rawsize = 0, i, j, row_size, row_size_mem, bytes_per_strref;
 
     TRACE("%s\n",debugstr_w(t->name));
 
-    row_size = table_get_row_size( db, t->colinfo, t->col_count, db->bytes_per_strref );
+    bytes_per_strref = db->bytes_per_strref;
+    row_size = table_get_row_size( db, t->colinfo, t->col_count, bytes_per_strref );
     row_size_mem = table_get_row_size( db, t->colinfo, t->col_count, LONG_STR_BYTES );
 
     /* if we can't read the table, just assume that it's empty */
@@ -410,8 +411,31 @@ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg
 
     if( rawsize % row_size )
     {
-        WARN("Table size is invalid %d/%d\n", rawsize, row_size );
-        goto err;
+        /* Check if the data was written with a different bytes_per_strref. This can happen
+         * when transforms change the string pool metadata without re-encoding all table streams. */
+        if (bytes_per_strref == LONG_STR_BYTES)
+        {
+            UINT alt_row_size = table_get_row_size( db, t->colinfo, t->col_count, sizeof(USHORT) );
+            if (alt_row_size != row_size && rawsize % alt_row_size == 0)
+            {
+                WARN("Table %s: data uses %u-byte string refs, not %u\n",
+                     debugstr_w(t->name), (UINT)sizeof(USHORT), bytes_per_strref);
+                bytes_per_strref = sizeof(USHORT);
+                row_size = alt_row_size;
+            }
+        }
+    }
+
+    if( rawsize % row_size )
+    {
+        UINT padding = rawsize % row_size;
+        if (padding < 4)
+            rawsize -= padding;
+        else
+        {
+            WARN("Table size is invalid %d/%d\n", rawsize, row_size );
+            goto err;
+        }
     }
 
     if ((t->row_count = rawsize / row_size))
@@ -434,7 +458,7 @@ static UINT read_table_from_storage( MSIDATABASE *db, MSITABLE *t, IStorage *stg
         for (j = 0; j < t->col_count; j++)
         {
             UINT m = bytes_per_column( db, &t->colinfo[j], LONG_STR_BYTES );
-            UINT n = bytes_per_column( db, &t->colinfo[j], db->bytes_per_strref );
+            UINT n = bytes_per_column( db, &t->colinfo[j], bytes_per_strref );
             UINT k;
 
             if ( n != 2 && n != 3 && n != 4 )
diff --git a/dlls/msi/tests/db.c b/dlls/msi/tests/db.c
index 56fff94c5dfa..5dc5e88c4575 100644
--- a/dlls/msi/tests/db.c
+++ b/dlls/msi/tests/db.c
@@ -9365,6 +9365,282 @@ static void test_viewfetch_wraparound(void)
     DeleteFileA(msifile);
 }
 
+static void write_raw_stream(IStorage *stg, const WCHAR *name, const void *data, DWORD size)
+{
+    IStream *stm;
+    DWORD count;
+    HRESULT hr;
+
+    hr = IStorage_CreateStream(stg, name, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+    hr = IStream_Write(stm, data, size, &count);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+    IStream_Release(stm);
+}
+
+static void test_table_stream_padding(void)
+{
+    static const WCHAR moo_encoded[] = {0x4840, 0x3e16, 0x4818, 0}; /* encoded "MOO" */
+    MSIHANDLE hdb, hview, hrec;
+    IStorage *stg;
+    IStream *stm;
+    WCHAR nameW[MAX_PATH];
+    HRESULT hr;
+    BYTE moo_data[64];
+    BYTE padded[64];
+    DWORD moo_size;
+    const char *query;
+    UINT r;
+
+    DeleteFileA(msifile);
+
+    r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "CREATE TABLE `MOO` (`A` LONG PRIMARY KEY `A`)";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`) VALUES (10)";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`) VALUES (20)";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    r = MsiDatabaseCommit(hdb);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    MsiCloseHandle(hdb);
+
+    MultiByteToWideChar(CP_ACP, 0, msifile, -1, nameW, MAX_PATH);
+    hr = StgOpenStorage(nameW, NULL, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
+                        NULL, 0, &stg);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+
+    hr = IStorage_OpenStream(stg, moo_encoded, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+    hr = IStream_Read(stm, moo_data, sizeof(moo_data), &moo_size);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+    ok(moo_size == 8, "Expected 8, got %lu\n", moo_size);
+    IStream_Release(stm);
+
+
+    memcpy(padded, moo_data, moo_size);
+    padded[moo_size] = 0;
+    padded[moo_size + 1] = 0;
+
+
+    hr = IStorage_DestroyElement(stg, moo_encoded);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+
+    hr = IStorage_CreateStream(stg, moo_encoded, STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stm);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+    hr = IStream_Write(stm, padded, moo_size + 2, &moo_size);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+    IStream_Release(stm);
+
+    IStorage_Release(stg);
+
+
+    r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "SELECT `A` FROM `MOO`";
+    r = MsiDatabaseOpenViewA(hdb, query, &hview);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    r = MsiViewExecute(hview, 0);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    r = MsiViewFetch(hview, &hrec);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    check_record(hrec, 1, "10");
+    MsiCloseHandle(hrec);
+
+    r = MsiViewFetch(hview, &hrec);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    check_record(hrec, 1, "20");
+    MsiCloseHandle(hrec);
+
+    r = MsiViewFetch(hview, &hrec);
+    ok(r == ERROR_NO_MORE_ITEMS, "Expected ERROR_NO_MORE_ITEMS, got %d\n", r);
+
+    MsiViewClose(hview);
+    MsiCloseHandle(hview);
+    MsiCloseHandle(hdb);
+    DeleteFileA(msifile);
+}
+
+/* Convert column-major table data from 2-byte to 3-byte string references. Returns the new size. */
+static DWORD convert_to_3byte_strref(const BYTE *old_data, DWORD old_size,
+                                     BYTE *new_data, const int *col_types, UINT col_count)
+{
+    UINT old_row_size = col_count * 2;
+    UINT row_count = old_size / old_row_size;
+    DWORD new_size = 0;
+    UINT old_ofs = 0;
+    UINT j, i;
+
+    for (j = 0; j < col_count; j++)
+    {
+        for (i = 0; i < row_count; i++)
+        {
+            new_data[new_size++] = old_data[old_ofs++];
+            new_data[new_size++] = old_data[old_ofs++];
+            if (!col_types[j])
+                new_data[new_size++] = 0;
+        }
+    }
+    return new_size;
+}
+
+static void test_table_mismatched_strref(void)
+{
+    static const CLSID CLSID_MsiDatabase =
+        { 0xc1084, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
+    static const WCHAR stringpool_enc[] = {0x4840, 0x3f3f, 0x4577, 0x446c, 0x3e6a, 0x44b2, 0x482f, 0};
+    static const WCHAR tables_enc[] = {0x4840, 0x3f7f, 0x4164, 0x422f, 0x4836, 0};
+    static const WCHAR columns_enc[] = {0x4840, 0x3b3f, 0x43f2, 0x4438, 0x45b1, 0};
+    static const int tables_col_types[] = {0};
+    static const int columns_col_types[] = {0, 1, 0, 1};
+
+    MSIHANDLE hdb, hview, hrec;
+    IStorage *src, *dst;
+    IEnumSTATSTG *enumstg;
+    STATSTG stat;
+    IStream *stm;
+    WCHAR nameW[MAX_PATH], tmpW[MAX_PATH];
+    HRESULT hr;
+    BYTE buf[4096], converted[4096];
+    DWORD size, new_size;
+    const char *query;
+    UINT r;
+
+    DeleteFileA(msifile);
+    DeleteFileA("msitest2.msi");
+
+    /* Create a valid MSI database with 2-byte string refs */
+    r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_CREATE, &hdb);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "CREATE TABLE `MOO` (`A` SHORT NOT NULL, `B` CHAR(72) PRIMARY KEY `A`)";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`, `B`) VALUES (1, 'one')";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`, `B`) VALUES (2, 'two')";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`, `B`) VALUES (3, 'three')";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`, `B`) VALUES (4, 'four')";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`, `B`) VALUES (5, 'five')";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "INSERT INTO `MOO` (`A`, `B`) VALUES (6, 'six')";
+    r = run_query(hdb, 0, query);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    r = MsiDatabaseCommit(hdb);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    MsiCloseHandle(hdb);
+
+    /* Rebuild the MSI with modifications:
+     * - Set 0x8000 flag in _StringPool (declares 3-byte string refs)
+     * - Convert _Tables and _Columns to 3-byte string refs
+     * - Leave MOO stream unchanged (2-byte string refs) to simulate mismatch */
+    MultiByteToWideChar(CP_ACP, 0, msifile, -1, nameW, MAX_PATH);
+    hr = StgOpenStorage(nameW, NULL, STGM_READ | STGM_SHARE_DENY_WRITE, NULL, 0, &src);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+
+    MultiByteToWideChar(CP_ACP, 0, "msitest2.msi", -1, tmpW, MAX_PATH);
+    hr = StgCreateDocfile(tmpW, STGM_CREATE | STGM_READWRITE | STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
+                          0, &dst);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+
+    hr = IStorage_SetClass(dst, &CLSID_MsiDatabase);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+
+    hr = IStorage_EnumElements(src, 0, NULL, 0, &enumstg);
+    ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+
+    while (IEnumSTATSTG_Next(enumstg, 1, &stat, NULL) == S_OK)
+    {
+        if (stat.type == STGTY_STREAM)
+        {
+            hr = IStorage_OpenStream(src, stat.pwcsName, NULL,
+                                     STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stm);
+            ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+            hr = IStream_Read(stm, buf, sizeof(buf), &size);
+            ok(hr == S_OK, "Expected S_OK, got %#lx\n", hr);
+            IStream_Release(stm);
+
+            if (!lstrcmpW(stat.pwcsName, stringpool_enc))
+            {
+                buf[3] |= 0x80;
+                write_raw_stream(dst, stat.pwcsName, buf, size);
+            }
+            else if (!lstrcmpW(stat.pwcsName, tables_enc))
+            {
+                new_size = convert_to_3byte_strref(buf, size, converted, tables_col_types, 1);
+                write_raw_stream(dst, stat.pwcsName, converted, new_size);
+            }
+            else if (!lstrcmpW(stat.pwcsName, columns_enc))
+            {
+                new_size = convert_to_3byte_strref(buf, size, converted, columns_col_types, 4);
+                write_raw_stream(dst, stat.pwcsName, converted, new_size);
+            }
+            else
+            {
+                write_raw_stream(dst, stat.pwcsName, buf, size);
+            }
+        }
+        CoTaskMemFree(stat.pwcsName);
+    }
+
+    IEnumSTATSTG_Release(enumstg);
+    IStorage_Release(src);
+    IStorage_Release(dst);
+
+    r = DeleteFileA(msifile);
+    ok(r, "DeleteFileA failed: %lu\n", GetLastError());
+    r = MoveFileA("msitest2.msi", msifile);
+    ok(r, "MoveFileA failed: %lu\n", GetLastError());
+
+    /* Open the modified MSI and verify the table is queryable despite mismatched strref */
+    r = MsiOpenDatabaseW(msifileW, MSIDBOPEN_READONLY, &hdb);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    query = "SELECT `A`, `B` FROM `MOO`";
+    r = MsiDatabaseOpenViewA(hdb, query, &hview);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    r = MsiViewExecute(hview, 0);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+
+    r = MsiViewFetch(hview, &hrec);
+    ok(r == ERROR_SUCCESS, "Expected ERROR_SUCCESS, got %d\n", r);
+    r = MsiRecordGetInteger(hrec, 1);
+    ok(r == 1, "Expected 1, got %d\n", r);
+    MsiCloseHandle(hrec);
+
+    MsiViewClose(hview);
+    MsiCloseHandle(hview);
+    MsiCloseHandle(hdb);
+    DeleteFileA(msifile);
+}
+
 START_TEST(db)
 {
     test_msidatabase();
@@ -9425,4 +9701,6 @@ START_TEST(db)
     test_viewmodify_insert();
     test_view_get_error();
     test_viewfetch_wraparound();
+    test_table_stream_padding();
+    test_table_mismatched_strref();
 }
diff --git a/dlls/msvcrt/crt_gccmain.c b/dlls/msvcrt/crt_gccmain.c
index 88ca28747327..4ead00250829 100644
--- a/dlls/msvcrt/crt_gccmain.c
+++ b/dlls/msvcrt/crt_gccmain.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/crt_init.h b/dlls/msvcrt/crt_init.h
index 97d9de618cc9..1ef8ccbcfc64 100644
--- a/dlls/msvcrt/crt_init.h
+++ b/dlls/msvcrt/crt_init.h
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/crt_main.c b/dlls/msvcrt/crt_main.c
index be3e748d723d..29165a484602 100644
--- a/dlls/msvcrt/crt_main.c
+++ b/dlls/msvcrt/crt_main.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/crt_winmain.c b/dlls/msvcrt/crt_winmain.c
index fda3d12f688a..804dfb615873 100644
--- a/dlls/msvcrt/crt_winmain.c
+++ b/dlls/msvcrt/crt_winmain.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/crt_wmain.c b/dlls/msvcrt/crt_wmain.c
index 598d2a338b35..8798418d03b7 100644
--- a/dlls/msvcrt/crt_wmain.c
+++ b/dlls/msvcrt/crt_wmain.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/crt_wwinmain.c b/dlls/msvcrt/crt_wwinmain.c
index b50f728025b5..c3ba32a5fb96 100644
--- a/dlls/msvcrt/crt_wwinmain.c
+++ b/dlls/msvcrt/crt_wwinmain.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/iob.c b/dlls/msvcrt/iob.c
index 4d8456867a8b..7bf4bc60d202 100644
--- a/dlls/msvcrt/iob.c
+++ b/dlls/msvcrt/iob.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/mathf.c b/dlls/msvcrt/mathf.c
index 7f46230e7bde..8daac69bfc5d 100644
--- a/dlls/msvcrt/mathf.c
+++ b/dlls/msvcrt/mathf.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/onexit.c b/dlls/msvcrt/onexit.c
index d0c61700542a..ffc28496636c 100644
--- a/dlls/msvcrt/onexit.c
+++ b/dlls/msvcrt/onexit.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/printf.h b/dlls/msvcrt/printf.h
index cfcfd5be771f..924459654dcd 100644
--- a/dlls/msvcrt/printf.h
+++ b/dlls/msvcrt/printf.h
@@ -255,13 +255,28 @@ static inline int FUNC_NAME(pf_output_format_str)(FUNC_NAME(puts_clbk) pf_puts,
     return r>=0 ? ret : r;
 }
 
+static inline BOOL FUNC_NAME(pf_is_str_wide)(pf_flags *flags, BOOL legacy_wide)
+{
+    BOOL api_is_wide = sizeof(APICHAR) == sizeof(wchar_t);
+    BOOL complement_is_narrow = legacy_wide && api_is_wide;
+
+    if((flags->NaturalString && api_is_wide) || flags->WideString || flags->IntegerLength == LEN_LONG)
+        return TRUE;
+    if((flags->NaturalString && !api_is_wide) || flags->IntegerLength == LEN_SHORT)
+        return FALSE;
+
+#if _MSVCR_VER < 140
+    if (flags->Format == 'Z')
+        return FALSE;
+#endif
+
+    return (flags->Format=='s' || flags->Format=='c') == complement_is_narrow;
+}
+
 static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
         const void *str, int len, pf_flags *flags, _locale_t locale, BOOL legacy_wide)
 {
-    BOOL api_is_wide = sizeof(APICHAR) == sizeof(wchar_t);
-    BOOL complement_is_narrow = legacy_wide ? api_is_wide : FALSE;
 #ifdef PRINTF_WIDE
-
     if(!str)
         return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, L"(null)", 6, flags, locale);
 #else
@@ -269,15 +284,10 @@ static inline int FUNC_NAME(pf_handle_string)(FUNC_NAME(puts_clbk) pf_puts, void
         return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, "(null)", 6, flags, locale);
 #endif
 
-    if((flags->NaturalString && api_is_wide) || flags->WideString || flags->IntegerLength == LEN_LONG)
+    if(FUNC_NAME(pf_is_str_wide)(flags, legacy_wide))
         return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locale);
-    if((flags->NaturalString && !api_is_wide) || flags->IntegerLength == LEN_SHORT)
-        return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale);
-
-    if((flags->Format=='S' || flags->Format=='C') == complement_is_narrow)
-        return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale);
     else
-        return FUNC_NAME(pf_output_format_wstr)(pf_puts, puts_ctx, str, len, flags, locale);
+        return FUNC_NAME(pf_output_format_str)(pf_puts, puts_ctx, str, len, flags, locale);
 }
 
 static inline int FUNC_NAME(pf_output_special_fp)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx,
@@ -1142,6 +1152,21 @@ int FUNC_NAME(pf_printf)(FUNC_NAME(puts_clbk) pf_puts, void *puts_ctx, const API
 
             i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, &ch, 1, &flags, locale, legacy_wide);
             if(i < 0) i = 0; /* ignore conversion error */
+        } else if(flags.Format == 'Z') {
+            /* UNICODE_STRING and ANSI_STRING have the same layout. */
+            UNICODE_STRING *ustr = pf_args(args_ctx, pos, VT_PTR, valist).get_ptr;
+            void *str = ustr ? ustr->Buffer : NULL;
+            int len = ustr ? ustr->Length : 0;
+
+            if(FUNC_NAME(pf_is_str_wide)(&flags, legacy_wide)) {
+                if(len % sizeof(wchar_t)) {
+                    *_errno() = EINVAL;
+                    return -1;
+                }
+                len /= sizeof(wchar_t);
+            }
+            i = FUNC_NAME(pf_handle_string)(pf_puts, puts_ctx, str, len,
+                    &flags, locale, legacy_wide);
         } else if(flags.Format == 'p') {
             flags.Format = 'X';
             flags.PadZero = TRUE;
diff --git a/dlls/msvcrt/sincos.c b/dlls/msvcrt/sincos.c
index 1a34c50f0349..f874a7432538 100644
--- a/dlls/msvcrt/sincos.c
+++ b/dlls/msvcrt/sincos.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/msvcrt/tests/printf.c b/dlls/msvcrt/tests/printf.c
index c21b12852758..d401f449f84a 100644
--- a/dlls/msvcrt/tests/printf.c
+++ b/dlls/msvcrt/tests/printf.c
@@ -33,6 +33,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
+#include "winternl.h"
 
 #include "wine/test.h"
 
@@ -170,6 +171,7 @@ static void test_sprintf( void )
         { "% d", " 1", 0, INT_ARG, 1 },
         { "%+ d", "+1", 0, INT_ARG, 1 },
         { "%S", "wide", 0, PTR_ARG, 0, 0, 0, L"wide" },
+        { "%Z", "ansi", 0, PTR_ARG, 0, 0, 0, &(ANSI_STRING){ 4, 4, (char *)"ansi" } },
         { "%04c", "0001", 0, INT_ARG, '1' },
         { "%-04c", "1   ", 0, INT_ARG, '1' },
         { "%#012x", "0x0000000001", 0, INT_ARG, 1 },
@@ -194,6 +196,9 @@ static void test_sprintf( void )
         { "%w-s", "-s", 0, PTR_ARG, 0, 0, 0, L"wide" },
         { "%ls", "wide", 0, PTR_ARG, 0, 0, 0, L"wide" },
         { "%Ls", "not wide", 0, PTR_ARG, 0, 0, 0, "not wide" },
+        { "%wZ", "wide", 0, PTR_ARG, 0, 0, 0, &(UNICODE_STRING){ 8, 8, (wchar_t *)L"wide" } },
+        { "%wZ", "wi", 0, PTR_ARG, 0, 0, 0, &(UNICODE_STRING){ 4, 8, (wchar_t *)L"wide" } },
+        { "%hZ", "not wide", 0, PTR_ARG, 0, 0, 0, &(ANSI_STRING){ 8, 8, (char *)"not wide" } },
         { "%b", "b", 0, NO_ARG },
         { "%3c", "  a", 0, INT_ARG, 'a' },
         { "%3d", "1234", 0, INT_ARG, 1234 },
@@ -215,6 +220,10 @@ static void test_sprintf( void )
         { "%o", "12", 0, INT_ARG, 10 },
         { "%s", "(null)", 0, PTR_ARG, 0, 0, 0, NULL },
         { "%s", "%%%%", 0, PTR_ARG, 0, 0, 0, "%%%%" },
+        { "%Z", "(null)", 0, PTR_ARG, 0, 0, 0, NULL },
+        { "%Z", "(null)", 0, PTR_ARG, 0, 0, 0, &(ANSI_STRING){ 0, 0, NULL } },
+        { "%Z", "(null)", 0, PTR_ARG, 0, 0, 0, &(ANSI_STRING){ 1, 1, NULL } },
+        { "%Z", "no", 0, PTR_ARG, 0, 0, 0, &(ANSI_STRING){ 2, 8, (char *)"not wide" } },
         { "%u", "4294967295", 0, INT_ARG, -1 },
         { "%w", "", 0, INT_ARG, -1 },
         { "%h", "", 0, INT_ARG, -1 },
@@ -434,6 +443,11 @@ static void test_sprintf( void )
     r = p_sprintf(buffer, "% *2d", 0, 7);
     ok(r==2, "r = %d\n", r);
     ok(!strcmp(buffer, " 7"), "failed: \"%s\"\n", buffer);
+
+    errno = 0;
+    r = p_sprintf(buffer, "%wZ", &(UNICODE_STRING){ 5, 8, (wchar_t *)L"wide" });
+    ok(r==-1, "r = %d\n", r);
+    ok(errno == EINVAL, "errno = %d\n", errno);
 }
 
 static void test_swprintf( void )
@@ -441,6 +455,7 @@ static void test_swprintf( void )
     wchar_t buffer[100];
     double pnumber = 789456123;
     const char string[] = "string";
+    ANSI_STRING ansi_string = { 11, 11, (char *)"ansi string" };
 
     swprintf(buffer, L"%+#23.15e", pnumber);
     ok(wcsstr(buffer, L"e+008") != 0, "Sprintf different\n");
@@ -450,6 +465,10 @@ static void test_swprintf( void )
     ok(wcslen(buffer) == 6, "Problem with \"%%S\" interpretation\n");
     swprintf(buffer, L"%hs", string);
     ok(!wcscmp(L"string", buffer), "swprintf failed with %%hs\n");
+    swprintf(buffer, L"%Z", &ansi_string);
+    ok(!wcscmp(L"ansi string", buffer), "swprintf failed with %%Z\n");
+    swprintf(buffer, L"%hZ", &ansi_string);
+    ok(!wcscmp(L"ansi string", buffer), "swprintf failed with %%hZ\n");
 }
 
 static void test_snprintf (void)
diff --git a/dlls/msvcrt/wcs.c b/dlls/msvcrt/wcs.c
index 1b7bc3e54e06..9ad7181311ac 100644
--- a/dlls/msvcrt/wcs.c
+++ b/dlls/msvcrt/wcs.c
@@ -28,6 +28,7 @@
 #include <wctype.h>
 #include "msvcrt.h"
 #include "winnls.h"
+#include "winternl.h"
 #include "wtypes.h"
 #include "wine/debug.h"
 
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index 55539feeb78a..4dd1516f3a67 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -704,6 +704,13 @@ static void _expect_ref(IUnknown* obj, ULONG ref, int line)
     ok_(__FILE__,line)(rc == ref, "expected refcount %ld, got %ld\n", ref, rc);
 }
 
+static ULONG get_refcount(void *iface)
+{
+    IUnknown *unknown = iface;
+    IUnknown_AddRef(unknown);
+    return IUnknown_Release(unknown);
+}
+
 #define EXPECT_LIST_LEN(list,len) _expect_list_len(list, len, __LINE__)
 static void _expect_list_len(IXMLDOMNodeList *list, LONG len, int line)
 {
@@ -1184,20 +1191,8 @@ static const WCHAR nonexistent_fileW[] = L"c:\\Nonexistent.xml";
 
 static const WCHAR szStrangeChars[] = L"&x \x2103";
 
-#define expect_bstr_eq_and_free(bstr, expect) { \
-    BSTR bstrExp = alloc_str_from_narrow(expect); \
-    ok(lstrcmpW(bstr, bstrExp) == 0, "String differs\n"); \
-    SysFreeString(bstr); \
-    SysFreeString(bstrExp); \
-}
-
 #define expect_eq(expr, value, type, format) { type ret = (expr); ok((value) == ret, #expr " expected " format " got " format "\n", value, ret); }
 
-#define ole_expect(expr, expect) { \
-    HRESULT r = expr; \
-    ok(r == (expect), #expr " returned %x, expected %x\n", r, expect); \
-}
-
 #define double_eq(x, y) ok((x)-(y)<=1e-14*(x) && (x)-(y)>=-1e-14*(x), "expected %.16g, got %.16g\n", x, y)
 
 static void* _create_object(const GUID *clsid, const char *name, const IID *iid, int line)
@@ -1925,11 +1920,8 @@ if (0)
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
         /* test put_data */
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = SysAllocString(L"str1");
-        hr = IXMLDOMText_put_nodeValue(nodetext, var);
+        hr = IXMLDOMText_put_nodeValue(nodetext, _variantbstr_("str1"));
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-        VariantClear(&var);
 
         hr = IXMLDOMText_get_text(nodetext, &str);
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -1949,11 +1941,8 @@ if (0)
         SysFreeString(str);
 
         /* ::replaceData() */
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = SysAllocString(L"str1");
-        hr = IXMLDOMText_put_nodeValue(nodetext, var);
+        hr = IXMLDOMText_put_nodeValue(nodetext, _variantbstr_("str1"));
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-        VariantClear(&var);
 
         hr = IXMLDOMText_replaceData(nodetext, 6, 0, NULL);
         ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
@@ -2132,11 +2121,8 @@ if (0)
         ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
 
         /* test put_data */
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = SysAllocString(L"open");  /* Doesn't matter what the string is, cannot set an xml node. */
-        hr = IXMLDOMProcessingInstruction_put_nodeValue(nodePI, var);
+        hr = IXMLDOMProcessingInstruction_put_nodeValue(nodePI, _variantbstr_("open"));
         ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
-        VariantClear(&var);
 
         /* test get nodeName */
         hr = IXMLDOMProcessingInstruction_get_nodeName(nodePI, &str);
@@ -3085,32 +3071,23 @@ static void test_create(void)
     IXMLDOMComment_Release(comment);
     SysFreeString(str);
 
-    V_VT(&var) = VT_BSTR;
-    V_BSTR(&var) = SysAllocString(L"comment");
     node = NULL;
-    hr = IXMLDOMDocument_createNode( doc, var, NULL, NULL, &node );
+    hr = IXMLDOMDocument_createNode(doc, _variantbstr_("comment"), NULL, NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!!node, "Unexpected object %p.\n", node);
     IXMLDOMNode_Release(node);
-    VariantClear(&var);
 
-    V_VT(&var) = VT_BSTR;
-    V_BSTR(&var) = SysAllocString(L"coMment");
     node = NULL;
-    hr = IXMLDOMDocument_createNode( doc, var, NULL, NULL, &node );
+    hr = IXMLDOMDocument_createNode(doc, _variantbstr_("coMment"), NULL, NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!!node, "Unexpected object %p.\n", node);
     IXMLDOMNode_Release(node);
-    VariantClear(&var);
 
-    V_VT(&var) = VT_BSTR;
-    V_BSTR(&var) = SysAllocString(L"8");
     node = NULL;
-    hr = IXMLDOMDocument_createNode( doc, var, NULL, NULL, &node );
+    hr = IXMLDOMDocument_createNode(doc, _variantbstr_("8"), NULL, NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!!node, "Unexpected object %p.\n", node);
     IXMLDOMNode_Release(node);
-    VariantClear(&var);
 
     /* NODE_TEXT */
     V_VT(&var) = VT_I1;
@@ -3161,23 +3138,17 @@ static void test_create(void)
     IXMLDOMText_Release(text);
     SysFreeString(str);
 
-    V_VT(&var) = VT_BSTR;
-    V_BSTR(&var) = SysAllocString(L"text");
     node = NULL;
-    hr = IXMLDOMDocument_createNode( doc, var, NULL, NULL, &node );
+    hr = IXMLDOMDocument_createNode(doc, _variantbstr_("text"), NULL, NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!!node, "Unexpected object %p.\n", node);
     IXMLDOMNode_Release(node);
-    VariantClear(&var);
 
-    V_VT(&var) = VT_BSTR;
-    V_BSTR(&var) = SysAllocString(L"teXt");
     node = NULL;
-    hr = IXMLDOMDocument_createNode( doc, var, NULL, NULL, &node );
+    hr = IXMLDOMDocument_createNode(doc, _variantbstr_("teXt"), NULL, NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!!node, "Unexpected object %p.\n", node);
     IXMLDOMNode_Release(node);
-    VariantClear(&var);
 
     /* NODE_CDATA_SECTION */
     V_VT(&var) = VT_I1;
@@ -3664,7 +3635,8 @@ static void test_get_text(void)
     {
         hr = IXMLDOMNode_get_text( nodeRoot, &str );
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-        expect_bstr_eq_and_free(str, "fn1.txt\n \nfn2.txt\n \nf1");
+        ok(!wcscmp(str, L"fn1.txt\n \nfn2.txt\n \nf1"), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
 
         IXMLDOMNode_Release(nodeRoot);
     }
@@ -3735,6 +3707,7 @@ static void test_get_childNodes(void)
     IXMLDOMNode *node, *node2;
     IXMLDOMElement *element;
     IUnknown *unk1, *unk2;
+    DOMNodeType node_type;
     ULONG fetched;
     VARIANT v[2];
     HRESULT hr;
@@ -3743,6 +3716,61 @@ static void test_get_childNodes(void)
 
     doc = create_document(&IID_IXMLDOMDocument);
 
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    /* Document children */
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_(szEmailXML), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_TRUE, "Unexpected value %d\n", b);
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMElement_Release(element);
+
+    hr = IXMLDOMDocument_get_childNodes(doc, &node_list);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNodeList_get_length(node_list, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 3, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNodeList_nextNode(node_list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeType(node, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_PROCESSING_INSTRUCTION, "Unexpected node %d.\n", node_type);
+    hr = IXMLDOMDocument_removeChild(doc, node, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNodeList_nextNode(node_list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeType(node, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_DOCUMENT_TYPE, "Unexpected node %d.\n", node_type);
+    hr = IXMLDOMDocument_removeChild(doc, node, NULL);
+    todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNodeList_nextNode(node_list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeType(node, &node_type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node_type == NODE_ELEMENT, "Unexpected node %d.\n", node_type);
+    hr = IXMLDOMDocument_removeChild(doc, node, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+    hr = IXMLDOMNodeList_get_length(node_list, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(len == 1, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    IXMLDOMNodeList_Release(node_list);
+
     hr = IXMLDOMDocument_loadXML( doc, _bstr_(complete4A), &b );
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok( b == VARIANT_TRUE, "failed to load XML string\n");
@@ -4551,7 +4579,8 @@ static void test_IXMLDOMDocument2(void)
     hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionLanguage"), &var);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     expect_eq(V_VT(&var), VT_BSTR, int, "%x");
-    expect_bstr_eq_and_free(V_BSTR(&var), "XSLPattern");
+    ok(!wcscmp(V_BSTR(&var), L"XSLPattern"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
     V_VT(&var) = VT_R4;
 
     /* the variant didn't get cleared*/
@@ -4586,7 +4615,8 @@ static void test_IXMLDOMDocument2(void)
     hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionLanguage"), &var);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     expect_eq(V_VT(&var), VT_BSTR, int, "%x");
-    expect_bstr_eq_and_free(V_BSTR(&var), "XSLPattern");
+    ok(!wcscmp(V_BSTR(&var), L"XSLPattern"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
 
     IXMLDOMDocument2_Release( doc2 );
     IXMLDOMDocument_Release( doc );
@@ -5082,36 +5112,36 @@ static void test_whitespace(void)
 typedef struct {
     const GUID *clsid;
     const char *name;
-    const char *ns;
+    const WCHAR *ns;
     HRESULT hr;
 } selection_ns_t;
 
 /* supposed to be tested with szExampleXML */
 static const selection_ns_t selection_ns_data[] = {
-    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   "\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   "\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   " xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
-
-    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  "\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  "\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  " xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
-
-    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", "\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", "\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", " xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
-
-    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", "\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", "\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", " xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
-
-    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", "\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", "\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", " xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
-    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
+    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   L"\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   L"\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   L" xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument,   "CLSID_DOMDocument",   L"xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
+
+    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  L"\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  L"\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  L" xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument2,  "CLSID_DOMDocument2",  L"xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
+
+    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", L"\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", L"\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", L" xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument30, "CLSID_DOMDocument30", L"xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
+
+    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", L"\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", L"\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", L" xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument40, "CLSID_DOMDocument40", L"xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
+
+    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", L"\txmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", L"\n\rxmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", L" xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29'", S_OK },
+    { &CLSID_DOMDocument60, "CLSID_DOMDocument60", L"xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' ", S_OK },
 
     { NULL }
 };
@@ -5160,6 +5190,7 @@ static void test_XPath(void)
 {
     const selection_ns_t *ptr = selection_ns_data;
     const xpath_test_t *xptest = xpath_test;
+    IXMLDOMNamedNodeMap *map;
     VARIANT var;
     VARIANT_BOOL b;
     IXMLDOMDocument2 *doc;
@@ -5223,10 +5254,38 @@ static void test_XPath(void)
             IXMLDOMNodeList_Release(list);
     }
 
-if (0)
+if (!winetest_platform_is_wine)
 {
     /* namespace:: axis test is disabled until namespace definitions
-       are supported as attribute nodes, currently it's another node type */
+       are supported as attribute nodes, currently it's another node type.
+
+       Query returns not only actually present attributes, but implicit as well. */
+
+    hr = IXMLDOMDocument2_get_documentElement(doc, &elem);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_get_attributes(elem, &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 == 3, "Unexpected length %ld.\n", len);
+
+    hr = IXMLDOMNamedNodeMap_getNamedItem(map, _bstr_("xmlns:foo"), &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNamedNodeMap_getNamedItem(map, _bstr_("a"), &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNamedNodeMap_getNamedItem(map, _bstr_("foo:b"), &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    IXMLDOMNamedNodeMap_Release(map);
+    IXMLDOMElement_Release(elem);
+
     hr = IXMLDOMDocument2_selectNodes(doc, _bstr_("/root/namespace::*"), &list);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     len = -1;
@@ -5240,6 +5299,22 @@ if (0)
     hr = IXMLDOMNode_get_nodeType(node, &type);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(type == NODE_ATTRIBUTE, "got %d\n", type);
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"xmlns:xml"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMNodeList_nextNode(list, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    type = NODE_INVALID;
+    hr = IXMLDOMNode_get_nodeType(node, &type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(type == NODE_ATTRIBUTE, "got %d\n", type);
+    hr = IXMLDOMNode_get_nodeName(node, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"xmlns:foo"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
     IXMLDOMNode_Release(node);
 
     IXMLDOMNodeList_Release(list);
@@ -5355,7 +5430,11 @@ if (0)
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     expect_eq(V_VT(&var), VT_BSTR, int, "%x");
     if (V_VT(&var) == VT_BSTR)
-        expect_bstr_eq_and_free(V_BSTR(&var), "xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' xmlns:foo=###");
+    {
+        ok(!wcscmp(V_BSTR(&var), L"xmlns:test='urn:uuid:86B2F87F-ACB6-45cd-8B77-9BDB92A01A29' xmlns:foo=###"),
+                "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    }
+    VariantClear(&var);
 
     /* extra attributes - same thing*/
     hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"),
@@ -5490,16 +5569,16 @@ if (0)
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
         V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = _bstr_(ptr->ns);
-
+        V_BSTR(&var) = SysAllocString(ptr->ns);
         hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionNamespaces"), var);
-        ok(hr == ptr->hr, "Unexpected hr %#lx., for %s, %s\n", hr, ptr->name, ptr->ns);
+        ok(hr == ptr->hr, "Unexpected hr %#lx, for %s, %s\n", hr, ptr->name, debugstr_w(ptr->ns));
+        VariantClear(&var);
 
         V_VT(&var) = VT_EMPTY;
         hr = IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionNamespaces"), &var);
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
         ok(V_VT(&var) == VT_BSTR, "got wrong property type %d\n", V_VT(&var));
-        ok(!lstrcmpW(V_BSTR(&var), _bstr_(ptr->ns)), "got wrong value %s\n", wine_dbgstr_w(V_BSTR(&var)));
+        ok(!lstrcmpW(V_BSTR(&var), ptr->ns), "Unexpected value %s.\n", wine_dbgstr_w(V_BSTR(&var)));
         VariantClear(&var);
 
         hr = IXMLDOMDocument2_selectNodes(doc, _bstr_("root//test:c"), &list);
@@ -5517,7 +5596,9 @@ if (0)
 
 static void test_cloneNode(void )
 {
+    IXMLDOMDocumentType *doctype, *doctype2;
     IXMLDOMDocument2 *doc, *doc_clone;
+    IXMLDOMElement *element;
     IXMLDOMDocument *doc2;
     VARIANT_BOOL b;
     IXMLDOMNodeList *pList;
@@ -5532,6 +5613,47 @@ static void test_cloneNode(void )
 
     doc = create_document(&IID_IXMLDOMDocument2);
 
+    /* Shallow cloning with a DTD */
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szEmailXML), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_TRUE, "Unexpected value %d.\n", b);
+
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMElement_Release(element);
+
+    hr = IXMLDOMDocument2_get_doctype(doc, &doctype);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    IXMLDOMDocumentType_Release(doctype);
+
+    hr = IXMLDOMDocument2_cloneNode(doc, VARIANT_FALSE, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!!node, "Got node %p.\n", node);
+    hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocument2, (void **)&doc_clone);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument2_get_doctype(doc_clone, &doctype2);
+    todo_wine
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
+    hr = IXMLDOMDocument2_get_documentElement(doc_clone, &element);
+    todo_wine
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMDocument2_Release(doc_clone);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMDocument2_cloneNode(doc, VARIANT_TRUE, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!!node, "Got node %p.\n", node);
+    hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMDocument2, (void **)&doc_clone);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument2_get_doctype(doc_clone, &doctype2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    IXMLDOMDocumentType_Release(doctype2);
+    hr = IXMLDOMDocument2_get_documentElement(doc_clone, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMElement_Release(element);
+    IXMLDOMDocument2_Release(doc_clone);
+    IXMLDOMNode_Release(node);
+
     hr = IXMLDOMDocument2_loadXML(doc, _bstr_(complete4A), &b);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(b == VARIANT_TRUE, "failed to load XML string\n");
@@ -5541,9 +5663,7 @@ static void test_cloneNode(void )
     ok(!lstrcmpW(V_BSTR(&v), L"XSLPattern"), "got prop value %s\n", wine_dbgstr_w(V_BSTR(&v)));
     VariantClear(&v);
 
-    V_BSTR(&v) = _bstr_("XPath");
-    V_VT(&v) = VT_BSTR;
-    hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), v);
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), _variantbstr_("XPath"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     /* clone document node */
@@ -5668,18 +5788,14 @@ static void test_xmlTypes(void)
     IXMLDOMDocument *doc;
     IXMLDOMElement *pRoot;
     HRESULT hr;
-    IXMLDOMComment *pComment;
     IXMLDOMElement *pElement;
     IXMLDOMAttribute *pAttribute;
     IXMLDOMNamedNodeMap *pAttribs;
-    IXMLDOMCDATASection *pCDataSec;
-    IXMLDOMImplementation *pIXMLDOMImplementation = NULL;
     IXMLDOMDocumentFragment *pDocFrag = NULL;
     IXMLDOMEntityReference *pEntityRef = NULL;
     BSTR str;
     IXMLDOMNode *pNextChild;
     VARIANT v;
-    LONG len = 0;
 
     doc = create_document(&IID_IXMLDOMDocument);
 
@@ -5707,59 +5823,6 @@ static void test_xmlTypes(void)
     ok( V_VT(&v) == VT_NULL, "incorrect dataType type\n");
     VariantClear(&v);
 
-    /* test implementation */
-    hr = IXMLDOMDocument_get_implementation(doc, NULL);
-    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-    hr = IXMLDOMDocument_get_implementation(doc, &pIXMLDOMImplementation);
-    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    if(hr == S_OK)
-    {
-        VARIANT_BOOL hasFeature = VARIANT_TRUE;
-        BSTR sEmpty = SysAllocStringLen(NULL, 0);
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, NULL, sEmpty, &hasFeature);
-        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, sEmpty, sEmpty, NULL);
-        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), sEmpty, &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_FALSE, "hasFeature returned false\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, sEmpty, sEmpty, &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_FALSE, "hasFeature returned true\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), NULL, &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_TRUE, "hasFeature returned false\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), sEmpty, &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_FALSE, "hasFeature returned false\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("DOM"), _bstr_("1.0"), &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_TRUE, "hasFeature returned true\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("XML"), _bstr_("1.0"), &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_TRUE, "hasFeature returned true\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("MS-DOM"), _bstr_("1.0"), &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_TRUE, "hasFeature returned true\n");
-
-        hr = IXMLDOMImplementation_hasFeature(pIXMLDOMImplementation, _bstr_("SSS"), NULL, &hasFeature);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        ok(hasFeature == VARIANT_FALSE, "hasFeature returned false\n");
-
-        SysFreeString(sEmpty);
-        IXMLDOMImplementation_Release(pIXMLDOMImplementation);
-    }
-
     pRoot = (IXMLDOMElement*)0x1;
     hr = IXMLDOMDocument_createElement(doc, NULL, &pRoot);
     ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
@@ -5778,379 +5841,86 @@ static void test_xmlTypes(void)
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
         if(hr == S_OK)
         {
-            /* Comment */
-            str = SysAllocString(L"A Comment");
-            hr = IXMLDOMDocument_createComment(doc, str, &pComment);
+            /* Element */
+            str = SysAllocString(L"EleTest");
+            hr = IXMLDOMDocument_createElement(doc, str, &pElement);
             SysFreeString(str);
             ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
             if(hr == S_OK)
             {
-                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pComment, NULL);
+                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
 
-                hr = IXMLDOMComment_get_nodeName(pComment, &str);
+                hr = IXMLDOMElement_get_nodeName(pElement, &str);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"#comment" ), "incorrect comment node Name\n");
+                ok( !lstrcmpW( str, L"EleTest" ), "incorrect element node Name\n");
                 SysFreeString(str);
 
-                hr = IXMLDOMComment_get_xml(pComment, &str);
+                hr = IXMLDOMElement_get_xml(pElement, &str);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"<!--A Comment-->" ), "incorrect comment xml\n");
+                ok( !lstrcmpW( str, L"<EleTest/>" ), "incorrect element xml\n");
                 SysFreeString(str);
 
-                /* put data Tests */
-                hr = IXMLDOMComment_put_data(pComment, _bstr_("This &is a ; test <>\\"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+                /* Attribute */
+                pAttribute = (IXMLDOMAttribute*)0x1;
+                hr = IXMLDOMDocument_createAttribute(doc, NULL, &pAttribute);
+                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+                ok(pAttribute == (void*)0x1, "Expect same ptr, got %p\n", pAttribute);
 
-                /* get data Tests */
-                hr = IXMLDOMComment_get_data(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect get_data string\n");
-                SysFreeString(str);
+                pAttribute = (IXMLDOMAttribute*)0x1;
+                hr = IXMLDOMDocument_createAttribute(doc, _bstr_(""), &pAttribute);
+                ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+                ok(pAttribute == (void*)0x1, "Expect same ptr, got %p\n", pAttribute);
 
-                /* Confirm XML text is good */
-                hr = IXMLDOMComment_get_xml(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"<!--This &is a ; test <>\\-->"), "incorrect xml string\n");
+                str = SysAllocString(L"Attr");
+                hr = IXMLDOMDocument_createAttribute(doc, str, &pAttribute);
                 SysFreeString(str);
-
-                /* Confirm we get the put_data Text back */
-                hr = IXMLDOMComment_get_text(pComment, &str);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect xml string\n");
-                SysFreeString(str);
+                if(hr == S_OK)
+                {
+                    IXMLDOMNode *pNewChild = (IXMLDOMNode *)0x1;
 
-                /* test length property */
-                hr = IXMLDOMComment_get_length(pComment, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 21, "expected 21 got %ld\n", len);
+                    hr = IXMLDOMAttribute_get_nextSibling(pAttribute, NULL);
+                    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
 
-                /* test substringData */
-                hr = IXMLDOMComment_substringData(pComment, 0, 4, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+                    pNextChild = (IXMLDOMNode *)0x1;
+                    hr = IXMLDOMAttribute_get_nextSibling(pAttribute, &pNextChild);
+                    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
+                    ok(pNextChild == NULL, "pNextChild not NULL\n");
 
-                /* test substringData - Invalid offset */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMComment_substringData(pComment, -1, 4, &str);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
+                    /* test Previous Sibling*/
+                    hr = IXMLDOMAttribute_get_previousSibling(pAttribute, NULL);
+                    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
 
-                /* test substringData - Invalid offset */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMComment_substringData(pComment, 30, 0, &str);
-                ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
+                    pNextChild = (IXMLDOMNode *)0x1;
+                    hr = IXMLDOMAttribute_get_previousSibling(pAttribute, &pNextChild);
+                    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
+                    ok(pNextChild == NULL, "pNextChild not NULL\n");
 
-                /* test substringData - Invalid size */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMComment_substringData(pComment, 0, -1, &str);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
+                    hr = IXMLDOMElement_appendChild(pElement, (IXMLDOMNode*)pAttribute, &pNewChild);
+                    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+                    ok(pNewChild == NULL, "pNewChild not NULL\n");
 
-                /* test substringData - Invalid size */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMComment_substringData(pComment, 2, 0, &str);
-                ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
+                    hr = IXMLDOMElement_get_attributes(pElement, &pAttribs);
+                    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+                    if ( hr == S_OK )
+                    {
+                        hr = IXMLDOMNamedNodeMap_setNamedItem(pAttribs, (IXMLDOMNode*)pAttribute, NULL );
+                        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
 
-                /* test substringData - Start of string */
-                hr = IXMLDOMComment_substringData(pComment, 0, 4, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This"), "incorrect substringData string\n");
-                SysFreeString(str);
+                        IXMLDOMNamedNodeMap_Release(pAttribs);
+                    }
 
-                /* test substringData - Middle of string */
-                hr = IXMLDOMComment_substringData(pComment, 13, 4, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"test"), "incorrect substringData string\n");
-                SysFreeString(str);
+                    hr = IXMLDOMAttribute_get_nodeName(pAttribute, &str);
+                    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+                    ok( !lstrcmpW( str, L"Attr" ), "incorrect attribute node Name\n");
+                    SysFreeString(str);
 
-                /* test substringData - End of string */
-                hr = IXMLDOMComment_substringData(pComment, 20, 4, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"\\"), "incorrect substringData string\n");
-                SysFreeString(str);
-
-                /* test appendData */
-                hr = IXMLDOMComment_appendData(pComment, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_appendData(pComment, _bstr_(""));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_appendData(pComment, _bstr_("Append"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This &is a ; test <>\\Append"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* test insertData */
-                str = SysAllocStringLen(NULL, 0);
-                hr = IXMLDOMComment_insertData(pComment, -1, str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, -1, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 1000, str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 1000, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 0, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 0, str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                SysFreeString(str);
-
-                hr = IXMLDOMComment_insertData(pComment, -1, _bstr_("Inserting"));
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 1000, _bstr_("Inserting"));
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 0, _bstr_("Begin "));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 17, _bstr_("Middle"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 39, _bstr_(" End"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"Begin This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete data */
-                /* invalid arguments */
-                hr = IXMLDOMComment_deleteData(pComment, -1, 1);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_deleteData(pComment, 0, 0);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_deleteData(pComment, 0, -1);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_get_length(pComment, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 43, "expected 43 got %ld\n", len);
-
-                hr = IXMLDOMComment_deleteData(pComment, len, 1);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_deleteData(pComment, len+1, 1);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                /* delete from start */
-                hr = IXMLDOMComment_deleteData(pComment, 0, 5);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_get_length(pComment, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 38, "expected 38 got %ld\n", len);
-
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete from end */
-                hr = IXMLDOMComment_deleteData(pComment, 35, 3);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_get_length(pComment, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 35, "expected 35 got %ld\n", len);
-
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append "), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete from inside */
-                hr = IXMLDOMComment_deleteData(pComment, 1, 33);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_get_length(pComment, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 2, "expected 2 got %ld\n", len);
-
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"  "), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete whole data ... */
-                hr = IXMLDOMComment_get_length(pComment, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_deleteData(pComment, 0, len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                /* ... and try again with empty string */
-                hr = IXMLDOMComment_deleteData(pComment, 0, len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                /* ::replaceData() */
-                V_VT(&v) = VT_BSTR;
-                V_BSTR(&v) = SysAllocString(L"str1");
-                hr = IXMLDOMComment_put_nodeValue(pComment, v);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                VariantClear(&v);
-
-                hr = IXMLDOMComment_replaceData(pComment, 6, 0, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                hr = IXMLDOMComment_replaceData(pComment, 0, 0, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* NULL pointer means delete */
-                hr = IXMLDOMComment_replaceData(pComment, 0, 1, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"tr1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* empty string means delete */
-                hr = IXMLDOMComment_replaceData(pComment, 0, 1, _bstr_(""));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"r1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* zero count means insert */
-                hr = IXMLDOMComment_replaceData(pComment, 0, 0, _bstr_("a"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"ar1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                hr = IXMLDOMComment_replaceData(pComment, 0, 2, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMComment_insertData(pComment, 0, _bstr_("m"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"m1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* nonempty string, count greater than its length */
-                hr = IXMLDOMComment_replaceData(pComment, 0, 2, _bstr_("a1.2"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"a1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* nonempty string, count less than its length */
-                hr = IXMLDOMComment_replaceData(pComment, 0, 1, _bstr_("wine"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMComment_get_text(pComment, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"wine1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                IXMLDOMComment_Release(pComment);
-            }
-
-            /* Element */
-            str = SysAllocString(L"EleTest");
-            hr = IXMLDOMDocument_createElement(doc, str, &pElement);
-            SysFreeString(str);
-            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-            if(hr == S_OK)
-            {
-                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pElement, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMElement_get_nodeName(pElement, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"EleTest" ), "incorrect element node Name\n");
-                SysFreeString(str);
-
-                hr = IXMLDOMElement_get_xml(pElement, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"<EleTest/>" ), "incorrect element xml\n");
-                SysFreeString(str);
-
-                /* Attribute */
-                pAttribute = (IXMLDOMAttribute*)0x1;
-                hr = IXMLDOMDocument_createAttribute(doc, NULL, &pAttribute);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                ok(pAttribute == (void*)0x1, "Expect same ptr, got %p\n", pAttribute);
-
-                pAttribute = (IXMLDOMAttribute*)0x1;
-                hr = IXMLDOMDocument_createAttribute(doc, _bstr_(""), &pAttribute);
-                ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
-                ok(pAttribute == (void*)0x1, "Expect same ptr, got %p\n", pAttribute);
-
-                str = SysAllocString(L"Attr");
-                hr = IXMLDOMDocument_createAttribute(doc, str, &pAttribute);
-                SysFreeString(str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                if(hr == S_OK)
-                {
-                    IXMLDOMNode *pNewChild = (IXMLDOMNode *)0x1;
-
-                    hr = IXMLDOMAttribute_get_nextSibling(pAttribute, NULL);
-                    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                    pNextChild = (IXMLDOMNode *)0x1;
-                    hr = IXMLDOMAttribute_get_nextSibling(pAttribute, &pNextChild);
-                    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                    ok(pNextChild == NULL, "pNextChild not NULL\n");
-
-                    /* test Previous Sibling*/
-                    hr = IXMLDOMAttribute_get_previousSibling(pAttribute, NULL);
-                    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                    pNextChild = (IXMLDOMNode *)0x1;
-                    hr = IXMLDOMAttribute_get_previousSibling(pAttribute, &pNextChild);
-                    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                    ok(pNextChild == NULL, "pNextChild not NULL\n");
-
-                    hr = IXMLDOMElement_appendChild(pElement, (IXMLDOMNode*)pAttribute, &pNewChild);
-                    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
-                    ok(pNewChild == NULL, "pNewChild not NULL\n");
-
-                    hr = IXMLDOMElement_get_attributes(pElement, &pAttribs);
-                    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                    if ( hr == S_OK )
-                    {
-                        hr = IXMLDOMNamedNodeMap_setNamedItem(pAttribs, (IXMLDOMNode*)pAttribute, NULL );
-                        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                        IXMLDOMNamedNodeMap_Release(pAttribs);
-                    }
-
-                    hr = IXMLDOMAttribute_get_nodeName(pAttribute, &str);
-                    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                    ok( !lstrcmpW( str, L"Attr" ), "incorrect attribute node Name\n");
-                    SysFreeString(str);
-
-                    /* test nodeName */
-                    hr = IXMLDOMAttribute_get_nodeName(pAttribute, &str);
-                    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                    ok( !lstrcmpW( str, L"Attr" ), "incorrect nodeName string\n");
-                    SysFreeString(str);
+                    /* test nodeName */
+                    hr = IXMLDOMAttribute_get_nodeName(pAttribute, &str);
+                    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+                    ok( !lstrcmpW( str, L"Attr" ), "incorrect nodeName string\n");
+                    SysFreeString(str);
 
                     /* test name property */
                     hr = IXMLDOMAttribute_get_name(pAttribute, &str);
@@ -6199,380 +5969,69 @@ static void test_xmlTypes(void)
                 IXMLDOMElement_Release(pElement);
             }
 
-            /* CData Section */
-            str = SysAllocString(L"[1]*2=3; &gee that is not right!");
-            hr = IXMLDOMDocument_createCDATASection(doc, str, NULL);
+            /* Document Fragments */
+            hr = IXMLDOMDocument_createDocumentFragment(doc, NULL);
             ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
 
-            hr = IXMLDOMDocument_createCDATASection(doc, str, &pCDataSec);
-            SysFreeString(str);
+            hr = IXMLDOMDocument_createDocumentFragment(doc, &pDocFrag);
             ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
             if(hr == S_OK)
             {
-                IXMLDOMNode *pNextChild = (IXMLDOMNode *)0x1;
-                VARIANT var;
-
-                VariantInit(&var);
-
-                hr = IXMLDOMCDATASection_QueryInterface(pCDataSec, &IID_IXMLDOMElement, (void**)&pElement);
-                ok(hr == E_NOINTERFACE, "Unexpected hr %#lx.\n", hr);
-
-                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pCDataSec, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_nodeName(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"#cdata-section" ), "incorrect cdata node Name\n");
-                SysFreeString(str);
+                IXMLDOMNode *node;
 
-                hr = IXMLDOMCDATASection_get_xml(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"<![CDATA[[1]*2=3; &gee that is not right!]]>" ), "incorrect cdata xml\n");
-                SysFreeString(str);
+                hr = IXMLDOMDocumentFragment_get_parentNode(pDocFrag, NULL);
+                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
 
-                /* test lastChild */
-                pNextChild = (IXMLDOMNode*)0x1;
-                hr = IXMLDOMCDATASection_get_lastChild(pCDataSec, &pNextChild);
+                node = (IXMLDOMNode *)0x1;
+                hr = IXMLDOMDocumentFragment_get_parentNode(pDocFrag, &node);
                 ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok(pNextChild == NULL, "pNextChild not NULL\n");
-
-                /* put data Tests */
-                hr = IXMLDOMCDATASection_put_data(pCDataSec, _bstr_("This &is a ; test <>\\"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                /* Confirm XML text is good */
-                hr = IXMLDOMCDATASection_get_xml(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"<![CDATA[This &is a ; test <>\\]]>"), "incorrect xml string\n");
-                SysFreeString(str);
-
-                /* Confirm we get the put_data Text back */
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect text string\n");
-                SysFreeString(str);
+                ok(node == NULL, "expected NULL, got %p\n", node);
 
-                /* test length property */
-                hr = IXMLDOMCDATASection_get_length(pCDataSec, &len);
+                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pDocFrag, NULL);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 21, "expected 21 got %ld\n", len);
 
-                /* test get data */
-                hr = IXMLDOMCDATASection_get_data(pCDataSec, &str);
+                hr = IXMLDOMDocumentFragment_get_nodeName(pDocFrag, &str);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect text string\n");
+                ok( !lstrcmpW( str, L"#document-fragment" ), "incorrect docfragment node Name\n");
                 SysFreeString(str);
 
-                /* test substringData */
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 0, 4, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                /* test substringData - Invalid offset */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, -1, 4, &str);
+                /* test next Sibling*/
+                hr = IXMLDOMDocumentFragment_get_nextSibling(pDocFrag, NULL);
                 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
 
-                /* test substringData - Invalid offset */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 30, 0, &str);
+                node = (IXMLDOMNode *)0x1;
+                hr = IXMLDOMDocumentFragment_get_nextSibling(pDocFrag, &node);
                 ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
+                ok(node == NULL, "next sibling not NULL\n");
 
-                /* test substringData - Invalid size */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 0, -1, &str);
+                /* test Previous Sibling*/
+                hr = IXMLDOMDocumentFragment_get_previousSibling(pDocFrag, NULL);
                 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
 
-                /* test substringData - Invalid size */
-                str = (void *)0xdeadbeef;
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 2, 0, &str);
+                node = (IXMLDOMNode *)0x1;
+                hr = IXMLDOMDocumentFragment_get_previousSibling(pDocFrag, &node);
                 ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok( str == NULL, "incorrect string\n");
+                ok(node == NULL, "previous sibling not NULL\n");
 
-                /* test substringData - Start of string */
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 0, 4, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This"), "incorrect substringData string\n");
-                SysFreeString(str);
+                IXMLDOMDocumentFragment_Release(pDocFrag);
+            }
 
-                /* test substringData - Middle of string */
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 13, 4, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"test"), "incorrect substringData string\n");
-                SysFreeString(str);
+            /* Entity References */
+            hr = IXMLDOMDocument_createEntityReference(doc, NULL, &pEntityRef);
+            ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
+            hr = IXMLDOMDocument_createEntityReference(doc, _bstr_(""), &pEntityRef);
+            ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
 
-                /* test substringData - End of string */
-                hr = IXMLDOMCDATASection_substringData(pCDataSec, 20, 4, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"\\"), "incorrect substringData string\n");
-                SysFreeString(str);
+            str = SysAllocString(L"entityref");
+            hr = IXMLDOMDocument_createEntityReference(doc, str, NULL);
+            ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
 
-                /* test appendData */
-                hr = IXMLDOMCDATASection_appendData(pCDataSec, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_appendData(pCDataSec, _bstr_(""));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_appendData(pCDataSec, _bstr_("Append"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"This &is a ; test <>\\Append"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* test insertData */
-                str = SysAllocStringLen(NULL, 0);
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, -1, str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, -1, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 1000, str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 1000, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                SysFreeString(str);
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, -1, _bstr_("Inserting"));
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 1000, _bstr_("Inserting"));
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, _bstr_("Begin "));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 17, _bstr_("Middle"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 39, _bstr_(" End"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"Begin This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete data */
-                /* invalid arguments */
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, -1, 1);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 0, 0);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 0, -1);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_length(pCDataSec, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 43, "expected 43 got %ld\n", len);
-
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, len, 1);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, len+1, 1);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                /* delete from start */
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 0, 5);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_length(pCDataSec, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 38, "expected 38 got %ld\n", len);
-
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete from end */
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 35, 3);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_length(pCDataSec, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 35, "expected 35 got %ld\n", len);
-
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append "), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete from inside */
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 1, 33);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_get_length(pCDataSec, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(len == 2, "expected 2 got %ld\n", len);
-
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"  "), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* delete whole data ... */
-                hr = IXMLDOMCDATASection_get_length(pCDataSec, &len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 0, len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                /* ... and try again with empty string */
-                hr = IXMLDOMCDATASection_deleteData(pCDataSec, 0, len);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                /* ::replaceData() */
-                V_VT(&v) = VT_BSTR;
-                V_BSTR(&v) = SysAllocString(L"str1");
-                hr = IXMLDOMCDATASection_put_nodeValue(pCDataSec, v);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                VariantClear(&v);
-
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 6, 0, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 0, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* NULL pointer means delete */
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 1, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"tr1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* empty string means delete */
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 1, _bstr_(""));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"r1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* zero count means insert */
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 0, _bstr_("a"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"ar1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 2, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMCDATASection_insertData(pCDataSec, 0, _bstr_("m"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"m1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* nonempty string, count greater than its length */
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 2, _bstr_("a1.2"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"a1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                /* nonempty string, count less than its length */
-                hr = IXMLDOMCDATASection_replaceData(pCDataSec, 0, 1, _bstr_("wine"));
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                hr = IXMLDOMCDATASection_get_text(pCDataSec, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok(!lstrcmpW(str, L"wine1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
-                SysFreeString(str);
-
-                IXMLDOMCDATASection_Release(pCDataSec);
-            }
-
-            /* Document Fragments */
-            hr = IXMLDOMDocument_createDocumentFragment(doc, NULL);
-            ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-            hr = IXMLDOMDocument_createDocumentFragment(doc, &pDocFrag);
-            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-            if(hr == S_OK)
-            {
-                IXMLDOMNode *node;
-
-                hr = IXMLDOMDocumentFragment_get_parentNode(pDocFrag, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                node = (IXMLDOMNode *)0x1;
-                hr = IXMLDOMDocumentFragment_get_parentNode(pDocFrag, &node);
-                ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok(node == NULL, "expected NULL, got %p\n", node);
-
-                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pDocFrag, NULL);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-
-                hr = IXMLDOMDocumentFragment_get_nodeName(pDocFrag, &str);
-                ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-                ok( !lstrcmpW( str, L"#document-fragment" ), "incorrect docfragment node Name\n");
-                SysFreeString(str);
-
-                /* test next Sibling*/
-                hr = IXMLDOMDocumentFragment_get_nextSibling(pDocFrag, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                node = (IXMLDOMNode *)0x1;
-                hr = IXMLDOMDocumentFragment_get_nextSibling(pDocFrag, &node);
-                ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok(node == NULL, "next sibling not NULL\n");
-
-                /* test Previous Sibling*/
-                hr = IXMLDOMDocumentFragment_get_previousSibling(pDocFrag, NULL);
-                ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-                node = (IXMLDOMNode *)0x1;
-                hr = IXMLDOMDocumentFragment_get_previousSibling(pDocFrag, &node);
-                ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
-                ok(node == NULL, "previous sibling not NULL\n");
-
-                IXMLDOMDocumentFragment_Release(pDocFrag);
-            }
-
-            /* Entity References */
-            hr = IXMLDOMDocument_createEntityReference(doc, NULL, &pEntityRef);
-            ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
-            hr = IXMLDOMDocument_createEntityReference(doc, _bstr_(""), &pEntityRef);
-            ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
-
-            str = SysAllocString(L"entityref");
-            hr = IXMLDOMDocument_createEntityReference(doc, str, NULL);
-            ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
-
-            hr = IXMLDOMDocument_createEntityReference(doc, str, &pEntityRef);
-            SysFreeString(str);
-            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-            if(hr == S_OK)
-            {
-                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pEntityRef, NULL);
+            hr = IXMLDOMDocument_createEntityReference(doc, str, &pEntityRef);
+            SysFreeString(str);
+            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+            if(hr == S_OK)
+            {
+                hr = IXMLDOMElement_appendChild(pRoot, (IXMLDOMNode*)pEntityRef, NULL);
                 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
 
                 /* test get_xml*/
@@ -6782,10 +6241,7 @@ static void test_save(void)
     IXMLDOMDocument_Release(doc2);
 
     /* save to path */
-    V_VT(&dest) = VT_BSTR;
-    V_BSTR(&dest) = _bstr_("test.xml");
-
-    hr = IXMLDOMDocument_save(doc, dest);
+    hr = IXMLDOMDocument_save(doc, _variantbstr_("test.xml"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     hfile = CreateFileA("test.xml", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
@@ -6800,12 +6256,13 @@ static void test_save(void)
     DeleteFileA("test.xml");
 
     /* save to path VT_BSTR | VT_BYREF */
-    filename = _bstr_("test.xml");
+    filename = SysAllocString(L"test.xml");
     V_VT(&dest) = VT_BSTR | VT_BYREF;
     V_BSTRREF(&dest) = &filename;
 
     hr = IXMLDOMDocument_save(doc, dest);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&dest);
 
     hfile = CreateFileA("test.xml", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
     ok(hfile != INVALID_HANDLE_VALUE, "Could not open file: %lu\n", GetLastError());
@@ -6887,10 +6344,7 @@ static void test_save(void)
     hr = IXMLDOMElement_setAttributeNode(root, attr, NULL);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    V_VT(&dest) = VT_BSTR;
-    V_BSTR(&dest) = _bstr_("test.xml");
-
-    hr = IXMLDOMDocument_save(doc, dest);
+    hr = IXMLDOMDocument_save(doc, _variantbstr_("test.xml"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     hfile = CreateFileA("test.xml", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
@@ -7003,17 +6457,11 @@ static void test_namespaces_change(void)
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
         /* try same prefix, different uri */
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = _bstr_("ns/uri2");
-
-        hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var);
+        hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), _variantbstr_("ns/uri2"));
         ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
 
         /* try same prefix and uri */
-        V_VT(&var) = VT_BSTR;
-        V_BSTR(&var) = _bstr_("ns/uri");
-
-        hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), var);
+        hr = IXMLDOMElement_setAttribute(elem, _bstr_("xmlns:ns"), _variantbstr_("ns/uri"));
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
         hr = IXMLDOMElement_get_xml(elem, &str);
@@ -7124,42 +6572,6 @@ static void test_namespaces_basic(void)
     free_bstrs();
 }
 
-static void test_FormattingXML(void)
-{
-    IXMLDOMDocument *doc;
-    IXMLDOMElement *pElement;
-    VARIANT_BOOL bSucc;
-    HRESULT hr;
-    BSTR str;
-    static const CHAR szLinefeedXML[] = "<?xml version=\"1.0\"?>\n<Root>\n\t<Sub val=\"A\" />\n</Root>";
-    static const CHAR szLinefeedRootXML[] = "<Root>\r\n\t<Sub val=\"A\"/>\r\n</Root>";
-
-    doc = create_document(&IID_IXMLDOMDocument);
-
-    hr = IXMLDOMDocument_loadXML(doc, _bstr_(szLinefeedXML), &bSucc);
-    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    ok(bSucc == VARIANT_TRUE, "Expected VARIANT_TRUE got VARIANT_FALSE\n");
-
-    if(bSucc == VARIANT_TRUE)
-    {
-        hr = IXMLDOMDocument_get_documentElement(doc, &pElement);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-        if(hr == S_OK)
-        {
-            hr = IXMLDOMElement_get_xml(pElement, &str);
-            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-            ok( !lstrcmpW( str, _bstr_(szLinefeedRootXML) ), "incorrect element xml\n");
-            SysFreeString(str);
-
-            IXMLDOMElement_Release(pElement);
-        }
-    }
-
-    IXMLDOMDocument_Release(doc);
-
-    free_bstrs();
-}
-
 typedef struct _nodetypedvalue_t {
     const char *name;
     VARTYPE type;
@@ -7564,9 +6976,7 @@ static void test_put_nodeValue(void)
     /* NODE_DOCUMENT */
     hr = IXMLDOMDocument_QueryInterface(doc, &IID_IXMLDOMNode, (void**)&node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("one two three");
-    hr = IXMLDOMNode_put_nodeValue(node, data);
+    hr = IXMLDOMNode_put_nodeValue(node, _variantbstr_("one two three"));
     ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
     IXMLDOMNode_Release(node);
 
@@ -7575,9 +6985,7 @@ static void test_put_nodeValue(void)
     V_I1(&type) = NODE_DOCUMENT_FRAGMENT;
     hr = IXMLDOMDocument_createNode(doc, type, _bstr_("test"), NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("one two three");
-    hr = IXMLDOMNode_put_nodeValue(node, data);
+    hr = IXMLDOMNode_put_nodeValue(node, _variantbstr_("one two three"));
     ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
     IXMLDOMNode_Release(node);
 
@@ -7586,9 +6994,7 @@ static void test_put_nodeValue(void)
     V_I1(&type) = NODE_ELEMENT;
     hr = IXMLDOMDocument_createNode(doc, type, _bstr_("test"), NULL, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("one two three");
-    hr = IXMLDOMNode_put_nodeValue(node, data);
+    hr = IXMLDOMNode_put_nodeValue(node, _variantbstr_("one two three"));
     ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
     IXMLDOMNode_Release(node);
 
@@ -7596,16 +7002,12 @@ static void test_put_nodeValue(void)
     hr = IXMLDOMDocument_createEntityReference(doc, _bstr_("ref"), &entityref);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
 
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("one two three");
-    hr = IXMLDOMEntityReference_put_nodeValue(entityref, data);
+    hr = IXMLDOMEntityReference_put_nodeValue(entityref, _variantbstr_("one two three"));
     ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
 
     hr = IXMLDOMEntityReference_QueryInterface(entityref, &IID_IXMLDOMNode, (void**)&node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("one two three");
-    hr = IXMLDOMNode_put_nodeValue(node, data);
+    hr = IXMLDOMNode_put_nodeValue(node, _variantbstr_("one two three"));
     ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr );
     IXMLDOMNode_Release(node);
     IXMLDOMEntityReference_Release(entityref);
@@ -7613,17 +7015,13 @@ static void test_put_nodeValue(void)
     /* supported types */
     hr = IXMLDOMDocument_createTextNode(doc, _bstr_(""), &text);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("Jeeves & Wooster");
-    hr = IXMLDOMText_put_nodeValue(text, data);
+    hr = IXMLDOMText_put_nodeValue(text, _variantbstr_("Jeeves & Wooster"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
     IXMLDOMText_Release(text);
 
     hr = IXMLDOMDocument_createAttribute(doc, _bstr_("attr"), &attr);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
-    V_VT(&data) = VT_BSTR;
-    V_BSTR(&data) = _bstr_("Jeeves & Wooster");
-    hr = IXMLDOMAttribute_put_nodeValue(attr, data);
+    hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("Jeeves & Wooster"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
     hr = IXMLDOMAttribute_get_nodeValue(attr, &data);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
@@ -8523,7 +7921,6 @@ static void test_setAttributeNode(void)
     IXMLDOMAttribute *attr, *attr2, *ret_attr;
     VARIANT_BOOL b;
     HRESULT hr;
-    VARIANT v;
     BSTR str;
     ULONG ref1, ref2;
 
@@ -8616,9 +8013,7 @@ static void test_setAttributeNode(void)
     ref1 = IXMLDOMAttribute_AddRef(attr);
     IXMLDOMAttribute_Release(attr);
 
-    V_VT(&v) = VT_BSTR;
-    V_BSTR(&v) = _bstr_("attrvalue1");
-    hr = IXMLDOMAttribute_put_nodeValue(attr, v);
+    hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("attrvalue1"));
     ok( hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     str = NULL;
@@ -8644,9 +8039,7 @@ static void test_setAttributeNode(void)
         "got %s\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    V_VT(&v) = VT_BSTR;
-    V_BSTR(&v) = _bstr_("attrvalue2");
-    hr = IXMLDOMAttribute_put_nodeValue(attr, v);
+    hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("attrvalue2"));
     ok( hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     hr = IXMLDOMElement_get_xml(elem, &str);
@@ -8753,6 +8146,7 @@ static const char get_prefix_doc[] =
 static void test_get_prefix(void)
 {
     IXMLDOMDocumentFragment *fragment;
+    IXMLDOMProcessingInstruction *pi;
     IXMLDOMCDATASection *cdata;
     IXMLDOMElement *element;
     IXMLDOMComment *comment;
@@ -8859,6 +8253,22 @@ static void test_get_prefix(void)
     ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
     ok(str == NULL, "got %s\n", wine_dbgstr_w(str));
 
+    /* PI */
+    hr = IXMLDOMDocument_createProcessingInstruction(doc, _bstr_("ns:target"), _bstr_("data"), &pi);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMProcessingInstruction_get_prefix(pi, &str);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!str, "Unexpected prefix %s.\n", debugstr_w(str));
+
+    hr = IXMLDOMProcessingInstruction_get_baseName(pi, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"ns:target"), "Unexpected name %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMProcessingInstruction_Release(pi);
+
     IXMLDOMDocument_Release(doc);
     free_bstrs();
 }
@@ -9000,9 +8410,7 @@ static void test_createProcessingInstruction(void)
 {
     static const WCHAR xml1[] = L"<?xml version=\"1.0\"?>\r\n<test/>\r\n";
     static const char xml2[] = "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\r\n<test/>\r\n";
-    static const char xml2_wine[] = "<?xml version=\"1.0\" encoding=\"windows-1252\"?>\n<test/>\n";
     static const char xml3[] = "<?xml version=\"1.0\" standalone=\"yes\"?>\r\n<test/>\r\n";
-    static const char xml3_wine[] = "<?xml version=\"1.0\" standalone=\"yes\"?>\n<test/>\n";
     IXMLDOMProcessingInstruction *pi;
     IXMLDOMDocument *doc;
     IXMLDOMNode *node, *item;
@@ -9114,7 +8522,8 @@ static void test_createProcessingInstruction(void)
     hr = GetHGlobalFromStream(stream, &global);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     p = GlobalLock(global);
-    ok(!memcmp(p, xml2, sizeof(xml2) - 1) || !memcmp(p, xml2_wine, sizeof(xml2_wine) - 1), "got %s\n", wine_dbgstr_a(p));
+    todo_wine
+    ok(!memcmp(p, xml2, sizeof(xml2) - 1), "Unexpected output %s.\n", wine_dbgstr_a(p));
     GlobalUnlock(global);
 
     /* Verify the result after load+save */
@@ -9136,7 +8545,8 @@ static void test_createProcessingInstruction(void)
     hr = GetHGlobalFromStream(stream, &global);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     p = GlobalLock(global);
-    ok(!memcmp(p, xml2, sizeof(xml2) - 1) || !memcmp(p, xml2_wine, sizeof(xml2_wine) - 1), "got %s\n", wine_dbgstr_a(p));
+    todo_wine
+    ok(!memcmp(p, xml2, sizeof(xml2) - 1), "Unexpected output %s.\n", wine_dbgstr_a(p));
     GlobalUnlock(global);
 
     IStream_Release(stream);
@@ -9157,7 +8567,8 @@ static void test_createProcessingInstruction(void)
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     p = GlobalLock(global);
-    ok(!memcmp(p, xml3, sizeof(xml3) - 1) || !memcmp(p, xml3_wine, sizeof(xml3_wine) - 1), "got %s\n", wine_dbgstr_a(p));
+    todo_wine
+    ok(!memcmp(p, xml3, sizeof(xml3) - 1), "Unexpected output %s.\n", wine_dbgstr_a(p));
     GlobalUnlock(global);
 
     IStream_Release(stream);
@@ -9204,17 +8615,14 @@ static void test_put_nodeTypedValue(void)
     hr = IXMLDOMElement_get_nodeTypedValue(elem, &type);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(V_VT(&type) == VT_BSTR, "got %d, expected VT_BSTR\n", V_VT(&type));
-    ok(memcmp(V_BSTR(&type), L"1", 2*sizeof(WCHAR)) == 0,
-       "got %s, expected \"1\"\n", wine_dbgstr_w(V_BSTR(&type)));
+    ok(!wcscmp(V_BSTR(&type), L"1"), "Unexpected value %s.\n", wine_dbgstr_w(V_BSTR(&type)));
     VariantClear(&type);
 
     /* int */
     hr = IXMLDOMElement_put_dataType(elem, _bstr_("int"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    V_VT(&value) = VT_BSTR;
-    V_BSTR(&value) = _bstr_("1");
-    hr = IXMLDOMElement_put_nodeTypedValue(elem, value);
+    hr = IXMLDOMElement_put_nodeTypedValue(elem, _variantbstr_("1"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     V_VT(&value) = VT_EMPTY;
@@ -9247,9 +8655,7 @@ static void test_put_nodeTypedValue(void)
     hr = IXMLDOMElement_put_dataType(elem, _bstr_("bin.base64"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    V_VT(&value) = VT_BSTR;
-    V_BSTR(&value) = _bstr_("ABCD");
-    hr = IXMLDOMElement_put_nodeTypedValue(elem, value);
+    hr = IXMLDOMElement_put_nodeTypedValue(elem, _variantbstr_("ABCD"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     V_VT(&value) = VT_EMPTY;
@@ -9323,9 +8729,7 @@ static void test_put_nodeTypedValue(void)
     SysFreeString(str);
 
     /* bin.hex */
-    V_VT(&value) = VT_BSTR;
-    V_BSTR(&value) = _bstr_("");
-    hr = IXMLDOMElement_put_nodeTypedValue(elem, value);
+    hr = IXMLDOMElement_put_nodeTypedValue(elem, _variantbstr_(""));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     hr = IXMLDOMElement_put_dataType(elem, _bstr_("bin.hex"));
@@ -9378,12 +8782,7 @@ static void test_put_nodeTypedValue(void)
 
 static void test_get_xml(void)
 {
-    static const char xmlA[] = "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n<a>test</a>\r\n";
-    static const char attrA[] = "attr=\"&quot;a &amp; b&quot;\"";
-    static const char attr2A[] = "\"a & b\"";
-    static const char attr3A[] = "attr=\"&amp;quot;a\"";
-    static const char attr4A[] = "&quot;a";
-    static const char fooA[] = "<foo/>";
+    static const char xml2A[] = "<?xml version=\"1.0\"?>\n<Root>\n\t<Sub val=\"A\" />\n</Root>";
     IXMLDOMProcessingInstruction *pi;
     IXMLDOMNode *first;
     IXMLDOMElement *elem = NULL;
@@ -9419,9 +8818,7 @@ static void test_get_xml(void)
 
     hr = IXMLDOMDocument_get_xml(doc, &xml);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
-    ok(memcmp(xml, _bstr_(xmlA), sizeof(xmlA)*sizeof(WCHAR)) == 0,
-        "got %s, expected %s\n", wine_dbgstr_w(xml), xmlA);
+    ok(!wcscmp(xml, L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n<a>test</a>\r\n"), "Unexpected %s.\n", wine_dbgstr_w(xml));
     SysFreeString(xml);
 
     IXMLDOMDocument_Release(doc);
@@ -9436,9 +8833,7 @@ static void test_get_xml(void)
 
     hr = IXMLDOMDocument_get_xml(doc, &xml);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
-    ok(memcmp(xml, _bstr_(fooA), (sizeof(fooA)-1)*sizeof(WCHAR)) == 0,
-        "got %s, expected %s\n", wine_dbgstr_w(xml), fooA);
+    ok(!wcscmp(xml, L"<foo/>\r\n"), "Unexpected %s.\n", debugstr_w(xml));
     SysFreeString(xml);
 
     IXMLDOMElement_Release(elem);
@@ -9447,46 +8842,65 @@ static void test_get_xml(void)
     hr = IXMLDOMDocument_createAttribute(doc, _bstr_("attr"), &attr);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    V_VT(&v) = VT_BSTR;
-    V_BSTR(&v) = _bstr_("\"a & b\"");
-    hr = IXMLDOMAttribute_put_value(attr, v);
+    hr = IXMLDOMAttribute_put_value(attr, _variantbstr_("\"a & b\""));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     xml = NULL;
     hr = IXMLDOMAttribute_get_xml(attr, &xml);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    ok(!memcmp(xml, _bstr_(attrA), (sizeof(attrA)-1)*sizeof(WCHAR)), "got %s\n", wine_dbgstr_w(xml));
+    ok(!wcscmp(xml, L"attr=\"&quot;a &amp; b&quot;\""), "Unexpected %s.\n", wine_dbgstr_w(xml));
     SysFreeString(xml);
 
     VariantInit(&v);
     hr = IXMLDOMAttribute_get_value(attr, &v);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(V_VT(&v) == VT_BSTR, "got type %d\n", V_VT(&v));
-    ok(!memcmp(V_BSTR(&v), _bstr_(attr2A), (sizeof(attr2A)-1)*sizeof(WCHAR)),
-        "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
+    ok(!wcscmp(V_BSTR(&v), L"\"a & b\""), "Unexpected %s.\n", debugstr_w(V_BSTR(&v)));
     VariantClear(&v);
 
-    V_VT(&v) = VT_BSTR;
-    V_BSTR(&v) = _bstr_("&quot;a");
-    hr = IXMLDOMAttribute_put_value(attr, v);
+    hr = IXMLDOMAttribute_put_value(attr, _variantbstr_("&quot;a"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     xml = NULL;
     hr = IXMLDOMAttribute_get_xml(attr, &xml);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    ok(!memcmp(xml, _bstr_(attr3A), (sizeof(attr3A)-1)*sizeof(WCHAR)), "got %s\n", wine_dbgstr_w(xml));
+    ok(!wcscmp(xml, L"attr=\"&amp;quot;a\""), "Unexpected %s.\n", debugstr_w(xml));
     SysFreeString(xml);
 
     VariantInit(&v);
     hr = IXMLDOMAttribute_get_value(attr, &v);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(V_VT(&v) == VT_BSTR, "got type %d\n", V_VT(&v));
-    ok(!memcmp(V_BSTR(&v), _bstr_(attr4A), (sizeof(attr4A)-1)*sizeof(WCHAR)),
-        "got %s\n", wine_dbgstr_w(V_BSTR(&v)));
+    ok(!wcscmp(V_BSTR(&v), L"&quot;a"), "Unexpected %s.\n", debugstr_w(V_BSTR(&v)));
     VariantClear(&v);
 
     IXMLDOMAttribute_Release(attr);
 
+    /* More complicated formatting */
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_(xml2A), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &elem);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+    hr = IXMLDOMElement_get_xml(elem, &xml);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(!lstrcmpW(xml, L"<Root>\r\n\t<Sub val=\"A\"/>\r\n</Root>"), "Unexpected xml %s.\n", debugstr_w(xml));
+    SysFreeString(xml);
+
+    IXMLDOMElement_Release(elem);
+
+    /* Excessive namespace definitions */
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_("<a xmlns:ns=\"uri\" ><b ns:attr=\"value\" xmlns:ns=\"uri\" /></a>"), &b );
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_xml(doc, &xml);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(xml, L"<a xmlns:ns=\"uri\"><b ns:attr=\"value\" xmlns:ns=\"uri\"/></a>\r\n"),
+            "Unexpected xml %s.\n", wine_dbgstr_w(xml));
+    SysFreeString(xml);
+
     IXMLDOMDocument_Release(doc);
 
     free_bstrs();
@@ -10102,8 +9516,17 @@ static void test_insertBefore(void)
 
 static void test_appendChild(void)
 {
+    IXMLDOMComment *comment1, *comment2;
+    IXMLDOMDocumentFragment *fragment;
+    IXMLDOMProcessingInstruction *pi;
     IXMLDOMDocument *doc, *doc2;
     IXMLDOMElement *elem, *elem2;
+    IXMLDOMText *text1, *text2;
+    IXMLDOMNodeList *list;
+    DOMNodeType node_type;
+    IXMLDOMNode *node;
+    LONG length;
+    VARIANT var;
     HRESULT hr;
 
     doc = create_document(&IID_IXMLDOMDocument);
@@ -10143,6 +9566,100 @@ static void test_appendChild(void)
     IXMLDOMElement_Release(elem2);
     IXMLDOMDocument_Release(doc);
     IXMLDOMDocument_Release(doc2);
+
+    /* Append a child to a document */
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    hr = IXMLDOMDocument_createElement(doc, _bstr_("elem"), &elem);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createElement(doc, _bstr_("elem2"), &elem2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)elem, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)elem2, NULL);
+    todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createComment(doc, _bstr_("Comment1"), &comment1);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_createComment(doc, _bstr_("Comment2"), &comment2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)comment1, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    V_VT(&var) = VT_DISPATCH;
+    V_DISPATCH(&var) = (IDispatch *)elem;
+    hr = IXMLDOMDocument_insertBefore(doc, (IXMLDOMNode *)comment2, var, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    IXMLDOMComment_Release(comment1);
+    IXMLDOMComment_Release(comment2);
+
+    hr = IXMLDOMDocument_createProcessingInstruction(doc, _bstr_("xml"), _bstr_("version=\"1.0\""), &pi);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_appendChild(doc, (IXMLDOMNode *)pi, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    IXMLDOMProcessingInstruction_Release(pi);
+
+    IXMLDOMElement_Release(elem);
+    IXMLDOMElement_Release(elem2);
+
+    /* Append document fragment with multiple children. */
+    hr = IXMLDOMDocument_createDocumentFragment(doc, &fragment);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createTextNode(doc, _bstr_("text1"), &text1);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_createTextNode(doc, _bstr_("text2"), &text2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    EXPECT_NO_CHILDREN(fragment);
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)text1, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)text2, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    EXPECT_CHILDREN(fragment);
+
+    hr = IXMLDOMDocument_createElement(doc, _bstr_("elem"), &elem);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_appendChild(elem, (IXMLDOMNode *)fragment, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(node == (IXMLDOMNode *)fragment, "Unexpected child %p.\n", node);
+    IXMLDOMNode_Release(node);
+    todo_wine
+    EXPECT_NO_CHILDREN(fragment);
+
+    hr = IXMLDOMElement_get_childNodes(elem, &list);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNodeList_get_length(list, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(length == 2, "Unexpected length %ld.\n", length);
+    while (IXMLDOMNodeList_nextNode(list, &node) == S_OK)
+    {
+        hr = IXMLDOMNode_get_nodeType(node, &node_type);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+        todo_wine
+        ok(node_type == NODE_TEXT, "Unexpected type %d.\n", node_type);
+        IXMLDOMNode_Release(node);
+    }
+
+    IXMLDOMNodeList_Release(list);
+
+    IXMLDOMElement_Release(elem);
+    IXMLDOMText_Release(text1);
+    IXMLDOMText_Release(text2);
+    IXMLDOMDocumentFragment_Release(fragment);
+
+    IXMLDOMDocument_Release(doc);
 }
 
 static void test_get_doctype(void)
@@ -10151,6 +9668,7 @@ static void test_get_doctype(void)
     IXMLDOMDocument *doc;
     VARIANT_BOOL b;
     HRESULT hr;
+    VARIANT v;
     BSTR s;
 
     doc = create_document(&IID_IXMLDOMDocument);
@@ -10180,6 +9698,17 @@ static void test_get_doctype(void)
     ok(!lstrcmpW(L"email", s), "got name %s\n", wine_dbgstr_w(s));
     SysFreeString(s);
 
+    hr = IXMLDOMDocumentType_get_nodeValue(doctype, NULL);
+    todo_wine
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    V_VT(&v) = VT_EMPTY;
+    hr = IXMLDOMDocumentType_get_nodeValue(doctype, &v);
+    todo_wine
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(V_VT(&v) == VT_NULL, "Unexpected type %d.\n", V_VT(&v));
+
     hr = IXMLDOMDocumentType_get_nodeName(doctype, &s);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!lstrcmpW(L"email", s), "got name %s\n", wine_dbgstr_w(s));
@@ -10419,7 +9948,6 @@ static void test_get_attributes(void)
     {
         IXMLDOMAttribute *attr;
         DOMNodeType type;
-        VARIANT v;
 
         node2 = NULL;
         hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node2);
@@ -10482,9 +10010,7 @@ static void test_get_attributes(void)
         hr = IXMLDOMDocument_createAttribute(doc, _bstr_("encoding"), &attr);
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-        V_VT(&v) = VT_BSTR;
-        V_BSTR(&v) = _bstr_("UTF-8");
-        hr = IXMLDOMAttribute_put_nodeValue(attr, v);
+        hr = IXMLDOMAttribute_put_nodeValue(attr, _variantbstr_("UTF-8"));
         ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
         EXPECT_REF(attr, 2);
@@ -12463,10 +11989,12 @@ static void test_supporterrorinfo(void)
     ISupportErrorInfo *errorinfo, *info2;
     IXMLDOMSchemaCollection *schemacache;
     IXMLDOMNamedNodeMap *map, *map2;
+    IXMLDOMDocumentType *doctype;
     IXMLDOMDocument *doc;
     IXMLDOMElement *elem;
     VARIANT_BOOL b;
     IUnknown *unk;
+    LONG refcount;
     REFIID *iid;
     void *dummy;
     HRESULT hr;
@@ -12602,6 +12130,38 @@ static void test_supporterrorinfo(void)
     ISupportErrorInfo_Release(errorinfo);
     IXMLDOMSchemaCollection_Release(schemacache);
 
+    /* IXMLDOMDocumentType */
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_(szEmailXML), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_TRUE, "Unexpected value %d.\n", b);
+
+    hr = IXMLDOMDocument_get_doctype(doc, &doctype);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    refcount = get_refcount(doctype);
+    hr = IXMLDOMDocumentType_QueryInterface(doctype, &IID_ISupportErrorInfo, (void **)&errorinfo);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(refcount == get_refcount(doctype), "Unexpected refcount %ld.\n", refcount);
+
+if (hr == S_OK)
+{
+    check_interface(errorinfo, &IID_IXMLDOMNode, FALSE);
+
+    hr = ISupportErrorInfo_InterfaceSupportsErrorInfo(errorinfo, &IID_IXMLDOMNode);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = ISupportErrorInfo_InterfaceSupportsErrorInfo(errorinfo, &IID_IXMLDOMDocumentType);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    ISupportErrorInfo_Release(errorinfo);
+}
+    IXMLDOMDocumentType_Release(doctype);
+
+    IXMLDOMDocument_Release(doc);
+
     free_bstrs();
 }
 
@@ -12648,9 +12208,7 @@ static void test_nodeValue(void)
         hr = IXMLDOMNode_get_nodeValue(node, NULL);
         ok(hr == E_INVALIDARG, "%d: unexpected hr %#lx\n", ptr->type, hr);
 
-        V_VT(&v) = VT_BSTR;
-        V_BSTR(&v) = _bstr_(ptr->put_content);
-        hr = IXMLDOMNode_put_nodeValue(node, v);
+        hr = IXMLDOMNode_put_nodeValue(node, _variantbstr_(ptr->put_content));
         ok(hr == ptr->put_hr, "%d: unexpected hr %#lx\n", ptr->type, hr);
 
         V_VT(&v) = VT_EMPTY;
@@ -12665,6 +12223,8 @@ static void test_nodeValue(void)
         IXMLDOMNode_Release(node);
 
         ptr++;
+
+        free_bstrs();
     }
 
     IXMLDOMDocument_Release(doc);
@@ -12678,7 +12238,6 @@ static void test_xmlns_attribute(void)
     IXMLDOMAttribute *pAttribute;
     IXMLDOMElement *elem;
     HRESULT hr;
-    VARIANT v;
 
     doc = create_document(&IID_IXMLDOMDocument);
 
@@ -12691,9 +12250,7 @@ static void test_xmlns_attribute(void)
     hr = IXMLDOMDocument_createAttribute(doc, _bstr_("xmlns:dt"), &pAttribute);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
 
-    V_VT(&v) = VT_BSTR;
-    V_BSTR(&v) = _bstr_("urn:schemas-microsoft-com:datatypes");
-    hr = IXMLDOMAttribute_put_nodeValue(pAttribute, v);
+    hr = IXMLDOMAttribute_put_nodeValue(pAttribute, _variantbstr_("urn:schemas-microsoft-com:datatypes"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
 
     hr = IXMLDOMElement_setAttributeNode(root, pAttribute, NULL);
@@ -14245,7 +13802,6 @@ static void test_load_with_site(void)
     char path[MAX_PATH];
     IXMLDOMDocument2 *doc;
     IObjectWithSite *site;
-    VARIANT var;
     VARIANT_BOOL b;
     HRESULT hr;
 
@@ -14275,9 +13831,7 @@ static void test_load_with_site(void)
        "QI(SID_SInternetHostSecurityManager, IID_IXMLDOMDocument) was not called\n");
 
     qi_count = 0;
-    V_VT(&var) = VT_BSTR;
-    V_BSTR(&var) = _bstr_(path);
-    hr = IXMLDOMDocument2_load(doc, var, &b);
+    hr = IXMLDOMDocument2_load(doc, _variantbstr_(path), &b);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(b == VARIANT_TRUE, "got %d\n", b);
     ok(qi_count == 0, "got %d QI calls\n", qi_count);
@@ -14452,227 +14006,2276 @@ static void test_put_text(void)
     if (winetest_platform_is_wine) /* put_text causes ASan errors and crash in Release */
         return;
 
-    doc = create_document(&IID_IXMLDOMDocument2);
+    doc = create_document(&IID_IXMLDOMDocument2);
+
+    b = VARIANT_FALSE;
+    str = SysAllocString(L"<?xml version='1.0' encoding='UTF-16'?>\n<open what=\"door\">sesame</open>\n");
+    hr = IXMLDOMDocument2_loadXML(doc, str, &b);
+    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    SysFreeString(str);
+
+    element = NULL;
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    node = NULL;
+    hr = IXMLDOMElement_get_firstChild(element, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* put_text on text node */
+    hr = IXMLDOMNode_put_text(node, _bstr_("SESAME"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = NULL;
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expected = L"<open what=\"door\">SESAME</open>";
+    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* put_text on attribute node */
+    map = NULL;
+    hr = IXMLDOMElement_get_attributes(element, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    node2 = NULL;
+    hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNode_put_text(node2, _bstr_("window"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* put_text on element parent */
+    hr = IXMLDOMElement_put_text(element, _bstr_("sesame"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = NULL;
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expected = L"<open what=\"window\">sesame</open>";
+    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* calling put_text on text node again doesn't affect element */
+    hr = IXMLDOMNode_put_text(node, _bstr_("SeSaMe"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = NULL;
+    hr = IXMLDOMNode_get_text(node, &str);
+    expected = L"SeSaMe";
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, expected), "Incorrect node string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    str = NULL;
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expected = L"<open what=\"window\">sesame</open>";
+    todo_wine
+    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMNode_Release(node2);
+    IXMLDOMNamedNodeMap_Release(map);
+    IXMLDOMNode_Release(node);
+    IXMLDOMElement_Release(element);
+    IXMLDOMDocument2_Release(doc);
+
+    /* put_text on element when children is not a text node */
+    doc = create_document(&IID_IXMLDOMDocument2);
+
+    b = VARIANT_FALSE;
+    str = SysAllocString(L"<?xml version='1.0' encoding='UTF-16'?>\n"
+                          "<open>\r\n"
+                            "\t<inside>sesame</inside>\r\n"
+                          "</open>\n");
+    hr = IXMLDOMDocument2_loadXML(doc, str, &b);
+    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    SysFreeString(str);
+
+    element = NULL;
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = NULL;
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    node = NULL;
+    hr = IXMLDOMElement_get_firstChild(element, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expected = L"<open>\r\n"
+                    "\t<inside>sesame</inside>\r\n"
+                "</open>";
+    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMElement_put_text(element, _bstr_("sesame"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = NULL;
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expected = L"<open>sesame</open>";
+    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMNode_Release(node);
+    IXMLDOMElement_Release(element);
+    IXMLDOMDocument2_Release(doc);
+
+    /* put_text on element with no children */
+    doc = create_document(&IID_IXMLDOMDocument2);
+
+    b = VARIANT_FALSE;
+    str = SysAllocString(L"<?xml version='1.0' encoding='UTF-16'?>\n"
+                          "<open></open>\n");
+    hr = IXMLDOMDocument2_loadXML(doc, str, &b);
+    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    SysFreeString(str);
+
+    element = NULL;
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    node = NULL;
+    hr = IXMLDOMElement_get_firstChild(element, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_put_text(element, _bstr_("sesame"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = NULL;
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    expected = L"<open>sesame</open>";
+    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMElement_Release(element);
+    IXMLDOMDocument2_Release(doc);
+    free_bstrs();
+}
+
+static void test_indent(void)
+{
+    HRESULT hr;
+    VARIANT_BOOL b = VARIANT_FALSE;
+    BSTR data, str;
+    const WCHAR *data_expected;
+    IXMLDOMDocument *doc;
+    IXMLDOMElement *element = NULL;
+
+    str = SysAllocString(L"<?xml version='1.0' encoding='Windows-1252'?>\n"
+                          "<root>\n"
+                              "<a>\n"
+                                  "<b/>\n"
+                              "</a>\n"
+                          "</root>\n");
+    hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_loadXML(doc, str, &b);
+    ok(hr == S_OK, "Unable to load XML hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unable to get element hr %#lx.\n", hr);
+    hr = IXMLDOMElement_get_xml(element, &data);
+    ok(hr == S_OK, "Unable to get XML hr %#lx.\n", hr);
+
+    data_expected = L"<root>\r\n"
+                         "\t<a>\r\n"
+                             "\t\t<b/>\r\n"
+                         "\t</a>\r\n"
+                     "</root>";
+    ok(!lstrcmpW(data, data_expected), "incorrect element string, got '%s'\n", wine_dbgstr_w(data));
+
+    SysFreeString(str);
+}
+
+static DWORD WINAPI new_thread(void *arg)
+{
+    HRESULT hr = CoInitialize(NULL);
+    ok(hr == S_OK, "failed to init com\n");
+    if (hr != S_OK) return 1;
+
+    test_indent();
+
+    CoUninitialize();
+    return 0;
+}
+
+static void test_get_parentNode(void)
+{
+    IXMLDOMNode *node, *child;
+    IXMLDOMAttribute *attr;
+    IXMLDOMElement *e, *e2;
+    IXMLDOMDocument *doc;
+    VARIANT_BOOL b;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument2, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* Document parent */
+    hr = IXMLDOMDocument_get_parentNode(doc, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    node = (void *)0x1;
+    hr = IXMLDOMDocument_get_parentNode(doc, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected node %p.\n", node);
+
+    /* Attribute parent */
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_("<a><b attr1=\"value\" /></a>"), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_get_documentElement(doc, &e);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMElement_get_firstChild(e, &child);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_QueryInterface(child, &IID_IXMLDOMElement, (void **)&e2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(child);
+
+    hr = IXMLDOMElement_getAttributeNode(e2, _bstr_("attr1"), &attr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMAttribute_get_parentNode(attr, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMAttribute_get_parentNode(attr, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected node %p.\n", node);
+    IXMLDOMAttribute_Release(attr);
+
+    IXMLDOMElement_Release(e2);
+    IXMLDOMElement_Release(e);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_removeAttributeNode(void)
+{
+    IXMLDOMElement *element;
+    IXMLDOMAttribute *attr;
+    IXMLDOMDocument *doc;
+    VARIANT_BOOL b;
+    VARIANT var;
+    HRESULT hr;
+    BSTR str;
+
+    if (winetest_platform_is_wine)
+        return;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_("<a ns:attr1=\"attr1-value\" xmlns:ns=\"uri\" ><ns:b ns:attr=\"attr-value\" /></a>"), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<a ns:attr1=\"attr1-value\" xmlns:ns=\"uri\"><ns:b ns:attr=\"attr-value\"/></a>"), "Unexpected str %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    V_VT(&var) = VT_EMPTY;
+    hr = IXMLDOMElement_getAttribute(element, _bstr_("ns"), &var);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(V_VT(&var) == VT_NULL, "Unexpected value %s.\n", debugstr_variant(&var));
+
+    V_VT(&var) = VT_EMPTY;
+    hr = IXMLDOMElement_getAttribute(element, _bstr_("xmlns:ns"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"uri"), "Unexpected value %s.\n", debugstr_variant(&var));
+    VariantClear(&var);
+
+    /* Try to remove namespace definition that's in use */
+    hr = IXMLDOMElement_removeAttribute(element, _bstr_("xmlns:ns"));
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<a xmlns:ns=\"uri\" ns:attr1=\"attr1-value\"><ns:b ns:attr=\"attr-value\"/></a>"), "Unexpected str %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMElement_getAttribute(element, _bstr_("xmlns:ns"), &var);
+    todo_wine
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_getAttributeNode(element, _bstr_("attr1"), &attr);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_getAttributeNode(element, _bstr_("ns:attr1"), &attr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMAttribute_get_namespaceURI(attr, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"uri"), "Unexpected uri %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMAttribute_Release(attr);
+
+    hr = IXMLDOMElement_removeAttribute(element, _bstr_("ns:attr1"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<a><ns:b xmlns:ns=\"uri\" ns:attr=\"attr-value\"/></a>"), "Unexpected str %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMElement_Release(element);
+
+    /* Change uri via attribute value, detach an attribute that's using it */
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_("<a xmlns:ns=\"uri\" ns:attr1=\"attr1-value\" >text</a>"), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_getAttributeNode(element, _bstr_("xmlns:ns"), &attr);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    if (hr == S_OK)
+    {
+        hr = IXMLDOMAttribute_put_text(attr, _bstr_("uri-2"));
+        ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+
+        IXMLDOMAttribute_Release(attr);
+    }
+
+    hr = IXMLDOMElement_getAttributeNode(element, _bstr_("ns:attr1"), &attr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_setAttribute(element, _bstr_("xmlns:ns"), _variantbstr_("uri2"));
+    todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_setAttribute(element, _bstr_("xmlns:ns"), _variantbstr_("uri"));
+    todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMAttribute_get_namespaceURI(attr, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"uri"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMElement_removeAttribute(element, _bstr_("ns:attr1"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMElement_setAttribute(element, _bstr_("xmlns:ns"), _variantbstr_("uri2"));
+    todo_wine
+    ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMAttribute_get_namespaceURI(attr, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"uri"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMAttribute_Release(attr);
+
+    IXMLDOMElement_Release(element);
+
+    IXMLDOMDocument_Release(doc);
+    free_bstrs();
+}
+
+static void test_comment(void)
+{
+    IXMLDOMComment *comment;
+    IXMLDOMDocument *doc;
+    HRESULT hr;
+    VARIANT v;
+    BSTR str;
+    LONG len;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument2, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    for (int i = 0; i < 2; ++i)
+    {
+        hr = IXMLDOMDocument_put_preserveWhiteSpace(doc, i == 0 ? VARIANT_TRUE : VARIANT_FALSE);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+        hr = IXMLDOMDocument_createComment(doc, _bstr_("A Comment -->"), &comment);
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMDocument_createComment(doc, _bstr_("A \nCo\rmment\r\n  & < \""), &comment);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_nodeName(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"#comment"), "Unexpected name %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_xml(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"<!--A \r\nCo\r\nmment\r\n  & < \"-->"), "Unexpected xml %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"A \nCo\nmment\n  & < \""), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_data(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"A \nCo\nmment\n  & < \""), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_nodeValue(comment, &v);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"A \nCo\nmment\n  & < \""), "Unexpected text %s.\n", debugstr_w(str));
+        VariantClear(&v);
+
+        hr = IXMLDOMComment_put_nodeValue(comment, _variantbstr_("comment --> a"));
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_put_nodeValue(comment, _variantbstr_("comment \ra"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_data(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"comment \na"), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_nodeValue(comment, &v);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(V_BSTR(&v), L"comment \na"), "Unexpected text %s.\n", debugstr_w(V_BSTR(&v)));
+        VariantClear(&v);
+
+        hr = IXMLDOMComment_put_nodeValue(comment, _variantbstr_("comment \na"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_xml(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW( str, L"<!--comment \r\na-->" ), "Unexpected xml %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"comment \na"), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_data(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"comment \na"), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_get_nodeValue(comment, &v);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(V_BSTR(&v), L"comment \na"), "Unexpected text %s.\n", debugstr_w(V_BSTR(&v)));
+        VariantClear(&v);
+
+        /* put data Tests */
+        hr = IXMLDOMComment_put_data(comment, _bstr_("This &is a ; test <>\\"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        /* get data Tests */
+        hr = IXMLDOMComment_get_data(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect get_data string\n");
+        SysFreeString(str);
+
+        /* Confirm XML text is good */
+        hr = IXMLDOMComment_get_xml(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"<!--This &is a ; test <>\\-->"), "incorrect xml string\n");
+        SysFreeString(str);
+
+        /* Confirm we get the put_data Text back */
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect xml string\n");
+        SysFreeString(str);
+
+        /* test length property */
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(len == 21, "expected 21 got %ld\n", len);
+
+        /* test substringData */
+        hr = IXMLDOMComment_substringData(comment, 0, 4, NULL);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        /* test substringData - Invalid offset */
+        str = (void *)0xdeadbeef;
+        hr = IXMLDOMComment_substringData(comment, -1, 4, &str);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+        ok( str == NULL, "incorrect string\n");
+
+        /* test substringData - Invalid offset */
+        str = (void *)0xdeadbeef;
+        hr = IXMLDOMComment_substringData(comment, 30, 0, &str);
+        ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
+        ok( str == NULL, "incorrect string\n");
+
+        /* test substringData - Invalid size */
+        str = (void *)0xdeadbeef;
+        hr = IXMLDOMComment_substringData(comment, 0, -1, &str);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+        ok( str == NULL, "incorrect string\n");
+
+        /* test substringData - Invalid size */
+        str = (void *)0xdeadbeef;
+        hr = IXMLDOMComment_substringData(comment, 2, 0, &str);
+        ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr );
+        ok( str == NULL, "incorrect string\n");
+
+        /* test substringData - Start of string */
+        hr = IXMLDOMComment_substringData(comment, 0, 4, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"This"), "incorrect substringData string\n");
+        SysFreeString(str);
+
+        /* test substringData - Middle of string */
+        hr = IXMLDOMComment_substringData(comment, 13, 4, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"test"), "incorrect substringData string\n");
+        SysFreeString(str);
+
+        /* test substringData - End of string */
+        hr = IXMLDOMComment_substringData(comment, 20, 4, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"\\"), "incorrect substringData string\n");
+        SysFreeString(str);
+
+        /* test appendData */
+        hr = IXMLDOMComment_appendData(comment, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_appendData(comment, _bstr_(""));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_appendData(comment, _bstr_("Append"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"This &is a ; test <>\\Append"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* test insertData */
+        str = SysAllocStringLen(NULL, 0);
+        hr = IXMLDOMComment_insertData(comment, -1, str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, -1, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 1000, str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 1000, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 0, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 0, str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_insertData(comment, -1, _bstr_("Inserting"));
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 1000, _bstr_("Inserting"));
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 0, _bstr_("Begin "));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 17, _bstr_("Middle"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 39, _bstr_(" End"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"Begin This &is a Middle; test <>\\Append End"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* delete data */
+        /* invalid arguments */
+        hr = IXMLDOMComment_deleteData(comment, -1, 1);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_deleteData(comment, 0, 0);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_deleteData(comment, 0, -1);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(len == 43, "expected 43 got %ld\n", len);
+
+        hr = IXMLDOMComment_deleteData(comment, len, 1);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_deleteData(comment, len+1, 1);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        /* delete from start */
+        hr = IXMLDOMComment_deleteData(comment, 0, 5);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(len == 38, "expected 38 got %ld\n", len);
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append End"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* delete from end */
+        hr = IXMLDOMComment_deleteData(comment, 35, 3);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(len == 35, "expected 35 got %ld\n", len);
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append "), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* delete from inside */
+        hr = IXMLDOMComment_deleteData(comment, 1, 33);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(len == 2, "expected 2 got %ld\n", len);
+
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"  "), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* delete whole data ... */
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_deleteData(comment, 0, len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        /* ... and try again with empty string */
+        hr = IXMLDOMComment_deleteData(comment, 0, len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        /* ::replaceData() */
+        hr = IXMLDOMComment_put_nodeValue(comment, _variantbstr_("str1"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_replaceData(comment, 6, 0, NULL);
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"str1"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_replaceData(comment, 0, 0, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"str1"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* NULL pointer means delete */
+        hr = IXMLDOMComment_replaceData(comment, 0, 1, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"tr1"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* empty string means delete */
+        hr = IXMLDOMComment_replaceData(comment, 0, 1, _bstr_(""));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"r1"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* zero count means insert */
+        hr = IXMLDOMComment_replaceData(comment, 0, 0, _bstr_("a"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"ar1"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_replaceData(comment, 0, 2, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMComment_insertData(comment, 0, _bstr_("m"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"m1"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* nonempty string, count greater than its length */
+        hr = IXMLDOMComment_replaceData(comment, 0, 2, _bstr_("a1.2"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"a1.2"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        /* nonempty string, count less than its length */
+        hr = IXMLDOMComment_replaceData(comment, 0, 1, _bstr_("wine"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        hr = IXMLDOMComment_get_text(comment, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"wine1.2"), "Unexpected text %s.\n", wine_dbgstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMComment_put_data(comment, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+        hr = IXMLDOMComment_get_length(comment, &len);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+        ok(!len, "Unexpected length %ld.\n", len);
+
+        IXMLDOMComment_Release(comment);
+    }
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_pi(void)
+{
+    IXMLDOMProcessingInstruction *pi;
+    IXMLDOMDocument *doc;
+    HRESULT hr;
+    VARIANT v;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument2, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    for (int i = 0; i < 2; ++i)
+    {
+        hr = IXMLDOMDocument_put_preserveWhiteSpace(doc, i == 0 ? VARIANT_TRUE : VARIANT_FALSE);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+        hr = IXMLDOMDocument_createProcessingInstruction(doc, _bstr_("target"), _bstr_("Some text ?>"), &pi);
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMDocument_createProcessingInstruction(doc, _bstr_("target"), _bstr_("A \nCo\rmment\r\n  & < \""), &pi);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMProcessingInstruction_get_nodeName(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"target"), "Unexpected name %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"<?target A \r\nCo\r\nmment\r\n  & < \"?>"), "Unexpected xml %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_text(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"A \nCo\nmment\n  & < \""), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_data(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"A \nCo\nmment\n  & < \""), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_nodeValue(pi, &v);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW(str, L"A \nCo\nmment\n  & < \""), "Unexpected text %s.\n", debugstr_w(str));
+        VariantClear(&v);
+
+        hr = IXMLDOMProcessingInstruction_put_nodeValue(pi, _variantbstr_("comment ?> a"));
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMProcessingInstruction_put_nodeValue(pi, _variantbstr_("comment \na"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        todo_wine
+        ok(!lstrcmpW( str, L"<?target comment \r\na?>"), "Unexpected xml %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_text(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"comment \na"), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_data(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"comment \na"), "Unexpected text %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_get_nodeValue(pi, &v);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"comment \na"), "Unexpected text %s.\n", debugstr_w(str));
+        VariantClear(&v);
+
+        /* put data Tests */
+        hr = IXMLDOMProcessingInstruction_put_data(pi, _bstr_("This &is a ; test <>\\"));
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+        /* get data Tests */
+        hr = IXMLDOMProcessingInstruction_get_data(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect get_data string\n");
+        SysFreeString(str);
+
+        /* Confirm XML text is good */
+        hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"<?target This &is a ; test <>\\?>"), "Unexpected string %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        /* Confirm we get the put_data Text back */
+        hr = IXMLDOMProcessingInstruction_get_text(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect xml string\n");
+        SysFreeString(str);
+
+        hr = IXMLDOMProcessingInstruction_put_data(pi, NULL);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+        hr = IXMLDOMProcessingInstruction_get_text(pi, &str);
+        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+        ok(!*str, "Unexpected string %s.\n", debugstr_w(str));
+        SysFreeString(str);
+
+        /* Can't have markup */
+        hr = IXMLDOMProcessingInstruction_put_data(pi, _bstr_("da?>ta"));
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+        hr = IXMLDOMProcessingInstruction_put_text(pi, _bstr_("da?>ta"));
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+        hr = IXMLDOMProcessingInstruction_put_nodeValue(pi, _variantbstr_("da?>ta"));
+        todo_wine
+        ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+        VariantClear(&v);
+
+        IXMLDOMProcessingInstruction_Release(pi);
+    }
+
+    IXMLDOMDocument_Release(doc);
+    free_bstrs();
+}
+
+static void test_dom_impl(void)
+{
+    IXMLDOMImplementation *impl;
+    IXMLDOMDocument *doc;
+    VARIANT_BOOL v;
+    BSTR sEmpty;
+    HRESULT hr;
+
+    sEmpty = SysAllocStringLen(NULL, 0);
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_implementation(doc, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_implementation(doc, &impl);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMImplementation_hasFeature(impl, NULL, sEmpty, &v);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMImplementation_hasFeature(impl, sEmpty, sEmpty, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    v = VARIANT_TRUE;
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("DOM"), sEmpty, &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(v == VARIANT_FALSE, "Unexpected value %d.\n", v);
+
+    v = VARIANT_TRUE;
+    hr = IXMLDOMImplementation_hasFeature(impl, sEmpty, sEmpty, &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(v == VARIANT_FALSE, "Unexpected value %d.\n", v);
+
+    v = VARIANT_FALSE;
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("DOM"), NULL, &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(v == VARIANT_TRUE, "Unexpected value %d.\n", v);
+
+    v = VARIANT_TRUE;
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("DOM"), sEmpty, &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(v == VARIANT_FALSE, "Unexpected value %d.\n", v);
+
+    v = VARIANT_FALSE;
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("DOM"), _bstr_("1.0"), &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(v == VARIANT_TRUE, "Unexpected value %d.\n", v);
+
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("XML"), _bstr_("1.0"), &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(v == VARIANT_TRUE, "Unexpected value %d.\n", v);
+
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("MS-DOM"), _bstr_("1.0"), &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(v == VARIANT_TRUE, "Unexpected value %d.\n", v);
+
+    hr = IXMLDOMImplementation_hasFeature(impl, _bstr_("SSS"), NULL, &v);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(v == VARIANT_FALSE, "Unexpected value %d.\n", v);
+
+    SysFreeString(sEmpty);
+    IXMLDOMImplementation_Release(impl);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_doc_fragment(void)
+{
+    IXMLDOMElement *element, *element2;
+    IXMLDOMDocumentFragment *fragment;
+    IXMLDOMProcessingInstruction *pi;
+    IXMLDOMCDATASection *cdata;
+    IXMLDOMComment *comment;
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *node;
+    IXMLDOMText *text;
+    HRESULT hr;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createElement(doc, _bstr_("e"), &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createDocumentFragment(doc, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createDocumentFragment(doc, &fragment);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_get_parentNode(fragment, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMDocumentFragment_get_parentNode(fragment, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected value %p.\n", node);
+
+    hr = IXMLDOMElement_appendChild(element, (IXMLDOMNode *)fragment, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_get_nodeName(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"#document-fragment"), "Unexpected name %s\n", debugstr_w(str));
+    SysFreeString(str);
+
+    /* Siblings */
+    hr = IXMLDOMDocumentFragment_get_nextSibling(fragment, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMDocumentFragment_get_nextSibling(fragment, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected value %p.\n", node);
+
+    hr = IXMLDOMDocumentFragment_get_previousSibling(fragment, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMDocumentFragment_get_previousSibling(fragment, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected value %p.\n", node);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!*str, "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!*str, "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_createProcessingInstruction(doc, _bstr_("t"), _bstr_("pi-text"), &pi);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)pi, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"<?t pi-text?>"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!*str, "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_createTextNode(doc, _bstr_("text-node"), &text);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)text, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMText_Release(text);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"<?t pi-text?>text-node"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"text-node"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_createComment(doc, _bstr_("comment"), &comment);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)comment, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMComment_Release(comment);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"<?t pi-text?>text-node<!--comment-->"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"text-node"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_createCDATASection(doc, _bstr_("cdata"), &cdata);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)cdata, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMCDATASection_Release(cdata);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"<?t pi-text?>text-node<!--comment--><![CDATA[cdata]]>"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"text-nodecdata"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_createElement(doc, _bstr_("e2"), &element2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createTextNode(doc, _bstr_("text-node2"), &text);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMElement_appendChild(element2, (IXMLDOMNode *)text, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMText_Release(text);
+
+    hr = IXMLDOMDocumentFragment_appendChild(fragment, (IXMLDOMNode *)element2, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"<?t pi-text?>text-node<!--comment--><![CDATA[cdata]]><e2>text-node2</e2>"),
+            "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"text-nodecdatatext-node2"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_createComment(doc, _bstr_("comment2"), &comment);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMElement_appendChild(element2, (IXMLDOMNode *)comment, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMComment_Release(comment);
+
+    hr = IXMLDOMDocumentFragment_get_xml(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"<?t pi-text?>text-node<!--comment--><![CDATA[cdata]]>"
+            "<e2>text-node2<!--comment2--></e2>"),
+            "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocumentFragment_get_text(fragment, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"text-nodecdatatext-node2"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMElement_get_text(element2, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"text-node2"), "Unexpected text %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMElement_Release(element2);
+
+    IXMLDOMProcessingInstruction_Release(pi);
+    IXMLDOMDocumentFragment_Release(fragment);
+    IXMLDOMElement_Release(element);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_text(void)
+{
+    IXMLDOMText *nodetext;
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *node;
+    VARIANT_BOOL b;
+    VARIANT var;
+    LONG length;
+    HRESULT hr;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    str = SysAllocString( L"open" );
+    hr = IXMLDOMDocument_createTextNode(doc, str, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createTextNode(doc, str, &nodetext);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    SysFreeString( str );
+
+    check_interface(nodetext, &IID_IXMLDOMElement, FALSE);
+
+    /* Text Last Child Checks */
+    hr = IXMLDOMText_get_lastChild(nodetext, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMText_get_lastChild(nodetext, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected node %p.\n", node);
+
+    /* test length property */
+    hr = IXMLDOMText_get_length(nodetext, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(length == 4, "Unexpected length %ld.\n", length);
+
+    hr = IXMLDOMText_put_data(nodetext, _bstr_("t\ne\rx\r\nt"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(length == 7, "Unexpected length %ld.\n", length);
+
+    hr = IXMLDOMText_get_data(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_nodeValue(nodetext, &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(V_BSTR(&var), L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    hr = IXMLDOMText_put_text(nodetext, _bstr_("t\ne\rx\r\nt"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_data(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_nodeValue(nodetext, &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(V_BSTR(&var), L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    hr = IXMLDOMText_put_nodeValue(nodetext, _variantbstr_("t\ne\rx\r\nt"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_data(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(str, L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_nodeValue(nodetext, &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!lstrcmpW(V_BSTR(&var), L"t\ne\nx\nt"), "Unexpected data %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    hr = IXMLDOMText_put_data(nodetext, _bstr_("&amp;\"<>\'"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    b = VARIANT_TRUE;
+    hr = IXMLDOMText_hasChildNodes(nodetext, &b);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
+
+    hr = IXMLDOMText_get_data(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"&amp;\"<>\'"), "Unexpected data %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_get_xml(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"&amp;amp;\"&lt;&gt;\'"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_put_data(nodetext, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!length, "Unexpected length %ld.\n", length);
+
+    /* put data Tests */
+    hr = IXMLDOMText_put_data(nodetext, _bstr_("This &is a ; test <>\\"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* get data Tests */
+    hr = IXMLDOMText_get_data(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect put_data string\n");
+    SysFreeString(str);
+
+    /* Confirm XML text is good */
+    hr = IXMLDOMText_get_xml(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &amp;is a ; test &lt;&gt;\\"), "incorrect xml string\n");
+    SysFreeString(str);
+
+    /* Confirm we get the put_data Text back */
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect xml string\n");
+    SysFreeString(str);
+
+    /* test substringData */
+    hr = IXMLDOMText_substringData(nodetext, 0, 4, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    /* test substringData - Invalid offset */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMText_substringData(nodetext, -1, 4, &str);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    ok( str == NULL, "incorrect string\n");
+
+    /* test substringData - Invalid offset */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMText_substringData(nodetext, 30, 0, &str);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok( str == NULL, "incorrect string\n");
+
+    /* test substringData - Invalid size */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMText_substringData(nodetext, 0, -1, &str);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    ok( str == NULL, "incorrect string\n");
+
+    /* test substringData - Invalid size */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMText_substringData(nodetext, 2, 0, &str);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok( str == NULL, "incorrect string\n");
+
+    /* test substringData - Start of string */
+    hr = IXMLDOMText_substringData(nodetext, 0, 4, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This"), "incorrect substringData string\n");
+    SysFreeString(str);
+
+    /* test substringData - Middle of string */
+    hr = IXMLDOMText_substringData(nodetext, 13, 4, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"test"), "incorrect substringData string\n");
+    SysFreeString(str);
+
+    /* test substringData - End of string */
+    hr = IXMLDOMText_substringData(nodetext, 20, 4, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"\\"), "incorrect substringData string\n");
+    SysFreeString(str);
+
+    /* test appendData */
+    hr = IXMLDOMText_appendData(nodetext, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_appendData(nodetext, _bstr_(""));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_appendData(nodetext, _bstr_("Append"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\Append"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* test insertData */
+    str = SysAllocStringLen(NULL, 0);
+    hr = IXMLDOMText_insertData(nodetext, -1, str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, -1, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 1000, str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 1000, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 0, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 0, str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    SysFreeString(str);
+
+    hr = IXMLDOMText_insertData(nodetext, -1, _bstr_("Inserting"));
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 1000, _bstr_("Inserting"));
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 0, _bstr_("Begin "));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 17, _bstr_("Middle"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 39, _bstr_(" End"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"Begin This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* delete data */
+    /* invalid arguments */
+    hr = IXMLDOMText_deleteData(nodetext, -1, 1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_deleteData(nodetext, 0, 0);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_deleteData(nodetext, 0, -1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(length == 43, "expected 43 got %ld\n", length);
+
+    hr = IXMLDOMText_deleteData(nodetext, length, 1);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_deleteData(nodetext, length + 1, 1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    /* delete from start */
+    hr = IXMLDOMText_deleteData(nodetext, 0, 5);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(length == 38, "expected 38 got %ld\n", length);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* delete from end */
+    hr = IXMLDOMText_deleteData(nodetext, 35, 3);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(length == 35, "expected 35 got %ld\n", length);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a Middle; test <>\\Append"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* delete from inside */
+    hr = IXMLDOMText_deleteData(nodetext, 1, 33);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(length == 2, "expected 2 got %ld\n", length);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L""), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* delete whole data ... */
+    hr = IXMLDOMText_get_length(nodetext, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_deleteData(nodetext, 0, length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    /* ... and try again with empty string */
+    hr = IXMLDOMText_deleteData(nodetext, 0, length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* test put_data */
+    hr = IXMLDOMText_put_nodeValue(nodetext, _variantbstr_("str1"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok( !lstrcmpW( str, L"str1" ), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str) );
+    SysFreeString(str);
+
+    /* test put_data */
+    V_VT(&var) = VT_I4;
+    V_I4(&var) = 99;
+    hr = IXMLDOMText_put_nodeValue(nodetext, var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    VariantClear(&var);
+
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"99"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* ::replaceData() */
+    hr = IXMLDOMText_put_nodeValue(nodetext, _variantbstr_("str1"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_replaceData(nodetext, 6, 0, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_replaceData(nodetext, 0, 0, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* NULL pointer means delete */
+    hr = IXMLDOMText_replaceData(nodetext, 0, 1, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"tr1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* empty string means delete */
+    hr = IXMLDOMText_replaceData(nodetext, 0, 1, _bstr_(""));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"r1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* zero count means insert */
+    hr = IXMLDOMText_replaceData(nodetext, 0, 0, _bstr_("a"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"ar1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMText_replaceData(nodetext, 0, 2, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_insertData(nodetext, 0, _bstr_("m"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"m1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* nonempty string, count greater than its length */
+    hr = IXMLDOMText_replaceData(nodetext, 0, 2, _bstr_("a1.2"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"a1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    /* nonempty string, count less than its length */
+    hr = IXMLDOMText_replaceData(nodetext, 0, 1, _bstr_("wine"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMText_get_text(nodetext, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"wine1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMText_Release( nodetext );
+
+    IXMLDOMDocument_Release(doc);
+    free_bstrs();
+}
+
+static void test_attribute_value(void)
+{
+    IXMLDOMAttribute *attr;
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *child;
+    IXMLDOMText *text;
+    DOMNodeType type;
+    VARIANT_BOOL b;
+    VARIANT value;
+    HRESULT hr;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_createAttribute(doc, _bstr_("attr"), &attr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    b = VARIANT_TRUE;
+    hr = IXMLDOMAttribute_hasChildNodes(attr, &b);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
+
+    V_VT(&value) = VT_EMPTY;
+    hr = IXMLDOMAttribute_get_value(attr, &value);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(V_VT(&value) == VT_BSTR, "Unexpected type %d.\n", V_VT(&value));
+    ok(!*V_BSTR(&value), "Unexpected string %s.\n", debugstr_w(V_BSTR(&value)));
+    VariantClear(&value);
+
+    hr = IXMLDOMAttribute_get_text(attr, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!*str, "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMAttribute_put_text(attr, _bstr_("a<b>c\"d\'&lt;"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMAttribute_get_text(attr, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"a<b>c\"d\'&lt;"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMAttribute_get_value(attr, &value);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(V_VT(&value) == VT_BSTR, "Unexpected type %d.\n", V_VT(&value));
+    ok(!wcscmp(L"a<b>c\"d\'&lt;", V_BSTR(&value)), "Unexpected string %s.\n", debugstr_w(V_BSTR(&value)));
+    VariantClear(&value);
+
+    hr = IXMLDOMAttribute_get_xml(attr, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"attr=\"a&lt;b&gt;c&quot;d\'&amp;lt;\""), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMAttribute_get_firstChild(attr, &child);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMNode_get_nodeType(child, &type);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(type == NODE_TEXT, "Unexpected type %d.\n", type);
+
+    hr = IXMLDOMNode_QueryInterface(child, &IID_IXMLDOMText, (void **)&text);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMText_get_data(text, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"a<b>c\"d\'&lt;"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMText_Release(text);
+
+    hr = IXMLDOMNode_get_xml(child, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"a&lt;b&gt;c\"d\'&amp;lt;"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_get_text(child, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"a<b>c\"d\'&lt;"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNode_get_nodeValue(child, &value);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(V_VT(&value) == VT_BSTR, "Unexpected type %d.\n", V_VT(&value));
+    ok(!wcscmp(L"a<b>c\"d\'&lt;", V_BSTR(&value)), "Unexpected string %s.\n", debugstr_w(V_BSTR(&value)));
+    VariantClear(&value);
+
+    IXMLDOMNode_Release(child);
+
+    /* Set via 'value' property */
+    hr = IXMLDOMAttribute_put_value(attr, _variantbstr_(""));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    b = VARIANT_FALSE;
+    hr = IXMLDOMAttribute_hasChildNodes(attr, &b);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(b == VARIANT_TRUE, "Unexpected value %d.\n", b);
+
+    V_VT(&value) = VT_EMPTY;
+    hr = IXMLDOMAttribute_put_value(attr, value);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    b = VARIANT_FALSE;
+    hr = IXMLDOMAttribute_hasChildNodes(attr, &b);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(b == VARIANT_TRUE, "Unexpected value %d.\n", b);
+
+    hr = IXMLDOMAttribute_put_value(attr, _variantbstr_("<>\"\'"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMAttribute_get_nodeValue(attr, &value);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(V_VT(&value) == VT_BSTR, "Unexpected type %d.\n", V_VT(&value));
+    ok(!wcscmp(L"<>\"\'", V_BSTR(&value)), "Unexpected string %s.\n", debugstr_w(V_BSTR(&value)));
+    VariantClear(&value);
+
+    hr = IXMLDOMAttribute_get_value(attr, &value);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(V_VT(&value) == VT_BSTR, "Unexpected type %d.\n", V_VT(&value));
+    ok(!wcscmp(L"<>\"\'", V_BSTR(&value)), "Unexpected string %s.\n", debugstr_w(V_BSTR(&value)));
+    VariantClear(&value);
+
+    IXMLDOMAttribute_Release(attr);
+
+    IXMLDOMDocument_Release(doc);
+    free_bstrs();
+}
+
+static void test_xmldecl_attributes(void)
+{
+    IXMLDOMProcessingInstruction *pi;
+    IXMLDOMNamedNodeMap *map;
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *node;
+    VARIANT_BOOL b;
+    LONG length;
+    HRESULT hr;
+    BSTR str;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument30, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\" ?><a>text</a>"), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_get_firstChild(doc, &node);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMNode_QueryInterface(node, &IID_IXMLDOMProcessingInstruction, (void **)&pi);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMProcessingInstruction_get_attributes(pi, &map);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    node = NULL;
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, _bstr_("encoding"), &node);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    if (node)
+        IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<?xml version=\"1.0\" standalone=\"yes\"?>"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    node = NULL;
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, _bstr_("standalone"), &node);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    if (node)
+        IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<?xml version=\"1.0\"?>"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMProcessingInstruction_get_data(pi, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"version=\"1.0\""), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    node = NULL;
+    hr = IXMLDOMNamedNodeMap_removeNamedItem(map, _bstr_("version"), &node);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    if (node)
+        IXMLDOMNode_Release(node);
+
+    hr = IXMLDOMProcessingInstruction_get_data(pi, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L""), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMNamedNodeMap_get_length(map, &length);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!length, "Unexpected length %ld.\n", length);
+
+    hr = IXMLDOMProcessingInstruction_get_xml(pi, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<?xml version=\"1.0\"?>"), "Unexpected string %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    IXMLDOMNamedNodeMap_Release(map);
+
+    IXMLDOMProcessingInstruction_Release(pi);
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_loadXML(void)
+{
+    IXMLDOMElement *element;
+    IXMLDOMDocument *doc;
+    VARIANT_BOOL b;
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_DOMDocument2, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument_loadXML(doc, NULL, NULL);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    b = VARIANT_TRUE;
+    hr = IXMLDOMDocument_loadXML(doc, NULL, &b);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_FALSE, "Unexpected value %d.\n", b);
+
+    hr = IXMLDOMDocument_loadXML(doc, _bstr_("<a>text</a>"), NULL);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    todo_wine
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    if (hr == S_OK)
+        IXMLDOMElement_Release(element);
+
+    /* Clears current document */
+    hr = IXMLDOMDocument_loadXML(doc, NULL, NULL);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_get_documentElement(doc, &element);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+
+    IXMLDOMDocument_Release(doc);
+}
+
+static void test_cdata(void)
+{
+    IXMLDOMCDATASection *cdata;
+    IXMLDOMDocument *doc;
+    IXMLDOMNode *node;
+    HRESULT hr;
+    LONG len;
+    BSTR str;
+
+    doc = create_document(&IID_IXMLDOMDocument);
+
+    str = SysAllocString(L"[1]*2=3; &gee that is not right!");
+    hr = IXMLDOMDocument_createCDATASection(doc, str, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr );
+
+    hr = IXMLDOMDocument_createCDATASection(doc, str, &cdata);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    SysFreeString(str);
+
+    check_interface(cdata, &IID_IXMLDOMElement, FALSE);
+
+    hr = IXMLDOMCDATASection_get_nodeName(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"#cdata-section"), "Unexpected named %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMCDATASection_get_xml(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW( str, L"<![CDATA[[1]*2=3; &gee that is not right!]]>"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    /* test lastChild */
+    hr = IXMLDOMCDATASection_get_lastChild(cdata, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    node = (IXMLDOMNode *)0x1;
+    hr = IXMLDOMCDATASection_get_lastChild(cdata, &node);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!node, "Unexpected pointer %p.\n", node);
+
+    /* put data Tests */
+    hr = IXMLDOMCDATASection_put_data(cdata, _bstr_("This &is a ; test <>\\"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 21, "expected 21 got %ld\n", len);
+
+    hr = IXMLDOMCDATASection_put_data(cdata, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_put_data(cdata, _bstr_("This &is a ; test <>\\"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 21, "Unexpected length %ld.\n", len);
+
+    /* Confirm XML text is good */
+    hr = IXMLDOMCDATASection_get_xml(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"<![CDATA[This &is a ; test <>\\]]>"), "incorrect xml string\n");
+    SysFreeString(str);
+
+    /* Confirm we get the put_data Text back */
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect text string\n");
+    SysFreeString(str);
+
+    /* test length property */
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 21, "expected 21 got %ld\n", len);
+
+    /* Confirm XML text is good */
+    hr = IXMLDOMCDATASection_get_xml(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"<![CDATA[This &is a ; test <>\\]]>"), "incorrect xml string\n");
+    SysFreeString(str);
+
+    /* Confirm we get the put_data Text back */
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect text string\n");
+    SysFreeString(str);
+
+    /* test length property */
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 21, "expected 21 got %ld\n", len);
+
+    /* test get data */
+    hr = IXMLDOMCDATASection_get_data(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\"), "incorrect text string\n");
+    SysFreeString(str);
+
+    /* test substringData */
+    hr = IXMLDOMCDATASection_substringData(cdata, 0, 4, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    /* test substringData - Invalid offset */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMCDATASection_substringData(cdata, -1, 4, &str);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    ok(!str, "Unexpected pointer %p.\n", str);
+
+    /* test substringData - Invalid offset */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMCDATASection_substringData(cdata, 30, 0, &str);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!str, "Unexpected pointer %p.\n", str);
+
+    /* test substringData - Invalid size */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMCDATASection_substringData(cdata, 0, -1, &str);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    ok(!str, "Unexpected pointer %p.\n", str);
+
+    /* test substringData - Invalid size */
+    str = (void *)0xdeadbeef;
+    hr = IXMLDOMCDATASection_substringData(cdata, 2, 0, &str);
+    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    ok(!str, "Unexpected pointer %p.\n", str);
+
+    /* test substringData - Start of string */
+    hr = IXMLDOMCDATASection_substringData(cdata, 0, 4, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(!lstrcmpW(str, L"This"), "incorrect substringData string\n");
+    SysFreeString(str);
+
+    /* test substringData - Middle of string */
+    hr = IXMLDOMCDATASection_substringData(cdata, 13, 4, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(!lstrcmpW(str, L"test"), "incorrect substringData string\n");
+    SysFreeString(str);
 
-    b = VARIANT_FALSE;
-    str = SysAllocString(L"<?xml version='1.0' encoding='UTF-16'?>\n<open what=\"door\">sesame</open>\n");
-    hr = IXMLDOMDocument2_loadXML(doc, str, &b);
-    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    /* test substringData - End of string */
+    hr = IXMLDOMCDATASection_substringData(cdata, 20, 4, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok(!lstrcmpW(str, L"\\"), "incorrect substringData string\n");
     SysFreeString(str);
 
-    element = NULL;
-    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    /* test appendData */
+    hr = IXMLDOMCDATASection_appendData(cdata, NULL);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    node = NULL;
-    hr = IXMLDOMElement_get_firstChild(element, &node);
+    hr = IXMLDOMCDATASection_appendData(cdata, _bstr_(""));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    /* put_text on text node */
-    hr = IXMLDOMNode_put_text(node, _bstr_("SESAME"));
+    hr = IXMLDOMCDATASection_appendData(cdata, _bstr_("Append"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    str = NULL;
-    hr = IXMLDOMElement_get_xml(element, &str);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-
-    expected = L"<open what=\"door\">SESAME</open>";
-    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    ok(!lstrcmpW(str, L"This &is a ; test <>\\Append"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    /* put_text on attribute node */
-    map = NULL;
-    hr = IXMLDOMElement_get_attributes(element, &map);
+    /* test insertData */
+    str = SysAllocStringLen(NULL, 0);
+    hr = IXMLDOMCDATASection_insertData(cdata, -1, str);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    node2 = NULL;
-    hr = IXMLDOMNamedNodeMap_get_item(map, 0, &node2);
+    hr = IXMLDOMCDATASection_insertData(cdata, -1, NULL);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    hr = IXMLDOMNode_put_text(node2, _bstr_("window"));
+    hr = IXMLDOMCDATASection_insertData(cdata, 1000, str);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    /* put_text on element parent */
-    hr = IXMLDOMElement_put_text(element, _bstr_("sesame"));
+    hr = IXMLDOMCDATASection_insertData(cdata, 1000, NULL);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    str = NULL;
-    hr = IXMLDOMElement_get_xml(element, &str);
+    hr = IXMLDOMCDATASection_insertData(cdata, 0, NULL);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    expected = L"<open what=\"window\">sesame</open>";
-    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    hr = IXMLDOMCDATASection_insertData(cdata, 0, str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     SysFreeString(str);
 
-    /* calling put_text on text node again doesn't affect element */
-    hr = IXMLDOMNode_put_text(node, _bstr_("SeSaMe"));
+    hr = IXMLDOMCDATASection_insertData(cdata, -1, _bstr_("Inserting"));
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_insertData(cdata, 1000, _bstr_("Inserting"));
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_insertData(cdata, 0, _bstr_("Begin "));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr );
+
+    hr = IXMLDOMCDATASection_insertData(cdata, 17, _bstr_("Middle"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    str = NULL;
-    hr = IXMLDOMNode_get_text(node, &str);
-    expected = L"SeSaMe";
+    hr = IXMLDOMCDATASection_insertData(cdata, 39, _bstr_(" End"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    ok(!lstrcmpW(str, expected), "Incorrect node string, got '%s'\n", wine_dbgstr_w(str));
+
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"Begin This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    str = NULL;
-    hr = IXMLDOMElement_get_xml(element, &str);
+    /* delete data */
+    /* invalid arguments */
+    hr = IXMLDOMCDATASection_deleteData(cdata, -1, 1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_deleteData(cdata, 0, 0);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    expected = L"<open what=\"window\">sesame</open>";
-    todo_wine
-    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
-    SysFreeString(str);
+    hr = IXMLDOMCDATASection_deleteData(cdata, 0, -1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
 
-    IXMLDOMNode_Release(node2);
-    IXMLDOMNamedNodeMap_Release(map);
-    IXMLDOMNode_Release(node);
-    IXMLDOMElement_Release(element);
-    IXMLDOMDocument2_Release(doc);
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 43, "expected 43 got %ld\n", len);
 
-    /* put_text on element when children is not a text node */
-    doc = create_document(&IID_IXMLDOMDocument2);
+    hr = IXMLDOMCDATASection_deleteData(cdata, len, 1);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    b = VARIANT_FALSE;
-    str = SysAllocString(L"<?xml version='1.0' encoding='UTF-16'?>\n"
-                          "<open>\r\n"
-                            "\t<inside>sesame</inside>\r\n"
-                          "</open>\n");
-    hr = IXMLDOMDocument2_loadXML(doc, str, &b);
-    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_deleteData(cdata, len+1, 1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
+    /* delete from start */
+    hr = IXMLDOMCDATASection_deleteData(cdata, 0, 5);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 38, "expected 38 got %ld\n", len);
+
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append End"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    element = NULL;
-    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    /* delete from end */
+    hr = IXMLDOMCDATASection_deleteData(cdata, 35, 3);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    str = NULL;
-    hr = IXMLDOMElement_get_xml(element, &str);
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 35, "expected 35 got %ld\n", len);
 
-    node = NULL;
-    hr = IXMLDOMElement_get_firstChild(element, &node);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L" This &is a Middle; test <>\\Append "), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
 
-    expected = L"<open>\r\n"
-                    "\t<inside>sesame</inside>\r\n"
-                "</open>";
-    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    /* delete from inside */
+    hr = IXMLDOMCDATASection_deleteData(cdata, 1, 33);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(len == 2, "expected 2 got %ld\n", len);
+
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"  "), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    hr = IXMLDOMElement_put_text(element, _bstr_("sesame"));
+    /* delete whole data ... */
+    hr = IXMLDOMCDATASection_get_length(cdata, &len);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    str = NULL;
-    hr = IXMLDOMElement_get_xml(element, &str);
+    hr = IXMLDOMCDATASection_deleteData(cdata, 0, len);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    expected = L"<open>sesame</open>";
-    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    /* ... and try again with empty string */
+    hr = IXMLDOMCDATASection_deleteData(cdata, 0, len);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* ::replaceData() */
+    hr = IXMLDOMCDATASection_put_nodeValue(cdata, _variantbstr_("str1"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMCDATASection_replaceData(cdata, 6, 0, NULL);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    IXMLDOMNode_Release(node);
-    IXMLDOMElement_Release(element);
-    IXMLDOMDocument2_Release(doc);
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 0, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"str1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
 
-    /* put_text on element with no children */
-    doc = create_document(&IID_IXMLDOMDocument2);
+    /* NULL pointer means delete */
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 1, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"tr1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
 
-    b = VARIANT_FALSE;
-    str = SysAllocString(L"<?xml version='1.0' encoding='UTF-16'?>\n"
-                          "<open></open>\n");
-    hr = IXMLDOMDocument2_loadXML(doc, str, &b);
-    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
+    /* empty string means delete */
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 1, _bstr_(""));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"r1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    element = NULL;
-    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    /* zero count means insert */
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 0, _bstr_("a"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"ar1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
 
-    node = NULL;
-    hr = IXMLDOMElement_get_firstChild(element, &node);
-    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 2, NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    hr = IXMLDOMElement_put_text(element, _bstr_("sesame"));
+    hr = IXMLDOMCDATASection_insertData(cdata, 0, _bstr_("m"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"m1"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
 
-    str = NULL;
-    hr = IXMLDOMElement_get_xml(element, &str);
+    /* nonempty string, count greater than its length */
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 2, _bstr_("a1.2"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"a1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
+    SysFreeString(str);
 
-    expected = L"<open>sesame</open>";
-    ok(!lstrcmpW(str, expected), "Incorrect element string, got '%s'\n", wine_dbgstr_w(str));
+    /* nonempty string, count less than its length */
+    hr = IXMLDOMCDATASection_replaceData(cdata, 0, 1, _bstr_("wine"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMCDATASection_get_text(cdata, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!lstrcmpW(str, L"wine1.2"), "incorrect get_text string, got '%s'\n", wine_dbgstr_w(str));
     SysFreeString(str);
 
-    IXMLDOMElement_Release(element);
-    IXMLDOMDocument2_Release(doc);
-    free_bstrs();
+    IXMLDOMCDATASection_Release(cdata);
+
+    IXMLDOMDocument_Release(doc);
 }
 
-static void test_indent(void)
+static void test_document_reload(void)
 {
+    IXMLDOMElement *element, *element2;
+    IXMLDOMDocument2 *doc, *doc2;
+    IXMLDOMDocument *owner;
+    VARIANT_BOOL b;
+    VARIANT var;
     HRESULT hr;
-    VARIANT_BOOL b = VARIANT_FALSE;
-    BSTR data, str;
-    const WCHAR *data_expected;
-    IXMLDOMDocument *doc;
-    IXMLDOMElement *element = NULL;
+    BSTR str;
 
-    str = SysAllocString(L"<?xml version='1.0' encoding='Windows-1252'?>\n"
-                          "<root>\n"
-                              "<a>\n"
-                                  "<b/>\n"
-                              "</a>\n"
-                          "</root>\n");
-    hr = CoCreateInstance(&CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
-    ok(hr == S_OK, "Unable to create instance hr %#lx.\n", hr);
-    hr = IXMLDOMDocument_loadXML(doc, str, &b);
-    ok(hr == S_OK, "Unable to load XML hr %#lx.\n", hr);
-    hr = IXMLDOMDocument_get_documentElement(doc, &element);
-    ok(hr == S_OK, "Unable to get element hr %#lx.\n", hr);
-    hr = IXMLDOMElement_get_xml(element, &data);
-    ok(hr == S_OK, "Unable to get XML hr %#lx.\n", hr);
+    doc = create_document(&IID_IXMLDOMDocument2);
 
-    data_expected = L"<root>\r\n"
-                         "\t<a>\r\n"
-                             "\t\t<b/>\r\n"
-                         "\t</a>\r\n"
-                     "</root>";
-    ok(!lstrcmpW(data, data_expected), "incorrect element string, got '%s'\n", wine_dbgstr_w(data));
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionLanguage"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"XSLPattern"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), _variantbstr_("XPath"));
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* Load document */
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_("<a>text</a>"), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionLanguage"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"XPath"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    /* Get a node, reload document. */
+    hr = IXMLDOMDocument2_get_documentElement(doc, &element);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
+    hr = IXMLDOMDocument2_get_xml(doc, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"<a>text</a>\r\n"), "Unexpected xml %s.\n", debugstr_w(str));
     SysFreeString(str);
-}
 
-static DWORD WINAPI new_thread(void *arg)
-{
-    HRESULT hr = CoInitialize(NULL);
-    ok(hr == S_OK, "failed to init com\n");
-    if (hr != S_OK) return 1;
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionLanguage"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"XPath"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
 
-    test_indent();
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_("<b>text</b>"), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    CoUninitialize();
-    return 0;
-}
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionLanguage"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"XPath"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
 
-static void test_get_parentNode(void)
-{
-    IXMLDOMDocument *doc;
-    IXMLDOMNode *node;
-    HRESULT hr;
+    hr = IXMLDOMDocument2_getProperty(doc, _bstr_("SelectionLanguage"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(V_BSTR(&var), L"XPath"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
 
-    hr = CoCreateInstance(&CLSID_DOMDocument2, NULL, CLSCTX_INPROC_SERVER, &IID_IXMLDOMDocument, (void **)&doc);
+    hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), _variantbstr_("XSLPattern"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
-    hr = IXMLDOMDocument_get_parentNode(doc, NULL);
-    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument2_get_xml(doc, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"<b>text</b>\r\n"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
 
-    node = (void *)0x1;
-    hr = IXMLDOMDocument_get_parentNode(doc, &node);
-    ok(hr == S_FALSE, "Unexpected hr %#lx.\n", hr);
-    ok(!node, "Unexpected node %p.\n", node);
+    hr = IXMLDOMElement_get_ownerDocument(element, &owner);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMDocument_get_xml(owner, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<b>text</b>\r\n"), "Unexpected xml %s.\n", debugstr_w(str));
+    hr = IXMLDOMDocument_get_documentElement(owner, &element2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    hr = IXMLDOMElement_get_xml(element2, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(str, L"<b>text</b>"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+    IXMLDOMElement_Release(element2);
+    SysFreeString(str);
 
-    IXMLDOMDocument_Release(doc);
+    hr = IXMLDOMElement_get_xml(element, &str);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!wcscmp(str, L"<a>text</a>"), "Unexpected xml %s.\n", debugstr_w(str));
+    SysFreeString(str);
+
+    hr = IXMLDOMDocument_QueryInterface(owner, &IID_IXMLDOMDocument2, (void **)&doc2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    IXMLDOMDocument_Release(owner);
+
+    hr = IXMLDOMDocument2_getProperty(doc2, _bstr_("SelectionLanguage"), &var);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    todo_wine
+    ok(!wcscmp(V_BSTR(&var), L"XSLPattern"), "Unexpected value %s.\n", debugstr_w(V_BSTR(&var)));
+    VariantClear(&var);
+
+    IXMLDOMElement_Release(element);
+    IXMLDOMDocument2_Release(doc2);
+    IXMLDOMDocument2_Release(doc);
+    free_bstrs();
 }
 
 START_TEST(domdoc)
@@ -14717,7 +16320,6 @@ START_TEST(domdoc)
     test_testTransforms();
     test_namespaces_basic();
     test_namespaces_change();
-    test_FormattingXML();
     test_nodeTypedValue();
     test_TransformWithLoadingLocalFile();
     test_put_nodeValue();
@@ -14768,6 +16370,17 @@ START_TEST(domdoc)
     test_max_element_depth_values();
     test_get_parentNode();
     test_put_text();
+    test_removeAttributeNode();
+    test_comment();
+    test_pi();
+    test_dom_impl();
+    test_doc_fragment();
+    test_text();
+    test_attribute_value();
+    test_xmldecl_attributes();
+    test_loadXML();
+    test_cdata();
+    test_document_reload();
 
     if (is_clsid_supported(&CLSID_MXNamespaceManager40, &IID_IMXNamespaceManager))
     {
diff --git a/dlls/netprofm/list.c b/dlls/netprofm/list.c
index 2b156fc562ca..197e3504e4f9 100644
--- a/dlls/netprofm/list.c
+++ b/dlls/netprofm/list.c
@@ -1800,30 +1800,41 @@ static IP_ADAPTER_ADDRESSES *get_network_adapters(void)
     return NULL;
 }
 
-static inline BOOL is_link_local( const SOCKADDR *addr )
+static void has_ipv6_address( const IP_ADAPTER_ADDRESSES *aa, BOOL *has_local, BOOL *has_global )
 {
-    const struct sockaddr_in6 *in = (const struct sockaddr_in6 *)addr;
-    return in->sin6_family == AF_INET6 && in->sin6_addr.u.Byte[0] == 0xfe && (in->sin6_addr.u.Byte[1] & 0xc0) == 0x80;
+    const IP_ADAPTER_UNICAST_ADDRESS *addr = aa->FirstUnicastAddress;
+    const struct in6_addr *sa6;
+
+    *has_local = *has_global = FALSE;
+    for (addr = aa->FirstUnicastAddress; addr; addr = addr->Next)
+    {
+        if (addr->Address.lpSockaddr->sa_family != AF_INET6) continue;
+        sa6 = &((struct sockaddr_in6 *)addr->Address.lpSockaddr)->sin6_addr;
+        if (IN6_IS_ADDR_LINKLOCAL(sa6) || IN6_IS_ADDR_SITELOCAL(sa6))
+            *has_local = TRUE;
+        else if (!IN6_IS_ADDR_UNSPECIFIED(sa6) && !IN6_IS_ADDR_MULTICAST(sa6) && !IN6_IS_ADDR_LOOPBACK(sa6))
+            *has_global = TRUE;
+    }
 }
 
-static BOOL has_address( const IP_ADAPTER_ADDRESSES *aa, USHORT family )
+static BOOL has_ipv4_address( const IP_ADAPTER_ADDRESSES *aa )
 {
     const IP_ADAPTER_UNICAST_ADDRESS *addr = aa->FirstUnicastAddress;
     while (addr)
     {
-        if (addr->Address.lpSockaddr->sa_family == family && !is_link_local( addr->Address.lpSockaddr ))
+        if (addr->Address.lpSockaddr->sa_family == AF_INET)
             return TRUE;
         addr = addr->Next;
     }
     return FALSE;
 }
 
-static BOOL has_gateway_address( const IP_ADAPTER_ADDRESSES *aa, USHORT family )
+static BOOL has_ipv4_gateway_address( const IP_ADAPTER_ADDRESSES *aa )
 {
     const IP_ADAPTER_GATEWAY_ADDRESS *addr = aa->FirstGatewayAddress;
     while (addr)
     {
-        if (addr->Address.lpSockaddr->sa_family == family && !is_link_local( addr->Address.lpSockaddr ))
+        if (addr->Address.lpSockaddr->sa_family == AF_INET)
             return TRUE;
         addr = addr->Next;
     }
@@ -1832,6 +1843,7 @@ static BOOL has_gateway_address( const IP_ADAPTER_ADDRESSES *aa, USHORT family )
 
 static void init_networks( struct list_manager *mgr )
 {
+    BOOL has_local, has_global;
     IP_ADAPTER_ADDRESSES *buf, *aa;
     GUID id;
 
@@ -1862,26 +1874,27 @@ static void init_networks( struct list_manager *mgr )
             goto done;
         }
 
-        if (has_address( aa, AF_INET ))
-        {
-            network->connected_v4 = VARIANT_TRUE;
-            connection->connected_v4 = VARIANT_TRUE;
-        }
-        if (has_address( aa, AF_INET6 ))
+        has_ipv6_address( aa, &has_local, &has_global );
+        if (has_local || has_global)
         {
             network->connected_v6 = VARIANT_TRUE;
             connection->connected_v6 = VARIANT_TRUE;
         }
-        if (has_gateway_address( aa, AF_INET ))
-        {
-            network->connected_to_internet_v4 = VARIANT_TRUE;
-            connection->connected_to_internet_v4 = VARIANT_TRUE;
-        }
-        if (has_gateway_address( aa, AF_INET6 ))
+        if (has_global)
         {
             network->connected_to_internet_v6 = VARIANT_TRUE;
             connection->connected_to_internet_v6 = VARIANT_TRUE;
         }
+        if (has_ipv4_address( aa ))
+        {
+            network->connected_v4 = VARIANT_TRUE;
+            connection->connected_v4 = VARIANT_TRUE;
+        }
+        if (has_ipv4_gateway_address( aa ))
+        {
+            network->connected_to_internet_v4 = VARIANT_TRUE;
+            connection->connected_to_internet_v4 = VARIANT_TRUE;
+        }
 
         network->mgr = &mgr->INetworkListManager_iface;
         INetworkListManager_AddRef( network->mgr );
diff --git a/dlls/ninput/main.c b/dlls/ninput/main.c
index 062b1c4a3a75..5e8c88af6479 100644
--- a/dlls/ninput/main.c
+++ b/dlls/ninput/main.c
@@ -257,3 +257,14 @@ HRESULT WINAPI ProcessInertiaInteractionContext(HINTERACTIONCONTEXT context)
     FIXME("context %p: stub!\n", context);
     return E_NOTIMPL;
 }
+
+/* Undocumented function at ordinal 2502 */
+HRESULT WINAPI NINPUT_2502(HINTERACTIONCONTEXT *context, void *p1, void *p2)
+{
+    FIXME("context %p p1 %p p2 %p: stub!\n", context, p1, p2);
+
+    if (!context)
+        return E_HANDLE;
+
+    return S_OK;
+}
diff --git a/dlls/ninput/ninput.spec b/dlls/ninput/ninput.spec
index 85f0e21a1468..34fbf2bc5ef4 100644
--- a/dlls/ninput/ninput.spec
+++ b/dlls/ninput/ninput.spec
@@ -1,4 +1,4 @@
-@ stub DefaultInputHandler
+1 stub DefaultInputHandler
 @ stub AddPointerInteractionContext
 @ stdcall BufferPointerPacketsInteractionContext(ptr long ptr)
 @ stdcall CreateInteractionContext(ptr)
@@ -22,3 +22,11 @@
 @ stub SetPivotInteractionContext
 @ stdcall SetPropertyInteractionContext(ptr long long)
 @ stub StopInteractionContext
+
+2500 stub @
+2501 stub @
+2502 stdcall @(ptr ptr ptr) NINPUT_2502
+2503 stub @
+2504 stub @
+2505 stub @
+2506 stub @
diff --git a/dlls/ninput/tests/ninput.c b/dlls/ninput/tests/ninput.c
index 3409fedd8681..97434f1624bf 100644
--- a/dlls/ninput/tests/ninput.c
+++ b/dlls/ninput/tests/ninput.c
@@ -296,6 +296,30 @@ static void test_ProcessBufferedPacketsInteractionContext(void)
     ok(hr == S_OK, "Failed to destroy context, hr %#lx.\n", hr);
 }
 
+static void test_ordinal_2502(void)
+{
+    static HRESULT (WINAPI *pOrdinal2502)(void *, void *, void *);
+    HINTERACTIONCONTEXT context;
+    HMODULE module;
+    HRESULT hr;
+
+    module = GetModuleHandleA("ninput");
+    pOrdinal2502 = (void *)GetProcAddress(module, (LPCSTR)2502);
+    ok(!!pOrdinal2502, "Failed to retrieve the function at ordinal 2502.\n");
+
+    hr = pOrdinal2502(NULL, NULL, NULL);
+    ok(hr == E_HANDLE, "Got unexpected hr %#lx.\n", hr);
+
+    hr = CreateInteractionContext(&context);
+    ok(hr == S_OK, "Failed to create context, hr %#lx.\n", hr);
+
+    hr = pOrdinal2502(context, NULL, NULL);
+    ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr);
+
+    hr = DestroyInteractionContext(context);
+    ok(hr == S_OK, "Failed to destroy context, hr %#lx.\n", hr);
+}
+
 START_TEST(ninput)
 {
     test_context();
@@ -304,4 +328,5 @@ START_TEST(ninput)
     test_BufferPointerPacketsInteractionContext();
     test_GetStateInteractionContext();
     test_ProcessBufferedPacketsInteractionContext();
+    test_ordinal_2502();
 }
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index ad5c3bdc60f8..022583aa20e2 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -4,8 +4,8 @@ UNIXLIB   = ntdll.so
 IMPORTLIB = ntdll
 IMPORTS   = $(TOMCRYPT_PE_LIBS) $(MUSL_PE_LIBS)
 EXTRAINCL = $(TOMCRYPT_PE_CFLAGS)
-UNIX_CFLAGS  = $(UNWIND_CFLAGS) $(HWLOC_CFLAGS)
-UNIX_LIBS    = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS)
+UNIX_CFLAGS  = $(HWLOC_CFLAGS)
+UNIX_LIBS    = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS)
 
 EXTRADLLFLAGS = -nodefaultlibs
 i386_EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000
@@ -15,6 +15,7 @@ VER_PRODUCTVERSION = 6,1,7601,24059
 
 SOURCES = \
 	actctx.c \
+	alpc.c \
 	atom.c \
 	crypt.c \
 	debugbuffer.c \
diff --git a/dlls/ntdll/alpc.c b/dlls/ntdll/alpc.c
new file mode 100644
index 000000000000..cba85e19a83b
--- /dev/null
+++ b/dlls/ntdll/alpc.c
@@ -0,0 +1,98 @@
+/*
+ * Advanced Local Procedure Call
+ *
+ * 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 <stdarg.h>
+#include <windef.h>
+#include <winternl.h>
+#include <ntstatus.h>
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(alpc);
+
+SIZE_T WINAPI AlpcGetHeaderSize(ULONG attribute_flags)
+{
+    static const struct
+    {
+        ULONG attribute;
+        SIZE_T size;
+    } attribute_sizes[] =
+    {
+        /* Attribute with a higher bit is stored before that with a lower bit */
+        {ALPC_MESSAGE_SECURITY_ATTRIBUTE, sizeof(ALPC_SECURITY_ATTR)},
+        {ALPC_MESSAGE_VIEW_ATTRIBUTE, sizeof(ALPC_VIEW_ATTR)},
+        {ALPC_MESSAGE_CONTEXT_ATTRIBUTE, sizeof(ALPC_CONTEXT_ATTR)},
+        {ALPC_MESSAGE_HANDLE_ATTRIBUTE, sizeof(ALPC_HANDLE_ATTR)},
+        {ALPC_MESSAGE_TOKEN_ATTRIBUTE, sizeof(ALPC_TOKEN_ATTR)},
+        {ALPC_MESSAGE_DIRECT_ATTRIBUTE, sizeof(ALPC_DIRECT_ATTR)},
+        {ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE, sizeof(ALPC_WORK_ON_BEHALF_ATTR)},
+    };
+    unsigned int i;
+    SIZE_T size;
+
+    TRACE("%#lx.\n", attribute_flags);
+
+    size = sizeof(ALPC_MESSAGE_ATTRIBUTES);
+    for (i = 0; i < ARRAY_SIZE(attribute_sizes); i++)
+    {
+        if (attribute_flags & attribute_sizes[i].attribute)
+            size += attribute_sizes[i].size;
+    }
+
+    return size;
+}
+
+void * WINAPI AlpcGetMessageAttribute(ALPC_MESSAGE_ATTRIBUTES *attributes, ULONG attribute_flag)
+{
+    TRACE("%p, %lx.\n", attributes, attribute_flag);
+
+    /* If no flag is specified */
+    if (!attribute_flag)
+        return NULL;
+
+    /* If more than one flag is specified */
+    if (attribute_flag & (attribute_flag - 1))
+        return NULL;
+
+    /* If the specified flag is not in allocated attributes */
+    if ((attribute_flag & attributes->AllocatedAttributes & ALPC_MESSAGE_ATTRIBUTE_ALL) != attribute_flag)
+        return NULL;
+
+    return (unsigned char *)attributes + AlpcGetHeaderSize(attributes->AllocatedAttributes & ~(attribute_flag | (attribute_flag - 1)));
+}
+
+NTSTATUS WINAPI AlpcInitializeMessageAttribute(ULONG attribute_flags, ALPC_MESSAGE_ATTRIBUTES *buffer,
+                                               SIZE_T buffer_size, SIZE_T *required_buffer_size)
+{
+    TRACE("%#lx, %p, %Ix, %p.\n", attribute_flags, buffer, buffer_size, required_buffer_size);
+
+    *required_buffer_size = AlpcGetHeaderSize(attribute_flags);
+
+    if (buffer_size < *required_buffer_size)
+        return STATUS_BUFFER_TOO_SMALL;
+
+    if (buffer)
+    {
+        buffer->AllocatedAttributes = attribute_flags;
+        buffer->ValidAttributes = 0;
+    }
+
+    return STATUS_SUCCESS;
+
+}
diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
index 4f21222ece62..a2b7513bfa3a 100644
--- a/dlls/ntdll/exception.c
+++ b/dlls/ntdll/exception.c
@@ -164,7 +164,6 @@ static LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
     while (entry != mark)
     {
         handler = CONTAINING_RECORD( entry, VECTORED_HANDLER, entry );
-        entry = entry->Flink;
         ++*handler->count;
         func = RtlDecodePointer( handler->func );
         RtlLeaveCriticalSection( &vectored_handlers_section );
@@ -177,6 +176,7 @@ static LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context )
         TRACE( "handler at %p returned %lx\n", func, ret );
 
         RtlEnterCriticalSection( &vectored_handlers_section );
+        entry = entry->Flink;
         if (!--*handler->count)  /* removed during execution */
         {
             RemoveEntryList( &handler->entry );
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 7d04a80b1eb6..f396c334e2d1 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -6,6 +6,9 @@
 @ stdcall A_SHAFinal(ptr ptr)
 @ stdcall A_SHAInit(ptr)
 @ stdcall A_SHAUpdate(ptr ptr long)
+@ stdcall AlpcGetHeaderSize(long)
+@ stdcall AlpcInitializeMessageAttribute(long ptr long ptr)
+@ stdcall AlpcGetMessageAttribute(ptr long)
 @ stdcall ApiSetQueryApiSetPresence(ptr ptr)
 @ stdcall ApiSetQueryApiSetPresenceEx(ptr ptr ptr)
 @ stub CsrAllocateCaptureBuffer
@@ -230,7 +233,7 @@
 @ stdcall -syscall NtFlushInstructionCache(long ptr long)
 @ stdcall -syscall NtFlushKey(long)
 @ stdcall -syscall NtFlushProcessWriteBuffers()
-@ stdcall -syscall NtFlushVirtualMemory(long ptr ptr long)
+@ stdcall -syscall NtFlushVirtualMemory(long ptr ptr ptr)
 # @ stub NtFlushWriteBuffer
 # @ stub NtFreeUserPhysicalPages
 @ stdcall -syscall=0x001e NtFreeVirtualMemory(long ptr ptr long)
@@ -1303,7 +1306,7 @@
 @ stdcall -private ZwFlushInstructionCache(long ptr long) NtFlushInstructionCache
 @ stdcall -private ZwFlushKey(long) NtFlushKey
 @ stdcall -private ZwFlushProcessWriteBuffers() NtFlushProcessWriteBuffers
-@ stdcall -private ZwFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory
+@ stdcall -private ZwFlushVirtualMemory(long ptr ptr ptr) NtFlushVirtualMemory
 # @ stub ZwFlushWriteBuffer
 # @ stub ZwFreeUserPhysicalPages
 @ stdcall -private ZwFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory
diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c
index 092126f1c469..954ace7824e4 100644
--- a/dlls/ntdll/signal_arm64ec.c
+++ b/dlls/ntdll/signal_arm64ec.c
@@ -420,7 +420,7 @@ DEFINE_SYSCALL(NtFlushBuffersFileEx, (HANDLE handle, ULONG flags, void *params,
 DEFINE_WRAPPED_SYSCALL(NtFlushInstructionCache, (HANDLE handle, const void *addr, SIZE_T size))
 DEFINE_SYSCALL(NtFlushKey, (HANDLE key))
 DEFINE_SYSCALL(NtFlushProcessWriteBuffers, (void))
-DEFINE_SYSCALL(NtFlushVirtualMemory, (HANDLE process, LPCVOID *addr_ptr, SIZE_T *size_ptr, ULONG unknown))
+DEFINE_SYSCALL(NtFlushVirtualMemory, (HANDLE process, LPCVOID *addr_ptr, SIZE_T *size_ptr, IO_STATUS_BLOCK *io))
 DEFINE_WRAPPED_SYSCALL(NtFreeVirtualMemory, (HANDLE process, PVOID *addr_ptr, SIZE_T *size_ptr, ULONG type))
 DEFINE_SYSCALL(NtFsControlFile, (HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_context, IO_STATUS_BLOCK *io, ULONG code, void *in_buffer, ULONG in_size, void *out_buffer, ULONG out_size))
 DEFINE_WRAPPED_SYSCALL(NtGetContextThread, (HANDLE handle, ARM64_NT_CONTEXT *context))
diff --git a/dlls/ntdll/tests/Makefile.in b/dlls/ntdll/tests/Makefile.in
index 42d663777eaa..96265a693448 100644
--- a/dlls/ntdll/tests/Makefile.in
+++ b/dlls/ntdll/tests/Makefile.in
@@ -2,6 +2,7 @@ TESTDLL   = ntdll.dll
 IMPORTS   = user32 advapi32
 
 SOURCES = \
+	alpc.c \
 	atom.c \
 	change.c \
 	directory.c \
diff --git a/dlls/ntdll/tests/alpc.c b/dlls/ntdll/tests/alpc.c
new file mode 100644
index 000000000000..f34da2090417
--- /dev/null
+++ b/dlls/ntdll/tests/alpc.c
@@ -0,0 +1,352 @@
+/*
+ * Advanced Local Procedure Call tests
+ *
+ * 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 <stdarg.h>
+#include <windef.h>
+#include <winternl.h>
+#include <ntstatus.h>
+#include "wine/test.h"
+
+#define DECL_FUNCPTR(f) static typeof(f) *p##f;
+
+DECL_FUNCPTR(AlpcGetHeaderSize)
+DECL_FUNCPTR(AlpcGetMessageAttribute)
+DECL_FUNCPTR(AlpcInitializeMessageAttribute)
+
+#undef DECL_FUNCPTR
+
+static void init_functions(void)
+{
+    HMODULE ntdll;
+
+    ntdll = GetModuleHandleA("ntdll.dll");
+    ok(ntdll != NULL, "GetModuleHandleA failed.\n");
+
+#define LOAD_FUNCPTR(f) p##f = (void *)GetProcAddress(ntdll, #f);
+
+    LOAD_FUNCPTR(AlpcGetHeaderSize)
+    LOAD_FUNCPTR(AlpcGetMessageAttribute)
+    LOAD_FUNCPTR(AlpcInitializeMessageAttribute)
+
+#undef LOAD_FUNCPTR
+}
+
+static void test_AlpcGetHeaderSize(void)
+{
+    unsigned int i, j;
+    SIZE_T size;
+
+    static const struct
+    {
+        ULONG attribute;
+        SIZE_T size;
+    }
+    tests[] =
+    {
+        {0, 0},
+        {1u << 1, 0},
+        {1u << 2, 0},
+        {1u << 3, 0},
+        {1u << 4, 0},
+        {1u << 5, 0},
+        {1u << 6, 0},
+        {1u << 7, 0},
+        {1u << 8, 0},
+        {1u << 9, 0},
+        {1u << 10, 0},
+        {1u << 11, 0},
+        {1u << 12, 0},
+        {1u << 13, 0},
+        {1u << 14, 0},
+        {1u << 15, 0},
+        {1u << 16, 0},
+        {1u << 17, 0},
+        {1u << 18, 0},
+        {1u << 19, 0},
+        {1u << 20, 0},
+        {1u << 21, 0},
+        {1u << 22, 0},
+        {1u << 23, 0},
+        {1u << 24, 0},
+        {1u << 25, sizeof(ALPC_WORK_ON_BEHALF_ATTR)},   /* ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE */
+        {1u << 26, sizeof(ALPC_DIRECT_ATTR)},           /* ALPC_MESSAGE_DIRECT_ATTRIBUTE */
+        {1u << 27, sizeof(ALPC_TOKEN_ATTR)},            /* ALPC_MESSAGE_TOKEN_ATTRIBUTE */
+        {1u << 28, sizeof(ALPC_HANDLE_ATTR)},           /* ALPC_MESSAGE_HANDLE_ATTRIBUTE */
+        {1u << 29, sizeof(ALPC_CONTEXT_ATTR)},          /* ALPC_MESSAGE_CONTEXT_ATTRIBUTE */
+        {1u << 30, sizeof(ALPC_VIEW_ATTR)},             /* ALPC_MESSAGE_VIEW_ATTRIBUTE */
+        {1u << 31, sizeof(ALPC_SECURITY_ATTR)},         /* ALPC_MESSAGE_SECURITY_ATTRIBUTE */
+        {0xffffffff, sizeof(ALPC_WORK_ON_BEHALF_ATTR) +
+                     sizeof(ALPC_DIRECT_ATTR) +
+                     sizeof(ALPC_TOKEN_ATTR) +
+                     sizeof(ALPC_HANDLE_ATTR) +
+                     sizeof(ALPC_CONTEXT_ATTR) +
+                     sizeof(ALPC_VIEW_ATTR) +
+                     sizeof(ALPC_SECURITY_ATTR)},       /* All attributes */
+    };
+
+    if (!pAlpcGetHeaderSize)
+    {
+        win_skip("AlpcGetHeaderSize is unavailable.\n");
+        return;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(tests); i++)
+    {
+        winetest_push_context("i %d", i);
+
+        /* Single attribute */
+        size = pAlpcGetHeaderSize(tests[i].attribute);
+        ok(size == sizeof(ALPC_MESSAGE_ATTRIBUTES) + tests[i].size, "Got unexpected size %Ix.\n", size);
+
+        /* Two attributes */
+        for (j = 0; j < ARRAY_SIZE(tests); j++)
+        {
+            if (tests[i].attribute & tests[j].attribute)
+                continue;
+
+            winetest_push_context("j %d", j);
+
+            size = pAlpcGetHeaderSize(tests[i].attribute | tests[j].attribute);
+            ok(size == sizeof(ALPC_MESSAGE_ATTRIBUTES) + tests[i].size + tests[j].size,
+               "Got unexpected size %Ix.\n", size);
+
+            winetest_pop_context();
+        }
+        winetest_pop_context();
+    }
+}
+
+static void test_AlpcGetMessageAttribute(void)
+{
+    unsigned char buffer[1024];
+    ALPC_MESSAGE_ATTRIBUTES *attr = (ALPC_MESSAGE_ATTRIBUTES *)buffer;
+    unsigned int i, j;
+    void *ptr;
+
+    static const ULONG attributes[] =
+    {
+        0,
+        ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE,
+        ALPC_MESSAGE_DIRECT_ATTRIBUTE,
+        ALPC_MESSAGE_TOKEN_ATTRIBUTE,
+        ALPC_MESSAGE_HANDLE_ATTRIBUTE,
+        ALPC_MESSAGE_CONTEXT_ATTRIBUTE,
+        ALPC_MESSAGE_VIEW_ATTRIBUTE,
+        ALPC_MESSAGE_SECURITY_ATTRIBUTE,
+    };
+
+    if (!pAlpcGetMessageAttribute)
+    {
+        win_skip("AlpcGetMessageAttribute is unavailable.\n");
+        return;
+    }
+
+    /* Invalid flag */
+    attr->AllocatedAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+    attr->ValidAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+    ptr = pAlpcGetMessageAttribute(attr, 0x1);
+    ok(ptr == NULL, "Got unexpected ptr.\n");
+
+    for (i = 0; i < ARRAY_SIZE(attributes); i++)
+    {
+        winetest_push_context("%#lx", attributes[i]);
+
+        /* The message has no allocated attributes */
+        attr->AllocatedAttributes = 0;
+        attr->ValidAttributes = attributes[i];
+        ptr = pAlpcGetMessageAttribute(attr, attributes[i]);
+        ok(ptr == NULL, "Got unexpected ptr.\n");
+
+        /* The message has no valid attributes */
+        attr->AllocatedAttributes = attributes[i];
+        attr->ValidAttributes = 0;
+        ptr = pAlpcGetMessageAttribute(attr, attributes[i]);
+        if (attributes[i])
+            ok(ptr == ((unsigned char *)attr + sizeof(*attr)), "Got unexpected ptr.\n");
+        else
+            ok(ptr == NULL, "Got unexpected ptr.\n");
+
+        /* Normal calls */
+        attr->AllocatedAttributes = attributes[i];
+        attr->ValidAttributes = attributes[i];
+        ptr = pAlpcGetMessageAttribute(attr, attributes[i]);
+        if (attributes[i])
+            ok(ptr == ((unsigned char *)attr + sizeof(*attr)), "Got unexpected ptr.\n");
+        else
+            ok(ptr == NULL, "Got unexpected ptr.\n");
+
+        /* The message has full attributes */
+        attr->AllocatedAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+        attr->ValidAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+        ptr = pAlpcGetMessageAttribute(attr, attributes[i]);
+        if (attributes[i])
+            ok(ptr == ((unsigned char *)attr + pAlpcGetHeaderSize(attr->AllocatedAttributes & ~(attributes[i] | (attributes[i] - 1)))),
+               "Got unexpected ptr.\n");
+        else
+            ok(ptr == NULL, "Got unexpected ptr.\n");
+
+        /* The message has some valid attributes */
+        for (j = 0; j < ARRAY_SIZE(attributes); j++)
+        {
+            attr->AllocatedAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+            attr->ValidAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL & ~attributes[j];
+            ptr = pAlpcGetMessageAttribute(attr, attributes[i]);
+            if (attributes[i])
+                ok(ptr == ((unsigned char *)attr + pAlpcGetHeaderSize(attr->AllocatedAttributes & ~(attributes[i] | (attributes[i] - 1)))),
+                   "Got unexpected ptr.\n");
+            else
+                ok(ptr == NULL, "Got unexpected ptr.\n");
+        }
+
+        /* Two attributes are passed to AlpcGetMessageAttribute() */
+        for (j = 0; j < ARRAY_SIZE(attributes); j++)
+        {
+            if (!attributes[i] || !attributes[j] || attributes[i] == attributes[j])
+                continue;
+
+            attr->AllocatedAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+            attr->ValidAttributes = ALPC_MESSAGE_ATTRIBUTE_ALL;
+            ptr = pAlpcGetMessageAttribute(attr, attributes[i] | attributes[j]);
+            ok(ptr == NULL, "Got unexpected ptr.\n");
+        }
+
+        winetest_pop_context();
+    }
+}
+
+static void test_AlpcInitializeMessageAttribute(void)
+{
+    unsigned char buffer[1024];
+    ALPC_MESSAGE_ATTRIBUTES *attr = (ALPC_MESSAGE_ATTRIBUTES *)buffer;
+    SIZE_T required_size, size;
+    unsigned int i, j, k;
+    NTSTATUS status;
+
+    static const ULONG attributes[] =
+    {
+        0,
+        ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE,
+        ALPC_MESSAGE_DIRECT_ATTRIBUTE,
+        ALPC_MESSAGE_TOKEN_ATTRIBUTE,
+        ALPC_MESSAGE_HANDLE_ATTRIBUTE,
+        ALPC_MESSAGE_CONTEXT_ATTRIBUTE,
+        ALPC_MESSAGE_VIEW_ATTRIBUTE,
+        ALPC_MESSAGE_SECURITY_ATTRIBUTE,
+        0xffffffff,
+    };
+
+    if (!pAlpcInitializeMessageAttribute)
+    {
+        win_skip("AlpcInitializeMessageAttribute is unavailable.\n");
+        return;
+    }
+
+    /* Check parameters */
+    for (i = 0; i < ARRAY_SIZE(attributes); i++)
+    {
+        winetest_push_context("i %d", i);
+
+        size = pAlpcGetHeaderSize(attributes[i]);
+
+        /* Null message pointer */
+        required_size = 0;
+        status = pAlpcInitializeMessageAttribute(attributes[i], NULL, size, &required_size);
+        ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+        ok(required_size == size, "Expected %Ix, got %Ix.\n", size, required_size);
+
+        /* Buffer too small */
+        attr->AllocatedAttributes = 0xdeadbeef;
+        attr->ValidAttributes = 0xdeadbeef;
+        required_size = 0;
+        status = pAlpcInitializeMessageAttribute(attributes[i], attr, size - 1, &required_size);
+        ok(status == STATUS_BUFFER_TOO_SMALL, "Got unexpected status %#lx.\n", status);
+        ok(attr->AllocatedAttributes == 0xdeadbeef, "Got unexpected %#lx.\n", attr->AllocatedAttributes);
+        ok(attr->ValidAttributes == 0xdeadbeef, "Got unexpected %#lx.\n", attr->ValidAttributes);
+        ok(required_size == size, "Expected %Ix, got %Ix.\n", size, required_size);
+
+        /* Buffer too large */
+        attr->AllocatedAttributes = 0xdeadbeef;
+        attr->ValidAttributes = 0xdeadbeef;
+        required_size = 0;
+        status = pAlpcInitializeMessageAttribute(attributes[i], attr, size + 1, &required_size);
+        ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+        ok(attr->AllocatedAttributes == attributes[i], "Got unexpected %#lx.\n", attr->AllocatedAttributes);
+        ok(attr->ValidAttributes == 0, "Got unexpected %#lx.\n", attr->ValidAttributes);
+        ok(required_size == size, "Expected %Ix, got %Ix.\n", size, required_size);
+
+        /* Correct buffer size */
+        memset(buffer, 0xa1, sizeof(buffer));
+        required_size = 0;
+        status = pAlpcInitializeMessageAttribute(attributes[i], attr, size, &required_size);
+        ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+        ok(attr->AllocatedAttributes == attributes[i], "Got unexpected %#lx.\n", attr->AllocatedAttributes);
+        ok(attr->ValidAttributes == 0, "Got unexpected %#lx.\n", attr->ValidAttributes);
+        ok(required_size == size, "Expected %Ix, got %Ix.\n", size, required_size);
+        /* Test that AlpcInitializeMessageAttribute() only sets AllocatedAttributes and ValidAttributes */
+        for (k = sizeof(*attr); k < sizeof(buffer); k++)
+        {
+            if (buffer[k] != 0xa1)
+            {
+                ok(0, "Marker got overwritten at %d.\n", k);
+                break;
+            }
+        }
+
+        /* Two attributes */
+        for (j = 0; j < ARRAY_SIZE(attributes); j++)
+        {
+            if (attributes[i] & attributes[j])
+                continue;
+
+            winetest_push_context("j %d", j);
+
+            memset(buffer, 0xb2, sizeof(buffer));
+            size = pAlpcGetHeaderSize(attributes[i] | attributes[j]);
+            required_size = 0;
+            status = pAlpcInitializeMessageAttribute(attributes[i] | attributes[j], attr, size, &required_size);
+            ok(status == STATUS_SUCCESS, "Got unexpected status %#lx.\n", status);
+            ok(attr->AllocatedAttributes == (attributes[i] | attributes[j]),
+               "Got unexpected %#lx.\n", attr->AllocatedAttributes);
+            ok(attr->ValidAttributes == 0, "Got unexpected %#lx.\n", attr->ValidAttributes);
+            ok(required_size == size, "Expected %Ix, got %Ix.\n", size, required_size);
+            /* Test that AlpcInitializeMessageAttribute() only sets AllocatedAttributes and ValidAttributes */
+            for (k = sizeof(*attr); k < sizeof(buffer); k++)
+            {
+                if (buffer[k] != 0xb2)
+                {
+                    ok(0, "Marker got overwritten at %d.\n", k);
+                    break;
+                }
+            }
+
+            winetest_pop_context();
+        }
+        winetest_pop_context();
+    }
+}
+
+START_TEST(alpc)
+{
+    init_functions();
+
+    test_AlpcGetHeaderSize();
+    test_AlpcGetMessageAttribute();
+    test_AlpcInitializeMessageAttribute();
+}
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 3d4c7d956f85..3b133ce1c696 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -2876,12 +2876,9 @@ static void test_readvirtualmemory(void)
     ok( strcmp(teststring, buffer) == 0, "Expected read memory to be the same as original memory\n");
 
     /* illegal remote address */
-    todo_wine{
     status = pNtReadVirtualMemory(process, (void *) 0x1234, buffer, 12, &readcount);
     ok( status == STATUS_PARTIAL_COPY, "Expected STATUS_PARTIAL_COPY, got %08lx\n", status);
-    if (status == STATUS_PARTIAL_COPY)
-        ok( readcount == 0, "Expected to read 0 bytes, got %Id\n",readcount);
-    }
+    ok( readcount == 0, "Expected to read 0 bytes, got %Id\n",readcount);
 
     /* 0 handle */
     status = pNtReadVirtualMemory(0, teststring, buffer, 12, &readcount);
diff --git a/dlls/ntdll/tests/wow64.c b/dlls/ntdll/tests/wow64.c
index 92d35d8647fc..59601c49563e 100644
--- a/dlls/ntdll/tests/wow64.c
+++ b/dlls/ntdll/tests/wow64.c
@@ -153,8 +153,11 @@ static void init(void)
     {
         SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION machines[8];
         HANDLE process = GetCurrentProcess();
-        NTSTATUS status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process,
+        NTSTATUS status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures2, &process,
                                                        sizeof(process), machines, sizeof(machines), NULL );
+        if (status)
+            status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process,
+                                                  sizeof(process), machines, sizeof(machines), NULL );
         if (!status)
             for (int i = 0; machines[i].Machine; i++)
                 trace( "machine %04x kernel %u user %u native %u process %u wow64 %u\n",
@@ -203,14 +206,18 @@ static BOOL create_process_machine( char *cmdline, DWORD flags, USHORT machine,
     return ret;
 }
 
-static void test_process_architecture( HANDLE process, USHORT expect_machine, USHORT expect_native )
+static void test_process_architecture( SYSTEM_INFORMATION_CLASS class, HANDLE process, USHORT expect_machine, USHORT expect_native )
 {
     SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION machines[8];
     NTSTATUS status;
     ULONG i, len;
 
+    if (class == SystemSupportedProcessorArchitectures &&
+        native_machine == IMAGE_FILE_MACHINE_ARM64 && expect_machine == IMAGE_FILE_MACHINE_AMD64)
+        expect_machine = IMAGE_FILE_MACHINE_ARM64;
+
     len = 0xdead;
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
+    status = pNtQuerySystemInformationEx( class, &process, sizeof(process),
                                           machines, sizeof(machines), &len );
     ok( !status, "failed %lx\n", status );
     ok( !(len & 3), "wrong len %lx\n", len );
@@ -230,11 +237,15 @@ static void test_process_architecture( HANDLE process, USHORT expect_machine, US
         if (machines[i].WoW64Container)
             ok( is_machine_32bit( machines[i].Machine ) && !is_machine_32bit( native_machine ),
                 "wrong wow64 %x\n", machines[i].Machine);
+
+        if (class == SystemSupportedProcessorArchitectures && native_machine == IMAGE_FILE_MACHINE_ARM64)
+            ok( machines[i].Machine != IMAGE_FILE_MACHINE_AMD64,
+                "SystemSupportedProcessorArchitectures returned AMD64\n");
     }
     ok( !*(DWORD *)&machines[i], "missing terminating null\n" );
 
     len = i * sizeof(machines[0]);
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
+    status = pNtQuerySystemInformationEx( class, &process, sizeof(process),
                                           machines, len, &len );
     ok( status == STATUS_BUFFER_TOO_SMALL, "failed %lx\n", status );
     ok( len == (i + 1) * sizeof(machines[0]), "wrong len %lu\n", len );
@@ -244,7 +255,8 @@ static void test_process_architecture( HANDLE process, USHORT expect_machine, US
         USHORT current = 0xdead, native = 0xbeef;
         status = pRtlWow64GetProcessMachines( process, &current, &native );
         ok( !status, "failed %lx\n", status );
-        if (expect_machine == expect_native)
+        if (expect_machine != IMAGE_FILE_MACHINE_I386 &&
+            expect_machine != IMAGE_FILE_MACHINE_ARMNT)
             ok( current == 0, "wrong current machine %x / %x\n", current, expect_machine );
         else
             ok( current == expect_machine, "wrong current machine %x / %x\n", current, expect_machine );
@@ -304,7 +316,7 @@ static void test_process_machine( HANDLE process, HANDLE thread,
     }
 }
 
-static void test_query_architectures(void)
+static void test_query_architectures(SYSTEM_INFORMATION_CLASS class)
 {
     static char cmd_sysnative[] = "C:\\windows\\sysnative\\cmd.exe /c exit";
     static char cmd_system32[] = "C:\\windows\\system32\\cmd.exe /c exit";
@@ -315,6 +327,7 @@ static void test_query_architectures(void)
     NTSTATUS status;
     HANDLE process;
     ULONG i, len;
+    USHORT machine;
 #ifdef __arm64ec__
     BOOL is_arm64ec = TRUE;
 #else
@@ -324,49 +337,50 @@ static void test_query_architectures(void)
     if (!pNtQuerySystemInformationEx) return;
 
     process = GetCurrentProcess();
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
+    status = pNtQuerySystemInformationEx( class, &process, sizeof(process),
                                           machines, sizeof(machines), &len );
     if (status == STATUS_INVALID_INFO_CLASS)
     {
-        win_skip( "SystemSupportedProcessorArchitectures not supported\n" );
+        win_skip( "SystemSupportedProcessorArchitectures%s not supported\n",
+                  class == SystemSupportedProcessorArchitectures2 ? "2" : "" );
         return;
     }
     ok( !status, "failed %lx\n", status );
 
     process = (HANDLE)0xdeadbeef;
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, sizeof(process),
+    status = pNtQuerySystemInformationEx( class, &process, sizeof(process),
                                           machines, sizeof(machines), &len );
     ok( status == STATUS_INVALID_HANDLE, "failed %lx\n", status );
     process = (HANDLE)0xdeadbeef;
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, 3,
+    status = pNtQuerySystemInformationEx( class, &process, 3,
                                           machines, sizeof(machines), &len );
     ok( status == STATUS_INVALID_PARAMETER || broken(status == STATUS_INVALID_HANDLE),
         "failed %lx\n", status );
     process = GetCurrentProcess();
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, &process, 3,
+    status = pNtQuerySystemInformationEx( class, &process, 3,
                                           machines, sizeof(machines), &len );
     ok( status == STATUS_INVALID_PARAMETER || broken( status == STATUS_SUCCESS),
         "failed %lx\n", status );
-    status = pNtQuerySystemInformationEx( SystemSupportedProcessorArchitectures, NULL, 0,
+    status = pNtQuerySystemInformationEx( class, NULL, 0,
                                           machines, sizeof(machines), &len );
     ok( status == STATUS_INVALID_PARAMETER, "failed %lx\n", status );
 
     winetest_push_context( "current" );
-    test_process_architecture( GetCurrentProcess(), is_win64 ? native_machine : current_machine,
+    test_process_architecture( class, GetCurrentProcess(), current_machine,
                                native_machine );
     test_process_machine( GetCurrentProcess(), GetCurrentThread(), current_machine,
                           is_arm64ec ? native_machine : current_machine );
     winetest_pop_context();
 
     winetest_push_context( "zero" );
-    test_process_architecture( 0, 0, native_machine );
+    test_process_architecture( class, 0, 0, native_machine );
     winetest_pop_context();
 
-    if (CreateProcessA( NULL, is_win64 ? cmd_system32 : cmd_sysnative, NULL, NULL,
-                        FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
+    machine = (is_win64 && native_machine == IMAGE_FILE_MACHINE_ARM64) ? current_machine : IMAGE_FILE_MACHINE_AMD64;
+    if (create_process_machine( is_win64 ? cmd_system32 : cmd_sysnative, CREATE_SUSPENDED, machine, &pi ))
     {
         winetest_push_context( "system32" );
-        test_process_architecture( pi.hProcess, native_machine, native_machine );
+        test_process_architecture( class, pi.hProcess, machine, native_machine );
         test_process_machine( pi.hProcess, pi.hThread,
                               is_win64 ? current_machine : native_machine, native_machine );
         TerminateProcess( pi.hProcess, 0 );
@@ -378,7 +392,7 @@ static void test_query_architectures(void)
                         FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi ))
     {
         winetest_push_context( "syswow64" );
-        test_process_architecture( pi.hProcess, IMAGE_FILE_MACHINE_I386, native_machine );
+        test_process_architecture( class, pi.hProcess, IMAGE_FILE_MACHINE_I386, native_machine );
         test_process_machine( pi.hProcess, pi.hThread, IMAGE_FILE_MACHINE_I386, IMAGE_FILE_MACHINE_I386 );
         TerminateProcess( pi.hProcess, 0 );
         CloseHandle( pi.hProcess );
@@ -392,7 +406,7 @@ static void test_query_architectures(void)
         if (create_process_machine( cmd_system32, CREATE_SUSPENDED, machine, &pi ))
         {
             winetest_push_context( "%04x", machine );
-            test_process_architecture( pi.hProcess, native_machine, native_machine );
+            test_process_architecture( class, pi.hProcess, machine, native_machine );
             test_process_machine( pi.hProcess, pi.hThread, machine, native_machine );
             TerminateProcess( pi.hProcess, 0 );
             CloseHandle( pi.hProcess );
@@ -3212,7 +3226,8 @@ static void test_arm64ec(void)
 START_TEST(wow64)
 {
     init();
-    test_query_architectures();
+    test_query_architectures(SystemSupportedProcessorArchitectures);
+    test_query_architectures(SystemSupportedProcessorArchitectures2);
     test_peb_teb();
     test_selectors();
     test_image_mappings();
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
index 9bc040e08dfe..b66be2bb06e9 100644
--- a/dlls/ntdll/unix/loader.c
+++ b/dlls/ntdll/unix/loader.c
@@ -94,7 +94,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(module);
 
-#if defined __i386__ || defined __x86_64__
+#if defined __i386__ || (defined __x86_64__ && !defined __APPLE__)
 #define SO_DLLS_SUPPORTED
 #endif
 
@@ -861,7 +861,7 @@ static NTSTATUS load_so_dll( void *args )
     NTSTATUS status;
     DWORD len;
 
-    if (get_load_order( nt_name ) == LO_DISABLED) return STATUS_DLL_NOT_FOUND;
+    if (get_load_order( nt_name, FALSE, NULL ) == LO_DISABLED) return STATUS_DLL_NOT_FOUND;
     InitializeObjectAttributes( &attr, nt_name, OBJ_CASE_INSENSITIVE, 0, 0 );
     if (!get_nt_and_unix_names( &attr, &true_nt_name, &unix_name, FILE_OPEN, FALSE ))
     {
@@ -1251,30 +1251,30 @@ done:
  * Load the builtin dll if specified by load order configuration.
  * Return STATUS_IMAGE_ALREADY_LOADED if we should keep the native one that we have found.
  */
-NTSTATUS load_builtin( const struct pe_image_info *image_info, UNICODE_STRING *nt_name,
-                       ANSI_STRING *exp_name, USHORT machine, SECTION_IMAGE_INFORMATION *info,
-                       void **module, SIZE_T *size, ULONG_PTR limit_low, ULONG_PTR limit_high,
-                       off_t offset )
+NTSTATUS load_builtin( struct pe_mapping_info *pe_mapping, USHORT machine,
+                       SECTION_IMAGE_INFORMATION *info, void **module, SIZE_T *size,
+                       ULONG_PTR limit_low, ULONG_PTR limit_high, off_t offset )
 {
     NTSTATUS status;
-    USHORT search_machine = image_info->machine;
-    enum loadorder loadorder = get_load_order( nt_name );
+    USHORT sysdir_machine, search_machine = pe_mapping->image.machine;
+    BOOL is_system_dir = is_system_dir_path( &pe_mapping->nt_name, &sysdir_machine );
+    enum loadorder loadorder = get_load_order( &pe_mapping->nt_name, is_system_dir, pe_mapping );
 
     if (loadorder == LO_DISABLED) return STATUS_DLL_NOT_FOUND;
 
-    if (image_info->wine_builtin)
+    if (pe_mapping->image.wine_builtin)
     {
         if (loadorder == LO_NATIVE) return STATUS_DLL_NOT_FOUND;
         loadorder = LO_BUILTIN_NATIVE;  /* load builtin, then fallback to the file we found */
     }
-    else if (image_info->wine_fakedll)
+    else if (pe_mapping->image.wine_fakedll)
     {
-        TRACE( "%s is a fake Wine dll\n", debugstr_us(nt_name) );
+        TRACE( "%s is a fake Wine dll\n", debugstr_us(&pe_mapping->nt_name) );
         if (loadorder == LO_NATIVE) return STATUS_DLL_NOT_FOUND;
         loadorder = LO_BUILTIN;  /* builtin with no fallback since mapping a fake dll is not useful */
     }
 
-    if (is_arm64ec() && image_info->is_hybrid && search_machine == IMAGE_FILE_MACHINE_AMD64)
+    if (is_arm64ec() && pe_mapping->image.is_hybrid && search_machine == IMAGE_FILE_MACHINE_AMD64)
         search_machine = current_machine;
 
     switch (loadorder)
@@ -1283,11 +1283,12 @@ NTSTATUS load_builtin( const struct pe_image_info *image_info, UNICODE_STRING *n
     case LO_NATIVE_BUILTIN:
         return STATUS_IMAGE_ALREADY_LOADED;
     case LO_BUILTIN:
-        return find_builtin_dll( nt_name, exp_name, module, size, info, limit_low, limit_high,
-                                 search_machine, machine, FALSE, offset );
+        return find_builtin_dll( &pe_mapping->nt_name, &pe_mapping->exp_name, module, size, info,
+                                 limit_low, limit_high, search_machine, machine, FALSE, offset );
     default:
-        status = find_builtin_dll( nt_name, exp_name, module, size, info, limit_low, limit_high,
-                                   search_machine, machine, (loadorder == LO_DEFAULT), offset );
+        status = find_builtin_dll( &pe_mapping->nt_name, &pe_mapping->exp_name, module, size, info,
+                                   limit_low, limit_high, search_machine, machine,
+                                   (loadorder == LO_DEFAULT), offset );
         if (status == STATUS_DLL_NOT_FOUND || status == STATUS_NOT_SUPPORTED)
             return STATUS_IMAGE_ALREADY_LOADED;
         return status;
@@ -1391,19 +1392,16 @@ static const WCHAR *get_machine_wow64_dir( WORD machine )
 
 
 /***************************************************************************
- *	is_builtin_path
+ *	is_system_dir_path
  *
  * Check if path is inside a system directory, to support loading builtins
  * when the corresponding file doesn't exist yet.
  */
-BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine )
+BOOL is_system_dir_path( const UNICODE_STRING *path, WORD *machine )
 {
     unsigned int i, len = path->Length / sizeof(WCHAR), dirlen;
     const WCHAR *sysdir, *p = path->Buffer;
 
-    /* only fake builtin existence during prefix bootstrap */
-    if (!is_prefix_bootstrap) return FALSE;
-
     for (i = 0; i < supported_machines_count; i++)
     {
         sysdir = get_machine_wow64_dir( supported_machines[i] );
@@ -1464,16 +1462,17 @@ static NTSTATUS open_main_image( UNICODE_STRING *nt_name, void **module, SECTION
  */
 NTSTATUS load_main_exe( UNICODE_STRING *nt_name, USHORT load_machine, void **module )
 {
-    enum loadorder loadorder = get_load_order( nt_name );
     unsigned int status;
     SIZE_T size;
     USHORT search_machine;
+    BOOL is_system_dir = is_system_dir_path( nt_name, &search_machine );
+    enum loadorder loadorder = get_load_order( nt_name, is_system_dir, NULL );
 
     status = open_main_image( nt_name, module, &main_image_info, loadorder, load_machine );
     if (status != STATUS_DLL_NOT_FOUND) return status;
 
     /* if path is in system dir, we can load the builtin even if the file itself doesn't exist */
-    if (loadorder != LO_NATIVE && is_builtin_path( nt_name, &search_machine ))
+    if (loadorder != LO_NATIVE && is_prefix_bootstrap && is_system_dir)
         status = find_builtin_dll( nt_name, NULL, module, &size, &main_image_info, 0, 0,
                                    search_machine, load_machine, FALSE, 0 );
     return status;
diff --git a/dlls/ntdll/unix/loadorder.c b/dlls/ntdll/unix/loadorder.c
index 11c3ab9bb476..76059137f76b 100644
--- a/dlls/ntdll/unix/loadorder.c
+++ b/dlls/ntdll/unix/loadorder.c
@@ -31,6 +31,7 @@
 #include "ntstatus.h"
 #include "windef.h"
 #include "winternl.h"
+#include "verrsrc.h"
 #include "unix_private.h"
 
 #include "wine/debug.h"
@@ -52,6 +53,22 @@ static struct
     struct module_loadorder *order;
 } env_list;
 
+struct version_info
+{
+    WORD  len;
+    WORD  val_len;
+    WORD  type;
+    WCHAR key[1];
+};
+
+struct version_entry
+{
+    const struct version_info *info;
+    const void                *value;
+    const void                *next;
+    const void                *child;
+};
+
 static const WCHAR separatorsW[] = {',',' ','\t',0};
 
 static HANDLE std_key;
@@ -59,6 +76,51 @@ static HANDLE app_key;
 static BOOL init_done;
 static BOOL main_exe_loaded;
 
+/***************************************************************************
+ *	get_version_entry
+ *
+ * Validate a version resource entry and fill a descriptor to it.
+ */
+static BOOL get_version_entry( struct version_entry *entry, const void *ptr, const void *end )
+{
+    unsigned int len;
+    const struct version_info *info = ptr;
+
+    if ((const char *)(info + 1) > (const char *)end) return FALSE;
+    if ((const char *)info + info->len > (const char *)end) return FALSE;
+
+    for (len = 0; info->key[len]; len++)
+        if (offsetof(struct version_info, key[len + 1]) > info->len) return FALSE;
+
+    len = (offsetof(struct version_info, key[len + 1]) + 3) & ~3;
+    if (len + info->val_len * (info->type ? 2 : 1) > info->len) return FALSE;
+
+    entry->info  = info;
+    entry->value = (const char *)info + len;
+    entry->child = (const char *)info + len + ((info->val_len * (info->type ? 2 : 1) + 3) & ~3);
+    entry->next  = (const char *)info + ((info->len + 3) & ~3);
+    return TRUE;
+}
+
+/***************************************************************************
+ *	version_find_key
+ *
+ * Find a specific key in a version resource block.
+ */
+static BOOL version_find_key( const struct version_entry *parent, const WCHAR *name,
+                              struct version_entry *child )
+{
+    struct version_entry ret;
+
+    if (!get_version_entry( &ret, parent->child, parent->next )) return FALSE;
+    for (;;)
+    {
+        if (!wcsicmp( ret.info->key, name )) break;
+        if (!get_version_entry( &ret, ret.next, parent->next )) return FALSE;
+    }
+    *child = ret;
+    return TRUE;
+}
 
 /***************************************************************************
  *	cmp_sort_func	(internal, static)
@@ -356,6 +418,47 @@ static enum loadorder get_load_order_value( HANDLE std_key, HANDLE app_key, WCHA
 }
 
 
+/***********************************************************************
+ *           prefer_native_heuristics
+ *
+ * Check if we should prefer loading native using heuristics based on the version resource.
+ */
+static BOOL prefer_native_heuristics( const UNICODE_STRING *nt_name,
+                                      const struct pe_mapping_info *pe_mapping )
+{
+    static const WCHAR fileinfoW[] = {'S','t','r','i','n','g','F','i','l','e','I','n','f','o',0};
+    static const WCHAR companyW[] = {'C','o','m','p','a','n','y','N','a','m','e',0};
+    static const WCHAR microsoftW[] = {'M','i','c','r','o','s','o','f','t'};
+
+    struct version_entry entry;
+    const VS_FIXEDFILEINFO *fileinfo;
+    const WCHAR *name;
+    ULONG len;
+
+    if (!pe_mapping) return FALSE;
+    if (!pe_mapping->version_len) return FALSE;
+    if (!get_version_entry( &entry, pe_mapping->version_res,
+                            (char *)pe_mapping->version_res + pe_mapping->version_len )) return FALSE;
+    fileinfo = entry.value;
+    if (entry.info->val_len < sizeof(*fileinfo)) return FALSE;
+    if (fileinfo->dwSignature != VS_FFI_SIGNATURE) return FALSE;
+
+    if (!version_find_key( &entry, fileinfoW, &entry )) return FALSE;
+    /* get the first child (usually "040904B0") */
+    if (!get_version_entry( &entry, entry.child, entry.next )) return FALSE;
+    if (!version_find_key( &entry, companyW, &entry )) return FALSE;
+    if (!entry.info->type || !entry.info->val_len) return FALSE;
+
+    name = entry.value;
+    len = entry.info->val_len;
+    if (!name[len - 1]) len--;
+    if (len >= ARRAY_SIZE(microsoftW) && !wcsnicmp( name, microsoftW, ARRAY_SIZE(microsoftW) ))
+        return FALSE;
+    TRACE( "preferring native from %s for %s\n", debugstr_wn( name, len ), debugstr_us( nt_name ));
+    return TRUE;
+}
+
+
 /***************************************************************************
  *	set_load_order_app_name
  */
@@ -375,12 +478,13 @@ void set_load_order_app_name( const WCHAR *app_name )
  * Return the loadorder of a module.
  * The system directory and '.dll' extension is stripped from the path.
  */
-enum loadorder get_load_order( const UNICODE_STRING *nt_name )
+enum loadorder get_load_order( const UNICODE_STRING *nt_name, BOOL is_system_dir,
+                               const struct pe_mapping_info *pe_mapping )
 {
     static const WCHAR prefixW[] = {'\\','?','?','\\'};
     enum loadorder ret = LO_INVALID;
     const WCHAR *path = nt_name->Buffer;
-    unsigned int i, len = nt_name->Length / sizeof(WCHAR);
+    unsigned int len = nt_name->Length / sizeof(WCHAR);
     WCHAR *module, *basename;
 
     if (!init_done) init_load_order();
@@ -391,20 +495,6 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name )
         len -= 4;
     }
 
-    /* Strip path information if the module resides in the system directory
-     */
-    if (len > wcslen(system_dir) - 4 && !wcsnicmp( system_dir + 4, path, wcslen(system_dir) - 4 ))
-    {
-        unsigned int pos = wcslen( system_dir ) - 4;
-        while (pos < len && (path[pos] == '\\' || path[pos] == '/')) pos++;
-        for (i = pos; i < len; i++) if (path[i] == '\\' || path[i] == '/') break;
-        if (i == len)
-        {
-            path += pos;
-            len -= pos;
-        }
-    }
-
     if (!(module = malloc( (len + 2) * sizeof(WCHAR) ))) return ret;
     memcpy( module + 1, path, len * sizeof(WCHAR) );  /* reserve module[0] for the wildcard char */
     module[len + 1] = 0;
@@ -412,7 +502,7 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name )
     basename = get_basename( module + 1 );
 
     /* first explicit module name */
-    if ((ret = get_load_order_value( std_key, app_key, module+1 )) != LO_INVALID)
+    if ((ret = get_load_order_value( std_key, app_key, is_system_dir ? basename : module+1 )) != LO_INVALID)
         goto done;
 
     /* then module basename preceded by '*' */
@@ -420,16 +510,24 @@ enum loadorder get_load_order( const UNICODE_STRING *nt_name )
     if ((ret = get_load_order_value( std_key, app_key, basename-1 )) != LO_INVALID)
         goto done;
 
-    /* then module basename without '*' (only if explicit path) */
-    if (basename != module+1 && ((ret = get_load_order_value( std_key, app_key, basename )) != LO_INVALID))
-        goto done;
-
-    /* if loading the main exe with an explicit path, try native first */
-    if (!main_exe_loaded && basename != module+1)
+    /* now some heuristics for explicit paths */
+    if (!is_system_dir)
     {
-        ret = LO_NATIVE_BUILTIN;
-        TRACE( "got main exe default %s for %s\n", debugstr_loadorder(ret), debugstr_us(nt_name) );
-        goto done;
+        /* module basename without '*' */
+        if (((ret = get_load_order_value( std_key, app_key, basename )) != LO_INVALID))
+            goto done;
+
+        if (!main_exe_loaded)  /* if loading the main exe, try native first */
+        {
+            ret = LO_NATIVE_BUILTIN;
+            TRACE( "got main exe default %s for %s\n", debugstr_loadorder(ret), debugstr_us(nt_name) );
+            goto done;
+        }
+        if (prefer_native_heuristics( nt_name, pe_mapping ))
+        {
+            ret = LO_NATIVE_BUILTIN;
+            goto done;
+        }
     }
 
     /* and last the hard-coded default */
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c
index 9b7b5a04ef23..67e2f3713d7e 100644
--- a/dlls/ntdll/unix/process.c
+++ b/dlls/ntdll/unix/process.c
@@ -275,7 +275,7 @@ static unsigned int get_pe_file_info( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *n
     }
     if (status)
     {
-        if (is_builtin_path( attr->ObjectName, &info->machine ))
+        if (is_prefix_bootstrap && is_system_dir_path( attr->ObjectName, &info->machine ))
         {
             TRACE( "assuming %04x builtin for %s\n", info->machine, debugstr_us(attr->ObjectName));
             return STATUS_SUCCESS;
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index c04328c85695..4295a56d77c0 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -545,7 +545,7 @@ static void invoke_system_apc( const union apc_call *call, union apc_result *res
         if ((ULONG_PTR)addr == call->virtual_flush.addr && size == call->virtual_flush.size)
         {
             result->virtual_flush.status = NtFlushVirtualMemory( NtCurrentProcess(),
-                                                                 (const void **)&addr, &size, 0 );
+                                                                 (const void **)&addr, &size, NULL );
             result->virtual_flush.addr = wine_server_client_ptr( addr );
             result->virtual_flush.size = size;
         }
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 7e644a6dd9f5..c321b98c4eda 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -63,10 +63,6 @@
 #ifdef HAVE_SYS_UCONTEXT_H
 # include <sys/ucontext.h>
 #endif
-#ifdef HAVE_LIBUNWIND
-# define UNW_LOCAL_ONLY
-# include <libunwind.h>
-#endif
 #ifdef __APPLE__
 # include <mach/mach.h>
 /* _thread_set_tsd_base is private API for setting GSBASE, added in macOS 10.12.
@@ -716,137 +712,6 @@ static NTSTATUS dwarf_virtual_unwind( ULONG64 ip, ULONG64 *frame,CONTEXT *contex
 }
 
 
-#ifdef HAVE_LIBUNWIND
-/***********************************************************************
- *           libunwind_virtual_unwind
- *
- * Equivalent of RtlVirtualUnwind for builtin modules.
- */
-static NTSTATUS libunwind_virtual_unwind( ULONG64 ip, ULONG64 *frame, CONTEXT *context,
-                                          PEXCEPTION_ROUTINE *handler, void **handler_data )
-{
-    unw_context_t unw_context;
-    unw_cursor_t cursor;
-    unw_proc_info_t info;
-    int rc;
-
-#ifdef __APPLE__
-    rc = unw_getcontext( &unw_context );
-    if (rc == UNW_ESUCCESS)
-        rc = unw_init_local( &cursor, &unw_context );
-    if (rc == UNW_ESUCCESS)
-    {
-        unw_set_reg( &cursor, UNW_REG_IP,     context->Rip );
-        unw_set_reg( &cursor, UNW_REG_SP,     context->Rsp );
-        unw_set_reg( &cursor, UNW_X86_64_RAX, context->Rax );
-        unw_set_reg( &cursor, UNW_X86_64_RDX, context->Rdx );
-        unw_set_reg( &cursor, UNW_X86_64_RCX, context->Rcx );
-        unw_set_reg( &cursor, UNW_X86_64_RBX, context->Rbx );
-        unw_set_reg( &cursor, UNW_X86_64_RSI, context->Rsi );
-        unw_set_reg( &cursor, UNW_X86_64_RDI, context->Rdi );
-        unw_set_reg( &cursor, UNW_X86_64_RBP, context->Rbp );
-        unw_set_reg( &cursor, UNW_X86_64_R8,  context->R8 );
-        unw_set_reg( &cursor, UNW_X86_64_R9,  context->R9 );
-        unw_set_reg( &cursor, UNW_X86_64_R10, context->R10 );
-        unw_set_reg( &cursor, UNW_X86_64_R11, context->R11 );
-        unw_set_reg( &cursor, UNW_X86_64_R12, context->R12 );
-        unw_set_reg( &cursor, UNW_X86_64_R13, context->R13 );
-        unw_set_reg( &cursor, UNW_X86_64_R14, context->R14 );
-        unw_set_reg( &cursor, UNW_X86_64_R15, context->R15 );
-    }
-#else
-    RAX_sig(&unw_context) = context->Rax;
-    RCX_sig(&unw_context) = context->Rcx;
-    RDX_sig(&unw_context) = context->Rdx;
-    RBX_sig(&unw_context) = context->Rbx;
-    RSP_sig(&unw_context) = context->Rsp;
-    RBP_sig(&unw_context) = context->Rbp;
-    RSI_sig(&unw_context) = context->Rsi;
-    RDI_sig(&unw_context) = context->Rdi;
-    R8_sig(&unw_context)  = context->R8;
-    R9_sig(&unw_context)  = context->R9;
-    R10_sig(&unw_context) = context->R10;
-    R11_sig(&unw_context) = context->R11;
-    R12_sig(&unw_context) = context->R12;
-    R13_sig(&unw_context) = context->R13;
-    R14_sig(&unw_context) = context->R14;
-    R15_sig(&unw_context) = context->R15;
-    RIP_sig(&unw_context) = context->Rip;
-    CS_sig(&unw_context)  = context->SegCs;
-    FS_sig(&unw_context)  = context->SegFs;
-    GS_sig(&unw_context)  = context->SegGs;
-    EFL_sig(&unw_context) = context->EFlags;
-    rc = unw_init_local( &cursor, &unw_context );
-#endif
-    if (rc != UNW_ESUCCESS)
-    {
-        WARN( "setup failed: %d\n", rc );
-        return STATUS_INVALID_DISPOSITION;
-    }
-
-    *handler = NULL;
-    *frame = context->Rsp;
-
-    rc = unw_get_proc_info(&cursor, &info);
-    if (UNW_ENOINFO < 0) rc = -rc;  /* LLVM libunwind has negative error codes */
-    if (rc != UNW_ESUCCESS && rc != -UNW_ENOINFO)
-    {
-        WARN( "failed to get info: %d\n", rc );
-        return STATUS_INVALID_DISPOSITION;
-    }
-    if (rc == -UNW_ENOINFO || ip < info.start_ip || ip > info.end_ip || info.end_ip == info.start_ip + 1)
-        return STATUS_UNSUCCESSFUL;
-
-    TRACE( "ip %#lx function %#lx-%#lx personality %#lx lsda %#lx fde %#lx\n",
-           ip, (unsigned long)info.start_ip, (unsigned long)info.end_ip, (unsigned long)info.handler,
-           (unsigned long)info.lsda, (unsigned long)info.unwind_info );
-
-    if (!(rc = unw_step( &cursor )))
-    {
-        WARN( "last frame\n" );
-        return STATUS_UNSUCCESSFUL;
-    }
-    if (rc < 0)
-    {
-        WARN( "failed to unwind: %d\n", rc );
-        return STATUS_INVALID_DISPOSITION;
-    }
-
-    unw_get_reg( &cursor, UNW_REG_IP,     (unw_word_t *)&context->Rip );
-    unw_get_reg( &cursor, UNW_REG_SP,     (unw_word_t *)&context->Rsp );
-    unw_get_reg( &cursor, UNW_X86_64_RAX, (unw_word_t *)&context->Rax );
-    unw_get_reg( &cursor, UNW_X86_64_RDX, (unw_word_t *)&context->Rdx );
-    unw_get_reg( &cursor, UNW_X86_64_RCX, (unw_word_t *)&context->Rcx );
-    unw_get_reg( &cursor, UNW_X86_64_RBX, (unw_word_t *)&context->Rbx );
-    unw_get_reg( &cursor, UNW_X86_64_RSI, (unw_word_t *)&context->Rsi );
-    unw_get_reg( &cursor, UNW_X86_64_RDI, (unw_word_t *)&context->Rdi );
-    unw_get_reg( &cursor, UNW_X86_64_RBP, (unw_word_t *)&context->Rbp );
-    unw_get_reg( &cursor, UNW_X86_64_R8,  (unw_word_t *)&context->R8 );
-    unw_get_reg( &cursor, UNW_X86_64_R9,  (unw_word_t *)&context->R9 );
-    unw_get_reg( &cursor, UNW_X86_64_R10, (unw_word_t *)&context->R10 );
-    unw_get_reg( &cursor, UNW_X86_64_R11, (unw_word_t *)&context->R11 );
-    unw_get_reg( &cursor, UNW_X86_64_R12, (unw_word_t *)&context->R12 );
-    unw_get_reg( &cursor, UNW_X86_64_R13, (unw_word_t *)&context->R13 );
-    unw_get_reg( &cursor, UNW_X86_64_R14, (unw_word_t *)&context->R14 );
-    unw_get_reg( &cursor, UNW_X86_64_R15, (unw_word_t *)&context->R15 );
-    *handler = (void*)info.handler;
-    *handler_data = (void*)info.lsda;
-
-    TRACE( "next function rip=%016lx\n", context->Rip );
-    TRACE( "  rax=%016lx rbx=%016lx rcx=%016lx rdx=%016lx\n",
-           context->Rax, context->Rbx, context->Rcx, context->Rdx );
-    TRACE( "  rsi=%016lx rdi=%016lx rbp=%016lx rsp=%016lx\n",
-           context->Rsi, context->Rdi, context->Rbp, context->Rsp );
-    TRACE( "   r8=%016lx  r9=%016lx r10=%016lx r11=%016lx\n",
-           context->R8, context->R9, context->R10, context->R11 );
-    TRACE( "  r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n",
-           context->R12, context->R13, context->R14, context->R15 );
-
-    return STATUS_SUCCESS;
-}
-#endif
-
-
 /***********************************************************************
  *           unwind_builtin_dll
  */
@@ -861,10 +726,6 @@ NTSTATUS unwind_builtin_dll( void *args )
     if (fde)
         return dwarf_virtual_unwind( context->Rip, &dispatch->EstablisherFrame, context, fde,
                                      &bases, &dispatch->LanguageHandler, &dispatch->HandlerData );
-#ifdef HAVE_LIBUNWIND
-    return libunwind_virtual_unwind( context->Rip, &dispatch->EstablisherFrame, context,
-                                     &dispatch->LanguageHandler, &dispatch->HandlerData );
-#endif
     return STATUS_UNSUCCESSFUL;
 }
 
@@ -2708,7 +2569,7 @@ static void sigsys_handler( int signal, siginfo_t *siginfo, void *sigcontext )
     ucontext_t *ucontext = init_handler( sigcontext );
     struct syscall_frame *frame = get_syscall_frame();
 
-    TRACE_(seh)("SIGSYS, rax %#llx, rip %#llx.\n", RAX_sig(ucontext), RIP_sig(ucontext));
+    TRACE_(seh)("SIGSYS, rax %#lx, rip %#lx.\n", (long)RAX_sig(ucontext), (long)RIP_sig(ucontext));
 
 #ifdef PR_SET_SYSCALL_USER_DISPATCH
     if (!syscall_dispatch_enabled)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index aa66ec2654cb..148624ff405d 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -4091,11 +4091,14 @@ NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
     }
 
     case SystemSupportedProcessorArchitectures:
+    case SystemSupportedProcessorArchitectures2:
     {
         SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION *machines = info;
         HANDLE process;
         ULONG i;
         USHORT machine = 0;
+        USHORT machines_to_return[8];
+        unsigned int machines_to_return_count = 0;
 
         if (!query || query_len < sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
         process = *(HANDLE *)query;
@@ -4110,7 +4113,18 @@ NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
             if (ret) return ret;
         }
 
-        len = (supported_machines_count + 1) * sizeof(*machines);
+        for (i = 0; i < supported_machines_count; i++)
+        {
+#ifdef __aarch64__
+            if (class == SystemSupportedProcessorArchitectures &&
+                supported_machines[i] == IMAGE_FILE_MACHINE_AMD64)
+                continue;
+#endif
+            machines_to_return[machines_to_return_count] = supported_machines[i];
+            machines_to_return_count++;
+        }
+
+        len = (machines_to_return_count + 1) * sizeof(*machines);
         if (size < len)
         {
             ret = STATUS_BUFFER_TOO_SMALL;
@@ -4119,20 +4133,23 @@ NTSTATUS WINAPI NtQuerySystemInformationEx( SYSTEM_INFORMATION_CLASS class,
         memset( machines, 0, len );
 
         /* native machine */
-        machines[0].Machine = supported_machines[0];
+        machines[0].Machine = machines_to_return[0];
         machines[0].UserMode = 1;
         machines[0].KernelMode = 1;
         machines[0].Native = 1;
-        machines[0].Process = (supported_machines[0] == machine || is_machine_64bit( machine ));
+        machines[0].Process = (machines_to_return[0] == machine ||
+                               (class == SystemSupportedProcessorArchitectures &&
+                                machine == IMAGE_FILE_MACHINE_AMD64));
         machines[0].WoW64Container = 0;
         machines[0].ReservedZero0 = 0;
-        /* wow64 machines */
-        for (i = 1; i < supported_machines_count; i++)
+        /* other machines */
+        for (i = 1; i < machines_to_return_count; i++)
         {
-            machines[i].Machine = supported_machines[i];
+            machines[i].Machine = machines_to_return[i];
             machines[i].UserMode = 1;
-            machines[i].Process = supported_machines[i] == machine;
-            machines[i].WoW64Container = 1;
+            machines[i].Process = machines_to_return[i] == machine;
+            if (!is_machine_64bit( machines_to_return[i] ))
+                machines[i].WoW64Container = 1;
         }
         ret = STATUS_SUCCESS;
         break;
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index a9e8f5228920..0a60da3a2025 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -149,6 +149,17 @@ struct async_fileio
     HANDLE               handle;
 };
 
+struct pe_mapping_info
+{
+    HANDLE               shared_file;
+    UNICODE_STRING       nt_name;
+    ANSI_STRING          exp_name;
+    void                *version_res;
+    ULONG                version_len;
+    struct pe_image_info image;
+    char                 data[];
+};
+
 static const SIZE_T page_size = 0x1000;
 static const SIZE_T teb_size = 0x3800;  /* TEB64 + TEB32 + debug info */
 static const SIZE_T signal_stack_mask = 0xffff;
@@ -212,11 +223,11 @@ extern void *create_startup_info( const UNICODE_STRING *nt_image, ULONG process_
                                   const struct pe_image_info *pe_info, DWORD *info_size );
 extern char *get_alternate_wineloader( WORD machine );
 extern NTSTATUS exec_wineloader( char **argv, int socketfd, const struct pe_image_info *pe_info );
-extern NTSTATUS load_builtin( const struct pe_image_info *image_info, UNICODE_STRING *nt_name,
-                              ANSI_STRING *exp_name, USHORT machine, SECTION_IMAGE_INFORMATION *info,
-                              void **module, SIZE_T *size, ULONG_PTR limit_low, ULONG_PTR limit_high, off_t offset );
+extern NTSTATUS load_builtin( struct pe_mapping_info *pe_mapping, USHORT machine,
+                              SECTION_IMAGE_INFORMATION *info, void **module, SIZE_T *size,
+                              ULONG_PTR limit_low, ULONG_PTR limit_high, off_t offset );
 extern NTSTATUS load_unixlib_by_name( const UNICODE_STRING *nt_name, void **handle_ret );
-extern BOOL is_builtin_path( const UNICODE_STRING *path, WORD *machine );
+extern BOOL is_system_dir_path( const UNICODE_STRING *path, WORD *machine );
 extern NTSTATUS load_main_exe( UNICODE_STRING *nt_name, USHORT load_machine, void **module );
 extern NTSTATUS load_start_exe( UNICODE_STRING *nt_name, void **module );
 extern ULONG_PTR redirect_arm64ec_rva( void *module, ULONG_PTR rva, const IMAGE_ARM64EC_METADATA *metadata );
@@ -558,7 +569,8 @@ enum loadorder
 };
 
 extern void set_load_order_app_name( const WCHAR *app_name );
-extern enum loadorder get_load_order( const UNICODE_STRING *nt_name );
+extern enum loadorder get_load_order( const UNICODE_STRING *nt_name, BOOL is_system_dir,
+                                      const struct pe_mapping_info *pe_mapping );
 
 static inline WCHAR ntdll_towupper( WCHAR ch )
 {
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 781598fced1d..9297a5f37981 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -73,7 +73,7 @@
 #undef host_page_size
 #endif
 
-#if defined(HAVE_LINUX_USERFAULTFD_H) && defined(HAVE_LINUX_FS_H)
+#if defined(HAVE_LINUX_USERFAULTFD_H) && defined(HAVE_LINUX_FS_H) && !defined(__ANDROID__)
 # include <linux/userfaultfd.h>
 # include <linux/fs.h>
 #if defined(UFFD_FEATURE_WP_ASYNC) && defined(PM_SCAN_WP_MATCHING)
@@ -3267,53 +3267,61 @@ done:
 }
 
 
+/***********************************************************************
+ *             free_pe_mapping_info
+ */
+static void free_pe_mapping_info( struct pe_mapping_info *info )
+{
+    if (info->shared_file) NtClose( info->shared_file );
+    free( info );
+}
+
+
 /***********************************************************************
  *             get_mapping_info
  */
 static unsigned int get_mapping_info( HANDLE handle, ACCESS_MASK access, unsigned int *sec_flags,
-                                      mem_size_t *full_size, HANDLE *shared_file,
-                                      struct pe_image_info **info, UNICODE_STRING *nt_name,
-                                      ANSI_STRING *exp_name )
+                                      mem_size_t *full_size, struct pe_mapping_info **info_ret )
 {
-    struct pe_image_info *image_info;
-    SIZE_T namelen, total, size = 1024;
+    struct pe_mapping_info *info;
+    SIZE_T total, size = 2048;
     unsigned int status;
 
+    *info_ret = NULL;
     for (;;)
     {
-        if (!(image_info = malloc( size ))) return STATUS_NO_MEMORY;
+        if (!(info = malloc( offsetof(struct pe_mapping_info, image) + size ))) return STATUS_NO_MEMORY;
 
         SERVER_START_REQ( get_mapping_info )
         {
             req->handle = wine_server_obj_handle( handle );
             req->access = access;
-            wine_server_set_reply( req, image_info, size );
+            wine_server_set_reply( req, &info->image, size );
             status = wine_server_call( req );
             *sec_flags   = reply->flags;
             *full_size   = reply->size;
-            namelen      = reply->name_len;
             total        = reply->total;
-            *shared_file = wine_server_ptr_handle( reply->shared_file );
+            info->shared_file = wine_server_ptr_handle( reply->shared_file );
+            info->version_len = reply->ver_len;
+            info->nt_name.Length = info->nt_name.MaximumLength = reply->name_len;
         }
         SERVER_END_REQ;
         if (!status && total <= size) break;
-        free( image_info );
+        free_pe_mapping_info( info );
         if (status) return status;
-        if (*shared_file) NtClose( *shared_file );
         size = total;
     }
 
     if (total)
     {
-        assert( total >= sizeof(*image_info) );
-        total -= sizeof(*image_info);
-        nt_name->Buffer = (WCHAR *)(image_info + 1);
-        nt_name->Length = nt_name->MaximumLength = namelen;
-        exp_name->Buffer = (char *)nt_name->Buffer + namelen;
-        exp_name->Length = exp_name->MaximumLength = total - namelen;
-        *info = image_info;
+        info->version_res     = info->data;
+        info->nt_name.Buffer  = (WCHAR *)(info->data + info->version_len);
+        info->exp_name.Buffer = info->data + info->version_len + info->nt_name.Length;
+        info->exp_name.Length = total - sizeof(info->image) - info->version_len - info->nt_name.Length;
+        info->exp_name.MaximumLength = info->exp_name.Length;
+        *info_ret = info;
     }
-    else free( image_info );
+    else free_pe_mapping_info( info );
 
     return STATUS_SUCCESS;
 }
@@ -3384,14 +3392,14 @@ static NTSTATUS map_image_view( struct file_view **view_ret, struct pe_image_inf
  *
  * Map a PE image section into memory.
  */
-static NTSTATUS virtual_map_image( HANDLE mapping, void **addr_ptr, SIZE_T *size_ptr, HANDLE shared_file,
+static NTSTATUS virtual_map_image( HANDLE mapping, void **addr_ptr, SIZE_T *size_ptr,
                                    ULONG_PTR limit_low, ULONG_PTR limit_high, ULONG alloc_type,
-                                   USHORT machine, struct pe_image_info *image_info,
-                                   UNICODE_STRING *nt_name, BOOL is_builtin, off_t offset)
+                                   struct pe_mapping_info *pe_mapping, USHORT machine,
+                                   BOOL is_builtin, off_t offset)
 {
     int unix_fd = -1, needs_close;
     int shared_fd = -1, shared_needs_close = 0;
-    SIZE_T size = image_info->map_size;
+    SIZE_T size = pe_mapping->image.map_size;
     struct file_view *view;
     unsigned int status;
     sigset_t sigset;
@@ -3402,31 +3410,33 @@ static NTSTATUS virtual_map_image( HANDLE mapping, void **addr_ptr, SIZE_T *size
     if ((status = server_get_unix_fd( mapping, 0, &unix_fd, &needs_close, NULL, NULL )))
         return status;
 
-    if (shared_file && ((status = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
-                                                      &shared_fd, &shared_needs_close, NULL, NULL ))))
+    if (pe_mapping->shared_file &&
+        ((status = server_get_unix_fd( pe_mapping->shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
+                                       &shared_fd, &shared_needs_close, NULL, NULL ))))
     {
         if (needs_close) close( unix_fd );
         return status;
     }
 
-    if (!image_info->map_addr &&
-        (image_info->image_charact & IMAGE_FILE_DLL) &&
-        (image_info->image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated))
+    if (!pe_mapping->image.map_addr &&
+        (pe_mapping->image.image_charact & IMAGE_FILE_DLL) &&
+        (pe_mapping->image.image_flags & IMAGE_FLAGS_ImageDynamicallyRelocated))
     {
         SERVER_START_REQ( get_image_map_address )
         {
             req->handle = wine_server_obj_handle( mapping );
-            if (!wine_server_call( req )) image_info->map_addr = reply->addr;
+            if (!wine_server_call( req )) pe_mapping->image.map_addr = reply->addr;
         }
         SERVER_END_REQ;
     }
 
     server_enter_uninterrupted_section( &virtual_mutex, &sigset );
 
-    status = map_image_view( &view, image_info, size, limit_low, limit_high, alloc_type );
+    status = map_image_view( &view, &pe_mapping->image, size, limit_low, limit_high, alloc_type );
     if (status) goto done;
 
-    status = map_image_into_view( view, nt_name, unix_fd, image_info, machine, shared_fd, needs_close );
+    status = map_image_into_view( view, &pe_mapping->nt_name, unix_fd, &pe_mapping->image,
+                                  machine, shared_fd, needs_close );
     if (status == STATUS_SUCCESS)
     {
         if (offset)
@@ -3435,14 +3445,14 @@ static NTSTATUS virtual_map_image( HANDLE mapping, void **addr_ptr, SIZE_T *size
             size -= offset;
         }
 
-        image_info->base = wine_server_client_ptr( view->base );
+        pe_mapping->image.base = wine_server_client_ptr( view->base );
         SERVER_START_REQ( map_image_view )
         {
             req->mapping = wine_server_obj_handle( mapping );
-            req->base    = image_info->base;
+            req->base    = pe_mapping->image.base;
             req->size    = size;
-            req->entry   = image_info->entry_point;
-            req->machine = image_info->machine;
+            req->entry   = pe_mapping->image.entry_point;
+            req->machine = pe_mapping->image.machine;
             req->offset  = offset;
             status = wine_server_call( req );
         }
@@ -3479,14 +3489,11 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P
     mem_size_t full_size;
     ACCESS_MASK access;
     SIZE_T size;
-    struct pe_image_info *image_info = NULL;
-    UNICODE_STRING nt_name;
-    ANSI_STRING exp_name;
+    struct pe_mapping_info *pe_mapping;
     void *base;
     int unix_handle = -1, needs_close;
     unsigned int vprot, sec_flags;
     struct file_view *view;
-    HANDLE shared_file;
     LARGE_INTEGER offset;
     sigset_t sigset;
 
@@ -3512,13 +3519,12 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P
         return STATUS_INVALID_PAGE_PROTECTION;
     }
 
-    res = get_mapping_info( handle, access, &sec_flags, &full_size, &shared_file,
-                            &image_info, &nt_name, &exp_name );
+    res = get_mapping_info( handle, access, &sec_flags, &full_size, &pe_mapping );
     if (res) return res;
 
     offset.QuadPart = offset_ptr ? offset_ptr->QuadPart : 0;
 
-    if (image_info)
+    if (pe_mapping)
     {
         SECTION_IMAGE_INFORMATION info;
         ULONG64 prev = 0;
@@ -3529,13 +3535,12 @@ static unsigned int virtual_map_section( HANDLE handle, PVOID *addr_ptr, ULONG_P
             NtCurrentTeb64()->Tib.ArbitraryUserPointer = PtrToUlong(NtCurrentTeb()->Tib.ArbitraryUserPointer);
         }
         /* check if we can replace that mapping with the builtin */
-        res = load_builtin( image_info, &nt_name, &exp_name, machine, &info,
-                            addr_ptr, size_ptr, limit_low, limit_high, offset.QuadPart );
+        res = load_builtin( pe_mapping, machine, &info, addr_ptr, size_ptr,
+                            limit_low, limit_high, offset.QuadPart );
         if (res == STATUS_IMAGE_ALREADY_LOADED)
-            res = virtual_map_image( handle, addr_ptr, size_ptr, shared_file, limit_low, limit_high,
-                                     alloc_type, machine, image_info, &nt_name, FALSE, offset.QuadPart );
-        if (shared_file) NtClose( shared_file );
-        free( image_info );
+            res = virtual_map_image( handle, addr_ptr, size_ptr, limit_low, limit_high,
+                                     alloc_type, pe_mapping, machine, FALSE, offset.QuadPart );
+        free_pe_mapping_info( pe_mapping );
         if (NtCurrentTeb64()) NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev;
         return res;
     }
@@ -3781,41 +3786,38 @@ NTSTATUS virtual_map_builtin_module( HANDLE mapping, void **module, SIZE_T *size
 {
     mem_size_t full_size;
     unsigned int sec_flags;
-    HANDLE shared_file;
-    struct pe_image_info *image_info = NULL;
+    struct pe_mapping_info *pe_mapping;
     NTSTATUS status;
-    UNICODE_STRING nt_name;
-    ANSI_STRING exp_name;
 
-    if ((status = get_mapping_info( mapping, SECTION_MAP_READ, &sec_flags, &full_size, &shared_file,
-                                    &image_info, &nt_name, &exp_name )))
+    if ((status = get_mapping_info( mapping, SECTION_MAP_READ, &sec_flags, &full_size, &pe_mapping )))
         return status;
 
-    if (!image_info) return STATUS_INVALID_PARAMETER;
+    if (!pe_mapping) return STATUS_INVALID_PARAMETER;
 
     *module = NULL;
     *size = 0;
 
-    if (!image_info->wine_builtin) /* ignore non-builtins */
+    if (!pe_mapping->image.wine_builtin) /* ignore non-builtins */
     {
-        if (!image_info->wine_fakedll)
-            WARN_(module)( "%s found in WINEDLLPATH but not a builtin, ignoring\n", debugstr_us(&nt_name) );
+        if (!pe_mapping->image.wine_fakedll)
+            WARN_(module)( "%s found in WINEDLLPATH but not a builtin, ignoring\n",
+                           debugstr_us(&pe_mapping->nt_name) );
         status = STATUS_DLL_NOT_FOUND;
     }
-    else if (prefer_native && (image_info->dll_charact & IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE))
+    else if (prefer_native && (pe_mapping->image.dll_charact & IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE))
     {
-        TRACE_(module)( "%s has prefer-native flag, ignoring builtin\n", debugstr_us(&nt_name) );
+        TRACE_(module)( "%s has prefer-native flag, ignoring builtin\n",
+                        debugstr_us(&pe_mapping->nt_name) );
         status = STATUS_IMAGE_ALREADY_LOADED;
     }
     else
     {
-        status = virtual_map_image( mapping, module, size, shared_file, limit_low, limit_high, 0,
-                                    machine, image_info, &nt_name, TRUE, offset );
-        virtual_fill_image_information( image_info, info );
+        status = virtual_map_image( mapping, module, size, limit_low, limit_high, 0,
+                                    pe_mapping, machine, TRUE, offset );
+        virtual_fill_image_information( &pe_mapping->image, info );
     }
 
-    if (shared_file) NtClose( shared_file );
-    free( image_info );
+    free_pe_mapping_info( pe_mapping );
     return status;
 }
 
@@ -3829,31 +3831,25 @@ NTSTATUS virtual_map_module( HANDLE mapping, void **module, SIZE_T *size, SECTIO
     unsigned int status;
     mem_size_t full_size;
     unsigned int sec_flags;
-    HANDLE shared_file;
-    struct pe_image_info *image_info = NULL;
-    UNICODE_STRING nt_name;
-    ANSI_STRING exp_name;
+    struct pe_mapping_info *pe_mapping;
 
-    if ((status = get_mapping_info( mapping, SECTION_MAP_READ, &sec_flags, &full_size, &shared_file,
-                                    &image_info, &nt_name, &exp_name )))
+    if ((status = get_mapping_info( mapping, SECTION_MAP_READ, &sec_flags, &full_size, &pe_mapping )))
         return status;
 
-    if (!image_info) return STATUS_INVALID_PARAMETER;
+    if (!pe_mapping) return STATUS_INVALID_PARAMETER;
 
     *module = NULL;
     *size = 0;
 
     /* check if we can replace that mapping with the builtin */
-    status = load_builtin( image_info, &nt_name, &exp_name, machine, info,
-                           module, size, limit_low, limit_high, 0 );
+    status = load_builtin( pe_mapping, machine, info, module, size, limit_low, limit_high, 0 );
     if (status == STATUS_IMAGE_ALREADY_LOADED)
     {
-        status = virtual_map_image( mapping, module, size, shared_file, limit_low, limit_high, 0,
-                                    machine, image_info, &nt_name, FALSE, 0 );
-        virtual_fill_image_information( image_info, info );
+        status = virtual_map_image( mapping, module, size, limit_low, limit_high, 0,
+                                    pe_mapping, machine, FALSE, 0 );
+        virtual_fill_image_information( &pe_mapping->image, info );
     }
-    if (shared_file) NtClose( shared_file );
-    free( image_info );
+    free_pe_mapping_info( pe_mapping );
     return status;
 }
 
@@ -6592,13 +6588,16 @@ NTSTATUS WINAPI NtQuerySection( HANDLE handle, SECTION_INFORMATION_CLASS class,
  *             ZwFlushVirtualMemory   (NTDLL.@)
  */
 NTSTATUS WINAPI NtFlushVirtualMemory( HANDLE process, LPCVOID *addr_ptr,
-                                      SIZE_T *size_ptr, ULONG unknown )
+                                      SIZE_T *size_ptr, IO_STATUS_BLOCK *io )
 {
     struct file_view *view;
     unsigned int status = STATUS_SUCCESS;
     sigset_t sigset;
     void *addr = ROUND_ADDR( *addr_ptr, page_mask );
 
+    if (io)
+        FIXME("Currently output io values not set.\n");
+
     if (process != NtCurrentProcess())
     {
         union apc_call call;
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index adf5a9bcd3fc..015ecec36032 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -3891,6 +3891,51 @@ error:
     return STATUS_UNSUCCESSFUL;
 }
 
+
+#ifdef _WIN64
+#define DEFAULT_SECURITY_COOKIE_64  0x00002b992ddfa232ull
+#endif
+#define DEFAULT_SECURITY_COOKIE_32  0xbb40e64e
+#define DEFAULT_SECURITY_COOKIE_16  (DEFAULT_SECURITY_COOKIE_32 >> 16)
+
+static void update_security_cookie( void *module, IMAGE_NT_HEADERS *nt )
+{
+    IMAGE_LOAD_CONFIG_DIRECTORY *cfg;
+    ULONG size;
+
+    cfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size );
+    if (!cfg) return;
+    size = min( size, cfg->Size );
+    if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie ) &&
+        cfg->SecurityCookie > (ULONG_PTR)module &&
+        cfg->SecurityCookie < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
+    {
+        static ULONG seed;
+        ULONG_PTR *cookie = (ULONG_PTR *)cfg->SecurityCookie;
+
+        TRACE( "initializing security cookie %p\n", cookie );
+
+        if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
+        for (;;)
+        {
+            if (*cookie == DEFAULT_SECURITY_COOKIE_16)
+                *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
+            else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
+                *cookie = RtlRandom( &seed );
+#ifdef DEFAULT_SECURITY_COOKIE_64
+            else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
+            {
+                *cookie = RtlRandom( &seed );
+                /* fill up, but keep the highest word clear */
+                *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
+            }
+#endif
+            else break;
+        }
+    }
+}
+
+
 /* find the LDR_DATA_TABLE_ENTRY corresponding to the driver module */
 static LDR_DATA_TABLE_ENTRY *find_ldr_module( HMODULE module )
 {
@@ -3979,6 +4024,8 @@ static void WINAPI ldr_notify_callback(ULONG reason, LDR_DLL_NOTIFICATION_DATA *
             return;
         }
     }
+
+    update_security_cookie( module, nt );
 }
 
 static WCHAR *get_windir_path( const WCHAR *path )
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 17c74b9322e2..85e530e55460 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -1445,7 +1445,7 @@
 @ stdcall -private ZwFlushBuffersFile(long ptr) NtFlushBuffersFile
 @ stdcall -private ZwFlushInstructionCache(long ptr long) NtFlushInstructionCache
 @ stdcall -private ZwFlushKey(long) NtFlushKey
-@ stdcall -private ZwFlushVirtualMemory(long ptr ptr long) NtFlushVirtualMemory
+@ stdcall -private ZwFlushVirtualMemory(long ptr ptr ptr) NtFlushVirtualMemory
 @ stdcall -private ZwFreeVirtualMemory(long ptr ptr long) NtFreeVirtualMemory
 @ stdcall -private ZwFsControlFile(long long ptr ptr ptr long ptr long ptr long) NtFsControlFile
 @ stdcall -private ZwImpersonateAnonymousToken(long) NtImpersonateAnonymousToken
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 06279b1c49e9..0c1361dca110 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -453,6 +453,7 @@ struct cancel_thread_ctx
 {
     HANDLE file;
     enum cancel_test test;
+    OVERLAPPED o, o2;
 };
 
 static DWORD WINAPI test_cancel_thread(void *param)
@@ -461,18 +462,23 @@ static DWORD WINAPI test_cancel_thread(void *param)
     NTSTATUS status = STATUS_SUCCESS;
     IO_STATUS_BLOCK cancel_sb;
     DWORD cancel_cnt, size;
-    OVERLAPPED o, o2, o3;
+    OVERLAPPED o3 = {0};
     BOOL res;
 
-    res = DeviceIoControl(ctx->file, IOCTL_WINETEST_RESET_CANCEL, NULL, 0, NULL, 0, NULL, &o);
+    memset(&ctx->o, 0, sizeof(OVERLAPPED));
+    memset(&ctx->o2, 0, sizeof(OVERLAPPED));
+
+    res = DeviceIoControl(ctx->file, IOCTL_WINETEST_RESET_CANCEL, NULL, 0, NULL, 0, NULL, &ctx->o);
     ok(res, "DeviceIoControl failed: %lu\n", GetLastError());
 
     if (ctx->test != cancelsync)
     {
-        res = DeviceIoControl(ctx->file, IOCTL_WINETEST_QUEUE_ASYNC, NULL, 0, NULL, 0, NULL, &o);
+        ctx->o.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+        res = DeviceIoControl(ctx->file, IOCTL_WINETEST_QUEUE_ASYNC, NULL, 0, NULL, 0, NULL, &ctx->o);
         ok(!res && GetLastError() == ERROR_IO_PENDING, "DeviceIoControl failed: %lu\n", GetLastError());
 
-        res = DeviceIoControl(ctx->file, IOCTL_WINETEST_QUEUE_ASYNC, NULL, 0, NULL, 0, NULL, &o2);
+        ctx->o2.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+        res = DeviceIoControl(ctx->file, IOCTL_WINETEST_QUEUE_ASYNC, NULL, 0, NULL, 0, NULL, &ctx->o2);
         ok(!res && GetLastError() == ERROR_IO_PENDING, "DeviceIoControl failed: %lu\n", GetLastError());
     }
 
@@ -608,7 +614,11 @@ static void test_overlapped(void)
     res = DeviceIoControl(file, IOCTL_WINETEST_COMPLETE_ASYNC, NULL, 0, NULL, 0, NULL, &overlapped);
     ok(res, "DeviceIoControl failed: %lu\n", GetLastError());
     WaitForSingleObject(thread, INFINITE);
+    WaitForSingleObject(ctx.o.hEvent, INFINITE);
+    WaitForSingleObject(ctx.o2.hEvent, INFINITE);
     CloseHandle(thread);
+    CloseHandle(ctx.o.hEvent);
+    CloseHandle(ctx.o2.hEvent);
 
     cancel_cnt = 0xdeadbeef;
     res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped2);
@@ -628,7 +638,11 @@ static void test_overlapped(void)
     res = DeviceIoControl(file, IOCTL_WINETEST_COMPLETE_ASYNC, NULL, 0, NULL, 0, NULL, &overlapped);
     ok(res, "DeviceIoControl failed: %lu\n", GetLastError());
     WaitForSingleObject(thread, INFINITE);
+    WaitForSingleObject(ctx.o.hEvent, INFINITE);
+    WaitForSingleObject(ctx.o2.hEvent, INFINITE);
     CloseHandle(thread);
+    CloseHandle(ctx.o.hEvent);
+    CloseHandle(ctx.o2.hEvent);
 
     cancel_cnt = 0xdeadbeef;
     res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped2);
@@ -646,7 +660,11 @@ static void test_overlapped(void)
     res = DeviceIoControl(file, IOCTL_WINETEST_COMPLETE_ASYNC, NULL, 0, NULL, 0, NULL, &overlapped);
     ok(res, "DeviceIoControl failed: %lu\n", GetLastError());
     WaitForSingleObject(thread, INFINITE);
+    WaitForSingleObject(ctx.o.hEvent, INFINITE);
+    WaitForSingleObject(ctx.o2.hEvent, INFINITE);
     CloseHandle(thread);
+    CloseHandle(ctx.o.hEvent);
+    CloseHandle(ctx.o2.hEvent);
 
     cancel_cnt = 0xdeadbeef;
     res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped2);
@@ -668,7 +686,11 @@ static void test_overlapped(void)
     res = DeviceIoControl(file, IOCTL_WINETEST_COMPLETE_ASYNC, NULL, 0, NULL, 0, NULL, &overlapped);
     ok(res, "DeviceIoControl failed: %lu\n", GetLastError());
     WaitForSingleObject(thread, INFINITE);
+    WaitForSingleObject(ctx.o.hEvent, INFINITE);
+    WaitForSingleObject(ctx.o2.hEvent, INFINITE);
     CloseHandle(thread);
+    CloseHandle(ctx.o.hEvent);
+    CloseHandle(ctx.o2.hEvent);
 
     cancel_cnt = 0xdeadbeef;
     res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped2);
diff --git a/dlls/odbc32/proxyodbc.c b/dlls/odbc32/proxyodbc.c
index dbe080f424f7..066e9c14064d 100644
--- a/dlls/odbc32/proxyodbc.c
+++ b/dlls/odbc32/proxyodbc.c
@@ -4821,6 +4821,22 @@ static SQLRETURN col_attributes_win32_a( struct statement *stmt, SQLUSMALLINT co
             free( strW );
         }
     }
+
+    if (stmt->hdr.win32_funcs->SQLColAttribute)
+        FIXME("Use SQLColAttribute\n");
+
+    if (stmt->hdr.win32_funcs->SQLColAttributeW)
+    {
+        switch (field_id)
+        {
+            case SQL_COLUMN_UNSIGNED:
+                return stmt->hdr.win32_funcs->SQLColAttributeW( stmt->hdr.win32_handle, col, field_id, char_attrs, buflen,
+                        retlen, num_attrs );
+            default:
+                FIXME("Unsupported for field %d.\n", field_id);
+        }
+    }
+
     return ret;
 }
 
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c
index c4f00ca5bead..e9997a86d241 100644
--- a/dlls/oleaut32/typelib.c
+++ b/dlls/oleaut32/typelib.c
@@ -4345,7 +4345,17 @@ static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
 			       const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
 			       const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
 {
-  SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars, pNameTable, NULL, hlp_strings);
+  sltg_ref_lookup_t *ref_lookup = NULL;
+
+  if (pTIHeader->href_table != 0xffffffff)
+      ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table),
+                               pTI->pTypeLib, (char *)pNameTable);
+
+  if (pTITail->vars_off != 0xffff)
+    SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars,
+                pNameTable, ref_lookup, hlp_strings);
+
+  free(ref_lookup);
 }
 
 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
diff --git a/dlls/quartz/tests/avisplit.c b/dlls/quartz/tests/avisplit.c
index cb756a07c5db..70e9b14d9028 100644
--- a/dlls/quartz/tests/avisplit.c
+++ b/dlls/quartz/tests/avisplit.c
@@ -1477,6 +1477,8 @@ static void test_seeking(void)
 {
     LONGLONG time, current, stop, prev_stop, earliest, latest, duration;
     const WCHAR *filename = load_resource(L"test.avi");
+    const LONGLONG one_second = 10000000;
+    const LONGLONG one_msec = 10000;
     IBaseFilter *filter = create_avi_splitter();
     IFilterGraph2 *graph = connect_input(filter, filename);
     IMediaSeeking *seeking;
@@ -1493,20 +1495,66 @@ static void test_seeking(void)
     {
         const GUID *guid;
         HRESULT hr;
+        HRESULT hr_set_time;
     }
     format_tests[] =
     {
-        {&TIME_FORMAT_MEDIA_TIME, S_OK},
-        {&TIME_FORMAT_FRAME, S_OK},
-
-        {&TIME_FORMAT_BYTE, S_FALSE},
-        {&TIME_FORMAT_NONE, S_FALSE},
-        {&TIME_FORMAT_SAMPLE, S_FALSE},
-        {&TIME_FORMAT_FIELD, S_FALSE},
-        {&testguid, S_FALSE},
+        {&TIME_FORMAT_MEDIA_TIME, S_OK, S_OK},
+        {&TIME_FORMAT_FRAME, S_OK, S_OK},
+        {&TIME_FORMAT_BYTE, S_FALSE, E_INVALIDARG},
+        {&TIME_FORMAT_NONE, S_FALSE, E_INVALIDARG},
+        {&TIME_FORMAT_SAMPLE, S_FALSE, E_INVALIDARG},
+        {&TIME_FORMAT_FIELD, S_FALSE, E_INVALIDARG},
+        {&testguid, S_FALSE, E_INVALIDARG},
     };
 
-    IBaseFilter_FindPin(filter, L"Stream 00", &pin);
+    const struct
+    {
+        const GUID *source_guid;
+        LONGLONG source_time;
+        const GUID *target_guid;
+        LONGLONG target_time;
+        HRESULT hr;
+        BOOL wine_todo;
+    } time_format_tests[] =
+    {
+        {&TIME_FORMAT_MEDIA_TIME, one_second, &TIME_FORMAT_MEDIA_TIME, one_second, S_OK},
+        {&TIME_FORMAT_MEDIA_TIME, one_second, &TIME_FORMAT_FRAME, 1, S_OK, TRUE},
+        {&TIME_FORMAT_MEDIA_TIME, one_second / 2 - 1, &TIME_FORMAT_FRAME, 0, S_OK, TRUE},
+        {&TIME_FORMAT_MEDIA_TIME, one_second / 2, &TIME_FORMAT_FRAME, 0, S_OK, TRUE},
+        {&TIME_FORMAT_MEDIA_TIME, 3 * one_second / 2, &TIME_FORMAT_FRAME, 1, S_OK, TRUE},
+        {&TIME_FORMAT_MEDIA_TIME, one_second, &TIME_FORMAT_FIELD, 0, E_INVALIDARG},
+        {&TIME_FORMAT_MEDIA_TIME, one_second, &TIME_FORMAT_SAMPLE, 1, S_OK, TRUE},
+        {&TIME_FORMAT_MEDIA_TIME, one_second, &TIME_FORMAT_BYTE, 0, E_INVALIDARG},
+
+        {&TIME_FORMAT_FRAME, 30, &TIME_FORMAT_MEDIA_TIME, 30 * one_second, S_OK, TRUE},
+        {&TIME_FORMAT_FRAME, 30, &TIME_FORMAT_FRAME, 30, S_OK, TRUE},
+        {&TIME_FORMAT_FRAME, 30, &TIME_FORMAT_FIELD, 0, E_INVALIDARG},
+        {&TIME_FORMAT_FRAME, 30, &TIME_FORMAT_SAMPLE, 0, E_INVALIDARG},
+        {&TIME_FORMAT_FRAME, 30, &TIME_FORMAT_BYTE, 0, E_INVALIDARG},
+
+        {&TIME_FORMAT_FIELD, 60, &TIME_FORMAT_MEDIA_TIME, 0, E_INVALIDARG},
+        {&TIME_FORMAT_FIELD, 60, &TIME_FORMAT_FRAME, 0, E_INVALIDARG},
+        {&TIME_FORMAT_FIELD, 60, &TIME_FORMAT_FIELD, 60, S_OK, TRUE},
+        {&TIME_FORMAT_FIELD, 60, &TIME_FORMAT_SAMPLE, 0, E_INVALIDARG},
+        {&TIME_FORMAT_FIELD, 60, &TIME_FORMAT_BYTE, 0, E_INVALIDARG},
+
+        {&TIME_FORMAT_SAMPLE, 48000, &TIME_FORMAT_MEDIA_TIME, 48000 * one_second, S_OK, TRUE},
+        {&TIME_FORMAT_SAMPLE, 48000, &TIME_FORMAT_FRAME, 0, E_INVALIDARG},
+        {&TIME_FORMAT_SAMPLE, 48000, &TIME_FORMAT_FIELD, 0, E_INVALIDARG},
+        {&TIME_FORMAT_SAMPLE, 48000, &TIME_FORMAT_SAMPLE, 48000, S_OK, TRUE},
+        {&TIME_FORMAT_SAMPLE, 48000, &TIME_FORMAT_BYTE, 0, E_INVALIDARG},
+
+        {&TIME_FORMAT_BYTE, 192000, &TIME_FORMAT_MEDIA_TIME, 0, E_INVALIDARG},
+        {&TIME_FORMAT_BYTE, 192000, &TIME_FORMAT_FRAME, 0, E_INVALIDARG},
+        {&TIME_FORMAT_BYTE, 192000, &TIME_FORMAT_FIELD, 0, E_INVALIDARG},
+        {&TIME_FORMAT_BYTE, 192000, &TIME_FORMAT_SAMPLE, 0, E_INVALIDARG},
+        {&TIME_FORMAT_BYTE, 192000, &TIME_FORMAT_BYTE, 192000, S_OK, TRUE},
+
+        {&TIME_FORMAT_NONE, 1, &TIME_FORMAT_MEDIA_TIME, 0, E_INVALIDARG},
+        {&TIME_FORMAT_MEDIA_TIME, one_second, &TIME_FORMAT_NONE, 0, E_INVALIDARG},
+    };
+                                                                                           IBaseFilter_FindPin(filter, L"Stream 00", &pin);
     IPin_QueryInterface(pin, &IID_IMediaSeeking, (void **)&seeking);
 
     hr = IMediaSeeking_GetCapabilities(seeking, &caps);
@@ -1538,10 +1586,14 @@ static void test_seeking(void)
     for (i = 0; i < ARRAY_SIZE(format_tests); ++i)
     {
         hr = IMediaSeeking_IsFormatSupported(seeking, format_tests[i].guid);
-        todo_wine_if(i == 1) ok(hr == format_tests[i].hr, "Got hr %#lx for format %s.\n",
+        todo_wine_if(i == 1)
+            ok(hr == format_tests[i].hr, "Got hr %#lx for format %s.\n",
                 hr, wine_dbgstr_guid(format_tests[i].guid));
     }
 
+    hr = IMediaSeeking_SetTimeFormat(seeking, &TIME_FORMAT_MEDIA_TIME);
+    ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
     hr = IMediaSeeking_QueryPreferredFormat(seeking, &format);
     ok(hr == S_OK, "Got hr %#lx.\n", hr);
     ok(IsEqualGUID(&format, &TIME_FORMAT_MEDIA_TIME), "Got format %s.\n", wine_dbgstr_guid(&format));
@@ -1555,6 +1607,39 @@ static void test_seeking(void)
     hr = IMediaSeeking_IsUsingTimeFormat(seeking, &TIME_FORMAT_FRAME);
     ok(hr == S_FALSE, "Got hr %#lx.\n", hr);
 
+    for (i = 0; i < ARRAY_SIZE(format_tests); ++i)
+    {
+        hr = IMediaSeeking_SetTimeFormat(seeking, format_tests[i].guid);
+        todo_wine_if(i == 1)
+            ok(hr == format_tests[i].hr_set_time, "Got hr %#lx for format %s.\n",
+               hr, wine_dbgstr_guid(format_tests[i].guid));
+    }
+
+    hr = IMediaSeeking_SetTimeFormat(seeking, &TIME_FORMAT_MEDIA_TIME);
+    ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+    for (i = 0; i < ARRAY_SIZE(time_format_tests); ++i)
+    {
+        LONGLONG result = 0xdeadbeef;
+
+        hr = IMediaSeeking_ConvertTimeFormat(seeking, &result, time_format_tests[i].target_guid,
+                time_format_tests[i].source_time, time_format_tests[i].source_guid);
+
+        todo_wine_if(time_format_tests[i].wine_todo)
+            ok(hr == time_format_tests[i].hr, "test %u hr %#lx.\n", i, hr);
+        if (hr == S_OK)
+        {
+            todo_wine_if(time_format_tests[i].wine_todo)
+                ok(result == time_format_tests[i].target_time, "wrong value %s at test %u.\n",
+                        wine_dbgstr_longlong(result), i);
+        }
+        else
+        {
+            ok(result == 0xdeadbeef, "result was modified at test %u: %s.\n",
+                    i, wine_dbgstr_longlong(result));
+        }
+    }
+
     hr = IMediaSeeking_SetTimeFormat(seeking, &TIME_FORMAT_SAMPLE);
     ok(hr == E_INVALIDARG, "Got hr %#lx.\n", hr);
     hr = IMediaSeeking_SetTimeFormat(seeking, &TIME_FORMAT_FRAME);
@@ -1575,7 +1660,7 @@ static void test_seeking(void)
     duration = 0;
     hr = IMediaSeeking_GetDuration(seeking, &duration);
     ok(hr == S_OK, "Got hr %#lx.\n", hr);
-    ok(duration == 50000000, "Got duration %I64d.\n", duration);
+    ok(duration == 5 * one_second, "Got duration %I64d.\n", duration);
 
     stop = current = 0xdeadbeef;
     hr = IMediaSeeking_GetStopPosition(seeking, &stop);
@@ -1603,7 +1688,7 @@ static void test_seeking(void)
     time = 0xdeadbeef;
     hr = IMediaSeeking_ConvertTimeFormat(seeking, &time, NULL, 123, &TIME_FORMAT_FRAME);
     todo_wine ok(hr == S_OK, "Got hr %#lx.\n", hr);
-    todo_wine ok(time == 123 * 10000000, "Got time %s.\n", wine_dbgstr_longlong(time));
+    todo_wine ok(time == 123 * one_second, "Got time %s.\n", wine_dbgstr_longlong(time));
 
     earliest = latest = 0xdeadbeef;
     hr = IMediaSeeking_GetAvailable(seeking, &earliest, &latest);
@@ -1630,13 +1715,13 @@ static void test_seeking(void)
     hr = IMediaSeeking_GetPreroll(seeking, &time);
     todo_wine ok(hr == E_NOTIMPL, "Got hr %#lx.\n", hr);
 
-    current = 1500 * 10000;
-    stop = 3500 * 10000;
+    current = 1500 * one_msec;
+    stop = 3500 * one_msec;
     hr = IMediaSeeking_SetPositions(seeking, &current, AM_SEEKING_AbsolutePositioning,
             &stop, AM_SEEKING_AbsolutePositioning);
     ok(hr == S_OK, "Got hr %#lx.\n", hr);
-    ok(current == 1500 * 10000, "Got time %s.\n", wine_dbgstr_longlong(current));
-    ok(stop == 3500 * 10000, "Got time %s.\n", wine_dbgstr_longlong(stop));
+    ok(current == 1500 * one_msec, "Got time %s.\n", wine_dbgstr_longlong(current));
+    ok(stop == 3500 * one_msec, "Got time %s.\n", wine_dbgstr_longlong(stop));
 
     stop = current = 0xdeadbeef;
     hr = IMediaSeeking_GetPositions(seeking, &current, &stop);
@@ -1645,8 +1730,8 @@ static void test_seeking(void)
     ok(current > 0 && current < duration, "Got time %s.\n", wine_dbgstr_longlong(current));
     ok(stop > 0 && stop < duration && stop > current, "Got time %s.\n", wine_dbgstr_longlong(stop));
 
-    current = 1500 * 10000;
-    stop = 3500 * 10000;
+    current = 1500 * one_msec;
+    stop = 3500 * one_msec;
     hr = IMediaSeeking_SetPositions(seeking, &current, AM_SEEKING_AbsolutePositioning | AM_SEEKING_ReturnTime,
             &stop, AM_SEEKING_AbsolutePositioning | AM_SEEKING_ReturnTime);
     ok(hr == S_OK, "Got hr %#lx.\n", hr);
diff --git a/dlls/quartz/tests/mpegaudio.c b/dlls/quartz/tests/mpegaudio.c
index 9fa6796e0967..804cbbcc3d13 100644
--- a/dlls/quartz/tests/mpegaudio.c
+++ b/dlls/quartz/tests/mpegaudio.c
@@ -905,7 +905,6 @@ struct testfilter
     unsigned int got_sample, got_new_segment, got_eos, got_begin_flush, got_end_flush;
     REFERENCE_TIME expected_start_time;
     REFERENCE_TIME expected_stop_time;
-    BOOL todo_time;
 };
 
 static inline struct testfilter *impl_from_strmbase_filter(struct strmbase_filter *iface)
@@ -1013,9 +1012,7 @@ static HRESULT WINAPI testsink_Receive(struct strmbase_sink *iface, IMediaSample
     ok(hr == S_OK, "Got hr %#lx.\n", hr);
     if (filter->got_sample == 1)
     {
-        todo_wine_if(filter->todo_time)
         ok(start == filter->expected_start_time, "Got start time %s.\n", wine_dbgstr_longlong(start));
-        todo_wine_if(filter->todo_time)
         ok(stop == filter->expected_stop_time, "Got stop time %s.\n", wine_dbgstr_longlong(stop));
     }
 
@@ -1513,7 +1510,6 @@ static void test_streaming_events(IMediaControl *control, IPin *sink,
 
     testsink->expected_start_time = 0;
     testsink->expected_stop_time = 120000;
-    testsink->todo_time = TRUE;
     hr = IMemInputPin_Receive(input, sample);
     ok(hr == S_OK, "Got hr %#lx.\n", hr);
     hr = IMemInputPin_Receive(input, sample);
diff --git a/dlls/quartz/tests/mpegsplit.c b/dlls/quartz/tests/mpegsplit.c
index 3d4ba8b79590..1d62f0000ee0 100644
--- a/dlls/quartz/tests/mpegsplit.c
+++ b/dlls/quartz/tests/mpegsplit.c
@@ -2027,10 +2027,12 @@ static void test_streamselect(IAMStreamSelect *sel)
 
 static void test_video_file(void)
 {
+    static const unsigned char SEQ_START_CODE[] = {0, 0, 1, 0xb3};
     const WCHAR *filename = load_resource(L"test.mpg");
     IBaseFilter *filter = create_mpeg_splitter();
     struct testfilter testsink_video;
     struct testfilter testsink_audio;
+    const MPEG1VIDEOINFO *format;
     IPin *source_video = NULL;
     IPin *source_audio = NULL;
     IMediaControl *control;
@@ -2075,6 +2077,13 @@ static void test_video_file(void)
     ok(IsEqualGUID(&testsink_video.sink.pin.mt.subtype, &MEDIASUBTYPE_MPEG1Payload), "Media types didn't match.\n");
     ok(IsEqualGUID(&testsink_video.sink.pin.mt.formattype, &FORMAT_MPEGVideo), "Media types didn't match.\n");
 
+    format = (const MPEG1VIDEOINFO *)testsink_video.sink.pin.mt.pbFormat;
+    ret = offsetof(MPEG1VIDEOINFO, bSequenceHeader[0]) + format->cbSequenceHeader;
+    ok(testsink_video.sink.pin.mt.cbFormat == ret, "cbFormat didn't match, got %lu.\n", testsink_video.sink.pin.mt.cbFormat);
+    todo_wine ok(format->dwStartTimeCode == 4096, "dwStartTimeCode didn't match, got %lu.\n", format->dwStartTimeCode);
+    ok(format->cbSequenceHeader == 12, "cbSequenceHeader didn't match, got %lu.\n", format->cbSequenceHeader);
+    ok(!memcmp(format->bSequenceHeader, SEQ_START_CODE, sizeof(SEQ_START_CODE)), "Sequence header didn't match.\n");
+
     ok(IsEqualGUID(&testsink_audio.sink.pin.mt.majortype, &MEDIATYPE_Audio), "Media types didn't match.\n");
     ok(IsEqualGUID(&testsink_audio.sink.pin.mt.subtype, &MEDIASUBTYPE_MPEG1AudioPayload), "Media types didn't match.\n");
     ok(IsEqualGUID(&testsink_audio.sink.pin.mt.formattype, &FORMAT_WaveFormatEx), "Media types didn't match.\n");
diff --git a/dlls/secur32/schannel.c b/dlls/secur32/schannel.c
index 3ad6be5e7382..83aea0b4737b 100644
--- a/dlls/secur32/schannel.c
+++ b/dlls/secur32/schannel.c
@@ -1486,13 +1486,13 @@ static void schan_decrypt_fill_buffer(PSecBufferDesc message, ULONG buffer_type,
 static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle,
         PSecBufferDesc message, ULONG message_seq_no, PULONG quality)
 {
+    unsigned expected_size, remaining_size;
     SECURITY_STATUS status = SEC_E_OK;
     struct schan_context *ctx;
     struct recv_params params;
     SecBuffer *buffer;
     SIZE_T data_size;
     char *data;
-    unsigned expected_size;
     ULONG received = 0;
     int idx;
     unsigned char *buf_ptr;
@@ -1517,13 +1517,13 @@ static SECURITY_STATUS SEC_ENTRY schan_DecryptMessage(PCtxtHandle context_handle
     {
         TRACE("Expected %u bytes, but buffer only contains %lu bytes\n", expected_size, buffer->cbBuffer);
         buffer->BufferType = SECBUFFER_MISSING;
-        buffer->cbBuffer = expected_size - buffer->cbBuffer;
+        buffer->cbBuffer = remaining_size = expected_size - buffer->cbBuffer;
 
         /* This is a bit weird, but windows does it too */
         idx = schan_find_sec_buffer_idx(message, 0, SECBUFFER_EMPTY);
         buffer = &message->pBuffers[idx];
         buffer->BufferType = SECBUFFER_MISSING;
-        buffer->cbBuffer = expected_size - buffer->cbBuffer;
+        buffer->cbBuffer = remaining_size;
 
         TRACE("Returning SEC_E_INCOMPLETE_MESSAGE\n");
         return SEC_E_INCOMPLETE_MESSAGE;
diff --git a/dlls/secur32/tests/schannel.c b/dlls/secur32/tests/schannel.c
index 2f693c6f8715..04ef9ca68809 100644
--- a/dlls/secur32/tests/schannel.c
+++ b/dlls/secur32/tests/schannel.c
@@ -1371,11 +1371,14 @@ static void test_communication(void)
 
     /* Incomplete data */
     buffers[0].pBuffers[1].BufferType = SECBUFFER_EMPTY;
+    buffers[0].pBuffers[1].cbBuffer = 1;
     buffers[0].pBuffers[0].cbBuffer = (data[3]<<8) | data[4];
     status = DecryptMessage(&context, &buffers[0], 0, NULL);
     ok(status == SEC_E_INCOMPLETE_MESSAGE, "Expected SEC_E_INCOMPLETE_MESSAGE, got %08lx\n", status);
     ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_MISSING, "Expected first buffer to be SECBUFFER_MISSING\n");
     ok(buffers[0].pBuffers[0].cbBuffer == 5, "Expected first buffer to be a five bytes\n");
+    ok(buffers[0].pBuffers[1].BufferType == SECBUFFER_MISSING, "Unexpected buffer type\n");
+    ok(buffers[0].pBuffers[1].cbBuffer == 5, "Unexpected buffer size\n");
 
     /* Renegotiate */
     buffers[0].pBuffers[0].BufferType = SECBUFFER_DATA;
diff --git a/dlls/secur32/tests/secur32.c b/dlls/secur32/tests/secur32.c
index 72a5ddef50bf..bc0dc01a1094 100644
--- a/dlls/secur32/tests/secur32.c
+++ b/dlls/secur32/tests/secur32.c
@@ -442,8 +442,7 @@ static void test_kerberos(void)
     static const ULONG optional_mask =
           SECPKG_FLAG_RESTRICTED_TOKENS
         | SECPKG_FLAG_APPCONTAINER_CHECKS
-        | 0x02000000; /* not defined in the SDK */
-
+        | SECPKG_FLAG_APPLY_LOOPBACK;
 
     status = QuerySecurityPackageInfoA(provider, &info);
     ok(status == SEC_E_OK, "Kerberos package not installed (%08lx), skipping test\n", status);
diff --git a/dlls/setupapi/devinst.c b/dlls/setupapi/devinst.c
index de628d81bd23..96e47c1c0849 100644
--- a/dlls/setupapi/devinst.c
+++ b/dlls/setupapi/devinst.c
@@ -243,47 +243,6 @@ static inline void copy_device_iface_data(SP_DEVICE_INTERFACE_DATA *data,
     data->Reserved = (ULONG_PTR)iface;
 }
 
-static WCHAR **devinst_table;
-static unsigned int devinst_table_size;
-
-static DEVINST get_devinst_for_device_id(const WCHAR *id)
-{
-    unsigned int i;
-
-    for (i = 0; i < devinst_table_size; ++i)
-    {
-        if (!devinst_table[i])
-            break;
-        if (!wcsicmp(devinst_table[i], id))
-            return i;
-    }
-    return i;
-}
-
-static DEVINST alloc_devinst_for_device_id(const WCHAR *id)
-{
-    DEVINST ret;
-
-    ret = get_devinst_for_device_id(id);
-    if (ret == devinst_table_size)
-    {
-        if (devinst_table)
-        {
-            devinst_table = realloc(devinst_table, devinst_table_size * 2 * sizeof(*devinst_table));
-            memset(devinst_table + devinst_table_size, 0, devinst_table_size * sizeof(*devinst_table));
-            devinst_table_size *= 2;
-        }
-        else
-        {
-            devinst_table_size = 256;
-            devinst_table = calloc(devinst_table_size, sizeof(*devinst_table));
-        }
-    }
-    if (!devinst_table[ret])
-        devinst_table[ret] = wcsdup(id);
-    return ret;
-}
-
 static void SETUPDI_GuidToString(const GUID *guid, LPWSTR guidStr)
 {
     swprintf(guidStr, 39, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
@@ -4225,134 +4184,6 @@ BOOL WINAPI SetupDiDeleteDevRegKey(HDEVINFO devinfo, SP_DEVINFO_DATA *device_dat
     return !l;
 }
 
-/***********************************************************************
- *              CM_Get_Device_IDA  (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST devnode, char *buffer, ULONG len, ULONG flags)
-{
-    TRACE("%lu, %p, %lu, %#lx\n", devnode, buffer, len, flags);
-
-    if (devnode >= devinst_table_size || !devinst_table[devnode])
-        return CR_NO_SUCH_DEVINST;
-
-    WideCharToMultiByte(CP_ACP, 0, devinst_table[devnode], -1, buffer, len, 0, 0);
-    TRACE("Returning %s\n", debugstr_a(buffer));
-    return CR_SUCCESS;
-}
-
-/***********************************************************************
- *              CM_Get_Device_IDW  (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_Device_IDW(DEVINST devnode, WCHAR *buffer, ULONG len, ULONG flags)
-{
-    TRACE("%lu, %p, %lu, %#lx\n", devnode, buffer, len, flags);
-
-    if (devnode >= devinst_table_size || !devinst_table[devnode])
-        return CR_NO_SUCH_DEVINST;
-
-    lstrcpynW(buffer, devinst_table[devnode], len);
-    TRACE("Returning %s\n", debugstr_w(buffer));
-    return CR_SUCCESS;
-}
-
-/***********************************************************************
- *              CM_Get_Device_ID_Size  (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_Device_ID_Size(ULONG *len, DEVINST devnode, ULONG flags)
-{
-    TRACE("%p, %lu, %#lx\n", len, devnode, flags);
-
-    if (devnode >= devinst_table_size || !devinst_table[devnode])
-        return CR_NO_SUCH_DEVINST;
-
-    *len = lstrlenW(devinst_table[devnode]);
-    return CR_SUCCESS;
-}
-
-/***********************************************************************
- *      CM_Locate_DevNodeA (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Locate_DevNodeA(DEVINST *devinst, DEVINSTID_A device_id, ULONG flags)
-{
-    TRACE("%p %s %#lx.\n", devinst, debugstr_a(device_id), flags);
-
-    return CM_Locate_DevNode_ExA(devinst, device_id, flags, NULL);
-}
-
-/***********************************************************************
- *      CM_Locate_DevNodeW (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Locate_DevNodeW(DEVINST *devinst, DEVINSTID_W device_id, ULONG flags)
-{
-    TRACE("%p %s %#lx.\n", devinst, debugstr_w(device_id), flags);
-
-    return CM_Locate_DevNode_ExW(devinst, device_id, flags, NULL);
-}
-
-/***********************************************************************
- *      CM_Locate_DevNode_ExA (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Locate_DevNode_ExA(DEVINST *devinst, DEVINSTID_A device_id, ULONG flags, HMACHINE machine)
-{
-    CONFIGRET ret;
-    DEVINSTID_W device_idw;
-    unsigned int slen;
-
-    TRACE("%p %s %#lx %p.\n", devinst, debugstr_a(device_id), flags, machine);
-
-    if (!device_id)
-    {
-        FIXME("NULL device_id unsupported.\n");
-        return CR_CALL_NOT_IMPLEMENTED;
-    }
-
-    slen = strlen(device_id) + 1;
-    if (!(device_idw = malloc(slen * sizeof(*device_idw))))
-        return CR_OUT_OF_MEMORY;
-
-    MultiByteToWideChar(CP_ACP, 0, device_id, slen, device_idw, slen);
-    ret = CM_Locate_DevNode_ExW(devinst, device_idw, flags, NULL);
-    free(device_idw);
-    return ret;
-}
-
-/***********************************************************************
- *      CM_Locate_DevNode_ExW (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Locate_DevNode_ExW(DEVINST *devinst, DEVINSTID_W device_id, ULONG flags, HMACHINE machine)
-{
-    HKEY enum_hkey, device_hkey;
-    LSTATUS status;
-
-    TRACE("%p %s %#lx %p.\n", devinst, debugstr_w(device_id), flags, machine);
-
-    if (!devinst)
-        return CR_INVALID_POINTER;
-
-    *devinst = 0;
-
-    if (machine)
-        FIXME("machine %p not supported.\n", machine);
-    if (flags)
-        FIXME("flags %#lx are not supported.\n", flags);
-
-    if (!device_id)
-    {
-        FIXME("NULL device_id unsupported.\n");
-        return CR_CALL_NOT_IMPLEMENTED;
-    }
-
-    RegCreateKeyExW(HKEY_LOCAL_MACHINE, Enum, 0, NULL, 0, KEY_READ, NULL, &enum_hkey, NULL);
-    if (!(status = RegOpenKeyExW(enum_hkey, device_id, 0, KEY_READ, &device_hkey)))
-        RegCloseKey(device_hkey);
-    RegCloseKey(enum_hkey);
-    if (status)
-        return CR_NO_SUCH_DEVNODE;
-
-    *devinst = alloc_devinst_for_device_id(device_id);
-    return CR_SUCCESS;
-}
-
 static CONFIGRET get_device_id_list(const WCHAR *filter, WCHAR *buffer, ULONG *len, ULONG flags)
 {
     const ULONG supported_flags = CM_GETIDLIST_FILTER_NONE | CM_GETIDLIST_FILTER_CLASS | CM_GETIDLIST_FILTER_PRESENT;
diff --git a/dlls/setupapi/setupapi.spec b/dlls/setupapi/setupapi.spec
index 6bfe922a1d73..6deb5cd949bb 100644
--- a/dlls/setupapi/setupapi.spec
+++ b/dlls/setupapi/setupapi.spec
@@ -75,10 +75,10 @@
 @ stdcall CM_Get_DevNode_Registry_Property_ExW(long long ptr ptr ptr long ptr)
 @ stdcall CM_Get_DevNode_Status(ptr ptr long long)
 @ stdcall CM_Get_DevNode_Status_Ex(ptr ptr long long ptr)
-@ stdcall CM_Get_Device_IDA(ptr ptr long long)
-@ stdcall CM_Get_Device_IDW(ptr ptr long long)
-@ stdcall CM_Get_Device_ID_ExA(ptr ptr long long ptr)
-@ stdcall CM_Get_Device_ID_ExW(ptr ptr long long ptr)
+@ stdcall CM_Get_Device_IDA(ptr ptr long long) cfgmgr32.CM_Get_Device_IDA
+@ stdcall CM_Get_Device_IDW(ptr ptr long long) cfgmgr32.CM_Get_Device_IDW
+@ stdcall CM_Get_Device_ID_ExA(ptr ptr long long ptr) cfgmgr32.CM_Get_Device_ID_ExA
+@ stdcall CM_Get_Device_ID_ExW(ptr ptr long long ptr) cfgmgr32.CM_Get_Device_ID_ExW
 @ stdcall CM_Get_Device_ID_ListA(str ptr long long)
 @ stdcall CM_Get_Device_ID_ListW(wstr ptr long long)
 @ stdcall CM_Get_Device_ID_List_ExA(str ptr long long ptr)
@@ -87,8 +87,8 @@
 @ stdcall CM_Get_Device_ID_List_SizeW(ptr wstr long)
 @ stdcall CM_Get_Device_ID_List_Size_ExA(ptr str long ptr)
 @ stdcall CM_Get_Device_ID_List_Size_ExW(ptr wstr long ptr)
-@ stdcall CM_Get_Device_ID_Size(ptr ptr long)
-@ stub CM_Get_Device_ID_Size_Ex
+@ stdcall CM_Get_Device_ID_Size(ptr ptr long) cfgmgr32.CM_Get_Device_ID_Size
+@ stdcall CM_Get_Device_ID_Size_Ex(ptr ptr long ptr) cfgmgr32.CM_Get_Device_ID_Size_Ex
 @ stdcall CM_Get_Device_Interface_AliasA(str ptr ptr ptr long)
 @ stdcall CM_Get_Device_Interface_AliasW(wstr ptr ptr ptr long)
 @ stub CM_Get_Device_Interface_Alias_ExA
@@ -132,10 +132,10 @@
 @ stub CM_Intersect_Range_List
 @ stub CM_Invert_Range_List
 @ stub CM_Is_Dock_Station_Present
-@ stdcall CM_Locate_DevNodeA(ptr str long)
-@ stdcall CM_Locate_DevNodeW(ptr wstr long)
-@ stdcall CM_Locate_DevNode_ExA(ptr str long long)
-@ stdcall CM_Locate_DevNode_ExW(ptr wstr long long)
+@ stdcall CM_Locate_DevNodeA(ptr str long) cfgmgr32.CM_Locate_DevNodeA
+@ stdcall CM_Locate_DevNodeW(ptr wstr long) cfgmgr32.CM_Locate_DevNodeW
+@ stdcall CM_Locate_DevNode_ExA(ptr str long long) cfgmgr32.CM_Locate_DevNode_ExA
+@ stdcall CM_Locate_DevNode_ExW(ptr wstr long long) cfgmgr32.CM_Locate_DevNode_ExW
 @ stub CM_Merge_Range_List
 @ stub CM_Modify_Res_Des
 @ stub CM_Modify_Res_Des_Ex
@@ -146,8 +146,8 @@
 @ stdcall CM_Open_Class_KeyW(ptr wstr long long ptr long) cfgmgr32.CM_Open_Class_KeyW
 @ stdcall CM_Open_Class_Key_ExA(ptr str long long ptr long ptr) cfgmgr32.CM_Open_Class_Key_ExA
 @ stdcall CM_Open_Class_Key_ExW(ptr wstr long long ptr long ptr) cfgmgr32.CM_Open_Class_Key_ExW
-@ stdcall CM_Open_DevNode_Key(long long long long ptr long)
-@ stub CM_Open_DevNode_Key_Ex
+@ stdcall CM_Open_DevNode_Key(long long long long ptr long) cfgmgr32.CM_Open_DevNode_Key
+@ stdcall CM_Open_DevNode_Key_Ex(long long long long ptr long ptr) cfgmgr32.CM_Open_DevNode_Key_Ex
 @ stub CM_Query_And_Remove_SubTreeA
 @ stub CM_Query_And_Remove_SubTreeW
 @ stub CM_Query_And_Remove_SubTree_ExA
diff --git a/dlls/setupapi/stubs.c b/dlls/setupapi/stubs.c
index 3b2641f98751..eccb82295c88 100644
--- a/dlls/setupapi/stubs.c
+++ b/dlls/setupapi/stubs.c
@@ -78,18 +78,6 @@ CONFIGRET WINAPI CM_Disconnect_Machine(HMACHINE handle)
 
 }
 
-/***********************************************************************
- *             CM_Open_DevNode_Key  (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Open_DevNode_Key(
-    DEVINST dnDevInst, REGSAM access, ULONG ulHardwareProfile, REGDISPOSITION disposition,
-    PHKEY phkDevice, ULONG ulFlags)
-{
-    FIXME("0x%08lx 0x%08lx 0x%08lx 0x%08lx %p 0x%08lx : stub\n", dnDevInst, access, ulHardwareProfile,
-          disposition, phkDevice, ulFlags);
-    return CR_SUCCESS;
-}
-
 /***********************************************************************
  *             CM_Get_Child  (SETUPAPI.@)
  */
@@ -110,26 +98,6 @@ CONFIGRET WINAPI CM_Get_Child_Ex(
     return CR_SUCCESS;
 }
 
-/***********************************************************************
- *             CM_Get_Device_ID_ExA  (SETUPAPI.@)
- */
-DWORD WINAPI CM_Get_Device_ID_ExA(
-    DEVINST dnDevInst, PCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine)
-{
-    FIXME("0x%08lx %p 0x%08lx 0x%08lx %p: stub\n", dnDevInst, Buffer, BufferLen, ulFlags, hMachine);
-    return CR_SUCCESS;
-}
-
-/***********************************************************************
- *             CM_Get_Device_ID_ExW  (SETUPAPI.@)
- */
-DWORD WINAPI CM_Get_Device_ID_ExW(
-    DEVINST dnDevInst, PWCHAR Buffer, ULONG BufferLen, ULONG ulFlags, HMACHINE hMachine)
-{
-    FIXME("0x%08lx %p 0x%08lx 0x%08lx %p: stub\n", dnDevInst, Buffer, BufferLen, ulFlags, hMachine);
-    return CR_SUCCESS;
-}
-
 /***********************************************************************
  *              CM_Get_Parent (SETUPAPI.@)
  */
@@ -287,44 +255,6 @@ CONFIGRET WINAPI CM_Get_Device_Interface_AliasW(const WCHAR *interface, GUID *cl
     return CR_FAILURE;
 }
 
-/***********************************************************************
- *      CM_Get_DevNode_Registry_Property_ExA (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_DevNode_Registry_Property_ExA(DEVINST dev, ULONG prop, PULONG regdatatype,
-    PVOID buf, PULONG len, ULONG flags, HMACHINE machine)
-{
-    FIXME("0x%08lx %lu %p %p %p 0x%08lx %p: stub\n", dev, prop, regdatatype, buf, len, flags, machine);
-    return CR_FAILURE;
-}
-
-/***********************************************************************
- *      CM_Get_DevNode_Registry_Property_ExW (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_DevNode_Registry_Property_ExW(DEVINST dev, ULONG prop, PULONG regdatatype,
-    PVOID buf, PULONG len, ULONG flags, HMACHINE machine)
-{
-    FIXME("0x%08lx %lu %p %p %p 0x%08lx %p: stub\n", dev, prop, regdatatype, buf, len, flags, machine);
-    return CR_FAILURE;
-}
-
-/***********************************************************************
- *      CM_Get_DevNode_Registry_PropertyA (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_DevNode_Registry_PropertyA(DEVINST dev, ULONG prop, PULONG regdatatype,
-    PVOID buf, PULONG len, ULONG flags)
-{
-    return CM_Get_DevNode_Registry_Property_ExA(dev, prop, regdatatype, buf, len, flags, NULL);
-}
-
-/***********************************************************************
- *      CM_Get_DevNode_Registry_PropertyW (SETUPAPI.@)
- */
-CONFIGRET WINAPI CM_Get_DevNode_Registry_PropertyW(DEVINST dev, ULONG prop, PULONG regdatatype,
-    PVOID buf, PULONG len, ULONG flags)
-{
-    return CM_Get_DevNode_Registry_Property_ExW(dev, prop, regdatatype, buf, len, flags, NULL);
-}
-
 /***********************************************************************
  *      CM_Get_DevNode_Status (SETUPAPI.@)
  */
diff --git a/dlls/taskschd/task.c b/dlls/taskschd/task.c
index 2ade926bf90b..7525a52566d8 100644
--- a/dlls/taskschd/task.c
+++ b/dlls/taskschd/task.c
@@ -819,6 +819,372 @@ static HRESULT RegistrationTrigger_create(ITrigger **trigger)
     return S_OK;
 }
 
+typedef struct {
+    ILogonTrigger ILogonTrigger_iface;
+    BOOL enabled;
+    LONG ref;
+    WCHAR *user_id;
+    WCHAR *id;
+    WCHAR *execution_time_limit;
+    WCHAR *start_boundary;
+    WCHAR *end_boundary;
+    WCHAR *delay;
+} LogonTrigger;
+
+static inline LogonTrigger *impl_from_ILogonTrigger(ILogonTrigger *iface)
+{
+    return CONTAINING_RECORD(iface, LogonTrigger, ILogonTrigger_iface);
+}
+
+static HRESULT WINAPI LogonTrigger_QueryInterface(ILogonTrigger *iface, REFIID riid, void **ppv)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+
+    if(IsEqualGUID(&IID_IUnknown, riid) ||
+       IsEqualGUID(&IID_IDispatch, riid) ||
+       IsEqualGUID(&IID_ITrigger, riid) ||
+       IsEqualGUID(&IID_ILogonTrigger, riid))
+    {
+        *ppv = &This->ILogonTrigger_iface;
+    }
+    else
+    {
+        FIXME("unsupported riid %s\n", debugstr_guid(riid));
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI LogonTrigger_AddRef(ILogonTrigger *iface)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+    TRACE("(%p) ref=%ld\n", This, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI LogonTrigger_Release(ILogonTrigger *iface)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+
+    if(!ref)
+    {
+        TRACE("destroying %p\n", iface);
+        free(This->user_id);
+        free(This->id);
+        free(This->execution_time_limit);
+        free(This->start_boundary);
+        free(This->end_boundary);
+        free(This->delay);
+        free(This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI LogonTrigger_GetTypeInfoCount(ILogonTrigger *iface, UINT *count)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    FIXME("(%p)->(%p)\n", This, count);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI LogonTrigger_GetTypeInfo(ILogonTrigger *iface, UINT index, LCID lcid, ITypeInfo **info)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    FIXME("(%p)->(%u %lu %p)\n", This, index, lcid, info);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI LogonTrigger_GetIDsOfNames(ILogonTrigger *iface, REFIID riid, LPOLESTR *names,
+                                        UINT count, LCID lcid, DISPID *dispid)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    FIXME("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), names, count, lcid, dispid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI LogonTrigger_Invoke(ILogonTrigger *iface, DISPID dispid, REFIID riid, LCID lcid, WORD flags,
+                                 DISPPARAMS *params, VARIANT *result, EXCEPINFO *excepinfo, UINT *argerr)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    FIXME("(%p)->(%ld %s %lx %x %p %p %p %p)\n", This, dispid, debugstr_guid(riid), lcid, flags,
+          params, result, excepinfo, argerr);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI LogonTrigger_get_Type(ILogonTrigger *iface, TASK_TRIGGER_TYPE2 *type)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, type);
+
+    if (!type) return E_POINTER;
+
+    *type = TASK_TRIGGER_LOGON;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_Id(ILogonTrigger *iface, BSTR *id)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, id);
+
+    if (!id) return E_POINTER;
+
+    if (!This->id) *id = NULL;
+    else if (!(*id = SysAllocString(This->id))) return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_Id(ILogonTrigger *iface, BSTR id)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    WCHAR *str = NULL;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(id));
+
+    if (id && !(str = wcsdup(id))) return E_OUTOFMEMORY;
+    free(This->id);
+    This->id = str;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_Repetition(ILogonTrigger *iface, IRepetitionPattern **repeat)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, repeat);
+
+    if (!repeat) return E_POINTER;
+
+    return RepetitionPattern_create(repeat);
+}
+
+static HRESULT WINAPI LogonTrigger_put_Repetition(ILogonTrigger *iface, IRepetitionPattern *repeat)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    FIXME("(%p)->(%p)\n", This, repeat);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI LogonTrigger_get_ExecutionTimeLimit(ILogonTrigger *iface, BSTR *limit)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, limit);
+
+    if (!limit) return E_POINTER;
+
+    if (!This->execution_time_limit) *limit = NULL;
+    else if (!(*limit = SysAllocString(This->execution_time_limit))) return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_ExecutionTimeLimit(ILogonTrigger *iface, BSTR limit)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    WCHAR *str = NULL;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(limit));
+
+    if (limit && !(str = wcsdup(limit))) return E_OUTOFMEMORY;
+    free(This->execution_time_limit);
+    This->execution_time_limit = str;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_StartBoundary(ILogonTrigger *iface, BSTR *start)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, start);
+
+    if (!start) return E_POINTER;
+
+    if (!This->start_boundary) *start = NULL;
+    else if (!(*start = SysAllocString(This->start_boundary))) return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_StartBoundary(ILogonTrigger *iface, BSTR start)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    WCHAR *str = NULL;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(start));
+
+    if (start && !(str = wcsdup(start))) return E_OUTOFMEMORY;
+    free(This->start_boundary);
+    This->start_boundary = str;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_EndBoundary(ILogonTrigger *iface, BSTR *end)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, end);
+
+    if (!end) return E_POINTER;
+
+    if (!This->end_boundary) *end = NULL;
+    else if (!(*end = SysAllocString(This->end_boundary))) return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_EndBoundary(ILogonTrigger *iface, BSTR end)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    WCHAR *str = NULL;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(end));
+
+    if (end && !(str = wcsdup(end))) return E_OUTOFMEMORY;
+    free(This->end_boundary);
+    This->end_boundary = str;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_Enabled(ILogonTrigger *iface, VARIANT_BOOL *enabled)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, enabled);
+
+    if (!enabled) return E_POINTER;
+
+    *enabled = This->enabled ? VARIANT_TRUE : VARIANT_FALSE;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_Enabled(ILogonTrigger *iface, VARIANT_BOOL enabled)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%x)\n", This, enabled);
+
+    This->enabled = !!enabled;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_Delay(ILogonTrigger *iface, BSTR *pDelay)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, pDelay);
+
+    if (!pDelay) return E_POINTER;
+
+    if (!This->delay) *pDelay = NULL;
+    else if (!(*pDelay = SysAllocString(This->delay))) return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_Delay(ILogonTrigger *iface, BSTR delay)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    WCHAR *str = NULL;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(delay));
+
+    if (delay && !(str = wcsdup(delay))) return E_OUTOFMEMORY;
+    free(This->delay);
+    This->delay = str;
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_get_UserId(ILogonTrigger *iface, BSTR *pUser)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+
+    TRACE("(%p)->(%p)\n", This, pUser);
+
+    if (!pUser) return E_POINTER;
+
+    if (!This->user_id) *pUser = NULL;
+    else if (!(*pUser = SysAllocString(This->user_id))) return E_OUTOFMEMORY;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI LogonTrigger_put_UserId(ILogonTrigger *iface, BSTR user)
+{
+    LogonTrigger *This = impl_from_ILogonTrigger(iface);
+    WCHAR *str = NULL;
+
+    TRACE("(%p)->(%s)\n", This, debugstr_w(user));
+
+    if (user && !(str = wcsdup(user))) return E_OUTOFMEMORY;
+    free(This->user_id);
+    This->user_id = str;
+    return S_OK;
+}
+
+static const ILogonTriggerVtbl LogonTrigger_vtbl = {
+    LogonTrigger_QueryInterface,
+    LogonTrigger_AddRef,
+    LogonTrigger_Release,
+    LogonTrigger_GetTypeInfoCount,
+    LogonTrigger_GetTypeInfo,
+    LogonTrigger_GetIDsOfNames,
+    LogonTrigger_Invoke,
+    LogonTrigger_get_Type,
+    LogonTrigger_get_Id,
+    LogonTrigger_put_Id,
+    LogonTrigger_get_Repetition,
+    LogonTrigger_put_Repetition,
+    LogonTrigger_get_ExecutionTimeLimit,
+    LogonTrigger_put_ExecutionTimeLimit,
+    LogonTrigger_get_StartBoundary,
+    LogonTrigger_put_StartBoundary,
+    LogonTrigger_get_EndBoundary,
+    LogonTrigger_put_EndBoundary,
+    LogonTrigger_get_Enabled,
+    LogonTrigger_put_Enabled,
+    LogonTrigger_get_Delay,
+    LogonTrigger_put_Delay,
+    LogonTrigger_get_UserId,
+    LogonTrigger_put_UserId
+};
+
+static HRESULT LogonTrigger_create(ITrigger **trigger)
+{
+    LogonTrigger *logon_trigger;
+
+    logon_trigger = malloc(sizeof(*logon_trigger));
+    if (!logon_trigger)
+        return E_OUTOFMEMORY;
+
+    logon_trigger->ILogonTrigger_iface.lpVtbl = &LogonTrigger_vtbl;
+    logon_trigger->ref = 1;
+    logon_trigger->enabled = TRUE;
+    logon_trigger->user_id = NULL;
+    logon_trigger->id = NULL;
+    logon_trigger->execution_time_limit = NULL;
+    logon_trigger->start_boundary = NULL;
+    logon_trigger->end_boundary = NULL;
+    logon_trigger->delay = NULL;
+
+    *trigger = (ITrigger*)&logon_trigger->ILogonTrigger_iface;
+    return S_OK;
+}
+
 typedef struct
 {
     ITriggerCollection ITriggerCollection_iface;
@@ -936,6 +1302,8 @@ static HRESULT WINAPI TriggerCollection_Create(ITriggerCollection *iface, TASK_T
         return DailyTrigger_create(trigger);
     case TASK_TRIGGER_REGISTRATION:
         return RegistrationTrigger_create(trigger);
+    case TASK_TRIGGER_LOGON:
+        return LogonTrigger_create(trigger);
     default:
         FIXME("Unimplemented type %d\n", type);
         return E_NOTIMPL;
diff --git a/dlls/taskschd/tests/scheduler.c b/dlls/taskschd/tests/scheduler.c
index 7715ef0845de..025522f322ca 100644
--- a/dlls/taskschd/tests/scheduler.c
+++ b/dlls/taskschd/tests/scheduler.c
@@ -1426,6 +1426,103 @@ static void test_registration_trigger(ITrigger *trigger)
     IRegistrationTrigger_Release(reg_trigger);
 }
 
+static void test_logon_trigger(ITrigger *trigger)
+{
+    ILogonTrigger *log_trigger;
+    HRESULT hr;
+    TASK_TRIGGER_TYPE2 type;
+    BSTR id, exc_time_limit, start_boundary, end_boundary, delay, user_id;
+    VARIANT_BOOL enabled;
+    static WCHAR id_str[] = L"Trigger_id_test";
+    static WCHAR exc_time_limit_str[] = L"Time_limit_test";
+    static WCHAR start_boundary_str[] = L"2023-01-01T00:00:00";
+    static WCHAR end_boundary_str[] = L"2026-01-01T01:00:00";
+    static WCHAR delay_str[] = L"10H";
+    static WCHAR user_id_str[] = L"User_id_test";
+
+    hr = ITrigger_QueryInterface(trigger, &IID_ILogonTrigger, (void**)&log_trigger);
+    ok(hr == S_OK, "Could not get IRegistrationTrigger iface: %08lx\n", hr);
+
+    hr = ILogonTrigger_get_Type(log_trigger, &type);
+    ok(hr == S_OK, "get_Type failed: %08lx\n", hr);
+    ok(type == TASK_TRIGGER_LOGON, "got %u\n", type);
+
+    hr = ILogonTrigger_get_Id(log_trigger, &id);
+    ok(hr == S_OK, "get_Id failed: %08lx\n", hr);
+    ok(id == NULL, "test ok!\n");
+
+    hr = ILogonTrigger_put_Id(log_trigger, id_str);
+    ok(hr == S_OK, "put_Id failed: %08lx\n", hr);
+    hr = ILogonTrigger_get_Id(log_trigger, &id);
+    ok(hr == S_OK, "get_Id failed: %08lx\n", hr);
+    ok(!lstrcmpW(id, id_str), "got %s\n", wine_dbgstr_w(id));
+
+    hr = ILogonTrigger_get_ExecutionTimeLimit(log_trigger, &exc_time_limit);
+    ok(hr == S_OK, "get_ExecutionTimeLimit failed: %08lx\n", hr);
+    ok(exc_time_limit == NULL, "test ok!\n");
+
+    hr = ILogonTrigger_put_ExecutionTimeLimit(log_trigger, exc_time_limit_str);
+    ok(hr == S_OK, "put_ExecutionTimeLimit failed: %08lx\n", hr);
+    hr = ILogonTrigger_get_ExecutionTimeLimit(log_trigger, &exc_time_limit);
+    ok(hr == S_OK, "get_ExecutionTimeLimit failed: %08lx\n", hr);
+    ok(!lstrcmpW(exc_time_limit, exc_time_limit_str), "got %s\n", wine_dbgstr_w(exc_time_limit));
+
+    hr = ILogonTrigger_get_StartBoundary(log_trigger, &start_boundary);
+    ok(hr == S_OK, "get_StartBoundary failed: %08lx\n", hr);
+    ok(start_boundary == NULL, "test ok!\n");
+
+    hr = ILogonTrigger_put_StartBoundary(log_trigger, start_boundary_str);
+    ok(hr == S_OK, "put_StartBoundary failed: %08lx\n", hr);
+    hr = ILogonTrigger_get_StartBoundary(log_trigger, &start_boundary);
+    ok(hr == S_OK, "get_StartBoundary failed: %08lx\n", hr);
+    ok(!lstrcmpW(start_boundary, start_boundary_str), "got %s\n", wine_dbgstr_w(start_boundary));
+
+    hr = ILogonTrigger_get_EndBoundary(log_trigger, &end_boundary);
+    ok(hr == S_OK, "get_EndBoundary failed: %08lx\n", hr);
+    ok(end_boundary == NULL, "test ok!\n");
+
+    hr = ILogonTrigger_put_EndBoundary(log_trigger, end_boundary_str);
+    ok(hr == S_OK, "put_EndBoundary failed: %08lx\n", hr);
+    hr = ILogonTrigger_get_EndBoundary(log_trigger, &end_boundary);
+    ok(hr == S_OK, "get_EndBoundary failed: %08lx\n", hr);
+    ok(!lstrcmpW(end_boundary, end_boundary_str), "got %s\n", wine_dbgstr_w(end_boundary));
+
+    enabled = VARIANT_FALSE;
+    hr = ILogonTrigger_get_Enabled(log_trigger, &enabled);
+    ok(hr == S_OK, "get_Enabled failed: %08lx\n", hr);
+    ok(enabled == VARIANT_TRUE, "got %d\n", enabled);
+
+    hr = ILogonTrigger_put_Enabled(log_trigger, VARIANT_FALSE);
+    ok(hr == S_OK, "put_Enabled failed: %08lx\n", hr);
+
+    enabled = VARIANT_TRUE;
+    hr = ILogonTrigger_get_Enabled(log_trigger, &enabled);
+    ok(hr == S_OK, "get_Enabled failed: %08lx\n", hr);
+    ok(enabled == VARIANT_FALSE, "got %d\n", enabled);
+
+    hr = ILogonTrigger_get_Delay(log_trigger, &delay);
+    ok(hr == S_OK, "get_Delay failed: %08lx\n", hr);
+    ok(delay == NULL, "test ok!\n");
+
+    hr = ILogonTrigger_put_Delay(log_trigger, delay_str);
+    ok(hr == S_OK, "put_Delay failed: %08lx\n", hr);
+    hr = ILogonTrigger_get_Delay(log_trigger, &delay);
+    ok(hr == S_OK, "get_EndBoundary failed: %08lx\n", hr);
+    ok(!lstrcmpW(delay, delay_str), "got %s\n", wine_dbgstr_w(delay));
+
+    hr = ILogonTrigger_get_UserId(log_trigger, &user_id);
+    ok(hr == S_OK, "get_UserId failed: %08lx\n", hr);
+    ok(user_id == NULL, "test ok!\n");
+
+    hr = ILogonTrigger_put_UserId(log_trigger, user_id_str);
+    ok(hr == S_OK, "put_UserId failed: %08lx\n", hr);
+    hr = ILogonTrigger_get_UserId(log_trigger, &user_id);
+    ok(hr == S_OK, "get_UserId failed: %08lx\n", hr);
+    ok(!lstrcmpW(user_id, user_id_str), "got %s\n", wine_dbgstr_w(user_id));
+
+    ILogonTrigger_Release(log_trigger);
+}
+
 static void create_action(ITaskDefinition *taskdef)
 {
     static WCHAR task1_exe[] = L"task1.exe";
@@ -1850,6 +1947,12 @@ static void test_TaskDefinition(void)
     ok(trigger != NULL, "trigger = NULL\n");
     test_registration_trigger(trigger);
     ITrigger_Release(trigger);
+
+    hr = ITriggerCollection_Create(trigger_col, TASK_TRIGGER_LOGON, &trigger);
+    ok(hr == S_OK, "Create failed: %08lx\n", hr);
+    ok(trigger != NULL, "trigger = NULL\n");
+    test_logon_trigger(trigger);
+    ITrigger_Release(trigger);
     ITriggerCollection_Release(trigger_col);
 
     hr = ITaskDefinition_get_Triggers(taskdef, &trigger_col2);
diff --git a/dlls/ucrtbase/atexit.c b/dlls/ucrtbase/atexit.c
index 142de9efa0c3..7b5032020cae 100644
--- a/dlls/ucrtbase/atexit.c
+++ b/dlls/ucrtbase/atexit.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/ucrtbase/printf.c b/dlls/ucrtbase/printf.c
index 4483fb936eac..0f881692ad65 100644
--- a/dlls/ucrtbase/printf.c
+++ b/dlls/ucrtbase/printf.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/ucrtbase/tests/printf.c b/dlls/ucrtbase/tests/printf.c
index 16dd4f3727b8..5b841047f0b4 100644
--- a/dlls/ucrtbase/tests/printf.c
+++ b/dlls/ucrtbase/tests/printf.c
@@ -29,6 +29,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
+#include "winternl.h"
 
 #include "wine/test.h"
 
@@ -533,14 +534,19 @@ static void test_printf_legacy_wide(void)
 {
     const wchar_t wide[] = {'A','B','C','D',0};
     const char narrow[] = "abcd";
+    const UNICODE_STRING wide_str = { 8, sizeof(wide), (wchar_t *)wide };
+    const ANSI_STRING narrow_str = { 4, sizeof(narrow), (char *)narrow };
     const char out[] = "abcd ABCD";
     /* The legacy wide flag doesn't affect narrow printfs, so the same
      * format should behave the same both with and without the flag. */
     const char narrow_fmt[] = "%s %ls";
+    const char narrow_str_fmt[] = "%hZ %Z";
     /* The standard behaviour is to use the same format as for the narrow
      * case, while the legacy case has got a different meaning for %s. */
     const wchar_t std_wide_fmt[] = {'%','s',' ','%','l','s',0};
     const wchar_t legacy_wide_fmt[] = {'%','h','s',' ','%','s',0};
+    const wchar_t std_wide_str_fmt[] = {'%','h','Z',' ','%','Z',0};
+    const wchar_t legacy_wide_str_fmt[] = {'%','Z',' ','%','l','Z',0};
     char buffer[20];
     wchar_t wbuffer[20];
 
@@ -549,10 +555,25 @@ static void test_printf_legacy_wide(void)
     vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, buffer, sizeof(buffer), narrow_fmt, narrow, wide);
     ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
 
+    vsprintf_wrapper(0, buffer, sizeof(buffer), narrow_str_fmt, &narrow_str, &wide_str);
+    ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
+    vsprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, buffer,
+            sizeof(buffer), narrow_str_fmt, &narrow_str, &wide_str);
+    ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
+
     vswprintf_wrapper(0, wbuffer, sizeof(wbuffer), std_wide_fmt, narrow, wide);
     WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
     ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
-    vswprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, wbuffer, sizeof(wbuffer), legacy_wide_fmt, narrow, wide);
+    vswprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, wbuffer,
+            sizeof(wbuffer), legacy_wide_fmt, narrow, wide);
+    WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
+    ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
+
+    vswprintf_wrapper(0, wbuffer, sizeof(wbuffer), std_wide_str_fmt, &narrow_str, &wide_str);
+    WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
+    ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
+    vswprintf_wrapper(_CRT_INTERNAL_PRINTF_LEGACY_WIDE_SPECIFIERS, wbuffer,
+            sizeof(wbuffer), legacy_wide_str_fmt, &narrow_str, &wide_str);
     WideCharToMultiByte(CP_ACP, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
     ok(!strcmp(buffer, out), "buffer wrong, got=%s\n", buffer);
 }
diff --git a/dlls/urlmon/Makefile.in b/dlls/urlmon/Makefile.in
index 42120e41fd0c..68007428facd 100644
--- a/dlls/urlmon/Makefile.in
+++ b/dlls/urlmon/Makefile.in
@@ -1,6 +1,6 @@
 MODULE    = urlmon.dll
 IMPORTLIB = urlmon
-IMPORTS   = uuid ole32 oleaut32 shell32 rpcrt4 shlwapi wininet user32 advapi32
+IMPORTS   = uuid ole32 oleaut32 shell32 rpcrt4 shlwapi wininet user32 advapi32 iertutil
 DELAYIMPORTS = advpack
 
 VER_PRODUCTVERSION = 6,0,2800,1485
diff --git a/dlls/urlmon/uri.c b/dlls/urlmon/uri.c
index cb5266518d1b..8051c61a01ee 100644
--- a/dlls/urlmon/uri.c
+++ b/dlls/urlmon/uri.c
@@ -17,206 +17,22 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include <limits.h>
-#include <wchar.h>
-
 #include "urlmon_main.h"
 #include "wine/debug.h"
 
 #define NO_SHLWAPI_REG
 #include "shlwapi.h"
 
-#include "strsafe.h"
-#include "winternl.h"
-#include "inaddr.h"
-#include "in6addr.h"
-#include "ip2string.h"
-
-#define URI_DISPLAY_NO_ABSOLUTE_URI         0x1
-#define URI_DISPLAY_NO_DEFAULT_PORT_AUTH    0x2
-
-#define ALLOW_NULL_TERM_SCHEME          0x01
-#define ALLOW_NULL_TERM_USER_NAME       0x02
-#define ALLOW_NULL_TERM_PASSWORD        0x04
-#define ALLOW_BRACKETLESS_IP_LITERAL    0x08
-#define SKIP_IP_FUTURE_CHECK            0x10
-#define IGNORE_PORT_DELIMITER           0x20
-
-#define RAW_URI_FORCE_PORT_DISP     0x1
-#define RAW_URI_CONVERT_TO_DOS_PATH 0x2
-
 #define COMBINE_URI_FORCE_FLAG_USE  0x1
 
 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
 
-static const IID IID_IUriObj = {0x4b364760,0x9f51,0x11df,{0x98,0x1c,0x08,0x00,0x20,0x0c,0x9a,0x66}};
-
-typedef struct {
-    IUri                IUri_iface;
-    IUriBuilderFactory  IUriBuilderFactory_iface;
-    IPersistStream      IPersistStream_iface;
-    IMarshal            IMarshal_iface;
-
-    LONG ref;
-
-    BSTR            raw_uri;
-
-    /* Information about the canonicalized URI's buffer. */
-    WCHAR           *canon_uri;
-    DWORD           canon_size;
-    DWORD           canon_len;
-    BOOL            display_modifiers;
-    DWORD           create_flags;
-
-    INT             scheme_start;
-    DWORD           scheme_len;
-    URL_SCHEME      scheme_type;
-
-    INT             userinfo_start;
-    DWORD           userinfo_len;
-    INT             userinfo_split;
-
-    INT             host_start;
-    DWORD           host_len;
-    Uri_HOST_TYPE   host_type;
-
-    INT             port_offset;
-    DWORD           port;
-    BOOL            has_port;
-
-    INT             authority_start;
-    DWORD           authority_len;
-
-    INT             domain_offset;
-
-    INT             path_start;
-    DWORD           path_len;
-    INT             extension_offset;
-
-    INT             query_start;
-    DWORD           query_len;
-
-    INT             fragment_start;
-    DWORD           fragment_len;
-} Uri;
-
-typedef struct {
-    IUriBuilder IUriBuilder_iface;
-    LONG ref;
-
-    Uri *uri;
-    DWORD modified_props;
-
-    WCHAR   *fragment;
-    DWORD   fragment_len;
-
-    WCHAR   *host;
-    DWORD   host_len;
-
-    WCHAR   *password;
-    DWORD   password_len;
-
-    WCHAR   *path;
-    DWORD   path_len;
-
-    BOOL    has_port;
-    DWORD   port;
-
-    WCHAR   *query;
-    DWORD   query_len;
-
-    WCHAR   *scheme;
-    DWORD   scheme_len;
-
-    WCHAR   *username;
-    DWORD   username_len;
-} UriBuilder;
-
-typedef struct {
-    BSTR            uri;
-
-    BOOL            is_relative;
-    BOOL            is_opaque;
-    BOOL            has_implicit_scheme;
-    BOOL            has_implicit_ip;
-    UINT            implicit_ipv4;
-    BOOL            must_have_path;
-
-    const WCHAR     *scheme;
-    DWORD           scheme_len;
-    URL_SCHEME      scheme_type;
-
-    const WCHAR     *username;
-    DWORD           username_len;
-
-    const WCHAR     *password;
-    DWORD           password_len;
-
-    const WCHAR     *host;
-    DWORD           host_len;
-    Uri_HOST_TYPE   host_type;
-
-    IN6_ADDR        ipv6_address;
-
-    BOOL            has_port;
-    const WCHAR     *port;
-    DWORD           port_len;
-    DWORD           port_value;
-
-    const WCHAR     *path;
-    DWORD           path_len;
-
-    const WCHAR     *query;
-    DWORD           query_len;
-
-    const WCHAR     *fragment;
-    DWORD           fragment_len;
-} parse_data;
-
-static const CHAR hexDigits[] = "0123456789ABCDEF";
-
-/* List of scheme types/scheme names that are recognized by the IUri interface as of IE 7. */
-static const struct {
-    URL_SCHEME  scheme;
-    WCHAR       scheme_name[16];
-} recognized_schemes[] = {
-    {URL_SCHEME_FTP,            L"ftp"},
-    {URL_SCHEME_HTTP,           L"http"},
-    {URL_SCHEME_GOPHER,         L"gopher"},
-    {URL_SCHEME_MAILTO,         L"mailto"},
-    {URL_SCHEME_NEWS,           L"news"},
-    {URL_SCHEME_NNTP,           L"nntp"},
-    {URL_SCHEME_TELNET,         L"telnet"},
-    {URL_SCHEME_WAIS,           L"wais"},
-    {URL_SCHEME_FILE,           L"file"},
-    {URL_SCHEME_MK,             L"mk"},
-    {URL_SCHEME_HTTPS,          L"https"},
-    {URL_SCHEME_SHELL,          L"shell"},
-    {URL_SCHEME_SNEWS,          L"snews"},
-    {URL_SCHEME_LOCAL,          L"local"},
-    {URL_SCHEME_JAVASCRIPT,     L"javascript"},
-    {URL_SCHEME_VBSCRIPT,       L"vbscript"},
-    {URL_SCHEME_ABOUT,          L"about"},
-    {URL_SCHEME_RES,            L"res"},
-    {URL_SCHEME_MSSHELLROOTED,  L"ms-shell-rooted"},
-    {URL_SCHEME_MSSHELLIDLIST,  L"ms-shell-idlist"},
-    {URL_SCHEME_MSHELP,         L"hcp"},
-    {URL_SCHEME_WILDCARD,       L"*"}
-};
-
-/* List of default ports Windows recognizes. */
-static const struct {
-    URL_SCHEME  scheme;
-    USHORT      port;
-} default_ports[] = {
-    {URL_SCHEME_FTP,    21},
-    {URL_SCHEME_HTTP,   80},
-    {URL_SCHEME_GOPHER, 70},
-    {URL_SCHEME_NNTP,   119},
-    {URL_SCHEME_TELNET, 23},
-    {URL_SCHEME_WAIS,   210},
-    {URL_SCHEME_HTTPS,  443},
-};
+const WCHAR * WINAPI wine_get_canonicalized_uri(IUri *uri);
+HRESULT WINAPI PrivateCoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD dwCombineFlags,
+                                            IUri **ppCombinedUri, DWORD_PTR dwReserved);
+HRESULT WINAPI PrivateCoInternetParseIUri(IUri *pIUri, PARSEACTION ParseAction, DWORD dwFlags,
+                                          LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult,
+                                          DWORD_PTR dwReserved);
 
 /* List of 3-character top level domain names Windows seems to recognize.
  * There might be more, but, these are the only ones I've found so far.
@@ -233,237 +49,11 @@ static const struct {
     {L"org"}
 };
 
-static Uri *get_uri_obj(IUri *uri)
-{
-    Uri *ret;
-    HRESULT hres;
-
-    hres = IUri_QueryInterface(uri, &IID_IUriObj, (void**)&ret);
-    return SUCCEEDED(hres) ? ret : NULL;
-}
-
-static inline BOOL is_alpha(WCHAR val) {
-    return ((val >= 'a' && val <= 'z') || (val >= 'A' && val <= 'Z'));
-}
-
-static inline BOOL is_num(WCHAR val) {
-    return (val >= '0' && val <= '9');
-}
-
-static inline BOOL is_drive_path(const WCHAR *str) {
-    return (is_alpha(str[0]) && (str[1] == ':' || str[1] == '|'));
-}
-
-static inline BOOL is_unc_path(const WCHAR *str) {
-    return (str[0] == '\\' && str[1] == '\\');
-}
-
-static inline BOOL is_forbidden_dos_path_char(WCHAR val) {
-    return (val == '>' || val == '<' || val == '\"');
-}
-
-/* A URI is implicitly a file path if it begins with
- * a drive letter (e.g. X:) or starts with "\\" (UNC path).
- */
-static inline BOOL is_implicit_file_path(const WCHAR *str) {
-    return (is_unc_path(str) || (is_alpha(str[0]) && str[1] == ':'));
-}
-
-/* Checks if the URI is a hierarchical URI. A hierarchical
- * URI is one that has "//" after the scheme.
- */
-static BOOL check_hierarchical(const WCHAR **ptr) {
-    const WCHAR *start = *ptr;
-
-    if(**ptr != '/')
-        return FALSE;
-
-    ++(*ptr);
-    if(**ptr != '/') {
-        *ptr = start;
-        return FALSE;
-    }
-
-    ++(*ptr);
-    return TRUE;
-}
-
-/* unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~" */
-static inline BOOL is_unreserved(WCHAR val) {
-    return (is_alpha(val) || is_num(val) || val == '-' || val == '.' ||
-            val == '_' || val == '~');
-}
-
-/* sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
- *               / "*" / "+" / "," / ";" / "="
- */
-static inline BOOL is_subdelim(WCHAR val) {
-    return (val == '!' || val == '$' || val == '&' ||
-            val == '\'' || val == '(' || val == ')' ||
-            val == '*' || val == '+' || val == ',' ||
-            val == ';' || val == '=');
-}
-
-/* gen-delims  = ":" / "/" / "?" / "#" / "[" / "]" / "@" */
-static inline BOOL is_gendelim(WCHAR val) {
-    return (val == ':' || val == '/' || val == '?' ||
-            val == '#' || val == '[' || val == ']' ||
-            val == '@');
-}
-
-/* Characters that delimit the end of the authority
- * section of a URI. Sometimes a '\\' is considered
- * an authority delimiter.
- */
-static inline BOOL is_auth_delim(WCHAR val, BOOL acceptSlash) {
-    return (val == '#' || val == '/' || val == '?' ||
-            val == '\0' || (acceptSlash && val == '\\'));
-}
-
-/* reserved = gen-delims / sub-delims */
-static inline BOOL is_reserved(WCHAR val) {
-    return (is_subdelim(val) || is_gendelim(val));
-}
-
-static inline BOOL is_hexdigit(WCHAR val) {
-    return ((val >= 'a' && val <= 'f') ||
-            (val >= 'A' && val <= 'F') ||
-            (val >= '0' && val <= '9'));
-}
-
-static inline BOOL is_path_delim(URL_SCHEME scheme, WCHAR val) {
-    return (!val || (val == '#' && scheme != URL_SCHEME_FILE) || val == '?');
-}
-
-static inline BOOL is_slash(WCHAR c)
-{
-    return c == '/' || c == '\\';
-}
-
 static inline BOOL is_ascii(WCHAR c)
 {
     return c < 0x80;
 }
 
-static BOOL is_default_port(URL_SCHEME scheme, DWORD port) {
-    DWORD i;
-
-    for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
-        if(default_ports[i].scheme == scheme && default_ports[i].port)
-            return TRUE;
-    }
-
-    return FALSE;
-}
-
-/* List of schemes types Windows seems to expect to be hierarchical. */
-static inline BOOL is_hierarchical_scheme(URL_SCHEME type) {
-    return(type == URL_SCHEME_HTTP || type == URL_SCHEME_FTP ||
-           type == URL_SCHEME_GOPHER || type == URL_SCHEME_NNTP ||
-           type == URL_SCHEME_TELNET || type == URL_SCHEME_WAIS ||
-           type == URL_SCHEME_FILE || type == URL_SCHEME_HTTPS ||
-           type == URL_SCHEME_RES);
-}
-
-/* Checks if 'flags' contains an invalid combination of Uri_CREATE flags. */
-static inline BOOL has_invalid_flag_combination(DWORD flags) {
-    return((flags & Uri_CREATE_DECODE_EXTRA_INFO && flags & Uri_CREATE_NO_DECODE_EXTRA_INFO) ||
-           (flags & Uri_CREATE_CANONICALIZE && flags & Uri_CREATE_NO_CANONICALIZE) ||
-           (flags & Uri_CREATE_CRACK_UNKNOWN_SCHEMES && flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES) ||
-           (flags & Uri_CREATE_PRE_PROCESS_HTML_URI && flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI) ||
-           (flags & Uri_CREATE_IE_SETTINGS && flags & Uri_CREATE_NO_IE_SETTINGS));
-}
-
-/* Applies each default Uri_CREATE flags to 'flags' if it
- * doesn't cause a flag conflict.
- */
-static void apply_default_flags(DWORD *flags) {
-    if(!(*flags & Uri_CREATE_NO_CANONICALIZE))
-        *flags |= Uri_CREATE_CANONICALIZE;
-    if(!(*flags & Uri_CREATE_NO_DECODE_EXTRA_INFO))
-        *flags |= Uri_CREATE_DECODE_EXTRA_INFO;
-    if(!(*flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES))
-        *flags |= Uri_CREATE_CRACK_UNKNOWN_SCHEMES;
-    if(!(*flags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI))
-        *flags |= Uri_CREATE_PRE_PROCESS_HTML_URI;
-    if(!(*flags & Uri_CREATE_IE_SETTINGS))
-        *flags |= Uri_CREATE_NO_IE_SETTINGS;
-}
-
-/* Determines if the URI is hierarchical using the information already parsed into
- * data and using the current location of parsing in the URI string.
- *
- * Windows considers a URI hierarchical if one of the following is true:
- *  A.) It's a wildcard scheme.
- *  B.) It's an implicit file scheme.
- *  C.) It's a known hierarchical scheme and it has two '\\' after the scheme name.
- *      (the '\\' will be converted into "//" during canonicalization).
- *  D.) "//" appears after the scheme name (or at the beginning if no scheme is given).
- */
-static inline BOOL is_hierarchical_uri(const WCHAR **ptr, const parse_data *data) {
-    const WCHAR *start = *ptr;
-
-    if(data->scheme_type == URL_SCHEME_WILDCARD)
-        return TRUE;
-    else if(data->scheme_type == URL_SCHEME_FILE && data->has_implicit_scheme)
-        return TRUE;
-    else if(is_hierarchical_scheme(data->scheme_type) && (*ptr)[0] == '\\' && (*ptr)[1] == '\\') {
-        *ptr += 2;
-        return TRUE;
-    } else if(data->scheme_type != URL_SCHEME_MAILTO && check_hierarchical(ptr))
-        return TRUE;
-
-    *ptr = start;
-    return FALSE;
-}
-
-/* Taken from dlls/jscript/lex.c */
-static int hex_to_int(WCHAR val) {
-    if(val >= '0' && val <= '9')
-        return val - '0';
-    else if(val >= 'a' && val <= 'f')
-        return val - 'a' + 10;
-    else if(val >= 'A' && val <= 'F')
-        return val - 'A' + 10;
-
-    return -1;
-}
-
-/* Helper function for converting a percent encoded string
- * representation of a WCHAR value into its actual WCHAR value. If
- * the two characters following the '%' aren't valid hex values then
- * this function returns the NULL character.
- *
- * E.g.
- *  "%2E" will result in '.' being returned by this function.
- */
-static WCHAR decode_pct_val(const WCHAR *ptr) {
-    WCHAR ret = '\0';
-
-    if(*ptr == '%' && is_hexdigit(*(ptr + 1)) && is_hexdigit(*(ptr + 2))) {
-        INT a = hex_to_int(*(ptr + 1));
-        INT b = hex_to_int(*(ptr + 2));
-
-        ret = a << 4;
-        ret += b;
-    }
-
-    return ret;
-}
-
-/* Helper function for percent encoding a given character
- * and storing the encoded value into a given buffer (dest).
- *
- * It's up to the calling function to ensure that there is
- * at least enough space in 'dest' for the percent encoded
- * value to be stored (so dest + 3 spaces available).
- */
-static inline void pct_encode_val(WCHAR val, WCHAR *dest) {
-    dest[0] = '%';
-    dest[1] = hexDigits[(val >> 4) & 0xf];
-    dest[2] = hexDigits[val & 0xf];
-}
-
 /* Attempts to parse the domain name from the host.
  *
  * This function also includes the Top-level Domain (TLD) name
@@ -587,6422 +177,151 @@ void find_domain_name(const WCHAR *host, DWORD host_len,
                                         (host+host_len)-(host+*domain_start)));
 }
 
-/* Removes the dot segments from a hierarchical URIs path component. This
- * function performs the removal in place.
- *
- * This function returns the new length of the path string.
+/***********************************************************************
+ *           CoInternetCombineIUri (urlmon.@)
  */
-static DWORD remove_dot_segments(WCHAR *path, DWORD path_len) {
-    WCHAR *out = path;
-    const WCHAR *in = out;
-    const WCHAR *end = out + path_len;
-    DWORD len;
-
-    while(in < end) {
-        /* Move the first path segment in the input buffer to the end of
-         * the output buffer, and any subsequent characters up to, including
-         * the next "/" character (if any) or the end of the input buffer.
-         */
-        while(in < end && !is_slash(*in))
-            *out++ = *in++;
-        if(in == end)
-            break;
-        *out++ = *in++;
-
-        while(in < end) {
-            if(*in != '.')
-                break;
-
-            /* Handle ending "/." */
-            if(in + 1 == end) {
-                ++in;
-                break;
-            }
+HRESULT WINAPI CoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD dwCombineFlags,
+                                     IUri **ppCombinedUri, DWORD_PTR dwReserved)
+{
+    HRESULT hr;
+    IInternetProtocolInfo *info;
+    const WCHAR *relative_canon_uri, *base_canon_uri;
 
-            /* Handle "/./" */
-            if(is_slash(in[1])) {
-                in += 2;
-                continue;
-            }
+    TRACE("(%p %p %lx %p %Ix)\n", pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
 
-            /* If we don't have "/../" or ending "/.." */
-            if(in[1] != '.' || (in + 2 != end && !is_slash(in[2])))
-                break;
+    if(!ppCombinedUri)
+        return E_INVALIDARG;
 
-            /* Find the slash preceding out pointer and move out pointer to it */
-            if(out > path+1 && is_slash(*--out))
-                --out;
-            while(out > path && !is_slash(*(--out)));
-            if(is_slash(*out))
-                ++out;
-            in += 2;
-            if(in != end)
-                ++in;
-        }
+    if(!pBaseUri || !pRelativeUri) {
+        *ppCombinedUri = NULL;
+        return E_INVALIDARG;
     }
 
-    len = out - path;
-    TRACE("(%p %ld): Path after dot segments removed %s len=%ld\n", path, path_len,
-        debugstr_wn(path, len), len);
-    return len;
-}
+    relative_canon_uri = wine_get_canonicalized_uri(pRelativeUri);
+    base_canon_uri = wine_get_canonicalized_uri(pBaseUri);
+    if(!relative_canon_uri || !base_canon_uri) {
+        *ppCombinedUri = NULL;
+        FIXME("(%p %p %lx %p %Ix) Unknown IUri types not supported yet.\n",
+            pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
+        return E_NOTIMPL;
+    }
 
-/* Attempts to find the file extension in a given path. */
-static INT find_file_extension(const WCHAR *path, DWORD path_len) {
-    const WCHAR *end;
+    info = get_protocol_info(base_canon_uri);
+    if(info) {
+        WCHAR result[INTERNET_MAX_URL_LENGTH+1];
+        DWORD result_len = 0;
 
-    for(end = path+path_len-1; end >= path && *end != '/' && *end != '\\'; --end) {
-        if(*end == '.')
-            return end-path;
+        hr = IInternetProtocolInfo_CombineUrl(info, base_canon_uri, relative_canon_uri, dwCombineFlags,
+                                              result, INTERNET_MAX_URL_LENGTH+1, &result_len, 0);
+        IInternetProtocolInfo_Release(info);
+        if(SUCCEEDED(hr)) {
+            hr = CreateUri(result, Uri_CREATE_ALLOW_RELATIVE, 0, ppCombinedUri);
+            if(SUCCEEDED(hr))
+                return hr;
+        }
     }
 
-    return -1;
+    return PrivateCoInternetCombineIUri(pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, 0);
 }
 
-/* Removes all the leading and trailing white spaces or
- * control characters from the URI and removes all control
- * characters inside of the URI string.
+/***********************************************************************
+ *           CoInternetCombineUrlEx (urlmon.@)
  */
-static BSTR pre_process_uri(LPCWSTR uri) {
-    const WCHAR *start, *end, *ptr;
-    WCHAR *ptr2;
-    DWORD len;
-    BSTR ret;
-
-    start = uri;
-    /* Skip leading controls and whitespace. */
-    while(*start && (iswcntrl(*start) || iswspace(*start))) ++start;
+HRESULT WINAPI CoInternetCombineUrlEx(IUri *pBaseUri, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags,
+                                      IUri **ppCombinedUri, DWORD_PTR dwReserved)
+{
+    IUri *relative;
+    const WCHAR *base_canon_uri;
+    HRESULT hr;
+    IInternetProtocolInfo *info;
 
-    /* URI consisted only of control/whitespace. */
-    if(!*start)
-        return SysAllocStringLen(NULL, 0);
+    TRACE("(%p %s %lx %p %Ix)\n", pBaseUri, debugstr_w(pwzRelativeUrl), dwCombineFlags,
+        ppCombinedUri, dwReserved);
 
-    end = start + lstrlenW(start);
-    while(--end > start && (iswcntrl(*end) || iswspace(*end)));
+    if(!ppCombinedUri)
+        return E_POINTER;
 
-    len = ++end - start;
-    for(ptr = start; ptr < end; ptr++) {
-        if(iswcntrl(*ptr))
-            len--;
+    if(!pwzRelativeUrl) {
+        *ppCombinedUri = NULL;
+        return E_UNEXPECTED;
     }
 
-    ret = SysAllocStringLen(NULL, len);
-    if(!ret)
-        return NULL;
-
-    for(ptr = start, ptr2=ret; ptr < end; ptr++) {
-        if(!iswcntrl(*ptr))
-            *ptr2++ = *ptr;
+    if(!pBaseUri) {
+        *ppCombinedUri = NULL;
+        return E_INVALIDARG;
     }
 
-    return ret;
-}
-
-/* Converts an IPv4 address in numerical form into its fully qualified
- * string form. This function returns the number of characters written
- * to 'dest'. If 'dest' is NULL this function will return the number of
- * characters that would have been written.
- *
- * It's up to the caller to ensure there's enough space in 'dest' for the
- * address.
- */
-static DWORD ui2ipv4(WCHAR *dest, UINT address) {
-    DWORD ret = 0;
-    UCHAR digits[4];
-
-    digits[0] = (address >> 24) & 0xff;
-    digits[1] = (address >> 16) & 0xff;
-    digits[2] = (address >> 8) & 0xff;
-    digits[3] = address & 0xff;
-
-    if(!dest) {
-        WCHAR tmp[16];
-        ret = swprintf(tmp, ARRAY_SIZE(tmp), L"%u.%u.%u.%u", digits[0], digits[1], digits[2], digits[3]);
-    } else
-        ret = swprintf(dest, 16, L"%u.%u.%u.%u", digits[0], digits[1], digits[2], digits[3]);
-
-    return ret;
-}
-
-static DWORD ui2str(WCHAR *dest, UINT value) {
-    DWORD ret = 0;
-
-    if(!dest) {
-        WCHAR tmp[11];
-        ret = swprintf(tmp, ARRAY_SIZE(tmp), L"%u", value);
-    } else
-        ret = swprintf(dest, 11, L"%u", value);
-
-    return ret;
-}
-
-/* Checks if the characters pointed to by 'ptr' are
- * a percent encoded data octet.
- *
- * pct-encoded = "%" HEXDIG HEXDIG
- */
-static BOOL check_pct_encoded(const WCHAR **ptr) {
-    const WCHAR *start = *ptr;
+    base_canon_uri = wine_get_canonicalized_uri(pBaseUri);
+    if(!base_canon_uri) {
+        *ppCombinedUri = NULL;
+        FIXME("(%p %s %lx %p %Ix) Unknown IUri's not supported yet.\n", pBaseUri, debugstr_w(pwzRelativeUrl),
+            dwCombineFlags, ppCombinedUri, dwReserved);
+        return E_NOTIMPL;
+    }
 
-    if(**ptr != '%')
-        return FALSE;
+    info = get_protocol_info(base_canon_uri);
+    if(info) {
+        WCHAR result[INTERNET_MAX_URL_LENGTH+1];
+        DWORD result_len = 0;
 
-    ++(*ptr);
-    if(!is_hexdigit(**ptr)) {
-        *ptr = start;
-        return FALSE;
+        hr = IInternetProtocolInfo_CombineUrl(info, base_canon_uri, pwzRelativeUrl, dwCombineFlags,
+                                              result, INTERNET_MAX_URL_LENGTH+1, &result_len, 0);
+        IInternetProtocolInfo_Release(info);
+        if(SUCCEEDED(hr)) {
+            hr = CreateUri(result, Uri_CREATE_ALLOW_RELATIVE, 0, ppCombinedUri);
+            if(SUCCEEDED(hr))
+                return hr;
+        }
     }
 
-    ++(*ptr);
-    if(!is_hexdigit(**ptr)) {
-        *ptr = start;
-        return FALSE;
+    hr = CreateUri(pwzRelativeUrl, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &relative);
+    if(FAILED(hr)) {
+        *ppCombinedUri = NULL;
+        return hr;
     }
 
-    ++(*ptr);
-    return TRUE;
-}
-
-/* dec-octet   = DIGIT                 ; 0-9
- *             / %x31-39 DIGIT         ; 10-99
- *             / "1" 2DIGIT            ; 100-199
- *             / "2" %x30-34 DIGIT     ; 200-249
- *             / "25" %x30-35          ; 250-255
- */
-static BOOL check_dec_octet(const WCHAR **ptr) {
-    const WCHAR *c1, *c2, *c3;
-
-    c1 = *ptr;
-    /* A dec-octet must be at least 1 digit long. */
-    if(*c1 < '0' || *c1 > '9')
-        return FALSE;
-
-    ++(*ptr);
-
-    c2 = *ptr;
-    /* Since the 1-digit requirement was met, it doesn't
-     * matter if this is a DIGIT value, it's considered a
-     * dec-octet.
-     */
-    if(*c2 < '0' || *c2 > '9')
-        return TRUE;
-
-    ++(*ptr);
-
-    c3 = *ptr;
-    /* Same explanation as above. */
-    if(*c3 < '0' || *c3 > '9')
-        return TRUE;
-
-    /* Anything > 255 isn't a valid IP dec-octet. */
-    if(*c1 >= '2' && *c2 >= '5' && *c3 >= '5') {
-        *ptr = c1;
-        return FALSE;
-    }
+    hr = PrivateCoInternetCombineIUri(pBaseUri, relative, dwCombineFlags, ppCombinedUri, COMBINE_URI_FORCE_FLAG_USE);
 
-    ++(*ptr);
-    return TRUE;
+    IUri_Release(relative);
+    return hr;
 }
 
-/* Checks if there is an implicit IPv4 address in the host component of the URI.
- * The max value of an implicit IPv4 address is UINT_MAX.
- *
- *  Ex:
- *      "234567" would be considered an implicit IPv4 address.
+/***********************************************************************
+ *           CoInternetParseIUri (urlmon.@)
  */
-static BOOL check_implicit_ipv4(const WCHAR **ptr, UINT *val) {
-    const WCHAR *start = *ptr;
-    ULONGLONG ret = 0;
-    *val = 0;
-
-    while(is_num(**ptr)) {
-        ret = ret*10 + (**ptr - '0');
-
-        if(ret > UINT_MAX) {
-            *ptr = start;
-            return FALSE;
-        }
-        ++(*ptr);
-    }
-
-    if(*ptr == start)
-        return FALSE;
+HRESULT WINAPI CoInternetParseIUri(IUri *pIUri, PARSEACTION ParseAction, DWORD dwFlags,
+                                   LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult,
+                                   DWORD_PTR dwReserved)
+{
+    HRESULT hr;
+    const WCHAR *canon_uri;
+    IInternetProtocolInfo *info;
 
-    *val = ret;
-    return TRUE;
-}
+    TRACE("(%p %d %lx %p %ld %p %Ix)\n", pIUri, ParseAction, dwFlags, pwzResult,
+        cchResult, pcchResult, dwReserved);
 
-/* Checks if the string contains an IPv4 address.
- *
- * This function has a strict mode or a non-strict mode of operation
- * When 'strict' is set to FALSE this function will return TRUE if
- * the string contains at least 'dec-octet "." dec-octet' since partial
- * IPv4 addresses will be normalized out into full IPv4 addresses. When
- * 'strict' is set this function expects there to be a full IPv4 address.
- *
- * IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
- */
-static BOOL check_ipv4address(const WCHAR **ptr, BOOL strict) {
-    const WCHAR *start = *ptr;
+    if(!pcchResult)
+        return E_POINTER;
 
-    if(!check_dec_octet(ptr)) {
-        *ptr = start;
-        return FALSE;
+    if(!pwzResult || !pIUri) {
+        *pcchResult = 0;
+        return E_INVALIDARG;
     }
 
-    if(**ptr != '.') {
-        *ptr = start;
-        return FALSE;
+    if(!(canon_uri = wine_get_canonicalized_uri(pIUri))) {
+        *pcchResult = 0;
+        FIXME("(%p %d %lx %p %ld %p %Ix) Unknown IUri's not supported for this action.\n",
+            pIUri, ParseAction, dwFlags, pwzResult, cchResult, pcchResult, dwReserved);
+        return E_NOTIMPL;
     }
 
-    ++(*ptr);
-    if(!check_dec_octet(ptr)) {
-        *ptr = start;
-        return FALSE;
-    }
-
-    if(**ptr != '.') {
-        if(strict) {
-            *ptr = start;
-            return FALSE;
-        } else
-            return TRUE;
-    }
-
-    ++(*ptr);
-    if(!check_dec_octet(ptr)) {
-        *ptr = start;
-        return FALSE;
-    }
-
-    if(**ptr != '.') {
-        if(strict) {
-            *ptr = start;
-            return FALSE;
-        } else
-            return TRUE;
-    }
-
-    ++(*ptr);
-    if(!check_dec_octet(ptr)) {
-        *ptr = start;
-        return FALSE;
-    }
-
-    /* Found a four digit ip address. */
-    return TRUE;
-}
-/* Tries to parse the scheme name of the URI.
- *
- * scheme = ALPHA *(ALPHA | NUM | '+' | '-' | '.') as defined by RFC 3896.
- * NOTE: Windows accepts a number as the first character of a scheme.
- */
-static BOOL parse_scheme_name(const WCHAR **ptr, parse_data *data, DWORD extras) {
-    const WCHAR *start = *ptr;
-
-    data->scheme = NULL;
-    data->scheme_len = 0;
-
-    while(**ptr) {
-        if(**ptr == '*' && *ptr == start) {
-            /* Might have found a wildcard scheme. If it is the next
-             * char has to be a ':' for it to be a valid URI
-             */
-            ++(*ptr);
-            break;
-        } else if(!is_num(**ptr) && !is_alpha(**ptr) && **ptr != '+' &&
-           **ptr != '-' && **ptr != '.')
-            break;
-
-        (*ptr)++;
-    }
-
-    if(*ptr == start)
-        return FALSE;
-
-    /* Schemes must end with a ':' */
-    if(**ptr != ':' && !((extras & ALLOW_NULL_TERM_SCHEME) && !**ptr)) {
-        *ptr = start;
-        return FALSE;
-    }
-
-    data->scheme = start;
-    data->scheme_len = *ptr - start;
-
-    ++(*ptr);
-    return TRUE;
-}
-
-/* Tries to deduce the corresponding URL_SCHEME for the given URI. Stores
- * the deduced URL_SCHEME in data->scheme_type.
- */
-static BOOL parse_scheme_type(parse_data *data) {
-    /* If there's scheme data then see if it's a recognized scheme. */
-    if(data->scheme && data->scheme_len) {
-        DWORD i;
-
-        for(i = 0; i < ARRAY_SIZE(recognized_schemes); ++i) {
-            if(lstrlenW(recognized_schemes[i].scheme_name) == data->scheme_len) {
-                /* Has to be a case insensitive compare. */
-                if(!StrCmpNIW(recognized_schemes[i].scheme_name, data->scheme, data->scheme_len)) {
-                    data->scheme_type = recognized_schemes[i].scheme;
-                    return TRUE;
-                }
-            }
-        }
-
-        /* If we get here it means it's not a recognized scheme. */
-        data->scheme_type = URL_SCHEME_UNKNOWN;
-        return TRUE;
-    } else if(data->is_relative) {
-        /* Relative URI's have no scheme. */
-        data->scheme_type = URL_SCHEME_UNKNOWN;
-        return TRUE;
-    } else {
-        /* Should never reach here! what happened... */
-        FIXME("(%p): Unable to determine scheme type for URI %s\n", data, debugstr_w(data->uri));
-        return FALSE;
-    }
-}
-
-/* Tries to parse (or deduce) the scheme_name of a URI. If it can't
- * parse a scheme from the URI it will try to deduce the scheme_name and scheme_type
- * using the flags specified in 'flags' (if any). Flags that affect how this function
- * operates are the Uri_CREATE_ALLOW_* flags.
- *
- * All parsed/deduced information will be stored in 'data' when the function returns.
- *
- * Returns TRUE if it was able to successfully parse the information.
- */
-static BOOL parse_scheme(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
-    /* First check to see if the uri could implicitly be a file path. */
-    if(is_implicit_file_path(*ptr)) {
-        if(flags & Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME) {
-            data->scheme = L"file";
-            data->scheme_len = lstrlenW(L"file");
-            data->has_implicit_scheme = TRUE;
-
-            TRACE("(%p %p %lx): URI is an implicit file path.\n", ptr, data, flags);
-        } else {
-            /* Windows does not consider anything that can implicitly be a file
-             * path to be a valid URI if the ALLOW_IMPLICIT_FILE_SCHEME flag is not set...
-             */
-            TRACE("(%p %p %lx): URI is implicitly a file path, but, the ALLOW_IMPLICIT_FILE_SCHEME flag wasn't set.\n",
-                    ptr, data, flags);
-            return FALSE;
-        }
-    } else if(!parse_scheme_name(ptr, data, extras)) {
-        /* No scheme was found, this means it could be:
-         *      a) an implicit Wildcard scheme
-         *      b) a relative URI
-         *      c) an invalid URI.
-         */
-        if(flags & Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME) {
-            data->scheme = L"*";
-            data->scheme_len = lstrlenW(L"*");
-            data->has_implicit_scheme = TRUE;
-
-            TRACE("(%p %p %lx): URI is an implicit wildcard scheme.\n", ptr, data, flags);
-        } else if (flags & Uri_CREATE_ALLOW_RELATIVE) {
-            data->is_relative = TRUE;
-            TRACE("(%p %p %lx): URI is relative.\n", ptr, data, flags);
-        } else {
-            TRACE("(%p %p %lx): Malformed URI found. Unable to deduce scheme name.\n", ptr, data, flags);
-            return FALSE;
-        }
-    }
-
-    if(!data->is_relative)
-        TRACE("(%p %p %lx): Found scheme=%s scheme_len=%ld\n", ptr, data, flags,
-                debugstr_wn(data->scheme, data->scheme_len), data->scheme_len);
-
-    if(!parse_scheme_type(data))
-        return FALSE;
-
-    TRACE("(%p %p %lx): Assigned %d as the URL_SCHEME.\n", ptr, data, flags, data->scheme_type);
-    return TRUE;
-}
-
-static BOOL parse_username(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
-    data->username = *ptr;
-
-    while(**ptr != ':' && **ptr != '@') {
-        if(**ptr == '%') {
-            if(!check_pct_encoded(ptr)) {
-                if(data->scheme_type != URL_SCHEME_UNKNOWN) {
-                    *ptr = data->username;
-                    data->username = NULL;
-                    return FALSE;
-                }
-            } else
-                continue;
-        } else if(extras & ALLOW_NULL_TERM_USER_NAME && !**ptr)
-            break;
-        else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
-            *ptr = data->username;
-            data->username = NULL;
-            return FALSE;
-        }
-
-        ++(*ptr);
-    }
-
-    data->username_len = *ptr - data->username;
-    return TRUE;
-}
-
-static BOOL parse_password(const WCHAR **ptr, parse_data *data, DWORD flags, DWORD extras) {
-    data->password = *ptr;
-
-    while(**ptr != '@') {
-        if(**ptr == '%') {
-            if(!check_pct_encoded(ptr)) {
-                if(data->scheme_type != URL_SCHEME_UNKNOWN) {
-                    *ptr = data->password;
-                    data->password = NULL;
-                    return FALSE;
-                }
-            } else
-                continue;
-        } else if(extras & ALLOW_NULL_TERM_PASSWORD && !**ptr)
-            break;
-        else if(is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
-            *ptr = data->password;
-            data->password = NULL;
-            return FALSE;
-        }
-
-        ++(*ptr);
-    }
-
-    data->password_len = *ptr - data->password;
-    return TRUE;
-}
-
-/* Parses the userinfo part of the URI (if it exists). The userinfo field of
- * a URI can consist of "username:password@", or just "username@".
- *
- * RFC def:
- * userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
- *
- * NOTES:
- *  1)  If there is more than one ':' in the userinfo part of the URI Windows
- *      uses the first occurrence of ':' to delimit the username and password
- *      components.
- *
- *      ex:
- *          ftp://user:pass:word@winehq.org
- *
- *      would yield "user" as the username and "pass:word" as the password.
- *
- *  2)  Windows allows any character to appear in the "userinfo" part of
- *      a URI, as long as it's not an authority delimiter character set.
- */
-static void parse_userinfo(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    const WCHAR *start = *ptr;
-
-    if(!parse_username(ptr, data, flags, 0)) {
-        TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
-        return;
-    }
-
-    if(**ptr == ':') {
-        ++(*ptr);
-        if(!parse_password(ptr, data, flags, 0)) {
-            *ptr = start;
-            data->username = NULL;
-            data->username_len = 0;
-            TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
-            return;
-        }
-    }
-
-    if(**ptr != '@') {
-        *ptr = start;
-        data->username = NULL;
-        data->username_len = 0;
-        data->password = NULL;
-        data->password_len = 0;
-
-        TRACE("(%p %p %lx): URI contained no userinfo.\n", ptr, data, flags);
-        return;
-    }
-
-    if(data->username)
-        TRACE("(%p %p %lx): Found username %s len=%ld.\n", ptr, data, flags,
-            debugstr_wn(data->username, data->username_len), data->username_len);
-
-    if(data->password)
-        TRACE("(%p %p %lx): Found password %s len=%ld.\n", ptr, data, flags,
-            debugstr_wn(data->password, data->password_len), data->password_len);
-
-    ++(*ptr);
-}
-
-/* Attempts to parse a port from the URI.
- *
- * NOTES:
- *  Windows seems to have a cap on what the maximum value
- *  for a port can be. The max value is USHORT_MAX.
- *
- * port = *DIGIT
- */
-static BOOL parse_port(const WCHAR **ptr, parse_data *data) {
-    UINT port = 0;
-    data->port = *ptr;
-
-    while(!is_auth_delim(**ptr, data->scheme_type != URL_SCHEME_UNKNOWN)) {
-        if(!is_num(**ptr)) {
-            *ptr = data->port;
-            data->port = NULL;
-            return FALSE;
-        }
-
-        port = port*10 + (**ptr-'0');
-
-        if(port > USHRT_MAX) {
-            *ptr = data->port;
-            data->port = NULL;
-            return FALSE;
-        }
-
-        ++(*ptr);
-    }
-
-    data->has_port = TRUE;
-    data->port_value = port;
-    data->port_len = *ptr - data->port;
-
-    TRACE("(%p %p): Found port %s len=%ld value=%lu\n", ptr, data,
-        debugstr_wn(data->port, data->port_len), data->port_len, data->port_value);
-    return TRUE;
-}
-
-/* Attempts to parse a IPv4 address from the URI.
- *
- * NOTES:
- *  Windows normalizes IPv4 addresses, This means there are three
- *  possibilities for the URI to contain an IPv4 address.
- *      1)  A well formed address (ex. 192.2.2.2).
- *      2)  A partially formed address. For example "192.0" would
- *          normalize to "192.0.0.0" during canonicalization.
- *      3)  An implicit IPv4 address. For example "256" would
- *          normalize to "0.0.1.0" during canonicalization. Also
- *          note that the maximum value for an implicit IP address
- *          is UINT_MAX, if the value in the URI exceeds this then
- *          it is not considered an IPv4 address.
- */
-static BOOL parse_ipv4address(const WCHAR **ptr, parse_data *data) {
-    const BOOL is_unknown = data->scheme_type == URL_SCHEME_UNKNOWN;
-    data->host = *ptr;
-
-    if(!check_ipv4address(ptr, FALSE)) {
-        if(!check_implicit_ipv4(ptr, &data->implicit_ipv4)) {
-            TRACE("(%p %p): URI didn't contain anything looking like an IPv4 address.\n", ptr, data);
-            *ptr = data->host;
-            data->host = NULL;
-            return FALSE;
-        } else
-            data->has_implicit_ip = TRUE;
-    }
-
-    data->host_len = *ptr - data->host;
-    data->host_type = Uri_HOST_IPV4;
-
-    /* Check if what we found is the only part of the host name (if it isn't
-     * we don't have an IPv4 address).
-     */
-    if(**ptr == ':') {
-        ++(*ptr);
-        if(!parse_port(ptr, data)) {
-            *ptr = data->host;
-            data->host = NULL;
-            return FALSE;
-        }
-    } else if(!is_auth_delim(**ptr, !is_unknown)) {
-        /* Found more data which belongs to the host, so this isn't an IPv4. */
-        *ptr = data->host;
-        data->host = NULL;
-        data->has_implicit_ip = FALSE;
-        return FALSE;
-    }
-
-    TRACE("(%p %p): IPv4 address found. host=%s host_len=%ld host_type=%d\n",
-        ptr, data, debugstr_wn(data->host, data->host_len),
-        data->host_len, data->host_type);
-    return TRUE;
-}
-
-/* Attempts to parse the reg-name from the URI.
- *
- * Because of the way Windows handles ':' this function also
- * handles parsing the port.
- *
- * reg-name = *( unreserved / pct-encoded / sub-delims )
- *
- * NOTE:
- *  Windows allows everything, but, the characters in "auth_delims" and ':'
- *  to appear in a reg-name, unless it's an unknown scheme type then ':' is
- *  allowed to appear (even if a valid port isn't after it).
- *
- *  Windows doesn't like host names which start with '[' and end with ']'
- *  and don't contain a valid IP literal address in between them.
- *
- *  On Windows if a '[' is encountered in the host name the ':' no longer
- *  counts as a delimiter until you reach the next ']' or an "authority delimiter".
- *
- *  A reg-name CAN be empty.
- */
-static BOOL parse_reg_name(const WCHAR **ptr, parse_data *data, DWORD extras) {
-    const BOOL has_start_bracket = **ptr == '[';
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-    const BOOL is_res = data->scheme_type == URL_SCHEME_RES;
-    BOOL inside_brackets = has_start_bracket;
-
-    /* res URIs don't have ports. */
-    BOOL ignore_col = (extras & IGNORE_PORT_DELIMITER) || is_res;
-
-    /* We have to be careful with file schemes. */
-    if(data->scheme_type == URL_SCHEME_FILE) {
-        /* This is because an implicit file scheme could be "C:\\test" and it
-         * would trick this function into thinking the host is "C", when after
-         * canonicalization the host would end up being an empty string. A drive
-         * path can also have a '|' instead of a ':' after the drive letter.
-         */
-        if(is_drive_path(*ptr)) {
-            /* Regular old drive paths have no host type (or host name). */
-            data->host_type = Uri_HOST_UNKNOWN;
-            data->host = *ptr;
-            data->host_len = 0;
-            return TRUE;
-        } else if(is_unc_path(*ptr))
-            /* Skip past the "\\" of a UNC path. */
-            *ptr += 2;
-    }
-
-    data->host = *ptr;
-
-    /* For res URIs, everything before the first '/' is
-     * considered the host.
-     */
-    while((!is_res && !is_auth_delim(**ptr, known_scheme)) ||
-          (is_res && **ptr && **ptr != '/')) {
-        if(**ptr == ':' && !ignore_col) {
-            /* We can ignore ':' if we are inside brackets.*/
-            if(!inside_brackets) {
-                const WCHAR *tmp = (*ptr)++;
-
-                /* Attempt to parse the port. */
-                if(!parse_port(ptr, data)) {
-                    /* Windows expects there to be a valid port for known scheme types. */
-                    if(data->scheme_type != URL_SCHEME_UNKNOWN) {
-                        *ptr = data->host;
-                        data->host = NULL;
-                        TRACE("(%p %p %lx): Expected valid port\n", ptr, data, extras);
-                        return FALSE;
-                    } else
-                        /* Windows gives up on trying to parse a port when it
-                         * encounters an invalid port.
-                         */
-                        ignore_col = TRUE;
-                } else {
-                    data->host_len = tmp - data->host;
-                    break;
-                }
-            }
-        } else if(**ptr == '%' && (known_scheme && !is_res)) {
-            /* Has to be a legit % encoded value. */
-            if(!check_pct_encoded(ptr)) {
-                *ptr = data->host;
-                data->host = NULL;
-                return FALSE;
-            } else
-                continue;
-        } else if(is_res && is_forbidden_dos_path_char(**ptr)) {
-            *ptr = data->host;
-            data->host = NULL;
-            return FALSE;
-        } else if(**ptr == ']')
-            inside_brackets = FALSE;
-        else if(**ptr == '[')
-            inside_brackets = TRUE;
-
-        ++(*ptr);
-    }
-
-    if(has_start_bracket) {
-        /* Make sure the last character of the host wasn't a ']'. */
-        if(*(*ptr-1) == ']') {
-            TRACE("(%p %p %lx): Expected an IP literal inside of the host\n", ptr, data, extras);
-            *ptr = data->host;
-            data->host = NULL;
-            return FALSE;
-        }
-    }
-
-    /* Don't overwrite our length if we found a port earlier. */
-    if(!data->port)
-        data->host_len = *ptr - data->host;
-
-    /* If the host is empty, then it's an unknown host type. */
-    if(data->host_len == 0 || is_res)
-        data->host_type = Uri_HOST_UNKNOWN;
-    else {
-        unsigned int i;
-
-        data->host_type = Uri_HOST_DNS;
-
-        for(i = 0; i < data->host_len; i++) {
-            if(!is_ascii(data->host[i])) {
-                data->host_type = Uri_HOST_IDN;
-                break;
-            }
-        }
-    }
-
-    TRACE("(%p %p %lx): Parsed reg-name. host=%s len=%ld type=%d\n", ptr, data, extras,
-          debugstr_wn(data->host, data->host_len), data->host_len, data->host_type);
-    return TRUE;
-}
-
-/* Attempts to parse an IPv6 address out of the URI.
- *
- * IPv6address =                               6( h16 ":" ) ls32
- *                /                       "::" 5( h16 ":" ) ls32
- *                / [               h16 ] "::" 4( h16 ":" ) ls32
- *                / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
- *                / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
- *                / [ *3( h16 ":" ) h16 ] "::"    h16 ":"   ls32
- *                / [ *4( h16 ":" ) h16 ] "::"              ls32
- *                / [ *5( h16 ":" ) h16 ] "::"              h16
- *                / [ *6( h16 ":" ) h16 ] "::"
- *
- * ls32        = ( h16 ":" h16 ) / IPv4address
- *             ; least-significant 32 bits of address.
- *
- * h16         = 1*4HEXDIG
- *             ; 16 bits of address represented in hexadecimal.
- */
-static BOOL parse_ipv6address(const WCHAR **ptr, parse_data *data) {
-    const WCHAR *terminator;
-
-    if(RtlIpv6StringToAddressW(*ptr, &terminator, &data->ipv6_address))
-        return FALSE;
-    if(*terminator != ']' && !is_auth_delim(*terminator, data->scheme_type != URL_SCHEME_UNKNOWN))
-        return FALSE;
-
-    *ptr = terminator;
-    data->host_type = Uri_HOST_IPV6;
-    return TRUE;
-}
-
-/*  IPvFuture  = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) */
-static BOOL parse_ipvfuture(const WCHAR **ptr, parse_data *data) {
-    const WCHAR *start = *ptr;
-
-    /* IPvFuture has to start with a 'v' or 'V'. */
-    if(**ptr != 'v' && **ptr != 'V')
-        return FALSE;
-
-    /* Following the v there must be at least 1 hex digit. */
-    ++(*ptr);
-    if(!is_hexdigit(**ptr)) {
-        *ptr = start;
-        return FALSE;
-    }
-
-    ++(*ptr);
-    while(is_hexdigit(**ptr))
-        ++(*ptr);
-
-    /* End of the hexdigit sequence must be a '.' */
-    if(**ptr != '.') {
-        *ptr = start;
-        return FALSE;
-    }
-
-    ++(*ptr);
-    if(!is_unreserved(**ptr) && !is_subdelim(**ptr) && **ptr != ':') {
-        *ptr = start;
-        return FALSE;
-    }
-
-    ++(*ptr);
-    while(is_unreserved(**ptr) || is_subdelim(**ptr) || **ptr == ':')
-        ++(*ptr);
-
-    data->host_type = Uri_HOST_UNKNOWN;
-
-    TRACE("(%p %p): Parsed IPvFuture address %s len=%d\n", ptr, data,
-          debugstr_wn(start, *ptr-start), (int)(*ptr-start));
-
-    return TRUE;
-}
-
-/* IP-literal = "[" ( IPv6address / IPvFuture  ) "]" */
-static BOOL parse_ip_literal(const WCHAR **ptr, parse_data *data, DWORD extras) {
-    data->host = *ptr;
-
-    if(**ptr != '[' && !(extras & ALLOW_BRACKETLESS_IP_LITERAL)) {
-        data->host = NULL;
-        return FALSE;
-    } else if(**ptr == '[')
-        ++(*ptr);
-
-    if(!parse_ipv6address(ptr, data)) {
-        if(extras & SKIP_IP_FUTURE_CHECK || !parse_ipvfuture(ptr, data)) {
-            *ptr = data->host;
-            data->host = NULL;
-            return FALSE;
-        }
-    }
-
-    if(**ptr != ']' && !(extras & ALLOW_BRACKETLESS_IP_LITERAL)) {
-        *ptr = data->host;
-        data->host = NULL;
-        return FALSE;
-    } else if(!**ptr && extras & ALLOW_BRACKETLESS_IP_LITERAL) {
-        /* The IP literal didn't contain brackets and was followed by
-         * a NULL terminator, so no reason to even check the port.
-         */
-        data->host_len = *ptr - data->host;
-        return TRUE;
-    }
-
-    ++(*ptr);
-    if(**ptr == ':') {
-        ++(*ptr);
-        /* If a valid port is not found, then let it trickle down to
-         * parse_reg_name.
-         */
-        if(!parse_port(ptr, data)) {
-            *ptr = data->host;
-            data->host = NULL;
-            return FALSE;
-        }
-    } else
-        data->host_len = *ptr - data->host;
-
-    return TRUE;
-}
-
-/* Parses the host information from the URI.
- *
- * host = IP-literal / IPv4address / reg-name
- */
-static BOOL parse_host(const WCHAR **ptr, parse_data *data, DWORD extras) {
-    if(!parse_ip_literal(ptr, data, extras)) {
-        if(!parse_ipv4address(ptr, data)) {
-            if(!parse_reg_name(ptr, data, extras)) {
-                TRACE("(%p %p %lx): Malformed URI, Unknown host type.\n",  ptr, data, extras);
-                return FALSE;
-            }
-        }
-    }
-
-    return TRUE;
-}
-
-/* Parses the authority information from the URI.
- *
- * authority   = [ userinfo "@" ] host [ ":" port ]
- */
-static BOOL parse_authority(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    parse_userinfo(ptr, data, flags);
-
-    /* Parsing the port will happen during one of the host parsing
-     * routines (if the URI has a port).
-     */
-    if(!parse_host(ptr, data, 0))
-        return FALSE;
-
-    return TRUE;
-}
-
-/* Attempts to parse the path information of a hierarchical URI. */
-static BOOL parse_path_hierarchical(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    const WCHAR *start = *ptr;
-    const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
-
-    if(is_path_delim(data->scheme_type, **ptr)) {
-        if(data->scheme_type == URL_SCHEME_WILDCARD && !data->must_have_path) {
-            data->path = NULL;
-            data->path_len = 0;
-        } else if(!(flags & Uri_CREATE_NO_CANONICALIZE)) {
-            /* If the path component is empty, then a '/' is added. */
-            data->path = L"/";
-            data->path_len = 1;
-        }
-    } else {
-        while(!is_path_delim(data->scheme_type, **ptr)) {
-            if(**ptr == '%' && data->scheme_type != URL_SCHEME_UNKNOWN && !is_file) {
-                if(!check_pct_encoded(ptr)) {
-                    *ptr = start;
-                    return FALSE;
-                } else
-                    continue;
-            } else if(is_forbidden_dos_path_char(**ptr) && is_file &&
-                      (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-                /* File schemes with USE_DOS_PATH set aren't allowed to have
-                 * a '<' or '>' or '\"' appear in them.
-                 */
-                *ptr = start;
-                return FALSE;
-            } else if(**ptr == '\\') {
-                /* Not allowed to have a backslash if NO_CANONICALIZE is set
-                 * and the scheme is known type (but not a file scheme).
-                 */
-                if(flags & Uri_CREATE_NO_CANONICALIZE) {
-                    if(data->scheme_type != URL_SCHEME_FILE &&
-                       data->scheme_type != URL_SCHEME_UNKNOWN) {
-                        *ptr = start;
-                        return FALSE;
-                    }
-                }
-            }
-
-            ++(*ptr);
-        }
-
-        /* The only time a URI doesn't have a path is when
-         * the NO_CANONICALIZE flag is set and the raw URI
-         * didn't contain one.
-         */
-        if(*ptr == start) {
-            data->path = NULL;
-            data->path_len = 0;
-        } else {
-            data->path = start;
-            data->path_len = *ptr - start;
-        }
-    }
-
-    if(data->path)
-        TRACE("(%p %p %lx): Parsed path %s len=%ld\n", ptr, data, flags,
-            debugstr_wn(data->path, data->path_len), data->path_len);
-    else
-        TRACE("(%p %p %lx): The URI contained no path\n", ptr, data, flags);
-
-    return TRUE;
-}
-
-/* Parses the path of an opaque URI (much less strict than the parser
- * for a hierarchical URI).
- *
- * NOTE:
- *  Windows allows invalid % encoded data to appear in opaque URI paths
- *  for unknown scheme types.
- *
- *  File schemes with USE_DOS_PATH set aren't allowed to have '<', '>', or '\"'
- *  appear in them.
- */
-static BOOL parse_path_opaque(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-    const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
-    const BOOL is_mailto = data->scheme_type == URL_SCHEME_MAILTO;
-
-    if (is_mailto && (*ptr)[0] == '/' && (*ptr)[1] == '/')
-    {
-        if ((*ptr)[2]) data->path = *ptr + 2;
-        else data->path = NULL;
-    }
-    else
-        data->path = *ptr;
-
-    while(!is_path_delim(data->scheme_type, **ptr)) {
-        if(**ptr == '%' && known_scheme) {
-            if(!check_pct_encoded(ptr)) {
-                *ptr = data->path;
-                data->path = NULL;
-                return FALSE;
-            } else
-                continue;
-        } else if(is_forbidden_dos_path_char(**ptr) && is_file &&
-                  (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-            *ptr = data->path;
-            data->path = NULL;
-            return FALSE;
-        }
-
-        ++(*ptr);
-    }
-
-    if (data->path) data->path_len = *ptr - data->path;
-    TRACE("(%p %p %lx): Parsed opaque URI path %s len=%ld\n", ptr, data, flags,
-        debugstr_wn(data->path, data->path_len), data->path_len);
-    return TRUE;
-}
-
-/* Determines how the URI should be parsed after the scheme information.
- *
- * If the scheme is followed by "//", then it is treated as a hierarchical URI
- * which then the authority and path information will be parsed out. Otherwise, the
- * URI will be treated as an opaque URI which the authority information is not parsed
- * out.
- *
- * RFC 3896 definition of hier-part:
- *
- * hier-part   = "//" authority path-abempty
- *                 / path-absolute
- *                 / path-rootless
- *                 / path-empty
- *
- * MSDN opaque URI definition:
- *  scheme ":" path [ "#" fragment ]
- *
- * NOTES:
- *  If the URI is of an unknown scheme type and has a "//" following the scheme then it
- *  is treated as a hierarchical URI, but, if the CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is
- *  set then it is considered an opaque URI regardless of what follows the scheme information
- *  (per MSDN documentation).
- */
-static BOOL parse_hierpart(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    const WCHAR *start = *ptr;
-
-    data->must_have_path = FALSE;
-
-    /* For javascript: URIs, simply set everything as a path */
-    if(data->scheme_type == URL_SCHEME_JAVASCRIPT) {
-        data->path = *ptr;
-        data->path_len = lstrlenW(*ptr);
-        data->is_opaque = TRUE;
-        *ptr += data->path_len;
-        return TRUE;
-    }
-
-    /* Checks if the authority information needs to be parsed. */
-    if(is_hierarchical_uri(ptr, data)) {
-        /* Only treat it as a hierarchical URI if the scheme_type is known or
-         * the Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES flag is not set.
-         */
-        if(data->scheme_type != URL_SCHEME_UNKNOWN ||
-           !(flags & Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES)) {
-            TRACE("(%p %p %lx): Treating URI as an hierarchical URI.\n", ptr, data, flags);
-            data->is_opaque = FALSE;
-
-            if(data->scheme_type == URL_SCHEME_WILDCARD && !data->has_implicit_scheme) {
-                if(**ptr == '/' && *(*ptr+1) == '/') {
-                    data->must_have_path = TRUE;
-                    *ptr += 2;
-                }
-            }
-
-            /* TODO: Handle hierarchical URI's, parse authority then parse the path. */
-            if(!parse_authority(ptr, data, flags))
-                return FALSE;
-
-            return parse_path_hierarchical(ptr, data, flags);
-        } else
-            /* Reset ptr to its starting position so opaque path parsing
-             * begins at the correct location.
-             */
-            *ptr = start;
-    }
-
-    /* If it reaches here, then the URI will be treated as an opaque
-     * URI.
-     */
-
-    TRACE("(%p %p %lx): Treating URI as an opaque URI.\n", ptr, data, flags);
-
-    data->is_opaque = TRUE;
-    if(!parse_path_opaque(ptr, data, flags))
-        return FALSE;
-
-    return TRUE;
-}
-
-/* Attempts to parse the query string from the URI.
- *
- * NOTES:
- *  If NO_DECODE_EXTRA_INFO flag is set, then invalid percent encoded
- *  data is allowed to appear in the query string. For unknown scheme types
- *  invalid percent encoded data is allowed to appear regardless.
- */
-static BOOL parse_query(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-
-    if(**ptr != '?') {
-        TRACE("(%p %p %lx): URI didn't contain a query string.\n", ptr, data, flags);
-        return TRUE;
-    }
-
-    data->query = *ptr;
-
-    ++(*ptr);
-    while(**ptr && **ptr != '#') {
-        if(**ptr == '%' && known_scheme &&
-           !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
-            if(!check_pct_encoded(ptr)) {
-                *ptr = data->query;
-                data->query = NULL;
-                return FALSE;
-            } else
-                continue;
-        }
-
-        ++(*ptr);
-    }
-
-    data->query_len = *ptr - data->query;
-
-    TRACE("(%p %p %lx): Parsed query string %s len=%ld\n", ptr, data, flags,
-        debugstr_wn(data->query, data->query_len), data->query_len);
-    return TRUE;
-}
-
-/* Attempts to parse the fragment from the URI.
- *
- * NOTES:
- *  If NO_DECODE_EXTRA_INFO flag is set, then invalid percent encoded
- *  data is allowed to appear in the query string. For unknown scheme types
- *  invalid percent encoded data is allowed to appear regardless.
- */
-static BOOL parse_fragment(const WCHAR **ptr, parse_data *data, DWORD flags) {
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-
-    if(**ptr != '#') {
-        TRACE("(%p %p %lx): URI didn't contain a fragment.\n", ptr, data, flags);
-        return TRUE;
-    }
-
-    data->fragment = *ptr;
-
-    ++(*ptr);
-    while(**ptr) {
-        if(**ptr == '%' && known_scheme &&
-           !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
-            if(!check_pct_encoded(ptr)) {
-                *ptr = data->fragment;
-                data->fragment = NULL;
-                return FALSE;
-            } else
-                continue;
-        }
-
-        ++(*ptr);
-    }
-
-    data->fragment_len = *ptr - data->fragment;
-
-    TRACE("(%p %p %lx): Parsed fragment %s len=%ld\n", ptr, data, flags,
-        debugstr_wn(data->fragment, data->fragment_len), data->fragment_len);
-    return TRUE;
-}
-
-/* Parses and validates the components of the specified by data->uri
- * and stores the information it parses into 'data'.
- *
- * Returns TRUE if it successfully parsed the URI. False otherwise.
- */
-static BOOL parse_uri(parse_data *data, DWORD flags) {
-    const WCHAR *ptr;
-    const WCHAR **pptr;
-
-    ptr = data->uri;
-    pptr = &ptr;
-
-    TRACE("(%p %lx): BEGINNING TO PARSE URI %s.\n", data, flags, debugstr_w(data->uri));
-
-    if(!parse_scheme(pptr, data, flags, 0))
-        return FALSE;
-
-    if(!parse_hierpart(pptr, data, flags))
-        return FALSE;
-
-    if(!parse_query(pptr, data, flags))
-        return FALSE;
-
-    if(!parse_fragment(pptr, data, flags))
-        return FALSE;
-
-    TRACE("(%p %lx): FINISHED PARSING URI.\n", data, flags);
-    return TRUE;
-}
-
-static BOOL canonicalize_username(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    const WCHAR *ptr;
-
-    if(!data->username) {
-        uri->userinfo_start = -1;
-        return TRUE;
-    }
-
-    uri->userinfo_start = uri->canon_len;
-    for(ptr = data->username; ptr < data->username+data->username_len; ++ptr) {
-        if(*ptr == '%') {
-            /* Only decode % encoded values for known scheme types. */
-            if(data->scheme_type != URL_SCHEME_UNKNOWN) {
-                /* See if the value really needs decoding. */
-                WCHAR val = decode_pct_val(ptr);
-                if(is_unreserved(val)) {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = val;
-
-                    ++uri->canon_len;
-
-                    /* Move pass the hex characters. */
-                    ptr += 2;
-                    continue;
-                }
-            }
-        } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr) && *ptr != '\\') {
-            /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
-             * is NOT set.
-             */
-            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
-                if(!computeOnly)
-                    pct_encode_val(*ptr, uri->canon_uri + uri->canon_len);
-
-                uri->canon_len += 3;
-                continue;
-            }
-        }
-
-        if(!computeOnly)
-            /* Nothing special, so just copy the character over. */
-            uri->canon_uri[uri->canon_len] = *ptr;
-        ++uri->canon_len;
-    }
-
-    return TRUE;
-}
-
-static BOOL canonicalize_password(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    const WCHAR *ptr;
-
-    if(!data->password) {
-        uri->userinfo_split = -1;
-        return TRUE;
-    }
-
-    if(uri->userinfo_start == -1)
-        /* Has a password, but, doesn't have a username. */
-        uri->userinfo_start = uri->canon_len;
-
-    uri->userinfo_split = uri->canon_len - uri->userinfo_start;
-
-    /* Add the ':' to the userinfo component. */
-    if(!computeOnly)
-        uri->canon_uri[uri->canon_len] = ':';
-    ++uri->canon_len;
-
-    for(ptr = data->password; ptr < data->password+data->password_len; ++ptr) {
-        if(*ptr == '%') {
-            /* Only decode % encoded values for known scheme types. */
-            if(data->scheme_type != URL_SCHEME_UNKNOWN) {
-                /* See if the value really needs decoding. */
-                WCHAR val = decode_pct_val(ptr);
-                if(is_unreserved(val)) {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = val;
-
-                    ++uri->canon_len;
-
-                    /* Move pass the hex characters. */
-                    ptr += 2;
-                    continue;
-                }
-            }
-        } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr) && *ptr != '\\') {
-            /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
-             * is NOT set.
-             */
-            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
-                if(!computeOnly)
-                    pct_encode_val(*ptr, uri->canon_uri + uri->canon_len);
-
-                uri->canon_len += 3;
-                continue;
-            }
-        }
-
-        if(!computeOnly)
-            /* Nothing special, so just copy the character over. */
-            uri->canon_uri[uri->canon_len] = *ptr;
-        ++uri->canon_len;
-    }
-
-    return TRUE;
-}
-
-/* Canonicalizes the userinfo of the URI represented by the parse_data.
- *
- * Canonicalization of the userinfo is a simple process. If there are any percent
- * encoded characters that fall in the "unreserved" character set, they are decoded
- * to their actual value. If a character is not in the "unreserved" or "reserved" sets
- * then it is percent encoded. Other than that the characters are copied over without
- * change.
- */
-static BOOL canonicalize_userinfo(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    uri->userinfo_start = uri->userinfo_split = -1;
-    uri->userinfo_len = 0;
-
-    if(!data->username && !data->password)
-        /* URI doesn't have userinfo, so nothing to do here. */
-        return TRUE;
-
-    if(!canonicalize_username(data, uri, flags, computeOnly))
-        return FALSE;
-
-    if(!canonicalize_password(data, uri, flags, computeOnly))
-        return FALSE;
-
-    uri->userinfo_len = uri->canon_len - uri->userinfo_start;
-    if(!computeOnly)
-        TRACE("(%p %p %lx %d): Canonicalized userinfo, userinfo_start=%d, userinfo=%s, userinfo_split=%d userinfo_len=%ld.\n",
-                data, uri, flags, computeOnly, uri->userinfo_start, debugstr_wn(uri->canon_uri + uri->userinfo_start, uri->userinfo_len),
-                uri->userinfo_split, uri->userinfo_len);
-
-    /* Now insert the '@' after the userinfo. */
-    if(!computeOnly)
-        uri->canon_uri[uri->canon_len] = '@';
-    ++uri->canon_len;
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize a reg_name.
- *
- * Things that happen:
- *  1)  If Uri_CREATE_NO_CANONICALIZE flag is not set, then the reg_name is
- *      lower cased. Unless it's an unknown scheme type, which case it's
- *      no lower cased regardless.
- *
- *  2)  Unreserved % encoded characters are decoded for known
- *      scheme types.
- *
- *  3)  Forbidden characters are % encoded as long as
- *      Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS flag is not set and
- *      it isn't an unknown scheme type.
- *
- *  4)  If it's a file scheme and the host is "localhost" it's removed.
- *
- *  5)  If it's a file scheme and Uri_CREATE_FILE_USE_DOS_PATH is set,
- *      then the UNC path characters are added before the host name.
- */
-static BOOL canonicalize_reg_name(const parse_data *data, Uri *uri,
-                                  DWORD flags, BOOL computeOnly) {
-    const WCHAR *ptr;
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-
-    if(data->scheme_type == URL_SCHEME_FILE &&
-       data->host_len == lstrlenW(L"localhost")) {
-        if(!StrCmpNIW(data->host, L"localhost", data->host_len)) {
-            uri->host_start = -1;
-            uri->host_len = 0;
-            uri->host_type = Uri_HOST_UNKNOWN;
-            return TRUE;
-        }
-    }
-
-    if(data->scheme_type == URL_SCHEME_FILE && flags & Uri_CREATE_FILE_USE_DOS_PATH) {
-        if(!computeOnly) {
-            uri->canon_uri[uri->canon_len] = '\\';
-            uri->canon_uri[uri->canon_len+1] = '\\';
-        }
-        uri->canon_len += 2;
-        uri->authority_start = uri->canon_len;
-    }
-
-    uri->host_start = uri->canon_len;
-
-    for(ptr = data->host; ptr < data->host+data->host_len; ++ptr) {
-        if(*ptr == '%' && known_scheme) {
-            WCHAR val = decode_pct_val(ptr);
-            if(is_unreserved(val)) {
-                /* If NO_CANONICALIZE is not set, then windows lower cases the
-                 * decoded value.
-                 */
-                if(!(flags & Uri_CREATE_NO_CANONICALIZE) && iswupper(val)) {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = towlower(val);
-                } else {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = val;
-                }
-                ++uri->canon_len;
-
-                /* Skip past the % encoded character. */
-                ptr += 2;
-                continue;
-            } else {
-                /* Just copy the % over. */
-                if(!computeOnly)
-                    uri->canon_uri[uri->canon_len] = *ptr;
-                ++uri->canon_len;
-            }
-        } else if(*ptr == '\\') {
-            /* Only unknown scheme types could have made it here with a '\\' in the host name. */
-            if(!computeOnly)
-                uri->canon_uri[uri->canon_len] = *ptr;
-            ++uri->canon_len;
-        } else if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) && is_ascii(*ptr) &&
-                  !is_unreserved(*ptr) && !is_reserved(*ptr) && known_scheme) {
-            if(!computeOnly) {
-                pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
-
-                /* The percent encoded value gets lower cased also. */
-                if(!(flags & Uri_CREATE_NO_CANONICALIZE)) {
-                    uri->canon_uri[uri->canon_len+1] = towlower(uri->canon_uri[uri->canon_len+1]);
-                    uri->canon_uri[uri->canon_len+2] = towlower(uri->canon_uri[uri->canon_len+2]);
-                }
-            }
-
-            uri->canon_len += 3;
-        } else {
-            if(!computeOnly) {
-                if(!(flags & Uri_CREATE_NO_CANONICALIZE) && known_scheme)
-                    uri->canon_uri[uri->canon_len] = towlower(*ptr);
-                else
-                    uri->canon_uri[uri->canon_len] = *ptr;
-            }
-
-            ++uri->canon_len;
-        }
-    }
-
-    uri->host_len = uri->canon_len - uri->host_start;
-
-    if(!computeOnly)
-        TRACE("(%p %p %lx %d): Canonicalize reg_name=%s len=%ld\n", data, uri, flags,
-            computeOnly, debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
-            uri->host_len);
-
-    if(!computeOnly)
-        find_domain_name(uri->canon_uri+uri->host_start, uri->host_len,
-            &(uri->domain_offset));
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize an implicit IPv4 address. */
-static BOOL canonicalize_implicit_ipv4address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    uri->host_start = uri->canon_len;
-
-    TRACE("%u\n", data->implicit_ipv4);
-    /* For unknown scheme types Windows doesn't convert
-     * the value into an IP address, but it still considers
-     * it an IPv4 address.
-     */
-    if(data->scheme_type == URL_SCHEME_UNKNOWN) {
-        if(!computeOnly)
-            memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
-        uri->canon_len += data->host_len;
-    } else {
-        if(!computeOnly)
-            uri->canon_len += ui2ipv4(uri->canon_uri+uri->canon_len, data->implicit_ipv4);
-        else
-            uri->canon_len += ui2ipv4(NULL, data->implicit_ipv4);
-    }
-
-    uri->host_len = uri->canon_len - uri->host_start;
-    uri->host_type = Uri_HOST_IPV4;
-
-    if(!computeOnly)
-        TRACE("%p %p %lx %d): Canonicalized implicit IP address=%s len=%ld\n",
-            data, uri, flags, computeOnly,
-            debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
-            uri->host_len);
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize an IPv4 address.
- *
- * If the parse_data represents a URI that has an implicit IPv4 address
- * (ex. http://256/, this function will convert 256 into 0.0.1.0). If
- * the implicit IP address exceeds the value of UINT_MAX (maximum value
- * for an IPv4 address) it's canonicalized as if it were a reg-name.
- *
- * If the parse_data contains a partial or full IPv4 address it normalizes it.
- * A partial IPv4 address is something like "192.0" and would be normalized to
- * "192.0.0.0". With a full (or partial) IPv4 address like "192.002.01.003" would
- * be normalized to "192.2.1.3".
- *
- * NOTES:
- *  Windows ONLY normalizes IPv4 address for known scheme types (one that isn't
- *  URL_SCHEME_UNKNOWN). For unknown scheme types, it simply copies the data from
- *  the original URI into the canonicalized URI, but, it still recognizes URI's
- *  host type as HOST_IPV4.
- */
-static BOOL canonicalize_ipv4address(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    if(data->has_implicit_ip)
-        return canonicalize_implicit_ipv4address(data, uri, flags, computeOnly);
-    else {
-        uri->host_start = uri->canon_len;
-
-        /* Windows only normalizes for known scheme types. */
-        if(data->scheme_type != URL_SCHEME_UNKNOWN) {
-            /* parse_data contains a partial or full IPv4 address, so normalize it. */
-            DWORD i, octetDigitCount = 0, octetCount = 0;
-            BOOL octetHasDigit = FALSE;
-
-            for(i = 0; i < data->host_len; ++i) {
-                if(data->host[i] == '0' && !octetHasDigit) {
-                    /* Can ignore leading zeros if:
-                     *  1) It isn't the last digit of the octet.
-                     *  2) i+1 != data->host_len
-                     *  3) i+1 != '.'
-                     */
-                    if(octetDigitCount == 2 ||
-                       i+1 == data->host_len ||
-                       data->host[i+1] == '.') {
-                        if(!computeOnly)
-                            uri->canon_uri[uri->canon_len] = data->host[i];
-                        ++uri->canon_len;
-                        TRACE("Adding zero\n");
-                    }
-                } else if(data->host[i] == '.') {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = data->host[i];
-                    ++uri->canon_len;
-
-                    octetDigitCount = 0;
-                    octetHasDigit = FALSE;
-                    ++octetCount;
-                } else {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = data->host[i];
-                    ++uri->canon_len;
-
-                    ++octetDigitCount;
-                    octetHasDigit = TRUE;
-                }
-            }
-
-            /* Make sure the canonicalized IP address has 4 dec-octets.
-             * If doesn't add "0" ones until there is 4;
-             */
-            for( ; octetCount < 3; ++octetCount) {
-                if(!computeOnly) {
-                    uri->canon_uri[uri->canon_len] = '.';
-                    uri->canon_uri[uri->canon_len+1] = '0';
-                }
-
-                uri->canon_len += 2;
-            }
-        } else {
-            /* Windows doesn't normalize addresses in unknown schemes. */
-            if(!computeOnly)
-                memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
-            uri->canon_len += data->host_len;
-        }
-
-        uri->host_len = uri->canon_len - uri->host_start;
-        if(!computeOnly)
-            TRACE("(%p %p %lx %d): Canonicalized IPv4 address, ip=%s len=%ld\n",
-                data, uri, flags, computeOnly,
-                debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
-                uri->host_len);
-    }
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize the IPv6 address of the URI.
- *
- * Multiple things happen during the canonicalization of an IPv6 address:
- *  1)  Any leading zero's in a h16 component are removed.
- *      Ex: [0001:0022::] -> [1:22::]
- *
- *  2)  The longest sequence of zero h16 components are compressed
- *      into a "::" (elision). If there's a tie, the first is chosen.
- *
- *      Ex: [0:0:0:0:1:6:7:8]   -> [::1:6:7:8]
- *          [0:0:0:0:1:2::]     -> [::1:2:0:0]
- *          [0:0:1:2:0:0:7:8]   -> [::1:2:0:0:7:8]
- *
- *  3)  If an IPv4 address is attached to the IPv6 address, it's
- *      also normalized.
- *      Ex: [::001.002.022.000] -> [::1.2.22.0]
- *
- *  4)  If an elision is present, but, only represents one h16 component
- *      it's expanded.
- *
- *      Ex: [1::2:3:4:5:6:7] -> [1:0:2:3:4:5:6:7]
- *
- *  5)  If the IPv6 address contains an IPv4 address and there exists
- *      at least 1 non-zero h16 component the IPv4 address is converted
- *      into two h16 components, otherwise it's normalized and kept as is.
- *
- *      Ex: [::192.200.003.4]       -> [::192.200.3.4]
- *          [ffff::192.200.003.4]   -> [ffff::c0c8:3041]
- *
- * NOTE:
- *  For unknown scheme types Windows simply copies the address over without any
- *  changes.
- *
- *  IPv4 address can be included in an elision if all its components are 0's.
- */
-static BOOL canonicalize_ipv6address(const parse_data *data, Uri *uri,
-                                     DWORD flags, BOOL computeOnly) {
-    uri->host_start = uri->canon_len;
-
-    if(data->scheme_type == URL_SCHEME_UNKNOWN) {
-        if(!computeOnly)
-            memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
-        uri->canon_len += data->host_len;
-    } else {
-        WCHAR buffer[46];
-        ULONG size = ARRAY_SIZE(buffer);
-
-        if(computeOnly) {
-            RtlIpv6AddressToStringExW(&data->ipv6_address, 0, 0, buffer, &size);
-            uri->canon_len += size + 1;
-        } else {
-            uri->canon_uri[uri->canon_len++] = '[';
-            RtlIpv6AddressToStringExW(&data->ipv6_address, 0, 0, uri->canon_uri + uri->canon_len, &size);
-            uri->canon_len += size - 1;
-            uri->canon_uri[uri->canon_len++] = ']';
-        }
-    }
-
-    uri->host_len = uri->canon_len - uri->host_start;
-
-    if(!computeOnly)
-        TRACE("(%p %p %lx %d): Canonicalized IPv6 address %s, len=%ld\n", data, uri, flags,
-            computeOnly, debugstr_wn(uri->canon_uri+uri->host_start, uri->host_len),
-            uri->host_len);
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize the host of the URI (if any). */
-static BOOL canonicalize_host(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    uri->host_start = -1;
-    uri->host_len = 0;
-    uri->domain_offset = -1;
-
-    if(data->host) {
-        switch(data->host_type) {
-        case Uri_HOST_DNS:
-            uri->host_type = Uri_HOST_DNS;
-            if(!canonicalize_reg_name(data, uri, flags, computeOnly))
-                return FALSE;
-
-            break;
-        case Uri_HOST_IPV4:
-            uri->host_type = Uri_HOST_IPV4;
-            if(!canonicalize_ipv4address(data, uri, flags, computeOnly))
-                return FALSE;
-
-            break;
-        case Uri_HOST_IPV6:
-            if(!canonicalize_ipv6address(data, uri, flags, computeOnly))
-                return FALSE;
-
-            uri->host_type = Uri_HOST_IPV6;
-            break;
-
-        case Uri_HOST_IDN:
-            uri->host_type = Uri_HOST_IDN;
-            if(!canonicalize_reg_name(data, uri, flags, computeOnly))
-                return FALSE;
-
-            break;
-        case Uri_HOST_UNKNOWN:
-            if(data->host_len > 0 || data->scheme_type != URL_SCHEME_FILE) {
-                uri->host_start = uri->canon_len;
-
-                /* Nothing happens to unknown host types. */
-                if(!computeOnly)
-                    memcpy(uri->canon_uri+uri->canon_len, data->host, data->host_len*sizeof(WCHAR));
-                uri->canon_len += data->host_len;
-                uri->host_len = data->host_len;
-            }
-
-            uri->host_type = Uri_HOST_UNKNOWN;
-            break;
-        default:
-            FIXME("(%p %p %lx %d): Canonicalization for host type %d not supported.\n", data,
-                    uri, flags, computeOnly, data->host_type);
-            return FALSE;
-       }
-   }
-
-   return TRUE;
-}
-
-static BOOL canonicalize_port(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    BOOL has_default_port = FALSE;
-    USHORT default_port = 0;
-    DWORD i;
-
-    uri->port_offset = -1;
-
-    /* Check if the scheme has a default port. */
-    for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
-        if(default_ports[i].scheme == data->scheme_type) {
-            has_default_port = TRUE;
-            default_port = default_ports[i].port;
-            break;
-        }
-    }
-
-    uri->has_port = data->has_port || has_default_port;
-
-    /* Possible cases:
-     *  1)  Has a port which is the default port.
-     *  2)  Has a port (not the default).
-     *  3)  Doesn't have a port, but, scheme has a default port.
-     *  4)  No port.
-     */
-    if(has_default_port && data->has_port && data->port_value == default_port) {
-        /* If it's the default port and this flag isn't set, don't do anything. */
-        if(flags & Uri_CREATE_NO_CANONICALIZE) {
-            uri->port_offset = uri->canon_len-uri->authority_start;
-            if(!computeOnly)
-                uri->canon_uri[uri->canon_len] = ':';
-            ++uri->canon_len;
-
-            if(data->port) {
-                /* Copy the original port over. */
-                if(!computeOnly)
-                    memcpy(uri->canon_uri+uri->canon_len, data->port, data->port_len*sizeof(WCHAR));
-                uri->canon_len += data->port_len;
-            } else {
-                if(!computeOnly)
-                    uri->canon_len += ui2str(uri->canon_uri+uri->canon_len, data->port_value);
-                else
-                    uri->canon_len += ui2str(NULL, data->port_value);
-            }
-        }
-
-        uri->port = default_port;
-    } else if(data->has_port) {
-        uri->port_offset = uri->canon_len-uri->authority_start;
-        if(!computeOnly)
-            uri->canon_uri[uri->canon_len] = ':';
-        ++uri->canon_len;
-
-        if(flags & Uri_CREATE_NO_CANONICALIZE && data->port) {
-            /* Copy the original over without changes. */
-            if(!computeOnly)
-                memcpy(uri->canon_uri+uri->canon_len, data->port, data->port_len*sizeof(WCHAR));
-            uri->canon_len += data->port_len;
-        } else {
-            if(!computeOnly)
-                uri->canon_len += ui2str(uri->canon_uri+uri->canon_len, data->port_value);
-            else
-                uri->canon_len += ui2str(NULL, data->port_value);
-        }
-
-        uri->port = data->port_value;
-    } else if(has_default_port)
-        uri->port = default_port;
-
-    return TRUE;
-}
-
-/* Canonicalizes the authority of the URI represented by the parse_data. */
-static BOOL canonicalize_authority(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    uri->authority_start = uri->canon_len;
-    uri->authority_len = 0;
-
-    if(!canonicalize_userinfo(data, uri, flags, computeOnly))
-        return FALSE;
-
-    if(!canonicalize_host(data, uri, flags, computeOnly))
-        return FALSE;
-
-    if(!canonicalize_port(data, uri, flags, computeOnly))
-        return FALSE;
-
-    if(uri->host_start != -1 || (data->is_relative && (data->password || data->username)))
-        uri->authority_len = uri->canon_len - uri->authority_start;
-    else
-        uri->authority_start = -1;
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize the path of a hierarchical URI.
- *
- * Things that happen:
- *  1). Forbidden characters are percent encoded, unless the NO_ENCODE_FORBIDDEN
- *      flag is set or it's a file URI. Forbidden characters are always encoded
- *      for file schemes regardless and forbidden characters are never encoded
- *      for unknown scheme types.
- *
- *  2). For known scheme types '\\' are changed to '/'.
- *
- *  3). Percent encoded, unreserved characters are decoded to their actual values.
- *      Unless the scheme type is unknown. For file schemes any percent encoded
- *      character in the unreserved or reserved set is decoded.
- *
- *  4). For File schemes if the path is starts with a drive letter and doesn't
- *      start with a '/' then one is appended.
- *      Ex: file://c:/test.mp3 -> file:///c:/test.mp3
- *
- *  5). Dot segments are removed from the path for all scheme types
- *      unless NO_CANONICALIZE flag is set. Dot segments aren't removed
- *      for wildcard scheme types.
- *
- * NOTES:
- *      file://c:/test%20test   -> file:///c:/test%2520test
- *      file://c:/test%3Etest   -> file:///c:/test%253Etest
- * if Uri_CREATE_FILE_USE_DOS_PATH is not set:
- *      file:///c:/test%20test  -> file:///c:/test%20test
- *      file:///c:/test%test    -> file:///c:/test%25test
- */
-static DWORD canonicalize_path_hierarchical(const WCHAR *path, DWORD path_len, URL_SCHEME scheme_type, BOOL has_host, DWORD flags,
-        BOOL is_implicit_scheme, WCHAR *ret_path) {
-    const BOOL known_scheme = scheme_type != URL_SCHEME_UNKNOWN;
-    const BOOL is_file = scheme_type == URL_SCHEME_FILE;
-    const BOOL is_res = scheme_type == URL_SCHEME_RES;
-    const WCHAR *ptr;
-    BOOL escape_pct = FALSE;
-    DWORD len = 0;
-
-    if(!path)
-        return 0;
-
-    ptr = path;
-
-    if(is_file && !has_host) {
-        /* Check if a '/' needs to be appended for the file scheme. */
-        if(path_len > 1 && is_drive_path(ptr) && !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-            if(ret_path)
-                ret_path[len] = '/';
-            len++;
-            escape_pct = TRUE;
-        } else if(*ptr == '/') {
-            if(!(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-                /* Copy the extra '/' over. */
-                if(ret_path)
-                    ret_path[len] = '/';
-                len++;
-            }
-            ++ptr;
-        }
-
-        if(is_drive_path(ptr)) {
-            if(ret_path) {
-                ret_path[len] = *ptr;
-                /* If there's a '|' after the drive letter, convert it to a ':'. */
-                ret_path[len+1] = ':';
-            }
-            ptr += 2;
-            len += 2;
-        }
-    }
-
-    if(!is_file && *path && *path != '/') {
-        /* Prepend a '/' to the path if it doesn't have one. */
-        if(ret_path)
-            ret_path[len] = '/';
-        len++;
-    }
-
-    for(; ptr < path+path_len; ++ptr) {
-        BOOL do_default_action = TRUE;
-
-        if(*ptr == '%' && !is_res) {
-            const WCHAR *tmp = ptr;
-            WCHAR val;
-
-            /* Check if the % represents a valid encoded char, or if it needs encoding. */
-            BOOL force_encode = !check_pct_encoded(&tmp) && is_file && !(flags&Uri_CREATE_FILE_USE_DOS_PATH);
-            val = decode_pct_val(ptr);
-
-            if(force_encode || escape_pct) {
-                /* Escape the percent sign in the file URI. */
-                if(ret_path)
-                    pct_encode_val(*ptr, ret_path+len);
-                len += 3;
-                do_default_action = FALSE;
-            } else if((is_unreserved(val) && known_scheme) ||
-                      (is_file && !is_implicit_scheme && (is_unreserved(val) || is_reserved(val) ||
-                      (val && flags&Uri_CREATE_FILE_USE_DOS_PATH && !is_forbidden_dos_path_char(val))))) {
-                if(ret_path)
-                    ret_path[len] = val;
-                len++;
-
-                ptr += 2;
-                continue;
-            }
-        } else if(*ptr == '/' && is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-            /* Convert the '/' back to a '\\'. */
-            if(ret_path)
-                ret_path[len] = '\\';
-            len++;
-            do_default_action = FALSE;
-        } else if(*ptr == '\\' && known_scheme) {
-            if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH))) {
-                /* Convert '\\' into a '/'. */
-                if(ret_path)
-                    ret_path[len] = '/';
-                len++;
-                do_default_action = FALSE;
-            }
-        } else if(known_scheme && !is_res && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr) &&
-                  (!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) || is_file)) {
-            if(!is_file || !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-                /* Escape the forbidden character. */
-                if(ret_path)
-                    pct_encode_val(*ptr, ret_path+len);
-                len += 3;
-                do_default_action = FALSE;
-            }
-        }
-
-        if(do_default_action) {
-            if(ret_path)
-                ret_path[len] = *ptr;
-            len++;
-        }
-    }
-
-    /* Removing the dot segments only happens when it's not in
-     * computeOnly mode and it's not a wildcard scheme. File schemes
-     * with USE_DOS_PATH set don't get dot segments removed.
-     */
-    if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) &&
-       scheme_type != URL_SCHEME_WILDCARD) {
-        if(!(flags & Uri_CREATE_NO_CANONICALIZE) && ret_path) {
-            /* Remove the dot segments (if any) and reset everything to the new
-             * correct length.
-             */
-            len = remove_dot_segments(ret_path, len);
-        }
-    }
-
-    if(ret_path)
-        TRACE("Canonicalized path %s len=%ld\n", debugstr_wn(ret_path, len), len);
-    return len;
-}
-
-/* Attempts to canonicalize the path for an opaque URI.
- *
- * For known scheme types:
- *  1)  forbidden characters are percent encoded if
- *      NO_ENCODE_FORBIDDEN_CHARACTERS isn't set.
- *
- *  2)  Percent encoded, unreserved characters are decoded
- *      to their actual values, for known scheme types.
- *
- *  3)  '\\' are changed to '/' for known scheme types
- *      except for mailto schemes.
- *
- *  4)  For file schemes, if USE_DOS_PATH is set all '/'
- *      are converted to backslashes.
- *
- *  5)  For file schemes, if USE_DOS_PATH isn't set all '\'
- *      are converted to forward slashes.
- */
-static BOOL canonicalize_path_opaque(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    const WCHAR *ptr;
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-    const BOOL is_file = data->scheme_type == URL_SCHEME_FILE;
-    const BOOL is_mk = data->scheme_type == URL_SCHEME_MK;
-
-    if(!data->path) {
-        uri->path_start = -1;
-        uri->path_len = 0;
-        return TRUE;
-    }
-
-    uri->path_start = uri->canon_len;
-
-    if(is_mk){
-        /* hijack this flag for SCHEME_MK to tell the function when to start
-         * converting slashes */
-        flags |= Uri_CREATE_FILE_USE_DOS_PATH;
-    }
-
-    /* For javascript: URIs, simply copy path part without any canonicalization */
-    if(data->scheme_type == URL_SCHEME_JAVASCRIPT) {
-        if(!computeOnly)
-            memcpy(uri->canon_uri+uri->canon_len, data->path, data->path_len*sizeof(WCHAR));
-        uri->path_len = data->path_len;
-        uri->canon_len += data->path_len;
-        return TRUE;
-    }
-
-    /* Windows doesn't allow a "//" to appear after the scheme
-     * of a URI, if it's an opaque URI.
-     */
-    if(data->scheme && *(data->path) == '/' && *(data->path+1) == '/') {
-        /* So it inserts a "/." before the "//" if it exists. */
-        if(!computeOnly) {
-            uri->canon_uri[uri->canon_len] = '/';
-            uri->canon_uri[uri->canon_len+1] = '.';
-        }
-
-        uri->canon_len += 2;
-    }
-
-    for(ptr = data->path; ptr < data->path+data->path_len; ++ptr) {
-        BOOL do_default_action = TRUE;
-
-        if(*ptr == '%' && known_scheme) {
-            WCHAR val = decode_pct_val(ptr);
-
-            if(is_unreserved(val)) {
-                if(!computeOnly)
-                    uri->canon_uri[uri->canon_len] = val;
-                ++uri->canon_len;
-
-                ptr += 2;
-                continue;
-            }
-        } else if(*ptr == '/' && is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-            if(!computeOnly)
-                uri->canon_uri[uri->canon_len] = '\\';
-            ++uri->canon_len;
-            do_default_action = FALSE;
-        } else if(*ptr == '\\') {
-            if((data->is_relative || is_mk || is_file) && !(flags & Uri_CREATE_FILE_USE_DOS_PATH)) {
-                /* Convert to a '/'. */
-                if(!computeOnly)
-                    uri->canon_uri[uri->canon_len] = '/';
-                ++uri->canon_len;
-                do_default_action = FALSE;
-            }
-        } else if(is_mk && *ptr == ':' && ptr + 1 < data->path + data->path_len && *(ptr + 1) == ':') {
-            flags &= ~Uri_CREATE_FILE_USE_DOS_PATH;
-        } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr) &&
-                  !(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
-            if(!(is_file && (flags & Uri_CREATE_FILE_USE_DOS_PATH))) {
-                if(!computeOnly)
-                    pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
-                uri->canon_len += 3;
-                do_default_action = FALSE;
-            }
-        }
-
-        if(do_default_action) {
-            if(!computeOnly)
-                uri->canon_uri[uri->canon_len] = *ptr;
-            ++uri->canon_len;
-        }
-    }
-
-    if(is_mk && !computeOnly && !(flags & Uri_CREATE_NO_CANONICALIZE)) {
-        DWORD new_len = remove_dot_segments(uri->canon_uri + uri->path_start,
-                                            uri->canon_len - uri->path_start);
-        uri->canon_len = uri->path_start + new_len;
-    }
-
-    uri->path_len = uri->canon_len - uri->path_start;
-
-    if(!computeOnly)
-        TRACE("(%p %p %lx %d): Canonicalized opaque URI path %s len=%ld\n", data, uri, flags, computeOnly,
-            debugstr_wn(uri->canon_uri+uri->path_start, uri->path_len), uri->path_len);
-    return TRUE;
-}
-
-/* Determines how the URI represented by the parse_data should be canonicalized.
- *
- * Essentially, if the parse_data represents an hierarchical URI then it calls
- * canonicalize_authority and the canonicalization functions for the path. If the
- * URI is opaque it canonicalizes the path of the URI.
- */
-static BOOL canonicalize_hierpart(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    if(!data->is_opaque || (data->is_relative && (data->password || data->username))) {
-        /* "//" is only added for non-wildcard scheme types.
-         *
-         * A "//" is only added to a relative URI if it has a
-         * host or port component (this only happens if a IUriBuilder
-         * is generating an IUri).
-         */
-        if((data->is_relative && (data->host || data->has_port)) ||
-           (!data->is_relative && data->scheme_type != URL_SCHEME_WILDCARD)) {
-            if(data->scheme_type == URL_SCHEME_WILDCARD)
-                FIXME("Here\n");
-
-            if(!computeOnly) {
-                INT pos = uri->canon_len;
-
-                uri->canon_uri[pos] = '/';
-                uri->canon_uri[pos+1] = '/';
-           }
-           uri->canon_len += 2;
-        }
-
-        if(!canonicalize_authority(data, uri, flags, computeOnly))
-            return FALSE;
-
-        if(data->is_relative && (data->password || data->username)) {
-            if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
-                return FALSE;
-        } else {
-            if(!computeOnly)
-                uri->path_start = uri->canon_len;
-            uri->path_len = canonicalize_path_hierarchical(data->path, data->path_len, data->scheme_type, data->host_len != 0,
-                    flags, data->has_implicit_scheme, computeOnly ? NULL : uri->canon_uri+uri->canon_len);
-            uri->canon_len += uri->path_len;
-            if(!computeOnly && !uri->path_len)
-                uri->path_start = -1;
-        }
-    } else {
-        /* Opaque URI's don't have an authority. */
-        uri->userinfo_start = uri->userinfo_split = -1;
-        uri->userinfo_len = 0;
-        uri->host_start = -1;
-        uri->host_len = 0;
-        uri->host_type = Uri_HOST_UNKNOWN;
-        uri->has_port = FALSE;
-        uri->authority_start = -1;
-        uri->authority_len = 0;
-        uri->domain_offset = -1;
-        uri->port_offset = -1;
-
-        if(is_hierarchical_scheme(data->scheme_type)) {
-            DWORD i;
-
-            /* Absolute URIs aren't displayed for known scheme types
-             * which should be hierarchical URIs.
-             */
-            uri->display_modifiers |= URI_DISPLAY_NO_ABSOLUTE_URI;
-
-            /* Windows also sets the port for these (if they have one). */
-            for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
-                if(data->scheme_type == default_ports[i].scheme) {
-                    uri->has_port = TRUE;
-                    uri->port = default_ports[i].port;
-                    break;
-                }
-            }
-        }
-
-        if(!canonicalize_path_opaque(data, uri, flags, computeOnly))
-            return FALSE;
-    }
-
-    if(uri->path_start > -1 && !computeOnly)
-        /* Finding file extensions happens for both types of URIs. */
-        uri->extension_offset = find_file_extension(uri->canon_uri+uri->path_start, uri->path_len);
-    else
-        uri->extension_offset = -1;
-
-    return TRUE;
-}
-
-/* Attempts to canonicalize the query string of the URI.
- *
- * Things that happen:
- *  1)  For known scheme types forbidden characters
- *      are percent encoded, unless the NO_DECODE_EXTRA_INFO flag is set
- *      or NO_ENCODE_FORBIDDEN_CHARACTERS is set.
- *
- *  2)  For known scheme types, percent encoded, unreserved characters
- *      are decoded as long as the NO_DECODE_EXTRA_INFO flag isn't set.
- */
-static BOOL canonicalize_query(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    const WCHAR *ptr, *end;
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-
-    if(!data->query) {
-        uri->query_start = -1;
-        uri->query_len = 0;
-        return TRUE;
-    }
-
-    uri->query_start = uri->canon_len;
-
-    end = data->query+data->query_len;
-    for(ptr = data->query; ptr < end; ++ptr) {
-        if(*ptr == '%') {
-            if(known_scheme && !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
-                WCHAR val = decode_pct_val(ptr);
-                if(is_unreserved(val)) {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = val;
-                    ++uri->canon_len;
-
-                    ptr += 2;
-                    continue;
-                }
-            }
-        } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr)) {
-            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) &&
-               !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
-                if(!computeOnly)
-                    pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
-                uri->canon_len += 3;
-                continue;
-            }
-        }
-
-        if(!computeOnly)
-            uri->canon_uri[uri->canon_len] = *ptr;
-        ++uri->canon_len;
-    }
-
-    uri->query_len = uri->canon_len - uri->query_start;
-
-    if(!computeOnly)
-        TRACE("(%p %p %lx %d): Canonicalized query string %s len=%ld\n", data, uri, flags,
-            computeOnly, debugstr_wn(uri->canon_uri+uri->query_start, uri->query_len),
-            uri->query_len);
-    return TRUE;
-}
-
-static BOOL canonicalize_fragment(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    const WCHAR *ptr, *end;
-    const BOOL known_scheme = data->scheme_type != URL_SCHEME_UNKNOWN;
-
-    if(!data->fragment) {
-        uri->fragment_start = -1;
-        uri->fragment_len = 0;
-        return TRUE;
-    }
-
-    uri->fragment_start = uri->canon_len;
-
-    end = data->fragment + data->fragment_len;
-    for(ptr = data->fragment; ptr < end; ++ptr) {
-        if(*ptr == '%') {
-            if(known_scheme && !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
-                WCHAR val = decode_pct_val(ptr);
-                if(is_unreserved(val)) {
-                    if(!computeOnly)
-                        uri->canon_uri[uri->canon_len] = val;
-                    ++uri->canon_len;
-
-                    ptr += 2;
-                    continue;
-                }
-            }
-        } else if(known_scheme && is_ascii(*ptr) && !is_unreserved(*ptr) && !is_reserved(*ptr)) {
-            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS) &&
-               !(flags & Uri_CREATE_NO_DECODE_EXTRA_INFO)) {
-                if(!computeOnly)
-                    pct_encode_val(*ptr, uri->canon_uri+uri->canon_len);
-                uri->canon_len += 3;
-                continue;
-            }
-        }
-
-        if(!computeOnly)
-            uri->canon_uri[uri->canon_len] = *ptr;
-        ++uri->canon_len;
-    }
-
-    uri->fragment_len = uri->canon_len - uri->fragment_start;
-
-    if(!computeOnly)
-        TRACE("(%p %p %lx %d): Canonicalized fragment %s len=%ld\n", data, uri, flags,
-            computeOnly, debugstr_wn(uri->canon_uri+uri->fragment_start, uri->fragment_len),
-            uri->fragment_len);
-    return TRUE;
-}
-
-/* Canonicalizes the scheme information specified in the parse_data using the specified flags. */
-static BOOL canonicalize_scheme(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
-    uri->scheme_start = -1;
-    uri->scheme_len = 0;
-
-    if(!data->scheme) {
-        /* The only type of URI that doesn't have to have a scheme is a relative
-         * URI.
-         */
-        if(!data->is_relative) {
-            FIXME("(%p %p %lx): Unable to determine the scheme type of %s.\n", data,
-                    uri, flags, debugstr_w(data->uri));
-            return FALSE;
-        }
-    } else {
-        if(!computeOnly) {
-            DWORD i;
-            INT pos = uri->canon_len;
-
-            for(i = 0; i < data->scheme_len; ++i) {
-                /* Scheme name must be lower case after canonicalization. */
-                uri->canon_uri[i + pos] = towlower(data->scheme[i]);
-            }
-
-            uri->canon_uri[i + pos] = ':';
-            uri->scheme_start = pos;
-
-            TRACE("(%p %p %lx): Canonicalized scheme=%s, len=%ld.\n", data, uri, flags,
-                    debugstr_wn(uri->canon_uri+uri->scheme_start,  data->scheme_len), data->scheme_len);
-        }
-
-        /* This happens in both computation modes. */
-        uri->canon_len += data->scheme_len + 1;
-        uri->scheme_len = data->scheme_len;
-    }
-    return TRUE;
-}
-
-/* Computes what the length of the URI specified by the parse_data will be
- * after canonicalization occurs using the specified flags.
- *
- * This function will return a non-zero value indicating the length of the canonicalized
- * URI, or -1 on error.
- */
-static int compute_canonicalized_length(const parse_data *data, DWORD flags) {
-    Uri uri;
-
-    memset(&uri, 0, sizeof(Uri));
-
-    TRACE("(%p %lx): Beginning to compute canonicalized length for URI %s\n", data, flags,
-            debugstr_w(data->uri));
-
-    if(!canonicalize_scheme(data, &uri, flags, TRUE)) {
-        ERR("(%p %lx): Failed to compute URI scheme length.\n", data, flags);
-        return -1;
-    }
-
-    if(!canonicalize_hierpart(data, &uri, flags, TRUE)) {
-        ERR("(%p %lx): Failed to compute URI hierpart length.\n", data, flags);
-        return -1;
-    }
-
-    if(!canonicalize_query(data, &uri, flags, TRUE)) {
-        ERR("(%p %lx): Failed to compute query string length.\n", data, flags);
-        return -1;
-    }
-
-    if(!canonicalize_fragment(data, &uri, flags, TRUE)) {
-        ERR("(%p %lx): Failed to compute fragment length.\n", data, flags);
-        return -1;
-    }
-
-    TRACE("(%p %lx): Finished computing canonicalized URI length. length=%ld\n", data, flags, uri.canon_len);
-
-    return uri.canon_len;
-}
-
-/* Canonicalizes the URI data specified in the parse_data, using the given flags. If the
- * canonicalization succeeds it will store all the canonicalization information
- * in the pointer to the Uri.
- *
- * To canonicalize a URI this function first computes what the length of the URI
- * specified by the parse_data will be. Once this is done it will then perform the actual
- * canonicalization of the URI.
- */
-static HRESULT canonicalize_uri(const parse_data *data, Uri *uri, DWORD flags) {
-    INT len;
-
-    uri->canon_uri = NULL;
-    uri->canon_size = uri->canon_len = 0;
-
-    TRACE("(%p %p %lx): beginning to canonicalize URI %s.\n", data, uri, flags, debugstr_w(data->uri));
-
-    /* First try to compute the length of the URI. */
-    len = compute_canonicalized_length(data, flags);
-    if(len == -1) {
-        ERR("(%p %p %lx): Could not compute the canonicalized length of %s.\n", data, uri, flags,
-                debugstr_w(data->uri));
-        return E_INVALIDARG;
-    }
-
-    uri->canon_uri = malloc((len + 1) * sizeof(WCHAR));
-    if(!uri->canon_uri)
-        return E_OUTOFMEMORY;
-
-    uri->canon_size = len;
-    if(!canonicalize_scheme(data, uri, flags, FALSE)) {
-        ERR("(%p %p %lx): Unable to canonicalize the scheme of the URI.\n", data, uri, flags);
-        return E_INVALIDARG;
-    }
-    uri->scheme_type = data->scheme_type;
-
-    if(!canonicalize_hierpart(data, uri, flags, FALSE)) {
-        ERR("(%p %p %lx): Unable to canonicalize the hierpart of the URI\n", data, uri, flags);
-        return E_INVALIDARG;
-    }
-
-    if(!canonicalize_query(data, uri, flags, FALSE)) {
-        ERR("(%p %p %lx): Unable to canonicalize query string of the URI.\n",
-            data, uri, flags);
-        return E_INVALIDARG;
-    }
-
-    if(!canonicalize_fragment(data, uri, flags, FALSE)) {
-        ERR("(%p %p %lx): Unable to canonicalize fragment of the URI.\n",
-            data, uri, flags);
-        return E_INVALIDARG;
-    }
-
-    /* There's a possibility we didn't use all the space we allocated
-     * earlier.
-     */
-    if(uri->canon_len < uri->canon_size) {
-        /* This happens if the URI is hierarchical and dot
-         * segments were removed from its path.
-         */
-        WCHAR *tmp = realloc(uri->canon_uri, (uri->canon_len + 1) * sizeof(WCHAR));
-        if(!tmp)
-            return E_OUTOFMEMORY;
-
-        uri->canon_uri = tmp;
-        uri->canon_size = uri->canon_len;
-    }
-
-    uri->canon_uri[uri->canon_len] = '\0';
-    TRACE("(%p %p %lx): finished canonicalizing the URI. uri=%s\n", data, uri, flags, debugstr_w(uri->canon_uri));
-
-    return S_OK;
-}
-
-static HRESULT get_builder_component(LPWSTR *component, DWORD *component_len,
-                                     LPCWSTR source, DWORD source_len,
-                                     LPCWSTR *output, DWORD *output_len)
-{
-    if(!output_len) {
-        if(output)
-            *output = NULL;
-        return E_POINTER;
-    }
-
-    if(!output) {
-        *output_len = 0;
-        return E_POINTER;
-    }
-
-    if(!(*component) && source) {
-        /* Allocate 'component', and copy the contents from 'source'
-         * into the new allocation.
-         */
-        *component = malloc((source_len + 1) * sizeof(WCHAR));
-        if(!(*component))
-            return E_OUTOFMEMORY;
-
-        memcpy(*component, source, source_len*sizeof(WCHAR));
-        (*component)[source_len] = '\0';
-        *component_len = source_len;
-    }
-
-    *output = *component;
-    *output_len = *component_len;
-    return *output ? S_OK : S_FALSE;
-}
-
-/* Allocates 'component' and copies the string from 'new_value' into 'component'.
- * If 'prefix' is set and 'new_value' isn't NULL, then it checks if 'new_value'
- * starts with 'prefix'. If it doesn't then 'prefix' is prepended to 'component'.
- *
- * If everything is successful, then will set 'success_flag' in 'flags'.
- */
-static HRESULT set_builder_component(LPWSTR *component, DWORD *component_len, LPCWSTR new_value,
-                                     WCHAR prefix, DWORD *flags, DWORD success_flag)
-{
-    free(*component);
-
-    if(!new_value) {
-        *component = NULL;
-        *component_len = 0;
-    } else {
-        BOOL add_prefix = FALSE;
-        DWORD len = lstrlenW(new_value);
-        DWORD pos = 0;
-
-        if(prefix && *new_value != prefix) {
-            add_prefix = TRUE;
-            *component = malloc((len + 2) * sizeof(WCHAR));
-        } else
-            *component = malloc((len + 1) * sizeof(WCHAR));
-
-        if(!(*component))
-            return E_OUTOFMEMORY;
-
-        if(add_prefix)
-            (*component)[pos++] = prefix;
-
-        memcpy(*component+pos, new_value, (len+1)*sizeof(WCHAR));
-        *component_len = len+pos;
-    }
-
-    *flags |= success_flag;
-    return S_OK;
-}
-
-static void reset_builder(UriBuilder *builder) {
-    if(builder->uri)
-        IUri_Release(&builder->uri->IUri_iface);
-    builder->uri = NULL;
-
-    free(builder->fragment);
-    builder->fragment = NULL;
-    builder->fragment_len = 0;
-
-    free(builder->host);
-    builder->host = NULL;
-    builder->host_len = 0;
-
-    free(builder->password);
-    builder->password = NULL;
-    builder->password_len = 0;
-
-    free(builder->path);
-    builder->path = NULL;
-    builder->path_len = 0;
-
-    free(builder->query);
-    builder->query = NULL;
-    builder->query_len = 0;
-
-    free(builder->scheme);
-    builder->scheme = NULL;
-    builder->scheme_len = 0;
-
-    free(builder->username);
-    builder->username = NULL;
-    builder->username_len = 0;
-
-    builder->has_port = FALSE;
-    builder->port = 0;
-    builder->modified_props = 0;
-}
-
-static HRESULT validate_scheme_name(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    const WCHAR *component;
-    const WCHAR *ptr;
-    const WCHAR **pptr;
-    DWORD expected_len;
-
-    if(builder->scheme) {
-        ptr = builder->scheme;
-        expected_len = builder->scheme_len;
-    } else if(builder->uri && builder->uri->scheme_start > -1) {
-        ptr = builder->uri->canon_uri+builder->uri->scheme_start;
-        expected_len = builder->uri->scheme_len;
-    } else {
-        ptr = L"";
-        expected_len = 0;
-    }
-
-    component = ptr;
-    pptr = &ptr;
-    if(parse_scheme(pptr, data, flags, ALLOW_NULL_TERM_SCHEME) &&
-       data->scheme_len == expected_len) {
-        if(data->scheme)
-            TRACE("(%p %p %lx): Found valid scheme component %s len=%ld.\n", builder, data, flags,
-               debugstr_wn(data->scheme, data->scheme_len), data->scheme_len);
-    } else {
-        TRACE("(%p %p %lx): Invalid scheme component found %s.\n", builder, data, flags,
-            debugstr_wn(component, expected_len));
-        return INET_E_INVALID_URL;
-   }
-
-    return S_OK;
-}
-
-static HRESULT validate_username(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    const WCHAR *ptr;
-    const WCHAR **pptr;
-    DWORD expected_len;
-
-    if(builder->username) {
-        ptr = builder->username;
-        expected_len = builder->username_len;
-    } else if(!(builder->modified_props & Uri_HAS_USER_NAME) && builder->uri &&
-              builder->uri->userinfo_start > -1 && builder->uri->userinfo_split != 0) {
-        /* Just use the username from the base Uri. */
-        data->username = builder->uri->canon_uri+builder->uri->userinfo_start;
-        data->username_len = (builder->uri->userinfo_split > -1) ?
-                                        builder->uri->userinfo_split : builder->uri->userinfo_len;
-        ptr = NULL;
-    } else {
-        ptr = NULL;
-        expected_len = 0;
-    }
-
-    if(ptr) {
-        const WCHAR *component = ptr;
-        pptr = &ptr;
-        if(parse_username(pptr, data, flags, ALLOW_NULL_TERM_USER_NAME) &&
-           data->username_len == expected_len)
-            TRACE("(%p %p %lx): Found valid username component %s len=%ld.\n", builder, data, flags,
-                debugstr_wn(data->username, data->username_len), data->username_len);
-        else {
-            TRACE("(%p %p %lx): Invalid username component found %s.\n", builder, data, flags,
-                debugstr_wn(component, expected_len));
-            return INET_E_INVALID_URL;
-        }
-    }
-
-    return S_OK;
-}
-
-static HRESULT validate_password(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    const WCHAR *ptr;
-    const WCHAR **pptr;
-    DWORD expected_len;
-
-    if(builder->password) {
-        ptr = builder->password;
-        expected_len = builder->password_len;
-    } else if(!(builder->modified_props & Uri_HAS_PASSWORD) && builder->uri &&
-              builder->uri->userinfo_split > -1) {
-        data->password = builder->uri->canon_uri+builder->uri->userinfo_start+builder->uri->userinfo_split+1;
-        data->password_len = builder->uri->userinfo_len-builder->uri->userinfo_split-1;
-        ptr = NULL;
-    } else {
-        ptr = NULL;
-        expected_len = 0;
-    }
-
-    if(ptr) {
-        const WCHAR *component = ptr;
-        pptr = &ptr;
-        if(parse_password(pptr, data, flags, ALLOW_NULL_TERM_PASSWORD) &&
-           data->password_len == expected_len)
-            TRACE("(%p %p %lx): Found valid password component %s len=%ld.\n", builder, data, flags,
-                debugstr_wn(data->password, data->password_len), data->password_len);
-        else {
-            TRACE("(%p %p %lx): Invalid password component found %s.\n", builder, data, flags,
-                debugstr_wn(component, expected_len));
-            return INET_E_INVALID_URL;
-        }
-    }
-
-    return S_OK;
-}
-
-static HRESULT validate_userinfo(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    HRESULT hr;
-
-    hr = validate_username(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    hr = validate_password(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    return S_OK;
-}
-
-static HRESULT validate_host(const UriBuilder *builder, parse_data *data) {
-    const WCHAR *ptr;
-    const WCHAR **pptr;
-    DWORD expected_len;
-
-    if(builder->host) {
-        ptr = builder->host;
-        expected_len = builder->host_len;
-    } else if(!(builder->modified_props & Uri_HAS_HOST) && builder->uri && builder->uri->host_start > -1) {
-        ptr = builder->uri->canon_uri + builder->uri->host_start;
-        expected_len = builder->uri->host_len;
-    } else
-        ptr = NULL;
-
-    if(ptr) {
-        const WCHAR *component = ptr;
-        DWORD extras = ALLOW_BRACKETLESS_IP_LITERAL|IGNORE_PORT_DELIMITER|SKIP_IP_FUTURE_CHECK;
-        pptr = &ptr;
-
-        if(parse_host(pptr, data, extras) && data->host_len == expected_len)
-            TRACE("(%p %p): Found valid host name %s len=%ld type=%d.\n", builder, data,
-                debugstr_wn(data->host, data->host_len), data->host_len, data->host_type);
-        else {
-            TRACE("(%p %p): Invalid host name found %s.\n", builder, data,
-                debugstr_wn(component, expected_len));
-            return INET_E_INVALID_URL;
-        }
-    }
-
-    return S_OK;
-}
-
-static void setup_port(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    if(builder->modified_props & Uri_HAS_PORT) {
-        if(builder->has_port) {
-            data->has_port = TRUE;
-            data->port_value = builder->port;
-        }
-    } else if(builder->uri && builder->uri->has_port) {
-        data->has_port = TRUE;
-        data->port_value = builder->uri->port;
-    }
-
-    if(data->has_port)
-        TRACE("(%p %p %lx): Using %lu as port for IUri.\n", builder, data, flags, data->port_value);
-}
-
-static HRESULT validate_path(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    const WCHAR *ptr = NULL;
-    const WCHAR *component;
-    const WCHAR **pptr;
-    DWORD expected_len;
-    BOOL check_len = TRUE;
-    BOOL valid = FALSE;
-
-    if(builder->path) {
-        ptr = builder->path;
-        expected_len = builder->path_len;
-    } else if(!(builder->modified_props & Uri_HAS_PATH) &&
-              builder->uri && builder->uri->path_start > -1) {
-        ptr = builder->uri->canon_uri+builder->uri->path_start;
-        expected_len = builder->uri->path_len;
-    } else {
-        ptr = L"";
-        check_len = FALSE;
-        expected_len = -1;
-    }
-
-    component = ptr;
-    pptr = &ptr;
-
-    /* How the path is validated depends on what type of
-     * URI it is.
-     */
-    valid = data->is_opaque ?
-        parse_path_opaque(pptr, data, flags) : parse_path_hierarchical(pptr, data, flags);
-
-    if(!valid || (check_len && expected_len != data->path_len)) {
-        TRACE("(%p %p %lx): Invalid path component %s.\n", builder, data, flags,
-            debugstr_wn(component, expected_len) );
-        return INET_E_INVALID_URL;
-    }
-
-    TRACE("(%p %p %lx): Valid path component %s len=%ld.\n", builder, data, flags,
-        debugstr_wn(data->path, data->path_len), data->path_len);
-
-    return S_OK;
-}
-
-static HRESULT validate_query(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    const WCHAR *ptr = NULL;
-    const WCHAR **pptr;
-    DWORD expected_len;
-
-    if(builder->query) {
-        ptr = builder->query;
-        expected_len = builder->query_len;
-    } else if(!(builder->modified_props & Uri_HAS_QUERY) && builder->uri &&
-              builder->uri->query_start > -1) {
-        ptr = builder->uri->canon_uri+builder->uri->query_start;
-        expected_len = builder->uri->query_len;
-    }
-
-    if(ptr) {
-        const WCHAR *component = ptr;
-        pptr = &ptr;
-
-        if(parse_query(pptr, data, flags) && expected_len == data->query_len)
-            TRACE("(%p %p %lx): Valid query component %s len=%ld.\n", builder, data, flags,
-                debugstr_wn(data->query, data->query_len), data->query_len);
-        else {
-            TRACE("(%p %p %lx): Invalid query component %s.\n", builder, data, flags,
-                debugstr_wn(component, expected_len));
-            return INET_E_INVALID_URL;
-        }
-    }
-
-    return S_OK;
-}
-
-static HRESULT validate_fragment(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    const WCHAR *ptr = NULL;
-    const WCHAR **pptr;
-    DWORD expected_len;
-
-    if(builder->fragment) {
-        ptr = builder->fragment;
-        expected_len = builder->fragment_len;
-    } else if(!(builder->modified_props & Uri_HAS_FRAGMENT) && builder->uri &&
-              builder->uri->fragment_start > -1) {
-        ptr = builder->uri->canon_uri+builder->uri->fragment_start;
-        expected_len = builder->uri->fragment_len;
-    }
-
-    if(ptr) {
-        const WCHAR *component = ptr;
-        pptr = &ptr;
-
-        if(parse_fragment(pptr, data, flags) && expected_len == data->fragment_len)
-            TRACE("(%p %p %lx): Valid fragment component %s len=%ld.\n", builder, data, flags,
-                debugstr_wn(data->fragment, data->fragment_len), data->fragment_len);
-        else {
-            TRACE("(%p %p %lx): Invalid fragment component %s.\n", builder, data, flags,
-                debugstr_wn(component, expected_len));
-            return INET_E_INVALID_URL;
-        }
-    }
-
-    return S_OK;
-}
-
-static HRESULT validate_components(const UriBuilder *builder, parse_data *data, DWORD flags) {
-    HRESULT hr;
-
-    memset(data, 0, sizeof(parse_data));
-
-    TRACE("(%p %p %lx): Beginning to validate builder components.\n", builder, data, flags);
-
-    hr = validate_scheme_name(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    /* Extra validation for file schemes. */
-    if(data->scheme_type == URL_SCHEME_FILE) {
-        if((builder->password || (builder->uri && builder->uri->userinfo_split > -1)) ||
-           (builder->username || (builder->uri && builder->uri->userinfo_start > -1))) {
-            TRACE("(%p %p %lx): File schemes can't contain a username or password.\n",
-                builder, data, flags);
-            return INET_E_INVALID_URL;
-        }
-    }
-
-    hr = validate_userinfo(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    hr = validate_host(builder, data);
-    if(FAILED(hr))
-        return hr;
-
-    setup_port(builder, data, flags);
-
-    /* The URI is opaque if it doesn't have an authority component. */
-    if(!data->is_relative)
-        data->is_opaque = !data->username && !data->password && !data->host && !data->has_port
-            && data->scheme_type != URL_SCHEME_FILE;
-    else
-        data->is_opaque = !data->host && !data->has_port;
-
-    hr = validate_path(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    hr = validate_query(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    hr = validate_fragment(builder, data, flags);
-    if(FAILED(hr))
-        return hr;
-
-    TRACE("(%p %p %lx): Finished validating builder components.\n", builder, data, flags);
-
-    return S_OK;
-}
-
-static HRESULT compare_file_paths(const Uri *a, const Uri *b, BOOL *ret)
-{
-    WCHAR *canon_path_a, *canon_path_b;
-    DWORD len_a, len_b;
-
-    if(!a->path_len) {
-        *ret = !b->path_len;
-        return S_OK;
-    }
-
-    if(!b->path_len) {
-        *ret = FALSE;
-        return S_OK;
-    }
-
-    /* Fast path */
-    if(a->path_len == b->path_len && !wcsnicmp(a->canon_uri+a->path_start, b->canon_uri+b->path_start, a->path_len)) {
-        *ret = TRUE;
-        return S_OK;
-    }
-
-    len_a = canonicalize_path_hierarchical(a->canon_uri+a->path_start, a->path_len, a->scheme_type, FALSE, 0, FALSE, NULL);
-    len_b = canonicalize_path_hierarchical(b->canon_uri+b->path_start, b->path_len, b->scheme_type, FALSE, 0, FALSE, NULL);
-
-    canon_path_a = malloc(len_a * sizeof(WCHAR));
-    if(!canon_path_a)
-        return E_OUTOFMEMORY;
-    canon_path_b = malloc(len_b * sizeof(WCHAR));
-    if(!canon_path_b) {
-        free(canon_path_a);
-        return E_OUTOFMEMORY;
-    }
-
-    len_a = canonicalize_path_hierarchical(a->canon_uri+a->path_start, a->path_len, a->scheme_type, FALSE, 0, FALSE, canon_path_a);
-    len_b = canonicalize_path_hierarchical(b->canon_uri+b->path_start, b->path_len, b->scheme_type, FALSE, 0, FALSE, canon_path_b);
-
-    *ret = len_a == len_b && !wcsnicmp(canon_path_a, canon_path_b, len_a);
-
-    free(canon_path_a);
-    free(canon_path_b);
-    return S_OK;
-}
-
-/* Checks if the two Uri's are logically equivalent. It's a simple
- * comparison, since they are both of type Uri, and it can access
- * the properties of each Uri directly without the need to go
- * through the "IUri_Get*" interface calls.
- */
-static HRESULT compare_uris(const Uri *a, const Uri *b, BOOL *ret) {
-    const BOOL known_scheme = a->scheme_type != URL_SCHEME_UNKNOWN;
-    const BOOL are_hierarchical = a->authority_start > -1 && b->authority_start > -1;
-    HRESULT hres;
-
-    *ret = FALSE;
-
-    if(a->scheme_type != b->scheme_type)
-        return S_OK;
-
-    /* Only compare the scheme names (if any) if their unknown scheme types. */
-    if(!known_scheme) {
-        if((a->scheme_start > -1 && b->scheme_start > -1) &&
-           (a->scheme_len == b->scheme_len)) {
-            /* Make sure the schemes are the same. */
-            if(StrCmpNW(a->canon_uri+a->scheme_start, b->canon_uri+b->scheme_start, a->scheme_len))
-                return S_OK;
-        } else if(a->scheme_len != b->scheme_len)
-            /* One of the Uri's has a scheme name, while the other doesn't. */
-            return S_OK;
-    }
-
-    /* If they have a userinfo component, perform case sensitive compare. */
-    if((a->userinfo_start > -1 && b->userinfo_start > -1) &&
-       (a->userinfo_len == b->userinfo_len)) {
-        if(StrCmpNW(a->canon_uri+a->userinfo_start, b->canon_uri+b->userinfo_start, a->userinfo_len))
-            return S_OK;
-    } else if(a->userinfo_len != b->userinfo_len)
-        /* One of the Uri's had a userinfo, while the other one doesn't. */
-        return S_OK;
-
-    /* Check if they have a host name. */
-    if((a->host_start > -1 && b->host_start > -1) &&
-       (a->host_len == b->host_len)) {
-        /* Perform a case insensitive compare if they are a known scheme type. */
-        if(known_scheme) {
-            if(StrCmpNIW(a->canon_uri+a->host_start, b->canon_uri+b->host_start, a->host_len))
-                return S_OK;
-        } else if(StrCmpNW(a->canon_uri+a->host_start, b->canon_uri+b->host_start, a->host_len))
-            return S_OK;
-    } else if(a->host_len != b->host_len)
-        /* One of the Uri's had a host, while the other one didn't. */
-        return S_OK;
-
-    if(a->has_port && b->has_port) {
-        if(a->port != b->port)
-            return S_OK;
-    } else if(a->has_port || b->has_port)
-        /* One had a port, while the other one didn't. */
-        return S_OK;
-
-    /* Windows is weird with how it handles paths. For example
-     * One URI could be "http://google.com" (after canonicalization)
-     * and one could be "http://google.com/" and the IsEqual function
-     * would still evaluate to TRUE, but, only if they are both hierarchical
-     * URIs.
-     */
-    if(a->scheme_type == URL_SCHEME_FILE) {
-        BOOL cmp;
-
-        hres = compare_file_paths(a, b, &cmp);
-        if(FAILED(hres) || !cmp)
-            return hres;
-    } else if((a->path_start > -1 && b->path_start > -1) &&
-       (a->path_len == b->path_len)) {
-        if(StrCmpNW(a->canon_uri+a->path_start, b->canon_uri+b->path_start, a->path_len))
-            return S_OK;
-    } else if(are_hierarchical && a->path_len == -1 && b->path_len == 0) {
-        if(*(a->canon_uri+a->path_start) != '/')
-            return S_OK;
-    } else if(are_hierarchical && b->path_len == 1 && a->path_len == 0) {
-        if(*(b->canon_uri+b->path_start) != '/')
-            return S_OK;
-    } else if(a->path_len != b->path_len)
-        return S_OK;
-
-    /* Compare the query strings of the two URIs. */
-    if((a->query_start > -1 && b->query_start > -1) &&
-       (a->query_len == b->query_len)) {
-        if(StrCmpNW(a->canon_uri+a->query_start, b->canon_uri+b->query_start, a->query_len))
-            return S_OK;
-    } else if(a->query_len != b->query_len)
-        return S_OK;
-
-    if((a->fragment_start > -1 && b->fragment_start > -1) &&
-       (a->fragment_len == b->fragment_len)) {
-        if(StrCmpNW(a->canon_uri+a->fragment_start, b->canon_uri+b->fragment_start, a->fragment_len))
-            return S_OK;
-    } else if(a->fragment_len != b->fragment_len)
-        return S_OK;
-
-    /* If we get here, the two URIs are equivalent. */
-    *ret = TRUE;
-    return S_OK;
-}
-
-static void convert_to_dos_path(const WCHAR *path, DWORD path_len,
-                                WCHAR *output, DWORD *output_len)
-{
-    const WCHAR *ptr = path;
-
-    if(path_len > 3 && *ptr == '/' && is_drive_path(path+1))
-        /* Skip over the leading / before the drive path. */
-        ++ptr;
-
-    for(; ptr < path+path_len; ++ptr) {
-        if(*ptr == '/') {
-            if(output)
-                *output++ = '\\';
-            (*output_len)++;
-        } else {
-            if(output)
-                *output++ = *ptr;
-            (*output_len)++;
-        }
-    }
-}
-
-/* Generates a raw uri string using the parse_data. */
-static DWORD generate_raw_uri(const parse_data *data, BSTR uri, DWORD flags) {
-    DWORD length = 0;
-
-    if(data->scheme) {
-        if(uri) {
-            memcpy(uri, data->scheme, data->scheme_len*sizeof(WCHAR));
-            uri[data->scheme_len] = ':';
-        }
-        length += data->scheme_len+1;
-    }
-
-    if(!data->is_opaque) {
-        /* For the "//" which appears before the authority component. */
-        if(uri) {
-            uri[length] = '/';
-            uri[length+1] = '/';
-        }
-        length += 2;
-
-        /* Check if we need to add the "\\" before the host name
-         * of a UNC server name in a DOS path.
-         */
-        if(flags & RAW_URI_CONVERT_TO_DOS_PATH &&
-           data->scheme_type == URL_SCHEME_FILE && data->host) {
-            if(uri) {
-                uri[length] = '\\';
-                uri[length+1] = '\\';
-            }
-            length += 2;
-        }
-    }
-
-    if(data->username) {
-        if(uri)
-            memcpy(uri+length, data->username, data->username_len*sizeof(WCHAR));
-        length += data->username_len;
-    }
-
-    if(data->password) {
-        if(uri) {
-            uri[length] = ':';
-            memcpy(uri+length+1, data->password, data->password_len*sizeof(WCHAR));
-        }
-        length += data->password_len+1;
-    }
-
-    if(data->password || data->username) {
-        if(uri)
-            uri[length] = '@';
-        ++length;
-    }
-
-    if(data->host) {
-        /* IPv6 addresses get the brackets added around them if they don't already
-         * have them.
-         */
-        const BOOL add_brackets = data->host_type == Uri_HOST_IPV6 && *(data->host) != '[';
-        if(add_brackets) {
-            if(uri)
-                uri[length] = '[';
-            ++length;
-        }
-
-        if(uri)
-            memcpy(uri+length, data->host, data->host_len*sizeof(WCHAR));
-        length += data->host_len;
-
-        if(add_brackets) {
-            if(uri)
-                uri[length] = ']';
-            length++;
-        }
-    }
-
-    if(data->has_port) {
-        /* The port isn't included in the raw uri if it's the default
-         * port for the scheme type.
-         */
-        DWORD i;
-        BOOL is_default = FALSE;
-
-        for(i = 0; i < ARRAY_SIZE(default_ports); ++i) {
-            if(data->scheme_type == default_ports[i].scheme &&
-               data->port_value == default_ports[i].port)
-                is_default = TRUE;
-        }
-
-        if(!is_default || flags & RAW_URI_FORCE_PORT_DISP) {
-            if(uri)
-                uri[length] = ':';
-            ++length;
-
-            if(uri)
-                length += ui2str(uri+length, data->port_value);
-            else
-                length += ui2str(NULL, data->port_value);
-        }
-    }
-
-    /* Check if a '/' should be added before the path for hierarchical URIs. */
-    if(!data->is_opaque && data->path && *(data->path) != '/') {
-        if(uri)
-            uri[length] = '/';
-        ++length;
-    }
-
-    if(data->path) {
-        if(!data->is_opaque && data->scheme_type == URL_SCHEME_FILE &&
-           flags & RAW_URI_CONVERT_TO_DOS_PATH) {
-            DWORD len = 0;
-
-            if(uri)
-                convert_to_dos_path(data->path, data->path_len, uri+length, &len);
-            else
-                convert_to_dos_path(data->path, data->path_len, NULL, &len);
-
-            length += len;
-        } else {
-            if(uri)
-                memcpy(uri+length, data->path, data->path_len*sizeof(WCHAR));
-            length += data->path_len;
-        }
-    }
-
-    if(data->query) {
-        if(uri)
-            memcpy(uri+length, data->query, data->query_len*sizeof(WCHAR));
-        length += data->query_len;
-    }
-
-    if(data->fragment) {
-        if(uri)
-            memcpy(uri+length, data->fragment, data->fragment_len*sizeof(WCHAR));
-        length += data->fragment_len;
-    }
-
-    if(uri)
-        TRACE("(%p %p): Generated raw uri=%s len=%ld\n", data, uri, debugstr_wn(uri, length), length);
-    else
-        TRACE("(%p %p): Computed raw uri len=%ld\n", data, uri, length);
-
-    return length;
-}
-
-static HRESULT generate_uri(const UriBuilder *builder, const parse_data *data, Uri *uri, DWORD flags) {
-    HRESULT hr;
-    DWORD length = generate_raw_uri(data, NULL, 0);
-    uri->raw_uri = SysAllocStringLen(NULL, length);
-    if(!uri->raw_uri)
-        return E_OUTOFMEMORY;
-
-    generate_raw_uri(data, uri->raw_uri, 0);
-
-    hr = canonicalize_uri(data, uri, flags);
-    if(FAILED(hr)) {
-        if(hr == E_INVALIDARG)
-            return INET_E_INVALID_URL;
-        return hr;
-    }
-
-    uri->create_flags = flags;
-    return S_OK;
-}
-
-static inline Uri* impl_from_IUri(IUri *iface)
-{
-    return CONTAINING_RECORD(iface, Uri, IUri_iface);
-}
-
-static inline void destroy_uri_obj(Uri *This)
-{
-    SysFreeString(This->raw_uri);
-    free(This->canon_uri);
-    free(This);
-}
-
-static HRESULT WINAPI Uri_QueryInterface(IUri *iface, REFIID riid, void **ppv)
-{
-    Uri *This = impl_from_IUri(iface);
-
-    if(IsEqualGUID(&IID_IUnknown, riid)) {
-        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = &This->IUri_iface;
-    }else if(IsEqualGUID(&IID_IUri, riid)) {
-        TRACE("(%p)->(IID_IUri %p)\n", This, ppv);
-        *ppv = &This->IUri_iface;
-    }else if(IsEqualGUID(&IID_IUriBuilderFactory, riid)) {
-        TRACE("(%p)->(IID_IUriBuilderFactory %p)\n", This, ppv);
-        *ppv = &This->IUriBuilderFactory_iface;
-    }else if(IsEqualGUID(&IID_IPersistStream, riid)) {
-        TRACE("(%p)->(IID_IPersistStream %p)\n", This, ppv);
-        *ppv = &This->IPersistStream_iface;
-    }else if(IsEqualGUID(&IID_IMarshal, riid)) {
-        TRACE("(%p)->(IID_IMarshal %p)\n", This, ppv);
-        *ppv = &This->IMarshal_iface;
-    }else if(IsEqualGUID(&IID_IUriObj, riid)) {
-        TRACE("(%p)->(IID_IUriObj %p)\n", This, ppv);
-        *ppv = This;
-        return S_OK;
-    }else {
-        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
-        *ppv = NULL;
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef((IUnknown*)*ppv);
-    return S_OK;
-}
-
-static ULONG WINAPI Uri_AddRef(IUri *iface)
-{
-    Uri *This = impl_from_IUri(iface);
-    LONG ref = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref=%ld\n", This, ref);
-
-    return ref;
-}
-
-static ULONG WINAPI Uri_Release(IUri *iface)
-{
-    Uri *This = impl_from_IUri(iface);
-    LONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref=%ld\n", This, ref);
-
-    if(!ref)
-        destroy_uri_obj(This);
-
-    return ref;
-}
-
-static HRESULT WINAPI Uri_GetPropertyBSTR(IUri *iface, Uri_PROPERTY uriProp, BSTR *pbstrProperty, DWORD dwFlags)
-{
-    Uri *This = impl_from_IUri(iface);
-    HRESULT hres;
-    TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pbstrProperty, dwFlags);
-
-    if(!This->create_flags)
-        return E_UNEXPECTED;
-    if(!pbstrProperty)
-        return E_POINTER;
-
-    if(uriProp > Uri_PROPERTY_STRING_LAST) {
-        /* It only returns S_FALSE for the ZONE property... */
-        if(uriProp == Uri_PROPERTY_ZONE) {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            if(!(*pbstrProperty))
-                return E_OUTOFMEMORY;
-            return S_FALSE;
-        }
-
-        *pbstrProperty = NULL;
-        return E_INVALIDARG;
-    }
-
-    if(dwFlags != 0 && dwFlags != Uri_DISPLAY_NO_FRAGMENT && dwFlags != Uri_PUNYCODE_IDN_HOST
-       && dwFlags != Uri_DISPLAY_IDN_HOST)
-        return E_INVALIDARG;
-
-    if((dwFlags == Uri_DISPLAY_NO_FRAGMENT && uriProp != Uri_PROPERTY_DISPLAY_URI)
-       || (dwFlags == Uri_PUNYCODE_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
-           && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST)
-       || (dwFlags == Uri_DISPLAY_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
-           && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST))
-        return E_INVALIDARG;
-
-    switch(uriProp) {
-    case Uri_PROPERTY_ABSOLUTE_URI:
-        if(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI) {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-        /* Uri_PUNYCODE_IDN_HOST doesn't remove user info containing only "@" and ":@" */
-        else if (dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1) {
-            unsigned int punycode_host_len;
-
-            punycode_host_len = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
-            *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-This->host_len+punycode_host_len);
-            hres = S_OK;
-            if(*pbstrProperty) {
-                memcpy(*pbstrProperty, This->canon_uri, This->host_start*sizeof(WCHAR));
-                IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, *pbstrProperty+This->host_start, punycode_host_len);
-                memcpy(*pbstrProperty+This->host_start+punycode_host_len,
-                       This->canon_uri+This->host_start+This->host_len,
-                       (This->canon_len-This->host_start-This->host_len)*sizeof(WCHAR));
-            }
-        } else {
-            if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1) {
-                if(This->userinfo_len == 0) {
-                    /* Don't include the '@' after the userinfo component. */
-                    *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-1);
-                    hres = S_OK;
-                    if(*pbstrProperty) {
-                        /* Copy everything before it. */
-                        memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
-
-                        /* And everything after it. */
-                        memcpy(*pbstrProperty+This->userinfo_start, This->canon_uri+This->userinfo_start+1,
-                               (This->canon_len-This->userinfo_start-1)*sizeof(WCHAR));
-                    }
-                } else if(This->userinfo_split == 0 && This->userinfo_len == 1) {
-                    /* Don't include the ":@" */
-                    *pbstrProperty = SysAllocStringLen(NULL, This->canon_len-2);
-                    hres = S_OK;
-                    if(*pbstrProperty) {
-                        memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
-                        memcpy(*pbstrProperty+This->userinfo_start, This->canon_uri+This->userinfo_start+2,
-                               (This->canon_len-This->userinfo_start-2)*sizeof(WCHAR));
-                    }
-                } else {
-                    *pbstrProperty = SysAllocString(This->canon_uri);
-                    hres = S_OK;
-                }
-            } else {
-                *pbstrProperty = SysAllocString(This->canon_uri);
-                hres = S_OK;
-            }
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_AUTHORITY:
-        if(This->authority_start > -1) {
-            if(This->port_offset > -1 && is_default_port(This->scheme_type, This->port) &&
-               This->display_modifiers & URI_DISPLAY_NO_DEFAULT_PORT_AUTH)
-                /* Don't include the port in the authority component. */
-                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->authority_start, This->port_offset);
-            else
-                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->authority_start, This->authority_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_DISPLAY_URI:
-        /* The Display URI contains everything except for the userinfo for known
-         * scheme types.
-         */
-        if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1) {
-            unsigned int length = This->canon_len-This->userinfo_len;
-
-            /* Skip fragment if Uri_DISPLAY_NO_FRAGMENT is specified */
-            if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
-                length -= This->fragment_len;
-
-            *pbstrProperty = SysAllocStringLen(NULL, length);
-
-            if(*pbstrProperty) {
-                /* Copy everything before the userinfo over. */
-                memcpy(*pbstrProperty, This->canon_uri, This->userinfo_start*sizeof(WCHAR));
-
-                /* Copy everything after the userinfo over. */
-                length -= This->userinfo_start+1;
-                memcpy(*pbstrProperty+This->userinfo_start,
-                   This->canon_uri+This->userinfo_start+This->userinfo_len+1, length*sizeof(WCHAR));
-            }
-        } else {
-            unsigned int length = This->canon_len;
-
-            /* Skip fragment if Uri_DISPLAY_NO_FRAGMENT is specified */
-            if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
-                length -= This->fragment_len;
-
-            *pbstrProperty = SysAllocStringLen(This->canon_uri, length);
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-        else
-            hres = S_OK;
-
-        break;
-    case Uri_PROPERTY_DOMAIN:
-        if(This->domain_offset > -1) {
-            if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN) {
-                unsigned int punycode_length;
-
-                punycode_length = IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset,
-                                             This->host_len-This->domain_offset, NULL, 0);
-                *pbstrProperty = SysAllocStringLen(NULL, punycode_length);
-                if (*pbstrProperty)
-                    IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset,
-                               This->host_len-This->domain_offset, *pbstrProperty, punycode_length);
-            } else {
-                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start+This->domain_offset,
-                                                   This->host_len-This->domain_offset);
-            }
-
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_EXTENSION:
-        if(This->extension_offset > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start+This->extension_offset,
-                                               This->path_len-This->extension_offset);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_FRAGMENT:
-        if(This->fragment_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->fragment_start, This->fragment_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_HOST:
-        if(This->host_start > -1) {
-            /* The '[' and ']' aren't included for IPv6 addresses. */
-            if(This->host_type == Uri_HOST_IPV6)
-                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start+1, This->host_len-2);
-            else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN) {
-                unsigned int punycode_length;
-
-                punycode_length = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
-                *pbstrProperty = SysAllocStringLen(NULL, punycode_length);
-                if (*pbstrProperty)
-                    IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, *pbstrProperty, punycode_length);
-            }
-            else
-                *pbstrProperty = SysAllocStringLen(This->canon_uri+This->host_start, This->host_len);
-
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_PASSWORD:
-        if(This->userinfo_split > -1) {
-            *pbstrProperty = SysAllocStringLen(
-                This->canon_uri+This->userinfo_start+This->userinfo_split+1,
-                This->userinfo_len-This->userinfo_split-1);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            return E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_PATH:
-        if(This->path_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start, This->path_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_PATH_AND_QUERY:
-        if(This->path_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->path_start, This->path_len+This->query_len);
-            hres = S_OK;
-        } else if(This->query_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->query_start, This->query_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_QUERY:
-        if(This->query_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->query_start, This->query_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_RAW_URI:
-        *pbstrProperty = SysAllocString(This->raw_uri);
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-        else
-            hres = S_OK;
-        break;
-    case Uri_PROPERTY_SCHEME_NAME:
-        if(This->scheme_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri + This->scheme_start, This->scheme_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_USER_INFO:
-        if(This->userinfo_start > -1) {
-            *pbstrProperty = SysAllocStringLen(This->canon_uri+This->userinfo_start, This->userinfo_len);
-            hres = S_OK;
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            hres = E_OUTOFMEMORY;
-
-        break;
-    case Uri_PROPERTY_USER_NAME:
-        if(This->userinfo_start > -1 && This->userinfo_split != 0) {
-            /* If userinfo_split is set, that means a password exists
-             * so the username is only from userinfo_start to userinfo_split.
-             */
-            if(This->userinfo_split > -1) {
-                *pbstrProperty = SysAllocStringLen(This->canon_uri + This->userinfo_start, This->userinfo_split);
-                hres = S_OK;
-            } else {
-                *pbstrProperty = SysAllocStringLen(This->canon_uri + This->userinfo_start, This->userinfo_len);
-                hres = S_OK;
-            }
-        } else {
-            *pbstrProperty = SysAllocStringLen(NULL, 0);
-            hres = S_FALSE;
-        }
-
-        if(!(*pbstrProperty))
-            return E_OUTOFMEMORY;
-
-        break;
-    default:
-        FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pbstrProperty, dwFlags);
-        hres = E_NOTIMPL;
-    }
-
-    return hres;
-}
-
-static HRESULT WINAPI Uri_GetPropertyLength(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
-{
-    Uri *This = impl_from_IUri(iface);
-    HRESULT hres;
-    TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pcchProperty, dwFlags);
-
-    if(!This->create_flags)
-        return E_UNEXPECTED;
-    if(!pcchProperty)
-        return E_INVALIDARG;
-
-    /* Can only return a length for a property if it's a string. */
-    if(uriProp > Uri_PROPERTY_STRING_LAST)
-        return E_INVALIDARG;
-
-    if(dwFlags != 0 && dwFlags != Uri_DISPLAY_NO_FRAGMENT && dwFlags != Uri_PUNYCODE_IDN_HOST
-       && dwFlags != Uri_DISPLAY_IDN_HOST) {
-        *pcchProperty = 0;
-        return E_INVALIDARG;
-    }
-
-    switch(uriProp) {
-    case Uri_PROPERTY_ABSOLUTE_URI:
-        if(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI) {
-            *pcchProperty = 0;
-            hres = S_FALSE;
-        }
-        /* Uri_PUNYCODE_IDN_HOST doesn't remove user info containing only "@" and ":@" */
-        else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1) {
-            unsigned int punycode_host_len = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
-            *pcchProperty = This->canon_len - This->host_len + punycode_host_len;
-            hres = S_OK;
-        } else {
-            if(This->scheme_type != URL_SCHEME_UNKNOWN) {
-                if(This->userinfo_start > -1 && This->userinfo_len == 0)
-                    /* Don't include the '@' in the length. */
-                    *pcchProperty = This->canon_len-1;
-                else if(This->userinfo_start > -1 && This->userinfo_len == 1 &&
-                        This->userinfo_split == 0)
-                    /* Don't include the ":@" in the length. */
-                    *pcchProperty = This->canon_len-2;
-                else
-                    *pcchProperty = This->canon_len;
-            } else
-                *pcchProperty = This->canon_len;
-
-            hres = S_OK;
-        }
-
-        break;
-    case Uri_PROPERTY_AUTHORITY:
-        if(This->port_offset > -1 &&
-           This->display_modifiers & URI_DISPLAY_NO_DEFAULT_PORT_AUTH &&
-           is_default_port(This->scheme_type, This->port))
-            /* Only count up until the port in the authority. */
-            *pcchProperty = This->port_offset;
-        else
-            *pcchProperty = This->authority_len;
-        hres = (This->authority_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_DISPLAY_URI:
-        if(This->scheme_type != URL_SCHEME_UNKNOWN && This->userinfo_start > -1)
-            *pcchProperty = This->canon_len-This->userinfo_len-1;
-        else
-            *pcchProperty = This->canon_len;
-
-        if(dwFlags == Uri_DISPLAY_NO_FRAGMENT && This->fragment_start > -1)
-            *pcchProperty -= This->fragment_len;
-
-        hres = S_OK;
-        break;
-    case Uri_PROPERTY_DOMAIN:
-        if(This->domain_offset > -1) {
-            if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN)
-                *pcchProperty = IdnToAscii(0, This->canon_uri+This->host_start+This->domain_offset, This->host_len-This->domain_offset, NULL, 0);
-            else
-                *pcchProperty = This->host_len - This->domain_offset;
-        }
-        else
-            *pcchProperty = 0;
-
-        hres = (This->domain_offset > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_EXTENSION:
-        if(This->extension_offset > -1) {
-            *pcchProperty = This->path_len - This->extension_offset;
-            hres = S_OK;
-        } else {
-            *pcchProperty = 0;
-            hres = S_FALSE;
-        }
-
-        break;
-    case Uri_PROPERTY_FRAGMENT:
-        *pcchProperty = This->fragment_len;
-        hres = (This->fragment_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_HOST:
-        *pcchProperty = This->host_len;
-
-        /* '[' and ']' aren't included in the length. */
-        if(This->host_type == Uri_HOST_IPV6)
-            *pcchProperty -= 2;
-        else if(dwFlags == Uri_PUNYCODE_IDN_HOST && This->host_type == Uri_HOST_IDN && This->host_start > -1)
-            *pcchProperty = IdnToAscii(0, This->canon_uri+This->host_start, This->host_len, NULL, 0);
-
-        hres = (This->host_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_PASSWORD:
-        *pcchProperty = (This->userinfo_split > -1) ? This->userinfo_len-This->userinfo_split-1 : 0;
-        hres = (This->userinfo_split > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_PATH:
-        *pcchProperty = This->path_len;
-        hres = (This->path_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_PATH_AND_QUERY:
-        *pcchProperty = This->path_len+This->query_len;
-        hres = (This->path_start > -1 || This->query_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_QUERY:
-        *pcchProperty = This->query_len;
-        hres = (This->query_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_RAW_URI:
-        *pcchProperty = SysStringLen(This->raw_uri);
-        hres = S_OK;
-        break;
-    case Uri_PROPERTY_SCHEME_NAME:
-        *pcchProperty = This->scheme_len;
-        hres = (This->scheme_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_USER_INFO:
-        *pcchProperty = This->userinfo_len;
-        hres = (This->userinfo_start > -1) ? S_OK : S_FALSE;
-        break;
-    case Uri_PROPERTY_USER_NAME:
-        *pcchProperty = (This->userinfo_split > -1) ? This->userinfo_split : This->userinfo_len;
-        if(This->userinfo_split == 0)
-            hres = S_FALSE;
-        else
-            hres = (This->userinfo_start > -1) ? S_OK : S_FALSE;
-        break;
-    default:
-        FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pcchProperty, dwFlags);
-        hres = E_NOTIMPL;
-    }
-
-    if(hres == S_OK
-       && ((dwFlags == Uri_DISPLAY_NO_FRAGMENT && uriProp != Uri_PROPERTY_DISPLAY_URI)
-            || (dwFlags == Uri_PUNYCODE_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
-                && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST)
-            || (dwFlags == Uri_DISPLAY_IDN_HOST && uriProp != Uri_PROPERTY_ABSOLUTE_URI
-                && uriProp != Uri_PROPERTY_DOMAIN && uriProp != Uri_PROPERTY_HOST))) {
-        *pcchProperty = 0;
-        hres = E_INVALIDARG;
-    }
-
-    return hres;
-}
-
-static HRESULT WINAPI Uri_GetPropertyDWORD(IUri *iface, Uri_PROPERTY uriProp, DWORD *pcchProperty, DWORD dwFlags)
-{
-    Uri *This = impl_from_IUri(iface);
-    HRESULT hres;
-
-    TRACE("(%p %s)->(%d %p %lx)\n", This, debugstr_w(This->canon_uri), uriProp, pcchProperty, dwFlags);
-
-    if(!This->create_flags)
-        return E_UNEXPECTED;
-    if(!pcchProperty)
-        return E_INVALIDARG;
-
-    /* Microsoft's implementation for the ZONE property of a URI seems to be lacking...
-     * From what I can tell, instead of checking which URLZONE the URI belongs to it
-     * simply assigns URLZONE_INVALID and returns E_NOTIMPL. This also applies to the GetZone
-     * function.
-     */
-    if(uriProp == Uri_PROPERTY_ZONE) {
-        *pcchProperty = URLZONE_INVALID;
-        return E_NOTIMPL;
-    }
-
-    if(uriProp < Uri_PROPERTY_DWORD_START) {
-        *pcchProperty = 0;
-        return E_INVALIDARG;
-    }
-
-    switch(uriProp) {
-    case Uri_PROPERTY_HOST_TYPE:
-        *pcchProperty = This->host_type;
-        hres = S_OK;
-        break;
-    case Uri_PROPERTY_PORT:
-        if(!This->has_port) {
-            *pcchProperty = 0;
-            hres = S_FALSE;
-        } else {
-            *pcchProperty = This->port;
-            hres = S_OK;
-        }
-
-        break;
-    case Uri_PROPERTY_SCHEME:
-        *pcchProperty = This->scheme_type;
-        hres = S_OK;
-        break;
-    default:
-        FIXME("(%p)->(%d %p %lx)\n", This, uriProp, pcchProperty, dwFlags);
-        hres = E_NOTIMPL;
-    }
-
-    return hres;
-}
-
-static HRESULT WINAPI Uri_HasProperty(IUri *iface, Uri_PROPERTY uriProp, BOOL *pfHasProperty)
-{
-    Uri *This = impl_from_IUri(iface);
-
-    TRACE("(%p %s)->(%d %p)\n", This, debugstr_w(This->canon_uri), uriProp, pfHasProperty);
-
-    if(!pfHasProperty)
-        return E_INVALIDARG;
-
-    switch(uriProp) {
-    case Uri_PROPERTY_ABSOLUTE_URI:
-        *pfHasProperty = !(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI);
-        break;
-    case Uri_PROPERTY_AUTHORITY:
-        *pfHasProperty = This->authority_start > -1;
-        break;
-    case Uri_PROPERTY_DISPLAY_URI:
-        *pfHasProperty = TRUE;
-        break;
-    case Uri_PROPERTY_DOMAIN:
-        *pfHasProperty = This->domain_offset > -1;
-        break;
-    case Uri_PROPERTY_EXTENSION:
-        *pfHasProperty = This->extension_offset > -1;
-        break;
-    case Uri_PROPERTY_FRAGMENT:
-        *pfHasProperty = This->fragment_start > -1;
-        break;
-    case Uri_PROPERTY_HOST:
-        *pfHasProperty = This->host_start > -1;
-        break;
-    case Uri_PROPERTY_PASSWORD:
-        *pfHasProperty = This->userinfo_split > -1;
-        break;
-    case Uri_PROPERTY_PATH:
-        *pfHasProperty = This->path_start > -1;
-        break;
-    case Uri_PROPERTY_PATH_AND_QUERY:
-        *pfHasProperty = (This->path_start > -1 || This->query_start > -1);
-        break;
-    case Uri_PROPERTY_QUERY:
-        *pfHasProperty = This->query_start > -1;
-        break;
-    case Uri_PROPERTY_RAW_URI:
-        *pfHasProperty = TRUE;
-        break;
-    case Uri_PROPERTY_SCHEME_NAME:
-        *pfHasProperty = This->scheme_start > -1;
-        break;
-    case Uri_PROPERTY_USER_INFO:
-        *pfHasProperty = This->userinfo_start > -1;
-        break;
-    case Uri_PROPERTY_USER_NAME:
-        if(This->userinfo_split == 0)
-            *pfHasProperty = FALSE;
-        else
-            *pfHasProperty = This->userinfo_start > -1;
-        break;
-    case Uri_PROPERTY_HOST_TYPE:
-        *pfHasProperty = TRUE;
-        break;
-    case Uri_PROPERTY_PORT:
-        *pfHasProperty = This->has_port;
-        break;
-    case Uri_PROPERTY_SCHEME:
-        *pfHasProperty = TRUE;
-        break;
-    case Uri_PROPERTY_ZONE:
-        *pfHasProperty = FALSE;
-        break;
-    default:
-        FIXME("(%p)->(%d %p): Unsupported property type.\n", This, uriProp, pfHasProperty);
-        return E_NOTIMPL;
-    }
-
-    return S_OK;
-}
-
-static HRESULT WINAPI Uri_GetAbsoluteUri(IUri *iface, BSTR *pstrAbsoluteUri)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrAbsoluteUri);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_ABSOLUTE_URI, pstrAbsoluteUri, 0);
-}
-
-static HRESULT WINAPI Uri_GetAuthority(IUri *iface, BSTR *pstrAuthority)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrAuthority);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_AUTHORITY, pstrAuthority, 0);
-}
-
-static HRESULT WINAPI Uri_GetDisplayUri(IUri *iface, BSTR *pstrDisplayUri)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrDisplayUri);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_DISPLAY_URI, pstrDisplayUri, 0);
-}
-
-static HRESULT WINAPI Uri_GetDomain(IUri *iface, BSTR *pstrDomain)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrDomain);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_DOMAIN, pstrDomain, 0);
-}
-
-static HRESULT WINAPI Uri_GetExtension(IUri *iface, BSTR *pstrExtension)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrExtension);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_EXTENSION, pstrExtension, 0);
-}
-
-static HRESULT WINAPI Uri_GetFragment(IUri *iface, BSTR *pstrFragment)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrFragment);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_FRAGMENT, pstrFragment, 0);
-}
-
-static HRESULT WINAPI Uri_GetHost(IUri *iface, BSTR *pstrHost)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrHost);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_HOST, pstrHost, 0);
-}
-
-static HRESULT WINAPI Uri_GetPassword(IUri *iface, BSTR *pstrPassword)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrPassword);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PASSWORD, pstrPassword, 0);
-}
-
-static HRESULT WINAPI Uri_GetPath(IUri *iface, BSTR *pstrPath)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrPath);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PATH, pstrPath, 0);
-}
-
-static HRESULT WINAPI Uri_GetPathAndQuery(IUri *iface, BSTR *pstrPathAndQuery)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrPathAndQuery);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_PATH_AND_QUERY, pstrPathAndQuery, 0);
-}
-
-static HRESULT WINAPI Uri_GetQuery(IUri *iface, BSTR *pstrQuery)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrQuery);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_QUERY, pstrQuery, 0);
-}
-
-static HRESULT WINAPI Uri_GetRawUri(IUri *iface, BSTR *pstrRawUri)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrRawUri);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_RAW_URI, pstrRawUri, 0);
-}
-
-static HRESULT WINAPI Uri_GetSchemeName(IUri *iface, BSTR *pstrSchemeName)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrSchemeName);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_SCHEME_NAME, pstrSchemeName, 0);
-}
-
-static HRESULT WINAPI Uri_GetUserInfo(IUri *iface, BSTR *pstrUserInfo)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrUserInfo);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_USER_INFO, pstrUserInfo, 0);
-}
-
-static HRESULT WINAPI Uri_GetUserName(IUri *iface, BSTR *pstrUserName)
-{
-    TRACE("(%p)->(%p)\n", iface, pstrUserName);
-    return IUri_GetPropertyBSTR(iface, Uri_PROPERTY_USER_NAME, pstrUserName, 0);
-}
-
-static HRESULT WINAPI Uri_GetHostType(IUri *iface, DWORD *pdwHostType)
-{
-    TRACE("(%p)->(%p)\n", iface, pdwHostType);
-    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_HOST_TYPE, pdwHostType, 0);
-}
-
-static HRESULT WINAPI Uri_GetPort(IUri *iface, DWORD *pdwPort)
-{
-    TRACE("(%p)->(%p)\n", iface, pdwPort);
-    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_PORT, pdwPort, 0);
-}
-
-static HRESULT WINAPI Uri_GetScheme(IUri *iface, DWORD *pdwScheme)
-{
-    TRACE("(%p)->(%p)\n", iface, pdwScheme);
-    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_SCHEME, pdwScheme, 0);
-}
-
-static HRESULT WINAPI Uri_GetZone(IUri *iface, DWORD *pdwZone)
-{
-    TRACE("(%p)->(%p)\n", iface, pdwZone);
-    return IUri_GetPropertyDWORD(iface, Uri_PROPERTY_ZONE,pdwZone, 0);
-}
-
-static HRESULT WINAPI Uri_GetProperties(IUri *iface, DWORD *pdwProperties)
-{
-    Uri *This = impl_from_IUri(iface);
-    TRACE("(%p %s)->(%p)\n", This, debugstr_w(This->canon_uri), pdwProperties);
-
-    if(!This->create_flags)
-        return E_UNEXPECTED;
-    if(!pdwProperties)
-        return E_INVALIDARG;
-
-    /* All URIs have these. */
-    *pdwProperties = Uri_HAS_DISPLAY_URI|Uri_HAS_RAW_URI|Uri_HAS_SCHEME|Uri_HAS_HOST_TYPE;
-
-    if(!(This->display_modifiers & URI_DISPLAY_NO_ABSOLUTE_URI))
-        *pdwProperties |= Uri_HAS_ABSOLUTE_URI;
-
-    if(This->scheme_start > -1)
-        *pdwProperties |= Uri_HAS_SCHEME_NAME;
-
-    if(This->authority_start > -1) {
-        *pdwProperties |= Uri_HAS_AUTHORITY;
-        if(This->userinfo_start > -1) {
-            *pdwProperties |= Uri_HAS_USER_INFO;
-            if(This->userinfo_split != 0)
-                *pdwProperties |= Uri_HAS_USER_NAME;
-        }
-        if(This->userinfo_split > -1)
-            *pdwProperties |= Uri_HAS_PASSWORD;
-        if(This->host_start > -1)
-            *pdwProperties |= Uri_HAS_HOST;
-        if(This->domain_offset > -1)
-            *pdwProperties |= Uri_HAS_DOMAIN;
-    }
-
-    if(This->has_port)
-        *pdwProperties |= Uri_HAS_PORT;
-    if(This->path_start > -1)
-        *pdwProperties |= Uri_HAS_PATH|Uri_HAS_PATH_AND_QUERY;
-    if(This->query_start > -1)
-        *pdwProperties |= Uri_HAS_QUERY|Uri_HAS_PATH_AND_QUERY;
-
-    if(This->extension_offset > -1)
-        *pdwProperties |= Uri_HAS_EXTENSION;
-
-    if(This->fragment_start > -1)
-        *pdwProperties |= Uri_HAS_FRAGMENT;
-
-    return S_OK;
-}
-
-static HRESULT WINAPI Uri_IsEqual(IUri *iface, IUri *pUri, BOOL *pfEqual)
-{
-    Uri *This = impl_from_IUri(iface);
-    Uri *other;
-
-    TRACE("(%p %s)->(%p %p)\n", This, debugstr_w(This->canon_uri), pUri, pfEqual);
-
-    if(!This->create_flags)
-        return E_UNEXPECTED;
-    if(!pfEqual)
-        return E_POINTER;
-
-    if(!pUri) {
-        *pfEqual = FALSE;
-
-        /* For some reason Windows returns S_OK here... */
-        return S_OK;
-    }
-
-    /* Try to convert it to a Uri (allows for a more simple comparison). */
-    if(!(other = get_uri_obj(pUri))) {
-        FIXME("(%p)->(%p %p) No support for unknown IUri's yet.\n", iface, pUri, pfEqual);
-        return E_NOTIMPL;
-    }
-
-    TRACE("comparing to %s\n", debugstr_w(other->canon_uri));
-    return compare_uris(This, other, pfEqual);
-}
-
-static const IUriVtbl UriVtbl = {
-    Uri_QueryInterface,
-    Uri_AddRef,
-    Uri_Release,
-    Uri_GetPropertyBSTR,
-    Uri_GetPropertyLength,
-    Uri_GetPropertyDWORD,
-    Uri_HasProperty,
-    Uri_GetAbsoluteUri,
-    Uri_GetAuthority,
-    Uri_GetDisplayUri,
-    Uri_GetDomain,
-    Uri_GetExtension,
-    Uri_GetFragment,
-    Uri_GetHost,
-    Uri_GetPassword,
-    Uri_GetPath,
-    Uri_GetPathAndQuery,
-    Uri_GetQuery,
-    Uri_GetRawUri,
-    Uri_GetSchemeName,
-    Uri_GetUserInfo,
-    Uri_GetUserName,
-    Uri_GetHostType,
-    Uri_GetPort,
-    Uri_GetScheme,
-    Uri_GetZone,
-    Uri_GetProperties,
-    Uri_IsEqual
-};
-
-static inline Uri* impl_from_IUriBuilderFactory(IUriBuilderFactory *iface)
-{
-    return CONTAINING_RECORD(iface, Uri, IUriBuilderFactory_iface);
-}
-
-static HRESULT WINAPI UriBuilderFactory_QueryInterface(IUriBuilderFactory *iface, REFIID riid, void **ppv)
-{
-    Uri *This = impl_from_IUriBuilderFactory(iface);
-    return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
-}
-
-static ULONG WINAPI UriBuilderFactory_AddRef(IUriBuilderFactory *iface)
-{
-    Uri *This = impl_from_IUriBuilderFactory(iface);
-    return IUri_AddRef(&This->IUri_iface);
-}
-
-static ULONG WINAPI UriBuilderFactory_Release(IUriBuilderFactory *iface)
-{
-    Uri *This = impl_from_IUriBuilderFactory(iface);
-    return IUri_Release(&This->IUri_iface);
-}
-
-static HRESULT WINAPI UriBuilderFactory_CreateIUriBuilder(IUriBuilderFactory *iface,
-                                                          DWORD dwFlags,
-                                                          DWORD_PTR dwReserved,
-                                                          IUriBuilder **ppIUriBuilder)
-{
-    Uri *This = impl_from_IUriBuilderFactory(iface);
-    TRACE("(%p)->(%08lx %08Ix %p)\n", This, dwFlags, dwReserved, ppIUriBuilder);
-
-    if(!ppIUriBuilder)
-        return E_POINTER;
-
-    if(dwFlags || dwReserved) {
-        *ppIUriBuilder = NULL;
-        return E_INVALIDARG;
-    }
-
-    return CreateIUriBuilder(NULL, 0, 0, ppIUriBuilder);
-}
-
-static HRESULT WINAPI UriBuilderFactory_CreateInitializedIUriBuilder(IUriBuilderFactory *iface,
-                                                                     DWORD dwFlags,
-                                                                     DWORD_PTR dwReserved,
-                                                                     IUriBuilder **ppIUriBuilder)
-{
-    Uri *This = impl_from_IUriBuilderFactory(iface);
-    TRACE("(%p)->(%08lx %08Ix %p)\n", This, dwFlags, dwReserved, ppIUriBuilder);
-
-    if(!ppIUriBuilder)
-        return E_POINTER;
-
-    if(dwFlags || dwReserved) {
-        *ppIUriBuilder = NULL;
-        return E_INVALIDARG;
-    }
-
-    return CreateIUriBuilder(&This->IUri_iface, 0, 0, ppIUriBuilder);
-}
-
-static const IUriBuilderFactoryVtbl UriBuilderFactoryVtbl = {
-    UriBuilderFactory_QueryInterface,
-    UriBuilderFactory_AddRef,
-    UriBuilderFactory_Release,
-    UriBuilderFactory_CreateIUriBuilder,
-    UriBuilderFactory_CreateInitializedIUriBuilder
-};
-
-static inline Uri* impl_from_IPersistStream(IPersistStream *iface)
-{
-    return CONTAINING_RECORD(iface, Uri, IPersistStream_iface);
-}
-
-static HRESULT WINAPI PersistStream_QueryInterface(IPersistStream *iface, REFIID riid, void **ppvObject)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    return IUri_QueryInterface(&This->IUri_iface, riid, ppvObject);
-}
-
-static ULONG WINAPI PersistStream_AddRef(IPersistStream *iface)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    return IUri_AddRef(&This->IUri_iface);
-}
-
-static ULONG WINAPI PersistStream_Release(IPersistStream *iface)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    return IUri_Release(&This->IUri_iface);
-}
-
-static HRESULT WINAPI PersistStream_GetClassID(IPersistStream *iface, CLSID *pClassID)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    TRACE("(%p)->(%p)\n", This, pClassID);
-
-    if(!pClassID)
-        return E_INVALIDARG;
-
-    *pClassID = CLSID_CUri;
-    return S_OK;
-}
-
-static HRESULT WINAPI PersistStream_IsDirty(IPersistStream *iface)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    TRACE("(%p)\n", This);
-    return S_FALSE;
-}
-
-struct persist_uri {
-    DWORD size;
-    DWORD unk1[2];
-    DWORD create_flags;
-    DWORD unk2[3];
-    DWORD fields_no;
-    BYTE data[1];
-};
-
-static HRESULT WINAPI PersistStream_Load(IPersistStream *iface, IStream *pStm)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    struct persist_uri *data;
-    parse_data parse;
-    DWORD size;
-    HRESULT hr;
-
-    TRACE("(%p)->(%p)\n", This, pStm);
-
-    if(This->create_flags)
-        return E_UNEXPECTED;
-    if(!pStm)
-        return E_INVALIDARG;
-
-    hr = IStream_Read(pStm, &size, sizeof(DWORD), NULL);
-    if(FAILED(hr))
-        return hr;
-    data = malloc(size);
-    if(!data)
-        return E_OUTOFMEMORY;
-    hr = IStream_Read(pStm, data->unk1, size-sizeof(DWORD)-2, NULL);
-    if(FAILED(hr)) {
-        free(data);
-        return hr;
-    }
-
-    if(size < sizeof(struct persist_uri)) {
-        free(data);
-        return S_OK;
-    }
-
-    if(*(DWORD*)data->data != Uri_PROPERTY_RAW_URI) {
-        free(data);
-        ERR("Can't find raw_uri\n");
-        return E_UNEXPECTED;
-    }
-
-    This->raw_uri = SysAllocString((WCHAR*)(data->data+sizeof(DWORD)*2));
-    if(!This->raw_uri) {
-        free(data);
-        return E_OUTOFMEMORY;
-    }
-    This->create_flags = data->create_flags;
-    free(data);
-    TRACE("%lx %s\n", This->create_flags, debugstr_w(This->raw_uri));
-
-    memset(&parse, 0, sizeof(parse_data));
-    parse.uri = This->raw_uri;
-    if(!parse_uri(&parse, This->create_flags)) {
-        SysFreeString(This->raw_uri);
-        This->create_flags = 0;
-        return E_UNEXPECTED;
-    }
-
-    hr = canonicalize_uri(&parse, This, This->create_flags);
-    if(FAILED(hr)) {
-        SysFreeString(This->raw_uri);
-        This->create_flags = 0;
-        return hr;
-    }
-
-    return S_OK;
-}
-
-static inline BYTE* persist_stream_add_strprop(Uri *This, BYTE *p, DWORD type, DWORD len, WCHAR *data)
-{
-    len *= sizeof(WCHAR);
-    *(DWORD*)p = type;
-    p += sizeof(DWORD);
-    *(DWORD*)p = len+sizeof(WCHAR);
-    p += sizeof(DWORD);
-    memcpy(p, data, len);
-    p += len;
-    *(WCHAR*)p = 0;
-    return p+sizeof(WCHAR);
-}
-
-static inline void persist_stream_save(Uri *This, IStream *pStm, BOOL marshal, struct persist_uri *data)
-{
-    BYTE *p = NULL;
-
-    data->create_flags = This->create_flags;
-
-    if(This->create_flags) {
-        data->fields_no = 1;
-        p = persist_stream_add_strprop(This, data->data, Uri_PROPERTY_RAW_URI,
-                SysStringLen(This->raw_uri), This->raw_uri);
-    }
-    if(This->scheme_type!=URL_SCHEME_HTTP && This->scheme_type!=URL_SCHEME_HTTPS
-            && This->scheme_type!=URL_SCHEME_FTP)
-        return;
-
-    if(This->fragment_len) {
-        data->fields_no++;
-        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_FRAGMENT,
-                This->fragment_len, This->canon_uri+This->fragment_start);
-    }
-
-    if(This->host_len) {
-        data->fields_no++;
-        if(This->host_type == Uri_HOST_IPV6)
-            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_HOST,
-                    This->host_len-2, This->canon_uri+This->host_start+1);
-        else
-            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_HOST,
-                    This->host_len, This->canon_uri+This->host_start);
-    }
-
-    if(This->userinfo_split > -1) {
-        data->fields_no++;
-        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PASSWORD,
-                This->userinfo_len-This->userinfo_split-1,
-                This->canon_uri+This->userinfo_start+This->userinfo_split+1);
-    }
-
-    if(This->path_len) {
-        data->fields_no++;
-        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PATH,
-                This->path_len, This->canon_uri+This->path_start);
-    } else if(marshal) {
-        WCHAR no_path = '/';
-        data->fields_no++;
-        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_PATH, 1, &no_path);
-    }
-
-    if(This->has_port) {
-        data->fields_no++;
-        *(DWORD*)p = Uri_PROPERTY_PORT;
-        p += sizeof(DWORD);
-        *(DWORD*)p = sizeof(DWORD);
-        p += sizeof(DWORD);
-        *(DWORD*)p = This->port;
-        p += sizeof(DWORD);
-    }
-
-    if(This->query_len) {
-        data->fields_no++;
-        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_QUERY,
-                This->query_len, This->canon_uri+This->query_start);
-    }
-
-    if(This->scheme_len) {
-        data->fields_no++;
-        p = persist_stream_add_strprop(This, p, Uri_PROPERTY_SCHEME_NAME,
-                This->scheme_len, This->canon_uri+This->scheme_start);
-    }
-
-    if(This->userinfo_start>-1 && This->userinfo_split!=0) {
-        data->fields_no++;
-        if(This->userinfo_split > -1)
-            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_USER_NAME,
-                    This->userinfo_split, This->canon_uri+This->userinfo_start);
-        else
-            p = persist_stream_add_strprop(This, p, Uri_PROPERTY_USER_NAME,
-                    This->userinfo_len, This->canon_uri+This->userinfo_start);
-    }
-}
-
-static HRESULT WINAPI PersistStream_Save(IPersistStream *iface, IStream *pStm, BOOL fClearDirty)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    struct persist_uri *data;
-    ULARGE_INTEGER size;
-    HRESULT hres;
-
-    TRACE("(%p)->(%p %x)\n", This, pStm, fClearDirty);
-
-    if(!pStm)
-        return E_INVALIDARG;
-
-    hres = IPersistStream_GetSizeMax(&This->IPersistStream_iface, &size);
-    if(FAILED(hres))
-        return hres;
-
-    data = calloc(1, size.u.LowPart);
-    if(!data)
-        return E_OUTOFMEMORY;
-    data->size = size.u.LowPart;
-    persist_stream_save(This, pStm, FALSE, data);
-
-    hres = IStream_Write(pStm, data, data->size-2, NULL);
-    free(data);
-    return hres;
-}
-
-static HRESULT WINAPI PersistStream_GetSizeMax(IPersistStream *iface, ULARGE_INTEGER *pcbSize)
-{
-    Uri *This = impl_from_IPersistStream(iface);
-    TRACE("(%p)->(%p)\n", This, pcbSize);
-
-    if(!pcbSize)
-        return E_INVALIDARG;
-
-    pcbSize->u.LowPart = 2+sizeof(struct persist_uri);
-    pcbSize->u.HighPart = 0;
-    if(This->create_flags)
-        pcbSize->u.LowPart += (SysStringLen(This->raw_uri)+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    else /* there's no place for fields no */
-        pcbSize->u.LowPart -= sizeof(DWORD);
-    if(This->scheme_type!=URL_SCHEME_HTTP && This->scheme_type!=URL_SCHEME_HTTPS
-            && This->scheme_type!=URL_SCHEME_FTP)
-        return S_OK;
-
-    if(This->fragment_len)
-        pcbSize->u.LowPart += (This->fragment_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    if(This->host_len) {
-        if(This->host_type == Uri_HOST_IPV6)
-            pcbSize->u.LowPart += (This->host_len-1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-        else
-            pcbSize->u.LowPart += (This->host_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    }
-    if(This->userinfo_split > -1)
-        pcbSize->u.LowPart += (This->userinfo_len-This->userinfo_split)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    if(This->path_len)
-        pcbSize->u.LowPart += (This->path_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    if(This->has_port)
-        pcbSize->u.LowPart += 3*sizeof(DWORD);
-    if(This->query_len)
-        pcbSize->u.LowPart += (This->query_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    if(This->scheme_len)
-        pcbSize->u.LowPart += (This->scheme_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    if(This->userinfo_start>-1 && This->userinfo_split!=0) {
-        if(This->userinfo_split > -1)
-            pcbSize->u.LowPart += (This->userinfo_split+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-        else
-            pcbSize->u.LowPart += (This->userinfo_len+1)*sizeof(WCHAR) + 2*sizeof(DWORD);
-    }
-    return S_OK;
-}
-
-static const IPersistStreamVtbl PersistStreamVtbl = {
-    PersistStream_QueryInterface,
-    PersistStream_AddRef,
-    PersistStream_Release,
-    PersistStream_GetClassID,
-    PersistStream_IsDirty,
-    PersistStream_Load,
-    PersistStream_Save,
-    PersistStream_GetSizeMax
-};
-
-static inline Uri* impl_from_IMarshal(IMarshal *iface)
-{
-    return CONTAINING_RECORD(iface, Uri, IMarshal_iface);
-}
-
-static HRESULT WINAPI Marshal_QueryInterface(IMarshal *iface, REFIID riid, void **ppvObject)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    return IUri_QueryInterface(&This->IUri_iface, riid, ppvObject);
-}
-
-static ULONG WINAPI Marshal_AddRef(IMarshal *iface)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    return IUri_AddRef(&This->IUri_iface);
-}
-
-static ULONG WINAPI Marshal_Release(IMarshal *iface)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    return IUri_Release(&This->IUri_iface);
-}
-
-static HRESULT WINAPI Marshal_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
-        DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, CLSID *pCid)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    TRACE("(%p)->(%s %p %lx %p %lx %p)\n", This, debugstr_guid(riid), pv,
-            dwDestContext, pvDestContext, mshlflags, pCid);
-
-    if(!pCid || (dwDestContext!=MSHCTX_LOCAL && dwDestContext!=MSHCTX_NOSHAREDMEM
-                && dwDestContext!=MSHCTX_INPROC))
-        return E_INVALIDARG;
-
-    *pCid = CLSID_CUri;
-    return S_OK;
-}
-
-struct inproc_marshal_uri {
-    DWORD size;
-    DWORD mshlflags;
-    DWORD unk[4]; /* process identifier? */
-    Uri *uri;
-};
-
-static HRESULT WINAPI Marshal_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
-        DWORD dwDestContext, void *pvDestContext, DWORD mshlflags, DWORD *pSize)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    ULARGE_INTEGER size;
-    HRESULT hres;
-    TRACE("(%p)->(%s %p %lx %p %lx %p)\n", This, debugstr_guid(riid), pv,
-            dwDestContext, pvDestContext, mshlflags, pSize);
-
-    if(!pSize || (dwDestContext!=MSHCTX_LOCAL && dwDestContext!=MSHCTX_NOSHAREDMEM
-                && dwDestContext!=MSHCTX_INPROC))
-        return E_INVALIDARG;
-
-    if(dwDestContext == MSHCTX_INPROC) {
-        *pSize = sizeof(struct inproc_marshal_uri);
-        return S_OK;
-    }
-
-    hres = IPersistStream_GetSizeMax(&This->IPersistStream_iface, &size);
-    if(FAILED(hres))
-        return hres;
-    if(!This->path_len && (This->scheme_type==URL_SCHEME_HTTP
-                || This->scheme_type==URL_SCHEME_HTTPS
-                || This->scheme_type==URL_SCHEME_FTP))
-        size.u.LowPart += 3*sizeof(DWORD);
-    *pSize = size.u.LowPart+2*sizeof(DWORD);
-    return S_OK;
-}
-
-static HRESULT WINAPI Marshal_MarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid,
-        void *pv, DWORD dwDestContext, void *pvDestContext, DWORD mshlflags)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    DWORD *data;
-    DWORD size;
-    HRESULT hres;
-
-    TRACE("(%p)->(%p %s %p %lx %p %lx)\n", This, pStm, debugstr_guid(riid), pv,
-            dwDestContext, pvDestContext, mshlflags);
-
-    if(!pStm || mshlflags!=MSHLFLAGS_NORMAL || (dwDestContext!=MSHCTX_LOCAL
-                && dwDestContext!=MSHCTX_NOSHAREDMEM && dwDestContext!=MSHCTX_INPROC))
-        return E_INVALIDARG;
-
-    if(dwDestContext == MSHCTX_INPROC) {
-        struct inproc_marshal_uri data;
-
-        data.size = sizeof(data);
-        data.mshlflags = MSHCTX_INPROC;
-        data.unk[0] = 0;
-        data.unk[1] = 0;
-        data.unk[2] = 0;
-        data.unk[3] = 0;
-        data.uri = This;
-
-        hres = IStream_Write(pStm, &data, data.size, NULL);
-        if(FAILED(hres))
-            return hres;
-
-        IUri_AddRef(&This->IUri_iface);
-        return S_OK;
-    }
-
-    hres = IMarshal_GetMarshalSizeMax(iface, riid, pv, dwDestContext,
-            pvDestContext, mshlflags, &size);
-    if(FAILED(hres))
-        return hres;
-
-    data = calloc(1, size);
-    if(!data)
-        return E_OUTOFMEMORY;
-
-    data[0] = size;
-    data[1] = dwDestContext;
-    data[2] = size-2*sizeof(DWORD);
-    persist_stream_save(This, pStm, TRUE, (struct persist_uri*)(data+2));
-
-    hres = IStream_Write(pStm, data, data[0]-2, NULL);
-    free(data);
-    return hres;
-}
-
-static HRESULT WINAPI Marshal_UnmarshalInterface(IMarshal *iface,
-        IStream *pStm, REFIID riid, void **ppv)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    DWORD header[2];
-    HRESULT hres;
-
-    TRACE("(%p)->(%p %s %p)\n", This, pStm, debugstr_guid(riid), ppv);
-
-    if(This->create_flags)
-        return E_UNEXPECTED;
-    if(!pStm || !riid || !ppv)
-        return E_INVALIDARG;
-
-    hres = IStream_Read(pStm, header, sizeof(header), NULL);
-    if(FAILED(hres))
-        return hres;
-
-    if(header[1]!=MSHCTX_LOCAL && header[1]!=MSHCTX_NOSHAREDMEM
-            && header[1]!=MSHCTX_INPROC)
-        return E_UNEXPECTED;
-
-    if(header[1] == MSHCTX_INPROC) {
-        struct inproc_marshal_uri data;
-        parse_data parse;
-
-        hres = IStream_Read(pStm, data.unk, sizeof(data)-2*sizeof(DWORD), NULL);
-        if(FAILED(hres))
-            return hres;
-
-        This->raw_uri = SysAllocString(data.uri->raw_uri);
-        if(!This->raw_uri) {
-            return E_OUTOFMEMORY;
-        }
-
-        memset(&parse, 0, sizeof(parse_data));
-        parse.uri = This->raw_uri;
-
-        if(!parse_uri(&parse, data.uri->create_flags))
-            return E_INVALIDARG;
-
-        hres = canonicalize_uri(&parse, This, data.uri->create_flags);
-        if(FAILED(hres))
-            return hres;
-
-        This->create_flags = data.uri->create_flags;
-        IUri_Release(&data.uri->IUri_iface);
-
-        return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
-    }
-
-    hres = IPersistStream_Load(&This->IPersistStream_iface, pStm);
-    if(FAILED(hres))
-        return hres;
-
-    return IUri_QueryInterface(&This->IUri_iface, riid, ppv);
-}
-
-static HRESULT WINAPI Marshal_ReleaseMarshalData(IMarshal *iface, IStream *pStm)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    LARGE_INTEGER off;
-    DWORD header[2];
-    HRESULT hres;
-
-    TRACE("(%p)->(%p)\n", This, pStm);
-
-    if(!pStm)
-        return E_INVALIDARG;
-
-    hres = IStream_Read(pStm, header, 2*sizeof(DWORD), NULL);
-    if(FAILED(hres))
-        return hres;
-
-    if(header[1] == MSHCTX_INPROC) {
-        struct inproc_marshal_uri data;
-
-        hres = IStream_Read(pStm, data.unk, sizeof(data)-2*sizeof(DWORD), NULL);
-        if(FAILED(hres))
-            return hres;
-
-        IUri_Release(&data.uri->IUri_iface);
-        return S_OK;
-    }
-
-    off.u.LowPart = header[0]-sizeof(header)-2;
-    off.u.HighPart = 0;
-    return IStream_Seek(pStm, off, STREAM_SEEK_CUR, NULL);
-}
-
-static HRESULT WINAPI Marshal_DisconnectObject(IMarshal *iface, DWORD dwReserved)
-{
-    Uri *This = impl_from_IMarshal(iface);
-    TRACE("(%p)->(%lx)\n", This, dwReserved);
-    return S_OK;
-}
-
-static const IMarshalVtbl MarshalVtbl = {
-    Marshal_QueryInterface,
-    Marshal_AddRef,
-    Marshal_Release,
-    Marshal_GetUnmarshalClass,
-    Marshal_GetMarshalSizeMax,
-    Marshal_MarshalInterface,
-    Marshal_UnmarshalInterface,
-    Marshal_ReleaseMarshalData,
-    Marshal_DisconnectObject
-};
-
-HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj)
-{
-    Uri *ret = calloc(1, sizeof(Uri));
-
-    TRACE("(%p %p)\n", pUnkOuter, ppobj);
-
-    *ppobj = ret;
-    if(!ret)
-        return E_OUTOFMEMORY;
-
-    ret->IUri_iface.lpVtbl = &UriVtbl;
-    ret->IUriBuilderFactory_iface.lpVtbl = &UriBuilderFactoryVtbl;
-    ret->IPersistStream_iface.lpVtbl = &PersistStreamVtbl;
-    ret->IMarshal_iface.lpVtbl = &MarshalVtbl;
-    ret->ref = 1;
-
-    *ppobj = &ret->IUri_iface;
-    return S_OK;
-}
-
-/***********************************************************************
- *           CreateUri (urlmon.@)
- *
- * Creates a new IUri object using the URI represented by pwzURI. This function
- * parses and validates the components of pwzURI and then canonicalizes the
- * parsed components.
- *
- * PARAMS
- *  pwzURI      [I] The URI to parse, validate, and canonicalize.
- *  dwFlags     [I] Flags which can affect how the parsing/canonicalization is performed.
- *  dwReserved  [I] Reserved (not used).
- *  ppURI       [O] The resulting IUri after parsing/canonicalization occurs.
- *
- * RETURNS
- *  Success: Returns S_OK. ppURI contains the pointer to the newly allocated IUri.
- *  Failure: E_INVALIDARG if there are invalid flag combinations in dwFlags, or an
- *           invalid parameter, or pwzURI doesn't represent a valid URI.
- *           E_OUTOFMEMORY if any memory allocation fails.
- *
- * NOTES
- *  Default flags:
- *      Uri_CREATE_CANONICALIZE, Uri_CREATE_DECODE_EXTRA_INFO, Uri_CREATE_CRACK_UNKNOWN_SCHEMES,
- *      Uri_CREATE_PRE_PROCESS_HTML_URI, Uri_CREATE_NO_IE_SETTINGS.
- */
-HRESULT WINAPI CreateUri(LPCWSTR pwzURI, DWORD dwFlags, DWORD_PTR dwReserved, IUri **ppURI)
-{
-    const DWORD supported_flags = Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_WILDCARD_SCHEME|
-        Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME|Uri_CREATE_NO_CANONICALIZE|Uri_CREATE_CANONICALIZE|
-        Uri_CREATE_DECODE_EXTRA_INFO|Uri_CREATE_NO_DECODE_EXTRA_INFO|Uri_CREATE_CRACK_UNKNOWN_SCHEMES|
-        Uri_CREATE_NO_CRACK_UNKNOWN_SCHEMES|Uri_CREATE_PRE_PROCESS_HTML_URI|Uri_CREATE_NO_PRE_PROCESS_HTML_URI|
-        Uri_CREATE_NO_IE_SETTINGS|Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS|Uri_CREATE_FILE_USE_DOS_PATH;
-    Uri *ret;
-    HRESULT hr;
-    parse_data data;
-
-    TRACE("(%s %lx %Ix %p)\n", debugstr_w(pwzURI), dwFlags, dwReserved, ppURI);
-
-    if(!ppURI)
-        return E_INVALIDARG;
-
-    if(!pwzURI) {
-        *ppURI = NULL;
-        return E_INVALIDARG;
-    }
-
-    /* Check for invalid flags. */
-    if(has_invalid_flag_combination(dwFlags)) {
-        *ppURI = NULL;
-        return E_INVALIDARG;
-    }
-
-    /* Currently unsupported. */
-    if(dwFlags & ~supported_flags)
-        FIXME("Ignoring unsupported flag(s) %lx\n", dwFlags & ~supported_flags);
-
-    hr = Uri_Construct(NULL, (void**)&ret);
-    if(FAILED(hr)) {
-        *ppURI = NULL;
-        return hr;
-    }
-
-    /* Explicitly set the default flags if it doesn't cause a flag conflict. */
-    apply_default_flags(&dwFlags);
-
-    /* Pre process the URI, unless told otherwise. */
-    if(!(dwFlags & Uri_CREATE_NO_PRE_PROCESS_HTML_URI))
-        ret->raw_uri = pre_process_uri(pwzURI);
-    else
-        ret->raw_uri = SysAllocString(pwzURI);
-
-    if(!ret->raw_uri) {
-        free(ret);
-        return E_OUTOFMEMORY;
-    }
-
-    memset(&data, 0, sizeof(parse_data));
-    data.uri = ret->raw_uri;
-
-    /* Validate and parse the URI into its components. */
-    if(!parse_uri(&data, dwFlags)) {
-        /* Encountered an unsupported or invalid URI */
-        IUri_Release(&ret->IUri_iface);
-        *ppURI = NULL;
-        return E_INVALIDARG;
-    }
-
-    /* Canonicalize the URI. */
-    hr = canonicalize_uri(&data, ret, dwFlags);
-    if(FAILED(hr)) {
-        IUri_Release(&ret->IUri_iface);
-        *ppURI = NULL;
-        return hr;
-    }
-
-    ret->create_flags = dwFlags;
-
-    *ppURI = &ret->IUri_iface;
-    return S_OK;
-}
-
-/***********************************************************************
- *           CreateUriWithFragment (urlmon.@)
- *
- * Creates a new IUri object. This is almost the same as CreateUri, expect that
- * it allows you to explicitly specify a fragment (pwzFragment) for pwzURI.
- *
- * PARAMS
- *  pwzURI      [I] The URI to parse and perform canonicalization on.
- *  pwzFragment [I] The explicit fragment string which should be added to pwzURI.
- *  dwFlags     [I] The flags which will be passed to CreateUri.
- *  dwReserved  [I] Reserved (not used).
- *  ppURI       [O] The resulting IUri after parsing/canonicalization.
- *
- * RETURNS
- *  Success: S_OK. ppURI contains the pointer to the newly allocated IUri.
- *  Failure: E_INVALIDARG if pwzURI already contains a fragment and pwzFragment
- *           isn't NULL. Will also return E_INVALIDARG for the same reasons as
- *           CreateUri will. E_OUTOFMEMORY if any allocation fails.
- */
-HRESULT WINAPI CreateUriWithFragment(LPCWSTR pwzURI, LPCWSTR pwzFragment, DWORD dwFlags,
-                                     DWORD_PTR dwReserved, IUri **ppURI)
-{
-    HRESULT hres;
-    TRACE("(%s %s %lx %Ix %p)\n", debugstr_w(pwzURI), debugstr_w(pwzFragment), dwFlags, dwReserved, ppURI);
-
-    if(!ppURI)
-        return E_INVALIDARG;
-
-    if(!pwzURI) {
-        *ppURI = NULL;
-        return E_INVALIDARG;
-    }
-
-    /* Check if a fragment should be appended to the URI string. */
-    if(pwzFragment) {
-        WCHAR *uriW;
-        DWORD uri_len, frag_len;
-        BOOL add_pound;
-
-        /* Check if the original URI already has a fragment component. */
-        if(StrChrW(pwzURI, '#')) {
-            *ppURI = NULL;
-            return E_INVALIDARG;
-        }
-
-        uri_len = lstrlenW(pwzURI);
-        frag_len = lstrlenW(pwzFragment);
-
-        /* If the fragment doesn't start with a '#', one will be added. */
-        add_pound = *pwzFragment != '#';
-
-        if(add_pound)
-            uriW = malloc((uri_len + frag_len + 2) * sizeof(WCHAR));
-        else
-            uriW = malloc((uri_len + frag_len + 1) * sizeof(WCHAR));
-
-        if(!uriW)
-            return E_OUTOFMEMORY;
-
-        memcpy(uriW, pwzURI, uri_len*sizeof(WCHAR));
-        if(add_pound)
-            uriW[uri_len++] = '#';
-        memcpy(uriW+uri_len, pwzFragment, (frag_len+1)*sizeof(WCHAR));
-
-        hres = CreateUri(uriW, dwFlags, 0, ppURI);
-
-        free(uriW);
-    } else
-        /* A fragment string wasn't specified, so just forward the call. */
-        hres = CreateUri(pwzURI, dwFlags, 0, ppURI);
-
-    return hres;
-}
-
-static HRESULT build_uri(const UriBuilder *builder, IUri **uri, DWORD create_flags,
-                         DWORD use_orig_flags, DWORD encoding_mask)
-{
-    HRESULT hr;
-    parse_data data;
-    Uri *ret;
-
-    if(!uri)
-        return E_POINTER;
-
-    if(encoding_mask && (!builder->uri || builder->modified_props)) {
-        *uri = NULL;
-        return E_NOTIMPL;
-    }
-
-    /* Decide what flags should be used when creating the Uri. */
-    if((use_orig_flags & UriBuilder_USE_ORIGINAL_FLAGS) && builder->uri)
-        create_flags = builder->uri->create_flags;
-    else {
-        if(has_invalid_flag_combination(create_flags)) {
-            *uri = NULL;
-            return E_INVALIDARG;
-        }
-
-        /* Set the default flags if they don't cause a conflict. */
-        apply_default_flags(&create_flags);
-    }
-
-    /* Return the base IUri if no changes have been made and the create_flags match. */
-    if(builder->uri && !builder->modified_props && builder->uri->create_flags == create_flags) {
-        *uri = &builder->uri->IUri_iface;
-        IUri_AddRef(*uri);
-        return S_OK;
-    }
-
-    hr = validate_components(builder, &data, create_flags);
-    if(FAILED(hr)) {
-        *uri = NULL;
-        return hr;
-    }
-
-    hr = Uri_Construct(NULL, (void**)&ret);
-    if(FAILED(hr)) {
-        *uri = NULL;
-        return hr;
-    }
-
-    hr = generate_uri(builder, &data, ret, create_flags);
-    if(FAILED(hr)) {
-        IUri_Release(&ret->IUri_iface);
-        *uri = NULL;
-        return hr;
-    }
-
-    *uri = &ret->IUri_iface;
-    return S_OK;
-}
-
-static inline UriBuilder* impl_from_IUriBuilder(IUriBuilder *iface)
-{
-    return CONTAINING_RECORD(iface, UriBuilder, IUriBuilder_iface);
-}
-
-static HRESULT WINAPI UriBuilder_QueryInterface(IUriBuilder *iface, REFIID riid, void **ppv)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-
-    if(IsEqualGUID(&IID_IUnknown, riid)) {
-        TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
-        *ppv = &This->IUriBuilder_iface;
-    }else if(IsEqualGUID(&IID_IUriBuilder, riid)) {
-        TRACE("(%p)->(IID_IUriBuilder %p)\n", This, ppv);
-        *ppv = &This->IUriBuilder_iface;
-    }else {
-        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
-        *ppv = NULL;
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef((IUnknown*)*ppv);
-    return S_OK;
-}
-
-static ULONG WINAPI UriBuilder_AddRef(IUriBuilder *iface)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    LONG ref = InterlockedIncrement(&This->ref);
-
-    TRACE("(%p) ref=%ld\n", This, ref);
-
-    return ref;
-}
-
-static ULONG WINAPI UriBuilder_Release(IUriBuilder *iface)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    LONG ref = InterlockedDecrement(&This->ref);
-
-    TRACE("(%p) ref=%ld\n", This, ref);
-
-    if(!ref) {
-        if(This->uri) IUri_Release(&This->uri->IUri_iface);
-        free(This->fragment);
-        free(This->host);
-        free(This->password);
-        free(This->path);
-        free(This->query);
-        free(This->scheme);
-        free(This->username);
-        free(This);
-    }
-
-    return ref;
-}
-
-static HRESULT WINAPI UriBuilder_CreateUriSimple(IUriBuilder *iface,
-                                                 DWORD        dwAllowEncodingPropertyMask,
-                                                 DWORD_PTR    dwReserved,
-                                                 IUri       **ppIUri)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    HRESULT hr;
-    TRACE("(%p)->(%ld %Id %p)\n", This, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
-
-    hr = build_uri(This, ppIUri, 0, UriBuilder_USE_ORIGINAL_FLAGS, dwAllowEncodingPropertyMask);
-    if(hr == E_NOTIMPL)
-        FIXME("(%p)->(%ld %Id %p)\n", This, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
-    return hr;
-}
-
-static HRESULT WINAPI UriBuilder_CreateUri(IUriBuilder *iface,
-                                           DWORD        dwCreateFlags,
-                                           DWORD        dwAllowEncodingPropertyMask,
-                                           DWORD_PTR    dwReserved,
-                                           IUri       **ppIUri)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    HRESULT hr;
-    TRACE("(%p)->(0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
-
-    if(dwCreateFlags == -1)
-        hr = build_uri(This, ppIUri, 0, UriBuilder_USE_ORIGINAL_FLAGS, dwAllowEncodingPropertyMask);
-    else
-        hr = build_uri(This, ppIUri, dwCreateFlags, 0, dwAllowEncodingPropertyMask);
-
-    if(hr == E_NOTIMPL)
-        FIXME("(%p)->(0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwAllowEncodingPropertyMask, dwReserved, ppIUri);
-    return hr;
-}
-
-static HRESULT WINAPI UriBuilder_CreateUriWithFlags(IUriBuilder *iface,
-                                         DWORD        dwCreateFlags,
-                                         DWORD        dwUriBuilderFlags,
-                                         DWORD        dwAllowEncodingPropertyMask,
-                                         DWORD_PTR    dwReserved,
-                                         IUri       **ppIUri)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    HRESULT hr;
-    TRACE("(%p)->(0x%08lx 0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwUriBuilderFlags,
-        dwAllowEncodingPropertyMask, dwReserved, ppIUri);
-
-    hr = build_uri(This, ppIUri, dwCreateFlags, dwUriBuilderFlags, dwAllowEncodingPropertyMask);
-    if(hr == E_NOTIMPL)
-        FIXME("(%p)->(0x%08lx 0x%08lx %ld %Id %p)\n", This, dwCreateFlags, dwUriBuilderFlags,
-            dwAllowEncodingPropertyMask, dwReserved, ppIUri);
-    return hr;
-}
-
-static HRESULT WINAPI  UriBuilder_GetIUri(IUriBuilder *iface, IUri **ppIUri)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p)\n", This, ppIUri);
-
-    if(!ppIUri)
-        return E_POINTER;
-
-    if(This->uri) {
-        IUri *uri = &This->uri->IUri_iface;
-        IUri_AddRef(uri);
-        *ppIUri = uri;
-    } else
-        *ppIUri = NULL;
-
-    return S_OK;
-}
-
-static HRESULT WINAPI UriBuilder_SetIUri(IUriBuilder *iface, IUri *pIUri)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p)\n", This, pIUri);
-
-    if(pIUri) {
-        Uri *uri;
-
-        if((uri = get_uri_obj(pIUri))) {
-            /* Only reset the builder if its Uri isn't the same as
-             * the Uri passed to the function.
-             */
-            if(This->uri != uri) {
-                reset_builder(This);
-
-                This->uri = uri;
-                if(uri->has_port)
-                    This->port = uri->port;
-
-                IUri_AddRef(pIUri);
-            }
-        } else {
-            FIXME("(%p)->(%p) Unknown IUri types not supported yet.\n", This, pIUri);
-            return E_NOTIMPL;
-        }
-    } else if(This->uri)
-        /* Only reset the builder if its Uri isn't NULL. */
-        reset_builder(This);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI UriBuilder_GetFragment(IUriBuilder *iface, DWORD *pcchFragment, LPCWSTR *ppwzFragment)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchFragment, ppwzFragment);
-
-    if(!This->uri || This->uri->fragment_start == -1 || This->modified_props & Uri_HAS_FRAGMENT)
-        return get_builder_component(&This->fragment, &This->fragment_len, NULL, 0, ppwzFragment, pcchFragment);
-    else
-        return get_builder_component(&This->fragment, &This->fragment_len, This->uri->canon_uri+This->uri->fragment_start,
-                                     This->uri->fragment_len, ppwzFragment, pcchFragment);
-}
-
-static HRESULT WINAPI UriBuilder_GetHost(IUriBuilder *iface, DWORD *pcchHost, LPCWSTR *ppwzHost)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchHost, ppwzHost);
-
-    if(!This->uri || This->uri->host_start == -1 || This->modified_props & Uri_HAS_HOST)
-        return get_builder_component(&This->host, &This->host_len, NULL, 0, ppwzHost, pcchHost);
-    else {
-        if(This->uri->host_type == Uri_HOST_IPV6)
-            /* Don't include the '[' and ']' around the address. */
-            return get_builder_component(&This->host, &This->host_len, This->uri->canon_uri+This->uri->host_start+1,
-                                         This->uri->host_len-2, ppwzHost, pcchHost);
-        else
-            return get_builder_component(&This->host, &This->host_len, This->uri->canon_uri+This->uri->host_start,
-                                         This->uri->host_len, ppwzHost, pcchHost);
-    }
-}
-
-static HRESULT WINAPI UriBuilder_GetPassword(IUriBuilder *iface, DWORD *pcchPassword, LPCWSTR *ppwzPassword)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchPassword, ppwzPassword);
-
-    if(!This->uri || This->uri->userinfo_split == -1 || This->modified_props & Uri_HAS_PASSWORD)
-        return get_builder_component(&This->password, &This->password_len, NULL, 0, ppwzPassword, pcchPassword);
-    else {
-        const WCHAR *start = This->uri->canon_uri+This->uri->userinfo_start+This->uri->userinfo_split+1;
-        DWORD len = This->uri->userinfo_len-This->uri->userinfo_split-1;
-        return get_builder_component(&This->password, &This->password_len, start, len, ppwzPassword, pcchPassword);
-    }
-}
-
-static HRESULT WINAPI UriBuilder_GetPath(IUriBuilder *iface, DWORD *pcchPath, LPCWSTR *ppwzPath)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchPath, ppwzPath);
-
-    if(!This->uri || This->uri->path_start == -1 || This->modified_props & Uri_HAS_PATH)
-        return get_builder_component(&This->path, &This->path_len, NULL, 0, ppwzPath, pcchPath);
-    else
-        return get_builder_component(&This->path, &This->path_len, This->uri->canon_uri+This->uri->path_start,
-                                     This->uri->path_len, ppwzPath, pcchPath);
-}
-
-static HRESULT WINAPI UriBuilder_GetPort(IUriBuilder *iface, BOOL *pfHasPort, DWORD *pdwPort)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pfHasPort, pdwPort);
-
-    if(!pfHasPort) {
-        if(pdwPort)
-            *pdwPort = 0;
-        return E_POINTER;
-    }
-
-    if(!pdwPort) {
-        *pfHasPort = FALSE;
-        return E_POINTER;
-    }
-
-    *pfHasPort = This->has_port;
-    *pdwPort = This->port;
-    return S_OK;
-}
-
-static HRESULT WINAPI UriBuilder_GetQuery(IUriBuilder *iface, DWORD *pcchQuery, LPCWSTR *ppwzQuery)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchQuery, ppwzQuery);
-
-    if(!This->uri || This->uri->query_start == -1 || This->modified_props & Uri_HAS_QUERY)
-        return get_builder_component(&This->query, &This->query_len, NULL, 0, ppwzQuery, pcchQuery);
-    else
-        return get_builder_component(&This->query, &This->query_len, This->uri->canon_uri+This->uri->query_start,
-                                     This->uri->query_len, ppwzQuery, pcchQuery);
-}
-
-static HRESULT WINAPI UriBuilder_GetSchemeName(IUriBuilder *iface, DWORD *pcchSchemeName, LPCWSTR *ppwzSchemeName)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchSchemeName, ppwzSchemeName);
-
-    if(!This->uri || This->uri->scheme_start == -1 || This->modified_props & Uri_HAS_SCHEME_NAME)
-        return get_builder_component(&This->scheme, &This->scheme_len, NULL, 0, ppwzSchemeName, pcchSchemeName);
-    else
-        return get_builder_component(&This->scheme, &This->scheme_len, This->uri->canon_uri+This->uri->scheme_start,
-                                     This->uri->scheme_len, ppwzSchemeName, pcchSchemeName);
-}
-
-static HRESULT WINAPI UriBuilder_GetUserName(IUriBuilder *iface, DWORD *pcchUserName, LPCWSTR *ppwzUserName)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p %p)\n", This, pcchUserName, ppwzUserName);
-
-    if(!This->uri || This->uri->userinfo_start == -1 || This->uri->userinfo_split == 0 ||
-       This->modified_props & Uri_HAS_USER_NAME)
-        return get_builder_component(&This->username, &This->username_len, NULL, 0, ppwzUserName, pcchUserName);
-    else {
-        const WCHAR *start = This->uri->canon_uri+This->uri->userinfo_start;
-
-        /* Check if there's a password in the userinfo section. */
-        if(This->uri->userinfo_split > -1)
-            /* Don't include the password. */
-            return get_builder_component(&This->username, &This->username_len, start,
-                                         This->uri->userinfo_split, ppwzUserName, pcchUserName);
-        else
-            return get_builder_component(&This->username, &This->username_len, start,
-                                         This->uri->userinfo_len, ppwzUserName, pcchUserName);
-    }
-}
-
-static HRESULT WINAPI UriBuilder_SetFragment(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-    return set_builder_component(&This->fragment, &This->fragment_len, pwzNewValue, '#',
-                                 &This->modified_props, Uri_HAS_FRAGMENT);
-}
-
-static HRESULT WINAPI UriBuilder_SetHost(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-
-    /* Host name can't be set to NULL. */
-    if(!pwzNewValue)
-        return E_INVALIDARG;
-
-    return set_builder_component(&This->host, &This->host_len, pwzNewValue, 0,
-                                 &This->modified_props, Uri_HAS_HOST);
-}
-
-static HRESULT WINAPI UriBuilder_SetPassword(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-    return set_builder_component(&This->password, &This->password_len, pwzNewValue, 0,
-                                 &This->modified_props, Uri_HAS_PASSWORD);
-}
-
-static HRESULT WINAPI UriBuilder_SetPath(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-    return set_builder_component(&This->path, &This->path_len, pwzNewValue, 0,
-                                 &This->modified_props, Uri_HAS_PATH);
-}
-
-static HRESULT WINAPI UriBuilder_SetPort(IUriBuilder *iface, BOOL fHasPort, DWORD dwNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%d %ld)\n", This, fHasPort, dwNewValue);
-
-    This->has_port = fHasPort;
-    This->port = dwNewValue;
-    This->modified_props |= Uri_HAS_PORT;
-    return S_OK;
-}
-
-static HRESULT WINAPI UriBuilder_SetQuery(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-    return set_builder_component(&This->query, &This->query_len, pwzNewValue, '?',
-                                 &This->modified_props, Uri_HAS_QUERY);
-}
-
-static HRESULT WINAPI UriBuilder_SetSchemeName(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-
-    /* Only set the scheme name if it's not NULL or empty. */
-    if(!pwzNewValue || !*pwzNewValue)
-        return E_INVALIDARG;
-
-    return set_builder_component(&This->scheme, &This->scheme_len, pwzNewValue, 0,
-                                 &This->modified_props, Uri_HAS_SCHEME_NAME);
-}
-
-static HRESULT WINAPI UriBuilder_SetUserName(IUriBuilder *iface, LPCWSTR pwzNewValue)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%s)\n", This, debugstr_w(pwzNewValue));
-    return set_builder_component(&This->username, &This->username_len, pwzNewValue, 0,
-                                 &This->modified_props, Uri_HAS_USER_NAME);
-}
-
-static HRESULT WINAPI UriBuilder_RemoveProperties(IUriBuilder *iface, DWORD dwPropertyMask)
-{
-    const DWORD accepted_flags = Uri_HAS_AUTHORITY|Uri_HAS_DOMAIN|Uri_HAS_EXTENSION|Uri_HAS_FRAGMENT|Uri_HAS_HOST|
-                                 Uri_HAS_PASSWORD|Uri_HAS_PATH|Uri_HAS_PATH_AND_QUERY|Uri_HAS_QUERY|
-                                 Uri_HAS_USER_INFO|Uri_HAS_USER_NAME;
-
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(0x%08lx)\n", This, dwPropertyMask);
-
-    if(dwPropertyMask & ~accepted_flags)
-        return E_INVALIDARG;
-
-    if(dwPropertyMask & Uri_HAS_FRAGMENT)
-        UriBuilder_SetFragment(iface, NULL);
-
-    /* Even though you can't set the host name to NULL or an
-     * empty string, you can still remove it... for some reason.
-     */
-    if(dwPropertyMask & Uri_HAS_HOST)
-        set_builder_component(&This->host, &This->host_len, NULL, 0,
-                              &This->modified_props, Uri_HAS_HOST);
-
-    if(dwPropertyMask & Uri_HAS_PASSWORD)
-        UriBuilder_SetPassword(iface, NULL);
-
-    if(dwPropertyMask & Uri_HAS_PATH)
-        UriBuilder_SetPath(iface, NULL);
-
-    if(dwPropertyMask & Uri_HAS_PORT)
-        UriBuilder_SetPort(iface, FALSE, 0);
-
-    if(dwPropertyMask & Uri_HAS_QUERY)
-        UriBuilder_SetQuery(iface, NULL);
-
-    if(dwPropertyMask & Uri_HAS_USER_NAME)
-        UriBuilder_SetUserName(iface, NULL);
-
-    return S_OK;
-}
-
-static HRESULT WINAPI UriBuilder_HasBeenModified(IUriBuilder *iface, BOOL *pfModified)
-{
-    UriBuilder *This = impl_from_IUriBuilder(iface);
-    TRACE("(%p)->(%p)\n", This, pfModified);
-
-    if(!pfModified)
-        return E_POINTER;
-
-    *pfModified = This->modified_props > 0;
-    return S_OK;
-}
-
-static const IUriBuilderVtbl UriBuilderVtbl = {
-    UriBuilder_QueryInterface,
-    UriBuilder_AddRef,
-    UriBuilder_Release,
-    UriBuilder_CreateUriSimple,
-    UriBuilder_CreateUri,
-    UriBuilder_CreateUriWithFlags,
-    UriBuilder_GetIUri,
-    UriBuilder_SetIUri,
-    UriBuilder_GetFragment,
-    UriBuilder_GetHost,
-    UriBuilder_GetPassword,
-    UriBuilder_GetPath,
-    UriBuilder_GetPort,
-    UriBuilder_GetQuery,
-    UriBuilder_GetSchemeName,
-    UriBuilder_GetUserName,
-    UriBuilder_SetFragment,
-    UriBuilder_SetHost,
-    UriBuilder_SetPassword,
-    UriBuilder_SetPath,
-    UriBuilder_SetPort,
-    UriBuilder_SetQuery,
-    UriBuilder_SetSchemeName,
-    UriBuilder_SetUserName,
-    UriBuilder_RemoveProperties,
-    UriBuilder_HasBeenModified,
-};
-
-/***********************************************************************
- *           CreateIUriBuilder (urlmon.@)
- */
-HRESULT WINAPI CreateIUriBuilder(IUri *pIUri, DWORD dwFlags, DWORD_PTR dwReserved, IUriBuilder **ppIUriBuilder)
-{
-    UriBuilder *ret;
-
-    TRACE("(%p %lx %Ix %p)\n", pIUri, dwFlags, dwReserved, ppIUriBuilder);
-
-    if(!ppIUriBuilder)
-        return E_POINTER;
-
-    ret = calloc(1, sizeof(UriBuilder));
-    if(!ret)
-        return E_OUTOFMEMORY;
-
-    ret->IUriBuilder_iface.lpVtbl = &UriBuilderVtbl;
-    ret->ref = 1;
-
-    if(pIUri) {
-        Uri *uri;
-
-        if((uri = get_uri_obj(pIUri))) {
-            if(!uri->create_flags) {
-                free(ret);
-                return E_UNEXPECTED;
-            }
-            IUri_AddRef(pIUri);
-            ret->uri = uri;
-
-            if(uri->has_port)
-                /* Windows doesn't set 'has_port' to TRUE in this case. */
-                ret->port = uri->port;
-
-        } else {
-            free(ret);
-            *ppIUriBuilder = NULL;
-            FIXME("(%p %lx %Ix %p): Unknown IUri types not supported yet.\n", pIUri, dwFlags,
-                  dwReserved, ppIUriBuilder);
-            return E_NOTIMPL;
-        }
-    }
-
-    *ppIUriBuilder = &ret->IUriBuilder_iface;
-    return S_OK;
-}
-
-/* Merges the base path with the relative path and stores the resulting path
- * and path len in 'result' and 'result_len'.
- */
-static HRESULT merge_paths(parse_data *data, const WCHAR *base, DWORD base_len, const WCHAR *relative,
-                           DWORD relative_len, WCHAR **result, DWORD *result_len, DWORD flags)
-{
-    const WCHAR *end = NULL;
-    DWORD base_copy_len = 0;
-    WCHAR *ptr;
-
-    if(base_len) {
-        if(data->scheme_type == URL_SCHEME_MK && *relative == '/') {
-            /* Find '::' segment */
-            for(end = base; end < base+base_len-1; end++) {
-                if(end[0] == ':' && end[1] == ':') {
-                    end++;
-                    break;
-                }
-            }
-
-            /* If not found, try finding the end of @xxx: */
-            if(end == base+base_len-1)
-                end = *base == '@' ? wmemchr(base, ':', base_len) : NULL;
-        }else {
-            /* Find the characters that will be copied over from the base path. */
-            for (end = base + base_len - 1; end >= base; end--) if (*end == '/') break;
-            if(end < base && data->scheme_type == URL_SCHEME_FILE)
-                /* Try looking for a '\\'. */
-                for (end = base + base_len - 1; end >= base; end--) if (*end == '\\') break;
-        }
-    }
-
-    if (end) base_copy_len = (end+1)-base;
-    *result = malloc((base_copy_len + relative_len + 1) * sizeof(WCHAR));
-
-    if(!(*result)) {
-        *result_len = 0;
-        return E_OUTOFMEMORY;
-    }
-
-    ptr = *result;
-    memcpy(ptr, base, base_copy_len*sizeof(WCHAR));
-    ptr += base_copy_len;
-
-    memcpy(ptr, relative, relative_len*sizeof(WCHAR));
-    ptr += relative_len;
-    *ptr = '\0';
-
-    *result_len = (ptr-*result);
-    TRACE("ret %s\n", debugstr_wn(*result, *result_len));
-    return S_OK;
-}
-
-static HRESULT combine_uri(Uri *base, Uri *relative, DWORD flags, IUri **result, DWORD extras) {
-    Uri *ret;
-    HRESULT hr;
-    parse_data data;
-    Uri *proc_uri = base;
-    DWORD create_flags = 0, len = 0;
-
-    memset(&data, 0, sizeof(parse_data));
-
-    /* Base case is when the relative Uri has a scheme name,
-     * if it does, then 'result' will contain the same data
-     * as the relative Uri.
-     */
-    if(relative->scheme_start > -1) {
-        data.uri = SysAllocString(relative->raw_uri);
-        if(!data.uri) {
-            *result = NULL;
-            return E_OUTOFMEMORY;
-        }
-
-        parse_uri(&data, Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME);
-
-        hr = Uri_Construct(NULL, (void**)&ret);
-        if(FAILED(hr)) {
-            *result = NULL;
-            return hr;
-        }
-
-        if(extras & COMBINE_URI_FORCE_FLAG_USE) {
-            if(flags & URL_DONT_SIMPLIFY)
-                create_flags |= Uri_CREATE_NO_CANONICALIZE;
-            if(flags & URL_DONT_UNESCAPE_EXTRA_INFO)
-                create_flags |= Uri_CREATE_NO_DECODE_EXTRA_INFO;
-        }
-
-        ret->raw_uri = data.uri;
-        hr = canonicalize_uri(&data, ret, create_flags);
-        if(FAILED(hr)) {
-            IUri_Release(&ret->IUri_iface);
-            *result = NULL;
-            return hr;
-        }
-
-        apply_default_flags(&create_flags);
-        ret->create_flags = create_flags;
-
-        *result = &ret->IUri_iface;
-    } else {
-        WCHAR *path = NULL;
-        DWORD raw_flags = 0;
-
-        if(base->scheme_start > -1) {
-            data.scheme = base->canon_uri+base->scheme_start;
-            data.scheme_len = base->scheme_len;
-            data.scheme_type = base->scheme_type;
-        } else {
-            data.is_relative = TRUE;
-            data.scheme_type = URL_SCHEME_UNKNOWN;
-            create_flags |= Uri_CREATE_ALLOW_RELATIVE;
-        }
-
-        if(relative->authority_start > -1)
-            proc_uri = relative;
-
-        if(proc_uri->authority_start > -1) {
-            if(proc_uri->userinfo_start > -1 && proc_uri->userinfo_split != 0) {
-                data.username = proc_uri->canon_uri+proc_uri->userinfo_start;
-                data.username_len = (proc_uri->userinfo_split > -1) ? proc_uri->userinfo_split : proc_uri->userinfo_len;
-            }
-
-            if(proc_uri->userinfo_split > -1) {
-                data.password = proc_uri->canon_uri+proc_uri->userinfo_start+proc_uri->userinfo_split+1;
-                data.password_len = proc_uri->userinfo_len-proc_uri->userinfo_split-1;
-            }
-
-            if(proc_uri->host_start > -1) {
-                const WCHAR *host = proc_uri->canon_uri+proc_uri->host_start;
-                parse_host(&host, &data, 0);
-            }
-
-            if(proc_uri->has_port) {
-                data.has_port = TRUE;
-                data.port_value = proc_uri->port;
-            }
-        } else if(base->scheme_type != URL_SCHEME_FILE)
-            data.is_opaque = TRUE;
-
-        if(proc_uri == relative || relative->path_start == -1 || !relative->path_len) {
-            if(proc_uri->path_start > -1) {
-                data.path = proc_uri->canon_uri+proc_uri->path_start;
-                data.path_len = proc_uri->path_len;
-            } else if(!data.is_opaque) {
-                /* Just set the path as a '/' if the base didn't have
-                 * one and if it's a hierarchical URI.
-                 */
-                data.path = L"/";
-                data.path_len = 1;
-            }
-
-            if(relative->query_start > -1)
-                proc_uri = relative;
-
-            if(proc_uri->query_start > -1) {
-                data.query = proc_uri->canon_uri+proc_uri->query_start;
-                data.query_len = proc_uri->query_len;
-            }
-        } else {
-            const WCHAR *ptr, **pptr;
-            DWORD path_offset = 0, path_len = 0;
-
-            /* There's two possibilities on what will happen to the path component
-             * of the result IUri. First, if the relative path begins with a '/'
-             * then the resulting path will just be the relative path. Second, if
-             * relative path doesn't begin with a '/' then the base path and relative
-             * path are merged together.
-             */
-            if(relative->path_len && *(relative->canon_uri+relative->path_start) == '/' && data.scheme_type != URL_SCHEME_MK) {
-                WCHAR *tmp = NULL;
-                BOOL copy_drive_path = FALSE;
-
-                /* If the relative IUri's path starts with a '/', then we
-                 * don't use the base IUri's path. Unless the base IUri
-                 * is a file URI, in which case it uses the drive path of
-                 * the base IUri (if it has any) in the new path.
-                 */
-                if(base->scheme_type == URL_SCHEME_FILE) {
-                    if(base->path_len > 3 && *(base->canon_uri+base->path_start) == '/' &&
-                       is_drive_path(base->canon_uri+base->path_start+1)) {
-                        path_len += 3;
-                        copy_drive_path = TRUE;
-                    }
-                }
-
-                path_len += relative->path_len;
-
-                path = malloc((path_len + 1) * sizeof(WCHAR));
-                if(!path) {
-                    *result = NULL;
-                    return E_OUTOFMEMORY;
-                }
-
-                tmp = path;
-
-                /* Copy the base paths, drive path over. */
-                if(copy_drive_path) {
-                    memcpy(tmp, base->canon_uri+base->path_start, 3*sizeof(WCHAR));
-                    tmp += 3;
-                }
-
-                memcpy(tmp, relative->canon_uri+relative->path_start, relative->path_len*sizeof(WCHAR));
-                path[path_len] = '\0';
-            } else {
-                /* Merge the base path with the relative path. */
-                hr = merge_paths(&data, base->canon_uri+base->path_start, base->path_len,
-                                 relative->canon_uri+relative->path_start, relative->path_len,
-                                 &path, &path_len, flags);
-                if(FAILED(hr)) {
-                    *result = NULL;
-                    return hr;
-                }
-
-                /* If the resulting IUri is a file URI, the drive path isn't
-                 * reduced out when the dot segments are removed.
-                 */
-                if(path_len >= 3 && data.scheme_type == URL_SCHEME_FILE && !data.host) {
-                    if(*path == '/' && is_drive_path(path+1))
-                        path_offset = 2;
-                    else if(is_drive_path(path))
-                        path_offset = 1;
-                }
-            }
-
-            /* Check if the dot segments need to be removed from the path. */
-            if(!(flags & URL_DONT_SIMPLIFY) && !data.is_opaque) {
-                DWORD offset = (path_offset > 0) ? path_offset+1 : 0;
-                DWORD new_len = remove_dot_segments(path+offset,path_len-offset);
-
-                if(new_len != path_len) {
-                    WCHAR *tmp = realloc(path, (offset + new_len + 1) * sizeof(WCHAR));
-                    if(!tmp) {
-                        free(path);
-                        *result = NULL;
-                        return E_OUTOFMEMORY;
-                    }
-
-                    tmp[new_len+offset] = '\0';
-                    path = tmp;
-                    path_len = new_len+offset;
-                }
-            }
-
-            if(relative->query_start > -1) {
-                data.query = relative->canon_uri+relative->query_start;
-                data.query_len = relative->query_len;
-            }
-
-            /* Make sure the path component is valid. */
-            ptr = path;
-            pptr = &ptr;
-            if((data.is_opaque && !parse_path_opaque(pptr, &data, 0)) ||
-               (!data.is_opaque && !parse_path_hierarchical(pptr, &data, 0))) {
-                free(path);
-                *result = NULL;
-                return E_INVALIDARG;
-            }
-        }
-
-        if(relative->fragment_start > -1) {
-            data.fragment = relative->canon_uri+relative->fragment_start;
-            data.fragment_len = relative->fragment_len;
-        }
-
-        if(flags & URL_DONT_SIMPLIFY)
-            raw_flags |= RAW_URI_FORCE_PORT_DISP;
-        if(flags & URL_FILE_USE_PATHURL)
-            raw_flags |= RAW_URI_CONVERT_TO_DOS_PATH;
-
-        len = generate_raw_uri(&data, data.uri, raw_flags);
-        data.uri = SysAllocStringLen(NULL, len);
-        if(!data.uri) {
-            free(path);
-            *result = NULL;
-            return E_OUTOFMEMORY;
-        }
-
-        generate_raw_uri(&data, data.uri, raw_flags);
-
-        hr = Uri_Construct(NULL, (void**)&ret);
-        if(FAILED(hr)) {
-            SysFreeString(data.uri);
-            free(path);
-            *result = NULL;
-            return hr;
-        }
-
-        if(flags & URL_DONT_SIMPLIFY)
-            create_flags |= Uri_CREATE_NO_CANONICALIZE;
-        if(flags & URL_FILE_USE_PATHURL)
-            create_flags |= Uri_CREATE_FILE_USE_DOS_PATH;
-
-        ret->raw_uri = data.uri;
-        hr = canonicalize_uri(&data, ret, create_flags);
-        if(FAILED(hr)) {
-            IUri_Release(&ret->IUri_iface);
-            *result = NULL;
-            return hr;
-        }
-
-        if(flags & URL_DONT_SIMPLIFY)
-            ret->display_modifiers |= URI_DISPLAY_NO_DEFAULT_PORT_AUTH;
-
-        apply_default_flags(&create_flags);
-        ret->create_flags = create_flags;
-        *result = &ret->IUri_iface;
-
-        free(path);
-    }
-
-    return S_OK;
-}
-
-/***********************************************************************
- *           CoInternetCombineIUri (urlmon.@)
- */
-HRESULT WINAPI CoInternetCombineIUri(IUri *pBaseUri, IUri *pRelativeUri, DWORD dwCombineFlags,
-                                     IUri **ppCombinedUri, DWORD_PTR dwReserved)
-{
-    HRESULT hr;
-    IInternetProtocolInfo *info;
-    Uri *relative, *base;
-    TRACE("(%p %p %lx %p %Ix)\n", pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
-
-    if(!ppCombinedUri)
-        return E_INVALIDARG;
-
-    if(!pBaseUri || !pRelativeUri) {
-        *ppCombinedUri = NULL;
-        return E_INVALIDARG;
-    }
-
-    relative = get_uri_obj(pRelativeUri);
-    base = get_uri_obj(pBaseUri);
-    if(!relative || !base) {
-        *ppCombinedUri = NULL;
-        FIXME("(%p %p %lx %p %Ix) Unknown IUri types not supported yet.\n",
-            pBaseUri, pRelativeUri, dwCombineFlags, ppCombinedUri, dwReserved);
-        return E_NOTIMPL;
-    }
-
-    info = get_protocol_info(base->canon_uri);
-    if(info) {
-        WCHAR result[INTERNET_MAX_URL_LENGTH+1];
-        DWORD result_len = 0;
-
-        hr = IInternetProtocolInfo_CombineUrl(info, base->canon_uri, relative->canon_uri, dwCombineFlags,
-                                              result, INTERNET_MAX_URL_LENGTH+1, &result_len, 0);
-        IInternetProtocolInfo_Release(info);
-        if(SUCCEEDED(hr)) {
-            hr = CreateUri(result, Uri_CREATE_ALLOW_RELATIVE, 0, ppCombinedUri);
-            if(SUCCEEDED(hr))
-                return hr;
-        }
-    }
-
-    return combine_uri(base, relative, dwCombineFlags, ppCombinedUri, 0);
-}
-
-/***********************************************************************
- *           CoInternetCombineUrlEx (urlmon.@)
- */
-HRESULT WINAPI CoInternetCombineUrlEx(IUri *pBaseUri, LPCWSTR pwzRelativeUrl, DWORD dwCombineFlags,
-                                      IUri **ppCombinedUri, DWORD_PTR dwReserved)
-{
-    IUri *relative;
-    Uri *base;
-    HRESULT hr;
-    IInternetProtocolInfo *info;
-
-    TRACE("(%p %s %lx %p %Ix)\n", pBaseUri, debugstr_w(pwzRelativeUrl), dwCombineFlags,
-        ppCombinedUri, dwReserved);
-
-    if(!ppCombinedUri)
-        return E_POINTER;
-
-    if(!pwzRelativeUrl) {
-        *ppCombinedUri = NULL;
-        return E_UNEXPECTED;
-    }
-
-    if(!pBaseUri) {
-        *ppCombinedUri = NULL;
-        return E_INVALIDARG;
-    }
-
-    base = get_uri_obj(pBaseUri);
-    if(!base) {
-        *ppCombinedUri = NULL;
-        FIXME("(%p %s %lx %p %Ix) Unknown IUri's not supported yet.\n", pBaseUri, debugstr_w(pwzRelativeUrl),
-            dwCombineFlags, ppCombinedUri, dwReserved);
-        return E_NOTIMPL;
-    }
-
-    info = get_protocol_info(base->canon_uri);
-    if(info) {
-        WCHAR result[INTERNET_MAX_URL_LENGTH+1];
-        DWORD result_len = 0;
-
-        hr = IInternetProtocolInfo_CombineUrl(info, base->canon_uri, pwzRelativeUrl, dwCombineFlags,
-                                              result, INTERNET_MAX_URL_LENGTH+1, &result_len, 0);
-        IInternetProtocolInfo_Release(info);
-        if(SUCCEEDED(hr)) {
-            hr = CreateUri(result, Uri_CREATE_ALLOW_RELATIVE, 0, ppCombinedUri);
-            if(SUCCEEDED(hr))
-                return hr;
-        }
-    }
-
-    hr = CreateUri(pwzRelativeUrl, Uri_CREATE_ALLOW_RELATIVE|Uri_CREATE_ALLOW_IMPLICIT_FILE_SCHEME, 0, &relative);
-    if(FAILED(hr)) {
-        *ppCombinedUri = NULL;
-        return hr;
-    }
-
-    hr = combine_uri(base, get_uri_obj(relative), dwCombineFlags, ppCombinedUri, COMBINE_URI_FORCE_FLAG_USE);
-
-    IUri_Release(relative);
-    return hr;
-}
-
-static HRESULT parse_canonicalize(const Uri *uri, DWORD flags, LPWSTR output,
-                                  DWORD output_len, DWORD *result_len)
-{
-    const WCHAR *ptr = NULL;
-    WCHAR *path = NULL;
-    const WCHAR **pptr;
-    DWORD len = 0;
-    BOOL reduce_path;
-
-    /* URL_UNESCAPE only has effect if none of the URL_ESCAPE flags are set. */
-    const BOOL allow_unescape = !(flags & URL_ESCAPE_UNSAFE) &&
-                                !(flags & URL_ESCAPE_SPACES_ONLY) &&
-                                !(flags & URL_ESCAPE_PERCENT);
-
-
-    /* Check if the dot segments need to be removed from the
-     * path component.
-     */
-    if(uri->scheme_start > -1 && uri->path_start > -1) {
-        ptr = uri->canon_uri+uri->scheme_start+uri->scheme_len+1;
-        pptr = &ptr;
-    }
-    reduce_path = !(flags & URL_DONT_SIMPLIFY) &&
-                  ptr && check_hierarchical(pptr);
-
-    for(ptr = uri->canon_uri; ptr < uri->canon_uri+uri->canon_len; ++ptr) {
-        BOOL do_default_action = TRUE;
-
-        /* Keep track of the path if we need to remove dot segments from
-         * it later.
-         */
-        if(reduce_path && !path && ptr == uri->canon_uri+uri->path_start)
-            path = output+len;
-
-        /* Check if it's time to reduce the path. */
-        if(reduce_path && ptr == uri->canon_uri+uri->path_start+uri->path_len) {
-            DWORD current_path_len = (output+len) - path;
-            DWORD new_path_len = remove_dot_segments(path, current_path_len);
-
-            /* Update the current length. */
-            len -= (current_path_len-new_path_len);
-            reduce_path = FALSE;
-        }
-
-        if(*ptr == '%') {
-            const WCHAR decoded = decode_pct_val(ptr);
-            if(decoded) {
-                if(allow_unescape && (flags & URL_UNESCAPE)) {
-                    if(len < output_len)
-                        output[len] = decoded;
-                    len++;
-                    ptr += 2;
-                    do_default_action = FALSE;
-                }
-            }
-
-            /* See if %'s needed to encoded. */
-            if(do_default_action && (flags & URL_ESCAPE_PERCENT)) {
-                if(len + 3 < output_len)
-                    pct_encode_val(*ptr, output+len);
-                len += 3;
-                do_default_action = FALSE;
-            }
-        } else if(*ptr == ' ') {
-            if((flags & URL_ESCAPE_SPACES_ONLY) &&
-               !(flags & URL_ESCAPE_UNSAFE)) {
-                if(len + 3 < output_len)
-                    pct_encode_val(*ptr, output+len);
-                len += 3;
-                do_default_action = FALSE;
-            }
-        } else if(is_ascii(*ptr) && !is_reserved(*ptr) && !is_unreserved(*ptr)) {
-            if(flags & URL_ESCAPE_UNSAFE) {
-                if(len + 3 < output_len)
-                    pct_encode_val(*ptr, output+len);
-                len += 3;
-                do_default_action = FALSE;
-            }
-        }
-
-        if(do_default_action) {
-            if(len < output_len)
-                output[len] = *ptr;
-            len++;
-        }
-    }
-
-    /* Sometimes the path is the very last component of the IUri, so
-     * see if the dot segments need to be reduced now.
-     */
-    if(reduce_path && path) {
-        DWORD current_path_len = (output+len) - path;
-        DWORD new_path_len = remove_dot_segments(path, current_path_len);
-
-        /* Update the current length. */
-        len -= (current_path_len-new_path_len);
-    }
-
-    if(len < output_len)
-        output[len] = 0;
-    else
-        output[output_len-1] = 0;
-
-    /* The null terminator isn't included in the length. */
-    *result_len = len;
-    if(len >= output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    return S_OK;
-}
-
-static HRESULT parse_friendly(IUri *uri, LPWSTR output, DWORD output_len,
-                              DWORD *result_len)
-{
-    HRESULT hr;
-    DWORD display_len;
-    BSTR display;
-
-    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_DISPLAY_URI, &display_len, 0);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    *result_len = display_len;
-    if(display_len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    hr = IUri_GetDisplayUri(uri, &display);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    memcpy(output, display, (display_len+1)*sizeof(WCHAR));
-    SysFreeString(display);
-    return S_OK;
-}
-
-static HRESULT parse_rootdocument(const Uri *uri, LPWSTR output, DWORD output_len,
-                                  DWORD *result_len)
-{
-    static const WCHAR colon_slashesW[] = {':','/','/'};
-
-    WCHAR *ptr;
-    DWORD len = 0;
-
-    /* Windows only returns the root document if the URI has an authority
-     * and it's not an unknown scheme type or a file scheme type.
-     */
-    if(uri->authority_start == -1 ||
-       uri->scheme_type == URL_SCHEME_UNKNOWN ||
-       uri->scheme_type == URL_SCHEME_FILE) {
-        *result_len = 0;
-        if(!output_len)
-            return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-        output[0] = 0;
-        return S_OK;
-    }
-
-    len = uri->scheme_len+uri->authority_len;
-    /* For the "://" and '/' which will be added. */
-    len += 4;
-
-    if(len+1 > output_len) {
-        *result_len = len;
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-    }
-
-    ptr = output;
-    memcpy(ptr, uri->canon_uri+uri->scheme_start, uri->scheme_len*sizeof(WCHAR));
-
-    /* Add the "://". */
-    ptr += uri->scheme_len;
-    memcpy(ptr, colon_slashesW, sizeof(colon_slashesW));
-
-    /* Add the authority. */
-    ptr += ARRAY_SIZE(colon_slashesW);
-    memcpy(ptr, uri->canon_uri+uri->authority_start, uri->authority_len*sizeof(WCHAR));
-
-    /* Add the '/' after the authority. */
-    ptr += uri->authority_len;
-    *ptr = '/';
-    ptr[1] = 0;
-
-    *result_len = len;
-    return S_OK;
-}
-
-static HRESULT parse_document(const Uri *uri, LPWSTR output, DWORD output_len,
-                              DWORD *result_len)
-{
-    DWORD len = 0;
-
-    /* It has to be a known scheme type, but, it can't be a file
-     * scheme. It also has to hierarchical.
-     */
-    if(uri->scheme_type == URL_SCHEME_UNKNOWN ||
-       uri->scheme_type == URL_SCHEME_FILE ||
-       uri->authority_start == -1) {
-        *result_len = 0;
-        if(output_len < 1)
-            return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-        output[0] = 0;
-        return S_OK;
-    }
-
-    if(uri->fragment_start > -1)
-        len = uri->fragment_start;
-    else
-        len = uri->canon_len;
-
-    *result_len = len;
-    if(len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    memcpy(output, uri->canon_uri, len*sizeof(WCHAR));
-    output[len] = 0;
-    return S_OK;
-}
-
-static HRESULT parse_path_from_url(const Uri *uri, LPWSTR output, DWORD output_len,
-                                   DWORD *result_len)
-{
-    const WCHAR *path_ptr;
-    WCHAR buffer[INTERNET_MAX_URL_LENGTH+1];
-    WCHAR *ptr;
-
-    if(uri->scheme_type != URL_SCHEME_FILE) {
-        *result_len = 0;
-        if(output_len > 0)
-            output[0] = 0;
-        return E_INVALIDARG;
-    }
-
-    ptr = buffer;
-    if(uri->host_start > -1) {
-        static const WCHAR slash_slashW[] = {'\\','\\'};
-
-        memcpy(ptr, slash_slashW, sizeof(slash_slashW));
-        ptr += ARRAY_SIZE(slash_slashW);
-        memcpy(ptr, uri->canon_uri+uri->host_start, uri->host_len*sizeof(WCHAR));
-        ptr += uri->host_len;
-    }
-
-    path_ptr = uri->canon_uri+uri->path_start;
-    if(uri->path_len > 3 && *path_ptr == '/' && is_drive_path(path_ptr+1))
-        /* Skip past the '/' in front of the drive path. */
-        ++path_ptr;
-
-    for(; path_ptr < uri->canon_uri+uri->path_start+uri->path_len; ++path_ptr, ++ptr) {
-        BOOL do_default_action = TRUE;
-
-        if(*path_ptr == '%') {
-            const WCHAR decoded = decode_pct_val(path_ptr);
-            if(decoded) {
-                *ptr = decoded;
-                path_ptr += 2;
-                do_default_action = FALSE;
-            }
-        } else if(*path_ptr == '/') {
-            *ptr = '\\';
-            do_default_action = FALSE;
-        }
-
-        if(do_default_action)
-            *ptr = *path_ptr;
-    }
-
-    *ptr = 0;
-
-    *result_len = ptr-buffer;
-    if(*result_len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    memcpy(output, buffer, (*result_len+1)*sizeof(WCHAR));
-    return S_OK;
-}
-
-static HRESULT parse_url_from_path(IUri *uri, LPWSTR output, DWORD output_len,
-                                   DWORD *result_len)
-{
-    HRESULT hr;
-    BSTR received;
-    DWORD len = 0;
-
-    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_ABSOLUTE_URI, &len, 0);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    *result_len = len;
-    if(len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    hr = IUri_GetAbsoluteUri(uri, &received);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    memcpy(output, received, (len+1)*sizeof(WCHAR));
-    SysFreeString(received);
-
-    return S_OK;
-}
-
-static HRESULT parse_schema(IUri *uri, LPWSTR output, DWORD output_len,
-                            DWORD *result_len)
-{
-    HRESULT hr;
-    DWORD len;
-    BSTR received;
-
-    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_SCHEME_NAME, &len, 0);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    *result_len = len;
-    if(len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    hr = IUri_GetSchemeName(uri, &received);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    memcpy(output, received, (len+1)*sizeof(WCHAR));
-    SysFreeString(received);
-
-    return S_OK;
-}
-
-static HRESULT parse_site(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
-{
-    HRESULT hr;
-    DWORD len;
-    BSTR received;
-
-    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_HOST, &len, 0);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    *result_len = len;
-    if(len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    hr = IUri_GetHost(uri, &received);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    memcpy(output, received, (len+1)*sizeof(WCHAR));
-    SysFreeString(received);
-
-    return S_OK;
-}
-
-static HRESULT parse_domain(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
-{
-    HRESULT hr;
-    DWORD len;
-    BSTR received;
-
-    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_DOMAIN, &len, 0);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    *result_len = len;
-    if(len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    hr = IUri_GetDomain(uri, &received);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    memcpy(output, received, (len+1)*sizeof(WCHAR));
-    SysFreeString(received);
-
-    return S_OK;
-}
-
-static HRESULT parse_anchor(IUri *uri, LPWSTR output, DWORD output_len, DWORD *result_len)
-{
-    HRESULT hr;
-    DWORD len;
-    BSTR received;
-
-    hr = IUri_GetPropertyLength(uri, Uri_PROPERTY_FRAGMENT, &len, 0);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    *result_len = len;
-    if(len+1 > output_len)
-        return STRSAFE_E_INSUFFICIENT_BUFFER;
-
-    hr = IUri_GetFragment(uri, &received);
-    if(FAILED(hr)) {
-        *result_len = 0;
-        return hr;
-    }
-
-    memcpy(output, received, (len+1)*sizeof(WCHAR));
-    SysFreeString(received);
-
-    return S_OK;
-}
-
-/***********************************************************************
- *           CoInternetParseIUri (urlmon.@)
- */
-HRESULT WINAPI CoInternetParseIUri(IUri *pIUri, PARSEACTION ParseAction, DWORD dwFlags,
-                                   LPWSTR pwzResult, DWORD cchResult, DWORD *pcchResult,
-                                   DWORD_PTR dwReserved)
-{
-    HRESULT hr;
-    Uri *uri;
-    IInternetProtocolInfo *info;
-
-    TRACE("(%p %d %lx %p %ld %p %Ix)\n", pIUri, ParseAction, dwFlags, pwzResult,
-        cchResult, pcchResult, dwReserved);
-
-    if(!pcchResult)
-        return E_POINTER;
-
-    if(!pwzResult || !pIUri) {
-        *pcchResult = 0;
-        return E_INVALIDARG;
-    }
-
-    if(!(uri = get_uri_obj(pIUri))) {
-        *pcchResult = 0;
-        FIXME("(%p %d %lx %p %ld %p %Ix) Unknown IUri's not supported for this action.\n",
-            pIUri, ParseAction, dwFlags, pwzResult, cchResult, pcchResult, dwReserved);
-        return E_NOTIMPL;
-    }
-
-    info = get_protocol_info(uri->canon_uri);
+    info = get_protocol_info(canon_uri);
     if(info) {
-        hr = IInternetProtocolInfo_ParseUrl(info, uri->canon_uri, ParseAction, dwFlags,
+        hr = IInternetProtocolInfo_ParseUrl(info, canon_uri, ParseAction, dwFlags,
                                             pwzResult, cchResult, pcchResult, 0);
         IInternetProtocolInfo_Release(info);
         if(SUCCEEDED(hr)) return hr;
     }
 
-    switch(ParseAction) {
-    case PARSE_CANONICALIZE:
-        hr = parse_canonicalize(uri, dwFlags, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_FRIENDLY:
-        hr = parse_friendly(pIUri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_ROOTDOCUMENT:
-        hr = parse_rootdocument(uri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_DOCUMENT:
-        hr = parse_document(uri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_PATH_FROM_URL:
-        hr = parse_path_from_url(uri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_URL_FROM_PATH:
-        hr = parse_url_from_path(pIUri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_SCHEMA:
-        hr = parse_schema(pIUri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_SITE:
-        hr = parse_site(pIUri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_DOMAIN:
-        hr = parse_domain(pIUri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_LOCATION:
-    case PARSE_ANCHOR:
-        hr = parse_anchor(pIUri, pwzResult, cchResult, pcchResult);
-        break;
-    case PARSE_SECURITY_URL:
-    case PARSE_MIME:
-    case PARSE_SERVER:
-    case PARSE_SECURITY_DOMAIN:
-        *pcchResult = 0;
-        hr = E_FAIL;
-        break;
-    default:
-        *pcchResult = 0;
-        hr = E_NOTIMPL;
-        FIXME("(%p %d %lx %p %ld %p %Ix) Partial stub.\n", pIUri, ParseAction, dwFlags,
-            pwzResult, cchResult, pcchResult, dwReserved);
-    }
-
-    return hr;
+    return PrivateCoInternetParseIUri(pIUri, ParseAction, dwFlags, pwzResult, cchResult, pcchResult, dwReserved);
 }
diff --git a/dlls/urlmon/urlmon.spec b/dlls/urlmon/urlmon.spec
index deb302e5179c..4be72c59d091 100644
--- a/dlls/urlmon/urlmon.spec
+++ b/dlls/urlmon/urlmon.spec
@@ -33,9 +33,9 @@
 @ stdcall CreateAsyncBindCtx(long ptr ptr ptr)
 @ stdcall CreateAsyncBindCtxEx(ptr long ptr ptr ptr long)
 @ stdcall CreateFormatEnumerator(long ptr ptr)
-@ stdcall CreateIUriBuilder(ptr long long ptr)
-@ stdcall CreateUri(wstr long long ptr)
-@ stdcall CreateUriWithFragment(wstr wstr long long ptr)
+@ stdcall CreateIUriBuilder(ptr long long ptr) iertutil.CreateIUriBuilder
+@ stdcall CreateUri(wstr long long ptr) iertutil.CreateUri
+@ stdcall CreateUriWithFragment(wstr wstr long long ptr) iertutil.CreateUriWithFragment
 @ stdcall CreateURLMoniker(ptr wstr ptr)
 @ stdcall CreateURLMonikerEx(ptr wstr ptr long)
 @ stdcall CreateURLMonikerEx2(ptr ptr ptr long)
diff --git a/dlls/urlmon/urlmon_main.c b/dlls/urlmon/urlmon_main.c
index 806a893d7d19..6901dc87771c 100644
--- a/dlls/urlmon/urlmon_main.c
+++ b/dlls/urlmon/urlmon_main.c
@@ -35,8 +35,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(urlmon);
 
-DEFINE_GUID(CLSID_CUri, 0xDF2FCE13, 0x25EC, 0x45BB, 0x9D,0x4C, 0xCE,0xCD,0x47,0xC2,0x43,0x0C);
-
 LONG URLMON_refCount = 0;
 HINSTANCE urlmon_instance;
 
@@ -373,8 +371,6 @@ static ClassFactory StdURLMonikerCF =
     { { &ClassFactoryVtbl }, StdURLMoniker_Construct};
 static ClassFactory MimeFilterCF =
     { { &ClassFactoryVtbl }, MimeFilter_Construct};
-static ClassFactory CUriCF =
-    { { &ClassFactoryVtbl }, Uri_Construct};
 
 struct object_creation_info
 {
@@ -396,7 +392,6 @@ static const struct object_creation_info object_creation[] =
     { &CLSID_InternetZoneManager,     &ZoneManagerCF.IClassFactory_iface,     NULL    },
     { &CLSID_StdURLMoniker,           &StdURLMonikerCF.IClassFactory_iface,   NULL    },
     { &CLSID_DeCompMimeFilter,        &MimeFilterCF.IClassFactory_iface,      NULL    },
-    { &CLSID_CUri,                    &CUriCF.IClassFactory_iface,            NULL    }
 };
 
 static void init_session(void)
diff --git a/dlls/urlmon/urlmon_main.h b/dlls/urlmon/urlmon_main.h
index ceb3e09b7614..20e5c82390ea 100644
--- a/dlls/urlmon/urlmon_main.h
+++ b/dlls/urlmon/urlmon_main.h
@@ -45,7 +45,6 @@ extern HRESULT FtpProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj);
 extern HRESULT GopherProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj);
 extern HRESULT MkProtocol_Construct(IUnknown *pUnkOuter, LPVOID *ppobj);
 extern HRESULT MimeFilter_Construct(IUnknown *pUnkOuter, LPVOID *ppobj);
-extern HRESULT Uri_Construct(IUnknown *pUnkOuter, LPVOID *ppobj);
 
 extern BOOL WINAPI URLMON_DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
 extern HRESULT WINAPI URLMON_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv);
@@ -53,7 +52,6 @@ extern HRESULT WINAPI URLMON_DllRegisterServer(void);
 extern HRESULT WINAPI URLMON_DllUnregisterServer(void);
 
 extern GUID const CLSID_PSFactoryBuffer;
-extern GUID const CLSID_CUri;
 
 /**********************************************************************
  * Dll lifetime tracking declaration for urlmon.dll
diff --git a/dlls/urlmon/urlmon_urlmon.idl b/dlls/urlmon/urlmon_urlmon.idl
index d557708c6ca2..cf4b4f76a706 100644
--- a/dlls/urlmon/urlmon_urlmon.idl
+++ b/dlls/urlmon/urlmon_urlmon.idl
@@ -105,13 +105,6 @@ coclass PSFactoryBuffer { interface IPSFactoryBuffer; }
 ]
 coclass DeCompMimeFilter { interface IInternetProtocol; interface IInternetProtocolSink; }
 
-[
-    helpstring("CUri"),
-    threading(apartment),
-    uuid(df2fce13-25ec-45bb-9d4c-cecd47c2430c)
-]
-coclass CUri { interface IUri; }
-
 [
     helpstring("Persistent Zone Identifier"),
     threading(both),
diff --git a/dlls/user32/tests/class.c b/dlls/user32/tests/class.c
index 66dee810c45b..6dc6c8871c28 100644
--- a/dlls/user32/tests/class.c
+++ b/dlls/user32/tests/class.c
@@ -2435,6 +2435,55 @@ static void test_class_name(void)
     UnregisterClassW(wcex.lpszClassName, hinst);
 }
 
+struct class_register_info
+{
+    const WCHAR *class_name;
+    int total_test_count;
+};
+
+static DWORD WINAPI thread_register_class_proc(void *param)
+{
+    struct class_register_info *info = param;
+    for (int i = 0; i < info->total_test_count; i++)
+    {
+        WNDCLASSEXW wcex = {0};
+        wcex.cbSize        = sizeof wcex;
+        wcex.lpfnWndProc   = ClassTest_WndProc;
+        wcex.hIcon         = LoadIconW(0, (LPCWSTR)IDI_APPLICATION);
+        wcex.lpszClassName = info->class_name;
+        RegisterClassExW(&wcex);
+    }
+
+    return 0;
+}
+
+static DWORD WINAPI thread_unregister_class_proc(void *param)
+{
+    struct class_register_info *info = param;
+    for (int i = 0; i < info->total_test_count; i++)
+    {
+        UnregisterClassW(info->class_name, 0);
+    }
+
+    return 0;
+}
+
+void test_class_multithread(void)
+{
+    struct class_register_info info_register = {L"test_class_multithread", 100};
+    struct class_register_info info_unregister = {L"test_class_multithread", 100};
+
+    HANDLE thread_register = CreateThread(NULL, 0, thread_register_class_proc, &info_register, 0, NULL);
+    HANDLE thread_unregister = CreateThread(NULL, 0, thread_unregister_class_proc, &info_unregister, 0, NULL);
+
+    ok(thread_register != NULL, "CreateThread failed, error %ld\n", GetLastError());
+    ok(WaitForSingleObject(thread_register, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+    CloseHandle(thread_register);
+    ok(thread_unregister != NULL, "CreateThread failed, error %ld\n", GetLastError());
+    ok(WaitForSingleObject(thread_unregister, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
+    CloseHandle(thread_unregister);
+}
+
 START_TEST(class)
 {
     char **argv;
@@ -2471,6 +2520,7 @@ START_TEST(class)
     test_comctl32_classes();
     test_actctx_classes();
     test_class_name();
+    test_class_multithread();
 
     /* this test unregisters the Button class so it should be executed at the end */
     test_instances();
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 135b11ddac4c..6ef13eaeaa3e 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -9297,6 +9297,12 @@ static void test_layered_window(void)
     HBITMAP hbm;
     BOOL ret;
     MSG msg;
+    HDC hdc_from_hwnd;
+    BLENDFUNCTION bf;
+    bf.AlphaFormat = 0;
+    bf.BlendFlags = 0;
+    bf.BlendOp = 0;
+    bf.SourceConstantAlpha = 180;
 
     if (!pGetLayeredWindowAttributes || !pSetLayeredWindowAttributes || !pUpdateLayeredWindow)
     {
@@ -9320,10 +9326,18 @@ static void test_layered_window(void)
     ret = pSetLayeredWindowAttributes( hwnd, 0, 0, LWA_ALPHA );
     ok( !ret, "SetLayeredWindowAttributes should fail on non-layered window\n" );
     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
+    hdc_from_hwnd = GetDC( hwnd );
+    ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc_from_hwnd, &pt, 0, &bf, ULW_ALPHA );
+    ReleaseDC ( hwnd, hdc_from_hwnd );
+    ok( ret, "UpdateLayeredWindow should succeed on layered window\n" );
     ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags );
     ok( !ret, "GetLayeredWindowAttributes should fail on layered but not initialized window\n" );
     ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE );
     ok( ret, "UpdateLayeredWindow should succeed on layered window\n" );
+    hdc_from_hwnd = GetDC( hwnd );
+    ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc_from_hwnd, &pt, 0, &bf, ULW_ALPHA );
+    ReleaseDC ( hwnd, hdc_from_hwnd );
+    ok( ret, "UpdateLayeredWindow should succeed on layered window\n" );
     ret = pGetLayeredWindowAttributes( hwnd, &key, &alpha, &flags );
     ok( !ret, "GetLayeredWindowAttributes should fail on layered but not initialized window\n" );
     ret = pSetLayeredWindowAttributes( hwnd, 0x123456, 44, LWA_ALPHA );
@@ -9459,6 +9473,10 @@ static void test_layered_window(void)
     SetWindowLongA( hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED );
     ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc, &pt, 0, NULL, ULW_OPAQUE );
     ok( ret, "UpdateLayeredWindow should succeed on layered window\n" );
+    hdc_from_hwnd = GetDC( hwnd );
+    ret = pUpdateLayeredWindow( hwnd, 0, NULL, &sz, hdc_from_hwnd, &pt, 0, &bf, ULW_ALPHA );
+    ReleaseDC ( hwnd, hdc_from_hwnd );
+    ok( ret, "UpdateLayeredWindow should succeed on layered window\n" );
 
     ret = pSetLayeredWindowAttributes( hwnd, 0, 255, LWA_ALPHA );
     ok( ret, "SetLayeredWindowAttributes should succeed on layered window\n" );
diff --git a/dlls/vbscript/compile.c b/dlls/vbscript/compile.c
index a3fedc950a1e..3777624c6d4d 100644
--- a/dlls/vbscript/compile.c
+++ b/dlls/vbscript/compile.c
@@ -402,7 +402,14 @@ static HRESULT compile_error(script_ctx_t *ctx, compile_ctx_t *compiler, HRESULT
     ctx->ei.scode = error;
     ctx->ei.bstrSource = get_vbscript_string(VBS_COMPILE_ERROR);
     map_vbs_exception(&ctx->ei);
-    return report_script_error(ctx, compiler->code, compiler->loc);
+
+    if(!ctx->error_loc_code) {
+        grab_vbscode(compiler->code);
+        ctx->error_loc_code = compiler->code;
+        ctx->error_loc_offset = compiler->loc;
+    }
+
+    return SCRIPT_E_RECORDED;
 }
 
 static expression_t *lookup_const_decls(compile_ctx_t *ctx, const WCHAR *name, BOOL lookup_global)
@@ -864,7 +871,7 @@ static HRESULT compile_foreach_statement(compile_ctx_t *ctx, foreach_statement_t
 static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *stat)
 {
     statement_ctx_t loop_ctx = {2};
-    unsigned step_instr, instr;
+    unsigned step_instr, loop_start, instr;
     BSTR identifier;
     HRESULT hres;
 
@@ -918,27 +925,30 @@ static HRESULT compile_forto_statement(compile_ctx_t *ctx, forto_statement_t *st
     if(!emit_catch(ctx, 2))
         return E_OUTOFMEMORY;
 
+    loop_start = ctx->instr_cnt;
     hres = compile_statement(ctx, &loop_ctx, stat->body);
     if(FAILED(hres))
         return hres;
 
-    /* FIXME: Error handling can't be done compatible with native using OP_incc here. */
+    /* We need a separated OP_step here so that errors jump to the end-of-loop catch. */
+    ctx->loc = stat->stat.loc;
     instr = push_instr(ctx, OP_incc);
     if(!instr)
         return E_OUTOFMEMORY;
     instr_ptr(ctx, instr)->arg1.bstr = identifier;
 
-    hres = push_instr_addr(ctx, OP_jmp, step_instr);
-    if(FAILED(hres))
-        return hres;
+    instr = push_instr(ctx, OP_step);
+    if(!instr)
+        return E_OUTOFMEMORY;
+    instr_ptr(ctx, instr)->arg2.bstr = identifier;
+    instr_ptr(ctx, instr)->arg1.uint = loop_ctx.for_end_label;
 
-    hres = push_instr_uint(ctx, OP_pop, 2);
+    hres = push_instr_addr(ctx, OP_jmp, loop_start);
     if(FAILED(hres))
         return hres;
 
     label_set_addr(ctx, loop_ctx.for_end_label);
 
-    /* FIXME: reconsider after OP_incc fixup. */
     if(!emit_catch(ctx, 0))
         return E_OUTOFMEMORY;
 
@@ -954,6 +964,9 @@ static HRESULT compile_with_statement(compile_ctx_t *ctx, with_statement_t *stat
     if(FAILED(hres))
         return hres;
 
+    if(!push_instr(ctx, OP_with))
+        return E_OUTOFMEMORY;
+
     if(!emit_catch(ctx, 1))
         return E_OUTOFMEMORY;
 
@@ -1138,8 +1151,7 @@ static HRESULT compile_dim_statement(compile_ctx_t *ctx, dim_statement_t *stat)
     while(1) {
         if(lookup_dim_decls(ctx, dim_decl->name) || lookup_args_name(ctx, dim_decl->name)
            || lookup_const_decls(ctx, dim_decl->name, FALSE)) {
-            FIXME("dim %s name redefined\n", debugstr_w(dim_decl->name));
-            return E_FAIL;
+            return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
         }
 
         ctx->func->var_cnt++;
@@ -1192,6 +1204,21 @@ static HRESULT compile_redim_statement(compile_ctx_t *ctx, redim_statement_t *st
     return S_OK;
 }
 
+static HRESULT compile_erase_statement(compile_ctx_t *ctx, erase_statement_t *stat)
+{
+    HRESULT hres;
+
+    hres = push_instr_bstr(ctx, OP_erase, stat->identifier);
+    if(FAILED(hres))
+        return hres;
+
+    if(!emit_catch(ctx, 0))
+        return E_OUTOFMEMORY;
+
+
+    return S_OK;
+}
+
 static HRESULT compile_const_statement(compile_ctx_t *ctx, const_statement_t *stat)
 {
     const_decl_t *decl, *next_decl = stat->decls;
@@ -1201,8 +1228,7 @@ static HRESULT compile_const_statement(compile_ctx_t *ctx, const_statement_t *st
 
         if(!lookup_const_decls(ctx, decl->name, FALSE)) {
             if(lookup_args_name(ctx, decl->name) || lookup_dim_decls(ctx, decl->name)) {
-                FIXME("%s redefined\n", debugstr_w(decl->name));
-                return E_FAIL;
+                return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
             }
         }
 
@@ -1254,8 +1280,7 @@ static HRESULT compile_exitdo_statement(compile_ctx_t *ctx)
             break;
     }
     if(!iter) {
-        FIXME("Exit Do outside Do Loop\n");
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_INVALID_EXIT);
     }
 
     if(pop_cnt) {
@@ -1280,8 +1305,7 @@ static HRESULT compile_exitfor_statement(compile_ctx_t *ctx)
             break;
     }
     if(!iter) {
-        FIXME("Exit For outside For loop\n");
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_INVALID_EXIT);
     }
 
     if(pop_cnt) {
@@ -1313,8 +1337,7 @@ static HRESULT exit_label(compile_ctx_t *ctx, unsigned jmp_label)
 static HRESULT compile_exitsub_statement(compile_ctx_t *ctx)
 {
     if(!ctx->sub_end_label) {
-        FIXME("Exit Sub outside Sub?\n");
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_INVALID_EXIT);
     }
 
     return exit_label(ctx, ctx->sub_end_label);
@@ -1323,8 +1346,7 @@ static HRESULT compile_exitsub_statement(compile_ctx_t *ctx)
 static HRESULT compile_exitfunc_statement(compile_ctx_t *ctx)
 {
     if(!ctx->func_end_label) {
-        FIXME("Exit Function outside Function?\n");
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_INVALID_EXIT);
     }
 
     return exit_label(ctx, ctx->func_end_label);
@@ -1333,8 +1355,7 @@ static HRESULT compile_exitfunc_statement(compile_ctx_t *ctx)
 static HRESULT compile_exitprop_statement(compile_ctx_t *ctx)
 {
     if(!ctx->prop_end_label) {
-        FIXME("Exit Property outside Property?\n");
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_INVALID_EXIT);
     }
 
     return exit_label(ctx, ctx->prop_end_label);
@@ -1377,8 +1398,7 @@ static HRESULT collect_const_decls(compile_ctx_t *ctx, statement_t *stat)
                     break; /* already collected */
 
                 if(lookup_args_name(ctx, decl->name) || lookup_dim_decls(ctx, decl->name)) {
-                    FIXME("%s redefined\n", debugstr_w(decl->name));
-                    return E_FAIL;
+                    return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
                 }
 
                 new_decl = compiler_alloc(ctx->code, sizeof(*new_decl));
@@ -1520,6 +1540,9 @@ static HRESULT compile_statement(compile_ctx_t *ctx, statement_ctx_t *stat_ctx,
         case STAT_ONERROR:
             hres = compile_onerror_statement(ctx, (onerror_statement_t*)stat);
             break;
+        case STAT_ERASE:
+            hres = compile_erase_statement(ctx, (erase_statement_t*)stat);
+            break;
         case STAT_REDIM:
             hres = compile_redim_statement(ctx, (redim_statement_t*)stat);
             break;
@@ -1712,8 +1735,7 @@ static HRESULT create_function(compile_ctx_t *ctx, function_decl_t *decl, functi
     HRESULT hres;
 
     if(lookup_dim_decls(ctx, decl->name) || lookup_const_decls(ctx, decl->name, FALSE)) {
-        FIXME("%s: redefinition\n", debugstr_w(decl->name));
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
     }
 
     func = compiler_alloc(ctx->code, sizeof(*func));
@@ -1835,8 +1857,7 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
 
     if(lookup_dim_decls(ctx, class_decl->name) || lookup_funcs_name(ctx, class_decl->name)
             || lookup_const_decls(ctx, class_decl->name, FALSE) || lookup_class_name(ctx, class_decl->name)) {
-        FIXME("%s: redefinition\n", debugstr_w(class_decl->name));
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
     }
 
     class_desc = compiler_alloc_zero(ctx->code, sizeof(*class_desc));
@@ -1908,8 +1929,7 @@ static HRESULT compile_class(compile_ctx_t *ctx, class_decl_t *class_decl)
 
     for(prop_decl = class_decl->props, i=0; prop_decl; prop_decl = prop_decl->next, i++) {
         if(lookup_class_funcs(class_desc, prop_decl->name)) {
-            FIXME("Property %s redefined\n", debugstr_w(prop_decl->name));
-            return E_FAIL;
+            return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
         }
 
         class_desc->props[i].name = compiler_alloc_string(ctx->code, prop_decl->name);
@@ -2006,15 +2026,13 @@ static HRESULT check_script_collisions(compile_ctx_t *ctx, script_ctx_t *script)
 
     for(i = 0; i < var_cnt; i++) {
         if(lookup_script_identifier(ctx, script, vars[i].name)) {
-            FIXME("%s: redefined\n", debugstr_w(vars[i].name));
-            return E_FAIL;
+            return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
         }
     }
 
     for(class = ctx->code->classes; class; class = class->next) {
         if(lookup_script_identifier(ctx, script, class->name)) {
-            FIXME("%s: redefined\n", debugstr_w(class->name));
-            return E_FAIL;
+            return MAKE_VBSERROR(VBSE_NAME_REDEFINED);
         }
     }
 
@@ -2093,7 +2111,7 @@ static void release_compiler(compile_ctx_t *ctx)
 }
 
 HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item_name, const WCHAR *delimiter,
-                       DWORD_PTR cookie, unsigned start_line, DWORD flags, vbscode_t **ret)
+                       DWORD_PTR cookie, unsigned start_line, DWORD flags, BOOL skip_collisions, vbscode_t **ret)
 {
     function_decl_t *func_decl;
     named_item_t *item = NULL;
@@ -2165,7 +2183,7 @@ HRESULT compile_script(script_ctx_t *script, const WCHAR *src, const WCHAR *item
     }
 
     hres = check_script_collisions(&ctx, script);
-    if(FAILED(hres)) {
+    if(FAILED(hres) && !skip_collisions) {
         hres = compile_error(script, &ctx, hres);
         release_compiler(&ctx);
         return hres;
@@ -2192,7 +2210,7 @@ HRESULT compile_procedure(script_ctx_t *script, const WCHAR *src, const WCHAR *i
     HRESULT hres;
 
     hres = compile_script(script, src, item_name, delimiter, cookie, start_line,
-                          flags & ~SCRIPTTEXT_ISPERSISTENT, &code);
+                          flags & ~SCRIPTTEXT_ISPERSISTENT, FALSE, &code);
     if(FAILED(hres))
         return hres;
 
diff --git a/dlls/vbscript/global.c b/dlls/vbscript/global.c
index f38ff895ef7b..b6a32fdacdbd 100644
--- a/dlls/vbscript/global.c
+++ b/dlls/vbscript/global.c
@@ -1927,14 +1927,60 @@ static HRESULT Global_Chr(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VA
 
 static HRESULT Global_AscW(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    BSTR conv_str = NULL, str;
+    HRESULT hres = S_OK;
+
+    TRACE("(%s)\n", debugstr_variant(arg));
+
+    switch(V_VT(arg)) {
+    case VT_NULL:
+        return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
+    case VT_EMPTY:
+        return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
+    case VT_BSTR:
+        str = V_BSTR(arg);
+        break;
+    default:
+        hres = to_string(arg, &conv_str);
+        if(FAILED(hres))
+            return hres;
+        str = conv_str;
+    }
+
+    if(!SysStringLen(str))
+        hres = MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
+    else
+        hres = return_short(res, *str);
+
+    SysFreeString(conv_str);
+    return hres;
 }
 
 static HRESULT Global_ChrW(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    int c;
+    WCHAR ch;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_variant(arg));
+
+    hres = to_int(arg, &c);
+    if(FAILED(hres))
+        return hres;
+
+    if(c != (short)c && c != (unsigned short)c) {
+        WARN("invalid arg %d\n", c);
+        return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
+    }
+
+    ch = c;
+    if(res) {
+        V_VT(res) = VT_BSTR;
+        V_BSTR(res) = SysAllocStringLen(&ch, 1);
+        if(!V_BSTR(res))
+            return E_OUTOFMEMORY;
+    }
+    return S_OK;
 }
 
 static HRESULT Global_Abs(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
@@ -3319,40 +3365,296 @@ static HRESULT Global_Round(BuiltinDisp *This, VARIANT *args, unsigned args_cnt,
     return return_double(res, d);
 }
 
+/* Check that the character is one of the 69 non-blank characters as defined by ECMA-262 B.2.1 */
+static inline BOOL is_ecma_nonblank(WCHAR c)
+{
+    return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')
+        || c == '@' || c == '*' || c == '_' || c == '+' || c == '-' || c == '.' || c == '/';
+}
+
+static WCHAR int_to_hex(int i)
+{
+    if(i < 10) return '0' + i;
+    return 'A' + i - 10;
+}
+
+static int hex_to_int(WCHAR c)
+{
+    if(c >= '0' && c <= '9') return c - '0';
+    if(c >= 'A' && c <= 'F') return c - 'A' + 10;
+    if(c >= 'a' && c <= 'f') return c - 'a' + 10;
+    return -1;
+}
+
 static HRESULT Global_Escape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    BSTR conv_str = NULL, str, ret;
+    const WCHAR *ptr;
+    DWORD len = 0;
+    HRESULT hres;
+
+    TRACE("(%s)\n", debugstr_variant(arg));
+
+    if(V_VT(arg) == VT_NULL)
+        return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
+
+    if(V_VT(arg) == VT_BSTR) {
+        str = V_BSTR(arg);
+    }else {
+        hres = to_string(arg, &conv_str);
+        if(FAILED(hres))
+            return hres;
+        str = conv_str;
+    }
+
+    for(ptr = str; *ptr; ptr++) {
+        if(*ptr > 0xff)
+            len += 6;
+        else if(is_ecma_nonblank(*ptr))
+            len++;
+        else
+            len += 3;
+    }
+
+    ret = SysAllocStringLen(NULL, len);
+    if(!ret) {
+        SysFreeString(conv_str);
+        return E_OUTOFMEMORY;
+    }
+
+    len = 0;
+    for(ptr = str; *ptr; ptr++) {
+        if(*ptr > 0xff) {
+            ret[len++] = '%';
+            ret[len++] = 'u';
+            ret[len++] = int_to_hex(*ptr >> 12);
+            ret[len++] = int_to_hex((*ptr >> 8) & 0xf);
+            ret[len++] = int_to_hex((*ptr >> 4) & 0xf);
+            ret[len++] = int_to_hex(*ptr & 0xf);
+        }else if(is_ecma_nonblank(*ptr)) {
+            ret[len++] = *ptr;
+        }else {
+            ret[len++] = '%';
+            ret[len++] = int_to_hex(*ptr >> 4);
+            ret[len++] = int_to_hex(*ptr & 0xf);
+        }
+    }
+
+    SysFreeString(conv_str);
+
+    if(res) {
+        V_VT(res) = VT_BSTR;
+        V_BSTR(res) = ret;
+    }else {
+        SysFreeString(ret);
+    }
+    return S_OK;
 }
 
 static HRESULT Global_Unescape(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    BSTR conv_str = NULL, str, ret;
+    const WCHAR *ptr;
+    DWORD len = 0;
+    HRESULT hres;
+
+    TRACE("(%s)\n", debugstr_variant(arg));
+
+    if(V_VT(arg) == VT_NULL)
+        return MAKE_VBSERROR(VBSE_ILLEGAL_NULL_USE);
+
+    if(V_VT(arg) == VT_BSTR) {
+        str = V_BSTR(arg);
+    }else {
+        hres = to_string(arg, &conv_str);
+        if(FAILED(hres))
+            return hres;
+        str = conv_str;
+    }
+
+    /* First pass: compute output length */
+    for(ptr = str; *ptr; ptr++) {
+        if(*ptr == '%') {
+            if(hex_to_int(ptr[1]) != -1 && hex_to_int(ptr[2]) != -1)
+                ptr += 2;
+            else if(ptr[1] == 'u' && hex_to_int(ptr[2]) != -1 && hex_to_int(ptr[3]) != -1
+                    && hex_to_int(ptr[4]) != -1 && hex_to_int(ptr[5]) != -1)
+                ptr += 5;
+        }
+        len++;
+    }
+
+    ret = SysAllocStringLen(NULL, len);
+    if(!ret) {
+        SysFreeString(conv_str);
+        return E_OUTOFMEMORY;
+    }
+
+    /* Second pass: decode */
+    len = 0;
+    for(ptr = str; *ptr; ptr++) {
+        if(*ptr == '%') {
+            if(hex_to_int(ptr[1]) != -1 && hex_to_int(ptr[2]) != -1) {
+                ret[len] = (hex_to_int(ptr[1]) << 4) + hex_to_int(ptr[2]);
+                ptr += 2;
+            }else if(ptr[1] == 'u' && hex_to_int(ptr[2]) != -1 && hex_to_int(ptr[3]) != -1
+                    && hex_to_int(ptr[4]) != -1 && hex_to_int(ptr[5]) != -1) {
+                ret[len] = (hex_to_int(ptr[2]) << 12) + (hex_to_int(ptr[3]) << 8)
+                    + (hex_to_int(ptr[4]) << 4) + hex_to_int(ptr[5]);
+                ptr += 5;
+            }else {
+                ret[len] = *ptr;
+            }
+        }else {
+            ret[len] = *ptr;
+        }
+        len++;
+    }
+
+    SysFreeString(conv_str);
+
+    if(res) {
+        V_VT(res) = VT_BSTR;
+        V_BSTR(res) = ret;
+    }else {
+        SysFreeString(ret);
+    }
+    return S_OK;
 }
 
 static HRESULT Global_Eval(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    vbscode_t *code;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_variant(arg));
+
+    if(V_VT(arg) != VT_BSTR) {
+        if(res)
+            return VariantCopy(res, arg);
+        return S_OK;
+    }
+
+    hres = compile_script(This->ctx, V_BSTR(arg), NULL, NULL, 0, 0,
+                          SCRIPTTEXT_ISEXPRESSION, FALSE, &code);
+    if(FAILED(hres)) {
+        clear_error_loc(This->ctx);
+        return hres;
+    }
+
+    if(is_exec_local_scope(This->ctx->current_exec)) {
+        This->ctx->caller_exec = This->ctx->current_exec;
+        return exec_script(This->ctx, FALSE, &code->main_code, NULL, NULL, res);
+    }
+
+    return exec_global_code(This->ctx, code, res, FALSE);
 }
 
 static HRESULT Global_Execute(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    vbscode_t *code;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_variant(arg));
+
+    if(V_VT(arg) != VT_BSTR)
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+
+    hres = compile_script(This->ctx, V_BSTR(arg), NULL, NULL, 0, 0,
+                          0, TRUE, &code);
+    if(FAILED(hres)) {
+        clear_error_loc(This->ctx);
+        return hres;
+    }
+
+    if(is_exec_local_scope(This->ctx->current_exec)) {
+        unsigned i;
+
+        /* Pre-register Dim variables in the caller's scope */
+        for(i = 0; i < code->main_code.var_cnt; i++) {
+            hres = exec_add_caller_dynamic_var(This->ctx, This->ctx->current_exec,
+                                               code->main_code.vars[i].name);
+            if(FAILED(hres))
+                return hres;
+        }
+
+        This->ctx->caller_exec = This->ctx->current_exec;
+        return exec_script(This->ctx, FALSE, &code->main_code, NULL, NULL, res);
+    }
+
+    return exec_global_code(This->ctx, code, res, FALSE);
 }
 
 static HRESULT Global_ExecuteGlobal(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    vbscode_t *code;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_variant(arg));
+
+    if(V_VT(arg) != VT_BSTR)
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+
+    hres = compile_script(This->ctx, V_BSTR(arg), NULL, NULL, 0, 0,
+                          0, TRUE, &code);
+    if(FAILED(hres)) {
+        clear_error_loc(This->ctx);
+        return hres;
+    }
+
+    return exec_global_code(This->ctx, code, res, FALSE);
 }
 
 static HRESULT Global_GetRef(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
 {
-    FIXME("\n");
-    return E_NOTIMPL;
+    named_item_t *item;
+    function_t **funcs;
+    IDispatch *disp;
+    const WCHAR *name;
+    size_t i, cnt;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_variant(arg));
+
+    if(V_VT(arg) != VT_BSTR)
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+
+    name = V_BSTR(arg);
+    if(!name || !name[0])
+        return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
+
+    /* Search the current named item's script object first */
+    item = This->ctx->current_named_item;
+    if(item && item->script_obj) {
+        funcs = item->script_obj->global_funcs;
+        cnt = item->script_obj->global_funcs_cnt;
+        for(i = 0; i < cnt; i++) {
+            if(!wcsicmp(funcs[i]->name, name)) {
+                hres = create_func_ref(This->ctx, funcs[i], &disp);
+                if(FAILED(hres))
+                    return hres;
+                V_VT(res) = VT_DISPATCH;
+                V_DISPATCH(res) = disp;
+                return S_OK;
+            }
+        }
+    }
+
+    /* Search global script object */
+    funcs = This->ctx->script_obj->global_funcs;
+    cnt = This->ctx->script_obj->global_funcs_cnt;
+    for(i = 0; i < cnt; i++) {
+        if(!wcsicmp(funcs[i]->name, name)) {
+            hres = create_func_ref(This->ctx, funcs[i], &disp);
+            if(FAILED(hres))
+                return hres;
+            V_VT(res) = VT_DISPATCH;
+            V_DISPATCH(res) = disp;
+            return S_OK;
+        }
+    }
+
+    return MAKE_VBSERROR(VBSE_ILLEGAL_FUNC_CALL);
 }
 
 static HRESULT Global_Err(BuiltinDisp *This, VARIANT *arg, unsigned args_cnt, VARIANT *res)
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index 79225af27b96..2a73a7fb51ab 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 
 static DISPID propput_dispid = DISPID_PROPERTYPUT;
 
-typedef struct {
+typedef struct _exec_ctx_t {
     vbscode_t *code;
     instr_t *instr;
     script_ctx_t *script;
@@ -47,6 +47,8 @@ typedef struct {
     VARIANT *stack;
 
     VARIANT ret_val;
+
+    exec_ctx_t *caller;
 } exec_ctx_t;
 
 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
@@ -182,6 +184,29 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
         }
     }
 
+    if(ctx->func->type == FUNC_GLOBAL && ctx->caller) {
+        exec_ctx_t *caller = ctx->caller;
+
+        for(i=0; i < caller->func->var_cnt; i++) {
+            if(!wcsicmp(caller->func->vars[i].name, name)) {
+                ref->type = REF_VAR;
+                ref->u.v = caller->vars+i;
+                return S_OK;
+            }
+        }
+
+        for(i=0; i < caller->func->arg_cnt; i++) {
+            if(!wcsicmp(caller->func->args[i].name, name)) {
+                ref->type = REF_VAR;
+                ref->u.v = caller->args+i;
+                return S_OK;
+            }
+        }
+
+        if(lookup_dynamic_vars(caller->dynamic_vars, name, ref))
+            return S_OK;
+    }
+
     if(ctx->code->named_item) {
         if(lookup_global_vars(ctx->code->named_item->script_obj, name, ref))
             return S_OK;
@@ -293,7 +318,7 @@ void clear_ei(EXCEPINFO *ei)
     memset(ei, 0, sizeof(*ei));
 }
 
-static void clear_error_loc(script_ctx_t *ctx)
+void clear_error_loc(script_ctx_t *ctx)
 {
     if(ctx->error_loc_code) {
         release_vbscode(ctx->error_loc_code);
@@ -449,15 +474,15 @@ static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
     }
 
     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
-        FIXME("not supported type: %s\n", debugstr_variant(v));
+        WARN("not supported type: %s\n", debugstr_variant(v));
         VariantClear(v);
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }
 
     v = V_BYREF(v);
     if(V_VT(v) != VT_DISPATCH) {
-        FIXME("not disp %s\n", debugstr_variant(v));
-        return E_FAIL;
+        WARN("not disp %s\n", debugstr_variant(v));
+        return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }
 
     if(V_DISPATCH(v))
@@ -527,8 +552,8 @@ HRESULT array_access(SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret)
     HRESULT hres;
 
     if(!array) {
-        FIXME("NULL array\n");
-        return E_FAIL;
+        WARN("NULL array\n");
+        return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
     }
 
     hres = SafeArrayLock(array);
@@ -536,9 +561,9 @@ HRESULT array_access(SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret)
         return hres;
 
     if(array->cDims != argc) {
-        FIXME("argc %d does not match cDims %d\n", dp->cArgs, array->cDims);
+        WARN("argc %d does not match cDims %d\n", dp->cArgs, array->cDims);
         SafeArrayUnlock(array);
-        return E_FAIL;
+        return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
     }
 
     indices = malloc(sizeof(*indices) * argc);
@@ -583,32 +608,30 @@ static HRESULT variant_call(exec_ctx_t *ctx, VARIANT *v, unsigned arg_cnt, VARIA
     case VT_DISPATCH:
         vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
         hres = disp_call(ctx->script, V_DISPATCH(v), DISPID_VALUE, &dp, res);
-        break;
+        stack_popn(ctx, arg_cnt);
+        return hres;
     default:
         FIXME("unsupported on %s\n", debugstr_variant(v));
         return E_NOTIMPL;
     }
 
-    if(array) {
-        if(!res) {
-            FIXME("no res\n");
-            return E_NOTIMPL;
-        }
-
-        vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
-        hres = array_access(array, &dp, &v);
-        if(FAILED(hres))
-            return hres;
+    if(!res) {
+        FIXME("no res\n");
+        return E_NOTIMPL;
+    }
 
+    vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
+    hres = array_access(array, &dp, &v);
+    if(SUCCEEDED(hres)) {
         V_VT(res) = VT_BYREF|VT_VARIANT;
         V_BYREF(res) = v;
     }
 
     stack_popn(ctx, arg_cnt);
-    return S_OK;
+    return hres;
 }
 
-static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res, BSTR identifier, unsigned arg_cnt)
+static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res, BSTR identifier, unsigned arg_cnt, BOOL is_call)
 {
     DISPPARAMS dp;
     ref_t ref;
@@ -626,9 +649,27 @@ static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res, BSTR identifier, unsigned
         if(arg_cnt)
             return variant_call(ctx, ref.u.v, arg_cnt, res);
 
+        if(is_call) {
+            VARIANT *v;
+
+            v = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
+            if(V_VT(v) == VT_DISPATCH) {
+                VARIANT result;
+                V_VT(&result) = VT_EMPTY;
+                hres = get_disp_value(ctx->script, V_DISPATCH(v), &result);
+                if(FAILED(hres))
+                    return hres;
+                if(res)
+                    *res = result;
+                else
+                    VariantClear(&result);
+                break;
+            }
+        }
+
         if(!res) {
-            FIXME("REF_VAR no res\n");
-            return E_NOTIMPL;
+            WARN("REF_VAR no res\n");
+            return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
         }
 
         V_VT(res) = VT_BYREF|VT_VARIANT;
@@ -688,7 +729,7 @@ static HRESULT interp_icall(exec_ctx_t *ctx)
 
     TRACE("\n");
 
-    hres = do_icall(ctx, &v, identifier, arg_cnt);
+    hres = do_icall(ctx, &v, identifier, arg_cnt, TRUE);
     if(FAILED(hres))
         return hres;
 
@@ -702,19 +743,26 @@ static HRESULT interp_icallv(exec_ctx_t *ctx)
 
     TRACE("\n");
 
-    return do_icall(ctx, NULL, identifier, arg_cnt);
+    return do_icall(ctx, NULL, identifier, arg_cnt, TRUE);
 }
 
 static HRESULT interp_vcall(exec_ctx_t *ctx)
 {
     const unsigned arg_cnt = ctx->instr->arg1.uint;
-    VARIANT res, *v;
+    VARIANT res = {0}, *v;
     HRESULT hres;
 
     TRACE("\n");
 
     v = stack_pop(ctx);
     hres = variant_call(ctx, v, arg_cnt, &res);
+    if(SUCCEEDED(hres) && V_VT(&res) == (VT_BYREF|VT_VARIANT)) {
+        VARIANT tmp;
+        V_VT(&tmp) = VT_EMPTY;
+        hres = VariantCopyInd(&tmp, &res);
+        if(SUCCEEDED(hres))
+            res = tmp;
+    }
     VariantClear(v);
     if(FAILED(hres))
         return hres;
@@ -750,8 +798,8 @@ static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
         return hres;
 
     if(!obj) {
-        FIXME("NULL obj\n");
-        return E_FAIL;
+        WARN("NULL obj\n");
+        return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }
 
     vbstack_to_dp(ctx, arg_cnt, FALSE, &dp);
@@ -803,7 +851,7 @@ static HRESULT interp_ident(exec_ctx_t *ctx)
         return stack_push(ctx, &v);
     }
 
-    hres = do_icall(ctx, &v, identifier, 0);
+    hres = do_icall(ctx, &v, identifier, 0, FALSE);
     if(FAILED(hres))
         return hres;
 
@@ -876,8 +924,8 @@ static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, WORD flags, DISPPARAMS *
             }
 
             if(!array) {
-                FIXME("null array\n");
-                return E_FAIL;
+                WARN("null array\n");
+                return MAKE_VBSERROR(VBSE_OUT_OF_BOUNDS);
             }
 
             hres = array_access(array, dp, &v);
@@ -979,8 +1027,8 @@ static HRESULT interp_assign_member(exec_ctx_t *ctx)
         return hres;
 
     if(!obj) {
-        FIXME("NULL obj\n");
-        return E_FAIL;
+        WARN("NULL obj\n");
+        return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }
 
     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
@@ -1011,8 +1059,8 @@ static HRESULT interp_set_member(exec_ctx_t *ctx)
         return hres;
 
     if(!obj) {
-        FIXME("NULL obj\n");
-        return E_FAIL;
+        WARN("NULL obj\n");
+        return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }
 
     hres = stack_assume_disp(ctx, arg_cnt, NULL);
@@ -1097,6 +1145,12 @@ static HRESULT interp_numval(exec_ctx_t *ctx)
     if(FAILED(hres))
         return hres;
 
+    if(V_VT(val.v) == VT_EMPTY) {
+        V_VT(&v) = VT_I2;
+        V_I2(&v) = 0;
+        return stack_push(ctx, &v);
+    }
+
     if (V_VT(val.v) == VT_BSTR) {
         V_VT(&v) = VT_EMPTY;
         hres = VariantChangeType(&v, val.v, 0, VT_R8);
@@ -1330,7 +1384,7 @@ static HRESULT interp_redim(exec_ctx_t *ctx)
 
     if(V_ISARRAY(v)) {
         SAFEARRAY *sa = V_ISBYREF(v) ? *V_ARRAYREF(v) : V_ARRAY(v);
-        if(sa->fFeatures & FADF_FIXEDSIZE)
+        if(sa && (sa->fFeatures & FADF_FIXEDSIZE))
             return MAKE_VBSERROR(VBSE_ARRAY_LOCKED);
     }
 
@@ -1421,6 +1475,69 @@ static HRESULT interp_redim_preserve(exec_ctx_t *ctx)
     return hres;
 }
 
+static HRESULT interp_erase(exec_ctx_t *ctx)
+{
+    const BSTR identifier = ctx->instr->arg1.bstr;
+    VARIANT *v;
+    SAFEARRAY *array;
+    ref_t ref;
+    HRESULT hres;
+
+    TRACE("%s\n", debugstr_w(identifier));
+
+    hres = lookup_identifier(ctx, identifier, VBDISP_LET, &ref);
+    if(FAILED(hres))
+        return hres;
+
+    if(ref.type == REF_NONE) {
+        if(ctx->func->code_ctx->option_explicit)
+            return MAKE_VBSERROR(VBSE_VARIABLE_UNDEFINED);
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+    }
+
+    if(ref.type != REF_VAR)
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+
+
+    v = ref.u.v;
+    if(V_VT(v) == (VT_VARIANT|VT_BYREF))
+        v = V_VARIANTREF(v);
+
+    if(!(V_VT(v) & VT_ARRAY)) {
+        WARN("Erase on non-array type %d\n", V_VT(v));
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+    }
+
+    array = V_ISBYREF(v) ? *V_ARRAYREF(v) : V_ARRAY(v);
+    if(!array)
+        return S_OK;
+
+    if(array->fFeatures & FADF_FIXEDSIZE) {
+        /* Fixed-size array: reinitialize all elements to default values. */
+        unsigned i, element_cnt = 1;
+        VARIANT *data;
+
+        for(i = 0; i < array->cDims; i++)
+            element_cnt *= array->rgsabound[i].cElements;
+
+        hres = SafeArrayAccessData(array, (void**)&data);
+        if(SUCCEEDED(hres)) {
+            for(i = 0; i < element_cnt; i++)
+                VariantClear(&data[i]);
+            SafeArrayUnaccessData(array);
+        }
+    }else {
+        /* Dynamic array: deallocate it. */
+        SafeArrayDestroy(array);
+        if(V_ISBYREF(v))
+            *V_ARRAYREF(v) = NULL;
+        else
+            V_ARRAY(v) = NULL;
+    }
+
+    return hres;
+}
+
 static HRESULT interp_step(exec_ctx_t *ctx)
 {
     const BSTR ident = ctx->instr->arg2.bstr;
@@ -1431,6 +1548,9 @@ static HRESULT interp_step(exec_ctx_t *ctx)
 
     TRACE("%s\n", debugstr_w(ident));
 
+    if(V_VT(stack_top(ctx, 0)) == VT_EMPTY || V_VT(stack_top(ctx, 1)) == VT_EMPTY)
+        return MAKE_VBSERROR(VBSE_FOR_LOOP_NOT_INITIALIZED);
+
     V_VT(&zero) = VT_I2;
     V_I2(&zero) = 0;
     hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
@@ -2109,8 +2229,8 @@ static HRESULT interp_is(exec_ctx_t *ctx)
 
     stack_pop_deref(ctx, &v);
     if(V_VT(v.v) != VT_DISPATCH && V_VT(v.v) != VT_UNKNOWN) {
-        FIXME("Unhandled type %s\n", debugstr_variant(v.v));
-        hres = E_NOTIMPL;
+        WARN("Unhandled type %s\n", debugstr_variant(v.v));
+        hres = MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }else if(V_UNKNOWN(v.v)) {
         hres = IUnknown_QueryInterface(V_UNKNOWN(v.v), &IID_IUnknown, (void**)&r);
     }
@@ -2120,8 +2240,8 @@ static HRESULT interp_is(exec_ctx_t *ctx)
 
     stack_pop_deref(ctx, &v);
     if(V_VT(v.v) != VT_DISPATCH && V_VT(v.v) != VT_UNKNOWN) {
-        FIXME("Unhandled type %s\n", debugstr_variant(v.v));
-        hres = E_NOTIMPL;
+        WARN("Unhandled type %s\n", debugstr_variant(v.v));
+        hres = MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
     }else if(V_UNKNOWN(v.v)) {
         hres = IUnknown_QueryInterface(V_UNKNOWN(v.v), &IID_IUnknown, (void**)&l);
     }
@@ -2389,6 +2509,20 @@ static HRESULT interp_incc(exec_ctx_t *ctx)
     return S_OK;
 }
 
+static HRESULT interp_with(exec_ctx_t *ctx)
+{
+    VARIANT *v;
+
+    TRACE("\n");
+
+    v = stack_top(ctx, 0);
+    if(V_VT(v) == (VT_VARIANT|VT_BYREF))
+        v = V_VARIANTREF(v);
+    if(V_VT(v) != VT_DISPATCH && V_VT(v) != VT_UNKNOWN)
+        return MAKE_VBSERROR(VBSE_OBJECT_REQUIRED);
+    return S_OK;
+}
+
 static HRESULT interp_catch(exec_ctx_t *ctx)
 {
     /* Nothing to do here, the OP is for unwinding only. */
@@ -2451,13 +2585,67 @@ static void release_exec(exec_ctx_t *ctx)
     free(ctx->stack);
 }
 
+BOOL is_exec_local_scope(exec_ctx_t *ctx)
+{
+    return ctx && ctx->func->type != FUNC_GLOBAL;
+}
+
+HRESULT exec_add_caller_dynamic_var(script_ctx_t *script, exec_ctx_t *ctx, const WCHAR *name)
+{
+    dynamic_var_t *new_var;
+    heap_pool_t *heap;
+    WCHAR *str;
+    unsigned size, i;
+
+    /* Skip if name already exists in caller's locals, args, or dynamic vars */
+    for(i = 0; i < ctx->func->var_cnt; i++) {
+        if(!wcsicmp(ctx->func->vars[i].name, name))
+            return S_OK;
+    }
+    for(i = 0; i < ctx->func->arg_cnt; i++) {
+        if(!wcsicmp(ctx->func->args[i].name, name))
+            return S_OK;
+    }
+    {
+        dynamic_var_t *var;
+        for(var = ctx->dynamic_vars; var; var = var->next) {
+            if(!wcsicmp(var->name, name))
+                return S_OK;
+        }
+    }
+
+    heap = &ctx->heap;
+
+    new_var = heap_pool_alloc(heap, sizeof(*new_var));
+    if(!new_var)
+        return E_OUTOFMEMORY;
+
+    size = (lstrlenW(name) + 1) * sizeof(WCHAR);
+    str = heap_pool_alloc(heap, size);
+    if(!str)
+        return E_OUTOFMEMORY;
+    memcpy(str, name, size);
+    new_var->name = str;
+    new_var->is_const = FALSE;
+    new_var->array = NULL;
+    V_VT(&new_var->v) = VT_EMPTY;
+
+    new_var->next = ctx->dynamic_vars;
+    ctx->dynamic_vars = new_var;
+    return S_OK;
+}
+
 HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbdisp_t *vbthis, DISPPARAMS *dp, VARIANT *res)
 {
     exec_ctx_t exec = {func->code_ctx};
+    named_item_t *prev_named_item;
+    exec_ctx_t *prev_exec;
     vbsop_t op;
     HRESULT hres = S_OK;
 
     exec.code = func->code_ctx;
+    exec.caller = ctx->caller_exec;
+    ctx->caller_exec = NULL;
 
     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
@@ -2527,6 +2715,12 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd
     exec.script = ctx;
     exec.func = func;
 
+    prev_named_item = ctx->current_named_item;
+    ctx->current_named_item = exec.code->named_item;
+
+    prev_exec = ctx->current_exec;
+    ctx->current_exec = &exec;
+
     while(exec.instr) {
         op = exec.instr->op;
         hres = op_funcs[op](&exec);
@@ -2587,13 +2781,15 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd
         exec.instr += op_move[op];
     }
 
+    ctx->current_exec = prev_exec;
+
     assert(!exec.top);
 
     if(extern_caller) {
         if(FAILED(hres)) {
             if(!ctx->ei.scode)
                 ctx->ei.scode = hres;
-            hres = report_script_error(ctx, ctx->error_loc_code, ctx->error_loc_offset);
+            hres = report_script_error(ctx, ctx->error_loc_code, ctx->error_loc_offset, FALSE);
             clear_error_loc(ctx);
         }
         IActiveScriptSite_OnLeaveScript(ctx->site);
@@ -2604,6 +2800,7 @@ HRESULT exec_script(script_ctx_t *ctx, BOOL extern_caller, function_t *func, vbd
         V_VT(&exec.ret_val) = VT_EMPTY;
     }
 
+    ctx->current_named_item = prev_named_item;
     release_exec(&exec);
     return hres;
 }
diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c
index 75838ac586a9..1f9c4c3b18c6 100644
--- a/dlls/vbscript/lex.c
+++ b/dlls/vbscript/lex.c
@@ -28,6 +28,13 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
 
+static int lex_error(parser_ctx_t *ctx, HRESULT hres)
+{
+    ctx->hres = hres;
+    ctx->error_loc = ctx->ptr - ctx->code;
+    return 0;
+}
+
 static const struct {
     const WCHAR *word;
     int token;
@@ -48,6 +55,7 @@ static const struct {
     {L"empty",     tEMPTY},
     {L"end",       tEND},
     {L"eqv",       tEQV},
+    {L"erase",     tERASE},
     {L"error",     tERROR},
     {L"exit",      tEXIT},
     {L"explicit",  tEXPLICIT},
@@ -169,8 +177,7 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret)
 
     while(ctx->ptr < ctx->end) {
         if(*ctx->ptr == '\n' || *ctx->ptr == '\r') {
-            FIXME("newline inside string literal\n");
-            return 0;
+            return lex_error(ctx, MAKE_VBSERROR(VBSE_UNTERMINATED_STRING));
         }
 
        if(*ctx->ptr == '"') {
@@ -183,8 +190,7 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret)
     }
 
     if(ctx->ptr == ctx->end) {
-        FIXME("unterminated string literal\n");
-        return 0;
+        return lex_error(ctx, MAKE_VBSERROR(VBSE_UNTERMINATED_STRING));
     }
 
     len += ctx->ptr-ptr;
@@ -206,6 +212,7 @@ static int parse_string_literal(parser_ctx_t *ctx, const WCHAR **ret)
 
 static int parse_date_literal(parser_ctx_t *ctx, DATE *ret)
 {
+    const WCHAR *start = ctx->ptr;
     const WCHAR *ptr = ++ctx->ptr;
     WCHAR *rptr;
     int len = 0;
@@ -213,8 +220,8 @@ static int parse_date_literal(parser_ctx_t *ctx, DATE *ret)
 
     while(ctx->ptr < ctx->end) {
         if(*ctx->ptr == '\n' || *ctx->ptr == '\r') {
-            FIXME("newline inside date literal\n");
-            return 0;
+            ctx->ptr = start;
+            return lex_error(ctx, MAKE_VBSERROR(VBSE_SYNTAX_ERROR));
         }
 
        if(*ctx->ptr == '#')
@@ -223,8 +230,8 @@ static int parse_date_literal(parser_ctx_t *ctx, DATE *ret)
     }
 
     if(ctx->ptr == ctx->end) {
-        FIXME("unterminated date literal\n");
-        return 0;
+        ctx->ptr = start;
+        return lex_error(ctx, MAKE_VBSERROR(VBSE_SYNTAX_ERROR));
     }
 
     len += ctx->ptr-ptr;
@@ -238,8 +245,8 @@ static int parse_date_literal(parser_ctx_t *ctx, DATE *ret)
     res = VarDateFromStr(rptr, ctx->lcid, 0, ret);
     free(rptr);
     if (FAILED(res)) {
-        FIXME("Invalid date literal\n");
-        return 0;
+        ctx->ptr = start;
+        return lex_error(ctx, MAKE_VBSERROR(VBSE_SYNTAX_ERROR));
     }
 
     ctx->ptr++;
@@ -298,8 +305,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret)
         }
 
         if(!is_digit(*ctx->ptr)) {
-            FIXME("Invalid numeric literal\n");
-            return 0;
+            return lex_error(ctx, MAKE_VBSERROR(VBSE_INVALID_NUMBER));
         }
 
         use_int = FALSE;
@@ -315,8 +321,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret)
             }
 
             if(sign*e + exp > INT_MAX/100) {
-                FIXME("Invalid numeric literal\n");
-                return 0;
+                return lex_error(ctx, MAKE_VBSERROR(VBSE_INVALID_NUMBER));
             }
         } while(is_digit(*ctx->ptr));
 
@@ -330,8 +335,7 @@ static int parse_numeric_literal(parser_ctx_t *ctx, void **ret)
 
     r = exp>=0 ? d*pow(10, exp) : d/pow(10, -exp);
     if(isinf(r)) {
-        FIXME("Invalid numeric literal\n");
-        return 0;
+        return lex_error(ctx, MAKE_VBSERROR(VBSE_INVALID_NUMBER));
     }
 
     *(double*)ret = r;
@@ -351,14 +355,20 @@ static int hex_to_int(WCHAR c)
 
 static int parse_hex_literal(parser_ctx_t *ctx, LONG *ret)
 {
-    const WCHAR *begin = ctx->ptr;
+    const WCHAR *begin;
     unsigned l = 0, d;
 
+    /* Skip leading zeros — Windows allows any number of them. */
+    while(ctx->ptr[1] == '0')
+        ctx->ptr++;
+
+    begin = ctx->ptr;
+
     while((d = hex_to_int(*++ctx->ptr)) != -1)
         l = l*16 + d;
 
-    if(begin + 9 /* max digits+1 */ < ctx->ptr) {
-        FIXME("invalid literal\n");
+    if(begin + 9 /* max 8 significant digits + 1 */ < ctx->ptr) {
+        WARN("overflow in hex literal\n");
         return 0;
     }
 
@@ -440,6 +450,14 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx)
             ctx->ptr++;
             return '.';
         }
+        /* After line continuation, ptr[-1] is a newline or space, but the dot
+         * is logically on the same line as the previous token. */
+        if(ctx->after_continuation
+                && (ctx->last_token == tIdentifier || ctx->last_token == ')'
+                || ctx->last_token == tEMPTYBRACKETS)) {
+            ctx->ptr++;
+            return '.';
+        }
         c = ctx->ptr[1];
         if('0' <= c && c <= '9')
             return parse_numeric_literal(ctx, lval);
@@ -510,7 +528,7 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx)
         }
         return '>';
     default:
-        FIXME("Unhandled char %c in %s\n", *ctx->ptr, debugstr_w(ctx->ptr));
+        return lex_error(ctx, MAKE_VBSERROR(VBSE_INVALID_CHAR));
     }
 
     return 0;
@@ -531,13 +549,13 @@ int parser_lex(void *lval, unsigned *loc, parser_ctx_t *ctx)
         if(ret == '_') {
             skip_spaces(ctx);
             if(*ctx->ptr != '\n' && *ctx->ptr != '\r') {
-                FIXME("'_' not followed by newline\n");
-                return 0;
+                return lex_error(ctx, MAKE_VBSERROR(VBSE_INVALID_CHAR));
             }
             if(*ctx->ptr == '\r')
                 ctx->ptr++;
             if(*ctx->ptr == '\n')
                 ctx->ptr++;
+            ctx->after_continuation = TRUE;
             continue;
         }
         if(ret != tNL || ctx->last_token != tNL)
@@ -546,5 +564,6 @@ int parser_lex(void *lval, unsigned *loc, parser_ctx_t *ctx)
         ctx->last_nl = ctx->ptr-ctx->code;
     }
 
+    ctx->after_continuation = FALSE;
     return (ctx->last_token = ret);
 }
diff --git a/dlls/vbscript/parse.h b/dlls/vbscript/parse.h
index 64c3dee2a69c..8df2c77ab8ab 100644
--- a/dlls/vbscript/parse.h
+++ b/dlls/vbscript/parse.h
@@ -116,6 +116,7 @@ typedef enum {
     STAT_DIM,
     STAT_DOUNTIL,
     STAT_DOWHILE,
+    STAT_ERASE,
     STAT_EXITDO,
     STAT_EXITFOR,
     STAT_EXITFUNC,
@@ -184,6 +185,11 @@ typedef struct {
     redim_decl_t *redim_decls;
 } redim_statement_t;
 
+typedef struct {
+    statement_t stat;
+    const WCHAR *identifier;
+} erase_statement_t;
+
 typedef struct _arg_decl_t {
     const WCHAR *name;
     BOOL by_ref;
@@ -302,6 +308,7 @@ typedef struct {
 
     int last_token;
     unsigned last_nl;
+    BOOL after_continuation;
 
     statement_t *stats;
     statement_t *stats_tail;
diff --git a/dlls/vbscript/parser.y b/dlls/vbscript/parser.y
index 4977358b333b..0d3bd4c9f43e 100644
--- a/dlls/vbscript/parser.y
+++ b/dlls/vbscript/parser.y
@@ -52,6 +52,7 @@ static statement_t *new_assign_statement(parser_ctx_t*,unsigned,expression_t*,ex
 static statement_t *new_set_statement(parser_ctx_t*,unsigned,expression_t*,expression_t*);
 static statement_t *new_dim_statement(parser_ctx_t*,unsigned,dim_decl_t*);
 static statement_t *new_redim_statement(parser_ctx_t*,unsigned,BOOL,redim_decl_t*);
+static statement_t *new_erase_statement(parser_ctx_t*,unsigned,const WCHAR*);
 static statement_t *new_while_statement(parser_ctx_t*,unsigned,statement_type_t,expression_t*,statement_t*);
 static statement_t *new_forto_statement(parser_ctx_t*,unsigned,const WCHAR*,expression_t*,expression_t*,expression_t*,statement_t*);
 static statement_t *new_foreach_statement(parser_ctx_t*,unsigned,const WCHAR*,expression_t*,statement_t*);
@@ -121,7 +122,7 @@ static statement_t *link_statements(statement_t*,statement_t*);
 %token <string> tNOT tAND tOR tXOR tEQV tIMP
 %token <string> tIS tMOD
 %token <string> tCALL tSUB tFUNCTION tGET tLET tCONST
-%token <string> tDIM tREDIM tPRESERVE
+%token <string> tDIM tREDIM tPRESERVE tERASE
 %token <string> tIF tELSE tELSEIF tEND tTHEN tEXIT
 %token <string> tWHILE tWEND tDO tLOOP tUNTIL tFOR tTO tEACH tIN
 %token <string> tSELECT tCASE tWITH
@@ -136,11 +137,14 @@ static statement_t *link_statements(statement_t*,statement_t*);
 %token <dbl> tDouble
 %token <date> tDate
 
+%right tNOT
+%left '=' tNEQ '>' '<' tGTEQ tLTEQ tIS
+
 %type <statement> Statement SimpleStatement StatementNl StatementsNl StatementsNl_opt BodyStatements IfStatement Else_opt
 %type <statement> GlobalDimDeclaration StatementsBody StatementsBody_opt
 %type <expression> Expression LiteralExpression PrimaryExpression EqualityExpression CallExpression ExpressionNl_opt
 %type <expression> ConcatExpression AdditiveExpression ModExpression IntdivExpression MultiplicativeExpression ExpExpression
-%type <expression> NotExpression UnaryExpression AndExpression OrExpression XorExpression EqvExpression SignExpression
+%type <expression> UnaryExpression AndExpression OrExpression XorExpression EqvExpression SignExpression
 %type <expression> ConstExpression NumericLiteralExpression
 %type <member> MemberExpression
 %type <expression> Arguments ArgumentList ArgumentList_opt Step_opt ExpressionList
@@ -217,6 +221,7 @@ SimpleStatement
                                             { $$ = new_assign_statement(ctx, @$, $1, $3); CHECK_ERROR; }
     | tDIM DimDeclList                      { $$ = new_dim_statement(ctx, @$, $2); CHECK_ERROR; }
     | tREDIM Preserve_opt ReDimDeclList     { $$ = new_redim_statement(ctx, @$, $2, $3); CHECK_ERROR; }
+    | tERASE Identifier                    { $$ = new_erase_statement(ctx, @$, $2); CHECK_ERROR; }
     | IfStatement                           { $$ = $1; }
     | tWHILE Expression StSep StatementsNl_opt tWEND
                                             { $$ = new_while_statement(ctx, @$, STAT_WHILE, $2, $4); CHECK_ERROR; }
@@ -273,6 +278,7 @@ ReDimDeclList
     : ReDimDecl                             { $$ = $1; }
     | ReDimDecl ',' ReDimDeclList           { $1->next = $3; $$ = $1; }
 
+
 DimDeclList
     : DimDecl                               { $$ = $1; }
     | DimDecl ',' DimDeclList               { $1->next = $3; $$ = $1; }
@@ -391,22 +397,19 @@ OrExpression
     | OrExpression tOR AndExpression            { $$ = new_binary_expression(ctx, EXPR_OR, $1, $3); CHECK_ERROR; }
 
 AndExpression
-    : NotExpression                             { $$ = $1; }
-    | AndExpression tAND NotExpression          { $$ = new_binary_expression(ctx, EXPR_AND, $1, $3); CHECK_ERROR; }
-
-NotExpression
-    : EqualityExpression            { $$ = $1; }
-    | tNOT NotExpression            { $$ = new_unary_expression(ctx, EXPR_NOT, $2); CHECK_ERROR; }
+    : EqualityExpression                            { $$ = $1; }
+    | AndExpression tAND EqualityExpression         { $$ = new_binary_expression(ctx, EXPR_AND, $1, $3); CHECK_ERROR; }
 
 EqualityExpression
-    : ConcatExpression                          { $$ = $1; }
-    | EqualityExpression '=' ConcatExpression   { $$ = new_binary_expression(ctx, EXPR_EQUAL, $1, $3); CHECK_ERROR; }
-    | EqualityExpression tNEQ ConcatExpression  { $$ = new_binary_expression(ctx, EXPR_NEQUAL, $1, $3); CHECK_ERROR; }
-    | EqualityExpression '>' ConcatExpression   { $$ = new_binary_expression(ctx, EXPR_GT, $1, $3); CHECK_ERROR; }
-    | EqualityExpression '<' ConcatExpression   { $$ = new_binary_expression(ctx, EXPR_LT, $1, $3); CHECK_ERROR; }
-    | EqualityExpression tGTEQ ConcatExpression { $$ = new_binary_expression(ctx, EXPR_GTEQ, $1, $3); CHECK_ERROR; }
-    | EqualityExpression tLTEQ ConcatExpression { $$ = new_binary_expression(ctx, EXPR_LTEQ, $1, $3); CHECK_ERROR; }
-    | EqualityExpression tIS ConcatExpression   { $$ = new_binary_expression(ctx, EXPR_IS, $1, $3); CHECK_ERROR; }
+    : ConcatExpression                              { $$ = $1; }
+    | tNOT EqualityExpression                       { $$ = new_unary_expression(ctx, EXPR_NOT, $2); CHECK_ERROR; }
+    | EqualityExpression '=' EqualityExpression     { $$ = new_binary_expression(ctx, EXPR_EQUAL, $1, $3); CHECK_ERROR; }
+    | EqualityExpression tNEQ EqualityExpression    { $$ = new_binary_expression(ctx, EXPR_NEQUAL, $1, $3); CHECK_ERROR; }
+    | EqualityExpression '>' EqualityExpression     { $$ = new_binary_expression(ctx, EXPR_GT, $1, $3); CHECK_ERROR; }
+    | EqualityExpression '<' EqualityExpression     { $$ = new_binary_expression(ctx, EXPR_LT, $1, $3); CHECK_ERROR; }
+    | EqualityExpression tGTEQ EqualityExpression   { $$ = new_binary_expression(ctx, EXPR_GTEQ, $1, $3); CHECK_ERROR; }
+    | EqualityExpression tLTEQ EqualityExpression   { $$ = new_binary_expression(ctx, EXPR_LTEQ, $1, $3); CHECK_ERROR; }
+    | EqualityExpression tIS EqualityExpression     { $$ = new_binary_expression(ctx, EXPR_IS, $1, $3); CHECK_ERROR; }
 
 ConcatExpression
     : AdditiveExpression                        { $$ = $1; }
@@ -514,6 +517,7 @@ Storage_opt
 
 Storage
     : tPUBLIC tDEFAULT              { $$ = STORAGE_IS_DEFAULT; }
+    | tDEFAULT tPRIVATE             { ctx->error_loc = @1; ctx->hres = MAKE_VBSERROR(VBSE_DEFAULT_MUST_BE_PUBLIC); CHECK_ERROR; }
     | tPUBLIC                       { $$ = 0; }
     | tPRIVATE                      { $$ = STORAGE_IS_PRIVATE; }
 
@@ -571,8 +575,8 @@ static int parser_error(unsigned *loc, parser_ctx_t *ctx, const char *str)
     if(ctx->error_loc == -1)
         ctx->error_loc = *loc;
     if(ctx->hres == S_OK) {
-        FIXME("%s: %s\n", debugstr_w(ctx->code + *loc), debugstr_a(str));
-        ctx->hres = E_FAIL;
+        WARN("%s: %s\n", debugstr_w(ctx->code + *loc), debugstr_a(str));
+        ctx->hres = MAKE_VBSERROR(VBSE_SYNTAX_ERROR);
     }else {
         WARN("%s: %08lx\n", debugstr_w(ctx->code + *loc), ctx->hres);
     }
@@ -760,8 +764,7 @@ static call_expression_t *make_call_expression(parser_ctx_t *ctx, expression_t *
     }
 
     if(call_expr->args->next) {
-        FIXME("Invalid syntax: invalid use of parentheses for arguments\n");
-        ctx->hres = E_FAIL;
+        ctx->hres = MAKE_VBSERROR(VBSE_CANNOT_USE_PARENS_CALLING_SUB);
         ctx->error_loc = ctx->ptr - ctx->code;
         return NULL;
     }
@@ -930,6 +933,18 @@ static statement_t *new_redim_statement(parser_ctx_t *ctx, unsigned loc, BOOL pr
     return &stat->stat;
 }
 
+static statement_t *new_erase_statement(parser_ctx_t *ctx, unsigned loc, const WCHAR *identifier)
+{
+    erase_statement_t *stat;
+
+    stat = new_statement(ctx, STAT_ERASE, sizeof(*stat), loc);
+    if(!stat)
+        return NULL;
+
+    stat->identifier = identifier;
+    return &stat->stat;
+}
+
 static elseif_decl_t *new_elseif_decl(parser_ctx_t *ctx, unsigned loc, expression_t *expr, statement_t *stat)
 {
     elseif_decl_t *decl;
@@ -1136,15 +1151,13 @@ static class_decl_t *add_class_function(parser_ctx_t *ctx, class_decl_t *class_d
     for(iter = class_decl->funcs; iter; iter = iter->next) {
         if(!wcsicmp(iter->name, decl->name)) {
             if(decl->type == FUNC_SUB || decl->type == FUNC_FUNCTION) {
-                FIXME("Redefinition of %s::%s\n", debugstr_w(class_decl->name), debugstr_w(decl->name));
-                ctx->hres = E_FAIL;
+                ctx->hres = MAKE_VBSERROR(VBSE_NAME_REDEFINED);
                 return NULL;
             }
 
             while(1) {
                 if(iter->type == decl->type) {
-                    FIXME("Redefinition of %s::%s\n", debugstr_w(class_decl->name), debugstr_w(decl->name));
-                    ctx->hres = E_FAIL;
+                    ctx->hres = MAKE_VBSERROR(VBSE_NAME_REDEFINED);
                     return NULL;
                 }
                 if(!iter->next_prop_func)
diff --git a/dlls/vbscript/tests/api.vbs b/dlls/vbscript/tests/api.vbs
index e18d887306b2..47e3ddee84b1 100644
--- a/dlls/vbscript/tests/api.vbs
+++ b/dlls/vbscript/tests/api.vbs
@@ -2144,6 +2144,59 @@ if Asc(Chr(&h81)) = &h8145 then
 end if
 call testAscError()
 
+sub testAscW(arg, expected)
+    dim x
+    x = AscW(arg)
+    call ok(x = expected, "AscW: x = " & x & " expected " & expected)
+    call ok(getVT(x) = "VT_I2*", "AscW: getVT = " & getVT(x))
+end sub
+
+call testAscW("T", 84)
+call testAscW("test", 116)
+call testAscW("3", 51)
+call testAscW(3, 51)
+call testAscW(Chr(0), 0)
+call testAscW(Chr(255), 255)
+if isEnglishLang then testAscW true, 84
+
+sub testAscWError()
+    on error resume next
+    call Err.clear()
+    call AscW(null)
+    Call ok(Err.number = 94, "AscW null: Err.number = " & Err.number)
+    call Err.clear()
+    call AscW(empty)
+    Call ok(Err.number = 5, "AscW empty: Err.number = " & Err.number)
+    call Err.clear()
+    call AscW("")
+    Call ok(Err.number = 5, "AscW """": Err.number = " & Err.number)
+end sub
+
+call testAscWError()
+
+Call ok(getVT(ChrW(120)) = "VT_BSTR", "getVT(ChrW(120)) = " & getVT(ChrW(120)))
+Call ok(ChrW(120) = "x", "ChrW(120) = " & ChrW(120))
+Call ok(ChrW(0) <> "", "ChrW(0) = """"")
+Call ok(ChrW(120.5) = "x", "ChrW(120.5) = " & ChrW(120.5))
+Call ok(ChrW(119.5) = "x", "ChrW(119.5) = " & ChrW(119.5))
+Call ok(ChrW("120") = "x", "ChrW(""120"") = " & ChrW("120"))
+Call ok(ChrW(255) = Chr(255), "ChrW(255) <> Chr(255)")
+Call ok(ChrW(0) = Chr(0), "ChrW(0) <> Chr(0)")
+Call ok(AscW(ChrW(8364)) = 8364, "AscW(ChrW(8364)) = " & AscW(ChrW(8364)))
+Call ok(AscW(ChrW(65535)) = -1, "AscW(ChrW(65535)) = " & AscW(ChrW(65535)))
+
+sub testChrWError()
+    on error resume next
+    call Err.clear()
+    call ChrW(65536)
+    call ok(Err.number = 5, "ChrW 65536: Err.number = " & Err.number)
+    call Err.clear()
+    call ChrW(-32769)
+    call ok(Err.number = 5, "ChrW -32769: Err.number = " & Err.number)
+end sub
+
+call testChrWError()
+
 sub testErrNumber(n)
     call ok(err.number = n, "err.number = " & err.number & " expected " & n)
 end sub
@@ -2624,4 +2677,55 @@ end sub
 call testFormatNumber()
 call testFormatNumberError()
 
+' Escape tests
+Call ok(Escape("hello") = "hello", "Escape(""hello"") = " & Escape("hello"))
+Call ok(Escape("hello world") = "hello%20world", "Escape(""hello world"") = " & Escape("hello world"))
+Call ok(Escape("@") = "@", "@ should not be escaped")
+Call ok(Escape("*") = "*", "* should not be escaped")
+Call ok(Escape("_") = "_", "_ should not be escaped")
+Call ok(Escape("+") = "+", "+ should not be escaped")
+Call ok(Escape("-") = "-", "- should not be escaped")
+Call ok(Escape(".") = ".", ". should not be escaped")
+Call ok(Escape("/") = "/", "/ should not be escaped")
+Call ok(Escape("ABC") = "ABC", "ABC should not be escaped")
+Call ok(Escape("abc") = "abc", "abc should not be escaped")
+Call ok(Escape("012") = "012", "012 should not be escaped")
+Call ok(Escape("<") = "%3C", "< escape = " & Escape("<"))
+Call ok(Escape(">") = "%3E", "> escape = " & Escape(">"))
+Call ok(Escape(" ") = "%20", "space escape = " & Escape(" "))
+Call ok(Escape("=") = "%3D", "= escape = " & Escape("="))
+Call ok(Escape("&") = "%26", "& escape = " & Escape("&"))
+Call ok(Escape(Unescape("%u20AC")) = "%u20AC", "Euro sign roundtrip escape")
+Call ok(Escape(Unescape("%u0100")) = "%u0100", "U+0100 roundtrip escape")
+Call ok(Escape("") = "", "Escape("""") should be empty")
+Call ok(getVT(Escape("test")) = "VT_BSTR", "getVT(Escape) = " & getVT(Escape("test")))
+
+' Unescape tests
+Call ok(Unescape("hello") = "hello", "Unescape(""hello"") = " & Unescape("hello"))
+Call ok(Unescape("hello%20world") = "hello world", "Unescape(""hello%20world"") = " & Unescape("hello%20world"))
+Call ok(Unescape("%3C%3E") = "<>", "Unescape(""%3C%3E"") = " & Unescape("%3C%3E"))
+Call ok(Unescape("%3c") = "<", "Unescape(""%3c"") lowercase")
+Call ok(Unescape("%3C") = "<", "Unescape(""%3C"") uppercase")
+Call ok(Unescape("%") = "%", "Unescape(""%"") incomplete")
+Call ok(Unescape("%2") = "%2", "Unescape(""%2"") incomplete")
+Call ok(Unescape("%2G") = "%2G", "Unescape(""%2G"") invalid hex")
+Call ok(Unescape(Escape("hello world!")) = "hello world!", "Roundtrip basic")
+Call ok(Unescape("") = "", "Unescape("""") should be empty")
+Call ok(getVT(Unescape("test")) = "VT_BSTR", "getVT(Unescape) = " & getVT(Unescape("test")))
+
+sub testEscapeError()
+    on error resume next
+    dim r
+
+    call Err.clear()
+    r = Escape(Null)
+    Call ok(Err.number = 94, "Escape(Null) Err.number = " & Err.number)
+
+    call Err.clear()
+    r = Unescape(Null)
+    Call ok(Err.number = 94, "Unescape(Null) Err.number = " & Err.number)
+end sub
+
+call testEscapeError()
+
 Call reportSuccess()
diff --git a/dlls/vbscript/tests/error.vbs b/dlls/vbscript/tests/error.vbs
index a9d4dc9c0be9..ce08bcec67a4 100644
--- a/dlls/vbscript/tests/error.vbs
+++ b/dlls/vbscript/tests/error.vbs
@@ -209,7 +209,7 @@ sub testThrow
     next
     call ok(y = 1, "y = " & y)
     call ok(x = 6, "x = " & x)
-    call todo_wine_ok(Err.Number = VB_E_FORLOOPNOTINITIALIZED, "Err.Number = " & Err.Number)
+    call ok(Err.Number = VB_E_FORLOOPNOTINITIALIZED, "Err.Number = " & Err.Number)
 
     Err.clear()
     y = 0
@@ -221,6 +221,18 @@ sub testThrow
     next
     call ok(y = 1, "y = " & y)
     call todo_wine_ok(x = 6, "x = " & x)
+    call ok(Err.Number = VB_E_FORLOOPNOTINITIALIZED, "Err.Number = " & Err.Number)
+
+    Err.clear()
+    y = 0
+    x = 6
+    for x = 100 to 200 step throwInt(E_TESTERROR)
+        call ok(Err.Number = E_TESTERROR, "Err.Number = " & Err.Number)
+        call todo_wine_ok(x = 6, "x = " & x)
+        y = y+1
+    next
+    call ok(y = 1, "y = " & y)
+    call todo_wine_ok(x = 6, "x = " & x)
     call todo_wine_ok(Err.Number = VB_E_FORLOOPNOTINITIALIZED, "Err.Number = " & Err.Number)
 
     select case throwInt(E_TESTERROR)
@@ -515,4 +527,89 @@ unused = undeclaredVar2
 todo_wine_ok err.number = 500, "err.number = " & err.number
 on error goto 0
 
+sub testObjectRequired()
+    on error resume next
+    dim x, r
+
+    ' Is operator with non-object operands
+    err.clear
+    r = "hello" Is Nothing
+    ok err.number = 424, "Is string: err.number = " & err.number
+
+    err.clear
+    r = Nothing Is "hello"
+    ok err.number = 424, "Is string rhs: err.number = " & err.number
+
+    err.clear
+    r = 42 Is 42
+    ok err.number = 424, "Is int: err.number = " & err.number
+
+    err.clear
+    r = Empty Is Empty
+    ok err.number = 424, "Is empty: err.number = " & err.number
+
+    err.clear
+    r = Null Is Nothing
+    ok err.number = 424, "Is null: err.number = " & err.number
+
+    ' Member call on Nothing
+    err.clear
+    set x = Nothing
+    x.Prop
+    ok err.number = 424, "Nothing.Prop: err.number = " & err.number
+
+    ' Assign member on Nothing
+    err.clear
+    set x = Nothing
+    x.Prop = 1
+    ok err.number = 424, "Nothing.Prop = 1: err.number = " & err.number
+
+    ' Set member on Nothing
+    err.clear
+    set x = Nothing
+    set x.Child = Nothing
+    ok err.number = 424, "Set Nothing.Child: err.number = " & err.number
+
+    ' With on non-object types (no member access)
+    err.clear
+    with 42
+    end with
+    ok err.number = 424, "With 42: err.number = " & err.number
+
+    err.clear
+    with "hello"
+    end with
+    ok err.number = 424, "With string: err.number = " & err.number
+
+    err.clear
+    with empty
+    end with
+    ok err.number = 424, "With empty: err.number = " & err.number
+
+    err.clear
+    with null
+    end with
+    ok err.number = 424, "With null: err.number = " & err.number
+
+    err.clear
+    with true
+    end with
+    ok err.number = 424, "With true: err.number = " & err.number
+
+    ' With Nothing should NOT raise 424 at entry
+    err.clear
+    with Nothing
+    end with
+    ok err.number = 0, "With Nothing: err.number = " & err.number
+
+    ' With Nothing + member access should raise 424
+    err.clear
+    with Nothing
+        .Prop = 1
+    end with
+    ok err.number = 424, "With Nothing .Prop: err.number = " & err.number
+end sub
+
+call testObjectRequired()
+
 call reportSuccess()
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 49889609aa95..ed4836021764 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -62,6 +62,20 @@ Call ok(&hfffe& = 65534, "&hfffe& <> -2")
 Call ok(&hffffffff& = -1, "&hffffffff& <> -1")
 Call ok((&h01or&h02)=3,"&h01or&h02 <> 3")
 
+' Hex literals with excess leading zeros
+Call ok(&H000000031 = 49, "&H000000031 <> 49")
+Call ok(&H0000000000000031 = 49, "&H0000000000000031 <> 49")
+Call ok(&H00000000000000FF = 255, "&H00000000000000FF <> 255")
+Call ok(&H0FFFFFFFF = -1, "&H0FFFFFFFF <> -1")
+Call ok(&H007FFFFFFF = 2147483647, "&H007FFFFFFF <> 2147483647")
+Call ok(&H000000031& = 49, "&H000000031& <> 49")
+Call ok(getVT(&H00000000000000FF) = "VT_I2", "getVT(&H00000000000000FF) is not VT_I2")
+Call ok(getVT(&H007FFFFFFF) = "VT_I4", "getVT(&H007FFFFFFF) is not VT_I4")
+Call ok(&h0 = 0, "&h0 <> 0")
+Call ok(&h0& = 0, "&h0& <> 0")
+Call ok(&h00 = 0, "&h00 <> 0")
+Call ok(&h000000000 = 0, "&h000000000 <> 0")
+
 ' Test concat when no space and var begins with h
 hi = "y"
 x = "x" &hi
@@ -92,6 +106,18 @@ Call ok(not(false = true = ""), "false = true = """" is true")
 Call ok(not (false = false <> false = false), "false = false <> false = false is true")
 Call ok(not ("" <> false = false), """"" <> false = false is true")
 
+Call ok(true <> Not true, "true <> Not true should be true")
+Call ok(false <> Not false, "false <> Not false should be true")
+Call ok(true = Not false, "true = Not false should be true")
+Call ok(Not false = true, "Not false = true should be true")
+Call ok(Not true <> true, "Not true <> true should be true")
+Call ok(Not true = false, "Not true = false should be true")
+Call ok(Not 1 > 2, "Not 1 > 2 should be true")
+Call ok(1 <> Not 0 = 0, "1 <> Not 0 = 0 should be true")
+Call ok(0 = Not 1 = 1, "0 = Not 1 = 1 should be true")
+Call ok(1 > Not 5 > 3, "1 > Not 5 > 3 should be true")
+Call ok(Not false And false = false, "Not false And false should be false")
+
 Call ok(getVT(false) = "VT_BOOL", "getVT(false) is not VT_BOOL")
 Call ok(getVT(true) = "VT_BOOL", "getVT(true) is not VT_BOOL")
 Call ok(getVT("") = "VT_BSTR", "getVT("""") is not VT_BSTR")
@@ -222,7 +248,7 @@ Call ok(11.6 Mod 5.5 = False, "11.6 Mod 5.5 = " & (11.6 Mod 5.5 = 0.6))
 Call ok(7 Mod 4+2 = 5, "7 Mod 4+2 <> 5")
 Call ok(getVT(2 mod null) = "VT_NULL", "getVT(2 mod null) = " & getVT(2 mod null))
 Call ok(getVT(null mod 2) = "VT_NULL", "getVT(null mod 2) = " & getVT(null mod 2))
-'FIXME: Call ok(empty mod 2 = 0, "empty mod 2 = " & (empty mod 2))
+Call ok(empty mod 2 = 0, "empty mod 2 = " & (empty mod 2))
 
 Call ok(5 \ 2 = 2, "5 \ 2 = " & (5\2))
 Call ok(4.6 \ 1.5 = 2, "4.6 \ 1.5 = " & (4.6\1.5))
@@ -247,6 +273,21 @@ x _
 
 x = 3
 
+Class ChainedCallTarget
+    Public Function Ret()
+        Set Ret = Me
+    End Function
+End Class
+
+Dim chainObj
+Set chainObj = New ChainedCallTarget
+chainObj.Ret().Ret()
+chainObj.Ret() _
+.Ret()
+chainObj _
+.Ret() _
+.Ret()
+
 if true then y = true : x = y
 ok x, "x is false"
 
@@ -768,6 +809,21 @@ if (isEnglishLang) then
     Call testfor ("1", "2.5", "0.5", 4)
 end if
 
+' Empty is treated as 0 in for-to loop expressions
+y = 0
+for x = empty to 3
+    y = y + 1
+next
+call ok(y = 4, "for empty to 3: y = " & y)
+call ok(x = 4, "for empty to 3: x = " & x)
+
+y = 0
+for x = 0 to empty
+    y = y + 1
+next
+call ok(y = 1, "for 0 to empty: y = " & y)
+call ok(x = 1, "for 0 to empty: x = " & x)
+
 for x = 1.5 to 1
     Call ok(false, "for..to called when unexpected")
 next
@@ -1666,6 +1722,25 @@ ok arr2(1,2) = 2, "arr2(1,2) = " & arr2(1,2)
 x = Array(Array(3))
 call ok(x(0)(0) = 3, "x(0)(0) = " & x(0)(0))
 
+Class ArrayReturnContainer
+    Public Default Property Get Item(key)
+        If key = "Key" Then
+            Item = Array("Value1", Array("SubValue1", "SubValue2"))
+        End If
+    End Property
+End Class
+
+Dim containerObj
+Set containerObj = New ArrayReturnContainer
+call ok(containerObj.Item("Key")(0) = "Value1", "containerObj.Item(Key)(0) = " & containerObj.Item("Key")(0))
+call ok(containerObj.Item("Key")(1)(0) = "SubValue1", "containerObj.Item(Key)(1)(0) = " & containerObj.Item("Key")(1)(0))
+call ok(containerObj.Item("Key")(1)(1) = "SubValue2", "containerObj.Item(Key)(1)(1) = " & containerObj.Item("Key")(1)(1))
+call ok(containerObj("Key")(0) = "Value1", "containerObj(Key)(0) = " & containerObj("Key")(0))
+call ok(containerObj("Key")(1)(0) = "SubValue1", "containerObj(Key)(1)(0) = " & containerObj("Key")(1)(0))
+
+call ok(Split("1;2", ";")(0) = "1", "Split(""1;2"", "";"")(0) = " & Split("1;2", ";")(0))
+call ok(Split("1;2", ";")(1) = "2", "Split(""1;2"", "";"")(1) = " & Split("1;2", ";")(1))
+
 function seta0(arr)
     arr(0) = 2
     seta0 = 1
@@ -1898,6 +1973,183 @@ call TestReDimPreserveByRef(rx)
 ok ubound(rx) = 7, "ubound(rx) = " & ubound(rx)
 ok rx(3) = 2, "rx(3) = " & rx(3)
 
+' ReDim on an uninitialized dynamic array (Dim arr() has a NULL SAFEARRAY pointer)
+dim dynarr()
+redim dynarr(3)
+ok ubound(dynarr) = 3, "ubound(dynarr) = " & ubound(dynarr)
+dynarr(0) = "a"
+dynarr(3) = "b"
+ok dynarr(0) = "a", "dynarr(0) = " & dynarr(0)
+ok dynarr(3) = "b", "dynarr(3) = " & dynarr(3)
+redim dynarr(5)
+ok ubound(dynarr) = 5, "ubound(dynarr) = " & ubound(dynarr)
+ok dynarr(0) = empty, "dynarr(0) after redim = " & dynarr(0)
+
+' ReDim Preserve on an uninitialized dynamic array should also work and retain data
+dim dynarr2()
+redim preserve dynarr2(3)
+ok ubound(dynarr2) = 3, "ubound(dynarr2) = " & ubound(dynarr2)
+dynarr2(0) = "x"
+redim preserve dynarr2(5)
+ok ubound(dynarr2) = 5, "ubound(dynarr2) = " & ubound(dynarr2)
+ok dynarr2(0) = "x", "dynarr2(0) after redim preserve = " & dynarr2(0)
+
+' Array dimension mismatch: should give error 9 (Subscript out of range)
+dim dimArr2d(3, 3)
+dimArr2d(0, 0) = "hello"
+on error resume next
+
+' 2D array accessed with 1 index
+err.clear
+y = dimArr2d(0)
+ok err.number = 9, "2D array 1 index: err.number = " & err.number
+
+' 1D array accessed with 2 indices
+dim dimArr1d(3)
+err.clear
+y = dimArr1d(0, 0)
+ok err.number = 9, "1D array 2 indices: err.number = " & err.number
+
+' 2D array accessed with 3 indices
+err.clear
+y = dimArr2d(0, 0, 0)
+ok err.number = 9, "2D array 3 indices: err.number = " & err.number
+
+' Assign to 2D array with 1 index
+err.clear
+dimArr2d(0) = "test"
+ok err.number = 9, "assign 2D array 1 index: err.number = " & err.number
+
+' Assign to 1D array with 2 indices
+err.clear
+dimArr1d(0, 0) = "test"
+ok err.number = 9, "assign 1D array 2 indices: err.number = " & err.number
+
+' Uninitialized dynamic array access
+dim dimDynArr()
+err.clear
+y = dimDynArr(0)
+ok err.number = 9, "uninitialized dynamic array access: err.number = " & err.number
+on error goto 0
+
+' Erase on fixed-size array: clears elements to default values
+dim eraseFixed(3)
+eraseFixed(0) = "a"
+eraseFixed(1) = 2
+eraseFixed(2) = True
+Erase eraseFixed
+ok eraseFixed(0) = empty, "eraseFixed(0) after Erase = " & eraseFixed(0)
+ok eraseFixed(1) = empty, "eraseFixed(1) after Erase = " & eraseFixed(1)
+ok eraseFixed(2) = empty, "eraseFixed(2) after Erase = " & eraseFixed(2)
+ok ubound(eraseFixed) = 3, "ubound(eraseFixed) after Erase = " & ubound(eraseFixed)
+
+' Erase on dynamic array: deallocates the array
+dim eraseDyn()
+redim eraseDyn(3)
+eraseDyn(0) = "x"
+Erase eraseDyn
+on error resume next
+y = eraseDyn(0)
+e = err.number
+on error goto 0
+ok e = 9, "access after Erase dynamic: err.number = " & e
+
+' Erase with multiple arrays (separate statements)
+dim eraseMulti1(2), eraseMulti2(2)
+eraseMulti1(0) = "a"
+eraseMulti2(0) = "b"
+Erase eraseMulti1
+Erase eraseMulti2
+ok eraseMulti1(0) = empty, "eraseMulti1(0) after Erase = " & eraseMulti1(0)
+ok eraseMulti2(0) = empty, "eraseMulti2(0) after Erase = " & eraseMulti2(0)
+
+' Erase on non-array variable: should give type mismatch error
+dim eraseNotArray
+eraseNotArray = 42
+on error resume next
+Erase eraseNotArray
+ok err.number = 13, "Erase non-array: err.number = " & err.number
+err.clear
+
+' Erase on Empty variable: should give type mismatch error
+dim eraseEmpty
+Erase eraseEmpty
+ok err.number = 13, "Erase empty var: err.number = " & err.number
+err.clear
+
+' Erase on Null variable: should give type mismatch error
+dim eraseNull
+eraseNull = Null
+Erase eraseNull
+ok err.number = 13, "Erase null var: err.number = " & err.number
+err.clear
+
+' Erase on Object variable: should give type mismatch error
+dim eraseObj
+set eraseObj = new regexp
+Erase eraseObj
+ok err.number = 13, "Erase object var: err.number = " & err.number
+err.clear
+
+' Erase on Nothing variable: should give type mismatch error
+dim eraseNothing
+set eraseNothing = Nothing
+Erase eraseNothing
+ok err.number = 13, "Erase nothing var: err.number = " & err.number
+err.clear
+
+' Erase on undeclared identifier: error 500 (Variable is undefined) with Option Explicit
+Erase eraseUndeclared
+ok err.number = 500, "Erase undeclared: err.number = " & err.number
+err.clear
+on error goto 0
+
+' Erase on uninitialized dynamic array: no error
+dim eraseUninit()
+Erase eraseUninit
+
+' Erase twice on fixed-size array: no error
+dim eraseTwice(2)
+eraseTwice(0) = "x"
+Erase eraseTwice
+Erase eraseTwice
+ok eraseTwice(0) = empty, "eraseTwice(0) after double Erase = " & eraseTwice(0)
+
+' Erase twice on dynamic array: no error
+dim eraseTwiceDyn()
+redim eraseTwiceDyn(2)
+eraseTwiceDyn(0) = "y"
+Erase eraseTwiceDyn
+Erase eraseTwiceDyn
+
+' ReDim after Erase on dynamic array
+dim eraseReDim()
+redim eraseReDim(3)
+eraseReDim(0) = "before"
+Erase eraseReDim
+redim eraseReDim(5)
+ok ubound(eraseReDim) = 5, "ubound(eraseReDim) after Erase+ReDim = " & ubound(eraseReDim)
+ok eraseReDim(0) = empty, "eraseReDim(0) after Erase+ReDim = " & eraseReDim(0)
+
+' Erase on ByRef array parameter: clears the original
+sub TestEraseByRef(ByRef arr)
+    Erase arr
+end sub
+dim eraseByRefArr(2)
+eraseByRefArr(0) = "hello"
+call TestEraseByRef(eraseByRefArr)
+ok eraseByRefArr(0) = empty, "eraseByRefArr(0) after ByRef Erase = " & eraseByRefArr(0)
+ok ubound(eraseByRefArr) = 2, "ubound(eraseByRefArr) after ByRef Erase = " & ubound(eraseByRefArr)
+
+' Erase on ByVal array parameter: does not affect the original
+sub TestEraseByVal(ByVal arr)
+    Erase arr
+end sub
+dim eraseByValArr(2)
+eraseByValArr(0) = "world"
+call TestEraseByVal(eraseByValArr)
+ok eraseByValArr(0) = "world", "eraseByValArr(0) after ByVal Erase = " & eraseByValArr(0)
+
 Class ArrClass
     Dim classarr(3)
     Dim classnoarr()
@@ -2187,6 +2439,7 @@ Class TestPropParam
     Public oDict
     Public gotNothing
     Public m_obj
+    Public m_objType
 
     Public Property Set bar(obj)
         Set m_obj = obj
@@ -2205,6 +2458,14 @@ Class TestPropParam
     Public Property Let ten(a,b,c,d,e,f,g,h,i,j)
         oDict = a & b & c & d & e & f & g & h & i & j
     End Property
+    Public Property Let objProp(aInput)
+        m_objType = getVT(aInput)
+        If IsObject(aInput) Then
+            Set m_obj = aInput
+        Else
+            m_obj = aInput
+        End If
+    End Property
 End Class
 
 Set x = new TestPropParam
@@ -2220,6 +2481,24 @@ Set x.foo("123") = Nothing
 call ok(x.oDict = "123","x.oDict = " & x.oDict & " expected 123")
 call ok(x.gotNothing=True,"x.gotNothing = " & x.gotNothing  & " expected true")
 
+' Property Let receives VT_DISPATCH argument as-is (does not extract default value)
+Set y = New EndTestClassWithProperty
+y.x = 42
+x.objProp = y
+call ok(x.m_objType = "VT_DISPATCH*", "Property Let aInput type: " & x.m_objType & " expected VT_DISPATCH*")
+call ok(x.m_obj = 42, "Property Let with object argument failed, m_obj = " & x.m_obj)
+
+' Property Let receives object without default property as VT_DISPATCH
+Set z = New EmptyClass
+x.objProp = z
+call ok(x.m_objType = "VT_DISPATCH*", "Property Let no-default aInput type: " & x.m_objType & " expected VT_DISPATCH*")
+
+' Set with only Property Let defined should fail (no fallback to Let)
+On Error Resume Next
+Set x.objProp = y
+call ok(Err.Number = 438, "Set Property Let only: Err.Number = " & Err.Number & " expected 438")
+On Error GoTo 0
+
 set x = new TestPropSyntax
 set x.prop = new TestPropSyntax
 set x.prop.prop = new TestPropSyntax
@@ -2233,7 +2512,7 @@ set x.getprop.getprop().prop = obj
 call ok(x.getprop.getprop().prop is obj, "x.getprop.getprop().prop is not obj (emptyclass)")
 
 ok getVT(x) = "VT_DISPATCH*", "getVT(x) = " & getVT(x)
-todo_wine_ok getVT(x()) = "VT_BSTR", "getVT(x()) = " & getVT(x())
+ok getVT(x()) = "VT_BSTR", "getVT(x()) = " & getVT(x())
 
 Class TestClassVariablesMulti
     Public pub1, pub2
@@ -2381,4 +2660,379 @@ arr (0) = 2 xor -2
 Call ok(indexedObj(3) = 6, "indexedObj(3) = " & indexedObj(3))
 Call ok(indexedObj(0) = 0, "indexedObj(0) = " & indexedObj(0))
 
+' GetRef tests
+Function GetRefTestFunc()
+    GetRefTestFunc = 42
+End Function
+
+Dim getRefRef
+Set getRefRef = GetRef("GetRefTestFunc")
+Call ok(IsObject(getRefRef), "IsObject(GetRef result) should be true")
+Call ok(getRefRef() = 42, "GetRef result call returned " & getRefRef())
+
+' GetRef with parameters
+Function GetRefAddFunc(a, b)
+    GetRefAddFunc = a + b
+End Function
+
+Set getRefRef = GetRef("GetRefAddFunc")
+Call ok(getRefRef(3, 4) = 7, "GetRef add call returned " & getRefRef(3, 4))
+
+' GetRef with a Sub
+Dim getRefSubCalled
+getRefSubCalled = False
+Sub GetRefTestSub()
+    getRefSubCalled = True
+End Sub
+
+Set getRefRef = GetRef("GetRefTestSub")
+Call getRefRef()
+Call ok(getRefSubCalled, "GetRef sub was not called")
+
+' GetRef with Sub that has parameters
+Dim getRefSubResult
+Sub GetRefTestSubArgs(a, b)
+    getRefSubResult = a + b
+End Sub
+
+Set getRefRef = GetRef("GetRefTestSubArgs")
+Call getRefRef(10, 20)
+Call ok(getRefSubResult = 30, "GetRef sub with args returned " & getRefSubResult)
+
+' GetRef case insensitivity
+Function getRefCaseFunc()
+    getRefCaseFunc = "hello"
+End Function
+
+Set getRefRef = GetRef("GETREFCASEFUNC")
+Call ok(getRefRef() = "hello", "GetRef case insensitive returned " & getRefRef())
+
+' GetRef default value (calling without parens triggers default property)
+Set getRefRef = GetRef("GetRefTestFunc")
+Dim getRefResult
+getRefResult = getRefRef
+Call ok(getRefResult = 42, "GetRef default value returned " & getRefResult)
+Call ok(getVT(getRefResult) = "VT_I2*", "GetRef default value type is " & getVT(getRefResult))
+
+' GetRef can be passed to another function
+Function GetRefCallIt(fn)
+    GetRefCallIt = fn()
+End Function
+
+Set getRefRef = GetRef("GetRefTestFunc")
+Call ok(GetRefCallIt(getRefRef) = 42, "GetRef passed to function returned " & GetRefCallIt(getRefRef))
+
+' GetRef error cases
+On Error Resume Next
+
+Err.Clear
+Set getRefRef = GetRef("NonExistentFunc")
+Call ok(Err.Number = 5, "GetRef non-existent function error is " & Err.Number)
+
+Err.Clear
+Set getRefRef = GetRef("")
+Call ok(Err.Number = 5, "GetRef empty string error is " & Err.Number)
+
+Err.Clear
+Set getRefRef = GetRef(123)
+Call ok(Err.Number = 13, "GetRef numeric arg error is " & Err.Number)
+
+Err.Clear
+Set getRefRef = GetRef(Null)
+Call ok(Err.Number = 13, "GetRef Null arg error is " & Err.Number)
+
+Err.Clear
+Set getRefRef = GetRef(Empty)
+Call ok(Err.Number = 13, "GetRef Empty arg error is " & Err.Number)
+
+Err.Clear
+Set getRefRef = GetRef(vbNullString)
+Call ok(Err.Number = 5, "GetRef vbNullString error is " & Err.Number)
+
+' Eval tests
+Call ok(Eval("1 + 2") = 3, "Eval(""1 + 2"") = " & Eval("1 + 2"))
+Call ok(Eval("""test""") = "test", "Eval(""""""test"""""") = " & Eval("""test"""))
+Call ok(Eval("true") = true, "Eval(""true"") = " & Eval("true"))
+
+x = 5
+Call ok(Eval("x + 1") = 6, "Eval(""x + 1"") = " & Eval("x + 1"))
+Call ok(Eval("x * x") = 25, "Eval(""x * x"") = " & Eval("x * x"))
+
+Sub TestEvalLocalScope
+    Dim a
+    a = 10
+    Call ok(Eval("a") = 10, "Eval(""a"") in local scope = " & Eval("a"))
+    Call ok(Eval("a + 5") = 15, "Eval(""a + 5"") in local scope = " & Eval("a + 5"))
+End Sub
+Call TestEvalLocalScope
+
+Function TestEvalLocalArgs(x)
+    TestEvalLocalArgs = Eval("x * 2")
+End Function
+Call ok(TestEvalLocalArgs(7) = 14, "TestEvalLocalArgs(7) = " & TestEvalLocalArgs(7))
+
+Dim evalLocal
+Sub TestEvalNoLeak
+    Dim evalLocal
+    evalLocal = 77
+    Call ok(Eval("evalLocal") = 77, "Eval evalLocal = " & Eval("evalLocal"))
+End Sub
+Call TestEvalNoLeak
+Call ok(getVT(evalLocal) = "VT_EMPTY*", "evalLocal leaked from Eval scope: " & getVT(evalLocal))
+
+' ExecuteGlobal tests
+x = 0
+ExecuteGlobal "x = 42"
+Call ok(x = 42, "ExecuteGlobal x = " & x)
+
+ExecuteGlobal "Function evalTestFunc : evalTestFunc = 7 : End Function"
+Call ok(evalTestFunc() = 7, "evalTestFunc() = " & evalTestFunc())
+
+' ExecuteGlobal: Dim creates a new global variable
+ExecuteGlobal "Dim egVar1 : egVar1 = 42"
+Call ok(egVar1 = 42, "ExecuteGlobal Dim egVar1 = " & egVar1)
+
+' ExecuteGlobal: Dim variable persists across calls
+ExecuteGlobal "Dim egVar2"
+ExecuteGlobal "egVar2 = 99"
+Call ok(egVar2 = 99, "ExecuteGlobal Dim egVar2 (set later) = " & egVar2)
+
+' ExecuteGlobal inside Sub: Dim creates a GLOBAL variable
+Sub TestExecGlobalDimInSub
+    ExecuteGlobal "Dim egFromSub : egFromSub = 123"
+End Sub
+Call TestExecGlobalDimInSub
+Call ok(egFromSub = 123, "ExecuteGlobal Dim in Sub - egFromSub = " & egFromSub)
+
+' ExecuteGlobal: Dim + Function in same call
+ExecuteGlobal "Dim egFuncVar : Function egGetVar() : egGetVar = egFuncVar : End Function"
+egFuncVar = 777
+Call ok(egGetVar() = 777, "ExecuteGlobal Dim+Function: egGetVar() = " & egGetVar())
+
+' ExecuteGlobal: ReDim creates global dynamic array
+ExecuteGlobal "ReDim egDynArr(1) : egDynArr(0) = ""a"" : egDynArr(1) = ""b"""
+Call ok(egDynArr(0) = "a", "ExecuteGlobal ReDim egDynArr(0) = " & egDynArr(0))
+Call ok(egDynArr(1) = "b", "ExecuteGlobal ReDim egDynArr(1) = " & egDynArr(1))
+
+' Execute tests
+x = 0
+Execute "x = 99"
+Call ok(x = 99, "Execute x = " & x)
+
+Sub TestExecuteLocalScope
+    Dim a
+    a = 10
+    Execute "a = 20"
+    Call ok(a = 20, "Execute local assign: a = " & a)
+End Sub
+Call TestExecuteLocalScope
+
+Dim executeLocal
+Sub TestExecuteNoLeak
+    Dim executeLocal
+    executeLocal = 10
+    Execute "executeLocal = 55"
+    Call ok(executeLocal = 55, "executeLocal = " & executeLocal)
+End Sub
+Call TestExecuteNoLeak
+Call ok(getVT(executeLocal) = "VT_EMPTY*", "executeLocal leaked from Execute scope: " & getVT(executeLocal))
+
+' Execute at global scope: Dim creates a new global variable
+Execute "Dim exVar1 : exVar1 = 77"
+Call ok(exVar1 = 77, "Execute (global) Dim exVar1 = " & exVar1)
+
+' Execute inside Sub: Dim creates variable visible in caller's scope
+Sub TestExecuteDimInSub
+    Dim localA
+    localA = 10
+    Execute "Dim localB : localB = 20"
+    Call ok(localB = 20, "Execute Dim in Sub - localB = " & localB)
+    Call ok(localA = 10, "Execute Dim in Sub - localA still = " & localA)
+End Sub
+Call TestExecuteDimInSub
+
+' Execute inside Function: Dim creates variable visible in function scope
+Function TestExecuteDimInFunc
+    Execute "Dim funcVar : funcVar = 55"
+    TestExecuteDimInFunc = funcVar
+End Function
+Call ok(TestExecuteDimInFunc() = 55, "Execute Dim in Function = " & TestExecuteDimInFunc())
+
+' Execute: Dim same name as existing local has no effect, value preserved
+Sub TestExecuteDimShadow
+    Dim x
+    x = 100
+    Execute "Dim x"
+    Call ok(x = 100, "x after Execute Dim x = " & x)
+    Execute "x = 200"
+    Call ok(x = 200, "x after Execute x=200 = " & x)
+End Sub
+Call TestExecuteDimShadow
+
+' Execute: Dim then use in same string, visible in caller
+Sub TestExecuteDimAndUse
+    Execute "Dim euVar : euVar = 999"
+    Call ok(euVar = 999, "Execute Dim+use euVar = " & euVar)
+End Sub
+Call TestExecuteDimAndUse
+
+' Execute: ReDim creates dynamic array visible in caller
+Sub TestExecuteReDim
+    Execute "ReDim dynArr(2) : dynArr(0) = 10 : dynArr(1) = 20 : dynArr(2) = 30"
+    Call ok(dynArr(1) = 20, "Execute ReDim dynArr(1) = " & dynArr(1))
+End Sub
+Call TestExecuteReDim
+
+' Option Explicit is per-compilation-unit in Execute/ExecuteGlobal
+On Error Resume Next
+
+' Option Explicit inside same Execute string enforces Dim requirement
+Err.Clear
+Execute "Option Explicit : noDimExec = 101"
+Call ok(Err.Number <> 0, "Execute Option Explicit undeclared should error: err=" & Err.Number)
+todo_wine_ok Err.Number = 500, "Execute Option Explicit undeclared: err=" & Err.Number & " expected 500"
+
+' Option Explicit inside same ExecuteGlobal string enforces Dim requirement
+Err.Clear
+ExecuteGlobal "Option Explicit : noDimExecGlobal = 102"
+Call ok(Err.Number <> 0, "ExecuteGlobal Option Explicit undeclared should error: err=" & Err.Number)
+todo_wine_ok Err.Number = 500, "ExecuteGlobal Option Explicit undeclared: err=" & Err.Number & " expected 500"
+
+' Option Explicit with Dim in same string works
+Err.Clear
+ExecuteGlobal "Option Explicit : Dim oeDimVar : oeDimVar = 555"
+Call ok(Err.Number = 0, "ExecuteGlobal Option Explicit + Dim: err=" & Err.Number)
+Call ok(oeDimVar = 555, "ExecuteGlobal Option Explicit + Dim: oeDimVar = " & oeDimVar)
+
+' Option Explicit does not propagate to subsequent calls
+Err.Clear
+ExecuteGlobal "Option Explicit"
+Call ok(Err.Number = 0, "ExecuteGlobal Option Explicit alone: err=" & Err.Number)
+Err.Clear
+ExecuteGlobal "noDimAfterOE = 123"
+Call ok(Err.Number = 0, "ExecuteGlobal after separate OE: err=" & Err.Number)
+
+On Error Goto 0
+
+
+' Eval/Execute/ExecuteGlobal error handling tests
+On Error Resume Next
+
+' Test Eval with syntax error
+Err.Clear
+Call Eval("1 + ")
+Call ok(Err.Number = 1002, "Eval syntax error: Err.Number = " & Err.Number & " expected 1002")
+Call ok(Err.Description = "Syntax error", "Eval syntax error: Err.Description = """ & Err.Description & """ expected ""Syntax error""")
+Call ok(Err.Source = "Microsoft VBScript compilation error", "Eval syntax error: Err.Source = """ & Err.Source & """")
+
+' Test Execute with syntax error
+Err.Clear
+Execute "x = "
+Call ok(Err.Number = 1002, "Execute syntax error: Err.Number = " & Err.Number & " expected 1002")
+Call ok(Err.Description = "Syntax error", "Execute syntax error: Err.Description = """ & Err.Description & """ expected ""Syntax error""")
+Call ok(Err.Source = "Microsoft VBScript compilation error", "Execute syntax error: Err.Source = """ & Err.Source & """")
+
+' Test ExecuteGlobal with syntax error
+Err.Clear
+ExecuteGlobal "y = "
+Call ok(Err.Number = 1002, "ExecuteGlobal syntax error: Err.Number = " & Err.Number & " expected 1002")
+Call ok(Err.Description = "Syntax error", "ExecuteGlobal syntax error: Err.Description = """ & Err.Description & """ expected ""Syntax error""")
+Call ok(Err.Source = "Microsoft VBScript compilation error", "ExecuteGlobal syntax error: Err.Source = """ & Err.Source & """")
+
+' Eval with non-string arguments returns the value directly
+Err.Clear
+Call ok(Eval(123) = 123, "Eval(123) = " & Eval(123))
+Call ok(Err.Number = 0, "Eval(123) Err.Number = " & Err.Number)
+
+Err.Clear
+Call ok(Eval(True) = True, "Eval(True) = " & Eval(True))
+Call ok(Err.Number = 0, "Eval(True) Err.Number = " & Err.Number)
+
+Err.Clear
+Call ok(IsNull(Eval(Null)), "Eval(Null) should be Null")
+Call ok(Err.Number = 0, "Eval(Null) Err.Number = " & Err.Number)
+
+Err.Clear
+Call ok(IsEmpty(Eval(Empty)), "Eval(Empty) should be Empty")
+Call ok(Err.Number = 0, "Eval(Empty) Err.Number = " & Err.Number)
+
+' Execute with non-string arguments returns type mismatch
+Err.Clear
+Execute 123
+Call ok(Err.Number = 13, "Execute 123 Err.Number = " & Err.Number)
+
+Err.Clear
+Execute Null
+Call ok(Err.Number = 13, "Execute Null Err.Number = " & Err.Number)
+
+Err.Clear
+Execute Empty
+Call ok(Err.Number = 13, "Execute Empty Err.Number = " & Err.Number)
+
+' ExecuteGlobal with non-string arguments returns type mismatch
+Err.Clear
+ExecuteGlobal 123
+Call ok(Err.Number = 13, "ExecuteGlobal 123 Err.Number = " & Err.Number)
+
+Err.Clear
+ExecuteGlobal Null
+Call ok(Err.Number = 13, "ExecuteGlobal Null Err.Number = " & Err.Number)
+
+Err.Clear
+ExecuteGlobal Empty
+Call ok(Err.Number = 13, "ExecuteGlobal Empty Err.Number = " & Err.Number)
+
+' Eval with Dim is a syntax error (Eval expects an expression, not a statement)
+Err.Clear
+Eval "Dim evalDimVar"
+Call ok(Err.Number = 1002, "Eval Dim: Err.Number = " & Err.Number & " expected 1002")
+
+' Test runtime error in Eval is caught by On Error Resume Next
+Err.Clear
+Call Eval("CBool(""notabool"")")
+Call ok(Err.Number = 13, "Eval type mismatch: Err.Number = " & Err.Number & " expected 13")
+Call ok(Err.Source = "Microsoft VBScript runtime error", "Eval type mismatch: Err.Source = """ & Err.Source & """")
+
+On Error Goto 0
+
+' Test calling a dispatch variable as statement (invokes default property)
+funcCalled = ""
+Set obj = New DefaultSubTest1
+obj 3
+Call ok(funcCalled = "init3", "dispatch var as statement: funcCalled = " & funcCalled)
+
+' Test calling a dispatch variable (default Function, no args) as statement
+funcCalled = ""
+Set obj = New DefaultSubTest2
+obj
+Call ok(funcCalled = "init", "dispatch var (default func) as statement: funcCalled = " & funcCalled)
+
+' Test calling non-dispatch variables as statement gives type mismatch (error 13)
+On Error Resume Next
+
+dim intCallVar
+intCallVar = 42
+Err.Clear
+intCallVar
+Call ok(Err.Number = 13, "int var as statement: err = " & Err.Number)
+
+dim strCallVar
+strCallVar = "hello"
+Err.Clear
+strCallVar
+Call ok(Err.Number = 13, "string var as statement: err = " & Err.Number)
+
+dim emptyCallVar
+Err.Clear
+emptyCallVar
+Call ok(Err.Number = 13, "empty var as statement: err = " & Err.Number)
+
+dim boolCallVar
+boolCallVar = True
+Err.Clear
+boolCallVar
+Call ok(Err.Number = 13, "bool var as statement: err = " & Err.Number)
+
+On Error GoTo 0
+
 reportSuccess()
diff --git a/dlls/vbscript/tests/noexplicit.vbs b/dlls/vbscript/tests/noexplicit.vbs
index 1f3f67e20dfb..3e3c840c3242 100644
--- a/dlls/vbscript/tests/noexplicit.vbs
+++ b/dlls/vbscript/tests/noexplicit.vbs
@@ -30,6 +30,11 @@ ok y = "", "y = " & y
 on error resume next
 z(0) = 42
 ok err.number = 13, "err.number = " & err.number
+err.clear
+
+' Erase on undeclared variable without Option Explicit: error 13 (Type mismatch)
+Erase eraseUndeclared
+ok err.number = 13, "Erase undeclared no explicit: err.number = " & err.number
 on error goto 0
 
 call reportSuccess()
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index 80cd3a34bd24..da6f31ff4dfc 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -2007,6 +2007,9 @@ static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface, S
 static IActiveScriptError **store_script_error;
 static ULONG error_line;
 static LONG error_char;
+static USHORT error_code;
+static BSTR error_source_line;
+static HRESULT error_source_line_hres;
 
 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, IActiveScriptError *pscripterror)
 {
@@ -2015,6 +2018,10 @@ static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, I
     hres = IActiveScriptError_GetSourcePosition(pscripterror, NULL, &error_line, &error_char);
     ok(hres == S_OK, "GetSourcePosition failed: %08lx\n", hres);
 
+    SysFreeString(error_source_line);
+    error_source_line = NULL;
+    error_source_line_hres = IActiveScriptError_GetSourceLineText(pscripterror, &error_source_line);
+
     if(!expect_OnScriptError) {
         EXCEPINFO info;
 
@@ -2023,6 +2030,15 @@ static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface, I
             trace("Error in line %lu: %x %s\n", error_line + 1, info.wCode, wine_dbgstr_w(info.bstrDescription));
     }else {
         IDispatchEx *dispex;
+        EXCEPINFO info;
+
+        hres = IActiveScriptError_GetExceptionInfo(pscripterror, &info);
+        if(SUCCEEDED(hres)) {
+            error_code = HRESULT_CODE(info.scode);
+            SysFreeString(info.bstrSource);
+            SysFreeString(info.bstrDescription);
+            SysFreeString(info.bstrHelpFile);
+        }
 
         hres = IActiveScriptError_QueryInterface(pscripterror, &IID_IDispatchEx, (void**)&dispex);
         ok(hres == E_NOINTERFACE, "QI(IDispatchEx) returned: %08lx\n", hres);
@@ -2696,6 +2712,9 @@ static void test_parse_errors(void)
         const WCHAR *src;
         unsigned error_line;
         int error_char;
+        const WCHAR *source_line;
+        HRESULT source_line_hres;
+        int error_code;
     }
     invalid_scripts[] =
     {
@@ -2703,7 +2722,8 @@ static void test_parse_errors(void)
             /* If...End If */
             L"If 0 > 1 Then\n"
             "    x = 0 End If\n",
-            1, 10
+            1, 10,
+            L"    x = 0 End If", S_OK, -1042
         },
         {
             /* ElseIf...End If */
@@ -2711,50 +2731,58 @@ static void test_parse_errors(void)
             "    x = 0\n"
             "ElseIf True Then\n"
             "    x = 1 End If\n",
-            3, 10
+            3, 10,
+            L"    x = 1 End If", S_OK, -1042
         },
         {
             /* Else End If (no separator) */
             L"If False Then\n"
             "    x = 0\n"
             "Else End If\n",
-            2, 5
+            2, 5,
+            L"Else End If", S_OK, -1024
         },
         {
             /* While...End While */
             L"While False\n"
             "    x = 0 End While\n",
-            1, 10
+            1, 10,
+            L"    x = 0 End While", S_OK, -1024
         },
         {
             /* While...Wend */
             L"While False\n"
             "    x = 0 Wend\n",
-            1, 10
+            1, 10,
+            L"    x = 0 Wend", S_OK, -1025
         },
         {
             /* Do While...Loop */
             L"Do While False\n"
             "    x = 0 Loop\n",
-            1, 10
+            1, 10,
+            L"    x = 0 Loop", S_OK, -1025
         },
         {
             /* Do Until...Loop */
             L"Do Until True\n"
             "    x = 0 Loop\n",
-            1, 10
+            1, 10,
+            L"    x = 0 Loop", S_OK, -1025
         },
         {
             /* Do...Loop While */
             L"Do\n"
             "    x = 0 Loop While False\n",
-            1, 10
+            1, 10,
+            L"    x = 0 Loop While False", S_OK, -1025
         },
         {
             /* Do...Loop Until */
             L"Do\n"
             "    x = 0 Loop Until True\n",
-            1, 10
+            1, 10,
+            L"    x = 0 Loop Until True", S_OK, -1025
         },
         {
             /* Select...End Select */
@@ -2765,36 +2793,43 @@ static void test_parse_errors(void)
             "    Case 42\n"
             "        x = True End Select\n"
             "Call ok(x, \"wrong case\")\n",
-            5, 17
+            5, 17,
+            L"        x = True End Select", S_OK, -1042
         },
         {
             /* Class...End Class  (empty) */
             L"Class C End Class",
-            0, 8
+            0, 8,
+            L"Class C End Class", S_OK, -1024
         },
         {
             /* Class...End Class  (empty) */
             L"Class C _\nEnd Class",
-            1, 0
+            1, 0,
+            L"End Class", S_OK, -1024
         },
         {
             /* invalid use of parentheses for call statement */
             L"strcomp(\"x\", \"y\")",
-            0, 17
+            0, 17,
+            L"strcomp(\"x\", \"y\")", S_OK, 1044
         },
         {
             L"\n\n\n  cint _\n   throwInt(&h80001234&)",
-            3, 2
+            3, 2,
+            NULL, E_FAIL
         },
         {
             L"dim x\n"
             "if true then throwInt(&h80001234&)",
-            1, 13
+            1, 13,
+            NULL, E_FAIL
         },
         {
             L"dim x\n"
             "if x = throwInt(&h80001234&) then x = 1",
-            1, 0
+            1, 0,
+            NULL, E_FAIL
         },
         {
             L"sub test\n"
@@ -2802,14 +2837,16 @@ static void test_parse_errors(void)
             "    if x = throwInt(&h80001234&) then x = 1\n"
             "end sub\n"
             "test\n",
-            2, 4
+            2, 4,
+            NULL, E_FAIL
         },
         {
             L"dim x\n"
             "do\n"
             "    x = 1\n"
             "loop until throwInt(&h80001234&)\n",
-            3, 0
+            3, 0,
+            NULL, E_FAIL
         },
         {
             L"\n  select case 3\n"
@@ -2818,7 +2855,8 @@ static void test_parse_errors(void)
             "    case throwInt(&h80001234&)\n"
             "        throwInt &h87001234&\n"
             "end select\n",
-            1, 2
+            1, 2,
+            NULL, E_FAIL
         },
         {
             L"if false then\n"
@@ -2828,7 +2866,189 @@ static void test_parse_errors(void)
             "else\n"
             "    throwInt &h87001234&\n"
             "end if\n",
-            2, 1
+            2, 1,
+            NULL, E_FAIL
+        },
+        {
+            /* Hex literal overflow */
+            L"x = &H100000001\n",
+            0, 4,
+            L"x = &H100000001", S_OK
+        },
+        {
+            /* Unterminated string constant - error 1033 */
+            L"x = \"hello\n",
+            0, 10,
+            NULL, S_OK, 1033
+        },
+        {
+            /* Expected 'End' - error 1014 */
+            L"If True Then\nx = 1\n",
+            2, 0,
+            NULL, S_OK, -1014
+        },
+        {
+            /* Name redefined - error 1041 */
+            L"Dim a\nDim a\n",
+            1, -4,
+            NULL, S_OK, 1041
+        },
+        {
+            /* Expected identifier - error 1010 */
+            L"Dim If\n",
+            0, 4,
+            NULL, S_OK, -1010
+        },
+        {
+            /* Invalid character - error 1032 */
+            L"x = @invalid\n",
+            0, 4,
+            NULL, S_OK, 1032
+        },
+        {
+            /* Expected literal constant - error 1045 */
+            L"Const x = 1 + \"a\"\n",
+            0, -17,
+            NULL, S_OK, -1045
+        },
+        {
+            /* Expected '(' - error 1005 */
+            L"Sub x)\nEnd Sub\n",
+            0, 5,
+            NULL, S_OK, -1005
+        },
+        {
+            /* Expected '=' - error 1011 */
+            L"Const x\n",
+            0, 7,
+            NULL, S_OK, -1011
+        },
+        {
+            /* Expected 'To' - error 1013 */
+            L"For i = 1 x 10\nNext\n",
+            0, 10,
+            NULL, S_OK, -1013
+        },
+        {
+            /* Expected 'Then' - error 1017 */
+            L"If True\nEnd If\n",
+            0, 7,
+            NULL, S_OK, -1017
+        },
+        {
+            /* Expected 'Wend' - error 1018 */
+            L"While True\nx = 1\n",
+            2, 0,
+            NULL, S_OK, -1018
+        },
+        {
+            /* Expected 'Loop' - error 1019 */
+            L"Do\nx = 1\n",
+            2, 0,
+            NULL, S_OK, -1019
+        },
+        {
+            /* Expected 'Next' - error 1020 */
+            L"For i = 1 To 10\nx = 1\n",
+            2, 0,
+            NULL, S_OK, -1020
+        },
+        {
+            /* Expected 'Case' - error 1021 */
+            L"Select x\nEnd Select\n",
+            0, 7,
+            NULL, S_OK, -1021
+        },
+        {
+            /* Expected integer constant - error 1026 */
+            L"Dim x(\"a\")\n",
+            0, 6,
+            NULL, S_OK, -1026
+        },
+        {
+            /* Invalid number - error 1031 */
+            L"x = 1e999\n",
+            0, 9,
+            NULL, S_OK, 1031
+        },
+        {
+            /* 'loop' without 'do' - error 1038 */
+            L"Loop\n",
+            0, 0,
+            NULL, S_OK, -1038
+        },
+        {
+            /* Invalid 'exit' statement - error 1039 */
+            L"Exit Do\n",
+            0, -5,
+            NULL, S_OK, 1039
+        },
+        {
+            /* Expected 'In' - error 1046 */
+            L"For Each x = arr\nNext\n",
+            0, 11,
+            NULL, S_OK, -1046
+        },
+        {
+            /* Must be defined inside a Class - error 1048 */
+            L"Property Get x\nEnd Property\n",
+            0, 9,
+            NULL, S_OK, -1048
+        },
+        {
+            /* Expected Let or Set or Get - error 1049 */
+            L"Class C\nProperty x\nEnd Property\nEnd Class\n",
+            1, 9,
+            NULL, S_OK, -1049
+        },
+        /* TODO: Wine allows arguments on Class_Initialize/Class_Terminate
+        {
+            Class initialize/terminate no arguments - error 1053
+            L"Class C\nSub Class_Initialize(x)\nEnd Sub\nEnd Class\n",
+            1, 20, 1053
+        },
+        */
+        {
+            /* Property Let/Set needs at least one argument - error 1054 */
+            L"Class C\nProperty Let x\nEnd Property\nEnd Class\n",
+            1, 14,
+            NULL, S_OK, -1054
+        },
+        {
+            /* Unexpected 'Next' - error 1055 */
+            L"Next\n",
+            0, 0,
+            NULL, S_OK, -1055
+        },
+        {
+            /* 'Default' must also specify 'Public' - error 1057 */
+            L"Class C\nDefault Private Function f()\nf = 1\nEnd Function\nEnd Class\n",
+            1, 0,
+            NULL, S_OK, 1057
+        },
+        {
+            /* Unterminated date literal */
+            L"x = #1/1/2000\n",
+            0, 4,
+            NULL, S_OK, 1002
+        },
+        {
+            /* Newline inside date literal */
+            L"x = #1/1/\n2000#\n",
+            0, 4,
+            NULL, S_OK, 1002
+        },
+        {
+            /* Invalid date literal */
+            L"x = #notadate#\n",
+            0, 4,
+            NULL, S_OK, 1002
+        },
+        {
+            /* '_' not followed by newline */
+            L"x = 1 _x\n",
+            0, 7,
+            NULL, S_OK, 1032
         }
     };
     HRESULT hres;
@@ -2838,6 +3058,7 @@ static void test_parse_errors(void)
     {
         error_line = ~0;
         error_char = -1;
+        error_code = 0;
         onerror_hres = S_OK;
 
         SET_EXPECT(OnScriptError);
@@ -2850,7 +3071,19 @@ static void test_parse_errors(void)
         todo_wine_if(invalid_scripts[i].error_char < 0)
         ok(error_char == abs(invalid_scripts[i].error_char), "[%u] error char %ld expected %d\n",
            i, error_char, invalid_scripts[i].error_char);
+        if(invalid_scripts[i].error_code)
+            todo_wine_if(invalid_scripts[i].error_code < 0)
+            ok(error_code == abs(invalid_scripts[i].error_code), "[%u] error code %u expected %u\n",
+               i, error_code, abs(invalid_scripts[i].error_code));
+        ok(error_source_line_hres == invalid_scripts[i].source_line_hres,
+           "[%u] GetSourceLineText returned: %08lx\n", i, error_source_line_hres);
+        if(error_source_line_hres == S_OK && invalid_scripts[i].source_line)
+            ok(!wcscmp(error_source_line, invalid_scripts[i].source_line),
+               "[%u] source line %s expected %s\n", i,
+               wine_dbgstr_w(error_source_line), wine_dbgstr_w(invalid_scripts[i].source_line));
     }
+    SysFreeString(error_source_line);
+    error_source_line = NULL;
 }
 
 static void test_msgbox(void)
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c
index adda087ce763..7500ec30a8d7 100644
--- a/dlls/vbscript/tests/vbscript.c
+++ b/dlls/vbscript/tests/vbscript.c
@@ -2234,6 +2234,45 @@ static void test_named_items(void)
     CHECK_CALLED(OnEnterScript);
     CHECK_CALLED(OnLeaveScript);
 
+    /* GetRef should only find functions in the current named item context */
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScriptParse_ParseScriptText(parse,
+        L"set x = GetRef(\"testSub_global\")\n", NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "GetRef(testSub_global) from global context failed: %08lx\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(GetIDsOfNames);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScriptParse_ParseScriptText(parse,
+        L"set x = GetRef(\"testSub\")\n", L"codeOnlyItem", NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "GetRef(testSub) from codeOnlyItem context failed: %08lx\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
+    /* GetRef should NOT find functions from other named items' contexts */
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnScriptError);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScriptParse_ParseScriptText(parse,
+        L"set x = GetRef(\"testSub\")\n", NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(FAILED(hres), "GetRef(testSub) from global context should fail: %08lx\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnScriptError);
+    CHECK_CALLED(OnLeaveScript);
+
+    /* GetRef from codeOnlyItem should find global functions (global scope is always accessible) */
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(GetIDsOfNames);
+    SET_EXPECT(OnLeaveScript);
+    hres = IActiveScriptParse_ParseScriptText(parse,
+        L"set x = GetRef(\"testSub_global\")\n", L"codeOnlyItem", NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "GetRef(testSub_global) from codeOnlyItem context failed: %08lx\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+
     IDispatchEx_Release(script_disp2);
     IDispatchEx_Release(script_disp);
 
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index e61c68842a19..66d1b84abf64 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -219,14 +219,14 @@ static HRESULT invoke_vbdisp(vbdisp_t *This, DISPID id, DWORD flags, BOOL extern
                 dp.rgvarg = buf;
             }
 
-            hres = get_propput_arg(This->desc->ctx, params, flags, dp.rgvarg, &needs_release);
+            hres = get_propput_arg(This->desc->ctx, params, flags | DISPATCH_PROPERTYPUTREF, dp.rgvarg, &needs_release);
             if(FAILED(hres)) {
                 if(dp.rgvarg != buf)
                     free(dp.rgvarg);
                 return hres;
             }
 
-            func = This->desc->funcs[id].entries[V_VT(dp.rgvarg) == VT_DISPATCH ? VBDISP_SET : VBDISP_LET];
+            func = This->desc->funcs[id].entries[(flags & DISPATCH_PROPERTYPUTREF) ? VBDISP_SET : VBDISP_LET];
             if(!func) {
                 FIXME("no letter/setter\n");
                 if(dp.rgvarg != buf)
@@ -563,6 +563,121 @@ HRESULT create_vbdisp(const class_desc_t *desc, vbdisp_t **ret)
     return S_OK;
 }
 
+typedef struct {
+    IDispatch IDispatch_iface;
+    LONG ref;
+    function_t *func;
+    script_ctx_t *ctx;
+} FuncRef;
+
+static inline FuncRef *FuncRef_from_IDispatch(IDispatch *iface)
+{
+    return CONTAINING_RECORD(iface, FuncRef, IDispatch_iface);
+}
+
+static HRESULT WINAPI FuncRef_QueryInterface(IDispatch *iface, REFIID riid, void **ppv)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+
+    if(IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IDispatch, riid)) {
+        TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+        *ppv = &This->IDispatch_iface;
+        IDispatch_AddRef(&This->IDispatch_iface);
+        return S_OK;
+    }
+
+    WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
+    *ppv = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI FuncRef_AddRef(IDispatch *iface)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+    LONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+    return ref;
+}
+
+static ULONG WINAPI FuncRef_Release(IDispatch *iface)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+    LONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) ref=%ld\n", This, ref);
+    if(!ref) {
+        release_vbscode(This->func->code_ctx);
+        free(This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI FuncRef_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+    TRACE("(%p)->(%p)\n", This, pctinfo);
+    *pctinfo = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI FuncRef_GetTypeInfo(IDispatch *iface, UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+    TRACE("(%p)->(%u %lu %p)\n", This, iTInfo, lcid, ppTInfo);
+    return DISP_E_BADINDEX;
+}
+
+static HRESULT WINAPI FuncRef_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *rgszNames,
+        UINT cNames, LCID lcid, DISPID *rgDispId)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+    TRACE("(%p)->(%s %p %u %lu %p)\n", This, debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
+    return DISP_E_UNKNOWNNAME;
+}
+
+static HRESULT WINAPI FuncRef_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, LCID lcid,
+        WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
+{
+    FuncRef *This = FuncRef_from_IDispatch(iface);
+
+    TRACE("(%p)->(%ld %s %ld %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
+          lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
+
+    if(dispIdMember != DISPID_VALUE)
+        return DISP_E_MEMBERNOTFOUND;
+
+    return exec_script(This->ctx, TRUE, This->func, NULL, pDispParams, pVarResult);
+}
+
+static const IDispatchVtbl FuncRefVtbl = {
+    FuncRef_QueryInterface,
+    FuncRef_AddRef,
+    FuncRef_Release,
+    FuncRef_GetTypeInfoCount,
+    FuncRef_GetTypeInfo,
+    FuncRef_GetIDsOfNames,
+    FuncRef_Invoke
+};
+
+HRESULT create_func_ref(script_ctx_t *ctx, function_t *func, IDispatch **ret)
+{
+    FuncRef *ref;
+
+    ref = calloc(1, sizeof(*ref));
+    if(!ref)
+        return E_OUTOFMEMORY;
+
+    ref->IDispatch_iface.lpVtbl = &FuncRefVtbl;
+    ref->ref = 1;
+    ref->func = func;
+    ref->ctx = ctx;
+    grab_vbscode(func->code_ctx);
+
+    *ret = &ref->IDispatch_iface;
+    return S_OK;
+}
+
 struct typeinfo_func {
     function_t *func;
     MEMBERID memid;
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c
index 715c98d32bbe..2e2fa6498da9 100644
--- a/dlls/vbscript/vbscript.c
+++ b/dlls/vbscript/vbscript.c
@@ -64,6 +64,8 @@ typedef struct {
     DWORD_PTR cookie;
     unsigned line;
     unsigned character;
+    vbscode_t *code;
+    unsigned loc;
 } VBScriptError;
 
 static inline WCHAR *heap_pool_strdup(heap_pool_t *heap, const WCHAR *str)
@@ -91,7 +93,7 @@ static inline BOOL is_started(VBScript *This)
         || This->state == SCRIPTSTATE_DISCONNECTED;
 }
 
-static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res)
+HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL extern_caller)
 {
     ScriptDisp *obj = ctx->script_obj;
     function_t *func_iter, **new_funcs;
@@ -138,6 +140,20 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res
 
     for (i = 0; i < code->main_code.var_cnt; i++)
     {
+        size_t j;
+        BOOL found = FALSE;
+
+        for (j = 0; j < obj->global_vars_cnt; j++)
+        {
+            if (!wcsicmp(obj->global_vars[j]->name, code->main_code.vars[i].name))
+            {
+                found = TRUE;
+                break;
+            }
+        }
+        if (found)
+            continue;
+
         if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var))))
             return E_OUTOFMEMORY;
 
@@ -148,11 +164,9 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res
         var->is_const = FALSE;
         var->array = NULL;
 
-        obj->global_vars[obj->global_vars_cnt + i] = var;
+        obj->global_vars[obj->global_vars_cnt++] = var;
     }
 
-    obj->global_vars_cnt += code->main_code.var_cnt;
-
     for (func_iter = code->funcs; func_iter; func_iter = func_iter->next)
     {
         for (i = 0; i < obj->global_funcs_cnt; i++)
@@ -189,7 +203,7 @@ static HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res
 
     prev_caller = ctx->vbcaller->caller;
     ctx->vbcaller->caller = SP_CALLER_UNINITIALIZED;
-    hres = exec_script(ctx, TRUE, &code->main_code, NULL, NULL, res);
+    hres = exec_script(ctx, extern_caller, &code->main_code, NULL, NULL, res);
     ctx->vbcaller->caller = prev_caller;
     return hres;
 }
@@ -200,7 +214,7 @@ static void exec_queued_code(script_ctx_t *ctx)
 
     LIST_FOR_EACH_ENTRY(iter, &ctx->code_list, vbscode_t, entry) {
         if(iter->pending_exec)
-            exec_global_code(ctx, iter, NULL);
+            exec_global_code(ctx, iter, NULL, TRUE);
     }
 }
 
@@ -505,8 +519,12 @@ static ULONG WINAPI VBScriptError_Release(IActiveScriptError *iface)
 
     TRACE("(%p) ref=%ld\n", This, ref);
 
-    if(!ref)
+    if(!ref) {
+        clear_ei(&This->ei);
+        if(This->code)
+            release_vbscode(This->code);
         free(This);
+    }
 
     return ref;
 }
@@ -542,8 +560,28 @@ static HRESULT WINAPI VBScriptError_GetSourcePosition(IActiveScriptError *iface,
 static HRESULT WINAPI VBScriptError_GetSourceLineText(IActiveScriptError *iface, BSTR *source)
 {
     VBScriptError *This = impl_from_IActiveScriptError(iface);
-    FIXME("(%p)->(%p)\n", This, source);
-    return E_NOTIMPL;
+    const WCHAR *nl, *line_end;
+
+    TRACE("(%p)->(%p)\n", This, source);
+
+    if(!source)
+        return E_POINTER;
+
+    if(!This->code) {
+        *source = NULL;
+        return E_FAIL;
+    }
+
+    nl = This->code->source + This->loc;
+    while(nl > This->code->source && nl[-1] != '\n')
+        nl--;
+
+    line_end = This->code->source + This->loc;
+    while(*line_end && *line_end != '\n' && *line_end != '\r')
+        line_end++;
+
+    *source = SysAllocStringLen(nl, line_end - nl);
+    return *source ? S_OK : E_OUTOFMEMORY;
 }
 
 static const IActiveScriptErrorVtbl VBScriptErrorVtbl = {
@@ -555,7 +593,7 @@ static const IActiveScriptErrorVtbl VBScriptErrorVtbl = {
     VBScriptError_GetSourceLineText
 };
 
-HRESULT report_script_error(script_ctx_t *ctx, const vbscode_t *code, unsigned loc)
+HRESULT report_script_error(script_ctx_t *ctx, vbscode_t *code, unsigned loc, BOOL store_source)
 {
     VBScriptError *error;
     const WCHAR *p, *nl;
@@ -580,6 +618,15 @@ HRESULT report_script_error(script_ctx_t *ctx, const vbscode_t *code, unsigned l
     }
     error->character = code->source + loc - nl;
 
+    if(store_source) {
+        grab_vbscode(code);
+        error->code = code;
+        error->loc = loc;
+    }else {
+        error->code = NULL;
+        error->loc = 0;
+    }
+
     hres = IActiveScriptSite_OnScriptError(ctx->site, &error->IActiveScriptError_iface);
     IActiveScriptError_Release(&error->IActiveScriptError_iface);
     return hres == S_OK ? SCRIPT_E_REPORTED : result;
@@ -1055,16 +1102,22 @@ static HRESULT WINAPI VBScriptParse_ParseScriptText(IActiveScriptParse *iface,
         return E_UNEXPECTED;
 
     hres = compile_script(This->ctx, pstrCode, pstrItemName, pstrDelimiter, dwSourceContextCookie,
-                          ulStartingLine, dwFlags, &code);
-    if(FAILED(hres))
+                          ulStartingLine, dwFlags, FALSE, &code);
+    if(FAILED(hres)) {
+        if(hres == SCRIPT_E_RECORDED) {
+            hres = report_script_error(This->ctx, This->ctx->error_loc_code,
+                                       This->ctx->error_loc_offset, TRUE);
+            clear_error_loc(This->ctx);
+        }
         return hres;
+    }
 
     if(!(dwFlags & SCRIPTTEXT_ISEXPRESSION) && !is_started(This)) {
         code->pending_exec = TRUE;
         return S_OK;
     }
 
-    return exec_global_code(This->ctx, code, pvarResult);
+    return exec_global_code(This->ctx, code, pvarResult, TRUE);
 }
 
 static const IActiveScriptParseVtbl VBScriptParseVtbl = {
@@ -1118,8 +1171,14 @@ static HRESULT WINAPI VBScriptParseProcedure_ParseProcedureText(IActiveScriptPar
 
     hres = compile_procedure(This->ctx, pstrCode, pstrItemName, pstrDelimiter, dwSourceContextCookie,
                              ulStartingLineNumber, dwFlags, &desc);
-    if(FAILED(hres))
+    if(FAILED(hres)) {
+        if(hres == SCRIPT_E_RECORDED) {
+            hres = report_script_error(This->ctx, This->ctx->error_loc_code,
+                                       This->ctx->error_loc_offset, TRUE);
+            clear_error_loc(This->ctx);
+        }
         return hres;
+    }
 
     hres = create_vbdisp(desc, &vbdisp);
     if(FAILED(hres))
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 6b67c8b1bc54..3bf23a34bfaa 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -52,6 +52,7 @@ heap_pool_t *heap_pool_mark(heap_pool_t*);
 typedef struct _function_t function_t;
 typedef struct _vbscode_t vbscode_t;
 typedef struct _script_ctx_t script_ctx_t;
+typedef struct _exec_ctx_t exec_ctx_t;
 typedef struct _vbdisp_t vbdisp_t;
 
 typedef enum {
@@ -167,6 +168,7 @@ HRESULT disp_propput(script_ctx_t*,IDispatch*,DISPID,WORD,DISPPARAMS*);
 HRESULT get_disp_value(script_ctx_t*,IDispatch*,VARIANT*);
 void collect_objects(script_ctx_t*);
 HRESULT create_script_disp(script_ctx_t*,ScriptDisp**);
+HRESULT create_func_ref(script_ctx_t*,function_t*,IDispatch**);
 
 HRESULT to_int(VARIANT*,int*);
 
@@ -202,9 +204,14 @@ struct _script_ctx_t {
 
     ScriptDisp *script_obj;
 
+    named_item_t *current_named_item;
+
     BuiltinDisp *global_obj;
     BuiltinDisp *err_obj;
 
+    exec_ctx_t *current_exec;
+    exec_ctx_t *caller_exec;
+
     EXCEPINFO ei;
     vbscode_t *error_loc_code;
     unsigned error_loc_offset;
@@ -251,6 +258,7 @@ typedef enum {
     X(hres,           1, ARG_UINT,    0)          \
     X(errmode,        1, ARG_INT,     0)          \
     X(eqv,            1, 0,           0)          \
+    X(erase,          1, ARG_BSTR,    0)          \
     X(exp,            1, 0,           0)          \
     X(gt,             1, 0,           0)          \
     X(gteq,           1, 0,           0)          \
@@ -296,6 +304,7 @@ typedef enum {
     X(val,            1, 0,           0)          \
     X(vcall,          1, ARG_UINT,    0)          \
     X(vcallv,         1, ARG_UINT,    0)          \
+    X(with,           1, 0,           0)          \
     X(xor,            1, 0,           0)
 
 typedef enum {
@@ -387,14 +396,18 @@ static inline void grab_vbscode(vbscode_t *code)
 }
 
 void release_vbscode(vbscode_t*);
-HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,vbscode_t**);
+HRESULT compile_script(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,BOOL,vbscode_t**);
 HRESULT compile_procedure(script_ctx_t*,const WCHAR*,const WCHAR*,const WCHAR*,DWORD_PTR,unsigned,DWORD,class_desc_t**);
 HRESULT exec_script(script_ctx_t*,BOOL,function_t*,vbdisp_t*,DISPPARAMS*,VARIANT*);
+HRESULT exec_global_code(script_ctx_t*,vbscode_t*,VARIANT*,BOOL);
+BOOL is_exec_local_scope(exec_ctx_t*);
+HRESULT exec_add_caller_dynamic_var(script_ctx_t*,exec_ctx_t*,const WCHAR*);
 void release_dynamic_var(dynamic_var_t*);
 named_item_t *lookup_named_item(script_ctx_t*,const WCHAR*,unsigned);
 void release_named_item(named_item_t*);
+void clear_error_loc(script_ctx_t*);
 void clear_ei(EXCEPINFO*);
-HRESULT report_script_error(script_ctx_t*,const vbscode_t*,unsigned);
+HRESULT report_script_error(script_ctx_t*,vbscode_t*,unsigned,BOOL);
 void detach_global_objects(script_ctx_t*);
 HRESULT get_builtin_id(BuiltinDisp*,const WCHAR*,DISPID*);
 HRESULT array_access(SAFEARRAY *array, DISPPARAMS *dp, VARIANT **ret);
diff --git a/dlls/vbscript/vbscript.rc b/dlls/vbscript/vbscript.rc
index b9a1c3ad5c3f..770052b641f5 100644
--- a/dlls/vbscript/vbscript.rc
+++ b/dlls/vbscript/vbscript.rc
@@ -41,6 +41,7 @@ STRINGTABLE
     VBSE_PATH_FILE_ACCESS              "Path/File access error"
     VBSE_PATH_NOT_FOUND                "Path not found"
     VBSE_OBJECT_VARIABLE_NOT_SET       "Object variable not set"
+    VBSE_FOR_LOOP_NOT_INITIALIZED      "For loop not initialized"
     VBSE_ILLEGAL_NULL_USE              "Invalid use of Null"
     VBSE_CANT_CREATE_TMP_FILE          "Can't create necessary temporary file"
     VBSE_OBJECT_REQUIRED               "Object required"
@@ -58,7 +59,40 @@ STRINGTABLE
     VBSE_INVALID_DLL_FUNCTION_NAME     "Specified DLL function not found"
     VBSE_INVALID_TYPELIB_VARIABLE      "Variable uses an Automation type not supported in VBScript"
     VBSE_SERVER_NOT_FOUND              "The remote server machine does not exist or is unavailable"
+    VBSE_VARIABLE_UNDEFINED            "Variable is undefined"
     VBSE_UNQUALIFIED_REFERENCE         "Invalid or unqualified reference"
+    VBSE_SYNTAX_ERROR                  "Syntax error"
+    VBSE_EXPECTED_LPAREN               "Expected '('"
+    VBSE_EXPECTED_IDENTIFIER           "Expected identifier"
+    VBSE_EXPECTED_ASSIGN               "Expected '='"
+    VBSE_EXPECTED_TO                   "Expected 'To'"
+    VBSE_EXPECTED_END                  "Expected 'End'"
+    VBSE_EXPECTED_THEN                 "Expected 'Then'"
+    VBSE_EXPECTED_WEND                 "Expected 'Wend'"
+    VBSE_EXPECTED_LOOP                 "Expected 'Loop'"
+    VBSE_EXPECTED_NEXT                 "Expected 'Next'"
+    VBSE_EXPECTED_CASE                 "Expected 'Case'"
+    VBSE_EXPECTED_STATEMENT            "Expected statement"
+    VBSE_EXPECTED_END_OF_STATEMENT     "Expected end of statement"
+    VBSE_EXPECTED_INTEGER_CONSTANT     "Expected integer constant"
+    VBSE_EXPECTED_WHILE_UNTIL_EOS      "Expected 'While', 'Until' or end of statement"
+    VBSE_INVALID_NUMBER                "Invalid number"
+    VBSE_INVALID_CHAR                  "Invalid character"
+    VBSE_UNTERMINATED_STRING           "Unterminated string constant"
+    VBSE_LOOP_WITHOUT_DO               "'loop' without 'do'"
+    VBSE_INVALID_EXIT                  "Invalid 'exit' statement"
+    VBSE_NAME_REDEFINED                "Name redefined"
+    VBSE_MUST_BE_FIRST_STATEMENT       "Must be first statement on the line"
+    VBSE_CANNOT_USE_PARENS_CALLING_SUB "Cannot use parentheses when calling a Sub"
+    VBSE_EXPECTED_LITERAL_CONSTANT     "Expected literal constant"
+    VBSE_EXPECTED_IN                   "Expected 'In'"
+    VBSE_EXPECTED_CLASS                "Expected 'Class'"
+    VBSE_MUST_BE_INSIDE_CLASS          "Must be defined inside a Class"
+    VBSE_EXPECTED_LET_SET_GET          "Expected Let or Set or Get in property declaration"
+    VBSE_CLASS_INIT_NO_ARGS            "Class initialize or terminate do not have arguments"
+    VBSE_PROPERTY_LET_SET_NEEDS_ARG    "Property set or let must have at least one argument"
+    VBSE_UNEXPECTED_NEXT               "Unexpected 'Next'"
+    VBSE_DEFAULT_MUST_BE_PUBLIC        "'Default' specification must also specify 'Public'"
 
     VBS_COMPILE_ERROR                  "Microsoft VBScript compilation error"
     VBS_RUNTIME_ERROR                  "Microsoft VBScript runtime error"
diff --git a/dlls/vbscript/vbscript_defs.h b/dlls/vbscript/vbscript_defs.h
index e0e9d1cac940..4654798b8a1d 100644
--- a/dlls/vbscript/vbscript_defs.h
+++ b/dlls/vbscript/vbscript_defs.h
@@ -252,6 +252,7 @@
 #define VBSE_PATH_FILE_ACCESS              75
 #define VBSE_PATH_NOT_FOUND                76
 #define VBSE_OBJECT_VARIABLE_NOT_SET       91
+#define VBSE_FOR_LOOP_NOT_INITIALIZED      92
 #define VBSE_ILLEGAL_NULL_USE              94
 #define VBSE_CANT_CREATE_TMP_FILE         322
 #define VBSE_OBJECT_REQUIRED              424
@@ -269,7 +270,40 @@
 #define VBSE_INVALID_DLL_FUNCTION_NAME    453
 #define VBSE_INVALID_TYPELIB_VARIABLE     458
 #define VBSE_SERVER_NOT_FOUND             462
+#define VBSE_VARIABLE_UNDEFINED           500
 #define VBSE_UNQUALIFIED_REFERENCE        505
+#define VBSE_SYNTAX_ERROR                1002
+#define VBSE_EXPECTED_LPAREN             1005
+#define VBSE_EXPECTED_IDENTIFIER         1010
+#define VBSE_EXPECTED_ASSIGN             1011
+#define VBSE_EXPECTED_TO                 1013
+#define VBSE_EXPECTED_END                1014
+#define VBSE_EXPECTED_THEN               1017
+#define VBSE_EXPECTED_WEND               1018
+#define VBSE_EXPECTED_LOOP               1019
+#define VBSE_EXPECTED_NEXT               1020
+#define VBSE_EXPECTED_CASE               1021
+#define VBSE_EXPECTED_STATEMENT          1024
+#define VBSE_EXPECTED_END_OF_STATEMENT   1025
+#define VBSE_EXPECTED_INTEGER_CONSTANT   1026
+#define VBSE_EXPECTED_WHILE_UNTIL_EOS    1028
+#define VBSE_INVALID_NUMBER              1031
+#define VBSE_INVALID_CHAR                1032
+#define VBSE_UNTERMINATED_STRING         1033
+#define VBSE_LOOP_WITHOUT_DO             1038
+#define VBSE_INVALID_EXIT                1039
+#define VBSE_NAME_REDEFINED              1041
+#define VBSE_MUST_BE_FIRST_STATEMENT     1042
+#define VBSE_CANNOT_USE_PARENS_CALLING_SUB 1044
+#define VBSE_EXPECTED_LITERAL_CONSTANT   1045
+#define VBSE_EXPECTED_IN                 1046
+#define VBSE_EXPECTED_CLASS              1047
+#define VBSE_MUST_BE_INSIDE_CLASS        1048
+#define VBSE_EXPECTED_LET_SET_GET        1049
+#define VBSE_CLASS_INIT_NO_ARGS          1053
+#define VBSE_PROPERTY_LET_SET_NEEDS_ARG  1054
+#define VBSE_UNEXPECTED_NEXT             1055
+#define VBSE_DEFAULT_MUST_BE_PUBLIC      1057
 
 #define VBS_COMPILE_ERROR                4096
 #define VBS_RUNTIME_ERROR                4097
diff --git a/dlls/vcruntime140/init_thread.c b/dlls/vcruntime140/init_thread.c
index 6d73f85785f8..a2db941bf790 100644
--- a/dlls/vcruntime140/init_thread.c
+++ b/dlls/vcruntime140/init_thread.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/vcruntime140/typeinfo.c b/dlls/vcruntime140/typeinfo.c
index e5b59d85e29d..2c5ddccddc9f 100644
--- a/dlls/vcruntime140/typeinfo.c
+++ b/dlls/vcruntime140/typeinfo.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/vcruntime140/typeinfo_root.cpp b/dlls/vcruntime140/typeinfo_root.cpp
index 018c292ee3f0..b6da6b61c55e 100644
--- a/dlls/vcruntime140/typeinfo_root.cpp
+++ b/dlls/vcruntime140/typeinfo_root.cpp
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/dlls/wevtapi/main.c b/dlls/wevtapi/main.c
index 8222a958e9ec..d12607890922 100644
--- a/dlls/wevtapi/main.c
+++ b/dlls/wevtapi/main.c
@@ -155,3 +155,11 @@ EVT_HANDLE WINAPI EvtCreateRenderContext(DWORD pathcount, const WCHAR **paths, D
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     return NULL;
 }
+
+BOOL WINAPI EvtRender(EVT_HANDLE context, EVT_HANDLE fragment, DWORD flags, DWORD buffer_size, void *buffer,
+                      DWORD *buffer_used, DWORD *property_count)
+{
+    FIXME("(%p %p %#lx %lu %p %p %p) stub!\n", context, fragment, flags, buffer_size, buffer, buffer_used, property_count);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
diff --git a/dlls/wevtapi/wevtapi.spec b/dlls/wevtapi/wevtapi.spec
index c7bf94b451a8..e25f9c509cdf 100644
--- a/dlls/wevtapi/wevtapi.spec
+++ b/dlls/wevtapi/wevtapi.spec
@@ -37,7 +37,7 @@
 @ stub EvtOpenPublisherMetadata
 @ stdcall EvtOpenSession(long ptr long long)
 @ stdcall EvtQuery(ptr wstr wstr long)
-@ stub EvtRender
+@ stdcall EvtRender(ptr ptr long long ptr ptr ptr)
 @ stdcall EvtSaveChannelConfig(ptr long)
 @ stub EvtSeek
 @ stdcall EvtSetChannelConfigProperty(ptr long long ptr)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c
index 5478088a4f4d..1587b6b6795a 100644
--- a/dlls/win32u/class.c
+++ b/dlls/win32u/class.c
@@ -547,6 +547,14 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam
 
     class->local      = !is_builtin && !(wc->style & CS_GLOBALCLASS);
 
+    /* Other non-null values must be set by caller */
+    if (wc->hIcon && !wc->hIconSm)
+        sm_icon = CopyImage( wc->hIcon, IMAGE_ICON,
+                             get_system_metrics( SM_CXSMICON ),
+                             get_system_metrics( SM_CYSMICON ),
+                             LR_COPYFROMRESOURCE );
+
+    user_lock();
     SERVER_START_REQ( create_class )
     {
         req->local      = class->local;
@@ -562,11 +570,7 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam
         atom = reply->atom;
     }
     SERVER_END_REQ;
-    if (!ret)
-    {
-        free( class );
-        return 0;
-    }
+    if (!ret) goto failed;
 
     if (!(shared = find_shared_session_object( locator.id, locator.offset )))
     {
@@ -578,18 +582,10 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam
             wine_server_call( req );
         }
         SERVER_END_REQ;
-        free( class );
-        return 0;
-    }
 
-    /* Other non-null values must be set by caller */
-    if (wc->hIcon && !wc->hIconSm)
-        sm_icon = CopyImage( wc->hIcon, IMAGE_ICON,
-                             get_system_metrics( SM_CXSMICON ),
-                             get_system_metrics( SM_CYSMICON ),
-                             LR_COPYFROMRESOURCE );
+        goto failed;
+    }
 
-    user_lock();
     if (class->local) list_add_head( &class_list, &class->entry );
     else list_add_tail( &class_list, &class->entry );
 
@@ -607,6 +603,13 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam
     class->shared        = shared;
     release_class_ptr( class );
     return atom;
+
+failed:
+    user_unlock();
+    NtUserDestroyCursor( sm_icon, 0 );
+    free( class );
+    return 0;
+
 }
 
 /***********************************************************************
@@ -621,6 +624,8 @@ BOOL WINAPI NtUserUnregisterClass( UNICODE_STRING *name, HINSTANCE instance,
     /* create the desktop window to trigger builtin class registration */
     get_desktop_window();
 
+    user_lock();
+
     SERVER_START_REQ( destroy_class )
     {
         req->instance = wine_server_client_ptr( instance );
@@ -628,11 +633,14 @@ BOOL WINAPI NtUserUnregisterClass( UNICODE_STRING *name, HINSTANCE instance,
         if (!wine_server_call_err( req )) class = wine_server_get_ptr( reply->client_ptr );
     }
     SERVER_END_REQ;
-    if (!class) return FALSE;
+    if (!class)
+    {
+        user_unlock();
+        return FALSE;
+    }
 
     TRACE( "%p\n", class );
 
-    user_lock();
     if (class->dce) free_dce( class->dce, 0, &drawables );
     list_remove( &class->entry );
     if (class->hbrBackground > (HBRUSH)(COLOR_GRADIENTINACTIVECAPTION + 1))
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index a0f7a4168e61..ab09c3b7d424 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -943,7 +943,7 @@ DWORD get_last_input_time(void)
 {
     DWORD ret;
 
-    SERVER_START_REQ( get_last_input_time )
+    SERVER_START_REQ( set_user_input_time )
     {
         wine_server_call( req );
         ret = reply->time;
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c
index fc129df07855..bcf25bf65abc 100644
--- a/dlls/win32u/window.c
+++ b/dlls/win32u/window.c
@@ -2678,7 +2678,7 @@ BOOL WINAPI NtUserUpdateLayeredWindow( HWND hwnd, HDC hdc_dst, const POINT *pts_
     apply_window_pos( hwnd, 0, swp_flags, surface, &new_rects, NULL );
     if (!surface) return FALSE;
 
-    if (!hdc_src || surface == &dummy_surface)
+    if (!hdc_src || surface == &dummy_surface || NtUserWindowFromDC( hdc_src ) == hwnd)
     {
         user_driver->pUpdateLayeredWindow( hwnd, source_alpha, flags );
         ret = TRUE;
diff --git a/dlls/windows.devices.radios/Makefile.in b/dlls/windows.devices.radios/Makefile.in
new file mode 100644
index 000000000000..55bcdedd0cb9
--- /dev/null
+++ b/dlls/windows.devices.radios/Makefile.in
@@ -0,0 +1,9 @@
+MODULE  = windows.devices.radios.dll
+IMPORTS = combase
+
+SOURCES = \
+	async.c \
+	async_private.idl \
+	classes.idl \
+	main.c \
+	vector.c
diff --git a/dlls/windows.devices.radios/async.c b/dlls/windows.devices.radios/async.c
new file mode 100644
index 000000000000..2d9246c237cd
--- /dev/null
+++ b/dlls/windows.devices.radios/async.c
@@ -0,0 +1,667 @@
+/* WinRT IAsync* implementation
+ *
+ * Copyright 2022 Bernhard Kölbl for CodeWeavers
+ * Copyright 2022 Rémi Bernon 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 WIDL_using_Wine_Internal
+#include "private.h"
+#include "initguid.h"
+#include "async_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(combase);
+
+#define Closed 4
+#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0)
+
+struct async_info
+{
+    IAsyncInfoImpl IAsyncInfoImpl_iface;
+    IAsyncInfo IAsyncInfo_iface;
+    IInspectable *IInspectable_outer;
+    LONG ref;
+
+    async_operation_callback callback;
+    TP_WORK *async_run_work;
+    IUnknown *invoker;
+    IUnknown *param;
+
+    CRITICAL_SECTION cs;
+    IAsyncOperationCompletedHandlerImpl *handler;
+    PROPVARIANT result;
+    AsyncStatus status;
+    HRESULT hr;
+};
+
+static inline struct async_info *impl_from_IAsyncInfoImpl( IAsyncInfoImpl *iface )
+{
+    return CONTAINING_RECORD( iface, struct async_info, IAsyncInfoImpl_iface );
+}
+
+static HRESULT WINAPI async_impl_QueryInterface( IAsyncInfoImpl *iface, REFIID iid, void **out )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( 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_IAsyncInfoImpl ))
+    {
+        IInspectable_AddRef( (*out = &impl->IAsyncInfoImpl_iface) );
+        return S_OK;
+    }
+
+    if (IsEqualGUID( iid, &IID_IAsyncInfo ))
+    {
+        IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI async_impl_AddRef( IAsyncInfoImpl *iface )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI async_impl_Release( IAsyncInfoImpl *iface )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        if (impl->handler && impl->handler != HANDLER_NOT_SET) IAsyncOperationCompletedHandlerImpl_Release( impl->handler );
+        IAsyncInfo_Close( &impl->IAsyncInfo_iface );
+        if (impl->param) IUnknown_Release( impl->param );
+        if (impl->invoker) IUnknown_Release( impl->invoker );
+        PropVariantClear( &impl->result );
+        impl->cs.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection( &impl->cs );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI async_impl_put_Completed( IAsyncInfoImpl *iface, IAsyncOperationCompletedHandlerImpl *handler )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p, handler %p.\n", iface, handler );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+    else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT;
+    else if ((impl->handler = handler))
+    {
+        IAsyncOperationCompletedHandlerImpl_AddRef( impl->handler );
+
+        if (impl->status > Started)
+        {
+            IInspectable *operation = impl->IInspectable_outer;
+            AsyncStatus status = impl->status;
+            impl->handler = NULL; /* Prevent concurrent invoke. */
+            LeaveCriticalSection( &impl->cs );
+
+            IAsyncOperationCompletedHandlerImpl_Invoke( handler, operation, status );
+            IAsyncOperationCompletedHandlerImpl_Release( handler );
+
+            return S_OK;
+        }
+    }
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static HRESULT WINAPI async_impl_get_Completed( IAsyncInfoImpl *iface, IAsyncOperationCompletedHandlerImpl **handler )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p, handler %p.\n", iface, handler );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+    if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL;
+    else IAsyncOperationCompletedHandlerImpl_AddRef( (*handler = impl->handler) );
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static HRESULT WINAPI async_impl_get_Result( IAsyncInfoImpl *iface, PROPVARIANT *result )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+    HRESULT hr = E_ILLEGAL_METHOD_CALL;
+
+    TRACE( "iface %p, result %p.\n", iface, result );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Completed || impl->status == Error)
+    {
+        PropVariantCopy( result, &impl->result );
+        hr = impl->hr;
+    }
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static BOOL async_info_complete( struct async_info *impl, BOOL called_async )
+{
+    IInspectable *operation = impl->IInspectable_outer;
+    PROPVARIANT result = {0};
+    HRESULT hr;
+
+    hr = impl->callback( impl->invoker, impl->param, &result, called_async );
+    if (!called_async && hr == STATUS_PENDING) return FALSE;
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed;
+    PropVariantCopy( &impl->result, &result );
+    impl->hr = hr;
+
+    if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET)
+    {
+        IAsyncOperationCompletedHandlerImpl *handler = impl->handler;
+        AsyncStatus status = impl->status;
+        impl->handler = NULL; /* Prevent concurrent invoke. */
+        LeaveCriticalSection( &impl->cs );
+
+        IAsyncOperationCompletedHandlerImpl_Invoke( handler, operation, status );
+        IAsyncOperationCompletedHandlerImpl_Release( handler );
+    }
+    else LeaveCriticalSection( &impl->cs );
+
+    /* release refcount acquired in Start */
+    IInspectable_Release( operation );
+
+    PropVariantClear( &result );
+    return TRUE;
+}
+
+static HRESULT WINAPI async_impl_Start( IAsyncInfoImpl *iface )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+
+    TRACE( "iface %p.\n", iface );
+
+    /* keep the async alive in the callback */
+    IInspectable_AddRef( impl->IInspectable_outer );
+    if (!async_info_complete( impl, FALSE )) SubmitThreadpoolWork( impl->async_run_work );
+
+    return S_OK;
+}
+
+static const struct IAsyncInfoImplVtbl async_impl_vtbl =
+{
+    /* IUnknown methods */
+    async_impl_QueryInterface,
+    async_impl_AddRef,
+    async_impl_Release,
+    /* IAsyncInfoImpl */
+    async_impl_put_Completed,
+    async_impl_get_Completed,
+    async_impl_get_Result,
+    async_impl_Start,
+};
+
+DEFINE_IINSPECTABLE_OUTER( async_info, IAsyncInfo, struct async_info, IInspectable_outer )
+
+static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id )
+{
+    struct async_info *impl = impl_from_IAsyncInfo( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p, id %p.\n", iface, id );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+    *id = 1;
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status )
+{
+    struct async_info *impl = impl_from_IAsyncInfo( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p, status %p.\n", iface, status );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+    *status = impl->status;
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code )
+{
+    struct async_info *impl = impl_from_IAsyncInfo( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p, error_code %p.\n", iface, error_code );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL;
+    else *error_code = impl->hr;
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface )
+{
+    struct async_info *impl = impl_from_IAsyncInfo( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p.\n", iface );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL;
+    else if (impl->status == Started) impl->status = Canceled;
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static HRESULT WINAPI async_info_Close( IAsyncInfo *iface )
+{
+    struct async_info *impl = impl_from_IAsyncInfo( iface );
+    HRESULT hr = S_OK;
+
+    TRACE( "iface %p.\n", iface );
+
+    EnterCriticalSection( &impl->cs );
+    if (impl->status == Started)
+        hr = E_ILLEGAL_STATE_CHANGE;
+    else if (impl->status != Closed)
+    {
+        CloseThreadpoolWork( impl->async_run_work );
+        impl->async_run_work = NULL;
+        impl->status = Closed;
+    }
+    LeaveCriticalSection( &impl->cs );
+
+    return hr;
+}
+
+static const struct IAsyncInfoVtbl async_info_vtbl =
+{
+    /* IUnknown methods */
+    async_info_QueryInterface,
+    async_info_AddRef,
+    async_info_Release,
+    /* IInspectable methods */
+    async_info_GetIids,
+    async_info_GetRuntimeClassName,
+    async_info_GetTrustLevel,
+    /* IAsyncInfo */
+    async_info_get_Id,
+    async_info_get_Status,
+    async_info_get_ErrorCode,
+    async_info_Cancel,
+    async_info_Close,
+};
+
+static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work )
+{
+    struct async_info *impl = impl_from_IAsyncInfoImpl( iface );
+
+    async_info_complete( impl, TRUE );
+}
+
+static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+                                  IInspectable *outer, IAsyncInfoImpl **out )
+{
+    struct async_info *impl;
+    HRESULT hr;
+
+    if (!(impl = calloc( 1, sizeof(struct async_info) ))) return E_OUTOFMEMORY;
+    impl->IAsyncInfoImpl_iface.lpVtbl = &async_impl_vtbl;
+    impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl;
+    impl->IInspectable_outer = outer;
+    impl->ref = 1;
+
+    impl->callback = callback;
+    impl->handler = HANDLER_NOT_SET;
+    impl->status = Started;
+    if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IAsyncInfoImpl_iface, NULL )))
+    {
+        hr = HRESULT_FROM_WIN32( GetLastError() );
+        free( impl );
+        return hr;
+    }
+
+    if ((impl->invoker = invoker)) IUnknown_AddRef( impl->invoker );
+    if ((impl->param = param)) IUnknown_AddRef( impl->param );
+
+    InitializeCriticalSectionEx( &impl->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
+    impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" );
+
+    *out = &impl->IAsyncInfoImpl_iface;
+    return S_OK;
+}
+
+struct async_inspectable
+{
+    IAsyncOperation_IInspectable IAsyncOperation_IInspectable_iface;
+    IAsyncInfoImpl *IAsyncInfoImpl_inner;
+    LONG ref;
+    const GUID *iid;
+};
+
+static inline struct async_inspectable *impl_from_IAsyncOperation_IInspectable( IAsyncOperation_IInspectable *iface )
+{
+    return CONTAINING_RECORD( iface, struct async_inspectable, IAsyncOperation_IInspectable_iface );
+}
+
+static HRESULT WINAPI async_inspectable_QueryInterface( IAsyncOperation_IInspectable *iface, REFIID iid, void **out )
+{
+    struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable( 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, impl->iid ))
+    {
+        IInspectable_AddRef( (*out = &impl->IAsyncOperation_IInspectable_iface) );
+        return S_OK;
+    }
+
+    return IAsyncInfoImpl_QueryInterface( impl->IAsyncInfoImpl_inner, iid, out );
+}
+
+static ULONG WINAPI async_inspectable_AddRef( IAsyncOperation_IInspectable *iface )
+{
+    struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI async_inspectable_Release( IAsyncOperation_IInspectable *iface )
+{
+    struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        /* guard against re-entry if inner releases an outer iface */
+        InterlockedIncrement( &impl->ref );
+        IAsyncInfoImpl_Release( impl->IAsyncInfoImpl_inner );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI async_inspectable_GetIids( IAsyncOperation_IInspectable *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 async_inspectable_GetRuntimeClassName( IAsyncOperation_IInspectable *iface, HSTRING *class_name )
+{
+    return WindowsCreateString( L"Windows.Foundation.IAsyncOperation`1<IInspectable>",
+                                ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<IInspectable>"),
+                                class_name );
+}
+
+static HRESULT WINAPI async_inspectable_GetTrustLevel( IAsyncOperation_IInspectable *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_inspectable_put_Completed( IAsyncOperation_IInspectable *iface, IAsyncOperationCompletedHandler_IInspectable *bool_handler )
+{
+    IAsyncOperationCompletedHandlerImpl *handler = (IAsyncOperationCompletedHandlerImpl *)bool_handler;
+    struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable( iface );
+    TRACE( "iface %p, handler %p.\n", iface, handler );
+    return IAsyncInfoImpl_put_Completed( impl->IAsyncInfoImpl_inner, handler );
+}
+
+static HRESULT WINAPI async_inspectable_get_Completed( IAsyncOperation_IInspectable *iface, IAsyncOperationCompletedHandler_IInspectable **bool_handler )
+{
+    IAsyncOperationCompletedHandlerImpl **handler = (IAsyncOperationCompletedHandlerImpl **)bool_handler;
+    struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable( iface );
+    TRACE( "iface %p, handler %p.\n", iface, handler );
+    return IAsyncInfoImpl_get_Completed( impl->IAsyncInfoImpl_inner, handler );
+}
+
+static HRESULT WINAPI async_inspectable_GetResults( IAsyncOperation_IInspectable *iface, IInspectable **results )
+{
+    struct async_inspectable *impl = impl_from_IAsyncOperation_IInspectable( iface );
+    PROPVARIANT result = {.vt = VT_UNKNOWN};
+    HRESULT hr;
+
+    TRACE( "iface %p, results %p.\n", iface, results );
+
+    if (SUCCEEDED(hr = IAsyncInfoImpl_get_Result( impl->IAsyncInfoImpl_inner, &result )))
+    {
+        if ((*results = (IInspectable *)result.punkVal)) IInspectable_AddRef( *results );
+        PropVariantClear( &result );
+    }
+
+    return hr;
+}
+
+static const struct IAsyncOperation_IInspectableVtbl async_inspectable_vtbl =
+{
+    /* IUnknown methods */
+    async_inspectable_QueryInterface,
+    async_inspectable_AddRef,
+    async_inspectable_Release,
+    /* IInspectable methods */
+    async_inspectable_GetIids,
+    async_inspectable_GetRuntimeClassName,
+    async_inspectable_GetTrustLevel,
+    /* IAsyncOperation<IInspectable> */
+    async_inspectable_put_Completed,
+    async_inspectable_get_Completed,
+    async_inspectable_GetResults,
+};
+
+HRESULT async_operation_inspectable_create( const GUID *iid, IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+                                            IAsyncOperation_IInspectable **out )
+{
+    struct async_inspectable *impl;
+    HRESULT hr;
+
+    *out = NULL;
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+    impl->IAsyncOperation_IInspectable_iface.lpVtbl = &async_inspectable_vtbl;
+    impl->ref = 1;
+    impl->iid = iid;
+
+    if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_IInspectable_iface, &impl->IAsyncInfoImpl_inner )) ||
+        FAILED(hr = IAsyncInfoImpl_Start( impl->IAsyncInfoImpl_inner )))
+    {
+        if (impl->IAsyncInfoImpl_inner) IAsyncInfoImpl_Release( impl->IAsyncInfoImpl_inner );
+        free( impl );
+        return hr;
+    }
+
+    *out = &impl->IAsyncOperation_IInspectable_iface;
+    TRACE( "created IAsyncOperation_IInspectable %p\n", *out );
+    return S_OK;
+}
+
+struct async_action
+{
+    IAsyncAction IAsyncAction_iface;
+    IAsyncInfoImpl *IAsyncInfoImpl_inner;
+    LONG ref;
+};
+
+static inline struct async_action *impl_from_IAsyncAction( IAsyncAction *iface )
+{
+    return CONTAINING_RECORD( iface, struct async_action, IAsyncAction_iface );
+}
+
+static HRESULT WINAPI async_action_QueryInterface( IAsyncAction *iface, REFIID iid, void **out )
+{
+    struct async_action *impl = impl_from_IAsyncAction( 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_IAsyncAction ))
+    {
+        IInspectable_AddRef( (*out = &impl->IAsyncAction_iface) );
+        return S_OK;
+    }
+
+    return IAsyncInfoImpl_QueryInterface( impl->IAsyncInfoImpl_inner, iid, out );
+}
+
+static ULONG WINAPI async_action_AddRef( IAsyncAction *iface )
+{
+    struct async_action *impl = impl_from_IAsyncAction( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI async_action_Release( IAsyncAction *iface )
+{
+    struct async_action *impl = impl_from_IAsyncAction( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        /* guard against re-entry if inner releases an outer iface */
+        InterlockedIncrement( &impl->ref );
+        IAsyncInfoImpl_Release( impl->IAsyncInfoImpl_inner );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI async_action_GetIids( IAsyncAction *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 async_action_GetRuntimeClassName( IAsyncAction *iface, HSTRING *class_name )
+{
+    return WindowsCreateString( L"Windows.Foundation.IAsyncOperation`1<Boolean>",
+                                ARRAY_SIZE(L"Windows.Foundation.IAsyncOperation`1<Boolean>"),
+                                class_name );
+}
+
+static HRESULT WINAPI async_action_GetTrustLevel( IAsyncAction *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI async_action_put_Completed( IAsyncAction *iface, IAsyncActionCompletedHandler *bool_handler )
+{
+    IAsyncOperationCompletedHandlerImpl *handler = (IAsyncOperationCompletedHandlerImpl *)bool_handler;
+    struct async_action *impl = impl_from_IAsyncAction( iface );
+    TRACE( "iface %p, handler %p.\n", iface, handler );
+    return IAsyncInfoImpl_put_Completed( impl->IAsyncInfoImpl_inner, handler );
+}
+
+static HRESULT WINAPI async_action_get_Completed( IAsyncAction *iface, IAsyncActionCompletedHandler **bool_handler )
+{
+    IAsyncOperationCompletedHandlerImpl **handler = (IAsyncOperationCompletedHandlerImpl **)bool_handler;
+    struct async_action *impl = impl_from_IAsyncAction( iface );
+    TRACE( "iface %p, handler %p.\n", iface, handler );
+    return IAsyncInfoImpl_get_Completed( impl->IAsyncInfoImpl_inner, handler );
+}
+
+static HRESULT WINAPI async_action_GetResults( IAsyncAction *iface )
+{
+    struct async_action *impl = impl_from_IAsyncAction( iface );
+    PROPVARIANT result;
+    HRESULT hr;
+
+    TRACE( "iface %p.\n", iface );
+
+    PropVariantInit( &result );
+    hr = IAsyncInfoImpl_get_Result( impl->IAsyncInfoImpl_inner, &result );
+    PropVariantClear( &result );
+    return hr;
+}
+
+static const struct IAsyncActionVtbl async_action_vtbl =
+{
+    /* IUnknown methods */
+    async_action_QueryInterface,
+    async_action_AddRef,
+    async_action_Release,
+    /* IInspectable methods */
+    async_action_GetIids,
+    async_action_GetRuntimeClassName,
+    async_action_GetTrustLevel,
+    /* IAsyncOperation<boolean> */
+    async_action_put_Completed,
+    async_action_get_Completed,
+    async_action_GetResults,
+};
+
+HRESULT async_action_create( IUnknown *invoker, async_operation_callback callback, IAsyncAction **out )
+{
+    struct async_action *impl;
+    HRESULT hr;
+
+    *out = NULL;
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+    impl->IAsyncAction_iface.lpVtbl = &async_action_vtbl;
+    impl->ref = 1;
+
+    if (FAILED(hr = async_info_create( invoker, NULL, callback, (IInspectable *)&impl->IAsyncAction_iface, &impl->IAsyncInfoImpl_inner )) ||
+        FAILED(hr = IAsyncInfoImpl_Start( impl->IAsyncInfoImpl_inner )))
+    {
+        if (impl->IAsyncInfoImpl_inner) IAsyncInfoImpl_Release( impl->IAsyncInfoImpl_inner );
+        free( impl );
+        return hr;
+    }
+
+    *out = &impl->IAsyncAction_iface;
+    TRACE( "created IAsyncAction %p\n", *out );
+    return S_OK;
+}
diff --git a/dlls/windows.devices.radios/async_private.idl b/dlls/windows.devices.radios/async_private.idl
new file mode 100644
index 000000000000..40ea63ca4c10
--- /dev/null
+++ b/dlls/windows.devices.radios/async_private.idl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2022 Rémi Bernon 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
+ */
+
+#pragma makedep header
+
+#ifdef __WIDL__
+#pragma winrt ns_prefix
+#endif
+
+import "propidl.idl";
+import "inspectable.idl";
+import "asyncinfo.idl";
+import "windowscontracts.idl";
+
+namespace Wine.Internal {
+    /* type-pruning version of AsyncOperationCompletedHandlerImpl<T> */
+    delegate HRESULT AsyncOperationCompletedHandlerImpl([in] IInspectable *async, [in] AsyncStatus status);
+
+    [
+        uuid(d81ab70d-82e0-481c-983d-401225d98a2c)
+    ]
+    interface IAsyncInfoImpl : IUnknown
+    {
+        [propput] HRESULT Completed([in] AsyncOperationCompletedHandlerImpl *handler);
+        [propget] HRESULT Completed([out, retval] AsyncOperationCompletedHandlerImpl **handler);
+        [propget] HRESULT Result([out, retval] PROPVARIANT *result);
+        HRESULT Start();
+    }
+
+    typedef HRESULT (*async_operation_callback)( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async );
+}
diff --git a/dlls/windows.devices.radios/classes.idl b/dlls/windows.devices.radios/classes.idl
new file mode 100644
index 000000000000..c3cfaabbf699
--- /dev/null
+++ b/dlls/windows.devices.radios/classes.idl
@@ -0,0 +1,28 @@
+/*
+ * Runtime Classes for windows.devices.radios.dll
+ *
+ * Copyright (C) 2026 Mohamad Al-Jaf
+ *
+ * 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
+ */
+
+#pragma makedep register
+#pragma winrt ns_prefix
+
+import "windows.devices.radios.idl";
+
+namespace Windows.Devices.Radios {
+    runtimeclass Radio;
+}
diff --git a/dlls/windows.devices.radios/main.c b/dlls/windows.devices.radios/main.c
new file mode 100644
index 000000000000..686853d8f579
--- /dev/null
+++ b/dlls/windows.devices.radios/main.c
@@ -0,0 +1,220 @@
+/* WinRT Windows.Devices.Radios Implementation
+ *
+ * Copyright (C) 2026 Mohamad Al-Jaf
+ *
+ * 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 "initguid.h"
+#include "private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(radios);
+
+struct radio_statics
+{
+    IActivationFactory IActivationFactory_iface;
+    IRadioStatics IRadioStatics_iface;
+    LONG ref;
+};
+
+static inline struct radio_statics *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+    return CONTAINING_RECORD( iface, struct radio_statics, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+    struct radio_statics *impl = impl_from_IActivationFactory( 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_IActivationFactory ))
+    {
+        *out = &impl->IActivationFactory_iface;
+        IInspectable_AddRef( *out );
+        return S_OK;
+    }
+
+    if (IsEqualGUID( iid, &IID_IRadioStatics ))
+    {
+        *out = &impl->IRadioStatics_iface;
+        IInspectable_AddRef( *out );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI factory_AddRef( IActivationFactory *iface )
+{
+    struct radio_statics *impl = impl_from_IActivationFactory( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI factory_Release( IActivationFactory *iface )
+{
+    struct radio_statics *impl = impl_from_IActivationFactory( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+    TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static HRESULT WINAPI factory_GetIids( IActivationFactory *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 factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+    FIXME( "iface %p, instance %p stub!\n", iface, instance );
+    return E_NOTIMPL;
+}
+
+static const struct IActivationFactoryVtbl factory_vtbl =
+{
+    /* IUnknown methods */
+    factory_QueryInterface,
+    factory_AddRef,
+    factory_Release,
+    /* IInspectable methods */
+    factory_GetIids,
+    factory_GetRuntimeClassName,
+    factory_GetTrustLevel,
+    /* IActivationFactory methods */
+    factory_ActivateInstance,
+};
+
+DEFINE_IINSPECTABLE( radio_statics, IRadioStatics, struct radio_statics, IActivationFactory_iface )
+
+static HRESULT get_radios_async( IUnknown *invoker, IUnknown *param, PROPVARIANT *result, BOOL called_async )
+{
+    struct vector_iids iids =
+    {
+        .iterable = &IID_IIterable_Radio,
+        .iterator = &IID_IIterator_Radio,
+        .vector = &IID_IVector_IInspectable,
+        .view = &IID_IVectorView_Radio,
+    };
+    IVector_IInspectable *vector;
+    IVectorView_Radio *view;
+    HRESULT hr;
+
+    FIXME( "stub!\n" );
+
+    if (FAILED(hr = vector_create( &iids, (void **)&vector ))) return hr;
+
+    hr = IVector_IInspectable_GetView( vector, (IVectorView_IInspectable **)&view );
+    IVector_IInspectable_Release( vector );
+    if (FAILED(hr)) return hr;
+
+    result->vt = VT_UNKNOWN;
+    result->punkVal = (IUnknown *)view;
+    return S_OK;
+}
+
+static HRESULT WINAPI radio_statics_GetRadiosAsync( IRadioStatics *iface, IAsyncOperation_IVectorView_Radio **value )
+{
+    TRACE( "iface %p, value %p\n", iface, value );
+
+    if (!value) return E_POINTER;
+    return async_operation_inspectable_create( &IID_IAsyncOperation_IVectorView_Radio, NULL, NULL, get_radios_async, (IAsyncOperation_IInspectable **)value );
+}
+
+static HRESULT WINAPI radio_statics_GetDeviceSelector( IRadioStatics *iface, HSTRING *selector )
+{
+    FIXME( "iface %p, selector %p stub!\n", iface, selector );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI radio_statics_FromIdAsync( IRadioStatics *iface, HSTRING id, IAsyncOperation_Radio **value )
+{
+    FIXME( "iface %p, id %s, value %p stub!\n", iface, debugstr_hstring( id ), value );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI radio_statics_RequestAccessAsync( IRadioStatics *iface, IAsyncOperation_RadioAccessStatus **value )
+{
+    FIXME( "iface %p, value %p stub!\n", iface, value );
+    return E_NOTIMPL;
+}
+
+static const struct IRadioStaticsVtbl radio_statics_vtbl =
+{
+    /* IUnknown methods */
+    radio_statics_QueryInterface,
+    radio_statics_AddRef,
+    radio_statics_Release,
+    /* IInspectable methods */
+    radio_statics_GetIids,
+    radio_statics_GetRuntimeClassName,
+    radio_statics_GetTrustLevel,
+    /* IRadioStatics methods */
+    radio_statics_GetRadiosAsync,
+    radio_statics_GetDeviceSelector,
+    radio_statics_FromIdAsync,
+    radio_statics_RequestAccessAsync,
+};
+
+static struct radio_statics radio_statics =
+{
+    {&factory_vtbl},
+    {&radio_statics_vtbl},
+    1,
+};
+
+static IActivationFactory *radio_factory = &radio_statics.IActivationFactory_iface;
+
+HRESULT WINAPI DllGetClassObject( REFCLSID clsid, REFIID riid, void **out )
+{
+    FIXME( "clsid %s, riid %s, out %p stub!\n", debugstr_guid( clsid ), debugstr_guid( riid ), out );
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **factory )
+{
+    const WCHAR *buffer = WindowsGetStringRawBuffer( classid, NULL );
+
+    TRACE( "class %s, factory %p.\n", debugstr_hstring( classid ), factory );
+
+    *factory = NULL;
+
+    if (!wcscmp( buffer, RuntimeClass_Windows_Devices_Radios_Radio ))
+        IActivationFactory_QueryInterface( radio_factory, &IID_IActivationFactory, (void **)factory );
+
+    if (*factory) return S_OK;
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
diff --git a/dlls/windows.devices.radios/private.h b/dlls/windows.devices.radios/private.h
new file mode 100644
index 000000000000..edd505e8a74c
--- /dev/null
+++ b/dlls/windows.devices.radios/private.h
@@ -0,0 +1,92 @@
+/* WinRT Windows.Devices.Radios Implementation
+ *
+ * Copyright (C) 2026 Mohamad Al-Jaf
+ *
+ * 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 __WINE_WINDOWS_DEVICES_RADIOS_PRIVATE_H
+#define __WINE_WINDOWS_DEVICES_RADIOS_PRIVATE_H
+
+#include <stdarg.h>
+
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+#include "winstring.h"
+
+#include "activation.h"
+
+#define WIDL_using_Windows_Foundation
+#define WIDL_using_Windows_Foundation_Collections
+#include "windows.foundation.h"
+#define WIDL_using_Windows_Devices_Radios
+#include "windows.devices.radios.h"
+
+#include "async_private.h"
+
+struct vector_iids
+{
+    const GUID *vector;
+    const GUID *view;
+    const GUID *iterable;
+    const GUID *iterator;
+};
+extern HRESULT vector_create( const struct vector_iids *iids, void **out );
+
+extern HRESULT async_operation_inspectable_create( const GUID *iid, IUnknown *invoker, IUnknown *param, async_operation_callback callback,
+                                                   IAsyncOperation_IInspectable **out );
+
+#define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr )             \
+    static inline impl_type *impl_from( iface_type *iface )                                        \
+    {                                                                                              \
+        return CONTAINING_RECORD( iface, impl_type, iface_mem );                                   \
+    }                                                                                              \
+    static HRESULT WINAPI pfx##_QueryInterface( iface_type *iface, REFIID iid, void **out )        \
+    {                                                                                              \
+        impl_type *impl = impl_from( iface );                                                      \
+        return IInspectable_QueryInterface( (IInspectable *)(expr), iid, out );                    \
+    }                                                                                              \
+    static ULONG WINAPI pfx##_AddRef( iface_type *iface )                                          \
+    {                                                                                              \
+        impl_type *impl = impl_from( iface );                                                      \
+        return IInspectable_AddRef( (IInspectable *)(expr) );                                      \
+    }                                                                                              \
+    static ULONG WINAPI pfx##_Release( iface_type *iface )                                         \
+    {                                                                                              \
+        impl_type *impl = impl_from( iface );                                                      \
+        return IInspectable_Release( (IInspectable *)(expr) );                                     \
+    }                                                                                              \
+    static HRESULT WINAPI pfx##_GetIids( iface_type *iface, ULONG *iid_count, IID **iids )         \
+    {                                                                                              \
+        impl_type *impl = impl_from( iface );                                                      \
+        return IInspectable_GetIids( (IInspectable *)(expr), iid_count, iids );                    \
+    }                                                                                              \
+    static HRESULT WINAPI pfx##_GetRuntimeClassName( iface_type *iface, HSTRING *class_name )      \
+    {                                                                                              \
+        impl_type *impl = impl_from( iface );                                                      \
+        return IInspectable_GetRuntimeClassName( (IInspectable *)(expr), class_name );             \
+    }                                                                                              \
+    static HRESULT WINAPI pfx##_GetTrustLevel( iface_type *iface, TrustLevel *trust_level )        \
+    {                                                                                              \
+        impl_type *impl = impl_from( iface );                                                      \
+        return IInspectable_GetTrustLevel( (IInspectable *)(expr), trust_level );                  \
+    }
+#define DEFINE_IINSPECTABLE( pfx, iface_type, impl_type, base_iface )                              \
+    DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, &impl->base_iface )
+#define DEFINE_IINSPECTABLE_OUTER( pfx, iface_type, impl_type, outer_iface )                       \
+    DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from_##iface_type, iface_type##_iface, impl->outer_iface )
+
+#endif
diff --git a/dlls/windows.devices.radios/tests/Makefile.in b/dlls/windows.devices.radios/tests/Makefile.in
new file mode 100644
index 000000000000..cfe4d78608c6
--- /dev/null
+++ b/dlls/windows.devices.radios/tests/Makefile.in
@@ -0,0 +1,5 @@
+TESTDLL = windows.devices.radios.dll
+IMPORTS = combase
+
+SOURCES = \
+	radios.c
diff --git a/dlls/windows.devices.radios/tests/radios.c b/dlls/windows.devices.radios/tests/radios.c
new file mode 100644
index 000000000000..1580fd5860e6
--- /dev/null
+++ b/dlls/windows.devices.radios/tests/radios.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2026 Mohamad Al-Jaf
+ *
+ * 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 "initguid.h"
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winstring.h"
+
+#include "roapi.h"
+
+#define WIDL_using_Windows_Foundation
+#define WIDL_using_Windows_Foundation_Collections
+#include "windows.foundation.h"
+#define WIDL_using_Windows_Devices_Radios
+#include "windows.devices.radios.h"
+
+#include "wine/test.h"
+
+static HRESULT (WINAPI *pWindowsDeleteString)( HSTRING str );
+static const WCHAR* (WINAPI *pWindowsGetStringRawBuffer)( HSTRING, UINT32* );
+
+static BOOL load_combase_functions(void)
+{
+    HMODULE combase = GetModuleHandleW( L"combase.dll" );
+
+#define LOAD_FUNC(m, f) if (!(p ## f = (void *)GetProcAddress( m, #f ))) goto failed;
+    LOAD_FUNC( combase, WindowsDeleteString );
+    LOAD_FUNC( combase, WindowsGetStringRawBuffer );
+#undef LOAD_FUNC
+
+    return TRUE;
+
+failed:
+    win_skip("Failed to load combase.dll functions, skipping tests\n");
+    return FALSE;
+}
+
+#define check_interface( obj, iid ) check_interface_( __LINE__, obj, iid )
+static void check_interface_( unsigned int line, void *obj, const IID *iid )
+{
+    IUnknown *iface = obj;
+    IUnknown *unk;
+    HRESULT hr;
+
+    hr = IUnknown_QueryInterface( iface, iid, (void **)&unk );
+    ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr );
+    IUnknown_Release( unk );
+}
+
+#define check_runtimeclass( a, b ) check_runtimeclass_( __LINE__, (IInspectable *)a, b )
+static void check_runtimeclass_( int line, IInspectable *inspectable, const WCHAR *class_name )
+{
+    const WCHAR *buffer;
+    UINT32 length;
+    HSTRING str;
+    HRESULT hr;
+
+    hr = IInspectable_GetRuntimeClassName( inspectable, &str );
+    ok_(__FILE__, line)( hr == S_OK, "GetRuntimeClassName returned %#lx\n", hr );
+    buffer = pWindowsGetStringRawBuffer( str, &length );
+    todo_wine
+    ok_(__FILE__, line)( !wcscmp( buffer, class_name ), "got class name %s\n", debugstr_w(buffer) );
+    pWindowsDeleteString( str );
+}
+
+#define check_vectorview_radio_async( a, b, c, d ) check_vectorview_radio_async_( __LINE__, a, b, c, d )
+static void check_vectorview_radio_async_( int line, IAsyncOperation_IVectorView_Radio *async, UINT32 expect_id, AsyncStatus expect_status, HRESULT expect_hr )
+{
+    IVectorView_Radio *result;
+    AsyncStatus async_status;
+    IAsyncInfo *async_info;
+    HRESULT hr, async_hr;
+    UINT32 async_id;
+
+    hr = IAsyncOperation_IVectorView_Radio_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 == expect_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 || broken( async_status == Error ), "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 || broken( async_hr == E_INVALIDARG), "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 );
+
+    hr = IAsyncOperation_IVectorView_Radio_GetResults( async, &result );
+    switch (expect_status)
+    {
+    case Completed:
+    case Error:
+        todo_wine_if(FAILED(expect_hr))
+        ok_(__FILE__, line)( hr == expect_hr, "GetResults returned %#lx\n", hr );
+        ok_(__FILE__, line)( result != NULL, "failed to get result\n" );
+
+        if (result)
+        {
+            UINT32 size = 0xdeadbeef;
+
+            hr = IVectorView_Radio_get_Size( result, &size );
+            ok_(__FILE__, line)( hr == S_OK, "IVectorView_Radio_get_Size returned %#lx\n", hr );
+            ok_(__FILE__, line)( size != 0xdeadbeef, "failed to get size\n" );
+        }
+        break;
+    case Canceled:
+    case Started:
+    default:
+        ok_(__FILE__, line)( hr == E_ILLEGAL_METHOD_CALL, "GetResults returned %#lx\n", hr );
+        break;
+    }
+}
+
+struct vectorview_radio_async_handler
+{
+    IAsyncOperationCompletedHandler_IVectorView_Radio IAsyncOperationCompletedHandler_IVectorView_Radio_iface;
+    IAsyncOperation_IVectorView_Radio *async;
+    AsyncStatus status;
+    BOOL invoked;
+    HANDLE event;
+};
+
+static inline struct vectorview_radio_async_handler *impl_from_IAsyncOperationCompletedHandler_IVectorView_Radio(
+    IAsyncOperationCompletedHandler_IVectorView_Radio *iface )
+{
+    return CONTAINING_RECORD( iface, struct vectorview_radio_async_handler, IAsyncOperationCompletedHandler_IVectorView_Radio_iface );
+}
+
+static HRESULT WINAPI vectorview_radio_async_handler_QueryInterface( IAsyncOperationCompletedHandler_IVectorView_Radio *iface, REFIID iid, void **out )
+{
+    if (IsEqualGUID( iid, &IID_IUnknown ) ||
+        IsEqualGUID( iid, &IID_IAgileObject ) ||
+        IsEqualGUID( iid, &IID_IAsyncOperationCompletedHandler_IVectorView_Radio ))
+    {
+        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 vectorview_radio_async_handler_AddRef( IAsyncOperationCompletedHandler_IVectorView_Radio *iface )
+{
+    return 2;
+}
+
+static ULONG WINAPI vectorview_radio_async_handler_Release( IAsyncOperationCompletedHandler_IVectorView_Radio *iface )
+{
+    return 1;
+}
+
+static HRESULT WINAPI vectorview_radio_async_handler_Invoke( IAsyncOperationCompletedHandler_IVectorView_Radio *iface,
+                                                             IAsyncOperation_IVectorView_Radio *async, AsyncStatus status )
+{
+    struct vectorview_radio_async_handler *impl = impl_from_IAsyncOperationCompletedHandler_IVectorView_Radio( iface );
+
+    trace( "iface %p, async %p, status %u\n", iface, async, status );
+
+    ok( !impl->invoked, "invoked twice\n" );
+    impl->invoked = TRUE;
+    impl->async = async;
+    impl->status = status;
+    if (impl->event) SetEvent( impl->event );
+
+    return S_OK;
+}
+
+static IAsyncOperationCompletedHandler_IVectorView_RadioVtbl vectorview_radio_async_handler_vtbl =
+{
+    /*** IUnknown methods ***/
+    vectorview_radio_async_handler_QueryInterface,
+    vectorview_radio_async_handler_AddRef,
+    vectorview_radio_async_handler_Release,
+    /*** IAsyncOperationCompletedHandler<IAsyncOperationCompletedHandler_IVectorView_Radio> methods ***/
+    vectorview_radio_async_handler_Invoke,
+};
+
+static struct vectorview_radio_async_handler default_vectorview_radio_async_handler = {{&vectorview_radio_async_handler_vtbl}};
+
+static void test_RadioStatics(void)
+{
+    IAsyncOperationCompletedHandler_IVectorView_Radio *tmp_handler = (void *)0xdeadbeef;
+    static const WCHAR *radio_statics_name = L"Windows.Devices.Radios.Radio";
+    struct vectorview_radio_async_handler vectorview_radio_async_handler;
+    IAsyncOperation_IVectorView_Radio *operation = (void *)0xdeadbeef;
+    IRadioStatics *radio_statics = (void *)0xdeadbeef;
+    IActivationFactory *factory = (void *)0xdeadbeef;
+    IAsyncInfo *async_info = (void *)0xdeadbeef;
+    HSTRING str;
+    HRESULT hr;
+    DWORD ret;
+
+    if (!load_combase_functions()) return;
+
+    hr = WindowsCreateString( radio_statics_name, wcslen( radio_statics_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( radio_statics_name ) );
+        return;
+    }
+
+    check_interface( factory, &IID_IUnknown );
+    check_interface( factory, &IID_IInspectable );
+    check_interface( factory, &IID_IAgileObject );
+
+    hr = IActivationFactory_QueryInterface( factory, &IID_IRadioStatics, (void **)&radio_statics );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+
+    hr = IRadioStatics_GetRadiosAsync( radio_statics, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IRadioStatics_GetRadiosAsync( radio_statics, &operation );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+
+    check_interface( operation, &IID_IUnknown );
+    check_interface( operation, &IID_IInspectable );
+    check_interface( operation, &IID_IAgileObject );
+    check_interface( operation, &IID_IAsyncInfo );
+    check_interface( operation, &IID_IAsyncOperation_IVectorView_Radio );
+    check_runtimeclass( operation, L"Windows.Foundation.IAsyncOperation`1<Windows.Foundation.Collections.IVectorView`1<Windows.Devices.Radios.Radio>>" );
+
+    hr = IAsyncOperation_IVectorView_Radio_get_Completed( operation, &tmp_handler );
+    ok( hr == S_OK, "get_Completed returned %#lx\n", hr );
+    ok( tmp_handler == NULL, "got handler %p\n", tmp_handler );
+    vectorview_radio_async_handler = default_vectorview_radio_async_handler;
+    vectorview_radio_async_handler.event = CreateEventW( NULL, FALSE, FALSE, NULL );
+    hr = IAsyncOperation_IVectorView_Radio_put_Completed( operation, &vectorview_radio_async_handler.IAsyncOperationCompletedHandler_IVectorView_Radio_iface );
+    ok( hr == S_OK, "put_Completed returned %#lx\n", hr );
+    ret = WaitForSingleObject( vectorview_radio_async_handler.event, 1000 );
+    ok( !ret, "WaitForSingleObject returned %#lx\n", ret );
+    ret = CloseHandle( vectorview_radio_async_handler.event );
+    ok( ret, "CloseHandle failed, error %lu\n", GetLastError() );
+    ok( vectorview_radio_async_handler.invoked, "handler not invoked\n" );
+    ok( vectorview_radio_async_handler.async == operation, "got async %p\n", vectorview_radio_async_handler.async );
+    ok( vectorview_radio_async_handler.status == Completed, "got status %u\n", vectorview_radio_async_handler.status );
+    vectorview_radio_async_handler = default_vectorview_radio_async_handler;
+    hr = IAsyncOperation_IVectorView_Radio_put_Completed( operation, &vectorview_radio_async_handler.IAsyncOperationCompletedHandler_IVectorView_Radio_iface );
+    ok( hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "put_Completed returned %#lx\n", hr );
+    ok( !vectorview_radio_async_handler.invoked, "handler invoked\n" );
+    ok( vectorview_radio_async_handler.async == NULL, "got async %p\n", vectorview_radio_async_handler.async );
+    ok( vectorview_radio_async_handler.status == Started, "got status %u\n", vectorview_radio_async_handler.status );
+
+    hr = IAsyncOperation_IVectorView_Radio_QueryInterface( operation, &IID_IAsyncInfo, (void **)&async_info );
+    ok( hr == S_OK, "QueryInterface returned %#lx\n", hr );
+    hr = IAsyncInfo_Cancel( async_info );
+    ok( hr == S_OK, "Cancel returned %#lx\n", hr );
+    check_vectorview_radio_async( operation, 1, Completed, S_OK );
+    hr = IAsyncInfo_Close( async_info );
+    ok( hr == S_OK, "Close returned %#lx\n", hr );
+    check_vectorview_radio_async( operation, 1, 4, S_OK );
+
+    IAsyncInfo_Release( async_info );
+    IAsyncOperation_IVectorView_Radio_Release( operation );
+    IRadioStatics_Release( radio_statics );
+    IActivationFactory_Release( factory );
+}
+
+START_TEST(radios)
+{
+    HRESULT hr;
+
+    hr = RoInitialize( RO_INIT_MULTITHREADED );
+    ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr );
+
+    test_RadioStatics();
+
+    RoUninitialize();
+}
diff --git a/dlls/windows.devices.radios/vector.c b/dlls/windows.devices.radios/vector.c
new file mode 100644
index 000000000000..5053b1c10bb2
--- /dev/null
+++ b/dlls/windows.devices.radios/vector.c
@@ -0,0 +1,675 @@
+/* DeviceInformationCollection implementation
+ *
+ * Copyright 2021 Rémi Bernon 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 "private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(combase);
+
+struct iterator
+{
+    IIterator_IInspectable IIterator_IInspectable_iface;
+    const GUID *iid;
+    LONG ref;
+
+    IVectorView_IInspectable *view;
+    UINT32 index;
+    UINT32 size;
+};
+
+static inline struct iterator *impl_from_IIterator_IInspectable( IIterator_IInspectable *iface )
+{
+    return CONTAINING_RECORD( iface, struct iterator, IIterator_IInspectable_iface );
+}
+
+static HRESULT WINAPI iterator_QueryInterface( IIterator_IInspectable *iface, REFIID iid, void **out )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( 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, impl->iid ))
+    {
+        IInspectable_AddRef( (*out = &impl->IIterator_IInspectable_iface) );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI iterator_AddRef( IIterator_IInspectable *iface )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI iterator_Release( IIterator_IInspectable *iface )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+
+    TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        IVectorView_IInspectable_Release( impl->view );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI iterator_GetIids( IIterator_IInspectable *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 iterator_GetRuntimeClassName( IIterator_IInspectable *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI iterator_GetTrustLevel( IIterator_IInspectable *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI iterator_get_Current( IIterator_IInspectable *iface, IInspectable **value )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( iface );
+    TRACE( "iface %p, value %p.\n", iface, value );
+    return IVectorView_IInspectable_GetAt( impl->view, impl->index, value );
+}
+
+static HRESULT WINAPI iterator_get_HasCurrent( IIterator_IInspectable *iface, boolean *value )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( iface );
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    *value = impl->index < impl->size;
+    return S_OK;
+}
+
+static HRESULT WINAPI iterator_MoveNext( IIterator_IInspectable *iface, boolean *value )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( iface );
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (impl->index < impl->size) impl->index++;
+    return IIterator_IInspectable_get_HasCurrent( iface, value );
+}
+
+static HRESULT WINAPI iterator_GetMany( IIterator_IInspectable *iface, UINT32 items_size,
+                                        IInspectable **items, UINT *count )
+{
+    struct iterator *impl = impl_from_IIterator_IInspectable( iface );
+    TRACE( "iface %p, items_size %u, items %p, count %p.\n", iface, items_size, items, count );
+    return IVectorView_IInspectable_GetMany( impl->view, impl->index, items_size, items, count );
+}
+
+static const IIterator_IInspectableVtbl iterator_vtbl =
+{
+    iterator_QueryInterface,
+    iterator_AddRef,
+    iterator_Release,
+    /* IInspectable methods */
+    iterator_GetIids,
+    iterator_GetRuntimeClassName,
+    iterator_GetTrustLevel,
+    /* IIterator<IInspectable*> methods */
+    iterator_get_Current,
+    iterator_get_HasCurrent,
+    iterator_MoveNext,
+    iterator_GetMany,
+};
+
+struct vector_view
+{
+    IVectorView_IInspectable IVectorView_IInspectable_iface;
+    IIterable_IInspectable IIterable_IInspectable_iface;
+    struct vector_iids iids;
+    LONG ref;
+
+    UINT32 size;
+    IInspectable *elements[1];
+};
+
+static inline struct vector_view *impl_from_IVectorView_IInspectable( IVectorView_IInspectable *iface )
+{
+    return CONTAINING_RECORD( iface, struct vector_view, IVectorView_IInspectable_iface );
+}
+
+static HRESULT WINAPI vector_view_QueryInterface( IVectorView_IInspectable *iface, REFIID iid, void **out )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( 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, impl->iids.view ))
+    {
+        IInspectable_AddRef( (*out = &impl->IVectorView_IInspectable_iface) );
+        return S_OK;
+    }
+
+    if (IsEqualGUID( iid, impl->iids.iterable ))
+    {
+        IInspectable_AddRef( (*out = &impl->IIterable_IInspectable_iface) );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI vector_view_AddRef( IVectorView_IInspectable *iface )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI vector_view_Release( IVectorView_IInspectable *iface )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( iface );
+    ULONG i, ref = InterlockedDecrement( &impl->ref );
+
+    TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        for (i = 0; i < impl->size; ++i) IInspectable_Release( impl->elements[i] );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI vector_view_GetIids( IVectorView_IInspectable *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 vector_view_GetRuntimeClassName( IVectorView_IInspectable *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI vector_view_GetTrustLevel( IVectorView_IInspectable *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI vector_view_GetAt( IVectorView_IInspectable *iface, UINT32 index, IInspectable **value )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( iface );
+
+    TRACE( "iface %p, index %u, value %p.\n", iface, index, value );
+
+    *value = NULL;
+    if (index >= impl->size) return E_BOUNDS;
+
+    IInspectable_AddRef( (*value = impl->elements[index]) );
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_view_get_Size( IVectorView_IInspectable *iface, UINT32 *value )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( iface );
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    *value = impl->size;
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_view_IndexOf( IVectorView_IInspectable *iface, IInspectable *element,
+                                           UINT32 *index, BOOLEAN *found )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( iface );
+    ULONG i;
+
+    TRACE( "iface %p, element %p, index %p, found %p.\n", iface, element, index, found );
+
+    for (i = 0; i < impl->size; ++i) if (impl->elements[i] == element) break;
+    if ((*found = (i < impl->size))) *index = i;
+    else *index = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_view_GetMany( IVectorView_IInspectable *iface, UINT32 start_index,
+                                           UINT32 items_size, IInspectable **items, UINT *count )
+{
+    struct vector_view *impl = impl_from_IVectorView_IInspectable( iface );
+    UINT32 i;
+
+    TRACE( "iface %p, start_index %u, items_size %u, items %p, count %p.\n",
+           iface, start_index, items_size, items, count );
+
+    if (start_index >= impl->size) return E_BOUNDS;
+
+    for (i = start_index; i < impl->size; ++i)
+    {
+        if (i - start_index >= items_size) break;
+        IInspectable_AddRef( (items[i - start_index] = impl->elements[i]) );
+    }
+    *count = i - start_index;
+
+    return S_OK;
+}
+
+static const struct IVectorView_IInspectableVtbl vector_view_vtbl =
+{
+    vector_view_QueryInterface,
+    vector_view_AddRef,
+    vector_view_Release,
+    /* IInspectable methods */
+    vector_view_GetIids,
+    vector_view_GetRuntimeClassName,
+    vector_view_GetTrustLevel,
+    /* IVectorView<IInspectable*> methods */
+    vector_view_GetAt,
+    vector_view_get_Size,
+    vector_view_IndexOf,
+    vector_view_GetMany,
+};
+
+DEFINE_IINSPECTABLE_( iterable_view, IIterable_IInspectable, struct vector_view, view_impl_from_IIterable_IInspectable,
+                      IIterable_IInspectable_iface, &impl->IVectorView_IInspectable_iface )
+
+static HRESULT WINAPI iterable_view_First( IIterable_IInspectable *iface, IIterator_IInspectable **value )
+{
+    struct vector_view *impl = view_impl_from_IIterable_IInspectable( iface );
+    struct iterator *iter;
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (!(iter = calloc( 1, sizeof(struct iterator) ))) return E_OUTOFMEMORY;
+    iter->IIterator_IInspectable_iface.lpVtbl = &iterator_vtbl;
+    iter->iid = impl->iids.iterator;
+    iter->ref = 1;
+
+    IVectorView_IInspectable_AddRef( (iter->view = &impl->IVectorView_IInspectable_iface) );
+    iter->size = impl->size;
+
+    *value = &iter->IIterator_IInspectable_iface;
+    return S_OK;
+}
+
+static const struct IIterable_IInspectableVtbl iterable_view_vtbl =
+{
+    iterable_view_QueryInterface,
+    iterable_view_AddRef,
+    iterable_view_Release,
+    /* IInspectable methods */
+    iterable_view_GetIids,
+    iterable_view_GetRuntimeClassName,
+    iterable_view_GetTrustLevel,
+    /* IIterable<T> methods */
+    iterable_view_First,
+};
+
+struct vector
+{
+    IVector_IInspectable IVector_IInspectable_iface;
+    IIterable_IInspectable IIterable_IInspectable_iface;
+    struct vector_iids iids;
+    LONG ref;
+
+    UINT32 size;
+    UINT32 capacity;
+    IInspectable **elements;
+};
+
+static inline struct vector *impl_from_IVector_IInspectable( IVector_IInspectable *iface )
+{
+    return CONTAINING_RECORD( iface, struct vector, IVector_IInspectable_iface );
+}
+
+static HRESULT WINAPI vector_QueryInterface( IVector_IInspectable *iface, REFIID iid, void **out )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( 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, impl->iids.vector ))
+    {
+        IInspectable_AddRef( (*out = &impl->IVector_IInspectable_iface) );
+        return S_OK;
+    }
+
+    if (IsEqualGUID( iid, impl->iids.iterable ))
+    {
+        IInspectable_AddRef( (*out = &impl->IIterable_IInspectable_iface) );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI vector_AddRef( IVector_IInspectable *iface )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p increasing refcount to %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI vector_Release( IVector_IInspectable *iface )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+
+    TRACE( "iface %p decreasing refcount to %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        IVector_IInspectable_Clear( iface );
+        free( impl );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI vector_GetIids( IVector_IInspectable *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 vector_GetRuntimeClassName( IVector_IInspectable *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI vector_GetTrustLevel( IVector_IInspectable *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI vector_GetAt( IVector_IInspectable *iface, UINT32 index, IInspectable **value )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+
+    TRACE( "iface %p, index %u, value %p.\n", iface, index, value );
+
+    *value = NULL;
+    if (index >= impl->size) return E_BOUNDS;
+
+    IInspectable_AddRef( (*value = impl->elements[index]) );
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_get_Size( IVector_IInspectable *iface, UINT32 *value )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    TRACE( "iface %p, value %p.\n", iface, value );
+    *value = impl->size;
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_GetView( IVector_IInspectable *iface, IVectorView_IInspectable **value )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    struct vector_view *view;
+    ULONG i;
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (!(view = calloc( 1, offsetof( struct vector_view, elements[impl->size] ) ))) return E_OUTOFMEMORY;
+    view->IVectorView_IInspectable_iface.lpVtbl = &vector_view_vtbl;
+    view->IIterable_IInspectable_iface.lpVtbl = &iterable_view_vtbl;
+    view->iids = impl->iids;
+    view->ref = 1;
+
+    for (i = 0; i < impl->size; ++i) IInspectable_AddRef( (view->elements[view->size++] = impl->elements[i]) );
+
+    *value = &view->IVectorView_IInspectable_iface;
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_IndexOf( IVector_IInspectable *iface, IInspectable *element, UINT32 *index, BOOLEAN *found )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    ULONG i;
+
+    TRACE( "iface %p, element %p, index %p, found %p.\n", iface, element, index, found );
+
+    for (i = 0; i < impl->size; ++i) if (impl->elements[i] == element) break;
+    if ((*found = (i < impl->size))) *index = i;
+    else *index = 0;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_SetAt( IVector_IInspectable *iface, UINT32 index, IInspectable *value )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+
+    TRACE( "iface %p, index %u, value %p.\n", iface, index, value );
+
+    if (index >= impl->size) return E_BOUNDS;
+    IInspectable_Release( impl->elements[index] );
+    IInspectable_AddRef( (impl->elements[index] = value) );
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_InsertAt( IVector_IInspectable *iface, UINT32 index, IInspectable *value )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    IInspectable **tmp = impl->elements;
+
+    TRACE( "iface %p, index %u, value %p.\n", iface, index, value );
+
+    if (impl->size == impl->capacity)
+    {
+        impl->capacity = max( 32, impl->capacity * 3 / 2 );
+        if (!(impl->elements = realloc( impl->elements, impl->capacity * sizeof(*impl->elements) )))
+        {
+            impl->elements = tmp;
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    memmove( impl->elements + index + 1, impl->elements + index, (impl->size++ - index) * sizeof(*impl->elements) );
+    IInspectable_AddRef( (impl->elements[index] = value) );
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_RemoveAt( IVector_IInspectable *iface, UINT32 index )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+
+    TRACE( "iface %p, index %u.\n", iface, index );
+
+    if (index >= impl->size) return E_BOUNDS;
+    IInspectable_Release( impl->elements[index] );
+    memmove( impl->elements + index, impl->elements + index + 1, (--impl->size - index) * sizeof(*impl->elements) );
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_Append( IVector_IInspectable *iface, IInspectable *value )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    return IVector_IInspectable_InsertAt( iface, impl->size, value );
+}
+
+static HRESULT WINAPI vector_RemoveAtEnd( IVector_IInspectable *iface )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+
+    TRACE( "iface %p.\n", iface );
+
+    if (impl->size) IInspectable_Release( impl->elements[--impl->size] );
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_Clear( IVector_IInspectable *iface )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+
+    TRACE( "iface %p.\n", iface );
+
+    while (impl->size) IVector_IInspectable_RemoveAtEnd( iface );
+    free( impl->elements );
+    impl->capacity = 0;
+    impl->elements = NULL;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_GetMany( IVector_IInspectable *iface, UINT32 start_index,
+                                      UINT32 items_size, IInspectable **items, UINT *count )
+{
+    struct vector *impl = impl_from_IVector_IInspectable( iface );
+    UINT32 i;
+
+    TRACE( "iface %p, start_index %u, items_size %u, items %p, count %p.\n",
+           iface, start_index, items_size, items, count );
+
+    if (start_index >= impl->size) return E_BOUNDS;
+
+    for (i = start_index; i < impl->size; ++i)
+    {
+        if (i - start_index >= items_size) break;
+        IInspectable_AddRef( (items[i - start_index] = impl->elements[i]) );
+    }
+    *count = i - start_index;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI vector_ReplaceAll( IVector_IInspectable *iface, UINT32 count, IInspectable **items )
+{
+    HRESULT hr;
+    ULONG i;
+
+    TRACE( "iface %p, count %u, items %p.\n", iface, count, items );
+
+    hr = IVector_IInspectable_Clear( iface );
+    for (i = 0; i < count && SUCCEEDED(hr); ++i) hr = IVector_IInspectable_Append( iface, items[i] );
+    return hr;
+}
+
+static const struct IVector_IInspectableVtbl vector_vtbl =
+{
+    vector_QueryInterface,
+    vector_AddRef,
+    vector_Release,
+    /* IInspectable methods */
+    vector_GetIids,
+    vector_GetRuntimeClassName,
+    vector_GetTrustLevel,
+    /* IVector<IInspectable*> methods */
+    vector_GetAt,
+    vector_get_Size,
+    vector_GetView,
+    vector_IndexOf,
+    vector_SetAt,
+    vector_InsertAt,
+    vector_RemoveAt,
+    vector_Append,
+    vector_RemoveAtEnd,
+    vector_Clear,
+    vector_GetMany,
+    vector_ReplaceAll,
+};
+
+DEFINE_IINSPECTABLE( iterable, IIterable_IInspectable, struct vector, IVector_IInspectable_iface )
+
+static HRESULT WINAPI iterable_First( IIterable_IInspectable *iface, IIterator_IInspectable **value )
+{
+    struct vector *impl = impl_from_IIterable_IInspectable( iface );
+    IIterable_IInspectable *iterable;
+    IVectorView_IInspectable *view;
+    HRESULT hr;
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (FAILED(hr = IVector_IInspectable_GetView( &impl->IVector_IInspectable_iface, &view ))) return hr;
+
+    hr = IVectorView_IInspectable_QueryInterface( view, impl->iids.iterable, (void **)&iterable );
+    IVectorView_IInspectable_Release( view );
+    if (FAILED(hr)) return hr;
+
+    hr = IIterable_IInspectable_First( iterable, value );
+    IIterable_IInspectable_Release( iterable );
+    return hr;
+}
+
+static const struct IIterable_IInspectableVtbl iterable_vtbl =
+{
+    iterable_QueryInterface,
+    iterable_AddRef,
+    iterable_Release,
+    /* IInspectable methods */
+    iterable_GetIids,
+    iterable_GetRuntimeClassName,
+    iterable_GetTrustLevel,
+    /* IIterable<T> methods */
+    iterable_First,
+};
+
+HRESULT vector_create( const struct vector_iids *iids, void **out )
+{
+    struct vector *impl;
+
+    TRACE( "iid %s, out %p.\n", debugstr_guid( iids->vector ), out );
+
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+    impl->IVector_IInspectable_iface.lpVtbl = &vector_vtbl;
+    impl->IIterable_IInspectable_iface.lpVtbl = &iterable_vtbl;
+    impl->iids = *iids;
+    impl->ref = 1;
+
+    *out = &impl->IVector_IInspectable_iface;
+    TRACE( "created %p\n", *out );
+    return S_OK;
+}
diff --git a/dlls/windows.devices.radios/windows.devices.radios.spec b/dlls/windows.devices.radios/windows.devices.radios.spec
new file mode 100644
index 000000000000..f80d1ea8ca18
--- /dev/null
+++ b/dlls/windows.devices.radios/windows.devices.radios.spec
@@ -0,0 +1,12 @@
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetActivationFactory(ptr ptr)
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllMain(long long ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
+@ stub RadioDeviceCreate
+@ stub RadioDeviceDelete
+@ stub RadioDeviceStart
+@ stub RadioDeviceStop
+@ stub StartRadioMonitor
+@ stub StopRadioMonitor
diff --git a/dlls/windows.web/Makefile.in b/dlls/windows.web/Makefile.in
index ebcf7bbc2f35..aaaacd6b2988 100644
--- a/dlls/windows.web/Makefile.in
+++ b/dlls/windows.web/Makefile.in
@@ -3,6 +3,7 @@ IMPORTS = combase
 
 SOURCES = \
 	classes.idl \
+	json_array.c \
 	json_object.c \
 	json_value.c \
 	main.c
diff --git a/dlls/windows.web/classes.idl b/dlls/windows.web/classes.idl
index 37537cfeb264..266f560af01a 100644
--- a/dlls/windows.web/classes.idl
+++ b/dlls/windows.web/classes.idl
@@ -24,6 +24,7 @@
 import "windows.data.json.idl";
 
 namespace Windows.Data.Json {
+    runtimeclass JsonArray;
     runtimeclass JsonObject;
     runtimeclass JsonValue;
 }
diff --git a/dlls/windows.web/json_array.c b/dlls/windows.web/json_array.c
new file mode 100644
index 000000000000..1e3890de86d8
--- /dev/null
+++ b/dlls/windows.web/json_array.c
@@ -0,0 +1,302 @@
+/* WinRT Windows.Data.Json.JsonArray Implementation
+ *
+ * Copyright (C) 2026 Olivia Ryan
+ *
+ * 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 "private.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(web);
+
+struct json_array
+{
+    IJsonArray IJsonArray_iface;
+    LONG ref;
+    IJsonValue **elements;
+    ULONG capacity;
+    ULONG length;
+};
+
+static inline struct json_array *impl_from_IJsonArray( IJsonArray *iface )
+{
+    return CONTAINING_RECORD( iface, struct json_array, IJsonArray_iface );
+}
+
+HRESULT json_array_push( IJsonArray *iface, IJsonValue *value )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+
+    TRACE( "iface %p, value %p.\n", iface, value );
+
+    if (impl->length == impl->capacity)
+    {
+        UINT32 capacity = max( 32, impl->capacity * 3 / 2 );
+        IJsonValue **new = impl->elements;
+        if (!(new = realloc( new, capacity * sizeof(*new) ))) return E_OUTOFMEMORY;
+        impl->elements = new;
+        impl->capacity = capacity;
+    }
+
+    impl->elements[impl->length++] = value;
+    IJsonValue_AddRef( value );
+    return S_OK;
+}
+
+static HRESULT WINAPI json_array_QueryInterface( IJsonArray *iface, REFIID iid, void **out )
+{
+    struct json_array *impl = impl_from_IJsonArray( 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_IJsonArray ))
+    {
+        *out = &impl->IJsonArray_iface;
+        IInspectable_AddRef( *out );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI json_array_AddRef( IJsonArray *iface )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI json_array_Release( IJsonArray *iface )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+
+    if (!ref)
+    {
+        for (UINT32 i = 0; i < impl->length; i++)
+            IJsonValue_Release( impl->elements[i] );
+
+        free( impl->elements );
+        free( impl );
+    }
+    return ref;
+}
+
+static HRESULT WINAPI json_array_GetIids( IJsonArray *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 json_array_GetRuntimeClassName( IJsonArray *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI json_array_GetTrustLevel( IJsonArray *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI json_array_GetObjectAt( IJsonArray *iface, UINT32 index, IJsonObject **value )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+
+    TRACE( "iface %p, index %u, value %p\n", iface, index, value );
+
+    if (!value) return E_INVALIDARG;
+    if (index >= impl->length) return E_BOUNDS;
+
+    return IJsonValue_GetObject( impl->elements[index], value );
+}
+
+static HRESULT WINAPI json_array_GetArrayAt( IJsonArray *iface, UINT32 index, IJsonArray **value )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+
+    TRACE( "iface %p, index %u, value %p\n", iface, index, value );
+
+    if (!value) return E_INVALIDARG;
+    if (index >= impl->length) return E_BOUNDS;
+
+    return IJsonValue_GetArray( impl->elements[index], value );
+}
+
+static HRESULT WINAPI json_array_GetStringAt( IJsonArray *iface, UINT32 index, HSTRING *value )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+
+    TRACE( "iface %p, index %u, value %p\n", iface, index, value );
+
+    if (!value) return E_INVALIDARG;
+    if (index >= impl->length) return E_BOUNDS;
+
+    return IJsonValue_GetString( impl->elements[index], value );
+}
+
+static HRESULT WINAPI json_array_GetNumberAt( IJsonArray *iface, UINT32 index, DOUBLE *value )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+
+    TRACE( "iface %p, index %u, value %p\n", iface, index, value );
+
+    if (!value) return E_INVALIDARG;
+    if (index >= impl->length) return E_BOUNDS;
+
+    return IJsonValue_GetNumber( impl->elements[index], value );
+}
+
+static HRESULT WINAPI json_array_GetBooleanAt( IJsonArray *iface, UINT32 index, boolean *value )
+{
+    struct json_array *impl = impl_from_IJsonArray( iface );
+
+    TRACE( "iface %p, index %u, value %p\n", iface, index, value );
+
+    if (!value) return E_INVALIDARG;
+    if (index >= impl->length) return E_BOUNDS;
+
+    return IJsonValue_GetBoolean( impl->elements[index], value );
+}
+
+static const struct IJsonArrayVtbl json_array_vtbl =
+{
+    json_array_QueryInterface,
+    json_array_AddRef,
+    json_array_Release,
+    /* IInspectable methods */
+    json_array_GetIids,
+    json_array_GetRuntimeClassName,
+    json_array_GetTrustLevel,
+    /* IJsonArray methods */
+    json_array_GetObjectAt,
+    json_array_GetArrayAt,
+    json_array_GetStringAt,
+    json_array_GetNumberAt,
+    json_array_GetBooleanAt,
+};
+
+struct json_array_statics
+{
+    IActivationFactory IActivationFactory_iface;
+    LONG ref;
+};
+
+static inline struct json_array_statics *impl_from_IActivationFactory( IActivationFactory *iface )
+{
+    return CONTAINING_RECORD( iface, struct json_array_statics, IActivationFactory_iface );
+}
+
+static HRESULT WINAPI factory_QueryInterface( IActivationFactory *iface, REFIID iid, void **out )
+{
+    struct json_array_statics *impl = impl_from_IActivationFactory( 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_IActivationFactory ))
+    {
+        *out = &impl->IActivationFactory_iface;
+        IInspectable_AddRef( *out );
+        return S_OK;
+    }
+
+    FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) );
+    *out = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI factory_AddRef( IActivationFactory *iface )
+{
+    struct json_array_statics *impl = impl_from_IActivationFactory( iface );
+    ULONG ref = InterlockedIncrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+    return ref;
+}
+
+static ULONG WINAPI factory_Release( IActivationFactory *iface )
+{
+    struct json_array_statics *impl = impl_from_IActivationFactory( iface );
+    ULONG ref = InterlockedDecrement( &impl->ref );
+    TRACE( "iface %p, ref %lu.\n", iface, ref );
+    return ref;
+}
+
+static HRESULT WINAPI factory_GetIids( IActivationFactory *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 factory_GetRuntimeClassName( IActivationFactory *iface, HSTRING *class_name )
+{
+    FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLevel *trust_level )
+{
+    FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
+{
+    struct json_array *impl;
+
+    TRACE( "iface %p, instance %p.\n", iface, instance );
+
+    *instance = NULL;
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+
+    impl->IJsonArray_iface.lpVtbl = &json_array_vtbl;
+    impl->ref = 1;
+
+    *instance = (IInspectable *)&impl->IJsonArray_iface;
+    return S_OK;
+}
+
+static const struct IActivationFactoryVtbl factory_vtbl =
+{
+    factory_QueryInterface,
+    factory_AddRef,
+    factory_Release,
+    /* IInspectable methods */
+    factory_GetIids,
+    factory_GetRuntimeClassName,
+    factory_GetTrustLevel,
+    /* IActivationFactory methods */
+    factory_ActivateInstance,
+};
+
+static struct json_array_statics json_array_statics =
+{
+    {&factory_vtbl},
+    1,
+};
+
+IActivationFactory *json_array_factory = &json_array_statics.IActivationFactory_iface;
diff --git a/dlls/windows.web/json_object.c b/dlls/windows.web/json_object.c
index 38c899288b78..a765d5cfd6c1 100644
--- a/dlls/windows.web/json_object.c
+++ b/dlls/windows.web/json_object.c
@@ -1,6 +1,7 @@
 /* WinRT Windows.Data.Json.JsonObject Implementation
  *
  * Copyright (C) 2024 Mohamad Al-Jaf
+ * Copyright (C) 2026 Olivia Ryan
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -26,6 +27,7 @@ struct json_object
 {
     IJsonObject IJsonObject_iface;
     LONG ref;
+    IMap_HSTRING_IInspectable *members;
 };
 
 static inline struct json_object *impl_from_IJsonObject( IJsonObject *iface )
@@ -33,7 +35,7 @@ static inline struct json_object *impl_from_IJsonObject( IJsonObject *iface )
     return CONTAINING_RECORD( iface, struct json_object, IJsonObject_iface );
 }
 
-static HRESULT WINAPI json_object_statics_QueryInterface( IJsonObject *iface, REFIID iid, void **out )
+static HRESULT WINAPI json_object_QueryInterface( IJsonObject *iface, REFIID iid, void **out )
 {
     struct json_object *impl = impl_from_IJsonObject( iface );
 
@@ -54,7 +56,7 @@ static HRESULT WINAPI json_object_statics_QueryInterface( IJsonObject *iface, RE
     return E_NOINTERFACE;
 }
 
-static ULONG WINAPI json_object_statics_AddRef( IJsonObject *iface )
+static ULONG WINAPI json_object_AddRef( IJsonObject *iface )
 {
     struct json_object *impl = impl_from_IJsonObject( iface );
     ULONG ref = InterlockedIncrement( &impl->ref );
@@ -62,94 +64,177 @@ static ULONG WINAPI json_object_statics_AddRef( IJsonObject *iface )
     return ref;
 }
 
-static ULONG WINAPI json_object_statics_Release( IJsonObject *iface )
+static ULONG WINAPI json_object_Release( IJsonObject *iface )
 {
     struct json_object *impl = impl_from_IJsonObject( iface );
     ULONG ref = InterlockedDecrement( &impl->ref );
 
     TRACE( "iface %p, ref %lu.\n", iface, ref );
 
-    if (!ref) free( impl );
+    if (!ref)
+    {
+        IMap_HSTRING_IInspectable_Release( impl->members );
+        free( impl );
+    }
     return ref;
 }
 
-static HRESULT WINAPI json_object_statics_GetIids( IJsonObject *iface, ULONG *iid_count, IID **iids )
+static HRESULT WINAPI json_object_GetIids( IJsonObject *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 json_object_statics_GetRuntimeClassName( IJsonObject *iface, HSTRING *class_name )
+static HRESULT WINAPI json_object_GetRuntimeClassName( IJsonObject *iface, HSTRING *class_name )
 {
     FIXME( "iface %p, class_name %p stub!\n", iface, class_name );
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI json_object_statics_GetTrustLevel( IJsonObject *iface, TrustLevel *trust_level )
+static HRESULT WINAPI json_object_GetTrustLevel( IJsonObject *iface, TrustLevel *trust_level )
 {
     FIXME( "iface %p, trust_level %p stub!\n", iface, trust_level );
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI json_object_statics_GetNamedValue( IJsonObject *iface, HSTRING name, IJsonValue **value )
+static HRESULT WINAPI json_object_GetNamedValue( IJsonObject *iface, HSTRING name, IJsonValue **value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    struct json_object *impl = impl_from_IJsonObject( iface );
+    boolean exists;
+    HRESULT hr;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    if (!value) return E_POINTER;
+
+    hr = IMap_HSTRING_IInspectable_HasKey( impl->members, name, &exists );
+    if (FAILED(hr) || !exists) return WEB_E_JSON_VALUE_NOT_FOUND;
+
+    return IMap_HSTRING_IInspectable_Lookup( impl->members, name, (IInspectable **)value );
 }
 
-static HRESULT WINAPI json_object_statics_SetNamedValue( IJsonObject *iface, HSTRING name, IJsonValue *value )
+static HRESULT WINAPI json_object_SetNamedValue( IJsonObject *iface, HSTRING name, IJsonValue *value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    struct json_object *impl = impl_from_IJsonObject( iface );
+    boolean dummy;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    return IMap_HSTRING_IInspectable_Insert( impl->members, name, (IInspectable *)value, &dummy );
 }
 
-static HRESULT WINAPI json_object_statics_GetNamedObject( IJsonObject *iface, HSTRING name, IJsonObject **value )
+static HRESULT WINAPI json_object_GetNamedObject( IJsonObject *iface, HSTRING name, IJsonObject **value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    IJsonValue *internal_value;
+    JsonValueType value_type;
+    HRESULT hr;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    if (!value) return E_POINTER;
+    if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value )))
+        return hr;
+
+    IJsonValue_Release( internal_value );
+    IJsonValue_get_ValueType( internal_value, &value_type );
+    if (value_type != JsonValueType_Object) return E_ILLEGAL_METHOD_CALL;
+
+    return IJsonValue_GetObject( internal_value, value );
 }
 
-static HRESULT WINAPI json_object_statics_GetNamedArray( IJsonObject *iface, HSTRING name, IJsonArray **value )
+static HRESULT WINAPI json_object_GetNamedArray( IJsonObject *iface, HSTRING name, IJsonArray **value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    IJsonValue *internal_value;
+    JsonValueType value_type;
+    HRESULT hr;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    if (!value) return E_POINTER;
+    if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value )))
+        return hr;
+
+    IJsonValue_Release( internal_value );
+    IJsonValue_get_ValueType( internal_value, &value_type );
+    if (value_type != JsonValueType_Array) return E_ILLEGAL_METHOD_CALL;
+
+    return IJsonValue_GetArray( internal_value, value );
 }
 
-static HRESULT WINAPI json_object_statics_GetNamedString( IJsonObject *iface, HSTRING name, HSTRING *value )
+static HRESULT WINAPI json_object_GetNamedString( IJsonObject *iface, HSTRING name, HSTRING *value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    IJsonValue *internal_value;
+    JsonValueType value_type;
+    HRESULT hr;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    if (!value) return E_POINTER;
+    if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value )))
+        return hr;
+
+    IJsonValue_Release( internal_value );
+    IJsonValue_get_ValueType( internal_value, &value_type );
+    if (value_type != JsonValueType_String) return E_ILLEGAL_METHOD_CALL;
+
+    return IJsonValue_GetString( internal_value, value );
 }
 
-static HRESULT WINAPI json_object_statics_GetNamedNumber( IJsonObject *iface, HSTRING name, DOUBLE *value )
+static HRESULT WINAPI json_object_GetNamedNumber( IJsonObject *iface, HSTRING name, DOUBLE *value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    IJsonValue *internal_value;
+    JsonValueType value_type;
+    HRESULT hr;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    if (!value) return E_POINTER;
+    if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value )))
+        return hr;
+
+    IJsonValue_Release( internal_value );
+    IJsonValue_get_ValueType( internal_value, &value_type );
+    if (value_type != JsonValueType_Number) return E_ILLEGAL_METHOD_CALL;
+
+    return IJsonValue_GetNumber( internal_value, value );
 }
 
-static HRESULT WINAPI json_object_statics_GetNamedBoolean( IJsonObject *iface, HSTRING name, boolean *value )
+static HRESULT WINAPI json_object_GetNamedBoolean( IJsonObject *iface, HSTRING name, boolean *value )
 {
-    FIXME( "iface %p, name %s, value %p stub!\n", iface, debugstr_hstring( name ), value );
-    return E_NOTIMPL;
+    IJsonValue *internal_value;
+    JsonValueType value_type;
+    HRESULT hr;
+
+    TRACE( "iface %p, name %s, value %p.\n", iface, debugstr_hstring( name ), value );
+
+    if (!value) return E_POINTER;
+    if (FAILED(hr = IJsonObject_GetNamedValue( iface, name, &internal_value )))
+        return hr;
+
+    IJsonValue_Release( internal_value );
+    IJsonValue_get_ValueType( internal_value, &value_type );
+    if (value_type != JsonValueType_Boolean) return E_ILLEGAL_METHOD_CALL;
+
+    return IJsonValue_GetBoolean( internal_value, value );
 }
 
-static const struct IJsonObjectVtbl json_object_statics_vtbl =
+static const struct IJsonObjectVtbl json_object_vtbl =
 {
-    json_object_statics_QueryInterface,
-    json_object_statics_AddRef,
-    json_object_statics_Release,
+    json_object_QueryInterface,
+    json_object_AddRef,
+    json_object_Release,
     /* IInspectable methods */
-    json_object_statics_GetIids,
-    json_object_statics_GetRuntimeClassName,
-    json_object_statics_GetTrustLevel,
+    json_object_GetIids,
+    json_object_GetRuntimeClassName,
+    json_object_GetTrustLevel,
     /* IJsonObject methods */
-    json_object_statics_GetNamedValue,
-    json_object_statics_SetNamedValue,
-    json_object_statics_GetNamedObject,
-    json_object_statics_GetNamedArray,
-    json_object_statics_GetNamedString,
-    json_object_statics_GetNamedNumber,
-    json_object_statics_GetNamedBoolean,
+    json_object_GetNamedValue,
+    json_object_SetNamedValue,
+    json_object_GetNamedObject,
+    json_object_GetNamedArray,
+    json_object_GetNamedString,
+    json_object_GetNamedNumber,
+    json_object_GetNamedBoolean,
 };
 
 struct json_object_statics
@@ -220,18 +305,34 @@ static HRESULT WINAPI factory_GetTrustLevel( IActivationFactory *iface, TrustLev
 
 static HRESULT WINAPI factory_ActivateInstance( IActivationFactory *iface, IInspectable **instance )
 {
+    IPropertySet *property_set;
+    HSTRING property_set_class;
     struct json_object *impl;
+    HSTRING_HEADER header;
+    HRESULT hr;
 
     TRACE( "iface %p, instance %p.\n", iface, instance );
 
     *instance = NULL;
     if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
 
-    impl->IJsonObject_iface.lpVtbl = &json_object_statics_vtbl;
+    impl->IJsonObject_iface.lpVtbl = &json_object_vtbl;
     impl->ref = 1;
 
+    WindowsCreateStringReference( RuntimeClass_Windows_Foundation_Collections_PropertySet, wcslen( RuntimeClass_Windows_Foundation_Collections_PropertySet ),
+                                  &header, &property_set_class );
+    if (FAILED(hr = RoActivateInstance( property_set_class, (IInspectable **)&property_set ))) goto failed;
+
+    hr = IPropertySet_QueryInterface( property_set, &IID_IMap_HSTRING_IInspectable, (void **)&impl->members );
+    IPropertySet_Release( property_set );
+    if (FAILED(hr)) goto failed;
+
     *instance = (IInspectable *)&impl->IJsonObject_iface;
     return S_OK;
+
+failed:
+    free( impl );
+    return hr;
 }
 
 static const struct IActivationFactoryVtbl factory_vtbl =
diff --git a/dlls/windows.web/json_value.c b/dlls/windows.web/json_value.c
index f1930beaad37..857d36303120 100644
--- a/dlls/windows.web/json_value.c
+++ b/dlls/windows.web/json_value.c
@@ -1,6 +1,7 @@
 /* WinRT Windows.Data.Json.JsonValue Implementation
  *
  * Copyright (C) 2024 Mohamad Al-Jaf
+ * Copyright (C) 2026 Olivia Ryan
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -121,10 +122,14 @@ struct json_value
     LONG ref;
 
     JsonValueType json_value_type;
-    HSTRING parsed_string;
-    double parsed_number;
-    boolean parsed_boolean;
-    HSTRING string_value;
+    union
+    {
+        boolean boolean_value;
+        HSTRING string_value;
+        double number_value;
+        IJsonArray *array_value;
+        IJsonObject *object_value;
+    };
 };
 
 static inline struct json_value *impl_from_IJsonValue( IJsonValue *iface )
@@ -170,8 +175,13 @@ static ULONG WINAPI json_value_Release( IJsonValue *iface )
 
     if (!ref)
     {
-        WindowsDeleteString( impl->parsed_string );
-        WindowsDeleteString( impl->string_value );
+        if (impl->json_value_type == JsonValueType_String)
+            WindowsDeleteString( impl->string_value );
+        else if (impl->json_value_type == JsonValueType_Array)
+            IJsonArray_Release( impl->array_value );
+        else if (impl->json_value_type == JsonValueType_Object)
+            IJsonObject_Release( impl->object_value );
+
         free( impl );
     }
     return ref;
@@ -222,7 +232,7 @@ static HRESULT WINAPI json_value_GetString( IJsonValue *iface, HSTRING *value )
     if (impl->json_value_type != JsonValueType_String) return E_ILLEGAL_METHOD_CALL;
     if (!value) return E_POINTER;
 
-    return WindowsDuplicateString( impl->parsed_string, value );
+    return WindowsDuplicateString( impl->string_value, value );
 }
 
 static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value )
@@ -234,7 +244,7 @@ static HRESULT WINAPI json_value_GetNumber( IJsonValue *iface, DOUBLE *value )
     if (impl->json_value_type != JsonValueType_Number) return E_ILLEGAL_METHOD_CALL;
     if (!value) return E_POINTER;
 
-    *value = impl->parsed_number;
+    *value = impl->number_value;
     return S_OK;
 }
 
@@ -247,7 +257,7 @@ static HRESULT WINAPI json_value_GetBoolean( IJsonValue *iface, boolean *value )
     if (impl->json_value_type != JsonValueType_Boolean) return E_ILLEGAL_METHOD_CALL;
     if (!value) return E_POINTER;
 
-    *value = impl->parsed_boolean;
+    *value = impl->boolean_value;
     return S_OK;
 }
 
@@ -255,24 +265,28 @@ static HRESULT WINAPI json_value_GetArray( IJsonValue *iface, IJsonArray **value
 {
     struct json_value *impl = impl_from_IJsonValue( iface );
 
-    FIXME( "iface %p, value %p stub!\n", iface, value );
+    TRACE( "iface %p, value %p\n", iface, value );
 
     if (!value) return E_POINTER;
     if (impl->json_value_type != JsonValueType_Array) return E_ILLEGAL_METHOD_CALL;
 
-    return E_NOTIMPL;
+    IJsonArray_AddRef( impl->array_value );
+    *value = impl->array_value;
+    return S_OK;
 }
 
 static HRESULT WINAPI json_value_GetObject( IJsonValue *iface, IJsonObject **value )
 {
     struct json_value *impl = impl_from_IJsonValue( iface );
 
-    FIXME( "iface %p, value %p stub!\n", iface, value );
+    TRACE( "iface %p, value %p\n", iface, value );
 
     if (!value) return E_POINTER;
     if (impl->json_value_type != JsonValueType_Object) return E_ILLEGAL_METHOD_CALL;
 
-    return E_NOTIMPL;
+    IJsonObject_AddRef( impl->object_value );
+    *value = impl->object_value;
+    return S_OK;
 }
 
 static const struct IJsonValueVtbl json_value_vtbl =
@@ -296,72 +310,212 @@ static const struct IJsonValueVtbl json_value_vtbl =
 
 DEFINE_IINSPECTABLE( json_value_statics, IJsonValueStatics, struct json_value_statics, IActivationFactory_iface )
 
-static HRESULT unescape_string( const WCHAR *src, HSTRING *output )
+struct json_buffer
 {
-    UINT32 len = wcslen( src ) - 1, n;
-    const WCHAR *end = src + len;
-    HSTRING_BUFFER buf;
-    HRESULT hr;
-    WCHAR *dst;
+    const WCHAR *str;
+    UINT32 len;
+};
+
+static WCHAR json_buffer_next( struct json_buffer *json, const WCHAR *valid )
+{
+    const WCHAR chr = *json->str;
 
-    for (len = n = 0; len + n < end - src; len++) { if (src[len + n] == '\\') n++; }
-    if (FAILED(hr = WindowsPreallocateStringBuffer( len, &dst, &buf ))) return hr;
-    while (src != end) { if (*src == '\\' && ++src == end) break; *dst++ = *src++; }
+    if (!json->len) return 0;
+    if (valid && !wcschr( valid, chr )) return 0;
+    json->str++;
+    json->len--;
 
-    return WindowsPromoteStringBuffer( buf, output );
+    return chr;
 }
 
-static HRESULT trim_string( HSTRING input, HSTRING *output )
+static BOOL json_buffer_take( struct json_buffer *json, const WCHAR *str, BOOL skip )
 {
     static const WCHAR valid_whitespace[] = L" \t\n\r";
-    UINT32 len, start = 0, end;
-    const WCHAR *json = WindowsGetStringRawBuffer( input, &len );
+    UINT32 len = wcslen( str );
 
-    end = len;
-    while (start < end && wcschr( valid_whitespace, json[start] )) start++;
-    while (end > start && wcschr( valid_whitespace, json[end - 1] )) end--;
+    while (skip && json_buffer_next( json, valid_whitespace )) { /* nothing */ }
+    if (json->len < len || wcsncmp( json->str, str, len )) return FALSE;
+    json->str += len;
+    json->len -= len;
 
-    return WindowsCreateString( json + start, end - start, output );
+    return TRUE;
 }
 
-static HRESULT parse_json_value( HSTRING input, struct json_value *impl )
+static HRESULT parse_json_string( struct json_buffer *json, HSTRING *output )
 {
-    UINT32 len;
-    const WCHAR *json = WindowsGetStringRawBuffer( input, &len );
-    HRESULT hr = S_OK;
+    const WCHAR valid_hex_chars[] = L"abcdefABCDEF0123456789";
+    WCHAR chr, *buf, *dst;
+    HRESULT hr;
 
-    /* FIXME: Handle all JSON edge cases */
+    /* validate and escape string, assuming string occupies remainder of buffer */
 
-    if (!len) return WEB_E_INVALID_JSON_STRING;
+    if (!json->len) return WEB_E_INVALID_JSON_STRING;
+    if (!(buf = calloc( json->len, sizeof( WCHAR )))) return E_OUTOFMEMORY;
+    dst = buf;
 
-    if (len == 4 && !wcsncmp( L"null", json, 4 ))
+    while (json->len && *json->str != '"')
     {
-        impl->json_value_type = JsonValueType_Null;
+        if (json_buffer_take( json, L"\\\"", FALSE ))      *(dst++) = '"';
+        else if (json_buffer_take( json, L"\\\\", FALSE )) *(dst++) = '\\';
+        else if (json_buffer_take( json, L"\\/", FALSE ))  *(dst++) = '/';
+        else if (json_buffer_take( json, L"\\b", FALSE ))  *(dst++) = '\b';
+        else if (json_buffer_take( json, L"\\f", FALSE ))  *(dst++) = '\f';
+        else if (json_buffer_take( json, L"\\n", FALSE ))  *(dst++) = '\n';
+        else if (json_buffer_take( json, L"\\r", FALSE ))  *(dst++) = '\r';
+        else if (json_buffer_take( json, L"\\t", FALSE ))  *(dst++) = '\t';
+        else if (json_buffer_take( json, L"\\u", FALSE ))
+        {
+            for (int i = 0; i < 4; i++)
+            {
+                if (!(chr = json_buffer_next( json, valid_hex_chars )))
+                {
+                    free( buf );
+                    return WEB_E_INVALID_JSON_STRING;
+                }
+
+                *dst <<= 4;
+                if (chr >= 'A') *dst |= (chr & 0x7) + 9;
+                else *dst |= chr & 0xf;
+            }
+            dst++;
+        }
+        else if (*json->str >= ' ')
+        {
+            *(dst++) = *(json->str++);
+            json->len--;
+        }
+        else
+        {
+            free( buf );
+            return WEB_E_INVALID_JSON_STRING;
+        }
     }
-    else if ((len == 4 && !wcsncmp( L"true", json, 4 )) || (len == 5 && !wcsncmp( L"false", json, 5 )))
+
+    hr = WindowsCreateString( buf, dst - buf, output );
+    free( buf );
+    return hr;
+}
+
+static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value );
+
+static HRESULT parse_json_array( struct json_buffer *json, IJsonArray **value )
+{
+    IJsonArray *array;
+    IJsonValue *child;
+    HRESULT hr;
+
+    if (FAILED(hr = IActivationFactory_ActivateInstance( json_array_factory, (IInspectable **)&array ))) return hr;
+
+    while (json->len && *json->str != ']')
     {
-        impl->parsed_boolean = len == 4;
-        impl->json_value_type = JsonValueType_Boolean;
+        if (FAILED(hr = parse_json_value( json, &child ))) break;
+        hr = json_array_push( array, child );
+        IJsonValue_Release( child );
+        if (FAILED(hr) || !json_buffer_take( json, L",", TRUE )) break;
+        if (json_buffer_take( json, L"]", TRUE ))
+        {
+            hr = WEB_E_INVALID_JSON_STRING;
+            break;
+        }
     }
-    else if (json[0] == '\"' && json[len - 1] == '\"')
+
+    if (FAILED(hr)) IJsonArray_Release( array );
+    else *value = array;
+    return hr;
+}
+
+static HRESULT parse_json_key_value( struct json_buffer *json, HSTRING *key, IJsonValue **value )
+{
+    HSTRING name;
+    HRESULT hr;
+
+    if (!json_buffer_take( json, L"\"", TRUE )) return WEB_E_INVALID_JSON_STRING;
+    if (FAILED(hr = parse_json_string( json, &name ))) return hr;
+
+    if (!json_buffer_take( json, L"\"", FALSE )) hr = WEB_E_INVALID_JSON_STRING;
+    else if (!json_buffer_take( json, L":", TRUE )) hr = WEB_E_INVALID_JSON_STRING;
+    else hr = parse_json_value( json, value );
+
+    if (FAILED(hr)) WindowsDeleteString( name );
+    else *key = name;
+    return hr;
+}
+
+static HRESULT parse_json_object( struct json_buffer *json, IJsonObject **value )
+{
+    IJsonObject *object;
+    HRESULT hr;
+
+    if (FAILED(hr = IActivationFactory_ActivateInstance( json_object_factory, (IInspectable**)&object ))) return hr;
+
+    while (json->len && *json->str != '}')
     {
-        json++;
-        len -= 2;
+        IJsonValue *value;
+        HSTRING key;
+
+        if (FAILED(hr = parse_json_key_value( json, &key, &value ))) break;
+        hr = IJsonObject_SetNamedValue( object, key, value );
+        WindowsDeleteString( key );
+        IJsonValue_Release( value );
+        if (FAILED(hr) || !json_buffer_take( json, L",", TRUE )) break;
+        if (json_buffer_take( json, L"}", TRUE ))
+        {
+            hr = WEB_E_INVALID_JSON_STRING;
+            break;
+        }
+    }
+
+    if (FAILED(hr)) IJsonObject_Release( object );
+    else *value = object;
+    return hr;
+}
 
-        if (len <= 2) return WEB_E_INVALID_JSON_STRING;
-        if (FAILED(hr = unescape_string( json, &impl->parsed_string ))) return hr;
+static HRESULT parse_json_value( struct json_buffer *json, IJsonValue **value )
+{
+    struct json_value *impl;
+    HRESULT hr = S_OK;
+
+    if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY;
+    impl->IJsonValue_iface.lpVtbl = &json_value_vtbl;
+    impl->ref = 1;
 
-        impl->json_value_type = JsonValueType_String;
+    if (json_buffer_take( json, L"null", TRUE ))
+    {
+        impl->json_value_type = JsonValueType_Null;
+    }
+    else if (json_buffer_take( json, L"true", TRUE ))
+    {
+        impl->boolean_value = TRUE;
+        impl->json_value_type = JsonValueType_Boolean;
+    }
+    else if (json_buffer_take( json, L"false", TRUE ))
+    {
+        impl->boolean_value = FALSE;
+        impl->json_value_type = JsonValueType_Boolean;
+    }
+    else if (json_buffer_take( json, L"\"", TRUE ))
+    {
+        if (SUCCEEDED(hr = parse_json_string( json, &impl->string_value )))
+        {
+            impl->json_value_type = JsonValueType_String;
+            if (!json_buffer_take( json, L"\"", FALSE )) hr = WEB_E_INVALID_JSON_STRING;
+        }
     }
-    else if (json[0] == '[' && json[len - 1] == ']')
+    else if (json_buffer_take( json, L"[", TRUE ))
     {
-        FIXME( "Array parsing not implemented!\n" );
-        impl->json_value_type = JsonValueType_Array;
+        if (SUCCEEDED(hr = parse_json_array( json, &impl->array_value )))
+        {
+            impl->json_value_type = JsonValueType_Array;
+            if (!json_buffer_take( json, L"]", TRUE )) hr = WEB_E_INVALID_JSON_STRING;
+        }
     }
-    else if (json[0] == '{' && json[len - 1] == '}')
+    else if (json_buffer_take( json, L"{", TRUE ))
     {
-        FIXME( "Object parsing not implemented!\n" );
-        impl->json_value_type = JsonValueType_Object;
+        if (SUCCEEDED(hr = parse_json_object( json, &impl->object_value )))
+        {
+            impl->json_value_type = JsonValueType_Object;
+            if (!json_buffer_take( json, L"}", TRUE )) hr = WEB_E_INVALID_JSON_STRING;
+        }
     }
     else
     {
@@ -369,51 +523,46 @@ static HRESULT parse_json_value( HSTRING input, struct json_value *impl )
         WCHAR *end;
 
         errno = 0;
-        result = wcstold( json, &end );
+        result = wcstold( json->str, &end );
+
+        json->len -= end - json->str;
+        json->str = end;
 
-        if (errno || errno == ERANGE || end != json + len) return WEB_E_INVALID_JSON_NUMBER;
+        if (errno || errno == ERANGE) hr = WEB_E_INVALID_JSON_NUMBER;
 
-        impl->parsed_number = result;
+        impl->number_value = result;
         impl->json_value_type = JsonValueType_Number;
     }
 
+    if (FAILED(hr)) IJsonValue_Release( &impl->IJsonValue_iface );
+    else *value = &impl->IJsonValue_iface;
     return hr;
 }
 
-static HRESULT parse_json( HSTRING json, struct json_value *impl )
+static HRESULT parse_json( HSTRING string, IJsonValue **value )
 {
-    HSTRING trimmed_json = NULL;
-    HRESULT hr = trim_string( json, &trimmed_json );
-
-    if (SUCCEEDED(hr) && WindowsIsStringEmpty( trimmed_json )) hr = WEB_E_INVALID_JSON_STRING;
-    if (SUCCEEDED(hr)) hr = parse_json_value( trimmed_json, impl );
+    HRESULT hr;
+    struct json_buffer json;
+    json.str = WindowsGetStringRawBuffer( string, &json.len );
 
-    WindowsDeleteString( trimmed_json );
-    return hr;
+    if (FAILED(hr = parse_json_value( &json, value ))) return hr;
+    if (!json_buffer_take( &json, L"", TRUE ) || json.len) return WEB_E_INVALID_JSON_STRING;
+    return S_OK;
 }
 
 static HRESULT WINAPI json_value_statics_Parse( IJsonValueStatics *iface, HSTRING input, IJsonValue **value )
 {
-    struct json_value *impl;
     HRESULT hr;
 
-    FIXME( "iface %p, input %s, value %p semi-stub\n", iface, debugstr_hstring( input ), value );
+    TRACE( "iface %p, input %s, value %p\n", iface, debugstr_hstring( input ), value );
 
     if (!value) return E_POINTER;
     if (!input) return WEB_E_INVALID_JSON_STRING;
-    if (!(impl = calloc( 1, sizeof( *impl ) ))) return E_OUTOFMEMORY;
 
-    if (FAILED(hr = parse_json( input, impl )))
-    {
-        free( impl );
-        return hr;
-    }
-    impl->IJsonValue_iface.lpVtbl = &json_value_vtbl;
-    impl->ref = 1;
+    if (SUCCEEDED(hr = parse_json( input, value )))
+        TRACE( "created IJsonValue %p.\n", *value );
 
-    *value = &impl->IJsonValue_iface;
-    TRACE( "created IJsonValue %p.\n", *value );
-    return S_OK;
+    return hr;
 }
 
 static HRESULT WINAPI json_value_statics_TryParse( IJsonValueStatics *iface, HSTRING input, IJsonValue **result, boolean *succeeded )
@@ -424,14 +573,40 @@ static HRESULT WINAPI json_value_statics_TryParse( IJsonValueStatics *iface, HST
 
 static HRESULT WINAPI json_value_statics_CreateBooleanValue( IJsonValueStatics *iface, boolean input, IJsonValue **value )
 {
-    FIXME( "iface %p, input %d, value %p stub!\n", iface, input, value );
-    return E_NOTIMPL;
+    struct json_value *impl;
+
+    TRACE( "iface %p, input %d, value %p\n", iface, input, value );
+
+    if (!value) return E_POINTER;
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+
+    impl->IJsonValue_iface.lpVtbl = &json_value_vtbl;
+    impl->ref = 1;
+    impl->json_value_type = JsonValueType_Boolean;
+    impl->boolean_value = input != FALSE;
+
+    *value = &impl->IJsonValue_iface;
+    TRACE( "created IJsonValue %p.\n", *value );
+    return S_OK;
 }
 
 static HRESULT WINAPI json_value_statics_CreateNumberValue( IJsonValueStatics *iface, DOUBLE input, IJsonValue **value )
 {
-    FIXME( "iface %p, input %f, value %p stub!\n", iface, input, value );
-    return E_NOTIMPL;
+    struct json_value *impl;
+
+    TRACE( "iface %p, input %f, value %p\n", iface, input, value );
+
+    if (!value) return E_POINTER;
+    if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY;
+
+    impl->IJsonValue_iface.lpVtbl = &json_value_vtbl;
+    impl->ref = 1;
+    impl->json_value_type = JsonValueType_Number;
+    impl->number_value = input;
+
+    *value = &impl->IJsonValue_iface;
+    TRACE( "created IJsonValue %p.\n", *value );
+    return S_OK;
 }
 
 static HRESULT WINAPI json_value_statics_CreateStringValue( IJsonValueStatics *iface, HSTRING input, IJsonValue **value )
@@ -449,8 +624,8 @@ static HRESULT WINAPI json_value_statics_CreateStringValue( IJsonValueStatics *i
     impl->json_value_type = JsonValueType_String;
     if (FAILED(hr = WindowsDuplicateString( input, &impl->string_value )))
     {
-         free( impl );
-         return hr;
+        free( impl );
+        return hr;
     }
 
     *value = &impl->IJsonValue_iface;
diff --git a/dlls/windows.web/main.c b/dlls/windows.web/main.c
index 60e95fdba0cc..bec92a817750 100644
--- a/dlls/windows.web/main.c
+++ b/dlls/windows.web/main.c
@@ -38,6 +38,8 @@ HRESULT WINAPI DllGetActivationFactory( HSTRING classid, IActivationFactory **fa
 
     *factory = NULL;
 
+    if (!wcscmp( buffer, RuntimeClass_Windows_Data_Json_JsonArray ))
+        IActivationFactory_QueryInterface( json_array_factory, &IID_IActivationFactory, (void **)factory );
     if (!wcscmp( buffer, RuntimeClass_Windows_Data_Json_JsonObject ))
         IActivationFactory_QueryInterface( json_object_factory, &IID_IActivationFactory, (void **)factory );
     if (!wcscmp( buffer, RuntimeClass_Windows_Data_Json_JsonValue ))
diff --git a/dlls/windows.web/private.h b/dlls/windows.web/private.h
index d5f0e76d641b..6722d69bc575 100644
--- a/dlls/windows.web/private.h
+++ b/dlls/windows.web/private.h
@@ -29,6 +29,7 @@
 #include "winstring.h"
 
 #include "activation.h"
+#include "roapi.h"
 
 #define WIDL_using_Windows_Foundation
 #define WIDL_using_Windows_Foundation_Collections
@@ -36,9 +37,12 @@
 #define WIDL_using_Windows_Data_Json
 #include "windows.data.json.h"
 
+extern IActivationFactory *json_array_factory;
 extern IActivationFactory *json_object_factory;
 extern IActivationFactory *json_value_factory;
 
+HRESULT json_array_push( IJsonArray *iface, IJsonValue *value );
+
 #define DEFINE_IINSPECTABLE_( pfx, iface_type, impl_type, impl_from, iface_mem, expr )             \
     static inline impl_type *impl_from( iface_type *iface )                                        \
     {                                                                                              \
diff --git a/dlls/windows.web/tests/web.c b/dlls/windows.web/tests/web.c
index b0f38edfb3b8..a023319e909d 100644
--- a/dlls/windows.web/tests/web.c
+++ b/dlls/windows.web/tests/web.c
@@ -45,16 +45,233 @@ static void check_interface_( unsigned int line, void *obj, const IID *iid )
     IUnknown_Release( unk );
 }
 
+static void test_JsonArrayStatics(void)
+{
+    static const WCHAR *json_value_statics_name = L"Windows.Data.Json.JsonValue";
+    static const WCHAR *json_array_name = L"Windows.Data.Json.JsonArray";
+    IJsonValueStatics *json_value_statics = (void *)0xdeadbeef;
+    IActivationFactory *factory = (void *)0xdeadbeef;
+    IInspectable *inspectable = (void *)0xdeadbeef;
+    IJsonObject *child_object = (void *)0xdeadbeef;
+    IJsonArray *child_array = (void *)0xdeadbeef;
+    IJsonArray *json_array = (void *)0xdeadbeef;
+    IJsonValue *json_value = (void *)0xdeadbeef;
+    BOOLEAN child_boolean;
+    HSTRING child_string;
+    DOUBLE child_number;
+    HSTRING str = NULL;
+    HRESULT hr;
+    LONG ref;
+
+    hr = WindowsCreateString( json_value_statics_name, wcslen( json_value_statics_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( json_value_statics_name ) );
+        return;
+    }
+
+    hr = IActivationFactory_QueryInterface( factory, &IID_IJsonValueStatics, (void **)&json_value_statics );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    ref = IActivationFactory_Release( factory );
+
+    hr = WindowsCreateString( json_array_name, wcslen( json_array_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( json_array_name ) );
+        return;
+    }
+
+    check_interface( factory, &IID_IUnknown );
+    check_interface( factory, &IID_IInspectable );
+    check_interface( factory, &IID_IAgileObject );
+
+    hr = IActivationFactory_QueryInterface( factory, &IID_IJsonArray, (void **)&json_array );
+    ok( hr == E_NOINTERFACE, "got hr %#lx.\n", hr );
+
+    hr = WindowsCreateString( json_array_name, wcslen( json_array_name ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = RoActivateInstance( str, &inspectable );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+
+    hr = IInspectable_QueryInterface( inspectable, &IID_IJsonArray, (void **)&json_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+
+    check_interface( inspectable, &IID_IAgileObject );
+
+    hr = IJsonArray_GetObjectAt( json_array, 0, NULL );
+    ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetObjectAt( json_array, 0, &child_object );
+    ok( hr == E_BOUNDS, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetArrayAt( json_array, 0, NULL );
+    ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetArrayAt( json_array, 0, &child_array );
+    ok( hr == E_BOUNDS, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetStringAt( json_array, 0, NULL );
+    ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetStringAt( json_array, 0, &child_string );
+    ok( hr == E_BOUNDS, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetNumberAt( json_array, 0, NULL );
+    ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetNumberAt( json_array, 0, &child_number );
+    ok( hr == E_BOUNDS, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, NULL );
+    ok( hr == E_INVALIDARG, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean );
+    ok( hr == E_BOUNDS, "got hr %#lx.\n", hr );
+
+    IJsonArray_Release( json_array );
+    IInspectable_Release( inspectable );
+    ref = IActivationFactory_Release( factory );
+    ok( ref == 1, "got ref %ld.\n", ref );
+
+    hr = WindowsCreateString( L"[{}]", wcslen( L"[{}]" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = IJsonValue_GetArray( json_value, &json_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( json_value );
+    hr = IJsonArray_GetObjectAt( json_array, 0, &child_object );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonObject_Release( child_object );
+    hr = IJsonArray_GetArrayAt( json_array, 0, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetStringAt( json_array, 0, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetNumberAt( json_array, 0, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    IJsonArray_Release( json_array );
+
+    hr = WindowsCreateString( L"[[]]", wcslen( L"[[]]" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = IJsonValue_GetArray( json_value, &json_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( json_value );
+    hr = IJsonArray_GetObjectAt( json_array, 0, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetArrayAt( json_array, 0, &child_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonArray_Release( child_array );
+    hr = IJsonArray_GetStringAt( json_array, 0, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetNumberAt( json_array, 0, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    IJsonArray_Release( json_array );
+
+    hr = WindowsCreateString( L"[\"Hello, World!\"]", wcslen( L"[\"Hello, World!\"]" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = IJsonValue_GetArray( json_value, &json_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( json_value );
+    hr = IJsonArray_GetObjectAt( json_array, 0, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetArrayAt( json_array, 0, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetStringAt( json_array, 0, &child_string );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( child_string );
+    hr = IJsonArray_GetNumberAt( json_array, 0, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    IJsonArray_Release( json_array );
+
+    hr = WindowsCreateString( L"[12.6]", wcslen( L"[12.6]" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = IJsonValue_GetArray( json_value, &json_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( json_value );
+    hr = IJsonArray_GetObjectAt( json_array, 0, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetArrayAt( json_array, 0, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetStringAt( json_array, 0, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetNumberAt( json_array, 0, &child_number );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    IJsonArray_Release( json_array );
+
+    hr = WindowsCreateString( L"[true]", wcslen( L"[true]" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = IJsonValue_GetArray( json_value, &json_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( json_value );
+    hr = IJsonArray_GetObjectAt( json_array, 0, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetArrayAt( json_array, 0, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetStringAt( json_array, 0, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetNumberAt( json_array, 0, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonArray_GetBooleanAt( json_array, 0, &child_boolean );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonArray_Release( json_array );
+
+    IJsonValueStatics_Release( json_value_statics );
+}
+
 static void test_JsonObjectStatics(void)
 {
+    static const WCHAR *json_value_statics_name = L"Windows.Data.Json.JsonValue";
     static const WCHAR *json_object_name = L"Windows.Data.Json.JsonObject";
+    IJsonValueStatics *json_value_statics = (void *)0xdeadbeef;
     IActivationFactory *factory = (void *)0xdeadbeef;
     IInspectable *inspectable = (void *)0xdeadbeef;
+    IJsonObject *child_object = (void *)0xdeadbeef;
     IJsonObject *json_object = (void *)0xdeadbeef;
+    IJsonArray *child_array = (void *)0xdeadbeef;
+    IJsonValue *child_value = (void *)0xdeadbeef;
+    BOOLEAN child_boolean;
+    HSTRING child_string;
+    DOUBLE child_number;
     HSTRING str = NULL;
     HRESULT hr;
     LONG ref;
 
+    hr = WindowsCreateString( json_value_statics_name, wcslen( json_value_statics_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( json_value_statics_name ) );
+        return;
+    }
+
+    hr = IActivationFactory_QueryInterface( factory, &IID_IJsonValueStatics, (void **)&json_value_statics );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    ref = IActivationFactory_Release( factory );
+
     hr = WindowsCreateString( json_object_name, wcslen( json_object_name ), &str );
     ok( hr == S_OK, "got hr %#lx.\n", hr );
     hr = RoGetActivationFactory( str, &IID_IActivationFactory, (void **)&factory );
@@ -83,9 +300,179 @@ static void test_JsonObjectStatics(void)
     ok( hr == S_OK, "got hr %#lx.\n", hr );
 
     check_interface( inspectable, &IID_IAgileObject );
+    IInspectable_Release( inspectable );
+
+    hr = WindowsCreateString( L"key", wcslen( L"key" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+
+    /* key pair does not exist */
+
+    hr = IJsonObject_GetNamedValue( json_object, NULL, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedValue( json_object, str, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedValue( json_object, NULL, &child_value );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedValue( json_object, str, &child_value );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+
+    hr = IJsonObject_GetNamedObject( json_object, NULL, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedObject( json_object, str, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedObject( json_object, NULL, &child_object );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedObject( json_object, str, &child_object );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+
+    hr = IJsonObject_GetNamedArray( json_object, NULL, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, str, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, NULL, &child_array );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, str, &child_array );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+
+    hr = IJsonObject_GetNamedString( json_object, NULL, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, str, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, NULL, &child_string );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, str, &child_string );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+
+    hr = IJsonObject_GetNamedNumber( json_object, NULL, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, str, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, NULL, &child_number );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, str, &child_number );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+
+    hr = IJsonObject_GetNamedBoolean( json_object, NULL, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, NULL, &child_boolean );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean );
+    ok( hr == WEB_E_JSON_VALUE_NOT_FOUND, "got hr %#lx.\n", hr );
+
+    /* key pair exists */
+
+    WindowsDeleteString( str );
+    hr = WindowsCreateString( L"{}", wcslen( L"{}" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = WindowsCreateString( L"key", wcslen( L"key" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_SetNamedValue( json_object, str, child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedValue( json_object, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedObject( json_object, str, &child_object );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonObject_Release( child_object );
+    hr = IJsonObject_GetNamedArray( json_object, str, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, str, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, str, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+
+    WindowsDeleteString( str );
+    hr = WindowsCreateString( L"[]", wcslen( L"[]" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    hr = WindowsCreateString( L"key", wcslen( L"key" ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_SetNamedValue( json_object, str, child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedValue( json_object, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedObject( json_object, str, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, str, &child_array );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonArray_Release( child_array );
+    hr = IJsonObject_GetNamedString( json_object, str, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, str, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+
+    hr = IJsonValueStatics_CreateStringValue( json_value_statics, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_SetNamedValue( json_object, str, child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedValue( json_object, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedObject( json_object, str, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, str, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, str, &child_string );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( child_string );
+    hr = IJsonObject_GetNamedNumber( json_object, str, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+
+    hr = IJsonValueStatics_CreateNumberValue( json_value_statics, 10, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_SetNamedValue( json_object, str, child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedValue( json_object, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedObject( json_object, str, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, str, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, str, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, str, &child_number );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+
+    hr = IJsonValueStatics_CreateBooleanValue( json_value_statics, FALSE, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonObject_SetNamedValue( json_object, str, child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedValue( json_object, str, &child_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    IJsonValue_Release( child_value );
+    hr = IJsonObject_GetNamedObject( json_object, str, &child_object );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedArray( json_object, str, &child_array );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedString( json_object, str, &child_string );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedNumber( json_object, str, &child_number );
+    ok( hr == E_ILLEGAL_METHOD_CALL, "got hr %#lx.\n", hr );
+    hr = IJsonObject_GetNamedBoolean( json_object, str, &child_boolean );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
 
     IJsonObject_Release( json_object );
-    IInspectable_Release( inspectable );
+    IJsonValueStatics_Release( json_value_statics );
     ref = IActivationFactory_Release( factory );
     ok( ref == 1, "got ref %ld.\n", ref );
 }
@@ -112,13 +499,14 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static
         if (expected_json_value_type == JsonValueType_Number)
             ok_(__FILE__, line)( hr == WEB_E_INVALID_JSON_NUMBER, "got hr %#lx.\n", hr );
         else
-            todo_wine
             ok_(__FILE__, line)( hr == WEB_E_INVALID_JSON_STRING, "got hr %#lx.\n", hr );
 
         WindowsDeleteString( str );
         return;
     }
+
     ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr );
+    if (FAILED(hr)) return;
     hr = IJsonValue_get_ValueType( json_value, &json_value_type );
     ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr );
     ok_(__FILE__, line)( json_value_type == expected_json_value_type, "got json_value_type %d.\n", json_value_type );
@@ -187,13 +575,11 @@ static void check_json_( unsigned int line, IJsonValueStatics *json_value_static
             break;
         case JsonValueType_Array:
             hr = IJsonValue_GetArray( json_value, &json_array );
-            todo_wine
             ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr );
             if (hr == S_OK) IJsonArray_Release( json_array );
             break;
         case JsonValueType_Object:
             hr = IJsonValue_GetObject( json_value, &json_object );
-            todo_wine
             ok_(__FILE__, line)( hr == S_OK, "got hr %#lx.\n", hr );
             if (hr == S_OK) IJsonObject_Release( json_object );
             break;
@@ -260,6 +646,30 @@ static void test_JsonValueStatics(void)
     hr = IActivationFactory_QueryInterface( factory, &IID_IJsonValueStatics, (void **)&json_value_statics );
     ok( hr == S_OK, "got hr %#lx.\n", hr );
 
+    hr = IJsonValueStatics_CreateBooleanValue( json_value_statics, FALSE, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_CreateBooleanValue( json_value_statics, FALSE, &json_value );
+    ok( hr == S_OK, "got hr %#lx,\n", hr );
+    hr = IJsonValue_get_ValueType( json_value, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonValue_get_ValueType( json_value, &json_value_type );
+    ok( json_value_type == JsonValueType_Boolean, "got JsonValueType %d.\n", json_value_type );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    ref = IJsonValue_Release( json_value );
+    ok( ref == 0, "got ref %ld.\n", ref );
+
+    hr = IJsonValueStatics_CreateNumberValue( json_value_statics, 0, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_CreateNumberValue( json_value_statics, 0, &json_value );
+    ok( hr == S_OK, "got hr %#lx,\n", hr );
+    hr = IJsonValue_get_ValueType( json_value, NULL );
+    ok( hr == E_POINTER, "got hr %#lx.\n", hr );
+    hr = IJsonValue_get_ValueType( json_value, &json_value_type );
+    ok( json_value_type == JsonValueType_Number, "got JsonValueType %d.\n", json_value_type );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    ref = IJsonValue_Release( json_value );
+    ok( ref == 0, "got ref %ld.\n", ref );
+
     hr = IJsonValueStatics_CreateStringValue( json_value_statics, NULL, &json_value );
     ok( hr == S_OK, "got hr %#lx.\n", hr );
     hr = IJsonValue_get_ValueType( json_value, NULL );
@@ -289,7 +699,6 @@ static void test_JsonValueStatics(void)
     hr = IJsonValueStatics_Parse( json_value_statics, str, NULL );
     ok( hr == E_POINTER, "got hr %#lx.\n", hr );
     hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
-    todo_wine
     ok( hr == WEB_E_INVALID_JSON_STRING, "got hr %#lx.\n", hr );
     WindowsDeleteString( str );
 
@@ -320,6 +729,31 @@ static void test_JsonValueStatics(void)
         IJsonValue_Release( json_value );
     }
 
+    json = L"\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0000\\u0057\\u0069\\u006e\\u0065\\udAbC\\uDcEf\"";
+    hr = WindowsCreateString( json, wcslen( json ), &str );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    hr = IJsonValueStatics_Parse( json_value_statics, str, &json_value );
+    ok( hr == S_OK, "got hr %#lx.\n", hr );
+    WindowsDeleteString( str );
+    if (SUCCEEDED(hr))
+    {
+        HSTRING parsed_str = NULL;
+        int res;
+
+        json = L"\"\\/\b\f\n\r\t\0Wine\U000BF0EF";
+        hr = WindowsCreateString( json, 15, &str );
+        ok( hr == S_OK, "got hr %#lx.\n", hr );
+        hr = IJsonValue_GetString( json_value, &parsed_str );
+        ok( hr == S_OK, "got hr %#lx.\n", hr );
+        hr = WindowsCompareStringOrdinal( str, parsed_str, &res );
+        ok( hr == S_OK, "got hr %#lx.\n", hr );
+        ok( res == 0, "got different HSTRINGS str = %s, parsed_str = %s.\n", wine_dbgstr_hstring( str ), wine_dbgstr_hstring( parsed_str ) );
+
+        WindowsDeleteString( parsed_str );
+        WindowsDeleteString( str );
+        IJsonValue_Release( json_value );
+    }
+
     json = L"null";
     check_json( json_value_statics, json, JsonValueType_Null, TRUE );
     json = L"false";
@@ -383,13 +817,24 @@ static void test_JsonValueStatics(void)
     check_json( json_value_statics, json, JsonValueType_String, FALSE );
     json = L"\v \"The Wine     Project\"";
     check_json( json_value_statics, json, JsonValueType_String, FALSE );
+    json = L"\"\\\"";
+    check_json( json_value_statics, json, JsonValueType_String, FALSE );
+    json = L"\"\\u123\"";
+    check_json( json_value_statics, json, JsonValueType_String, FALSE );
     json = L"[\"Wine\" \"Linux\"]";
     check_json( json_value_statics, json, JsonValueType_Array, FALSE );
+    json = L"[\"Wine\", \"Linux\",]";
+    check_json( json_value_statics, json, JsonValueType_Array, FALSE );
     json = L"{"
             "    \"Wine\": \"The Wine Project\","
             "    \"Linux\": [\"Arch\", \"BTW\"]"
             "";
     check_json( json_value_statics, json, JsonValueType_Object, FALSE );
+    json = L"{"
+            "    \"Wine\": \"The Wine Project\","
+            "    \"Linux\": [\"Arch\", \"BTW\"],"
+            "}";
+    check_json( json_value_statics, json, JsonValueType_Object, FALSE );
 
     ref = IJsonValueStatics_Release( json_value_statics );
     ok( ref == 2, "got ref %ld.\n", ref );
@@ -404,6 +849,7 @@ START_TEST(web)
     hr = RoInitialize( RO_INIT_MULTITHREADED );
     ok( hr == S_OK, "RoInitialize failed, hr %#lx\n", hr );
 
+    test_JsonArrayStatics();
     test_JsonObjectStatics();
     test_JsonValueStatics();
 
diff --git a/dlls/wineandroid.drv/AndroidManifest.xml b/dlls/wineandroid.drv/AndroidManifest.xml
index 574b98e3820b..7f0a5e6ce64c 100644
--- a/dlls/wineandroid.drv/AndroidManifest.xml
+++ b/dlls/wineandroid.drv/AndroidManifest.xml
@@ -9,6 +9,7 @@
         android:icon="@drawable/wine"
         android:label="Wine" >
         <activity
+            android:exported="true"
             android:label="Wine"
             android:name=".WineActivity"
             android:launchMode="singleInstance"
diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h
index 16d609111746..3107136cb7e9 100644
--- a/dlls/wineandroid.drv/android.h
+++ b/dlls/wineandroid.drv/android.h
@@ -119,7 +119,7 @@ enum android_window_messages
     WM_ANDROID_REFRESH = WM_WINE_FIRST_DRIVER_MSG,
 };
 
-extern void init_gralloc( const struct hw_module_t *module );
+extern void init_ahardwarebuffers(void);
 extern HWND get_capture_window(void);
 extern void init_monitors( int width, int height );
 extern void set_screen_dpi( DWORD dpi );
diff --git a/dlls/wineandroid.drv/android_native.h b/dlls/wineandroid.drv/android_native.h
index fc26beb65341..7c3c49630ade 100644
--- a/dlls/wineandroid.drv/android_native.h
+++ b/dlls/wineandroid.drv/android_native.h
@@ -26,16 +26,6 @@
 
 /* Native window definitions */
 
-typedef struct native_handle
-{
-    int version;
-    int numFds;
-    int numInts;
-    int data[0];
-} native_handle_t;
-
-typedef const native_handle_t *buffer_handle_t;
-
 struct android_native_base_t
 {
     int magic;
@@ -53,18 +43,7 @@ typedef struct android_native_rect_t
     int32_t bottom;
 } android_native_rect_t;
 
-struct ANativeWindowBuffer
-{
-    struct android_native_base_t common;
-    int width;
-    int height;
-    int stride;
-    int format;
-    int usage;
-    void *reserved[2];
-    buffer_handle_t handle;
-    void *reserved_proc[8];
-};
+struct ANativeWindowBuffer;
 
 struct ANativeWindow
 {
@@ -125,9 +104,7 @@ enum native_window_perform
 enum native_window_api
 {
     NATIVE_WINDOW_API_EGL = 1,
-    NATIVE_WINDOW_API_CPU = 2,
-    NATIVE_WINDOW_API_MEDIA = 3,
-    NATIVE_WINDOW_API_CAMERA = 4
+    NATIVE_WINDOW_API_CPU = 2
 };
 
 enum android_pixel_format
@@ -141,176 +118,10 @@ enum android_pixel_format
     PF_RGBA_4444 = 7
 };
 
-
-/* Hardware module definitions */
-
-struct hw_module_methods_t;
-struct hw_device_t;
-struct android_ycbcr;
-
-struct hw_module_t
-{
-    uint32_t tag;
-    uint16_t module_api_version;
-    uint16_t hal_api_version;
-    const char *id;
-    const char *name;
-    const char *author;
-    struct hw_module_methods_t *methods;
-    void *dso;
-    void *reserved[32-7];
-};
-
-struct hw_module_methods_t
-{
-    int (*open)(const struct hw_module_t *module, const char *id, struct hw_device_t **device);
-};
-
-struct hw_device_t
-{
-    uint32_t tag;
-    uint32_t version;
-    struct hw_module_t *module;
-    void *reserved[12];
-    int (*close)(struct hw_device_t *device);
-};
-
-struct gralloc_module_t
-{
-    struct hw_module_t common;
-    int (*registerBuffer)(struct gralloc_module_t const *module, buffer_handle_t handle);
-    int (*unregisterBuffer)(struct gralloc_module_t const *module, buffer_handle_t handle);
-    int (*lock)(struct gralloc_module_t const *module, buffer_handle_t handle, int usage, int l, int t, int w, int h, void **vaddr);
-    int (*unlock)(struct gralloc_module_t const *module, buffer_handle_t handle);
-    int (*perform)(struct gralloc_module_t const *module, int operation, ... );
-    int (*lock_ycbcr)(struct gralloc_module_t const *module, buffer_handle_t handle, int usage, int l, int t, int w, int h, struct android_ycbcr *ycbcr);
-    void *reserved_proc[6];
-};
-
 #define ANDROID_NATIVE_MAKE_CONSTANT(a,b,c,d) \
     (((unsigned)(a)<<24)|((unsigned)(b)<<16)|((unsigned)(c)<<8)|(unsigned)(d))
 
 #define ANDROID_NATIVE_WINDOW_MAGIC \
     ANDROID_NATIVE_MAKE_CONSTANT('_','w','n','d')
 
-#define ANDROID_NATIVE_BUFFER_MAGIC \
-    ANDROID_NATIVE_MAKE_CONSTANT('_','b','f','r')
-
-enum gralloc_usage
-{
-    GRALLOC_USAGE_SW_READ_NEVER         = 0x00000000,
-    GRALLOC_USAGE_SW_READ_RARELY        = 0x00000002,
-    GRALLOC_USAGE_SW_READ_OFTEN         = 0x00000003,
-    GRALLOC_USAGE_SW_READ_MASK          = 0x0000000F,
-    GRALLOC_USAGE_SW_WRITE_NEVER        = 0x00000000,
-    GRALLOC_USAGE_SW_WRITE_RARELY       = 0x00000020,
-    GRALLOC_USAGE_SW_WRITE_OFTEN        = 0x00000030,
-    GRALLOC_USAGE_SW_WRITE_MASK         = 0x000000F0,
-    GRALLOC_USAGE_HW_TEXTURE            = 0x00000100,
-    GRALLOC_USAGE_HW_RENDER             = 0x00000200,
-    GRALLOC_USAGE_HW_2D                 = 0x00000400,
-    GRALLOC_USAGE_HW_COMPOSER           = 0x00000800,
-    GRALLOC_USAGE_HW_FB                 = 0x00001000,
-    GRALLOC_USAGE_HW_VIDEO_ENCODER      = 0x00010000,
-    GRALLOC_USAGE_HW_CAMERA_WRITE       = 0x00020000,
-    GRALLOC_USAGE_HW_CAMERA_READ        = 0x00040000,
-    GRALLOC_USAGE_HW_CAMERA_ZSL         = 0x00060000,
-    GRALLOC_USAGE_HW_CAMERA_MASK        = 0x00060000,
-    GRALLOC_USAGE_HW_MASK               = 0x00071F00,
-    GRALLOC_USAGE_EXTERNAL_DISP         = 0x00002000,
-    GRALLOC_USAGE_PROTECTED             = 0x00004000,
-    GRALLOC_USAGE_PRIVATE_0             = 0x10000000,
-    GRALLOC_USAGE_PRIVATE_1             = 0x20000000,
-    GRALLOC_USAGE_PRIVATE_2             = 0x40000000,
-    GRALLOC_USAGE_PRIVATE_3             = 0x80000000,
-    GRALLOC_USAGE_PRIVATE_MASK          = 0xF0000000,
-};
-
-#define GRALLOC_HARDWARE_MODULE_ID "gralloc"
-
-extern int hw_get_module(const char *id, const struct hw_module_t **module);
-
-typedef enum
-{
-    GRALLOC1_CAPABILITY_INVALID = 0,
-    GRALLOC1_CAPABILITY_TEST_ALLOCATE = 1,
-    GRALLOC1_CAPABILITY_LAYERED_BUFFERS = 2,
-    GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE = 3,
-    GRALLOC1_LAST_CAPABILITY = 3,
-} gralloc1_capability_t;
-
-typedef enum
-{
-    GRALLOC1_FUNCTION_INVALID = 0,
-    GRALLOC1_FUNCTION_DUMP = 1,
-    GRALLOC1_FUNCTION_CREATE_DESCRIPTOR = 2,
-    GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR = 3,
-    GRALLOC1_FUNCTION_SET_CONSUMER_USAGE = 4,
-    GRALLOC1_FUNCTION_SET_DIMENSIONS = 5,
-    GRALLOC1_FUNCTION_SET_FORMAT = 6,
-    GRALLOC1_FUNCTION_SET_PRODUCER_USAGE = 7,
-    GRALLOC1_FUNCTION_GET_BACKING_STORE = 8,
-    GRALLOC1_FUNCTION_GET_CONSUMER_USAGE = 9,
-    GRALLOC1_FUNCTION_GET_DIMENSIONS = 10,
-    GRALLOC1_FUNCTION_GET_FORMAT = 11,
-    GRALLOC1_FUNCTION_GET_PRODUCER_USAGE = 12,
-    GRALLOC1_FUNCTION_GET_STRIDE = 13,
-    GRALLOC1_FUNCTION_ALLOCATE = 14,
-    GRALLOC1_FUNCTION_RETAIN = 15,
-    GRALLOC1_FUNCTION_RELEASE = 16,
-    GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES = 17,
-    GRALLOC1_FUNCTION_LOCK = 18,
-    GRALLOC1_FUNCTION_LOCK_FLEX = 19,
-    GRALLOC1_FUNCTION_UNLOCK = 20,
-    GRALLOC1_FUNCTION_SET_LAYER_COUNT = 21,
-    GRALLOC1_FUNCTION_GET_LAYER_COUNT = 22,
-    GRALLOC1_FUNCTION_VALIDATE_BUFFER_SIZE = 23,
-    GRALLOC1_FUNCTION_GET_TRANSPORT_SIZE = 24,
-    GRALLOC1_FUNCTION_IMPORT_BUFFER = 25,
-    GRALLOC1_LAST_FUNCTION = 25,
-} gralloc1_function_descriptor_t;
-
-typedef enum
-{
-    GRALLOC1_ERROR_NONE = 0,
-    GRALLOC1_ERROR_BAD_DESCRIPTOR = 1,
-    GRALLOC1_ERROR_BAD_HANDLE = 2,
-    GRALLOC1_ERROR_BAD_VALUE = 3,
-    GRALLOC1_ERROR_NOT_SHARED = 4,
-    GRALLOC1_ERROR_NO_RESOURCES = 5,
-    GRALLOC1_ERROR_UNDEFINED = 6,
-    GRALLOC1_ERROR_UNSUPPORTED = 7,
-} gralloc1_error_t;
-
-typedef enum
-{
-    GRALLOC1_PRODUCER_USAGE_NONE = 0,
-    GRALLOC1_PRODUCER_USAGE_CPU_READ = 1u << 1,
-    GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN = 1u << 2 | GRALLOC1_PRODUCER_USAGE_CPU_READ,
-    GRALLOC1_PRODUCER_USAGE_CPU_WRITE = 1u << 5,
-    GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN = 1u << 6 | GRALLOC1_PRODUCER_USAGE_CPU_WRITE,
-} gralloc1_producer_usage_t;
-
-typedef enum
-{
-    GRALLOC1_CONSUMER_USAGE_NONE = 0,
-    GRALLOC1_CONSUMER_USAGE_CPU_READ = 1u << 1,
-    GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN = 1u << 2 | GRALLOC1_CONSUMER_USAGE_CPU_READ,
-} gralloc1_consumer_usage_t;
-
-typedef struct gralloc1_device
-{
-    struct hw_device_t common;
-    void (*getCapabilities)(struct gralloc1_device *device, uint32_t *outCount, int32_t *outCapabilities);
-    void* (*getFunction)(struct gralloc1_device *device, int32_t descriptor);
-} gralloc1_device_t;
-
-typedef struct gralloc1_rect
-{
-    int32_t left;
-    int32_t top;
-    int32_t width;
-    int32_t height;
-} gralloc1_rect_t;
-
 #endif /* __WINE_ANDROID_NATIVE_H */
diff --git a/dlls/wineandroid.drv/build.gradle.in b/dlls/wineandroid.drv/build.gradle.in
index 662e8b7ea22f..56ffd06ca82f 100644
--- a/dlls/wineandroid.drv/build.gradle.in
+++ b/dlls/wineandroid.drv/build.gradle.in
@@ -18,20 +18,31 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+if (GradleVersion.current() < GradleVersion.version("9.4.0")) {
+    throw new GradleException("Gradle 9.4.0+ required")
+}
+
 apply plugin: 'com.android.application'
 
 buildscript
 {
     repositories
     {
-        jcenter()
+        google()
+        mavenCentral()
     }
     dependencies
     {
-        classpath "com.android.tools.build:gradle:2.2.1"
+        classpath "com.android.tools.build:gradle:9.1.0"
     }
 }
 
+repositories
+{
+    google()
+    mavenCentral()
+}
+
 def get_srcdir()
 {
     if (srcdir.equals(".")) { return "."; }
@@ -52,32 +63,39 @@ def add_icon_task( dir, scale )
     }
 }
 
-def checksum_task()
+def checksum_task = tasks.create( "checksumAssets", Exec )
 {
-    return tasks.create( "checksumAssets", Exec ) {
-        commandLine "sh", "-c",
-                    "(test -d assets && " +
-                    "rm -f assets/files.sum assets/sums.sum && " +
-                    "sha256sum \$(find assets -type f -print) | sed 's/ assets\\// /' >files.sum && " +
-                    "sha256sum files.sum >sums.sum && " +
-                    "mv files.sum sums.sum assets) || rm -rf assets";
-    }
+    commandLine "sh", "-c",
+                "(test -d assets && " +
+                "rm -f assets/files.sum assets/sums.sum && " +
+                "sha256sum \$(find assets -type f -print) | sed 's/ assets\\// /' >files.sum && " +
+                "sha256sum files.sum >sums.sum && " +
+                "mv files.sum sums.sum assets) || rm -rf assets";
 }
 
-tasks.whenTaskAdded
+def icon_tasks = [
+    add_icon_task( "ldpi", 0.75 ),
+    add_icon_task( "mdpi", 1 ),
+    add_icon_task( "hdpi", 1.5 ),
+    add_icon_task( "xhdpi", 2 ),
+    add_icon_task( "xxhdpi", 3 ),
+    add_icon_task( "xxxhdpi", 4 )
+]
+
+tasks.configureEach
 {
-    if (name.equals( "generateDebugResources" ))
+    if (name.equals( "preBuild" ) ||
+        name.equals( "processDebugResources" ) ||
+        name.equals( "processDebugNavigationResources" ) ||
+        name.equals( "mergeDebugResources" ))
     {
-        dependsOn add_icon_task( "ldpi", 0.75 )
-        dependsOn add_icon_task( "mdpi", 1 )
-        dependsOn add_icon_task( "hdpi", 1.5 )
-        dependsOn add_icon_task( "xhdpi", 2 )
-        dependsOn add_icon_task( "xxhdpi", 3 )
-        dependsOn add_icon_task( "xxxhdpi", 4 )
+        dependsOn icon_tasks
     }
-    if (name.equals( "generateDebugAssets" ))
+    if (name.equals( "preBuild" ) ||
+        name.equals( "generateDebugAssets" ) ||
+        name.equals( "mergeDebugAssets" ))
     {
-        dependsOn checksum_task()
+        dependsOn checksum_task
     }
 }
 
@@ -88,16 +106,15 @@ tasks.withType(JavaCompile)
 
 android
 {
-    compileSdkVersion 25
-    buildToolsVersion "25.0.3"
+    namespace "org.winehq.wine"
+    compileSdkVersion 36
 
     defaultConfig
     {
         applicationId "org.winehq.wine"
-        minSdkVersion 17
+        minSdkVersion 26
         versionCode 1
         versionName "@PACKAGE_VERSION@"
-        setProperty( "archivesBaseName", "wine" )
     }
 
     sourceSets
@@ -110,3 +127,19 @@ android
         main.manifest.srcFile get_srcdir() + "/AndroidManifest.xml"
     }
 }
+
+configurations.configureEach
+{
+    exclude group: "org.jetbrains.kotlin", module: "kotlin-stdlib"
+}
+
+androidComponents
+{
+    onVariants(selector().all())
+    { variant ->
+        variant.outputs.forEach
+        { output ->
+            output.outputFileName.set("wine-${variant.name}.apk")
+        }
+    }
+}
diff --git a/dlls/wineandroid.drv/device.c b/dlls/wineandroid.drv/device.c
index b976968f092e..3d77033a9807 100644
--- a/dlls/wineandroid.drv/device.c
+++ b/dlls/wineandroid.drv/device.c
@@ -24,11 +24,14 @@
 
 #include "config.h"
 
+#define __ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__
+
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <sys/ioctl.h>
+#include <sys/socket.h>
 #include <unistd.h>
 
 #include "ntstatus.h"
@@ -41,8 +44,23 @@
 #include "wine/server.h"
 #include "wine/debug.h"
 
+#include <dlfcn.h>
+
 WINE_DEFAULT_DEBUG_CHANNEL(android);
 
+#define DECL_FUNCPTR(f) static typeof(f) * p##f = NULL
+
+struct AHardwareBuffer* ANativeWindowBuffer_getHardwareBuffer(struct ANativeWindowBuffer* anwb) __INTRODUCED_IN(26);
+
+DECL_FUNCPTR( AHardwareBuffer_describe );
+DECL_FUNCPTR( AHardwareBuffer_acquire );
+DECL_FUNCPTR( AHardwareBuffer_release );
+DECL_FUNCPTR( AHardwareBuffer_lock );
+DECL_FUNCPTR( AHardwareBuffer_unlock );
+DECL_FUNCPTR( AHardwareBuffer_recvHandleFromUnixSocket );
+DECL_FUNCPTR( AHardwareBuffer_sendHandleToUnixSocket );
+DECL_FUNCPTR( ANativeWindowBuffer_getHardwareBuffer );
+
 #ifndef SYNC_IOC_WAIT
 #define SYNC_IOC_WAIT _IOW('>', 0, __s32)
 #endif
@@ -74,21 +92,11 @@ enum android_ioctl
 
 #define NB_CACHED_BUFFERS 4
 
-struct native_buffer_wrapper;
-
-/* buffer for storing a variable-size native handle inside an ioctl structure */
-union native_handle_buffer
-{
-    native_handle_t handle;
-    int space[256];
-};
-
 /* data about the native window in the context of the Java process */
 struct native_win_data
 {
     struct ANativeWindow       *parent;
-    struct ANativeWindowBuffer *buffers[NB_CACHED_BUFFERS];
-    void                       *mappings[NB_CACHED_BUFFERS];
+    struct AHardwareBuffer *buffers[NB_CACHED_BUFFERS];
     HWND                        hwnd;
     BOOL                        opengl;
     int                         generation;
@@ -102,25 +110,18 @@ struct native_win_data
 struct native_win_wrapper
 {
     struct ANativeWindow          win;
-    struct native_buffer_wrapper *buffers[NB_CACHED_BUFFERS];
-    struct ANativeWindowBuffer   *locked_buffer;
+    struct
+    {
+        struct AHardwareBuffer   *self;
+        int                       buffer_id;
+        int                       generation;
+    } buffers[NB_CACHED_BUFFERS];
+    struct AHardwareBuffer       *locked_buffer;
     HWND                          hwnd;
     BOOL                          opengl;
     LONG                          ref;
 };
 
-/* wrapper for a native buffer in the context of the client (non-Java) process */
-struct native_buffer_wrapper
-{
-    struct ANativeWindowBuffer buffer;
-    LONG                       ref;
-    HWND                       hwnd;
-    void                      *bits;
-    int                        buffer_id;
-    int                        generation;
-    union native_handle_buffer native_handle;
-};
-
 struct ioctl_header
 {
     int  hwnd;
@@ -132,7 +133,7 @@ struct ioctl_android_create_window
     struct ioctl_header hdr;
     int                 parent;
     float               scale;
-    bool                is_desktop;
+    BOOL                is_desktop;
 };
 
 struct ioctl_android_destroy_window
@@ -155,15 +156,9 @@ struct ioctl_android_window_pos_changed
 struct ioctl_android_dequeueBuffer
 {
     struct ioctl_header hdr;
-    int                 win32;
-    int                 width;
-    int                 height;
-    int                 stride;
-    int                 format;
-    int                 usage;
-    int                 buffer_id;
-    int                 generation;
-    union native_handle_buffer native_handle;
+    HANDLE handle;
+    int buffer_id;
+    int generation;
 };
 
 struct ioctl_android_queueBuffer
@@ -223,18 +218,6 @@ struct ioctl_android_set_cursor
     int                 bits[1];
 };
 
-static struct gralloc_module_t *gralloc_module;
-static struct gralloc1_device *gralloc1_device;
-static BOOL gralloc1_caps[GRALLOC1_LAST_CAPABILITY + 1];
-
-static gralloc1_error_t (*gralloc1_retain)( gralloc1_device_t *device, buffer_handle_t buffer );
-static gralloc1_error_t (*gralloc1_release)( gralloc1_device_t *device, buffer_handle_t buffer );
-static gralloc1_error_t (*gralloc1_lock)( gralloc1_device_t *device, buffer_handle_t buffer,
-                                          uint64_t producerUsage, uint64_t consumerUsage,
-                                          const gralloc1_rect_t *accessRegion, void **outData,
-                                          int32_t acquireFence );
-static gralloc1_error_t (*gralloc1_unlock)( gralloc1_device_t *device, buffer_handle_t buffer,
-                                            int32_t *outReleaseFence );
 
 static inline BOOL is_in_desktop_process(void)
 {
@@ -247,11 +230,6 @@ static inline DWORD current_client_id(void)
     return client_id ? client_id : GetCurrentProcessId();
 }
 
-static inline BOOL is_client_in_process(void)
-{
-    return current_client_id() == GetCurrentProcessId();
-}
-
 #ifdef __i386__  /* the Java VM uses %fs/%gs for its own purposes, so we need to wrap the calls */
 
 static WORD orig_fs, java_fs;
@@ -327,75 +305,46 @@ static void wait_fence_and_close( int fence )
     close( fence );
 }
 
-static int duplicate_fd( HANDLE client, int fd )
+static inline struct ANativeWindowBuffer *anwb_from_ahb(AHardwareBuffer *ahb)
 {
-    HANDLE handle, ret = 0;
+    static ptrdiff_t off = (ptrdiff_t)-1;
 
-    if (!wine_server_fd_to_handle( dup(fd), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
-        NtDuplicateObject( GetCurrentProcess(), handle, client, &ret,
-                           0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
-
-    if (!ret) return -1;
-    return HandleToLong( ret );
-}
+    if (!ahb) return NULL;
 
-static int map_native_handle( union native_handle_buffer *dest, const native_handle_t *src,
-                              HANDLE mapping, HANDLE client )
-{
-    const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
-    int i;
-
-    if (mapping)  /* only duplicate the mapping handle */
-    {
-        HANDLE ret = 0;
-        if (!NtDuplicateObject( GetCurrentProcess(), mapping, client, &ret,
-                                0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE ))
-            return -ENOSPC;
-        dest->handle.numFds = 0;
-        dest->handle.numInts = 1;
-        dest->handle.data[0] = HandleToLong( ret );
-        return 0;
-    }
-    if (is_client_in_process())  /* transfer the actual handle pointer */
+    if (off == (ptrdiff_t)-1)
     {
-        dest->handle.numFds = 0;
-        dest->handle.numInts = sizeof(src) / sizeof(int);
-        memcpy( dest->handle.data, &src, sizeof(src) );
-        return 0;
+        struct ANativeWindowBuffer *fake =
+        (struct ANativeWindowBuffer *)(uintptr_t)0x10000u;
+
+        AHardwareBuffer *h = pANativeWindowBuffer_getHardwareBuffer(fake);
+        off = (const char *)h - (const char *)fake;
     }
-    if (size > sizeof(*dest)) return -ENOSPC;
-    memcpy( dest, src, size );
-    /* transfer file descriptors to the client process */
-    for (i = 0; i < dest->handle.numFds; i++)
-        dest->handle.data[i] = duplicate_fd( client, src->data[i] );
-    return 0;
+
+    return (struct ANativeWindowBuffer *)((char *)ahb - off);
 }
 
-static native_handle_t *unmap_native_handle( const native_handle_t *src )
+static AHardwareBuffer *ahb_from_anwb( struct native_win_wrapper *win, struct ANativeWindowBuffer *buffer, int *buffer_id, int *generation )
 {
-    const size_t size = offsetof( native_handle_t, data[src->numFds + src->numInts] );
-    native_handle_t *dest;
-    int i;
+    AHardwareBuffer *ahb;
+    unsigned int i;
 
-    if (!is_in_desktop_process())
+    if (!buffer) return NULL;
+
+    ahb = pANativeWindowBuffer_getHardwareBuffer(buffer);
+
+    if (win)
     {
-        dest = malloc( size );
-        memcpy( dest, src, size );
-        /* fetch file descriptors passed from the server process */
-        for (i = 0; i < dest->numFds; i++)
-            wine_server_handle_to_fd( LongToHandle(src->data[i]), GENERIC_READ | SYNCHRONIZE,
-                                      &dest->data[i], NULL );
-    }
-    else memcpy( &dest, src->data, sizeof(dest) );
-    return dest;
-}
+        for (i = 0; i < NB_CACHED_BUFFERS; ++i)
+        {
+            if (win->buffers[i].self != ahb) continue;
 
-static void close_native_handle( native_handle_t *handle )
-{
-    int i;
+            if (buffer_id) *buffer_id = win->buffers[i].buffer_id;
+            if (generation) *generation = win->buffers[i].generation;
+            break;
+        }
+    }
 
-    for (i = 0; i < handle->numFds; i++) close( handle->data[i] );
-    free( handle );
+    return ahb;
 }
 
 /* insert a buffer index at the head of the LRU list */
@@ -414,8 +363,7 @@ static void insert_buffer_lru( struct native_win_data *win, int index )
     win->buffer_lru[0] = index;
 }
 
-static int register_buffer( struct native_win_data *win, struct ANativeWindowBuffer *buffer,
-                            HANDLE *mapping, int *is_new )
+static int register_buffer( struct native_win_data *win, struct AHardwareBuffer *buffer, int *is_new )
 {
     unsigned int i;
 
@@ -434,27 +382,12 @@ static int register_buffer( struct native_win_data *win, struct ANativeWindowBuf
 
         TRACE( "%p %p evicting buffer %p id %d from cache\n",
                win->hwnd, win->parent, win->buffers[i], i );
-        win->buffers[i]->common.decRef( &win->buffers[i]->common );
-        if (win->mappings[i]) NtUnmapViewOfSection( GetCurrentProcess(), win->mappings[i] );
+        pAHardwareBuffer_release(win->buffers[i]);
     }
 
     win->buffers[i] = buffer;
-    win->mappings[i] = NULL;
 
-    if (mapping)
-    {
-        OBJECT_ATTRIBUTES attr;
-        LARGE_INTEGER size;
-        SIZE_T count = 0;
-        size.QuadPart = buffer->stride * buffer->height * 4;
-        InitializeObjectAttributes( &attr, NULL, OBJ_OPENIF, NULL, NULL );
-        NtCreateSection( mapping,
-                         STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ | SECTION_MAP_WRITE,
-                         &attr, &size, PAGE_READWRITE, 0, INVALID_HANDLE_VALUE );
-        NtMapViewOfSection( *mapping, GetCurrentProcess(), &win->mappings[i], 0, 0,
-                            NULL, &count, ViewShare, 0, PAGE_READONLY );
-    }
-    buffer->common.incRef( &buffer->common );
+    pAHardwareBuffer_acquire(buffer);
     *is_new = 1;
     TRACE( "%p %p %p -> %d\n", win->hwnd, win->parent, buffer, i );
 
@@ -470,7 +403,7 @@ static struct ANativeWindowBuffer *get_registered_buffer( struct native_win_data
         ERR( "unknown buffer %d for %p %p\n", id, win->hwnd, win->parent );
         return NULL;
     }
-    return win->buffers[id];
+    return anwb_from_ahb(win->buffers[id]);
 }
 
 static void release_native_window( struct native_win_data *data )
@@ -480,12 +413,10 @@ static void release_native_window( struct native_win_data *data )
     if (data->parent) pANativeWindow_release( data->parent );
     for (i = 0; i < NB_CACHED_BUFFERS; i++)
     {
-        if (data->buffers[i]) data->buffers[i]->common.decRef( &data->buffers[i]->common );
-        if (data->mappings[i]) NtUnmapViewOfSection( GetCurrentProcess(), data->mappings[i] );
+        if (data->buffers[i]) pAHardwareBuffer_release(data->buffers[i]);
         data->buffer_lru[i] = -1;
     }
     memset( data->buffers, 0, sizeof(data->buffers) );
-    memset( data->mappings, 0, sizeof(data->mappings) );
 }
 
 static void free_native_win_data( struct native_win_data *data )
@@ -555,93 +486,36 @@ void register_native_window( HWND hwnd, struct ANativeWindow *win, BOOL opengl )
     NtQueueApcThread( thread, register_window_callback, (ULONG_PTR)hwnd, (ULONG_PTR)win, opengl );
 }
 
-void init_gralloc( const struct hw_module_t *module )
+#define LOAD_FUNCPTR(lib, func) do { \
+    const char *err; \
+    dlerror(); \
+    p##func = dlsym( lib, #func ); \
+    if (!p##func) \
+    { \
+        err = dlerror(); \
+        ERR( "can't find symbol %s: %s\n", #func, err ? err : "unknown error" ); \
+        abort(); \
+    } \
+} while (0)
+void init_ahardwarebuffers(void)
 {
-    struct hw_device_t *device;
-    int ret;
-
-    TRACE( "got module %p ver %u.%u id %s name %s author %s\n",
-           module, module->module_api_version >> 8, module->module_api_version & 0xff,
-           debugstr_a(module->id), debugstr_a(module->name), debugstr_a(module->author) );
+    void *libandroid;
 
-    switch (module->module_api_version >> 8)
+    if (!(libandroid = dlopen( "libandroid.so", RTLD_NOW )))
     {
-    case 0:
-        gralloc_module = (struct gralloc_module_t *)module;
-        break;
-    case 1:
-        if (!(ret = module->methods->open( module, GRALLOC_HARDWARE_MODULE_ID, &device )))
-        {
-            int32_t caps[64];
-            uint32_t i, count = ARRAY_SIZE(caps);
-
-            gralloc1_device = (struct gralloc1_device *)device;
-            gralloc1_retain  = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_RETAIN );
-            gralloc1_release = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_RELEASE );
-            gralloc1_lock    = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_LOCK );
-            gralloc1_unlock  = gralloc1_device->getFunction( gralloc1_device, GRALLOC1_FUNCTION_UNLOCK );
-            TRACE( "got device version %u funcs %p %p %p %p\n", device->version,
-                   gralloc1_retain, gralloc1_release, gralloc1_lock, gralloc1_unlock );
-
-            gralloc1_device->getCapabilities( gralloc1_device, &count, caps );
-            if (count == ARRAY_SIZE(caps)) ERR( "too many gralloc capabilities\n" );
-            for (i = 0; i < count; i++)
-                if (caps[i] < ARRAY_SIZE(gralloc1_caps)) gralloc1_caps[caps[i]] = TRUE;
-        }
-        else ERR( "failed to open gralloc err %d\n", ret );
-        break;
-    default:
-        ERR( "unknown gralloc module version %u\n", module->module_api_version >> 8 );
-        break;
+        const char *err = dlerror();
+        ERR( "failed to dlopen libandroid.so: %s\n", err ? err : "unknown error" );
+        abort();
     }
-}
 
-static int gralloc_grab_buffer( struct ANativeWindowBuffer *buffer )
-{
-    if (gralloc1_device)
-        return gralloc1_retain( gralloc1_device, buffer->handle );
-    if (gralloc_module)
-        return gralloc_module->registerBuffer( gralloc_module, buffer->handle );
-    return -ENODEV;
-}
-
-static void gralloc_release_buffer( struct ANativeWindowBuffer *buffer )
-{
-    if (gralloc1_device) gralloc1_release( gralloc1_device, buffer->handle );
-    else if (gralloc_module) gralloc_module->unregisterBuffer( gralloc_module, buffer->handle );
-
-    if (!gralloc1_caps[GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE])
-        close_native_handle( (native_handle_t *)buffer->handle );
-}
-
-static int gralloc_lock( struct ANativeWindowBuffer *buffer, void **bits )
-{
-    if (gralloc1_device)
-    {
-        gralloc1_rect_t rect = { 0, 0, buffer->width, buffer->height };
-        return gralloc1_lock( gralloc1_device, buffer->handle,
-                              GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN |
-                              GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN,
-                              GRALLOC1_CONSUMER_USAGE_NONE, &rect, bits, -1 );
-    }
-    if (gralloc_module)
-        return gralloc_module->lock( gralloc_module, buffer->handle,
-                                     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-                                     0, 0, buffer->width, buffer->height, bits );
-
-    *bits = ((struct native_buffer_wrapper *)buffer)->bits;
-    return 0;
-}
-
-static void gralloc_unlock( struct ANativeWindowBuffer *buffer )
-{
-    if (gralloc1_device)
-    {
-        int fence;
-        gralloc1_unlock( gralloc1_device, buffer->handle, &fence );
-        wait_fence_and_close( fence );
-    }
-    else if (gralloc_module) gralloc_module->unlock( gralloc_module, buffer->handle );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_describe );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_acquire );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_release );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_lock );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_unlock );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_recvHandleFromUnixSocket );
+    LOAD_FUNCPTR( libandroid, AHardwareBuffer_sendHandleToUnixSocket );
+    LOAD_FUNCPTR( libandroid, ANativeWindowBuffer_getHardwareBuffer );
 }
 
 /* get the capture window stored in the desktop process */
@@ -805,53 +679,97 @@ static NTSTATUS dequeueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size,
     struct ioctl_android_dequeueBuffer *res = data;
     struct native_win_data *win_data;
     struct ANativeWindowBuffer *buffer = NULL;
+    AHardwareBuffer *ahb = NULL;
     int fence, ret, is_new;
 
     if (out_size < sizeof( *res )) return STATUS_BUFFER_OVERFLOW;
-
-    if (in_size < offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
-        return STATUS_INVALID_PARAMETER;
+    if (in_size < sizeof(res->hdr)) return STATUS_INVALID_PARAMETER;
 
     if (!(win_data = get_ioctl_native_win_data( &res->hdr ))) return STATUS_INVALID_HANDLE;
     if (!(parent = win_data->parent)) return STATUS_DEVICE_NOT_READY;
 
-    *ret_size = offsetof( struct ioctl_android_dequeueBuffer, native_handle );
+    res->handle = 0;
+    res->buffer_id = -1;
+    res->generation = 0;
+    *ret_size = sizeof(*res);
+
     wrap_java_call();
     ret = parent->dequeueBuffer( parent, &buffer, &fence );
     unwrap_java_call();
-    if (!ret)
+    if (ret)
+    {
+        ERR( "%08x failed %d\n", res->hdr.hwnd, ret );
+        return android_error_to_status( ret );
+    }
+
+    if (!buffer)
+    {
+        TRACE( "got invalid buffer\n" );
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence );
+    ahb = pANativeWindowBuffer_getHardwareBuffer( buffer );
+
+    res->buffer_id = register_buffer( win_data, ahb, &is_new );
+    res->generation = win_data->generation;
+    res->handle = 0;
+
+    if (is_new)
     {
-        HANDLE mapping = 0;
+        int sv[2] = { -1, -1 };
+        HANDLE local = 0;
+        OBJECT_ATTRIBUTES attr = { .Length = sizeof(attr) };
+        CLIENT_ID cid = { .UniqueProcess = UlongToHandle( current_client_id() ) };
+        HANDLE process;
 
-        if (!buffer)
+        if (!ahb)
         {
-            TRACE( "got invalid buffer\n" );
+            wait_fence_and_close( fence );
             return STATUS_UNSUCCESSFUL;
         }
 
-        TRACE( "%08x got buffer %p fence %d\n", res->hdr.hwnd, buffer, fence );
-        res->width  = buffer->width;
-        res->height = buffer->height;
-        res->stride = buffer->stride;
-        res->format = buffer->format;
-        res->usage  = buffer->usage;
-        res->buffer_id = register_buffer( win_data, buffer, res->win32 ? &mapping : NULL, &is_new );
-        res->generation = win_data->generation;
-        if (is_new)
+        if (socketpair( AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv ) < 0)
         {
-            OBJECT_ATTRIBUTES attr = { .Length = sizeof(attr) };
-            CLIENT_ID cid = { .UniqueProcess = UlongToHandle( current_client_id() ) };
-            HANDLE process;
-            NtOpenProcess( &process, PROCESS_DUP_HANDLE, &attr, &cid );
-            map_native_handle( &res->native_handle, buffer->handle, mapping, process );
-            NtClose( process );
-            *ret_size = sizeof( *res );
+            wait_fence_and_close( fence );
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        if (NtOpenProcess( &process, PROCESS_DUP_HANDLE, &attr, &cid ))
+        {
+            close( sv[0] );
+            close( sv[1] );
+            wait_fence_and_close( fence );
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        if (!wine_server_fd_to_handle( dup(sv[1]), GENERIC_READ | SYNCHRONIZE, 0, &local ))
+        {
+            NTSTATUS status = NtDuplicateObject( GetCurrentProcess(), local, process, &res->handle, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
+            if (status && local) NtClose( local );
+        }
+
+        NtClose( process );
+        close( sv[1] );
+
+        if (!res->handle)
+        {
+            close( sv[0] );
+            wait_fence_and_close( fence );
+            return STATUS_UNSUCCESSFUL;
+        }
+
+        ret = pAHardwareBuffer_sendHandleToUnixSocket( ahb, sv[0] );
+        close( sv[0] );
+        if (ret)
+        {
+            wait_fence_and_close( fence );
+            return android_error_to_status( ret );
         }
-        wait_fence_and_close( fence );
-        return STATUS_SUCCESS;
     }
-    ERR( "%08x failed %d\n", res->hdr.hwnd, ret );
-    return android_error_to_status( ret );
+
+    wait_fence_and_close( fence );
+    return STATUS_SUCCESS;
 }
 
 static NTSTATUS cancelBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, ULONG_PTR *ret_size )
@@ -893,15 +811,7 @@ static NTSTATUS queueBuffer_ioctl( void *data, DWORD in_size, DWORD out_size, UL
 
     if (!(buffer = get_registered_buffer( win_data, res->buffer_id ))) return STATUS_INVALID_HANDLE;
 
-    TRACE( "%08x buffer %p mapping %p\n", res->hdr.hwnd, buffer, win_data->mappings[res->buffer_id] );
-    if (win_data->mappings[res->buffer_id])
-    {
-        void *bits;
-        ret = gralloc_lock( buffer, &bits );
-        if (ret) return android_error_to_status( ret );
-        memcpy( bits, win_data->mappings[res->buffer_id], buffer->stride * buffer->height * 4 );
-        gralloc_unlock( buffer );
-    }
+    TRACE( "%08x buffer %p\n", res->hdr.hwnd, buffer );
     wrap_java_call();
     ret = parent->queueBuffer( parent, buffer, -1 );
     unwrap_java_call();
@@ -1239,98 +1149,72 @@ static void win_decRef( struct android_native_base_t *base )
     InterlockedDecrement( &win->ref );
 }
 
-static void buffer_incRef( struct android_native_base_t *base )
-{
-    struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
-    InterlockedIncrement( &buffer->ref );
-}
-
-static void buffer_decRef( struct android_native_base_t *base )
-{
-    struct native_buffer_wrapper *buffer = (struct native_buffer_wrapper *)base;
-
-    if (!InterlockedDecrement( &buffer->ref ))
-    {
-        if (!is_in_desktop_process()) gralloc_release_buffer( &buffer->buffer );
-        if (buffer->bits) NtUnmapViewOfSection( GetCurrentProcess(), buffer->bits );
-        free( buffer );
-    }
-}
-
 static int dequeueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer **buffer, int *fence )
 {
     struct native_win_wrapper *win = (struct native_win_wrapper *)window;
     struct ioctl_android_dequeueBuffer res = {0};
     DWORD size = sizeof(res);
-    int ret, use_win32 = !gralloc_module && !gralloc1_device;
+    int ret;
 
     res.hdr.hwnd = HandleToLong( win->hwnd );
     res.hdr.opengl = win->opengl;
-    res.win32 = use_win32;
-    ret = android_ioctl( IOCTL_DEQUEUE_BUFFER,
-                         &res, offsetof( struct ioctl_android_dequeueBuffer, native_handle ),
-                         &res, &size );
+    res.handle = 0;
+    res.buffer_id = -1;
+    res.generation = 0;
+
+    ret = android_ioctl( IOCTL_DEQUEUE_BUFFER, &res, sizeof(res.hdr), &res, &size );
     if (ret) return ret;
+    if (size < sizeof(res)) return -EINVAL;
+
+    if (res.buffer_id < 0 || res.buffer_id >= NB_CACHED_BUFFERS) return -EINVAL;
 
-    /* if we received the native handle, this is a new buffer */
-    if (size > offsetof( struct ioctl_android_dequeueBuffer, native_handle ))
+    if (res.handle)
     {
-        struct native_buffer_wrapper *buf = calloc( 1, sizeof(*buf) );
-
-        buf->buffer.common.magic   = ANDROID_NATIVE_BUFFER_MAGIC;
-        buf->buffer.common.version = sizeof( buf->buffer );
-        buf->buffer.common.incRef  = buffer_incRef;
-        buf->buffer.common.decRef  = buffer_decRef;
-        buf->buffer.width          = res.width;
-        buf->buffer.height         = res.height;
-        buf->buffer.stride         = res.stride;
-        buf->buffer.format         = res.format;
-        buf->buffer.usage          = res.usage;
-        buf->buffer.handle         = unmap_native_handle( &res.native_handle.handle );
-        buf->ref                   = 1;
-        buf->hwnd                  = win->hwnd;
-        buf->buffer_id             = res.buffer_id;
-        buf->generation            = res.generation;
-        if (win->buffers[res.buffer_id])
-            win->buffers[res.buffer_id]->buffer.common.decRef(&win->buffers[res.buffer_id]->buffer.common);
-        win->buffers[res.buffer_id] = buf;
-
-        if (use_win32)
-        {
-            LARGE_INTEGER zero = { .QuadPart = 0 };
-            SIZE_T count = 0;
-            HANDLE mapping = LongToHandle( res.native_handle.handle.data[0] );
-            NtMapViewOfSection( mapping, GetCurrentProcess(), &buf->bits, 0, 0, &zero, &count,
-                                ViewShare, 0, PAGE_READWRITE );
-            NtClose( mapping );
-        }
-        else if (!is_in_desktop_process())
+        AHardwareBuffer *ahb = NULL;
+        int fd;
+
+        if (wine_server_handle_to_fd( res.handle, GENERIC_READ | SYNCHRONIZE, &fd, NULL ))
         {
-            if ((ret = gralloc_grab_buffer( &buf->buffer )) < 0)
-                WARN( "hwnd %p, buffer %p failed to register %d %s\n",
-                      win->hwnd, &buf->buffer, ret, strerror(-ret) );
+            NtClose( res.handle );
+            return -EINVAL;
         }
+        NtClose( res.handle );
+
+        ret = pAHardwareBuffer_recvHandleFromUnixSocket( fd, &ahb );
+        close( fd );
+        if (ret) return ret;
+
+        if (win->buffers[res.buffer_id].self)
+            pAHardwareBuffer_release( win->buffers[res.buffer_id].self );
+
+        win->buffers[res.buffer_id].self = ahb;
+        win->buffers[res.buffer_id].buffer_id = res.buffer_id;
+        win->buffers[res.buffer_id].generation = res.generation;
     }
 
-    *buffer = &win->buffers[res.buffer_id]->buffer;
+    if (!win->buffers[res.buffer_id].self) return -EINVAL;
+
+    *buffer = anwb_from_ahb(win->buffers[res.buffer_id].self);
     *fence = -1;
 
-    TRACE( "hwnd %p, buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
-           win->hwnd, *buffer, res.width, res.height, res.stride, res.format, res.usage, *fence );
+    TRACE( "hwnd %p, buffer %p id %d gen %d fence %d\n",
+           win->hwnd, *buffer, res.buffer_id, res.generation, *fence );
     return 0;
 }
 
 static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
 {
     struct native_win_wrapper *win = (struct native_win_wrapper *)window;
-    struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
     struct ioctl_android_cancelBuffer cancel;
 
-    TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
-           win->hwnd, buffer, buffer->width, buffer->height,
-           buffer->stride, buffer->format, buffer->usage, fence );
-    cancel.buffer_id = buf->buffer_id;
-    cancel.generation = buf->generation;
+    TRACE( "hwnd %p buffer %p fence %d\n", win->hwnd, buffer, fence );
+
+    if (!ahb_from_anwb( win, buffer, &cancel.buffer_id, &cancel.generation ))
+    {
+        wait_fence_and_close( fence );
+        return -EINVAL;
+    }
+
     cancel.hdr.hwnd = HandleToLong( win->hwnd );
     cancel.hdr.opengl = win->opengl;
     wait_fence_and_close( fence );
@@ -1340,14 +1224,16 @@ static int cancelBuffer( struct ANativeWindow *window, struct ANativeWindowBuffe
 static int queueBuffer( struct ANativeWindow *window, struct ANativeWindowBuffer *buffer, int fence )
 {
     struct native_win_wrapper *win = (struct native_win_wrapper *)window;
-    struct native_buffer_wrapper *buf = (struct native_buffer_wrapper *)buffer;
     struct ioctl_android_queueBuffer queue;
 
-    TRACE( "hwnd %p buffer %p %dx%d stride %d fmt %d usage %d fence %d\n",
-           win->hwnd, buffer, buffer->width, buffer->height,
-           buffer->stride, buffer->format, buffer->usage, fence );
-    queue.buffer_id = buf->buffer_id;
-    queue.generation = buf->generation;
+    TRACE( "hwnd %p buffer %p fence %d\n", win->hwnd, buffer, fence );
+
+    if (!ahb_from_anwb( win, buffer, &queue.buffer_id, &queue.generation ))
+    {
+        wait_fence_and_close( fence );
+        return -EINVAL;
+    }
+
     queue.hdr.hwnd = HandleToLong( win->hwnd );
     queue.hdr.opengl = win->opengl;
     wait_fence_and_close( fence );
@@ -1476,6 +1362,7 @@ static int perform( ANativeWindow *window, int operation, ... )
     {
         struct ANativeWindowBuffer *buffer = NULL;
         struct ANativeWindow_Buffer *buffer_ret = va_arg( args, ANativeWindow_Buffer * );
+        struct AHardwareBuffer* b = NULL;
         ARect *bounds = va_arg( args, ARect * );
         int ret = window->dequeueBuffer_DEPRECATED( window, &buffer );
         if (!ret && !buffer)
@@ -1485,25 +1372,31 @@ static int perform( ANativeWindow *window, int operation, ... )
         }
         if (!ret)
         {
-            if ((ret = gralloc_lock( buffer, &buffer_ret->bits )))
+            if (!(b = ahb_from_anwb((struct native_win_wrapper*) window, buffer, NULL, NULL))) {
+                ret = -EINVAL;
+            }
+
+            if (b && (ret = pAHardwareBuffer_lock( b, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN, -1, NULL, &buffer_ret->bits )))
             {
-                WARN( "gralloc->lock %p failed %d %s\n", win->hwnd, ret, strerror(-ret) );
+                WARN( "AHardwareBuffer_lock %p failed %d %s\n", win->hwnd, ret, strerror(-ret) );
                 window->cancelBuffer( window, buffer, -1 );
             }
         }
         if (!ret)
         {
-            buffer_ret->width  = buffer->width;
-            buffer_ret->height = buffer->height;
-            buffer_ret->stride = buffer->stride;
-            buffer_ret->format = buffer->format;
-            win->locked_buffer = buffer;
+            AHardwareBuffer_Desc d = {0};
+            pAHardwareBuffer_describe(b, &d);
+            buffer_ret->width  = d.width;
+            buffer_ret->height = d.height;
+            buffer_ret->stride = d.stride;
+            buffer_ret->format = d.format;
+            win->locked_buffer = b;
             if (bounds)
             {
                 bounds->left   = 0;
                 bounds->top    = 0;
-                bounds->right  = buffer->width;
-                bounds->bottom = buffer->height;
+                bounds->right  = d.width;
+                bounds->bottom = d.height;
             }
         }
         va_end( args );
@@ -1515,8 +1408,8 @@ static int perform( ANativeWindow *window, int operation, ... )
         int ret = -EINVAL;
         if (win->locked_buffer)
         {
-            gralloc_unlock( win->locked_buffer );
-            ret = window->queueBuffer( window, win->locked_buffer, -1 );
+            pAHardwareBuffer_unlock(win->locked_buffer, NULL);
+            ret = window->queueBuffer( window, anwb_from_ahb(win->locked_buffer), -1 );
             win->locked_buffer = NULL;
         }
         va_end( args );
@@ -1589,7 +1482,7 @@ void release_ioctl_window( struct ANativeWindow *window )
 
     TRACE( "%p %p\n", win, win->hwnd );
     for (i = 0; i < ARRAY_SIZE( win->buffers ); i++)
-        if (win->buffers[i]) win->buffers[i]->buffer.common.decRef( &win->buffers[i]->buffer.common );
+        if (win->buffers[i].self) pAHardwareBuffer_release(win->buffers[i].self);
 
     destroy_ioctl_window( win->hwnd, win->opengl );
     free( win );
diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c
index 01c9671b68f3..303655cde58b 100644
--- a/dlls/wineandroid.drv/init.c
+++ b/dlls/wineandroid.drv/init.c
@@ -341,153 +341,6 @@ static const JNINativeMethod methods[] =
 DECL_FUNCPTR( __android_log_print );
 DECL_FUNCPTR( ANativeWindow_fromSurface );
 DECL_FUNCPTR( ANativeWindow_release );
-DECL_FUNCPTR( hw_get_module );
-
-#ifndef DT_GNU_HASH
-#define DT_GNU_HASH 0x6ffffef5
-#endif
-
-static unsigned int gnu_hash( const char *name )
-{
-    unsigned int h = 5381;
-    while (*name) h = h * 33 + (unsigned char)*name++;
-    return h;
-}
-
-static unsigned int hash_symbol( const char *name )
-{
-    unsigned int hi, hash = 0;
-    while (*name)
-    {
-        hash = (hash << 4) + (unsigned char)*name++;
-        hi = hash & 0xf0000000;
-        hash ^= hi;
-        hash ^= hi >> 24;
-    }
-    return hash;
-}
-
-static void *find_symbol( const struct dl_phdr_info* info, const char *var, int type )
-{
-    const ElfW(Dyn) *dyn = NULL;
-    const ElfW(Phdr) *ph;
-    const ElfW(Sym) *symtab = NULL;
-    const Elf32_Word *hashtab = NULL;
-    const Elf32_Word *gnu_hashtab = NULL;
-    const char *strings = NULL;
-    Elf32_Word idx;
-
-    for (ph = info->dlpi_phdr; ph < &info->dlpi_phdr[info->dlpi_phnum]; ++ph)
-    {
-        if (PT_DYNAMIC == ph->p_type)
-        {
-            dyn = (const ElfW(Dyn) *)(info->dlpi_addr + ph->p_vaddr);
-            break;
-        }
-    }
-    if (!dyn) return NULL;
-
-    while (dyn->d_tag)
-    {
-        if (dyn->d_tag == DT_STRTAB)
-            strings = (const char*)(info->dlpi_addr + dyn->d_un.d_ptr);
-        if (dyn->d_tag == DT_SYMTAB)
-            symtab = (const ElfW(Sym) *)(info->dlpi_addr + dyn->d_un.d_ptr);
-        if (dyn->d_tag == DT_HASH)
-            hashtab = (const Elf32_Word *)(info->dlpi_addr + dyn->d_un.d_ptr);
-        if (dyn->d_tag == DT_GNU_HASH)
-            gnu_hashtab = (const Elf32_Word *)(info->dlpi_addr + dyn->d_un.d_ptr);
-        dyn++;
-    }
-
-    if (!symtab || !strings) return NULL;
-
-    if (gnu_hashtab)  /* new style hash table */
-    {
-        const unsigned int hash   = gnu_hash(var);
-        const Elf32_Word nbuckets = gnu_hashtab[0];
-        const Elf32_Word symbias  = gnu_hashtab[1];
-        const Elf32_Word nwords   = gnu_hashtab[2];
-        const ElfW(Addr) *bitmask = (const ElfW(Addr) *)(gnu_hashtab + 4);
-        const Elf32_Word *buckets = (const Elf32_Word *)(bitmask + nwords);
-        const Elf32_Word *chains  = buckets + nbuckets - symbias;
-
-        if (!(idx = buckets[hash % nbuckets])) return NULL;
-        do
-        {
-            if ((chains[idx] & ~1u) == (hash & ~1u) &&
-                ELF32_ST_BIND(symtab[idx].st_info) == STB_GLOBAL &&
-                ELF32_ST_TYPE(symtab[idx].st_info) == type &&
-                !strcmp( strings + symtab[idx].st_name, var ))
-                return (void *)(info->dlpi_addr + symtab[idx].st_value);
-        } while (!(chains[idx++] & 1u));
-    }
-    else if (hashtab)  /* old style hash table */
-    {
-        const unsigned int hash   = hash_symbol( var );
-        const Elf32_Word nbuckets = hashtab[0];
-        const Elf32_Word *buckets = hashtab + 2;
-        const Elf32_Word *chains  = buckets + nbuckets;
-
-        for (idx = buckets[hash % nbuckets]; idx; idx = chains[idx])
-        {
-            if (ELF32_ST_BIND(symtab[idx].st_info) == STB_GLOBAL &&
-                ELF32_ST_TYPE(symtab[idx].st_info) == type &&
-                !strcmp( strings + symtab[idx].st_name, var ))
-                return (void *)(info->dlpi_addr + symtab[idx].st_value);
-        }
-    }
-    return NULL;
-}
-
-static int enum_libs( struct dl_phdr_info* info, size_t size, void* data )
-{
-    const char *p;
-
-    if (!info->dlpi_name) return 0;
-    if (!(p = strrchr( info->dlpi_name, '/' ))) return 0;
-    if (strcmp( p, "/libhardware.so" )) return 0;
-    TRACE( "found libhardware at %p\n", info->dlpi_phdr );
-    phw_get_module = find_symbol( info, "hw_get_module", STT_FUNC );
-    return 1;
-}
-
-static void load_hardware_libs(void)
-{
-    const struct hw_module_t *module;
-    int ret;
-    void *libhardware;
-
-    if ((libhardware = dlopen( "libhardware.so", RTLD_GLOBAL )))
-    {
-        LOAD_FUNCPTR( libhardware, hw_get_module );
-    }
-    else
-    {
-        /* Android >= N disallows loading libhardware, so we load libandroid (which imports
-         * libhardware), and then we can find libhardware in the list of loaded libraries.
-         */
-        if (!dlopen( "libandroid.so", RTLD_GLOBAL ))
-        {
-            ERR( "failed to load libandroid.so: %s\n", dlerror() );
-            return;
-        }
-        dl_iterate_phdr( enum_libs, 0 );
-        if (!phw_get_module)
-        {
-            ERR( "failed to find hw_get_module\n" );
-            return;
-        }
-    }
-
-    if ((ret = phw_get_module( GRALLOC_HARDWARE_MODULE_ID, &module )))
-    {
-        ERR( "failed to load gralloc module err %d\n", ret );
-        return;
-    }
-
-    init_gralloc( module );
-}
 
 static void load_android_libs(void)
 {
@@ -533,7 +386,7 @@ static HRESULT android_init( void *arg )
 
     object = *p_java_object;
 
-    load_hardware_libs();
+    init_ahardwarebuffers();
 
     pthread_mutexattr_init( &attr );
     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
diff --git a/dlls/winebth.sys/dbus.c b/dlls/winebth.sys/dbus.c
index a2b1e1020fb8..aa2cef1cc0a1 100644
--- a/dlls/winebth.sys/dbus.c
+++ b/dlls/winebth.sys/dbus.c
@@ -1,8 +1,7 @@
 /*
  * Support for communicating with BlueZ over DBus.
  *
- * Copyright 2024 Vibhav Pant
- * Copyright 2025 Vibhav Pant
+ * Copyright 2024-2026 Vibhav Pant
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -91,6 +90,7 @@ const int bluez_timeout = -1;
 #define DBUS_OBJECTMANAGER_SIGNAL_INTERFACESADDED "InterfacesAdded"
 #define DBUS_OBJECTMANAGER_SIGNAL_INTERFACESREMOVED "InterfacesRemoved"
 #define DBUS_PROPERTIES_SIGNAL_PROPERTIESCHANGED "PropertiesChanged"
+#define DBUS_DBUS_SIGNAL_NAMEOWNERCHANGED "NameOwnerChanged"
 
 #define DBUS_INTERFACES_ADDED_SIGNATURE                                                            \
     DBUS_TYPE_OBJECT_PATH_AS_STRING                                                                \
@@ -114,6 +114,9 @@ const int bluez_timeout = -1;
     DBUS_DICT_ENTRY_END_CHAR_AS_STRING                                                             \
     DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_STRING_AS_STRING
 
+#define DBUS_NAMEOWNERCHANGED_SIGNATURE \
+    DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
+
 #define BLUEZ_DEST "org.bluez"
 #define BLUEZ_INTERFACE_ADAPTER "org.bluez.Adapter1"
 #define BLUEZ_INTERFACE_DEVICE  "org.bluez.Device1"
@@ -292,22 +295,61 @@ static NTSTATUS bluez_get_objects_async( DBusConnection *connection, DBusPending
     DBusMessage *request;
     dbus_bool_t success;
 
-    TRACE( "Getting managed objects under '/' at service '%s'\n", BLUEZ_DEST );
-    request = p_dbus_message_new_method_call(
-        BLUEZ_DEST, "/", DBUS_INTERFACE_OBJECTMANAGER, "GetManagedObjects" );
+    request = p_dbus_message_new_method_call( BLUEZ_DEST, "/", DBUS_INTERFACE_OBJECTMANAGER, "GetManagedObjects" );
     if (!request)
-    {
         return STATUS_NO_MEMORY;
-    }
 
     success = p_dbus_connection_send_with_reply( connection, request, call, -1 );
     p_dbus_message_unref( request );
+    return success ? (*call ? STATUS_SUCCESS : STATUS_INTERNAL_ERROR) : STATUS_NO_MEMORY;
+}
+
+#define WINE_BLUEZ_AUTH_AGENT_PATH "/org/winehq/wine/winebth/AuthAgent"
+
+static void bluez_register_auth_agent_callback( DBusPendingCall *call, void *data )
+{
+    DBusMessage *reply = p_dbus_pending_call_steal_reply( call );
+    DBusError error;
+
+    p_dbus_error_init( &error );
+    if (p_dbus_set_error_from_message( &error, reply ))
+        ERR( "Failed to register authentication agent with BlueZ, expect issues with pairing: %s\n",
+             dbgstr_dbus_error( &error ) );
+    else
+        TRACE( "Registered authentication agent %s with BlueZ\n", WINE_BLUEZ_AUTH_AGENT_PATH );
+    p_dbus_error_free( &error );
+    p_dbus_message_unref( reply );
+}
+
+static NTSTATUS bluez_register_auth_agent_async( DBusConnection *connection )
+{
+    static const char *wine_bluez_auth_agent_path = WINE_BLUEZ_AUTH_AGENT_PATH;
+    static const char *capability = "KeyboardDisplay";
+    DBusPendingCall *call;
+    DBusMessage *request;
+    dbus_bool_t success;
+
+    request = p_dbus_message_new_method_call( BLUEZ_DEST, "/org/bluez", BLUEZ_INTERFACE_AGENT_MANAGER, "RegisterAgent" );
+    if (!request)
+        return STATUS_NO_MEMORY;
+
+    success = p_dbus_message_append_args( request, DBUS_TYPE_OBJECT_PATH, &wine_bluez_auth_agent_path, DBUS_TYPE_STRING,
+                                          &capability, DBUS_TYPE_INVALID );
     if (!success)
+    {
+        p_dbus_message_unref( request );
         return STATUS_NO_MEMORY;
+    }
 
-    if (*call == NULL)
-        return STATUS_INVALID_PARAMETER;
+    success = p_dbus_connection_send_with_reply( connection, request, &call, -1 );
+    p_dbus_message_unref( request );
+    if (!success)
+        return STATUS_NO_MEMORY;
+    if (!call)
+        return STATUS_INTERNAL_ERROR;
 
+    p_dbus_pending_call_set_notify( call, bluez_register_auth_agent_callback, NULL, NULL );
+    p_dbus_pending_call_unref( call );
     return STATUS_SUCCESS;
 }
 
@@ -984,8 +1026,151 @@ static NTSTATUS bluez_device_get_props_by_path_async( DBusConnection *connection
     return STATUS_SUCCESS;
 }
 
+struct bluez_gatt_characteristic_value
+{
+    DBusMessage *message;
+    const BYTE *buf; /* Points into message */
+};
+
+/* array_iter must point to the start of the byte array, message should be the DBus message that the iterator belongs
+ * to. */
+static BOOL bluez_gatt_characteristic_value_new_from_iter( DBusMessage *message, DBusMessageIter *array_iter,
+                                                           struct winebluetooth_gatt_characteristic_value *value )
+{
+    struct bluez_gatt_characteristic_value *val;
+    DBusMessageIter bytes_iter;
+    int size;
+
+    TRACE_( dbus )( "(%s, %s, %p)\n", dbgstr_dbus_message( message ), dbgstr_dbus_iter( array_iter ), value );
+
+    if (!(val = calloc( 1, sizeof( *val ) ))) return FALSE;
+    val->message = p_dbus_message_ref( message );
+    p_dbus_message_iter_recurse( array_iter, &bytes_iter );
+    p_dbus_message_iter_get_fixed_array( &bytes_iter, &val->buf, &size );
+
+    value->size = size;
+    value->handle = (UINT_PTR)val;
+
+    return TRUE;
+}
+
+void bluez_gatt_characteristic_value_free( void *val )
+{
+    struct bluez_gatt_characteristic_value *value = val;
+
+    p_dbus_message_unref( value->message );
+    free( value );
+}
+
+void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *dest )
+{
+    struct bluez_gatt_characteristic_value *val = (struct bluez_gatt_characteristic_value *)value->handle;
+
+    memcpy( dest, val->buf, value->size );
+    bluez_gatt_characteristic_value_free( val );
+}
+
+static NTSTATUS bluez_gatt_error_to_status( const DBusError *error )
+{
+    if (p_dbus_error_has_name( error, "org.bluez.Error.NotPermitted" ))
+    {
+        if (!strcmp( error->message, "Read not permitted" ))
+            return STATUS_BTH_ATT_READ_NOT_PERMITTED;
+        else if (!strcmp( error->message, "Write not permitted" ))
+            return STATUS_BTH_ATT_WRITE_NOT_PERMITTED;
+        else
+            return STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION;
+    }
+    else if (p_dbus_error_has_name( error, "org.bluez.Error.NotAuthorized" ))
+        return STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION;
+    else if (p_dbus_error_has_name( error, "org.bluez.Error.NotSupported" ))
+        return STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED;
+    else if (p_dbus_error_has_name( error, "org.bluez.Error.InvalidArguments" ))
+    {
+        if (!strcmp( error->message, "Invalid offset" ))
+            return STATUS_BTH_ATT_INVALID_OFFSET;
+        else if (!strcmp( error->message, "Invalid Length" ))
+            return STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH;
+        return STATUS_BTH_ATT_UNKNOWN_ERROR;
+    }
+    else if (p_dbus_error_has_name( error, "org.bluez.Error.Failed" ) && !strcmp( error->message, "Not connected" ))
+        return STATUS_DEVICE_NOT_CONNECTED;
+    return bluez_dbus_error_to_ntstatus( error );
+}
+
+struct bluez_async_req_data
+{
+    IRP *irp;
+    struct bluez_watcher_ctx *watcher_ctx;
+};
+
+static void bluez_gatt_characteristic_read_callback( DBusPendingCall *pending, void *param );
+
+NTSTATUS bluez_gatt_characteristic_read( void *connection, void *watcher_ctx, struct unix_name *characteristic,
+                                         IRP *irp )
+{
+    DBusMessageIter args_iter, dict_iter = DBUS_MESSAGE_ITER_INIT_CLOSED;
+    struct bluez_async_req_data *data = NULL;
+    DBusPendingCall *pending_call = NULL;
+    DBusMessage *request;
+    NTSTATUS status;
+    dbus_bool_t success;
+
+    TRACE( "(%s, %p)\n", debugstr_a( characteristic->str ), irp );
+
+    request = p_dbus_message_new_method_call( BLUEZ_DEST, characteristic->str, BLUEZ_INTERFACE_GATT_CHARACTERISTICS,
+                                              "ReadValue" );
+    if (!request)
+        return STATUS_NO_MEMORY;
+    if (!(data = malloc( sizeof( *data ) )))
+    {
+        status = STATUS_NO_MEMORY;
+        goto failed;
+    }
+
+    data->irp = irp;
+    data->watcher_ctx = watcher_ctx;
+    p_dbus_message_iter_init_append( request, &args_iter );
+    if (!p_dbus_message_iter_open_container( &args_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter ))
+    {
+        status = STATUS_NO_MEMORY;
+        goto failed;
+    }
+    if (!p_dbus_message_iter_close_container( &args_iter, &dict_iter ))
+    {
+        status = STATUS_NO_MEMORY;
+        goto failed;
+    }
+    success = p_dbus_connection_send_with_reply( connection, request, &pending_call, bluez_timeout );
+    if (!success)
+    {
+        status = STATUS_NO_MEMORY;
+        goto failed;
+    }
+    if (!pending_call)
+    {
+        status = STATUS_INTERNAL_ERROR;
+        goto failed;
+    }
+    if (!p_dbus_pending_call_set_notify( pending_call, bluez_gatt_characteristic_read_callback, data, free ))
+    {
+        p_dbus_pending_call_cancel( pending_call );
+        p_dbus_pending_call_unref( pending_call );
+        status = STATUS_NO_MEMORY;
+        goto failed;
+    }
+    p_dbus_pending_call_unref( pending_call );
+    p_dbus_message_unref( request );
+    return STATUS_PENDING;
+failed:
+    p_dbus_message_iter_abandon_container_if_open( &args_iter, &dict_iter );
+    p_dbus_message_unref( request );
+    return status;
+}
+
 struct bluez_watcher_ctx
 {
+    DBusConnection *connection;
     char *bluez_dbus_unique_name;
     DBusPendingCall *init_device_list_call;
 
@@ -1002,6 +1187,40 @@ struct bluez_watcher_ctx
     struct list event_list;
 };
 
+static BOOL bluez_event_list_queue_new_event( struct list *event_list,
+                                              enum winebluetooth_watcher_event_type event_type,
+                                              union winebluetooth_watcher_event_data event );
+
+static void bluez_gatt_characteristic_read_callback( DBusPendingCall *pending, void *param )
+{
+    struct winebluetooth_watcher_event_gatt_characteristic_value_read read = {0};
+    union winebluetooth_watcher_event_data event;
+    struct bluez_async_req_data *data = param;
+    DBusMessage *reply;
+    DBusError error;
+
+    read.irp = data->irp;
+    reply = p_dbus_pending_call_steal_reply( pending );
+    p_dbus_error_init( &error );
+    if (p_dbus_set_error_from_message( &error, reply ))
+        read.result = bluez_gatt_error_to_status( &error );
+    else
+    {
+        DBusMessageIter iter;
+
+        p_dbus_message_iter_init( reply, &iter );
+        if (!bluez_gatt_characteristic_value_new_from_iter( reply, &iter, &read.value ))
+            read.result = STATUS_NO_MEMORY;
+    }
+
+    event.gatt_characteristic_value_read = read;
+    if (!bluez_event_list_queue_new_event( &data->watcher_ctx->event_list,
+                                           BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ, event ))
+        bluez_gatt_characteristic_value_free( (struct bluez_gatt_characteristic_value *)read.value.handle );
+    p_dbus_error_free( &error );
+    p_dbus_message_unref( reply );
+}
+
 struct bluez_init_entry
 {
     union {
@@ -1062,13 +1281,15 @@ void *bluez_dbus_init( void )
     return connection;
 }
 
-/* Return the unique connection name for org.bluez. We use this to ensure that only BlueZ can make method calls to us. */
-static NTSTATUS bluez_dbus_get_unique_name( DBusConnection *connection, char **unique_name )
+/* Return the unique connection name for org.bluez. We use this to ensure that:
+ * - BlueZ is actually available on this sytem before we make any calls to it.
+ * - Only BlueZ can make method calls to us.
+ */
+static NTSTATUS bluez_dbus_get_unique_name_async( DBusConnection *connection, DBusPendingCall **call )
 {
-    const char *bluez_name = BLUEZ_DEST, *name;
-    NTSTATUS ret = STATUS_SUCCESS;
-    DBusMessage *request, *reply;
-    DBusError error;
+    const char *bluez_name = BLUEZ_DEST;
+    DBusMessage *request;
+    dbus_bool_t success;
 
     request = p_dbus_message_new_method_call( "org.freedesktop.DBus", "/org/freedesktop/DBus", DBUS_INTERFACE_DBUS,
                                               "GetNameOwner" );
@@ -1080,30 +1301,42 @@ static NTSTATUS bluez_dbus_get_unique_name( DBusConnection *connection, char **u
         return STATUS_NO_MEMORY;
     }
 
-    p_dbus_error_init( &error );
-    reply = p_dbus_connection_send_with_reply_and_block( connection, request, bluez_timeout, &error );
+    success = p_dbus_connection_send_with_reply( connection, request, call, bluez_timeout);
     p_dbus_message_unref( request );
-    if (!reply)
-    {
-        ret = bluez_dbus_error_to_ntstatus( &error );
-        WARN_(dbus)( "Failed to get unique name for org.bluez: %s\n", dbgstr_dbus_error( &error ) );
-        p_dbus_error_free( &error );
-        return ret;
-    }
+    return success ? (*call ? STATUS_SUCCESS : STATUS_INTERNAL_ERROR) : STATUS_NO_MEMORY;
+}
 
-    if (!p_dbus_message_get_args( reply, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID ))
-    {
-        ERR_(dbus)( "Failed to read string from GetNameOwner reply: %s\n", dbgstr_dbus_error( &error ) );
-        ret = bluez_dbus_error_to_ntstatus( &error );
-    }
-    else if (!(*unique_name = strdup( name )))
-        ret = STATUS_NO_MEMORY;
-    else
-        TRACE_(dbus)( "Got unique connection name for org.bluez: %s", debugstr_a( name ) );
-    p_dbus_message_unref( reply );
-    p_dbus_error_free( &error );
+/* Called once the BlueZ service has been activated by the system. */
+static void bluez_on_service_available( struct bluez_watcher_ctx *ctx )
+{
+    NTSTATUS status;
 
-    return ret;
+    TRACE_(dbus)( "org.bluez available on %s, initializing bluetooth.\n", debugstr_a( ctx->bluez_dbus_unique_name ) );
+
+    if ((status = bluez_register_auth_agent_async( ctx->connection )))
+        ERR_(dbus)( "Failed to create async RegisterAgent call: %#x\n", status );
+    if ((status = bluez_get_objects_async( ctx->connection, &ctx->init_device_list_call )))
+        ERR_(dbus)( "Failed to create async GetManagedObjects call: %#x\n", status );
+}
+
+static void bluez_dbus_get_name_owner_callback( DBusPendingCall *call, void *data )
+{
+    DBusMessage *reply = p_dbus_pending_call_steal_reply( call );
+    struct bluez_watcher_ctx *ctx = data;
+    const char *name;
+    DBusError error;
+
+    p_dbus_error_init( &error );
+    if (p_dbus_set_error_from_message( &error, reply ))
+        WARN_(dbus)( "Failed to get unique name for org.bluez: %s\n", dbgstr_dbus_error( &error ) );
+    else if (!p_dbus_message_get_args( reply, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID ))
+        ERR_(dbus)( "Failed to read string from GetNameOwner reply: %s\n", dbgstr_dbus_error(  &error ) );
+    /* If bluez_signal_handler has already set a unique_name, nothing needs to be done. This can happen if BlueZ
+     * (re)starts right after we set up the signal handler in bluez_watcher_init. */
+    else if (!ctx->bluez_dbus_unique_name && ((ctx->bluez_dbus_unique_name = strdup( name ))))
+        bluez_on_service_available( ctx );
+    p_dbus_error_free( &error );
+    p_dbus_message_unref( reply );
 }
 
 void bluez_dbus_close( void *connection )
@@ -1236,17 +1469,12 @@ static DBusHandlerResult bluez_auth_agent_vtable_message_handler( DBusConnection
 const static struct DBusObjectPathVTable bluez_auth_agent_object_vtable = {
     .message_function = bluez_auth_agent_vtable_message_handler };
 
-#define WINE_BLUEZ_AUTH_AGENT_PATH "/org/winehq/wine/winebth/AuthAgent"
-
 NTSTATUS bluez_auth_agent_start( void *connection, void **auth_agent_ctx )
 {
-    static const char *wine_bluez_auth_agent_path = WINE_BLUEZ_AUTH_AGENT_PATH;
-    static const char *capability = "KeyboardDisplay";
     struct bluez_auth_agent_ctx *ctx;
-    DBusMessage *request;
+    NTSTATUS status = STATUS_SUCCESS;
     dbus_bool_t success;
     DBusError error;
-    NTSTATUS status;
 
     TRACE( "(%s, %p)\n", dbgstr_dbus_connection( connection ), auth_agent_ctx );
 
@@ -1269,40 +1497,9 @@ NTSTATUS bluez_auth_agent_start( void *connection, void **auth_agent_ctx )
         ERR_(dbus)( "Failed to register object: %s\n", dbgstr_dbus_error( &error ) );
         status = bluez_dbus_error_to_ntstatus( &error );
         bluez_auth_agent_ctx_decref( ctx );
-        goto done;
-    }
-
-    request = p_dbus_message_new_method_call( BLUEZ_DEST, "/org/bluez", BLUEZ_INTERFACE_AGENT_MANAGER,
-                                              "RegisterAgent" );
-    if (!request)
-    {
-        status = STATUS_NO_MEMORY;
-        goto failure;
-    }
-
-    success = p_dbus_message_append_args( request, DBUS_TYPE_OBJECT_PATH, &wine_bluez_auth_agent_path, DBUS_TYPE_STRING,
-                                          &capability, DBUS_TYPE_INVALID );
-    if (!success)
-    {
-        status = STATUS_NO_MEMORY;
-        goto failure;
     }
-
-    success = p_dbus_connection_send( connection, request, NULL );
-    p_dbus_message_unref( request );
-    if (!success)
-    {
-        status = STATUS_NO_MEMORY;
-        goto failure;
-    }
-    status = STATUS_SUCCESS;
-    *auth_agent_ctx = ctx;
-    goto done;
-
-failure:
-    p_dbus_connection_unregister_object_path( connection, WINE_BLUEZ_AUTH_AGENT_PATH );
-    bluez_auth_agent_ctx_decref( ctx );
-done:
+    else
+        *auth_agent_ctx = ctx;
     p_dbus_error_free( &error );
     return status;
 }
@@ -1467,18 +1664,9 @@ NTSTATUS bluez_device_disconnect( void *connection, const char *device_path )
     return STATUS_SUCCESS;
 }
 
-static BOOL bluez_event_list_queue_new_event( struct list *event_list,
-                                              enum winebluetooth_watcher_event_type event_type,
-                                              union winebluetooth_watcher_event_data event );
-struct bluez_device_pair_data
-{
-    IRP *irp;
-    struct bluez_watcher_ctx *watcher_ctx;
-};
-
 static void bluez_device_pair_callback( DBusPendingCall *pending, void *param )
 {
-    struct bluez_device_pair_data *data = param;
+    struct bluez_async_req_data *data = param;
     DBusMessage *reply;
     DBusError error;
     union winebluetooth_watcher_event_data event = {0};
@@ -1502,7 +1690,7 @@ NTSTATUS bluez_device_start_pairing( void *connection, void *watcher_ctx, struct
 {
     DBusMessage *request;
     DBusPendingCall *pending_call = NULL;
-    struct bluez_device_pair_data *data;
+    struct bluez_async_req_data *data;
     dbus_bool_t success;
 
     TRACE( "(%p, %p, %s, %p)\n", connection, watcher_ctx, debugstr_a( device->str ), irp );
@@ -1689,9 +1877,47 @@ static UINT16 bluez_dbus_get_invalidated_properties_from_iter(
     return mask;
 }
 
-static void bluez_signal_handler( DBusConnection *conn, DBusMessage *msg, const char *signal_iface, const char *signal_name, const char *signal_sig, struct list *event_list )
+static void bluez_signal_handler( DBusConnection *conn, DBusMessage *msg, const char *signal_iface,
+                                  const char *signal_name, const char *signal_sig, struct bluez_watcher_ctx *ctx )
 {
+    struct list *event_list = &ctx->event_list;
+
+    if (!strcmp( signal_iface, DBUS_INTERFACE_DBUS ) &&
+        !strcmp( signal_name, DBUS_DBUS_SIGNAL_NAMEOWNERCHANGED ) &&
+        !strcmp( signal_sig, DBUS_NAMEOWNERCHANGED_SIGNATURE ))
+    {
+        const static union winebluetooth_watcher_event_data empty_event;
+        const char *name, *old_owner, *new_owner;
+        DBusError error;
 
+        p_dbus_error_init( &error );
+        if (!p_dbus_message_get_args( msg, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner,
+                                      DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID ))
+        {
+            ERR( "Failed to read NameOwnerChanged arguments: %s\n", dbgstr_dbus_error( &error ) );
+            p_dbus_error_free( &error );
+            return;
+        }
+        p_dbus_error_free( &error );
+        if (strcmp( name, BLUEZ_DEST )) return;
+        if (new_owner[0] && (!ctx->bluez_dbus_unique_name || strcmp( ctx->bluez_dbus_unique_name, new_owner )))
+        {
+            free( ctx->bluez_dbus_unique_name );
+            if ((ctx->bluez_dbus_unique_name = strdup( new_owner )))
+                bluez_on_service_available( ctx );
+        }
+        else if (ctx->bluez_dbus_unique_name)
+        {
+            TRACE_(dbus)( "org.bluez down, removing all entries.\n" );
+
+            free( ctx->bluez_dbus_unique_name );
+            ctx->bluez_dbus_unique_name = NULL;
+            /* When BlueZ shuts down gracefully, we will already have received InterfaceRemoved signals for
+             * all previously added Bluetooth entries. This event is useful for when BlueZ crashes, in which
+             * case we would have to remove the entries ourselves. */
+            bluez_event_list_queue_new_event( event_list, BLUETOOTH_WATCHER_EVENT_TYPE_SERVICE_DOWN, empty_event );
+        }
+    }
     if (!strcmp( signal_iface, DBUS_INTERFACE_OBJECTMANAGER ) &&
         !strcmp( signal_name, DBUS_OBJECTMANAGER_SIGNAL_INTERFACESADDED ) &&
         !strcmp( signal_sig, DBUS_INTERFACES_ADDED_SIGNATURE ))
@@ -2144,6 +2370,51 @@ static void bluez_signal_handler( DBusConnection *conn, DBusMessage *msg, const
                 return;
             }
         }
+        else if (!strcmp( iface, BLUEZ_INTERFACE_GATT_CHARACTERISTICS ))
+        {
+            struct winebluetooth_watcher_event_gatt_characteristic_value_changed changed_event = {0};
+            union winebluetooth_watcher_event_data event;
+            DBusMessageIter changed_props_iter, variant;
+            const char *prop_name, *object_path;
+            struct unix_name *chrc_name;
+            BOOL val_changed = FALSE;
+
+            p_dbus_message_iter_next( &iter );
+            p_dbus_message_iter_recurse( &iter, &changed_props_iter );
+            while ((prop_name = bluez_next_dict_entry( &changed_props_iter, &variant )))
+            {
+                if (!strcmp( prop_name, "Value" )
+                    && p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY
+                    && p_dbus_message_iter_get_element_type( &variant ) == DBUS_TYPE_BYTE)
+                {
+                    val_changed = bluez_gatt_characteristic_value_new_from_iter( msg, &variant, &changed_event.value );
+                    break;
+                }
+            }
+            if (!val_changed)
+                return;
+
+            object_path = p_dbus_message_get_path( msg );
+            TRACE( "Value changed for GATT characteristic %s\n", debugstr_a( object_path ) );
+            if (!(chrc_name = unix_name_get_or_create( object_path )))
+            {
+                ERR( "Failed to allocate memory for GATT characteristic path %s\n", debugstr_a( object_path ) );
+                bluez_gatt_characteristic_value_free(
+                    (struct bluez_gatt_characteristic_value *)changed_event.value.handle );
+                return;
+            }
+
+            changed_event.characteristic.handle = (UINT_PTR)chrc_name;
+            event.gatt_characteristic_value_changed = changed_event;
+            if (!bluez_event_list_queue_new_event( event_list, BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED,
+                                                   event ))
+            {
+                unix_name_free( chrc_name );
+                bluez_gatt_characteristic_value_free(
+                    (struct bluez_gatt_characteristic_value *)changed_event.value.handle );
+                return;
+            }
+        }
     }
 }
 
@@ -2158,7 +2429,7 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v
     type = p_dbus_message_get_type( msg );
     if (type == DBUS_MESSAGE_TYPE_SIGNAL)
         bluez_signal_handler( conn, msg, p_dbus_message_get_interface( msg ), p_dbus_message_get_member( msg ),
-                              p_dbus_message_get_signature( msg ), &ctx->event_list );
+                              p_dbus_message_get_signature( msg ), ctx );
     else if (type == DBUS_MESSAGE_TYPE_METHOD_CALL)
     {
         DBusMessage *reply;
@@ -2166,7 +2437,8 @@ static DBusHandlerResult bluez_filter( DBusConnection *conn, DBusMessage *msg, v
         dbus_bool_t success;
 
         /* Only allow incoming method calls from org.bluez. */
-        if (!(sender = p_dbus_message_get_sender( msg )) || strcmp( sender, ctx->bluez_dbus_unique_name ))
+        if (!(sender = p_dbus_message_get_sender( msg )) || !ctx->bluez_dbus_unique_name ||
+            strcmp( sender, ctx->bluez_dbus_unique_name ))
         {
             if (!(reply = p_dbus_message_new_error( msg, DBUS_ERROR_ACCESS_DENIED, "Access Denied" )))
                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
@@ -2189,8 +2461,14 @@ static const char BLUEZ_MATCH_PROPERTIES[] = "type='signal',"
                                              "interface='"DBUS_INTERFACE_PROPERTIES"',"
                                              "member='PropertiesChanged',"
                                              "sender='"BLUEZ_DEST"',";
+static const char DBUS_MATCH_NAMEOWNERCHANGED[] = "type='signal',"
+                                                  "interface='"DBUS_INTERFACE_DBUS"',"
+                                                  "member='NameOwnerChanged',"
+                                                  "arg0='"BLUEZ_DEST"',"
+                                                  "path='/org/freedesktop/DBus',"
+                                                  "sender='org.freedesktop.DBus'";
 
-static const char *BLUEZ_MATCH_RULES[] = { BLUEZ_MATCH_OBJECTMANAGER, BLUEZ_MATCH_PROPERTIES };
+static const char *BLUEZ_MATCH_RULES[] = { BLUEZ_MATCH_OBJECTMANAGER, BLUEZ_MATCH_PROPERTIES, DBUS_MATCH_NAMEOWNERCHANGED };
 
 /* Free up the watcher alongside any remaining events and initial devices and other associated resources. */
 static void bluez_watcher_free( struct bluez_watcher_ctx *watcher )
@@ -2216,6 +2494,8 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher )
         list_remove( &event1->entry );
         switch (event1->event_type)
         {
+        case BLUETOOTH_WATCHER_EVENT_TYPE_SERVICE_DOWN:
+            break;
         case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED:
             unix_name_free( (struct unix_name *)event1->event.radio_added.radio.handle );
             break;
@@ -2247,36 +2527,40 @@ static void bluez_watcher_free( struct bluez_watcher_ctx *watcher )
         case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_ADDED:
             unix_name_free( (struct unix_name *)event1->event.gatt_characteristic_added.characteristic.handle );
             unix_name_free( (struct unix_name *)event1->event.gatt_characteristic_added.service.handle );
+            bluez_gatt_characteristic_value_free(
+                (struct bluez_gatt_characteristic_value *)event1->event.gatt_characteristic_added.value.handle );
             break;
         case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED:
             unix_name_free( (struct unix_name *)event1->event.gatt_characterisic_removed.handle );
             break;
+        case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED:
+            unix_name_free( (struct unix_name *)event1->event.gatt_characteristic_value_changed.characteristic.handle );
+            bluez_gatt_characteristic_value_free(
+                (struct bluez_gatt_characteristic_value *)event1->event.gatt_characteristic_added.value.handle );
+            break;
+        case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ:
+            bluez_gatt_characteristic_value_free(
+                (struct bluez_gatt_characteristic_value *)event1->event.gatt_characteristic_value_read.value.handle );
+            break;
         }
         free( event1 );
     }
 
+    p_dbus_connection_unref( watcher->connection );
     free( watcher->bluez_dbus_unique_name );
     free( watcher );
 }
 
 NTSTATUS bluez_watcher_init( void *connection, void **ctx )
 {
-    DBusError err;
+    struct bluez_watcher_ctx *watcher_ctx;
+    DBusPendingCall *call;
     NTSTATUS status;
-    struct bluez_watcher_ctx *watcher_ctx =
-        calloc( 1, sizeof( struct bluez_watcher_ctx ) );
+    DBusError err;
     SIZE_T i;
 
-    if (watcher_ctx == NULL) return STATUS_NO_MEMORY;
-    p_dbus_error_init( &err );
-    status = bluez_dbus_get_unique_name( connection, &watcher_ctx->bluez_dbus_unique_name );
-    if (status) goto done;
-    status = bluez_get_objects_async( connection, &watcher_ctx->init_device_list_call );
-    if (status)
-    {
-        ERR( "could not create async GetManagedObjects call: %#x\n", status);
-        goto done;
-    }
+    if (!(watcher_ctx = calloc( 1, sizeof( struct bluez_watcher_ctx ) ))) return STATUS_NO_MEMORY;
+    watcher_ctx->connection = p_dbus_connection_ref( connection );
     list_init( &watcher_ctx->initial_radio_list );
     list_init( &watcher_ctx->initial_device_list );
     list_init( &watcher_ctx->initial_gatt_service_list );
@@ -2288,23 +2572,33 @@ NTSTATUS bluez_watcher_init( void *connection, void **ctx )
      * is racy as the filter is removed from a different thread. */
     if (!p_dbus_connection_add_filter( connection, bluez_filter, watcher_ctx, NULL ))
     {
-        ERR( "Could not add DBus filter\n" );
+        ERR_(dbus)( "Could not add DBus filter\n" );
         status = STATUS_NO_MEMORY;
         goto done;
     }
+    p_dbus_error_init( &err );
     for (i = 0; i < ARRAY_SIZE( BLUEZ_MATCH_RULES ); i++)
     {
         const char *rule = BLUEZ_MATCH_RULES[i];
 
-        TRACE( "Adding DBus match rule %s\n", debugstr_a( rule ) );
+        TRACE_(dbus)( "Adding DBus match rule %s\n", debugstr_a( rule ) );
         p_dbus_bus_add_match( connection, rule, &err );
         if (p_dbus_error_is_set( &err ))
         {
-            ERR( "Could not add DBus match %s: %s\n", debugstr_a( rule ), dbgstr_dbus_error( &err ) );
+            ERR_(dbus)( "Could not add DBus match %s: %s\n", debugstr_a( rule ), dbgstr_dbus_error( &err ) );
             status = bluez_dbus_error_to_ntstatus( &err );
             goto done;
         }
     }
+    /* Get the unique name after setting up a signal handler, this avoids a race condition if BlueZ (re)starts (and thus
+     * gets a new unique name) between the call to GetNameOwner and dbus_connection_add_filter. */
+    if ((status = bluez_dbus_get_unique_name_async( connection, &call ))) goto done;
+    if (!p_dbus_pending_call_set_notify( call, bluez_dbus_get_name_owner_callback, watcher_ctx, NULL ))
+    {
+        status = STATUS_NO_MEMORY;
+        p_dbus_pending_call_cancel( call );
+    }
+    p_dbus_pending_call_unref( call );
 done:
     p_dbus_error_free( &err );
     if (status)
@@ -2314,6 +2608,7 @@ done:
             p_dbus_pending_call_cancel( watcher_ctx->init_device_list_call );
             p_dbus_pending_call_unref( watcher_ctx->init_device_list_call );
         }
+        p_dbus_connection_unref( watcher_ctx->connection );
         free( watcher_ctx->bluez_dbus_unique_name );
         free( watcher_ctx );
     }
@@ -2510,10 +2805,28 @@ static NTSTATUS bluez_build_initial_device_lists( DBusMessage *reply, struct lis
 
                 init_entry->object.characteristic.characteristic.handle = (UINT_PTR)char_name;
                 while ((prop_name = bluez_next_dict_entry( &prop_iter, &variant )))
-                    bluez_gatt_characteristic_props_from_dict_entry( prop_name, &variant,
-                                                                     &init_entry->object.characteristic );
+                {
+                    if (!strcmp( prop_name, "Value" )
+                        && p_dbus_message_iter_get_arg_type( &variant ) == DBUS_TYPE_ARRAY
+                        && p_dbus_message_iter_get_element_type( &variant ) == DBUS_TYPE_BYTE)
+                    {
+                        if (!bluez_gatt_characteristic_value_new_from_iter( reply, &variant,
+                                                                            &init_entry->object.characteristic.value ))
+                        {
+                            unix_name_free( char_name );
+                            free( init_entry );
+                            status = STATUS_NO_MEMORY;
+                            goto done;
+                        }
+                    }
+                    else
+                        bluez_gatt_characteristic_props_from_dict_entry( prop_name, &variant,
+                                                                         &init_entry->object.characteristic );
+                }
                 if (!init_entry->object.characteristic.service.handle)
                 {
+                    bluez_gatt_characteristic_value_free(
+                        (struct bluez_gatt_characteristic_value *)init_entry->object.characteristic.value.handle );
                     unix_name_free( char_name );
                     free( init_entry );
                     ERR( "Could not find the associated service for the GATT charcteristic %s\n", debugstr_a( path ) );
@@ -2732,5 +3045,10 @@ NTSTATUS bluez_device_start_pairing( void *connection, void *watcher_ctx, struct
 {
     return STATUS_NOT_SUPPORTED;
 }
-
+void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *buf ) {}
+void bluez_gatt_characteristic_value_free( void *val ) {}
+NTSTATUS bluez_gatt_characteristic_read( void *connection, void *watcher, struct unix_name *characteristic, IRP *irp )
+{
+    return STATUS_NOT_SUPPORTED;
+}
 #endif /* SONAME_LIBDBUS_1 */
diff --git a/dlls/winebth.sys/dbus.h b/dlls/winebth.sys/dbus.h
index 4cbf37883df2..511e8caf25bf 100644
--- a/dlls/winebth.sys/dbus.h
+++ b/dlls/winebth.sys/dbus.h
@@ -84,6 +84,7 @@
     DO_FUNC(dbus_message_is_signal); \
     DO_FUNC(dbus_message_iter_append_basic); \
     DO_FUNC(dbus_message_iter_abandon_container); \
+    DO_FUNC(dbus_message_iter_abandon_container_if_open); \
     DO_FUNC(dbus_message_iter_close_container); \
     DO_FUNC(dbus_message_iter_get_arg_type); \
     DO_FUNC(dbus_message_iter_get_element_type); \
diff --git a/dlls/winebth.sys/unixlib.c b/dlls/winebth.sys/unixlib.c
index 530fe4324131..cda33695bbbb 100644
--- a/dlls/winebth.sys/unixlib.c
+++ b/dlls/winebth.sys/unixlib.c
@@ -275,6 +275,28 @@ static NTSTATUS bluetooth_gatt_characteristic_free( void *args )
     return STATUS_SUCCESS;
 }
 
+static NTSTATUS bluetooth_gatt_characteristic_read( void *args )
+{
+    struct bluetooth_gatt_characteristic_read_params *params = args;
+    if (!dbus_connection) return STATUS_NOT_SUPPORTED;
+    return bluez_gatt_characteristic_read( dbus_connection, bluetooth_watcher, params->chrc, params->irp );
+}
+
+static NTSTATUS bluetooth_gatt_characteristic_value_move( void *args )
+{
+    struct bluetooth_gatt_characteristic_value_move_params *params = args;
+    if (!dbus_connection) return STATUS_NOT_SUPPORTED;
+    bluez_gatt_characteristic_value_move( params->val, params->buf );
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS bluetooth_gatt_characteristic_value_free( void *args )
+{
+    struct bluetooth_gatt_characteristic_value_free_params *params = args;
+    if (!dbus_connection) return STATUS_NOT_SUPPORTED;
+    bluez_gatt_characteristic_value_free( (void *)params->handle );
+    return STATUS_SUCCESS;
+}
 
 static NTSTATUS bluetooth_get_event( void *args )
 {
@@ -308,6 +330,10 @@ const unixlib_entry_t __wine_unix_call_funcs[] = {
     bluetooth_gatt_service_free,
 
     bluetooth_gatt_characteristic_free,
+    bluetooth_gatt_characteristic_read,
+
+    bluetooth_gatt_characteristic_value_move,
+    bluetooth_gatt_characteristic_value_free,
 
     bluetooth_get_event,
 };
diff --git a/dlls/winebth.sys/unixlib.h b/dlls/winebth.sys/unixlib.h
index 765003a5fc37..909a47577790 100644
--- a/dlls/winebth.sys/unixlib.h
+++ b/dlls/winebth.sys/unixlib.h
@@ -69,11 +69,27 @@ struct bluetooth_gatt_service_free_params
     unix_name_t service;
 };
 
+struct bluetooth_gatt_characteristic_dup_params
+{
+    unix_name_t characteristic;
+};
+
 struct bluetooth_gatt_characteristic_free_params
 {
     unix_name_t characteristic;
 };
 
+struct bluetooth_gatt_characteristic_value_move_params
+{
+    struct winebluetooth_gatt_characteristic_value *val;
+    BYTE *buf;
+};
+
+struct bluetooth_gatt_characteristic_value_free_params
+{
+    UINT_PTR handle;
+};
+
 struct bluetooth_device_disconnect_params
 {
     unix_name_t device;
@@ -126,6 +142,12 @@ struct bluetooth_device_start_pairing_params
     IRP *irp;
 };
 
+struct bluetooth_gatt_characteristic_read_params
+{
+    unix_name_t chrc;
+    IRP *irp;
+};
+
 struct bluetooth_get_event_params
 {
     struct winebluetooth_event result;
@@ -155,6 +177,10 @@ enum bluetoothapis_funcs
     unix_bluetooth_gatt_service_free,
 
     unix_bluetooth_gatt_characteristic_free,
+    unix_bluetooth_gatt_characteristic_read,
+
+    unix_bluetooth_gatt_characteristic_value_move,
+    unix_bluetooth_gatt_characteristic_value_free,
 
     unix_bluetooth_get_event,
 
diff --git a/dlls/winebth.sys/unixlib_priv.h b/dlls/winebth.sys/unixlib_priv.h
index 4348aa6f5df4..b0c2059d526c 100644
--- a/dlls/winebth.sys/unixlib_priv.h
+++ b/dlls/winebth.sys/unixlib_priv.h
@@ -61,5 +61,9 @@ extern NTSTATUS bluez_auth_agent_send_response( void *auth_agent, struct unix_na
 extern NTSTATUS bluez_device_disconnect( void *connection, const char *device_path );
 extern NTSTATUS bluez_device_start_pairing( void *dbus_connection, void *watcher_ctx, struct unix_name *device, IRP *irp );
 extern NTSTATUS bluez_watcher_init( void *connection, void **ctx );
+extern void bluez_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *value, BYTE *buf );
+extern void bluez_gatt_characteristic_value_free( void *val );
+extern NTSTATUS bluez_gatt_characteristic_read( void *connection, void *watcher_ctx, struct unix_name *characteristic,
+                                                IRP *irp );
 extern void bluez_watcher_close( void *connection, void *ctx );
 #endif /* __WINE_WINEBTH_UNIXLIB_PRIV_H */
diff --git a/dlls/winebth.sys/winebluetooth.c b/dlls/winebth.sys/winebluetooth.c
index f91d2b9a4406..5bab7230fa32 100644
--- a/dlls/winebth.sys/winebluetooth.c
+++ b/dlls/winebth.sys/winebluetooth.c
@@ -1,8 +1,7 @@
 /*
  * Wine bluetooth APIs
  *
- * Copyright 2024 Vibhav Pant
- * Copyright 2025 Vibhav Pant
+ * Copyright 2024-2026 Vibhav Pant
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -224,6 +223,43 @@ void winebluetooth_gatt_characteristic_free( winebluetooth_gatt_characteristic_t
     UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_free, &args );
 }
 
+NTSTATUS winebluetooth_gatt_characteristic_read_async( winebluetooth_gatt_characteristic_t chrc, IRP *irp )
+{
+    struct bluetooth_gatt_characteristic_read_params params = {0};
+
+    TRACE( "(%p, %p)\n", (void *)chrc.handle, irp );
+    params.chrc = chrc.handle;
+    params.irp = irp;
+    return UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_read, &params );
+}
+
+static const char *
+debugstr_winebluetooth_gatt_characteristic_value( const struct winebluetooth_gatt_characteristic_value *val )
+{
+    return val ? wine_dbg_sprintf( "{ %I32u { %#Ix } }", val->size, val->handle ) : "(null)";
+}
+
+void winebluetooth_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *val, BYTE *dest )
+{
+    struct bluetooth_gatt_characteristic_value_move_params args = {0};
+
+    TRACE( "(%s, %p)\n", debugstr_winebluetooth_gatt_characteristic_value( val ), dest );
+
+    args.val = val;
+    args.buf = dest;
+    UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_value_move, &args );
+}
+
+void winebluetooth_gatt_characteristic_value_free( struct winebluetooth_gatt_characteristic_value *val )
+{
+    struct bluetooth_gatt_characteristic_value_free_params args = {0};
+
+    TRACE( "(%#Ix)\n", val->handle );
+
+    args.handle = val->handle;
+    UNIX_BLUETOOTH_CALL( bluetooth_gatt_characteristic_value_free, &args );
+}
+
 NTSTATUS winebluetooth_get_event( struct winebluetooth_event *result )
 {
     struct bluetooth_get_event_params params = {0};
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c
index 510d7fb72b74..fccac50bdefe 100644
--- a/dlls/winebth.sys/winebth.c
+++ b/dlls/winebth.sys/winebth.c
@@ -1,7 +1,7 @@
 /*
  * Bluetooth bus driver
  *
- * Copyright 2024-2025 Vibhav Pant
+ * Copyright 2024-2026 Vibhav Pant
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -122,6 +122,8 @@ struct bluetooth_gatt_service
 
     CRITICAL_SECTION chars_cs;
     struct list characteristics; /* Guarded by chars_cs */
+
+    LIST_ENTRY irp_list; /* Guarded by chars_cs */
 };
 
 struct bluetooth_gatt_characteristic
@@ -130,6 +132,7 @@ struct bluetooth_gatt_characteristic
 
     winebluetooth_gatt_characteristic_t characteristic;
     BTH_LE_GATT_CHARACTERISTIC props;
+    BTH_LE_GATT_CHARACTERISTIC_VALUE *value;
 };
 
 enum bluetooth_pdo_ext_type
@@ -194,6 +197,20 @@ static struct bluetooth_gatt_service *find_gatt_service( struct list *services,
     return NULL;
 }
 
+/* Called should hold chars_cs */
+static struct bluetooth_gatt_characteristic *find_gatt_characteristic( struct list *chars, const BTH_LE_UUID *uuid,
+                                                                       UINT16 handle )
+{
+    struct bluetooth_gatt_characteristic *chrc;
+
+    LIST_FOR_EACH_ENTRY( chrc, chars, struct bluetooth_gatt_characteristic, entry )
+    {
+        if (IsBthLEUuidMatch( chrc->props.CharacteristicUuid, *uuid ) && chrc->props.AttributeHandle == handle)
+            return chrc;
+    }
+    return NULL;
+}
+
 static NTSTATUS bluetooth_gatt_service_get_characteristics( struct bluetooth_gatt_service *service, IRP *irp )
 {
     const SIZE_T min_size = offsetof( struct winebth_le_device_get_gatt_characteristics_params, characteristics[0] );
@@ -232,6 +249,7 @@ static NTSTATUS bluetooth_gatt_service_get_characteristics( struct bluetooth_gat
 static NTSTATUS bluetooth_gatt_service_dispatch( DEVICE_OBJECT *device, struct bluetooth_gatt_service *ext, IRP *irp )
 {
     IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( irp );
+    ULONG outsize = stack->Parameters.DeviceIoControl.OutputBufferLength;
     ULONG code = stack->Parameters.DeviceIoControl.IoControlCode;
     NTSTATUS status = irp->IoStatus.Status;
 
@@ -251,12 +269,68 @@ static NTSTATUS bluetooth_gatt_service_dispatch( DEVICE_OBJECT *device, struct b
         status = bluetooth_gatt_service_get_characteristics( ext, irp );
         break;
     }
+    case IOCTL_WINEBTH_GATT_SERVICE_READ_CHARACTERISITIC_VALUE:
+    {
+        struct winebth_gatt_service_read_characterisitic_value_params *params = irp->AssociatedIrp.SystemBuffer;
+        struct bluetooth_gatt_characteristic *chrc;
+
+        if (!params || outsize < sizeof( *params ))
+        {
+            status = STATUS_INVALID_USER_BUFFER;
+            break;
+        }
+
+        EnterCriticalSection( &ext->chars_cs );
+        chrc = find_gatt_characteristic( &ext->characteristics, &params->uuid, params->handle );
+        if (!chrc)
+        {
+            status = STATUS_NOT_FOUND;
+            LeaveCriticalSection( &ext->chars_cs );
+            break;
+        }
+        if (!chrc->props.IsReadable)
+        {
+            status = STATUS_PRIVILEGE_NOT_HELD;
+            LeaveCriticalSection( &ext->chars_cs );
+            break;
+        }
+        if (params->from_device || !chrc->value)
+        {
+            status = winebluetooth_gatt_characteristic_read_async( chrc->characteristic, irp );
+            if (status == STATUS_PENDING)
+            {
+                IoMarkIrpPending( irp );
+                InsertTailList( &ext->irp_list, &irp->Tail.Overlay.ListEntry );
+            }
+        }
+        else
+        {
+            ULONG needed = offsetof( struct winebth_gatt_service_read_characterisitic_value_params, buf[chrc->value->DataSize] );
+
+            params->size = chrc->value->DataSize;
+            if (outsize >= needed)
+            {
+                status = STATUS_SUCCESS;
+                memcpy( params->buf, chrc->value->Data, params->size );
+                irp->IoStatus.Information = needed;
+            }
+            else
+            {
+                status = STATUS_MORE_ENTRIES;
+                irp->IoStatus.Information = sizeof( *params );
+            }
+        }
+        LeaveCriticalSection( &ext->chars_cs );
+        break;
+    }
     default:
         FIXME( "Unimplemented IOCTL code: %#lx\n", code );
     }
-
-    irp->IoStatus.Status = status;
-    IoCompleteRequest( irp, IO_NO_INCREMENT );
+    if (status != STATUS_PENDING)
+    {
+        irp->IoStatus.Status = status;
+        IoCompleteRequest( irp, IO_NO_INCREMENT );
+    }
     return status;
 }
 
@@ -748,9 +822,26 @@ static NTSTATUS radio_get_hw_name_w( winebluetooth_radio_t radio, WCHAR **name )
     free( name_a );
     return STATUS_SUCCESS;
 }
+
+static void bluetooth_remove_all_radios( void )
+{
+    struct bluetooth_radio *radio, *radio2;
+
+    EnterCriticalSection( &device_list_cs );
+    LIST_FOR_EACH_ENTRY_SAFE( radio, radio2, &device_list, struct bluetooth_radio, entry )
+    {
+        radio->removed = TRUE;
+        list_remove( &radio->entry );
+    }
+    LeaveCriticalSection( &device_list_cs );
+
+    IoInvalidateDeviceRelations( bus_pdo, BusRelations );
+}
+
 static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added event )
 {
     struct bluetooth_pdo_ext *ext;
+    struct bluetooth_radio *radio;
     DEVICE_OBJECT *device_obj;
     UNICODE_STRING string;
     NTSTATUS status;
@@ -758,6 +849,18 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added
     WCHAR *hw_name;
     static unsigned int radio_index;
 
+    EnterCriticalSection( &device_list_cs );
+    LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry )
+    {
+        if (winebluetooth_radio_equal( radio->radio, event.radio ))
+        {
+            WARN( "Radio %#Ix already exists, skipping.\n", event.radio.handle );
+            LeaveCriticalSection( &device_list_cs );
+            winebluetooth_radio_free( event.radio );
+            return;
+        }
+    }
+
     swprintf( name, ARRAY_SIZE( name ), L"\\Device\\WINEBTH-RADIO-%d", radio_index++ );
     TRACE( "Adding new bluetooth radio %p: %s\n", (void *)event.radio.handle, debugstr_w( name ) );
 
@@ -765,6 +868,8 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added
     if (status)
     {
         ERR( "Failed to get hardware name for radio %p, status %#lx\n", (void *)event.radio.handle, status );
+        LeaveCriticalSection( &device_list_cs );
+        winebluetooth_radio_free( event.radio );
         return;
     }
 
@@ -774,6 +879,8 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added
     if (status)
     {
         ERR( "Failed to create device, status %#lx\n", status );
+        LeaveCriticalSection( &device_list_cs );
+        winebluetooth_radio_free( event.radio );
         return;
     }
 
@@ -790,7 +897,6 @@ static void add_bluetooth_radio( struct winebluetooth_watcher_event_radio_added
 
     InitializeListHead( &ext->radio.irp_list );
 
-    EnterCriticalSection( &device_list_cs );
     list_add_tail( &device_list, &ext->radio.entry );
     LeaveCriticalSection( &device_list_cs );
 
@@ -809,7 +915,6 @@ static void remove_bluetooth_radio( winebluetooth_radio_t radio )
             TRACE( "Removing bluetooth radio %p\n", (void *)radio.handle );
             device->removed = TRUE;
             list_remove( &device->entry );
-            IoInvalidateDeviceRelations( device->device_obj, BusRelations );
             break;
         }
     }
@@ -902,10 +1007,21 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even
     {
         if (winebluetooth_radio_equal( event.radio, radio->radio ))
         {
+            struct bluetooth_remote_device *device;
             struct bluetooth_pdo_ext *ext;
             DEVICE_OBJECT *device_obj;
             NTSTATUS status;
 
+            LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry )
+            {
+                if (winebluetooth_device_equal( device->device, event.device ))
+                {
+                    WARN( "Remote device %#Ix already exists, skipping.\n", event.device.handle );
+                    winebluetooth_device_free( event.device );
+                    goto done;
+                }
+            }
+
             status = IoCreateDevice( driver_obj, sizeof( *ext ), NULL, FILE_DEVICE_BLUETOOTH,
                                      FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &device_obj );
             if (status)
@@ -943,6 +1059,7 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even
             break;
         }
     }
+done:
     LeaveCriticalSection( &device_list_cs );
 
     winebluetooth_radio_free( event.radio );
@@ -1171,36 +1288,26 @@ static void bluetooth_radio_report_auth_event( struct winebluetooth_auth_event e
 
 static void complete_irp( IRP *irp, NTSTATUS result )
 {
-    EnterCriticalSection( &device_list_cs );
     RemoveEntryList( &irp->Tail.Overlay.ListEntry );
-    LeaveCriticalSection( &device_list_cs );
 
     irp->IoStatus.Status = result;
     IoCompleteRequest( irp, IO_NO_INCREMENT );
 }
 
+/* Enables the low energy interface for this device if it hasn't been already. Caller should hold device->props_cs. */
 static void bluetooth_device_enable_le_iface( struct bluetooth_remote_device *device )
 {
-    EnterCriticalSection( &device->props_cs );
     /* The device hasn't been started by the PnP manager yet. Set le, and let remote_device_pdo_pnp enable the
      * interface. */
     if (!device->started)
-    {
         device->le = TRUE;
-        LeaveCriticalSection( &device->props_cs );
-        return;
-    }
-
-    if (device->le)
+    else if (!device->le)
     {
-        LeaveCriticalSection( &device->props_cs );
-        return;
-    }
-    device->le = TRUE;
-    if (!IoRegisterDeviceInterface( device->device_obj, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL,
-                                    &device->bthle_symlink_name ))
+        device->le = TRUE;
+        if (!IoRegisterDeviceInterface( device->device_obj, &GUID_BLUETOOTHLE_DEVICE_INTERFACE, NULL,
+            &device->bthle_symlink_name ))
         IoSetDeviceInterfaceState( &device->bthle_symlink_name, TRUE );
-    LeaveCriticalSection( &device->props_cs );
+    }
 }
 
 static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_event_gatt_service_added event )
@@ -1216,10 +1323,22 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even
         {
             if (winebluetooth_device_equal( event.device, device->device ) && !device->removed)
             {
+                struct bluetooth_gatt_service *service;
                 struct bluetooth_pdo_ext *ext;
                 DEVICE_OBJECT *device_obj;
                 NTSTATUS status;
 
+                EnterCriticalSection( &device->props_cs );
+                LIST_FOR_EACH_ENTRY( service, &device->gatt_services, struct bluetooth_gatt_service, entry )
+                {
+                    if (winebluetooth_gatt_service_equal( service->service, event.service ))
+                    {
+                        WARN( "GATT service %#Ix already exists, skipping.\n", event.device.handle );
+                        LeaveCriticalSection( &device->props_cs );
+                        goto failed;
+                    }
+                }
+
                 TRACE( "Adding GATT service %s for remote device %p\n", debugstr_guid( &event.uuid ),
                        (void *)event.device.handle );
 
@@ -1228,6 +1347,7 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even
                 if (status)
                 {
                     ERR( "Failed to create GATT service PDO, status %#lx\n", status );
+                    LeaveCriticalSection( &device->props_cs );
                     goto failed;
                 }
 
@@ -1239,13 +1359,13 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even
                 ext->gatt_service.primary = !!event.is_primary;
                 ext->gatt_service.handle = event.attr_handle;
                 ext->gatt_service.remote_device = device;
+                InitializeListHead( &ext->gatt_service.irp_list );
 
                 list_init( &ext->gatt_service.characteristics );
                 InitializeCriticalSectionEx( &ext->gatt_service.chars_cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO );
                 ext->gatt_service.chars_cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": bluetooth_gatt_service.chars_cs");
                 bluetooth_device_enable_le_iface( device );
 
-                EnterCriticalSection( &device->props_cs );
                 list_add_tail( &device->gatt_services, &ext->gatt_service.entry );
                 LeaveCriticalSection( &device->props_cs );
 
@@ -1328,11 +1448,34 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga
                 {
                     struct bluetooth_gatt_characteristic *entry;
 
+                    LIST_FOR_EACH_ENTRY( entry, &svc->characteristics, struct bluetooth_gatt_characteristic, entry )
+                    {
+                        if (winebluetooth_gatt_characteristic_equal( entry->characteristic, characteristic.characteristic ))
+                        {
+                            WARN( "GATT characteristic %#Ix already exists, skipping.\n",
+                                  entry->characteristic.handle );
+                            LeaveCriticalSection( &device->props_cs );
+                            goto failed;
+                        }
+                    }
+
                     if (!(entry = calloc( 1, sizeof( *entry ) )))
                     {
                         LeaveCriticalSection( &device->props_cs );
                         goto failed;
                     }
+                    if (characteristic.value.size)
+                    {
+                        entry->value = calloc( 1, offsetof( BTH_LE_GATT_CHARACTERISTIC_VALUE, Data[characteristic.value.size] ) );
+                        if (!entry->value)
+                        {
+                            LeaveCriticalSection( &device->props_cs );
+                            free( entry );
+                            goto failed;
+                        }
+                        entry->value->DataSize = characteristic.value.size;
+                        winebluetooth_gatt_characteristic_value_move( &characteristic.value, entry->value->Data );
+                    }
 
                     TRACE( "Adding GATT characteristic %#x under service %s for device %p\n",
                            characteristic.props.AttributeHandle, debugstr_guid( &svc->uuid ),
@@ -1352,6 +1495,7 @@ bluetooth_gatt_service_add_characteristic( struct winebluetooth_watcher_event_ga
     }
 failed:
     LeaveCriticalSection( &device_list_cs );
+    winebluetooth_gatt_characteristic_value_free( &characteristic.value );
     winebluetooth_gatt_characteristic_free( characteristic.characteristic );
     winebluetooth_gatt_service_free( characteristic.service );
 }
@@ -1390,6 +1534,8 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris
 
                         winebluetooth_gatt_characteristic_free( chrc->characteristic );
                         winebluetooth_gatt_characteristic_free( handle );
+                        if (chrc->value)
+                            free( chrc->value );
                         free( chrc );
                         return;
                     }
@@ -1403,6 +1549,102 @@ static void bluetooth_gatt_characteristic_remove( winebluetooth_gatt_characteris
     winebluetooth_gatt_characteristic_free( handle );
 }
 
+static void bluetooth_gatt_characteristic_value_update( struct winebluetooth_watcher_event_gatt_characteristic_value_changed event )
+{
+    struct bluetooth_radio *radio;
+    BOOL free_chrc_val = TRUE;
+
+    EnterCriticalSection( &device_list_cs );
+    LIST_FOR_EACH_ENTRY( radio, &device_list, struct bluetooth_radio, entry )
+    {
+        struct bluetooth_remote_device *device;
+
+        LIST_FOR_EACH_ENTRY( device, &radio->remote_devices, struct bluetooth_remote_device, entry )
+        {
+            struct bluetooth_gatt_service *svc;
+
+            EnterCriticalSection( &device->props_cs );
+            if (!device->le)
+            {
+                LeaveCriticalSection( &device->props_cs );
+                continue;
+            }
+            LIST_FOR_EACH_ENTRY( svc, &device->gatt_services, struct bluetooth_gatt_service, entry )
+            {
+                struct bluetooth_gatt_characteristic *chrc;
+
+                EnterCriticalSection( &svc->chars_cs );
+                LIST_FOR_EACH_ENTRY( chrc, &svc->characteristics, struct bluetooth_gatt_characteristic, entry )
+                {
+                    if (winebluetooth_gatt_characteristic_equal( chrc->characteristic, event.characteristic ))
+                    {
+                        if (!chrc->value || chrc->value->DataSize < event.value.size)
+                        {
+                            void *tmp;
+
+                            tmp = realloc( chrc->value, offsetof( BTH_LE_GATT_CHARACTERISTIC_VALUE, Data[event.value.size] ) );
+                            if (!tmp)
+                            {
+                                LeaveCriticalSection( &svc->chars_cs );
+                                LeaveCriticalSection( &device->props_cs );
+                                goto done;
+                            }
+                            chrc->value = tmp;
+                        }
+                        chrc->value->DataSize = event.value.size;
+                        winebluetooth_gatt_characteristic_value_move( &event.value, chrc->value->Data );
+                        free_chrc_val = FALSE;
+                        LeaveCriticalSection( &svc->chars_cs );
+                        LeaveCriticalSection( &device->props_cs );
+                        goto done;
+                    }
+                }
+                LeaveCriticalSection( &svc->chars_cs );
+            }
+            LeaveCriticalSection( &device->props_cs );
+        }
+    }
+done:
+    LeaveCriticalSection( &device_list_cs );
+    if (free_chrc_val)
+        winebluetooth_gatt_characteristic_value_free( &event.value );
+    winebluetooth_gatt_characteristic_free( event.characteristic );
+}
+
+static void bluetooth_gatt_characteristic_value_read_complete_irp(
+    struct winebluetooth_watcher_event_gatt_characteristic_value_read read )
+{
+    IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation( read.irp );
+    struct bluetooth_pdo_ext *ext = stack->DeviceObject->DeviceExtension;
+    NTSTATUS status;
+
+    assert( ext->type == BLUETOOTH_PDO_EXT_GATT_SERVICE );
+
+    if (!(status = read.result))
+    {
+        ULONG needed = offsetof( struct winebth_gatt_service_read_characterisitic_value_params, buf[read.value.size] );
+        struct winebth_gatt_service_read_characterisitic_value_params *params = read.irp->AssociatedIrp.SystemBuffer;
+        ULONG outsize = stack->Parameters.DeviceIoControl.OutputBufferLength;
+
+        params->size = read.value.size;
+        if (outsize >= needed)
+        {
+            read.irp->IoStatus.Information = needed;
+            winebluetooth_gatt_characteristic_value_move( &read.value, params->buf );
+        }
+        else
+        {
+            status = STATUS_MORE_ENTRIES;
+            read.irp->IoStatus.Information = sizeof( *params );
+            winebluetooth_gatt_characteristic_value_free( &read.value );
+        }
+    }
+
+    EnterCriticalSection( &ext->gatt_service.chars_cs );
+    complete_irp( read.irp, status );
+    LeaveCriticalSection( &ext->gatt_service.chars_cs );
+}
+
 static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg )
 {
     NTSTATUS status;
@@ -1420,6 +1662,9 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg )
                 struct winebluetooth_watcher_event *event = &result.data.watcher_event;
                 switch (event->event_type)
                 {
+                    case BLUETOOTH_WATCHER_EVENT_TYPE_SERVICE_DOWN:
+                        bluetooth_remove_all_radios();
+                        break;
                     case BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED:
                         add_bluetooth_radio( event->event_data.radio_added );
                         break;
@@ -1439,8 +1684,10 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg )
                         bluetooth_radio_update_device_props( event->event_data.device_props_changed);
                         break;
                     case BLUETOOTH_WATCHER_EVENT_TYPE_PAIRING_FINISHED:
+                        EnterCriticalSection( &device_list_cs );
                         complete_irp( event->event_data.pairing_finished.irp,
                                       event->event_data.pairing_finished.result );
+                        LeaveCriticalSection( &device_list_cs );
                         break;
                     case BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_GATT_SERVICE_ADDED:
                         bluetooth_device_add_gatt_service( event->event_data.gatt_service_added );
@@ -1454,6 +1701,13 @@ static DWORD CALLBACK bluetooth_event_loop_thread_proc( void *arg )
                     case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED:
                         bluetooth_gatt_characteristic_remove( event->event_data.gatt_characterisic_removed );
                         break;
+                    case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED:
+                        bluetooth_gatt_characteristic_value_update( event->event_data.gatt_characteristic_value_changed );
+                        break;
+                    case BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ:
+                        bluetooth_gatt_characteristic_value_read_complete_irp(
+                            event->event_data.gatt_characteristic_value_read );
+                        break;
                     default:
                         FIXME( "Unknown bluetooth watcher event code: %#x\n", event->event_type );
                 }
@@ -1697,13 +1951,12 @@ static void bluetooth_radio_set_properties( DEVICE_OBJECT *obj,
                                  sizeof( props->version ), &props->version );
 }
 
-/* Caller should hold device_list_cs. */
-static void remove_pending_irps( struct bluetooth_radio *radio )
+static void remove_pending_irps( LIST_ENTRY *irp_list )
 {
     LIST_ENTRY *entry;
     IRP *irp;
 
-    while ((entry = RemoveHeadList( &radio->irp_list )) != &radio->irp_list)
+    while ((entry = RemoveHeadList( irp_list )) != irp_list)
     {
         irp = CONTAINING_RECORD( entry, IRP, Tail.Overlay.ListEntry );
         irp->IoStatus.Status = STATUS_DELETE_PENDING;
@@ -1757,7 +2010,9 @@ static NTSTATUS WINAPI gatt_service_pdo_pnp( DEVICE_OBJECT *device_obj, struct b
     case IRP_MN_REMOVE_DEVICE:
     {
         struct bluetooth_gatt_characteristic *chrc, *next;
+
         assert( ext->removed );
+        remove_pending_irps( &ext->irp_list );
         if (ext->service_symlink_name.Buffer)
         {
             IoSetDeviceInterfaceState( &ext->service_symlink_name, FALSE );
@@ -1776,6 +2031,7 @@ static NTSTATUS WINAPI gatt_service_pdo_pnp( DEVICE_OBJECT *device_obj, struct b
     }
     case IRP_MN_SURPRISE_REMOVAL:
     {
+        remove_pending_irps( &ext->irp_list );
         EnterCriticalSection( &ext->remote_device->props_cs );
         if (!ext->removed)
         {
@@ -1986,7 +2242,7 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot
         case IRP_MN_REMOVE_DEVICE:
             assert( device->removed );
             EnterCriticalSection( &device_list_cs );
-            remove_pending_irps( device );
+            remove_pending_irps( &device->irp_list );
             LeaveCriticalSection( &device_list_cs );
 
             if (device->bthport_symlink_name.Buffer)
@@ -2006,7 +2262,7 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot
             break;
         case IRP_MN_SURPRISE_REMOVAL:
             EnterCriticalSection( &device_list_cs );
-            remove_pending_irps( device );
+            remove_pending_irps( &device->irp_list );
             if (!device->removed)
             {
                 device->removed = TRUE;
diff --git a/dlls/winebth.sys/winebth_priv.h b/dlls/winebth.sys/winebth_priv.h
index 765fe1d55f78..d2d8c4477e11 100644
--- a/dlls/winebth.sys/winebth_priv.h
+++ b/dlls/winebth.sys/winebth_priv.h
@@ -262,8 +262,19 @@ static inline BOOL winebluetooth_gatt_characteristic_equal( winebluetooth_gatt_c
     return c1.handle == c2.handle;
 }
 
+struct winebluetooth_gatt_characteristic_value
+{
+    UINT32 size;
+    UINT_PTR handle;
+};
+
+void winebluetooth_gatt_characteristic_value_move( struct winebluetooth_gatt_characteristic_value *val, BYTE *dest );
+void winebluetooth_gatt_characteristic_value_free( struct winebluetooth_gatt_characteristic_value *val );
+NTSTATUS winebluetooth_gatt_characteristic_read_async( winebluetooth_gatt_characteristic_t chrc, IRP *irp );
+
 enum winebluetooth_watcher_event_type
 {
+    BLUETOOTH_WATCHER_EVENT_TYPE_SERVICE_DOWN,
     BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_ADDED,
     BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_REMOVED,
     BLUETOOTH_WATCHER_EVENT_TYPE_RADIO_PROPERTIES_CHANGED,
@@ -275,6 +286,8 @@ enum winebluetooth_watcher_event_type
     BLUETOOTH_WATCHER_EVENT_TYPE_DEVICE_GATT_SERVICE_REMOVED,
     BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_ADDED,
     BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_REMOVED,
+    BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_CHANGED,
+    BLUETOOTH_WATCHER_EVENT_TYPE_GATT_CHARACTERISTIC_VALUE_READ,
 };
 
 struct winebluetooth_watcher_event_radio_added
@@ -346,6 +359,20 @@ struct winebluetooth_watcher_event_gatt_characteristic_added
     winebluetooth_gatt_characteristic_t characteristic;
     winebluetooth_gatt_service_t service;
     BTH_LE_GATT_CHARACTERISTIC props;
+    struct winebluetooth_gatt_characteristic_value value;
+};
+
+struct winebluetooth_watcher_event_gatt_characteristic_value_changed
+{
+    winebluetooth_gatt_characteristic_t characteristic;
+    struct winebluetooth_gatt_characteristic_value value;
+};
+
+struct winebluetooth_watcher_event_gatt_characteristic_value_read
+{
+    IRP *irp;
+    struct winebluetooth_gatt_characteristic_value value;
+    NTSTATUS result;
 };
 
 union winebluetooth_watcher_event_data
@@ -361,6 +388,8 @@ union winebluetooth_watcher_event_data
     winebluetooth_gatt_service_t gatt_service_removed;
     struct winebluetooth_watcher_event_gatt_characteristic_added gatt_characteristic_added;
     winebluetooth_gatt_characteristic_t gatt_characterisic_removed;
+    struct winebluetooth_watcher_event_gatt_characteristic_value_changed gatt_characteristic_value_changed;
+    struct winebluetooth_watcher_event_gatt_characteristic_value_read gatt_characteristic_value_read;
 };
 
 struct winebluetooth_watcher_event
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 45f480d693c0..e754cc633b72 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4441,7 +4441,7 @@ void CDECL wined3d_device_context_update_sub_resource(struct wined3d_device_cont
 void CDECL wined3d_device_context_resolve_sub_resource(struct wined3d_device_context *context,
         struct wined3d_resource *dst_resource, unsigned int dst_sub_resource_idx,
         struct wined3d_resource *src_resource, unsigned int src_sub_resource_idx,
-        enum wined3d_format_id format_id)
+        uint32_t flags, enum wined3d_format_id format_id)
 {
     struct wined3d_texture *dst_texture, *src_texture;
     unsigned int dst_level, src_level;
@@ -4485,7 +4485,7 @@ void CDECL wined3d_device_context_resolve_sub_resource(struct wined3d_device_con
     SetRect(&src_rect, 0, 0, wined3d_texture_get_level_width(src_texture, src_level),
             wined3d_texture_get_level_height(src_texture, src_level));
     wined3d_device_context_blt(context, dst_texture, dst_sub_resource_idx, &dst_rect,
-            src_texture, src_sub_resource_idx, &src_rect, 0, &fx, WINED3D_TEXF_POINT);
+            src_texture, src_sub_resource_idx, &src_rect, flags, &fx, WINED3D_TEXF_POINT);
     wined3d_device_context_unlock(context);
 }
 
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index def9182d9b37..2e7017ec8c42 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -2806,7 +2806,7 @@ static void resolve_depth_buffer(struct wined3d_device *device)
         return;
 
     wined3d_device_context_resolve_sub_resource(&device->cs->c, dst_resource, 0,
-            src_view->resource, src_view->sub_resource_idx, dst_resource->format->id);
+            src_view->resource, src_view->sub_resource_idx, 0, dst_resource->format->id);
 }
 
 static void wined3d_device_set_render_state(struct wined3d_device *device,
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 067b3afc30e1..cf081a17c68e 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -1379,7 +1379,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_
     BOOL scale, convert, resolve, resolve_typeless = FALSE;
     const struct wined3d_format *resolve_format = NULL;
     const struct wined3d_color_key *colour_key = NULL;
-    DWORD src_location, dst_location, valid_locations;
+    DWORD dst_location, valid_locations;
     struct wined3d_context *context;
     enum wined3d_blit_op blit_op;
     RECT src_rect, dst_rect;
@@ -1613,13 +1613,6 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_
 
     context = context_acquire(device, dst_texture, dst_sub_resource_idx);
 
-    if (src_texture->resource.multisample_type != WINED3D_MULTISAMPLE_NONE && !resolve_typeless
-            && ((scale && !context->d3d_info->scaled_resolve)
-            || convert || !wined3d_is_colour_blit(blit_op)))
-        src_location = WINED3D_LOCATION_RB_RESOLVED;
-    else
-        src_location = src_texture->resource.draw_binding;
-
     if (!(dst_texture->resource.access & WINED3D_RESOURCE_ACCESS_GPU))
         dst_location = dst_texture->resource.map_binding;
     else if (dst_texture->resource.multisample_type != WINED3D_MULTISAMPLE_NONE
@@ -1629,7 +1622,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_
         dst_location = dst_texture->resource.draw_binding;
 
     valid_locations = device->blitter->ops->blitter_blit(device->blitter, blit_op, context,
-            src_texture, src_sub_resource_idx, src_location, &src_rect,
+            src_texture, src_sub_resource_idx, src_texture->resource.draw_binding, &src_rect,
             dst_texture, dst_sub_resource_idx, dst_location, &dst_rect, colour_key, filter, resolve_format);
 
     context_release(context);
diff --git a/dlls/wined3d/texture_gl.c b/dlls/wined3d/texture_gl.c
index 4996a24545c7..311ee954c239 100644
--- a/dlls/wined3d/texture_gl.c
+++ b/dlls/wined3d/texture_gl.c
@@ -496,6 +496,33 @@ static bool gl_formats_compatible(struct wined3d_texture *src_texture, DWORD src
     return src_internal == dst_internal;
 }
 
+static bool raw_blitter_supported(enum wined3d_blit_op op, struct wined3d_texture *src_texture,
+        uint32_t src_location, struct wined3d_texture *dst_texture, uint32_t dst_location)
+{
+    if (op != WINED3D_BLIT_OP_RAW_BLIT)
+        return false;
+
+    if (!gl_formats_compatible(src_texture, src_location, dst_texture, dst_location))
+        return false;
+
+    if (((src_texture->resource.format_attrs | dst_texture->resource.format_attrs) & WINED3D_FORMAT_ATTR_HEIGHT_SCALE))
+        return false;
+
+    if (wined3d_resource_get_sample_count(&src_texture->resource)
+            != wined3d_resource_get_sample_count(&dst_texture->resource))
+        return false;
+
+    /* If we would need to copy from a renderbuffer or drawable, we'd probably
+     * be better off using the FBO blitter directly, since we'd need to use it
+     * to copy the resource contents to the texture anyway. */
+    if (src_texture->resource.format->id == dst_texture->resource.format->id
+            && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
+            || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))))
+        return false;
+
+    return true;
+}
+
 static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_op op,
         struct wined3d_context *context, struct wined3d_texture *src_texture, unsigned int src_sub_resource_idx,
         DWORD src_location, const RECT *src_rect, struct wined3d_texture *dst_texture,
@@ -512,18 +539,7 @@ static DWORD raw_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit
     GLuint src_name, dst_name;
     DWORD location;
 
-    /* If we would need to copy from a renderbuffer or drawable, we'd probably
-     * be better off using the FBO blitter directly, since we'd need to use it
-     * to copy the resource contents to the texture anyway.
-     *
-     * We also can't copy between depth/stencil and colour resources, since
-     * the formats are considered incompatible in OpenGL. */
-    if (op != WINED3D_BLIT_OP_RAW_BLIT || !gl_formats_compatible(src_texture, src_location, dst_texture, dst_location)
-            || ((src_texture->resource.format_attrs | dst_texture->resource.format_attrs)
-                    & WINED3D_FORMAT_ATTR_HEIGHT_SCALE)
-            || (src_texture->resource.format->id == dst_texture->resource.format->id
-            && (!(src_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB))
-            || !(dst_location & (WINED3D_LOCATION_TEXTURE_RGB | WINED3D_LOCATION_TEXTURE_SRGB)))))
+    if (!raw_blitter_supported(op, src_texture, src_location, dst_texture, dst_location))
     {
         if (!(next = blitter->next))
         {
@@ -637,6 +653,13 @@ static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct win
     if (src_ds != dst_ds)
         return false;
 
+    /* We can't do raw blits, but we are the only blitter that can do resolve,
+     * so we handle this case by delegating the format conversion to the raw
+     * blitter. */
+    if (blit_op == WINED3D_BLIT_OP_RAW_BLIT && src_resource->multisample_type != WINED3D_MULTISAMPLE_NONE
+            && dst_resource->multisample_type == WINED3D_MULTISAMPLE_NONE)
+        blit_op = src_ds ? WINED3D_BLIT_OP_DEPTH_BLIT : WINED3D_BLIT_OP_COLOR_BLIT;
+
     switch (blit_op)
     {
         case WINED3D_BLIT_OP_COLOR_BLIT:
@@ -674,7 +697,7 @@ static bool fbo_blitter_supported(enum wined3d_blit_op blit_op, const struct win
 /* Blit between surface locations. Onscreen on different swapchains is not supported.
  * Depth / stencil is not supported. Context activation is done by the caller. */
 static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_context *context,
-        enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
+        enum wined3d_blit_op blit_op, enum wined3d_texture_filter_type filter, struct wined3d_texture *src_texture,
         unsigned int src_sub_resource_idx, DWORD src_location, const RECT *src_rect,
         struct wined3d_texture *dst_texture, unsigned int dst_sub_resource_idx, DWORD dst_location,
         const RECT *dst_rect, const struct wined3d_format *resolve_format)
@@ -700,6 +723,16 @@ static void texture2d_blt_fbo(struct wined3d_device *device, struct wined3d_cont
             && (abs(src_rect->bottom - src_rect->top) != abs(dst_rect->bottom - dst_rect->top)
             || abs(src_rect->right - src_rect->left) != abs(dst_rect->right - dst_rect->left));
 
+    if (resolve && blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
+    {
+        if ((scaled_resolve && !context->d3d_info->scaled_resolve)
+                || src_texture->resource.format->id != dst_texture->resource.format->id)
+        {
+            src_location = WINED3D_LOCATION_RB_RESOLVED;
+            resolve = scaled_resolve = false;
+        }
+    }
+
     if (filter == WINED3D_TEXF_LINEAR)
         gl_filter = scaled_resolve ? GL_SCALED_RESOLVE_NICEST_EXT : GL_LINEAR;
     else
@@ -1056,10 +1089,10 @@ static DWORD fbo_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit
                 resolve_format);
     }
 
-    if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT)
+    if (blit_op == WINED3D_BLIT_OP_COLOR_BLIT || blit_op == WINED3D_BLIT_OP_RAW_BLIT)
     {
         TRACE("Colour blit.\n");
-        texture2d_blt_fbo(device, context, filter, src_texture, src_sub_resource_idx, src_location,
+        texture2d_blt_fbo(device, context, blit_op, filter, src_texture, src_sub_resource_idx, src_location,
                 src_rect, dst_texture, dst_sub_resource_idx, dst_location, dst_rect, resolve_format);
         return dst_location;
     }
@@ -2089,7 +2122,7 @@ static BOOL wined3d_texture_load_renderbuffer(struct wined3d_texture *texture,
     else /* texture2d_blt_fbo() will load the source location if necessary. */
         src_location = WINED3D_LOCATION_TEXTURE_RGB;
 
-    texture2d_blt_fbo(texture->resource.device, context, WINED3D_TEXF_POINT, texture,
+    texture2d_blt_fbo(texture->resource.device, context, WINED3D_BLIT_OP_COLOR_BLIT, WINED3D_TEXF_POINT, texture,
             sub_resource_idx, src_location, &rect, texture, sub_resource_idx, dst_location, &rect, NULL);
 
     return TRUE;
@@ -2123,11 +2156,11 @@ static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_g
 
         SetRect(&src_rect, src_box.left, src_box.top, src_box.right, src_box.bottom);
         if (srgb)
-            texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
+            texture2d_blt_fbo(device, &context_gl->c, WINED3D_BLIT_OP_COLOR_BLIT, WINED3D_TEXF_POINT,
                     &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect,
                     &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect, NULL);
         else
-            texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT,
+            texture2d_blt_fbo(device, &context_gl->c, WINED3D_BLIT_OP_COLOR_BLIT, WINED3D_TEXF_POINT,
                     &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_SRGB, &src_rect,
                     &texture_gl->t, sub_resource_idx, WINED3D_LOCATION_TEXTURE_RGB, &src_rect, NULL);
 
@@ -2145,7 +2178,8 @@ static BOOL wined3d_texture_gl_load_texture(struct wined3d_texture_gl *texture_g
         dst_location = srgb ? WINED3D_LOCATION_TEXTURE_SRGB : WINED3D_LOCATION_TEXTURE_RGB;
         if (fbo_blitter_supported(WINED3D_BLIT_OP_COLOR_BLIT, gl_info,
                 &texture_gl->t.resource, src_location, &texture_gl->t.resource, dst_location))
-            texture2d_blt_fbo(device, &context_gl->c, WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx,
+            texture2d_blt_fbo(device, &context_gl->c, WINED3D_BLIT_OP_COLOR_BLIT,
+                    WINED3D_TEXF_POINT, &texture_gl->t, sub_resource_idx,
                     src_location, &src_rect, &texture_gl->t, sub_resource_idx, dst_location, &src_rect, NULL);
 
         return TRUE;
diff --git a/dlls/wined3d/texture_vk.c b/dlls/wined3d/texture_vk.c
index a11606303c15..cedf068319c5 100644
--- a/dlls/wined3d/texture_vk.c
+++ b/dlls/wined3d/texture_vk.c
@@ -1574,13 +1574,13 @@ static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wine
     return true;
 }
 
-static bool use_raw_blit(enum wined3d_blit_op op, const struct wined3d_format_vk *src_format_vk,
-        const struct wined3d_format_vk *dst_format_vk, const RECT *src_rect, const RECT *dst_rect)
+static bool use_raw_blit(enum wined3d_blit_op op, VkFormat src_format,
+        VkFormat dst_format, const RECT *src_rect, const RECT *dst_rect)
 {
     if (op == WINED3D_BLIT_OP_RAW_BLIT)
         return true;
 
-    return src_format_vk->vk_format == dst_format_vk->vk_format
+    return src_format == dst_format
             && src_rect->right - src_rect->left == dst_rect->right - dst_rect->left
             && src_rect->bottom - src_rect->top == dst_rect->bottom - dst_rect->top;
 }
@@ -1694,6 +1694,7 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
         VkImageType vk_image_type;
         VkImageCopy copy_region;
         VkFormat vk_format;
+        bool raw;
 
         if (resolve_format)
         {
@@ -1807,7 +1808,9 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
             resolve_region.srcOffset.z = 0;
         }
 
-        if (dst_format_vk->vk_format != vk_format)
+        raw = use_raw_blit(op, vk_format, dst_format_vk->vk_format, src_rect, dst_rect);
+
+        if (dst_format_vk->vk_format != vk_format || !raw)
         {
             struct wined3d_image_vk dst_image;
 
@@ -1857,29 +1860,60 @@ static DWORD vk_blitter_blit(struct wined3d_blitter *blitter, enum wined3d_blit_
                     resolve_dst_layout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
                     dst_vk_image, &vk_range);
 
-            copy_region.srcSubresource.aspectMask = vk_dst_range.aspectMask;
-            copy_region.srcSubresource.mipLevel = 0;
-            copy_region.srcSubresource.baseArrayLayer = 0;
-            copy_region.srcSubresource.layerCount = 1;
-            copy_region.srcOffset.x = 0;
-            copy_region.srcOffset.y = 0;
-            copy_region.srcOffset.z = 0;
-            copy_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
-            copy_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
-            copy_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
-            copy_region.dstSubresource.layerCount = 1;
-            copy_region.dstOffset.x = dst_rect->left;
-            copy_region.dstOffset.y = dst_rect->top;
-            copy_region.dstOffset.z = 0;
-            copy_region.extent.width = resolve_region.extent.width;
-            copy_region.extent.height = resolve_region.extent.height;
-            copy_region.extent.depth = 1;
-
-            VK_CALL(vkCmdCopyImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
-                    dst_texture_vk->image.vk_image, dst_layout, 1, &copy_region));
+            if (raw)
+            {
+                copy_region.srcSubresource.aspectMask = vk_dst_range.aspectMask;
+                copy_region.srcSubresource.mipLevel = 0;
+                copy_region.srcSubresource.baseArrayLayer = 0;
+                copy_region.srcSubresource.layerCount = 1;
+                copy_region.srcOffset.x = 0;
+                copy_region.srcOffset.y = 0;
+                copy_region.srcOffset.z = 0;
+                copy_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
+                copy_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
+                copy_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
+                copy_region.dstSubresource.layerCount = 1;
+                copy_region.dstOffset.x = dst_rect->left;
+                copy_region.dstOffset.y = dst_rect->top;
+                copy_region.dstOffset.z = 0;
+                copy_region.extent.width = resolve_region.extent.width;
+                copy_region.extent.height = resolve_region.extent.height;
+                copy_region.extent.depth = 1;
+
+                VK_CALL(vkCmdCopyImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                        dst_texture_vk->image.vk_image, dst_layout, 1, &copy_region));
+            }
+            else
+            {
+                VkImageBlit blit_region;
+
+                blit_region.srcSubresource.aspectMask = vk_dst_range.aspectMask;
+                blit_region.srcSubresource.mipLevel = 0;
+                blit_region.srcSubresource.baseArrayLayer = 0;
+                blit_region.srcSubresource.layerCount = 1;
+                blit_region.srcOffsets[0].x = 0;
+                blit_region.srcOffsets[0].y = 0;
+                blit_region.srcOffsets[0].z = 0;
+                blit_region.srcOffsets[1].x = resolve_region.extent.width;
+                blit_region.srcOffsets[1].y = resolve_region.extent.height;
+                blit_region.srcOffsets[1].z = 1;
+                blit_region.dstSubresource.aspectMask = vk_dst_range.aspectMask;
+                blit_region.dstSubresource.mipLevel = vk_dst_range.baseMipLevel;
+                blit_region.dstSubresource.baseArrayLayer = vk_dst_range.baseArrayLayer;
+                blit_region.dstSubresource.layerCount = 1;
+                blit_region.dstOffsets[0].x = dst_rect->left;
+                blit_region.dstOffsets[0].y = dst_rect->top;
+                blit_region.dstOffsets[0].z = 0;
+                blit_region.dstOffsets[1].x = dst_rect->right;
+                blit_region.dstOffsets[1].y = dst_rect->bottom;
+                blit_region.dstOffsets[1].z = 1;
+
+                VK_CALL(vkCmdBlitImage(vk_command_buffer, dst_vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
+                        dst_texture_vk->image.vk_image, dst_layout, 1, &blit_region, vk_filter_from_wined3d(filter)));
+            }
         }
     }
-    else if (use_raw_blit(op, src_format_vk, dst_format_vk, src_rect, dst_rect))
+    else if (use_raw_blit(op, src_format_vk->vk_format, dst_format_vk->vk_format, src_rect, dst_rect))
     {
         const struct wined3d_format *src_format = src_texture_vk->t.resource.format;
         VkImageCopy region;
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index dc86887c2514..e08dd0895212 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -141,7 +141,7 @@
 @ cdecl wined3d_device_context_issue_query(ptr ptr long)
 @ cdecl wined3d_device_context_map(ptr ptr long ptr ptr long)
 @ cdecl wined3d_device_context_reset_state(ptr)
-@ cdecl wined3d_device_context_resolve_sub_resource(ptr ptr long ptr long long)
+@ cdecl wined3d_device_context_resolve_sub_resource(ptr ptr long ptr long long long)
 @ cdecl wined3d_device_context_set_blend_state(ptr ptr ptr long)
 @ cdecl wined3d_device_context_set_constant_buffers(ptr long long long ptr)
 @ cdecl wined3d_device_context_set_depth_stencil_state(ptr ptr long)
diff --git a/dlls/winedmo/unix_demuxer.c b/dlls/winedmo/unix_demuxer.c
index 4c6bc15579b7..de7c8e766118 100644
--- a/dlls/winedmo/unix_demuxer.c
+++ b/dlls/winedmo/unix_demuxer.c
@@ -138,6 +138,7 @@ NTSTATUS demuxer_create( void *arg )
 {
     struct demuxer_create_params *params = arg;
     const char *ext = params->url ? strrchr( params->url, '.' ) : "";
+    BOOL needs_find_stream_info = FALSE;
     const AVInputFormat *format;
     struct demuxer *demuxer;
     int i, ret;
@@ -155,16 +156,36 @@ NTSTATUS demuxer_create( void *arg )
     }
     format = demuxer->ctx->iformat;
 
+    /* Determine if we need a call to avformat_find_stream_info. Some stream information is only
+     * available after calling it. */
     if ((params->duration = get_context_duration( demuxer->ctx )) == AV_NOPTS_VALUE ||
         strstr( format->name, "mp3" ))
+        needs_find_stream_info = TRUE;
+
+    for (i = 0; i < demuxer->ctx->nb_streams && !needs_find_stream_info; i++)
     {
-        if ((ret = avformat_find_stream_info( demuxer->ctx, NULL )) < 0)
-        {
-            ERR( "Failed to find stream info, error %s.\n", debugstr_averr(ret) );
-            goto failed;
-        }
-        params->duration = get_context_duration( demuxer->ctx );
+        /* For H264 streams, sample aspect ratio is sometimes found in its sequence parameter set,
+         * which requires avformat_find_stream_info. */
+        AVStream *stream = demuxer->ctx->streams[i];
+        AVCodecParameters *par = stream->codecpar;
+
+        if (par->codec_id != AV_CODEC_ID_H264) continue;
+
+        /* If sample aspect ratio is available somewhere, skip find stream info. */
+        if (stream->sample_aspect_ratio.den && stream->sample_aspect_ratio.num) continue;
+        if (par->sample_aspect_ratio.den && par->sample_aspect_ratio.num) continue;
+
+        needs_find_stream_info = TRUE;
     }
+
+    if (needs_find_stream_info && (ret = avformat_find_stream_info( demuxer->ctx, NULL )) < 0)
+    {
+        ERR( "Failed to find stream info, error %s.\n", debugstr_averr( ret ) );
+        goto failed;
+    }
+
+    if (params->duration == AV_NOPTS_VALUE) params->duration = get_context_duration( demuxer->ctx );
+
     if (!(demuxer->streams = calloc( demuxer->ctx->nb_streams, sizeof(*demuxer->streams) ))) goto failed;
     if (demuxer_create_streams( demuxer )) goto failed;
 
@@ -367,11 +388,12 @@ NTSTATUS demuxer_stream_type( void *arg )
     struct demuxer *demuxer = get_demuxer( params->demuxer );
     AVStream *stream = demuxer->ctx->streams[params->stream];
     AVCodecParameters *par = demuxer->streams[params->stream].filter->par_out;
+    AVRational sar = stream->sample_aspect_ratio;
 
     TRACE( "demuxer %p, stream %u, stream %p, index %u\n", demuxer, params->stream, stream, stream->index );
 
-    return media_type_from_codec_params( par, &stream->sample_aspect_ratio,
-                                         &stream->avg_frame_rate, 0, &params->media_type );
+    if (!sar.den || !sar.num) sar = stream->codecpar->sample_aspect_ratio;
+    return media_type_from_codec_params( par, &sar, &stream->avg_frame_rate, 0, &params->media_type );
 }
 
 #endif /* HAVE_FFMPEG */
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index 45c36e07ca29..c7893f710263 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -92,7 +92,7 @@ static HRESULT video_format_from_media_type(IMFMediaType *media_type, MFVIDEOFOR
             memset(mpeg, 0, mpeg_size);
             mpeg->hdr = **format;
 
-            IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, mpeg->sequence_header, len, NULL);
+            IMFMediaType_GetBlob(media_type, &MF_MT_MPEG_SEQUENCE_HEADER, mpeg->sequence_header, len, &mpeg->sequence_header_count);
             IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG_START_TIME_CODE, (UINT32 *)&mpeg->start_time_code);
             IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_PROFILE, &mpeg->profile);
             IMFMediaType_GetUINT32(media_type, &MF_MT_MPEG2_LEVEL, &mpeg->level);
diff --git a/dlls/winegstreamer/quartz_parser.c b/dlls/winegstreamer/quartz_parser.c
index f09e8b9382a8..38971f2fcb96 100644
--- a/dlls/winegstreamer/quartz_parser.c
+++ b/dlls/winegstreamer/quartz_parser.c
@@ -745,8 +745,10 @@ static bool amt_from_wg_format_video_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo
 {
     MPEG1VIDEOINFO *video_format;
     uint32_t frame_time;
+    DWORD size;
 
-    if (!(video_format = CoTaskMemAlloc(sizeof(*video_format))))
+    size = offsetof(MPEG1VIDEOINFO, bSequenceHeader) + format->u.video.codec_data_len;
+    if (!(video_format = CoTaskMemAlloc(size)))
         return false;
 
     mt->majortype = MEDIATYPE_Video;
@@ -754,10 +756,10 @@ static bool amt_from_wg_format_video_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo
     mt->bTemporalCompression = TRUE;
     mt->lSampleSize = 1;
     mt->formattype = FORMAT_MPEGVideo;
-    mt->cbFormat = sizeof(MPEG1VIDEOINFO);
+    mt->cbFormat = size;
     mt->pbFormat = (BYTE *)video_format;
 
-    memset(video_format, 0, sizeof(*video_format));
+    memset(video_format, 0, size);
     if ((frame_time = MulDiv(10000000, format->u.video.fps_d, format->u.video.fps_n)) != -1)
         video_format->hdr.AvgTimePerFrame = frame_time;
     video_format->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
@@ -768,6 +770,30 @@ static bool amt_from_wg_format_video_mpeg1(AM_MEDIA_TYPE *mt, const struct wg_fo
     video_format->hdr.bmiHeader.biCompression = mt->subtype.Data1;
     video_format->hdr.bmiHeader.biSizeImage = wg_format_get_max_size(format);
 
+    /* Ignore additional start code units after the sequence header. */
+    size = 12; /* minimum sequence header length */
+    if (format->u.video.codec_data_len >= size
+            && format->u.video.codec_data[0] == 0x00
+            && format->u.video.codec_data[1] == 0x00
+            && format->u.video.codec_data[2] == 0x01
+            && format->u.video.codec_data[3] == 0xb3)
+    {
+        /* has intra quantiser matrix? */
+        if (format->u.video.codec_data[size-1] & 2)
+            size += 64;
+
+        /* has non-intra quantiser matrix? */
+        if (format->u.video.codec_data_len >= size
+                && (format->u.video.codec_data[size-1] & 1))
+            size += 64;
+
+        if (format->u.video.codec_data_len >= size)
+        {
+            video_format->cbSequenceHeader = size;
+            memcpy(video_format->bSequenceHeader, format->u.video.codec_data, size);
+        }
+    }
+
     return true;
 }
 
@@ -1136,7 +1162,7 @@ static bool amt_to_wg_format_video_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_form
         FIXME("Unknown format type %s.\n", debugstr_guid(&mt->formattype));
         return false;
     }
-    if (mt->cbFormat < sizeof(VIDEOINFOHEADER) || !mt->pbFormat)
+    if (!mt->pbFormat || mt->cbFormat < offsetof(MPEG1VIDEOINFO, bSequenceHeader) + video_format->cbSequenceHeader)
     {
         ERR("Unexpected format size %lu.\n", mt->cbFormat);
         return false;
@@ -1148,6 +1174,13 @@ static bool amt_to_wg_format_video_mpeg1(const AM_MEDIA_TYPE *mt, struct wg_form
     format->u.video.fps_n = 10000000;
     format->u.video.fps_d = video_format->hdr.AvgTimePerFrame;
 
+    format->u.video.codec_data_len = video_format->cbSequenceHeader;
+    if (format->u.video.codec_data_len > sizeof(format->u.video.codec_data))
+    {
+        ERR("Too big codec_data value (%u).\n", format->u.video.codec_data_len);
+        format->u.video.codec_data_len = 0;
+    }
+    memcpy(format->u.video.codec_data, video_format->bSequenceHeader, format->u.video.codec_data_len);
     return true;
 }
 
@@ -2270,7 +2303,7 @@ static HRESULT WINAPI GSTOutPin_DecideBufferSize(struct strmbase_source *iface,
     {
         MPEG1VIDEOINFO *format = (MPEG1VIDEOINFO *)pin->pin.pin.mt.pbFormat;
         buffer_size = format->hdr.bmiHeader.biSizeImage;
-        buffer_count = 8;
+        buffer_count = 30;
     }
     else if (IsEqualGUID(&pin->pin.pin.mt.formattype, &FORMAT_WaveFormatEx)
             && (IsEqualGUID(&pin->pin.pin.mt.subtype, &MEDIASUBTYPE_PCM)
diff --git a/dlls/winegstreamer/quartz_transform.c b/dlls/winegstreamer/quartz_transform.c
index 5b4b9e77cf98..63451f5b45c6 100644
--- a/dlls/winegstreamer/quartz_transform.c
+++ b/dlls/winegstreamer/quartz_transform.c
@@ -413,11 +413,29 @@ static HRESULT WINAPI transform_sink_receive(struct strmbase_sink *pin, IMediaSa
     return S_OK;
 }
 
+static HRESULT transform_sink_begin_flush(struct strmbase_sink *pin)
+{
+    struct transform *filter = impl_from_strmbase_filter(pin->pin.filter);
+    HRESULT hr;
+
+    TRACE("(%p)\n", pin);
+
+    hr = wg_transform_flush(filter->transform);
+
+    wg_sample_queue_flush(filter->sample_queue, true);
+
+    if (filter->source.pin.peer)
+        IPin_BeginFlush(filter->source.pin.peer);
+
+    return hr;
+}
+
 static const struct strmbase_sink_ops sink_ops =
 {
     .base.pin_query_accept = transform_sink_query_accept,
     .base.pin_query_interface = transform_sink_query_interface,
     .pfnReceive = transform_sink_receive,
+    .sink_begin_flush = transform_sink_begin_flush,
 };
 
 static HRESULT transform_source_query_accept(struct strmbase_pin *pin, const AM_MEDIA_TYPE *mt)
diff --git a/dlls/winegstreamer/unixlib.h b/dlls/winegstreamer/unixlib.h
index 5d11934fac2a..f545df7ad0b1 100644
--- a/dlls/winegstreamer/unixlib.h
+++ b/dlls/winegstreamer/unixlib.h
@@ -154,7 +154,7 @@ struct wg_format
          * H264: width, height, fps_n, fps_d, profile, level, codec_data_len, codec_data.
          * WMV: width, height, fps_n, fps_d, codec_data_len, codec_data.
          * INDEO: width, height, fps_n, fps_d, version.
-         * MPEG1: width, height, fps_n, fps_d. */
+         * MPEG1: width, height, fps_n, fps_d, codec_data_len, codec_data. */
         struct
         {
             wg_video_format format;
@@ -168,7 +168,7 @@ struct wg_format
             uint32_t level;
             uint32_t version;
             uint32_t codec_data_len;
-            unsigned char codec_data[64];
+            unsigned char codec_data[140]; /* =MAX_SIZE_MPEG1_SEQUENCE_INFO */
         } video;
     } u;
 };
diff --git a/dlls/winegstreamer/wg_format.c b/dlls/winegstreamer/wg_format.c
index bed7ffb2964a..fce3d27a0d3d 100644
--- a/dlls/winegstreamer/wg_format.c
+++ b/dlls/winegstreamer/wg_format.c
@@ -470,6 +470,10 @@ static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstC
 {
     const GstStructure *structure = gst_caps_get_structure(caps, 0);
     gint width, height, fps_n, fps_d;
+    const GValue *codec_data_value;
+    GstBuffer *codec_data;
+    GstMapInfo map;
+    guint size;
 
     if (!gst_structure_get_int(structure, "width", &width))
     {
@@ -481,6 +485,12 @@ static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstC
         GST_WARNING("Missing \"height\" value in %" GST_PTR_FORMAT ".", caps);
         return;
     }
+    if (!(codec_data_value = gst_structure_get_value(structure, "codec_data"))
+            || !(codec_data = gst_value_get_buffer(codec_data_value)))
+    {
+        GST_WARNING("Missing \"codec_data\" value in %" GST_PTR_FORMAT ".", caps);
+        return;
+    }
     if (!gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d))
     {
         fps_n = 0;
@@ -492,6 +502,15 @@ static void wg_format_from_caps_video_mpeg1(struct wg_format *format, const GstC
     format->u.video.height = height;
     format->u.video.fps_n = fps_n;
     format->u.video.fps_d = fps_d;
+
+    gst_buffer_map(codec_data, &map, GST_MAP_READ);
+
+    assert(sizeof(format->u.video.codec_data) >= MAX_SIZE_MPEG1_SEQUENCE_INFO);
+    size = min(map.size, MAX_SIZE_MPEG1_SEQUENCE_INFO);
+    format->u.video.codec_data_len = size;
+    memcpy(format->u.video.codec_data, map.data, size);
+
+    gst_buffer_unmap(codec_data, &map);
 }
 
 static const struct
@@ -1077,6 +1096,7 @@ static GstCaps *wg_format_to_caps_video_indeo(const struct wg_format *format)
 
 static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format)
 {
+    GstBuffer *buffer;
     GstCaps *caps;
 
     if (!(caps = gst_caps_new_empty_simple("video/mpeg")))
@@ -1091,6 +1111,20 @@ static GstCaps *wg_format_to_caps_video_mpeg1(const struct wg_format *format)
         gst_caps_set_simple(caps, "height", G_TYPE_INT, format->u.video.height, NULL);
     if (format->u.video.fps_d || format->u.video.fps_n)
         gst_caps_set_simple(caps, "framerate", GST_TYPE_FRACTION, format->u.video.fps_n, format->u.video.fps_d, NULL);
+
+    if (format->u.video.codec_data_len)
+    {
+        if (!(buffer = gst_buffer_new_and_alloc(format->u.video.codec_data_len)))
+        {
+            gst_caps_unref(caps);
+            return NULL;
+        }
+
+        gst_buffer_fill(buffer, 0, format->u.video.codec_data, format->u.video.codec_data_len);
+        gst_caps_set_simple(caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
+        gst_buffer_unref(buffer);
+    }
+
     return caps;
 }
 
diff --git a/dlls/winegstreamer/wg_parser.c b/dlls/winegstreamer/wg_parser.c
index f1926e3f0811..da414af61345 100644
--- a/dlls/winegstreamer/wg_parser.c
+++ b/dlls/winegstreamer/wg_parser.c
@@ -915,11 +915,9 @@ static bool stream_create_post_processing_elements(GstPad *pad, struct wg_parser
 
     if (!strcmp(name, "video/x-raw"))
     {
-        /* DirectShow can express interlaced video, but downstream filters can't
-         * necessarily consume it. In particular, the video renderer can't. */
-        if (!(element = create_element("deinterlace", "good"))
-                || !append_element(parser->container, element, &first, &last))
-            return false;
+        /* decodebin doesn't provide framerate for raw video. This causes the
+         * the deinterlace element to reject the caps. So we need to go through
+         * videoconvert first (as it fixates the framerate) */
 
         /* decodebin considers many YUV formats to be "raw", but some quartz
          * filters can't handle those. Also, videoflip can't handle all "raw"
@@ -928,6 +926,12 @@ static bool stream_create_post_processing_elements(GstPad *pad, struct wg_parser
                 || !append_element(parser->container, element, &first, &last))
             return false;
 
+        /* DirectShow can express interlaced video, but downstream filters can't
+         * necessarily consume it. In particular, the video renderer can't. */
+        if (!(element = create_element("deinterlace", "good"))
+                || !append_element(parser->container, element, &first, &last))
+            return false;
+
         /* Let GStreamer choose a default number of threads. */
         gst_util_set_object_arg(G_OBJECT(element), "n-threads", "0");
 
diff --git a/dlls/winemac.drv/keyboard.c b/dlls/winemac.drv/keyboard.c
index 64abc5b161f6..fb3c9bcf30e8 100644
--- a/dlls/winemac.drv/keyboard.c
+++ b/dlls/winemac.drv/keyboard.c
@@ -37,6 +37,34 @@
 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
 WINE_DECLARE_DEBUG_CHANNEL(key);
 
+static BOOL is_ime_hkl( HKL hkl )
+{
+    /* See https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values#input-method-editors */
+    switch (HIWORD(hkl))
+    {
+    case MAKELANGID(LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_BENGALI, SUBLANG_BENGALI_INDIA): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): return TRUE;
+    case MAKELANGID(LANG_GUJARATI, SUBLANG_GUJARATI_INDIA): return TRUE;
+    case MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA): return TRUE;
+    case MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN): return TRUE;
+    case MAKELANGID(LANG_KANNADA, SUBLANG_KANNADA_INDIA): return TRUE;
+    case MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN): return TRUE;
+    case MAKELANGID(LANG_MALAYALAM, SUBLANG_MALAYALAM_INDIA): return TRUE;
+    case MAKELANGID(LANG_MARATHI, SUBLANG_MARATHI_INDIA): return TRUE;
+    case MAKELANGID(LANG_NEPALI, SUBLANG_NEPALI_NEPAL): return TRUE;
+    case MAKELANGID(LANG_ODIA, SUBLANG_ODIA_INDIA): return TRUE;
+    case MAKELANGID(LANG_PUNJABI, SUBLANG_PUNJABI_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA): return TRUE;
+    case MAKELANGID(LANG_TELUGU, SUBLANG_TELUGU_INDIA): return TRUE;
+    case MAKELANGID(LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM): return TRUE;
+    case MAKELANGID(LANG_YI, SUBLANG_YI_PRC): return TRUE;
+    default: return (HIWORD(hkl) & 0xe000) == 0xe000;
+    }
+}
 
 /* Indexed by Mac virtual keycode values defined above. */
 static const struct {
@@ -313,7 +341,9 @@ static struct list layout_list = LIST_INIT( layout_list );
 struct layout
 {
     struct list entry;
-    HKL hkl;
+    LANGID lang;
+    /* "Layout Id", used by NtUserGetKeyboardLayoutName / LoadKeyboardLayoutW */
+    WORD layout_id;
     TISInputSourceRef input_source;
     BOOL enabled; /* is the input source enabled - ie displayed in the input source selector UI */
 };
@@ -412,27 +442,10 @@ static DWORD get_lcid(CFStringRef lang)
     return locale->inotneutral ? entry->id : locale->idefaultlanguage;
 }
 
-static HKL get_hkl(CFStringRef lang, CFStringRef type)
+static HKL get_layout_hkl(struct layout *layout, LCID locale)
 {
-    ULONG_PTR lcid = get_lcid(lang);
-    struct layout *layout;
-
-    /* Look for the last occurrence of this lcid in the list and if
-       present use that value + 0x10000 */
-    LIST_FOR_EACH_ENTRY_REV(layout, &layout_list, struct layout, entry)
-    {
-        ULONG_PTR hkl = HandleToUlong(layout->hkl);
-
-        if (LOWORD(hkl) == lcid)
-        {
-            lcid = (hkl & ~0xe0000000) + 0x10000;
-            break;
-        }
-    }
-
-    if (!CFEqual(type, kTISTypeKeyboardLayout)) lcid |= 0xe0000000;
-
-    return (HKL)lcid;
+    if (!layout->layout_id) return UlongToHandle(MAKELONG(locale, layout->lang));
+    return UlongToHandle(MAKELONG(locale, layout->layout_id));
 }
 
 /******************************************************************
@@ -468,6 +481,7 @@ static struct layout *get_layout_from_source(TISInputSourceRef input)
  */
 static void update_layout_list(void)
 {
+    LCID locale = LOWORD(NtUserGetKeyboardLayout(0));
     CFArrayRef sources;
     struct layout *layout;
     int i;
@@ -486,18 +500,28 @@ static void update_layout_list(void)
         layout = get_layout_from_source(input);
         if (!layout)
         {
+            static WORD next_layout_id = 1;
+
             CFStringRef type = CFDictionaryGetValue(dict, macdrv_input_source_type_key);
-            CFStringRef lang = CFDictionaryGetValue(dict, macdrv_input_source_lang_key);
+            LANGID lang = get_lcid(CFDictionaryGetValue(dict, macdrv_input_source_lang_key));
+            HKL lang_hkl = UlongToPtr(MAKELONG(lang, lang));
+            UINT index = 0;
+
+            LIST_FOR_EACH_ENTRY_REV(layout, &layout_list, struct layout, entry)
+                if (layout->lang == lang) index++;
 
-            layout = malloc(sizeof(*layout));
+            layout = calloc(1, sizeof(*layout));
             layout->input_source = (TISInputSourceRef)CFRetain(input);
-            layout->hkl = get_hkl(lang, type);
+            layout->lang = lang;
+            if (is_ime_hkl(lang_hkl) && !index) layout->layout_id = 0; /* HKL has a builtin IME */
+            else if (!CFEqual(type, kTISTypeKeyboardLayout)) layout->layout_id = 0xe000 | next_layout_id++;
+            else if (index) layout->layout_id = 0xf000 | next_layout_id++;
 
             list_add_tail(&layout_list, &layout->entry);
-            TRACE("adding new layout %p\n", layout->hkl);
+            TRACE("adding new layout %p\n", get_layout_hkl(layout, locale));
         }
         else
-            TRACE("enabling already existing layout %p\n", layout->hkl);
+            TRACE("enabling already existing layout %p\n", get_layout_hkl(layout, locale));
 
         layout->enabled = TRUE;
     }
@@ -512,6 +536,7 @@ static void update_layout_list(void)
  */
 HKL macdrv_get_hkl_from_source(TISInputSourceRef input)
 {
+    LCID locale = LOWORD(NtUserGetKeyboardLayout(0));
     struct layout *layout;
     HKL ret = 0;
 
@@ -519,7 +544,7 @@ HKL macdrv_get_hkl_from_source(TISInputSourceRef input)
 
     update_layout_list();
     layout = get_layout_from_source(input);
-    if (layout) ret = layout->hkl;
+    if (layout) ret = get_layout_hkl(layout, locale);
 
     pthread_mutex_unlock(&layout_list_mutex);
 
@@ -1165,7 +1190,7 @@ BOOL macdrv_ActivateKeyboardLayout(HKL hkl, UINT flags)
 
     LIST_FOR_EACH_ENTRY(layout, &layout_list, struct layout, entry)
     {
-        if (layout->hkl == hkl)
+        if (HIWORD(hkl) == layout->layout_id ? layout->layout_id : layout->lang)
         {
             if (macdrv_select_input_source(layout->input_source))
             {
@@ -1302,6 +1327,7 @@ INT macdrv_GetKeyNameText(LONG lparam, LPWSTR buffer, INT size)
  */
 UINT macdrv_GetKeyboardLayoutList(INT size, HKL *list)
 {
+    LCID locale = LOWORD(NtUserGetKeyboardLayout(0));
     int count = 0;
     struct layout *layout;
 
@@ -1317,7 +1343,7 @@ UINT macdrv_GetKeyboardLayoutList(INT size, HKL *list)
         if (list)
         {
             if (count >= size) break;
-            list[count] = layout->hkl;
+            list[count] = get_layout_hkl(layout, locale);
             TRACE("\t%d: %p\n", count, list[count]);
         }
         count++;
diff --git a/dlls/winevulkan/loader_thunks.c b/dlls/winevulkan/loader_thunks.c
index 1cfe08caed26..ad1b8272b6f8 100644
--- a/dlls/winevulkan/loader_thunks.c
+++ b/dlls/winevulkan/loader_thunks.c
@@ -5093,6 +5093,17 @@ uint64_t WINAPI vkGetDeviceCombinedImageSamplerIndexNVX(VkDevice device, uint64_
     return params.result;
 }
 
+VkResult WINAPI vkGetDeviceFaultDebugInfoKHR(VkDevice device, VkDeviceFaultDebugInfoKHR *pDebugInfo)
+{
+    struct vkGetDeviceFaultDebugInfoKHR_params params;
+    NTSTATUS status;
+    params.device = device;
+    params.pDebugInfo = pDebugInfo;
+    status = UNIX_CALL(vkGetDeviceFaultDebugInfoKHR, &params);
+    assert(!status && "vkGetDeviceFaultDebugInfoKHR");
+    return params.result;
+}
+
 VkResult WINAPI vkGetDeviceFaultInfoEXT(VkDevice device, VkDeviceFaultCountsEXT *pFaultCounts, VkDeviceFaultInfoEXT *pFaultInfo)
 {
     struct vkGetDeviceFaultInfoEXT_params params;
@@ -5105,6 +5116,19 @@ VkResult WINAPI vkGetDeviceFaultInfoEXT(VkDevice device, VkDeviceFaultCountsEXT
     return params.result;
 }
 
+VkResult WINAPI vkGetDeviceFaultReportsKHR(VkDevice device, uint64_t timeout, uint32_t *pFaultCounts, VkDeviceFaultInfoKHR *pFaultInfo)
+{
+    struct vkGetDeviceFaultReportsKHR_params params;
+    NTSTATUS status;
+    params.device = device;
+    params.timeout = timeout;
+    params.pFaultCounts = pFaultCounts;
+    params.pFaultInfo = pFaultInfo;
+    status = UNIX_CALL(vkGetDeviceFaultReportsKHR, &params);
+    assert(!status && "vkGetDeviceFaultReportsKHR");
+    return params.result;
+}
+
 void WINAPI vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
 {
     struct vkGetDeviceGroupPeerMemoryFeatures_params params;
@@ -8136,7 +8160,9 @@ static const struct vulkan_func vk_device_dispatch_table[] =
     {"vkGetDeviceBufferMemoryRequirements", vkGetDeviceBufferMemoryRequirements},
     {"vkGetDeviceBufferMemoryRequirementsKHR", vkGetDeviceBufferMemoryRequirementsKHR},
     {"vkGetDeviceCombinedImageSamplerIndexNVX", vkGetDeviceCombinedImageSamplerIndexNVX},
+    {"vkGetDeviceFaultDebugInfoKHR", vkGetDeviceFaultDebugInfoKHR},
     {"vkGetDeviceFaultInfoEXT", vkGetDeviceFaultInfoEXT},
+    {"vkGetDeviceFaultReportsKHR", vkGetDeviceFaultReportsKHR},
     {"vkGetDeviceGroupPeerMemoryFeatures", vkGetDeviceGroupPeerMemoryFeatures},
     {"vkGetDeviceGroupPeerMemoryFeaturesKHR", vkGetDeviceGroupPeerMemoryFeaturesKHR},
     {"vkGetDeviceGroupPresentCapabilitiesKHR", vkGetDeviceGroupPresentCapabilitiesKHR},
diff --git a/dlls/winevulkan/loader_thunks.h b/dlls/winevulkan/loader_thunks.h
index f7613d6ae925..635e58f6c32e 100644
--- a/dlls/winevulkan/loader_thunks.h
+++ b/dlls/winevulkan/loader_thunks.h
@@ -523,7 +523,9 @@ enum unix_call
     unix_vkGetDeviceBufferMemoryRequirements,
     unix_vkGetDeviceBufferMemoryRequirementsKHR,
     unix_vkGetDeviceCombinedImageSamplerIndexNVX,
+    unix_vkGetDeviceFaultDebugInfoKHR,
     unix_vkGetDeviceFaultInfoEXT,
+    unix_vkGetDeviceFaultReportsKHR,
     unix_vkGetDeviceGroupPeerMemoryFeatures,
     unix_vkGetDeviceGroupPeerMemoryFeaturesKHR,
     unix_vkGetDeviceGroupPresentCapabilitiesKHR,
@@ -4548,6 +4550,13 @@ struct vkGetDeviceCombinedImageSamplerIndexNVX_params
     uint64_t result;
 };
 
+struct vkGetDeviceFaultDebugInfoKHR_params
+{
+    VkDevice device;
+    VkDeviceFaultDebugInfoKHR *pDebugInfo;
+    VkResult result;
+};
+
 struct vkGetDeviceFaultInfoEXT_params
 {
     VkDevice device;
@@ -4556,6 +4565,15 @@ struct vkGetDeviceFaultInfoEXT_params
     VkResult result;
 };
 
+struct vkGetDeviceFaultReportsKHR_params
+{
+    VkDevice device;
+    uint64_t DECLSPEC_ALIGN(8) timeout;
+    uint32_t *pFaultCounts;
+    VkDeviceFaultInfoKHR *pFaultInfo;
+    VkResult result;
+};
+
 struct vkGetDeviceGroupPeerMemoryFeatures_params
 {
     VkDevice device;
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index a00a32d0499a..7ec27bd379ef 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.346"
+VK_XML_VERSION = "1.4.347"
 
 # Filenames to create.
 WINE_VULKAN_H = "../../include/wine/vulkan.h"
@@ -307,6 +307,7 @@ FORCE_STRUCT_CONVERSIONS = {
     "VkCommandBufferSubmitInfoKHR",
     "VkSemaphoreSubmitInfo",
     "VkSemaphoreSubmitInfoKHR",
+    "VkPhysicalDeviceLayeredApiPropertiesKHR",
 }
 
 STRUCT_CHAIN_CONVERSIONS = {
@@ -323,7 +324,6 @@ STRUCT_CHAIN_CONVERSIONS = {
     # Ignore to not confuse host loader.
     "VkDeviceCreateInfo": {"strip": ["VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO"]},
     "VkInstanceCreateInfo": {"strip": ["VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO"]},
-    "VkPhysicalDeviceLayeredApiPropertiesKHR": {"strip": ["VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR"]},
 }
 
 # Some struct members are conditionally ignored and callers are free to leave them uninitialized.
@@ -1781,6 +1781,8 @@ class Record(Type):
 
     @staticmethod
     def from_xml(struct):
+        if struct.attrib["name"] == "VkPhysicalDeviceVulkan14Properties":
+            del struct.attrib["returnedonly"]
         returnedonly = "returnedonly" in struct.attrib
         members = filter(is_api_supported, struct.findall("member"))
         members = [VkMember.from_xml(member, returnedonly) for member in members]
@@ -2417,6 +2419,11 @@ class Generator(object):
         f.write("    }\n")
         f.write("}\n\n")
 
+        f.write("static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties232 *out);\n")
+        f.write("#ifdef _WIN64\n")
+        f.write("static void convert_VkPhysicalDeviceProperties2_host_to_win64(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties2 *out);\n")
+        f.write("#endif\n")
+
         f.write(conv_helpers)
         f.write(thunks)
 
diff --git a/dlls/winevulkan/vulkan_thunks.c b/dlls/winevulkan/vulkan_thunks.c
index 06d5b646c96f..11b3b02a5e7f 100644
--- a/dlls/winevulkan/vulkan_thunks.c
+++ b/dlls/winevulkan/vulkan_thunks.c
@@ -1127,19 +1127,21 @@ typedef struct VkDescriptorUpdateTemplateEntry32
 } VkDescriptorUpdateTemplateEntry32;
 typedef VkDescriptorUpdateTemplateEntry32 VkDescriptorUpdateTemplateEntryKHR32;
 
-typedef struct VkDeviceFaultAddressInfoEXT32
+typedef struct VkDeviceFaultAddressInfoKHR32
 {
-    VkDeviceFaultAddressTypeEXT addressType;
+    VkDeviceFaultAddressTypeKHR addressType;
     VkDeviceAddress DECLSPEC_ALIGN(8) reportedAddress;
     VkDeviceSize DECLSPEC_ALIGN(8) addressPrecision;
-} VkDeviceFaultAddressInfoEXT32;
+} VkDeviceFaultAddressInfoKHR32;
+typedef VkDeviceFaultAddressInfoKHR32 VkDeviceFaultAddressInfoEXT32;
 
-typedef struct VkDeviceFaultVendorInfoEXT32
+typedef struct VkDeviceFaultVendorInfoKHR32
 {
     char description[VK_MAX_DESCRIPTION_SIZE];
     uint64_t DECLSPEC_ALIGN(8) vendorFaultCode;
     uint64_t DECLSPEC_ALIGN(8) vendorFaultData;
-} VkDeviceFaultVendorInfoEXT32;
+} VkDeviceFaultVendorInfoKHR32;
+typedef VkDeviceFaultVendorInfoKHR32 VkDeviceFaultVendorInfoEXT32;
 
 typedef struct VkDeviceMemoryCopyKHR32
 {
@@ -3334,6 +3336,14 @@ typedef struct VkDeviceFaultCountsEXT32
     VkDeviceSize DECLSPEC_ALIGN(8) vendorBinarySize;
 } VkDeviceFaultCountsEXT32;
 
+typedef struct VkDeviceFaultDebugInfoKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    uint32_t vendorBinarySize;
+    PTR32 pVendorBinaryData;
+} VkDeviceFaultDebugInfoKHR32;
+
 typedef struct VkDeviceFaultInfoEXT32
 {
     VkStructureType sType;
@@ -3344,6 +3354,26 @@ typedef struct VkDeviceFaultInfoEXT32
     PTR32 pVendorBinaryData;
 } VkDeviceFaultInfoEXT32;
 
+typedef struct VkDeviceFaultInfoKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    VkDeviceFaultFlagsKHR flags;
+    uint64_t DECLSPEC_ALIGN(8) groupId;
+    char description[VK_MAX_DESCRIPTION_SIZE];
+    VkDeviceFaultAddressInfoKHR32 DECLSPEC_ALIGN(8) faultAddressInfo;
+    VkDeviceFaultAddressInfoKHR32 DECLSPEC_ALIGN(8) instructionAddressInfo;
+    VkDeviceFaultVendorInfoKHR32 DECLSPEC_ALIGN(8) vendorInfo;
+} VkDeviceFaultInfoKHR32;
+
+typedef struct VkDeviceFaultShaderAbortMessageInfoKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    uint64_t DECLSPEC_ALIGN(8) messageDataSize;
+    PTR32 pMessageData;
+} VkDeviceFaultShaderAbortMessageInfoKHR32;
+
 typedef struct VkDeviceGroupBindSparseInfo32
 {
     VkStructureType sType;
@@ -5555,6 +5585,23 @@ typedef struct VkPhysicalDeviceFaultFeaturesEXT32
     VkBool32 deviceFaultVendorBinary;
 } VkPhysicalDeviceFaultFeaturesEXT32;
 
+typedef struct VkPhysicalDeviceFaultFeaturesKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    VkBool32 deviceFault;
+    VkBool32 deviceFaultVendorBinary;
+    VkBool32 deviceFaultReportMasked;
+    VkBool32 deviceFaultDeviceLostOnMasked;
+} VkPhysicalDeviceFaultFeaturesKHR32;
+
+typedef struct VkPhysicalDeviceFaultPropertiesKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    uint32_t maxDeviceFaultCount;
+} VkPhysicalDeviceFaultPropertiesKHR32;
+
 typedef struct VkPhysicalDeviceFeatures232
 {
     VkStructureType sType;
@@ -6992,6 +7039,20 @@ typedef struct VkPhysicalDeviceShader64BitIndexingFeaturesEXT32
     VkBool32 shader64BitIndexing;
 } VkPhysicalDeviceShader64BitIndexingFeaturesEXT32;
 
+typedef struct VkPhysicalDeviceShaderAbortFeaturesKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    VkBool32 shaderAbort;
+} VkPhysicalDeviceShaderAbortFeaturesKHR32;
+
+typedef struct VkPhysicalDeviceShaderAbortPropertiesKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    uint64_t DECLSPEC_ALIGN(8) maxShaderAbortMessageSize;
+} VkPhysicalDeviceShaderAbortPropertiesKHR32;
+
 typedef struct VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV32
 {
     VkStructureType sType;
@@ -7061,6 +7122,13 @@ typedef struct VkPhysicalDeviceShaderClockFeaturesKHR32
     VkBool32 shaderDeviceClock;
 } VkPhysicalDeviceShaderClockFeaturesKHR32;
 
+typedef struct VkPhysicalDeviceShaderConstantDataFeaturesKHR32
+{
+    VkStructureType sType;
+    PTR32 pNext;
+    VkBool32 shaderConstantData;
+} VkPhysicalDeviceShaderConstantDataFeaturesKHR32;
+
 typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32
 {
     VkStructureType sType;
@@ -10548,6 +10616,10 @@ static uint64_t wine_vk_unwrap_handle(uint32_t type, uint64_t handle)
     }
 }
 
+static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties232 *out);
+#ifdef _WIN64
+static void convert_VkPhysicalDeviceProperties2_host_to_win64(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties2 *out);
+#endif
 static void convert_VkAcquireNextImageInfoKHR_win32_to_unwrapped_host(const VkAcquireNextImageInfoKHR32 *in, VkAcquireNextImageInfoKHR *out)
 {
     if (!in) return;
@@ -19194,6 +19266,20 @@ static void convert_VkDeviceCreateInfo_win64_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceFaultFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceFaultFeaturesKHR *in_ext = (const VkPhysicalDeviceFaultFeaturesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->deviceFault = in_ext->deviceFault;
+            out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary;
+            out_ext->deviceFaultReportMasked = in_ext->deviceFaultReportMasked;
+            out_ext->deviceFaultDeviceLostOnMasked = in_ext->deviceFaultDeviceLostOnMasked;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2:
         {
             VkPhysicalDeviceFeatures2 *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -20396,6 +20482,17 @@ static void convert_VkDeviceCreateInfo_win64_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderAbortFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderAbortFeaturesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->shaderAbort = in_ext->shaderAbort;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV:
         {
             VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -20488,6 +20585,17 @@ static void convert_VkDeviceCreateInfo_win64_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderConstantDataFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderConstantDataFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderConstantDataFeaturesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->shaderConstantData = in_ext->shaderConstantData;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM:
         {
             VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -21494,7 +21602,7 @@ static void convert_VkDeviceCreateInfo_win32_to_host(struct conversion_context *
     out->queueCreateInfoCount = in->queueCreateInfoCount;
     out->pQueueCreateInfos = convert_VkDeviceQueueCreateInfo_array_win32_to_host(ctx, (const VkDeviceQueueCreateInfo32 *)UlongToPtr(in->pQueueCreateInfos), in->queueCreateInfoCount);
     out->enabledLayerCount = in->enabledLayerCount;
-    out->ppEnabledLayerNames = convert_char_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppEnabledLayerNames), in->enabledLayerCount);
+    out->ppEnabledLayerNames = UlongToPtr(in->ppEnabledLayerNames);
     out->enabledExtensionCount = in->enabledExtensionCount;
     out->ppEnabledExtensionNames = convert_char_pointer_array_win32_to_host(ctx, (const PTR32 *)UlongToPtr(in->ppEnabledExtensionNames), in->enabledExtensionCount);
     out->pEnabledFeatures = UlongToPtr(in->pEnabledFeatures);
@@ -22360,6 +22468,20 @@ static void convert_VkDeviceCreateInfo_win32_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceFaultFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceFaultFeaturesKHR32 *in_ext = (const VkPhysicalDeviceFaultFeaturesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->deviceFault = in_ext->deviceFault;
+            out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary;
+            out_ext->deviceFaultReportMasked = in_ext->deviceFaultReportMasked;
+            out_ext->deviceFaultDeviceLostOnMasked = in_ext->deviceFaultDeviceLostOnMasked;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2:
         {
             VkPhysicalDeviceFeatures2 *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -23562,6 +23684,17 @@ static void convert_VkDeviceCreateInfo_win32_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderAbortFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderAbortFeaturesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->shaderAbort = in_ext->shaderAbort;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV:
         {
             VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -23654,6 +23787,17 @@ static void convert_VkDeviceCreateInfo_win32_to_host(struct conversion_context *
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderConstantDataFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderConstantDataFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderConstantDataFeaturesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->shaderConstantData = in_ext->shaderConstantData;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM:
         {
             VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -30048,6 +30192,66 @@ static void convert_VkDeviceBufferMemoryRequirements_win32_to_host(struct conver
         FIXME("Unexpected pNext\n");
 }
 
+static void convert_VkDeviceFaultDebugInfoKHR_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultDebugInfoKHR32 *in, VkDeviceFaultDebugInfoKHR *out)
+{
+    const VkBaseInStructure32 *in_header;
+    VkBaseOutStructure *out_header = (void *)out;
+
+    if (!in) return;
+
+    out->sType = in->sType;
+    out->pNext = NULL;
+
+    for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext))
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR:
+        {
+            VkDeviceFaultShaderAbortMessageInfoKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            FIXME("Unhandled sType %u.\n", in_header->sType);
+            break;
+        }
+    }
+}
+
+static void convert_VkDeviceFaultDebugInfoKHR_host_to_win32(const VkDeviceFaultDebugInfoKHR *in, VkDeviceFaultDebugInfoKHR32 *out)
+{
+    const VkBaseInStructure *in_header;
+    VkBaseOutStructure32 *out_header = (void *)out;
+
+    if (!in) return;
+
+    out->vendorBinarySize = in->vendorBinarySize;
+    out->pVendorBinaryData = PtrToUlong(in->pVendorBinaryData);
+
+    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR:
+        {
+            VkDeviceFaultShaderAbortMessageInfoKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR);
+            const VkDeviceFaultShaderAbortMessageInfoKHR *in_ext = (const VkDeviceFaultShaderAbortMessageInfoKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR;
+            out_ext->messageDataSize = in_ext->messageDataSize;
+            out_ext->pMessageData = PtrToUlong(in_ext->pMessageData);
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            break;
+        }
+    }
+}
+
 static void convert_VkDeviceFaultCountsEXT_win32_to_host(const VkDeviceFaultCountsEXT32 *in, VkDeviceFaultCountsEXT *out)
 {
     if (!in) return;
@@ -30061,9 +30265,9 @@ static void convert_VkDeviceFaultCountsEXT_win32_to_host(const VkDeviceFaultCoun
         FIXME("Unexpected pNext\n");
 }
 
-static VkDeviceFaultAddressInfoEXT *convert_VkDeviceFaultAddressInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultAddressInfoEXT32 *in, uint32_t count)
+static VkDeviceFaultAddressInfoKHR *convert_VkDeviceFaultAddressInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultAddressInfoKHR32 *in, uint32_t count)
 {
-    VkDeviceFaultAddressInfoEXT *out;
+    VkDeviceFaultAddressInfoKHR *out;
     if (!in || !count) return NULL;
 
     out = conversion_context_alloc(ctx, count * sizeof(*out));
@@ -30071,9 +30275,9 @@ static VkDeviceFaultAddressInfoEXT *convert_VkDeviceFaultAddressInfoEXT_array_wi
     return out;
 }
 
-static VkDeviceFaultVendorInfoEXT *convert_VkDeviceFaultVendorInfoEXT_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultVendorInfoEXT32 *in, uint32_t count)
+static VkDeviceFaultVendorInfoKHR *convert_VkDeviceFaultVendorInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultVendorInfoKHR32 *in, uint32_t count)
 {
-    VkDeviceFaultVendorInfoEXT *out;
+    VkDeviceFaultVendorInfoKHR *out;
     if (!in || !count) return NULL;
 
     out = conversion_context_alloc(ctx, count * sizeof(*out));
@@ -30087,8 +30291,8 @@ static void convert_VkDeviceFaultInfoEXT_win32_to_host(struct conversion_context
 
     out->sType = in->sType;
     out->pNext = NULL;
-    out->pAddressInfos = convert_VkDeviceFaultAddressInfoEXT_array_win32_to_host(ctx, (VkDeviceFaultAddressInfoEXT32 *)UlongToPtr(in->pAddressInfos), 1);
-    out->pVendorInfos = convert_VkDeviceFaultVendorInfoEXT_array_win32_to_host(ctx, (VkDeviceFaultVendorInfoEXT32 *)UlongToPtr(in->pVendorInfos), 1);
+    out->pAddressInfos = convert_VkDeviceFaultAddressInfoKHR_array_win32_to_host(ctx, (VkDeviceFaultAddressInfoKHR32 *)UlongToPtr(in->pAddressInfos), 1);
+    out->pVendorInfos = convert_VkDeviceFaultVendorInfoKHR_array_win32_to_host(ctx, (VkDeviceFaultVendorInfoKHR32 *)UlongToPtr(in->pVendorInfos), 1);
     if (in->pNext)
         FIXME("Unexpected pNext\n");
 }
@@ -30102,7 +30306,7 @@ static void convert_VkDeviceFaultCountsEXT_host_to_win32(const VkDeviceFaultCoun
     out->vendorBinarySize = in->vendorBinarySize;
 }
 
-static void convert_VkDeviceFaultAddressInfoEXT_host_to_win32(const VkDeviceFaultAddressInfoEXT *in, VkDeviceFaultAddressInfoEXT32 *out)
+static void convert_VkDeviceFaultAddressInfoKHR_host_to_win32(const VkDeviceFaultAddressInfoKHR *in, VkDeviceFaultAddressInfoKHR32 *out)
 {
     if (!in) return;
 
@@ -30111,7 +30315,7 @@ static void convert_VkDeviceFaultAddressInfoEXT_host_to_win32(const VkDeviceFaul
     out->addressPrecision = in->addressPrecision;
 }
 
-static void convert_VkDeviceFaultAddressInfoEXT_array_host_to_win32(const VkDeviceFaultAddressInfoEXT *in, VkDeviceFaultAddressInfoEXT32 *out, uint32_t count)
+static void convert_VkDeviceFaultAddressInfoKHR_array_host_to_win32(const VkDeviceFaultAddressInfoKHR *in, VkDeviceFaultAddressInfoKHR32 *out, uint32_t count)
 {
     unsigned int i;
 
@@ -30119,11 +30323,11 @@ static void convert_VkDeviceFaultAddressInfoEXT_array_host_to_win32(const VkDevi
 
     for (i = 0; i < count; i++)
     {
-        convert_VkDeviceFaultAddressInfoEXT_host_to_win32(&in[i], &out[i]);
+        convert_VkDeviceFaultAddressInfoKHR_host_to_win32(&in[i], &out[i]);
     }
 }
 
-static void convert_VkDeviceFaultVendorInfoEXT_host_to_win32(const VkDeviceFaultVendorInfoEXT *in, VkDeviceFaultVendorInfoEXT32 *out)
+static void convert_VkDeviceFaultVendorInfoKHR_host_to_win32(const VkDeviceFaultVendorInfoKHR *in, VkDeviceFaultVendorInfoKHR32 *out)
 {
     if (!in) return;
 
@@ -30132,7 +30336,7 @@ static void convert_VkDeviceFaultVendorInfoEXT_host_to_win32(const VkDeviceFault
     out->vendorFaultData = in->vendorFaultData;
 }
 
-static void convert_VkDeviceFaultVendorInfoEXT_array_host_to_win32(const VkDeviceFaultVendorInfoEXT *in, VkDeviceFaultVendorInfoEXT32 *out, uint32_t count)
+static void convert_VkDeviceFaultVendorInfoKHR_array_host_to_win32(const VkDeviceFaultVendorInfoKHR *in, VkDeviceFaultVendorInfoKHR32 *out, uint32_t count)
 {
     unsigned int i;
 
@@ -30140,7 +30344,7 @@ static void convert_VkDeviceFaultVendorInfoEXT_array_host_to_win32(const VkDevic
 
     for (i = 0; i < count; i++)
     {
-        convert_VkDeviceFaultVendorInfoEXT_host_to_win32(&in[i], &out[i]);
+        convert_VkDeviceFaultVendorInfoKHR_host_to_win32(&in[i], &out[i]);
     }
 }
 
@@ -30149,11 +30353,61 @@ static void convert_VkDeviceFaultInfoEXT_host_to_win32(const VkDeviceFaultInfoEX
     if (!in) return;
 
     memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char));
-    convert_VkDeviceFaultAddressInfoEXT_array_host_to_win32(in->pAddressInfos, (VkDeviceFaultAddressInfoEXT32 *)UlongToPtr(out->pAddressInfos), 1);
-    convert_VkDeviceFaultVendorInfoEXT_array_host_to_win32(in->pVendorInfos, (VkDeviceFaultVendorInfoEXT32 *)UlongToPtr(out->pVendorInfos), 1);
+    convert_VkDeviceFaultAddressInfoKHR_array_host_to_win32(in->pAddressInfos, (VkDeviceFaultAddressInfoKHR32 *)UlongToPtr(out->pAddressInfos), 1);
+    convert_VkDeviceFaultVendorInfoKHR_array_host_to_win32(in->pVendorInfos, (VkDeviceFaultVendorInfoKHR32 *)UlongToPtr(out->pVendorInfos), 1);
     out->pVendorBinaryData = PtrToUlong(in->pVendorBinaryData);
 }
 
+static void convert_VkDeviceFaultInfoKHR_win32_to_host(const VkDeviceFaultInfoKHR32 *in, VkDeviceFaultInfoKHR *out)
+{
+    if (!in) return;
+
+    out->sType = in->sType;
+    out->pNext = NULL;
+    if (in->pNext)
+        FIXME("Unexpected pNext\n");
+}
+
+static VkDeviceFaultInfoKHR *convert_VkDeviceFaultInfoKHR_array_win32_to_host(struct conversion_context *ctx, const VkDeviceFaultInfoKHR32 *in, uint32_t count)
+{
+    VkDeviceFaultInfoKHR *out;
+    unsigned int i;
+
+    if (!in || !count) return NULL;
+
+    out = conversion_context_alloc(ctx, count * sizeof(*out));
+    for (i = 0; i < count; i++)
+    {
+        convert_VkDeviceFaultInfoKHR_win32_to_host(&in[i], &out[i]);
+    }
+
+    return out;
+}
+
+static void convert_VkDeviceFaultInfoKHR_host_to_win32(const VkDeviceFaultInfoKHR *in, VkDeviceFaultInfoKHR32 *out)
+{
+    if (!in) return;
+
+    out->flags = in->flags;
+    out->groupId = in->groupId;
+    memcpy(out->description, in->description, VK_MAX_DESCRIPTION_SIZE * sizeof(char));
+    convert_VkDeviceFaultAddressInfoKHR_host_to_win32(&in->faultAddressInfo, &out->faultAddressInfo);
+    convert_VkDeviceFaultAddressInfoKHR_host_to_win32(&in->instructionAddressInfo, &out->instructionAddressInfo);
+    convert_VkDeviceFaultVendorInfoKHR_host_to_win32(&in->vendorInfo, &out->vendorInfo);
+}
+
+static void convert_VkDeviceFaultInfoKHR_array_host_to_win32(const VkDeviceFaultInfoKHR *in, VkDeviceFaultInfoKHR32 *out, uint32_t count)
+{
+    unsigned int i;
+
+    if (!in) return;
+
+    for (i = 0; i < count; i++)
+    {
+        convert_VkDeviceFaultInfoKHR_host_to_win32(&in[i], &out[i]);
+    }
+}
+
 static void convert_VkDeviceGroupPresentCapabilitiesKHR_win32_to_host(const VkDeviceGroupPresentCapabilitiesKHR32 *in, VkDeviceGroupPresentCapabilitiesKHR *out)
 {
     if (!in) return;
@@ -32390,6 +32644,20 @@ static void convert_VkPhysicalDeviceFeatures2_win32_to_host(struct conversion_co
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceFaultFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceFaultFeaturesKHR32 *in_ext = (const VkPhysicalDeviceFaultFeaturesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->deviceFault = in_ext->deviceFault;
+            out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary;
+            out_ext->deviceFaultReportMasked = in_ext->deviceFaultReportMasked;
+            out_ext->deviceFaultDeviceLostOnMasked = in_ext->deviceFaultDeviceLostOnMasked;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FORMAT_PACK_FEATURES_ARM:
         {
             VkPhysicalDeviceFormatPackFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -33581,6 +33849,17 @@ static void convert_VkPhysicalDeviceFeatures2_win32_to_host(struct conversion_co
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderAbortFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderAbortFeaturesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->shaderAbort = in_ext->shaderAbort;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV:
         {
             VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -33673,6 +33952,17 @@ static void convert_VkPhysicalDeviceFeatures2_win32_to_host(struct conversion_co
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderConstantDataFeaturesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderConstantDataFeaturesKHR32 *in_ext = (const VkPhysicalDeviceShaderConstantDataFeaturesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->shaderConstantData = in_ext->shaderConstantData;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM:
         {
             VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -35236,6 +35526,18 @@ static void convert_VkPhysicalDeviceFeatures2_host_to_win32(const VkPhysicalDevi
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceFaultFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR);
+            const VkPhysicalDeviceFaultFeaturesKHR *in_ext = (const VkPhysicalDeviceFaultFeaturesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR;
+            out_ext->deviceFault = in_ext->deviceFault;
+            out_ext->deviceFaultVendorBinary = in_ext->deviceFaultVendorBinary;
+            out_ext->deviceFaultReportMasked = in_ext->deviceFaultReportMasked;
+            out_ext->deviceFaultDeviceLostOnMasked = in_ext->deviceFaultDeviceLostOnMasked;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FORMAT_PACK_FEATURES_ARM:
         {
             VkPhysicalDeviceFormatPackFeaturesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FORMAT_PACK_FEATURES_ARM);
@@ -36219,6 +36521,15 @@ static void convert_VkPhysicalDeviceFeatures2_host_to_win32(const VkPhysicalDevi
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR);
+            const VkPhysicalDeviceShaderAbortFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderAbortFeaturesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR;
+            out_ext->shaderAbort = in_ext->shaderAbort;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV:
         {
             VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT16_VECTOR_FEATURES_NV);
@@ -36299,6 +36610,15 @@ static void convert_VkPhysicalDeviceFeatures2_host_to_win32(const VkPhysicalDevi
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR:
+        {
+            VkPhysicalDeviceShaderConstantDataFeaturesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR);
+            const VkPhysicalDeviceShaderConstantDataFeaturesKHR *in_ext = (const VkPhysicalDeviceShaderConstantDataFeaturesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR;
+            out_ext->shaderConstantData = in_ext->shaderConstantData;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM:
         {
             VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_FEATURES_ARM);
@@ -37887,17 +38207,40 @@ static void convert_VkPhysicalDeviceProperties_host_to_win32(const VkPhysicalDev
     out->sparseProperties = in->sparseProperties;
 }
 
-static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_win32_to_host(const VkPhysicalDeviceLayeredApiPropertiesKHR32 *in, VkPhysicalDeviceLayeredApiPropertiesKHR *out)
+#ifdef _WIN64
+static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_win64_to_host(struct conversion_context *ctx, const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR *out)
 {
+    const VkBaseInStructure *in_header;
+    VkBaseOutStructure *out_header = (void *)out;
+
     if (!in) return;
 
     out->sType = in->sType;
     out->pNext = NULL;
-    if (in->pNext)
-        FIXME("Unexpected pNext\n");
+
+    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            FIXME("Unhandled sType %u.\n", in_header->sType);
+            break;
+        }
+    }
 }
+#endif /* _WIN64 */
 
-static VkPhysicalDeviceLayeredApiPropertiesKHR *convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceLayeredApiPropertiesKHR32 *in, uint32_t count)
+#ifdef _WIN64
+static VkPhysicalDeviceLayeredApiPropertiesKHR *convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_win64_to_host(struct conversion_context *ctx, const VkPhysicalDeviceLayeredApiPropertiesKHR *in, uint32_t count)
 {
     VkPhysicalDeviceLayeredApiPropertiesKHR *out;
     unsigned int i;
@@ -37907,15 +38250,17 @@ static VkPhysicalDeviceLayeredApiPropertiesKHR *convert_VkPhysicalDeviceLayeredA
     out = conversion_context_alloc(ctx, count * sizeof(*out));
     for (i = 0; i < count; i++)
     {
-        convert_VkPhysicalDeviceLayeredApiPropertiesKHR_win32_to_host(&in[i], &out[i]);
+        convert_VkPhysicalDeviceLayeredApiPropertiesKHR_win64_to_host(ctx, &in[i], &out[i]);
     }
 
     return out;
 }
+#endif /* _WIN64 */
 
-static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceProperties232 *in, VkPhysicalDeviceProperties2 *out)
+#ifdef _WIN64
+static void convert_VkPhysicalDeviceProperties2_win64_to_host(struct conversion_context *ctx, const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties2 *out)
 {
-    const VkBaseInStructure32 *in_header;
+    const VkBaseInStructure *in_header;
     VkBaseOutStructure *out_header = (void *)out;
 
     if (!in) return;
@@ -37923,7 +38268,7 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
     out->sType = in->sType;
     out->pNext = NULL;
 
-    for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext))
+    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
     {
         switch (in_header->sType)
         {
@@ -38065,7 +38410,7 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM:
         {
             VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
-            const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM32 *in_ext = (const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM32 *)in_header;
+            const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *in_ext = (const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM;
             out_ext->pNext = NULL;
             out_ext->tensorCaptureReplayDescriptorDataSize = in_ext->tensorCaptureReplayDescriptorDataSize;
@@ -38165,6 +38510,15 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFaultPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES:
         {
             VkPhysicalDeviceFloatControlsProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -38249,13 +38603,13 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES:
         {
             VkPhysicalDeviceHostImageCopyProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
-            const VkPhysicalDeviceHostImageCopyProperties32 *in_ext = (const VkPhysicalDeviceHostImageCopyProperties32 *)in_header;
+            const VkPhysicalDeviceHostImageCopyProperties *in_ext = (const VkPhysicalDeviceHostImageCopyProperties *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES;
             out_ext->pNext = NULL;
             out_ext->copySrcLayoutCount = in_ext->copySrcLayoutCount;
-            out_ext->pCopySrcLayouts = UlongToPtr(in_ext->pCopySrcLayouts);
+            out_ext->pCopySrcLayouts = in_ext->pCopySrcLayouts;
             out_ext->copyDstLayoutCount = in_ext->copyDstLayoutCount;
-            out_ext->pCopyDstLayouts = UlongToPtr(in_ext->pCopyDstLayouts);
+            out_ext->pCopyDstLayouts = in_ext->pCopyDstLayouts;
             memcpy(out_ext->optimalTilingLayoutUUID, in_ext->optimalTilingLayoutUUID, VK_UUID_SIZE * sizeof(uint8_t));
             out_ext->identicalMemoryTypeRequirements = in_ext->identicalMemoryTypeRequirements;
             out_header->pNext = (void *)out_ext;
@@ -38310,11 +38664,11 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR:
         {
             VkPhysicalDeviceLayeredApiPropertiesListKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
-            const VkPhysicalDeviceLayeredApiPropertiesListKHR32 *in_ext = (const VkPhysicalDeviceLayeredApiPropertiesListKHR32 *)in_header;
+            const VkPhysicalDeviceLayeredApiPropertiesListKHR *in_ext = (const VkPhysicalDeviceLayeredApiPropertiesListKHR *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR;
             out_ext->pNext = NULL;
             out_ext->layeredApiCount = in_ext->layeredApiCount;
-            out_ext->pLayeredApis = convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_win32_to_host(ctx, (VkPhysicalDeviceLayeredApiPropertiesKHR32 *)UlongToPtr(in_ext->pLayeredApis), in_ext->layeredApiCount);
+            out_ext->pLayeredApis = convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_win64_to_host(ctx, in_ext->pLayeredApis, in_ext->layeredApiCount);
             out_header->pNext = (void *)out_ext;
             out_header = (void *)out_ext;
             break;
@@ -38661,6 +39015,17 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderAbortPropertiesKHR *in_ext = (const VkPhysicalDeviceShaderAbortPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->maxShaderAbortMessageSize = in_ext->maxShaderAbortMessageSize;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM:
         {
             VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
@@ -38817,7 +39182,7 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM:
         {
             VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
-            const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM32 *in_ext = (const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM32 *)in_header;
+            const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *in_ext = (const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM;
             out_ext->pNext = NULL;
             out_ext->queueSubmitBoundary = in_ext->queueSubmitBoundary;
@@ -38901,8 +39266,34 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES:
         {
             VkPhysicalDeviceVulkan14Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceVulkan14Properties *in_ext = (const VkPhysicalDeviceVulkan14Properties *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES;
             out_ext->pNext = NULL;
+            out_ext->lineSubPixelPrecisionBits = in_ext->lineSubPixelPrecisionBits;
+            out_ext->maxVertexAttribDivisor = in_ext->maxVertexAttribDivisor;
+            out_ext->supportsNonZeroFirstInstance = in_ext->supportsNonZeroFirstInstance;
+            out_ext->maxPushDescriptors = in_ext->maxPushDescriptors;
+            out_ext->dynamicRenderingLocalReadDepthStencilAttachments = in_ext->dynamicRenderingLocalReadDepthStencilAttachments;
+            out_ext->dynamicRenderingLocalReadMultisampledAttachments = in_ext->dynamicRenderingLocalReadMultisampledAttachments;
+            out_ext->earlyFragmentMultisampleCoverageAfterSampleCounting = in_ext->earlyFragmentMultisampleCoverageAfterSampleCounting;
+            out_ext->earlyFragmentSampleMaskTestBeforeSampleCounting = in_ext->earlyFragmentSampleMaskTestBeforeSampleCounting;
+            out_ext->depthStencilSwizzleOneSupport = in_ext->depthStencilSwizzleOneSupport;
+            out_ext->polygonModePointSize = in_ext->polygonModePointSize;
+            out_ext->nonStrictSinglePixelWideLinesUseParallelogram = in_ext->nonStrictSinglePixelWideLinesUseParallelogram;
+            out_ext->nonStrictWideLinesUseParallelogram = in_ext->nonStrictWideLinesUseParallelogram;
+            out_ext->blockTexelViewCompatibleMultipleLayers = in_ext->blockTexelViewCompatibleMultipleLayers;
+            out_ext->maxCombinedImageSamplerDescriptorCount = in_ext->maxCombinedImageSamplerDescriptorCount;
+            out_ext->fragmentShadingRateClampCombinerInputs = in_ext->fragmentShadingRateClampCombinerInputs;
+            out_ext->defaultRobustnessStorageBuffers = in_ext->defaultRobustnessStorageBuffers;
+            out_ext->defaultRobustnessUniformBuffers = in_ext->defaultRobustnessUniformBuffers;
+            out_ext->defaultRobustnessVertexInputs = in_ext->defaultRobustnessVertexInputs;
+            out_ext->defaultRobustnessImages = in_ext->defaultRobustnessImages;
+            out_ext->copySrcLayoutCount = in_ext->copySrcLayoutCount;
+            out_ext->pCopySrcLayouts = in_ext->pCopySrcLayouts;
+            out_ext->copyDstLayoutCount = in_ext->copyDstLayoutCount;
+            out_ext->pCopyDstLayouts = in_ext->pCopyDstLayouts;
+            memcpy(out_ext->optimalTilingLayoutUUID, in_ext->optimalTilingLayoutUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_ext->identicalMemoryTypeRequirements = in_ext->identicalMemoryTypeRequirements;
             out_header->pNext = (void *)out_ext;
             out_header = (void *)out_ext;
             break;
@@ -38913,18 +39304,43 @@ static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_
         }
     }
 }
+#endif /* _WIN64 */
 
-static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_host_to_win32(const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR32 *out)
+#ifdef _WIN64
+static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_host_to_win64(const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR *out)
 {
+    const VkBaseInStructure *in_header;
+    VkBaseOutStructure *out_header = (void *)out;
+
     if (!in) return;
 
     out->vendorID = in->vendorID;
     out->deviceID = in->deviceID;
     out->layeredAPI = in->layeredAPI;
     memcpy(out->deviceName, in->deviceName, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE * sizeof(char));
+
+    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR);
+            const VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *in_ext = (const VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR;
+            convert_VkPhysicalDeviceProperties2_host_to_win64(&in_ext->properties, &out_ext->properties);
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            break;
+        }
+    }
 }
+#endif /* _WIN64 */
 
-static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_host_to_win32(const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR32 *out, uint32_t count)
+#ifdef _WIN64
+static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_host_to_win64(const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR *out, uint32_t count)
 {
     unsigned int i;
 
@@ -38932,18 +39348,20 @@ static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_host_to_win32(
 
     for (i = 0; i < count; i++)
     {
-        convert_VkPhysicalDeviceLayeredApiPropertiesKHR_host_to_win32(&in[i], &out[i]);
+        convert_VkPhysicalDeviceLayeredApiPropertiesKHR_host_to_win64(&in[i], &out[i]);
     }
 }
+#endif /* _WIN64 */
 
-static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties232 *out)
+#ifdef _WIN64
+static void convert_VkPhysicalDeviceProperties2_host_to_win64(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties2 *out)
 {
     const VkBaseInStructure *in_header;
-    VkBaseOutStructure32 *out_header = (void *)out;
+    VkBaseOutStructure *out_header = (void *)out;
 
     if (!in) return;
 
-    convert_VkPhysicalDeviceProperties_host_to_win32(&in->properties, &out->properties);
+    out->properties = in->properties;
 
     for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
     {
@@ -38951,7 +39369,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         {
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR:
         {
-            VkPhysicalDeviceAccelerationStructurePropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR);
+            VkPhysicalDeviceAccelerationStructurePropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR);
             const VkPhysicalDeviceAccelerationStructurePropertiesKHR *in_ext = (const VkPhysicalDeviceAccelerationStructurePropertiesKHR *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
             out_ext->maxGeometryCount = in_ext->maxGeometryCount;
@@ -38967,7 +39385,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT:
         {
-            VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT);
+            VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT);
             const VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
             out_ext->advancedBlendMaxColorAttachments = in_ext->advancedBlendMaxColorAttachments;
@@ -38981,7 +39399,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV:
         {
-            VkPhysicalDeviceClusterAccelerationStructurePropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV);
+            VkPhysicalDeviceClusterAccelerationStructurePropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV);
             const VkPhysicalDeviceClusterAccelerationStructurePropertiesNV *in_ext = (const VkPhysicalDeviceClusterAccelerationStructurePropertiesNV *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV;
             out_ext->maxVerticesPerCluster = in_ext->maxVerticesPerCluster;
@@ -38997,7 +39415,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI:
         {
-            VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI);
+            VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI);
             const VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI *in_ext = (const VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI;
             memcpy(out_ext->maxWorkGroupCount, in_ext->maxWorkGroupCount, 3 * sizeof(uint32_t));
@@ -39009,7 +39427,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR:
         {
-            VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR);
+            VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR);
             const VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR *in_ext = (const VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR;
             out_ext->meshAndTaskShaderDerivatives = in_ext->meshAndTaskShaderDerivatives;
@@ -39018,7 +39436,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT:
         {
-            VkPhysicalDeviceConservativeRasterizationPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT);
+            VkPhysicalDeviceConservativeRasterizationPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT);
             const VkPhysicalDeviceConservativeRasterizationPropertiesEXT *in_ext = (const VkPhysicalDeviceConservativeRasterizationPropertiesEXT *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
             out_ext->primitiveOverestimationSize = in_ext->primitiveOverestimationSize;
@@ -39035,7 +39453,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV:
         {
-            VkPhysicalDeviceCooperativeMatrix2PropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV);
+            VkPhysicalDeviceCooperativeMatrix2PropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV);
             const VkPhysicalDeviceCooperativeMatrix2PropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrix2PropertiesNV *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV;
             out_ext->cooperativeMatrixWorkgroupScopeMaxWorkgroupSize = in_ext->cooperativeMatrixWorkgroupScopeMaxWorkgroupSize;
@@ -39046,7 +39464,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR:
         {
-            VkPhysicalDeviceCooperativeMatrixPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR);
+            VkPhysicalDeviceCooperativeMatrixPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR);
             const VkPhysicalDeviceCooperativeMatrixPropertiesKHR *in_ext = (const VkPhysicalDeviceCooperativeMatrixPropertiesKHR *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR;
             out_ext->cooperativeMatrixSupportedStages = in_ext->cooperativeMatrixSupportedStages;
@@ -39055,7 +39473,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV:
         {
-            VkPhysicalDeviceCooperativeMatrixPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV);
+            VkPhysicalDeviceCooperativeMatrixPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV);
             const VkPhysicalDeviceCooperativeMatrixPropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrixPropertiesNV *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV;
             out_ext->cooperativeMatrixSupportedStages = in_ext->cooperativeMatrixSupportedStages;
@@ -39064,7 +39482,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV:
         {
-            VkPhysicalDeviceCooperativeVectorPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV);
+            VkPhysicalDeviceCooperativeVectorPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV);
             const VkPhysicalDeviceCooperativeVectorPropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeVectorPropertiesNV *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV;
             out_ext->cooperativeVectorSupportedStages = in_ext->cooperativeVectorSupportedStages;
@@ -39076,7 +39494,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR:
         {
-            VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR);
+            VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR);
             const VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR;
             out_ext->supportedQueues = in_ext->supportedQueues;
@@ -39085,7 +39503,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT:
         {
-            VkPhysicalDeviceCustomBorderColorPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT);
+            VkPhysicalDeviceCustomBorderColorPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT);
             const VkPhysicalDeviceCustomBorderColorPropertiesEXT *in_ext = (const VkPhysicalDeviceCustomBorderColorPropertiesEXT *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT;
             out_ext->maxCustomBorderColorSamplers = in_ext->maxCustomBorderColorSamplers;
@@ -39094,7 +39512,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES:
         {
-            VkPhysicalDeviceDepthStencilResolveProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES);
+            VkPhysicalDeviceDepthStencilResolveProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES);
             const VkPhysicalDeviceDepthStencilResolveProperties *in_ext = (const VkPhysicalDeviceDepthStencilResolveProperties *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
             out_ext->supportedDepthResolveModes = in_ext->supportedDepthResolveModes;
@@ -39106,7 +39524,7 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT:
         {
-            VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT);
+            VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT);
             const VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT;
             out_ext->combinedImageSamplerDensityMapDescriptorSize = in_ext->combinedImageSamplerDensityMapDescriptorSize;
@@ -39115,7 +39533,2669 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
         }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT:
         {
-            VkPhysicalDeviceDescriptorBufferPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT);
+            VkPhysicalDeviceDescriptorBufferPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT);
+            const VkPhysicalDeviceDescriptorBufferPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT;
+            out_ext->combinedImageSamplerDescriptorSingleArray = in_ext->combinedImageSamplerDescriptorSingleArray;
+            out_ext->bufferlessPushDescriptors = in_ext->bufferlessPushDescriptors;
+            out_ext->allowSamplerImageViewPostSubmitCreation = in_ext->allowSamplerImageViewPostSubmitCreation;
+            out_ext->descriptorBufferOffsetAlignment = in_ext->descriptorBufferOffsetAlignment;
+            out_ext->maxDescriptorBufferBindings = in_ext->maxDescriptorBufferBindings;
+            out_ext->maxResourceDescriptorBufferBindings = in_ext->maxResourceDescriptorBufferBindings;
+            out_ext->maxSamplerDescriptorBufferBindings = in_ext->maxSamplerDescriptorBufferBindings;
+            out_ext->maxEmbeddedImmutableSamplerBindings = in_ext->maxEmbeddedImmutableSamplerBindings;
+            out_ext->maxEmbeddedImmutableSamplers = in_ext->maxEmbeddedImmutableSamplers;
+            out_ext->bufferCaptureReplayDescriptorDataSize = in_ext->bufferCaptureReplayDescriptorDataSize;
+            out_ext->imageCaptureReplayDescriptorDataSize = in_ext->imageCaptureReplayDescriptorDataSize;
+            out_ext->imageViewCaptureReplayDescriptorDataSize = in_ext->imageViewCaptureReplayDescriptorDataSize;
+            out_ext->samplerCaptureReplayDescriptorDataSize = in_ext->samplerCaptureReplayDescriptorDataSize;
+            out_ext->accelerationStructureCaptureReplayDescriptorDataSize = in_ext->accelerationStructureCaptureReplayDescriptorDataSize;
+            out_ext->samplerDescriptorSize = in_ext->samplerDescriptorSize;
+            out_ext->combinedImageSamplerDescriptorSize = in_ext->combinedImageSamplerDescriptorSize;
+            out_ext->sampledImageDescriptorSize = in_ext->sampledImageDescriptorSize;
+            out_ext->storageImageDescriptorSize = in_ext->storageImageDescriptorSize;
+            out_ext->uniformTexelBufferDescriptorSize = in_ext->uniformTexelBufferDescriptorSize;
+            out_ext->robustUniformTexelBufferDescriptorSize = in_ext->robustUniformTexelBufferDescriptorSize;
+            out_ext->storageTexelBufferDescriptorSize = in_ext->storageTexelBufferDescriptorSize;
+            out_ext->robustStorageTexelBufferDescriptorSize = in_ext->robustStorageTexelBufferDescriptorSize;
+            out_ext->uniformBufferDescriptorSize = in_ext->uniformBufferDescriptorSize;
+            out_ext->robustUniformBufferDescriptorSize = in_ext->robustUniformBufferDescriptorSize;
+            out_ext->storageBufferDescriptorSize = in_ext->storageBufferDescriptorSize;
+            out_ext->robustStorageBufferDescriptorSize = in_ext->robustStorageBufferDescriptorSize;
+            out_ext->inputAttachmentDescriptorSize = in_ext->inputAttachmentDescriptorSize;
+            out_ext->accelerationStructureDescriptorSize = in_ext->accelerationStructureDescriptorSize;
+            out_ext->maxSamplerDescriptorBufferRange = in_ext->maxSamplerDescriptorBufferRange;
+            out_ext->maxResourceDescriptorBufferRange = in_ext->maxResourceDescriptorBufferRange;
+            out_ext->samplerDescriptorBufferAddressSpaceSize = in_ext->samplerDescriptorBufferAddressSpaceSize;
+            out_ext->resourceDescriptorBufferAddressSpaceSize = in_ext->resourceDescriptorBufferAddressSpaceSize;
+            out_ext->descriptorBufferAddressSpaceSize = in_ext->descriptorBufferAddressSpaceSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM);
+            const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *in_ext = (const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM;
+            out_ext->tensorCaptureReplayDescriptorDataSize = in_ext->tensorCaptureReplayDescriptorDataSize;
+            out_ext->tensorViewCaptureReplayDescriptorDataSize = in_ext->tensorViewCaptureReplayDescriptorDataSize;
+            out_ext->tensorDescriptorSize = in_ext->tensorDescriptorSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDescriptorHeapPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT);
+            const VkPhysicalDeviceDescriptorHeapPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorHeapPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT;
+            out_ext->samplerHeapAlignment = in_ext->samplerHeapAlignment;
+            out_ext->resourceHeapAlignment = in_ext->resourceHeapAlignment;
+            out_ext->maxSamplerHeapSize = in_ext->maxSamplerHeapSize;
+            out_ext->maxResourceHeapSize = in_ext->maxResourceHeapSize;
+            out_ext->minSamplerHeapReservedRange = in_ext->minSamplerHeapReservedRange;
+            out_ext->minSamplerHeapReservedRangeWithEmbedded = in_ext->minSamplerHeapReservedRangeWithEmbedded;
+            out_ext->minResourceHeapReservedRange = in_ext->minResourceHeapReservedRange;
+            out_ext->samplerDescriptorSize = in_ext->samplerDescriptorSize;
+            out_ext->imageDescriptorSize = in_ext->imageDescriptorSize;
+            out_ext->bufferDescriptorSize = in_ext->bufferDescriptorSize;
+            out_ext->samplerDescriptorAlignment = in_ext->samplerDescriptorAlignment;
+            out_ext->imageDescriptorAlignment = in_ext->imageDescriptorAlignment;
+            out_ext->bufferDescriptorAlignment = in_ext->bufferDescriptorAlignment;
+            out_ext->maxPushDataSize = in_ext->maxPushDataSize;
+            out_ext->imageCaptureReplayOpaqueDataSize = in_ext->imageCaptureReplayOpaqueDataSize;
+            out_ext->maxDescriptorHeapEmbeddedSamplers = in_ext->maxDescriptorHeapEmbeddedSamplers;
+            out_ext->samplerYcbcrConversionCount = in_ext->samplerYcbcrConversionCount;
+            out_ext->sparseDescriptorHeaps = in_ext->sparseDescriptorHeaps;
+            out_ext->protectedDescriptorHeaps = in_ext->protectedDescriptorHeaps;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_TENSOR_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceDescriptorHeapTensorPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_TENSOR_PROPERTIES_ARM);
+            const VkPhysicalDeviceDescriptorHeapTensorPropertiesARM *in_ext = (const VkPhysicalDeviceDescriptorHeapTensorPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_TENSOR_PROPERTIES_ARM;
+            out_ext->tensorDescriptorSize = in_ext->tensorDescriptorSize;
+            out_ext->tensorDescriptorAlignment = in_ext->tensorDescriptorAlignment;
+            out_ext->tensorCaptureReplayOpaqueDataSize = in_ext->tensorCaptureReplayOpaqueDataSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES:
+        {
+            VkPhysicalDeviceDescriptorIndexingProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES);
+            const VkPhysicalDeviceDescriptorIndexingProperties *in_ext = (const VkPhysicalDeviceDescriptorIndexingProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES;
+            out_ext->maxUpdateAfterBindDescriptorsInAllPools = in_ext->maxUpdateAfterBindDescriptorsInAllPools;
+            out_ext->shaderUniformBufferArrayNonUniformIndexingNative = in_ext->shaderUniformBufferArrayNonUniformIndexingNative;
+            out_ext->shaderSampledImageArrayNonUniformIndexingNative = in_ext->shaderSampledImageArrayNonUniformIndexingNative;
+            out_ext->shaderStorageBufferArrayNonUniformIndexingNative = in_ext->shaderStorageBufferArrayNonUniformIndexingNative;
+            out_ext->shaderStorageImageArrayNonUniformIndexingNative = in_ext->shaderStorageImageArrayNonUniformIndexingNative;
+            out_ext->shaderInputAttachmentArrayNonUniformIndexingNative = in_ext->shaderInputAttachmentArrayNonUniformIndexingNative;
+            out_ext->robustBufferAccessUpdateAfterBind = in_ext->robustBufferAccessUpdateAfterBind;
+            out_ext->quadDivergentImplicitLod = in_ext->quadDivergentImplicitLod;
+            out_ext->maxPerStageDescriptorUpdateAfterBindSamplers = in_ext->maxPerStageDescriptorUpdateAfterBindSamplers;
+            out_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers;
+            out_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers;
+            out_ext->maxPerStageDescriptorUpdateAfterBindSampledImages = in_ext->maxPerStageDescriptorUpdateAfterBindSampledImages;
+            out_ext->maxPerStageDescriptorUpdateAfterBindStorageImages = in_ext->maxPerStageDescriptorUpdateAfterBindStorageImages;
+            out_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments = in_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments;
+            out_ext->maxPerStageUpdateAfterBindResources = in_ext->maxPerStageUpdateAfterBindResources;
+            out_ext->maxDescriptorSetUpdateAfterBindSamplers = in_ext->maxDescriptorSetUpdateAfterBindSamplers;
+            out_ext->maxDescriptorSetUpdateAfterBindUniformBuffers = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffers;
+            out_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageBuffers = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffers;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindSampledImages = in_ext->maxDescriptorSetUpdateAfterBindSampledImages;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageImages = in_ext->maxDescriptorSetUpdateAfterBindStorageImages;
+            out_ext->maxDescriptorSetUpdateAfterBindInputAttachments = in_ext->maxDescriptorSetUpdateAfterBindInputAttachments;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT);
+            const VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT;
+            out_ext->maxIndirectPipelineCount = in_ext->maxIndirectPipelineCount;
+            out_ext->maxIndirectShaderObjectCount = in_ext->maxIndirectShaderObjectCount;
+            out_ext->maxIndirectSequenceCount = in_ext->maxIndirectSequenceCount;
+            out_ext->maxIndirectCommandsTokenCount = in_ext->maxIndirectCommandsTokenCount;
+            out_ext->maxIndirectCommandsTokenOffset = in_ext->maxIndirectCommandsTokenOffset;
+            out_ext->maxIndirectCommandsIndirectStride = in_ext->maxIndirectCommandsIndirectStride;
+            out_ext->supportedIndirectCommandsInputModes = in_ext->supportedIndirectCommandsInputModes;
+            out_ext->supportedIndirectCommandsShaderStages = in_ext->supportedIndirectCommandsShaderStages;
+            out_ext->supportedIndirectCommandsShaderStagesPipelineBinding = in_ext->supportedIndirectCommandsShaderStagesPipelineBinding;
+            out_ext->supportedIndirectCommandsShaderStagesShaderBinding = in_ext->supportedIndirectCommandsShaderStagesShaderBinding;
+            out_ext->deviceGeneratedCommandsTransformFeedback = in_ext->deviceGeneratedCommandsTransformFeedback;
+            out_ext->deviceGeneratedCommandsMultiDrawIndirectCount = in_ext->deviceGeneratedCommandsMultiDrawIndirectCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV);
+            const VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *in_ext = (const VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV;
+            out_ext->maxGraphicsShaderGroupCount = in_ext->maxGraphicsShaderGroupCount;
+            out_ext->maxIndirectSequenceCount = in_ext->maxIndirectSequenceCount;
+            out_ext->maxIndirectCommandsTokenCount = in_ext->maxIndirectCommandsTokenCount;
+            out_ext->maxIndirectCommandsStreamCount = in_ext->maxIndirectCommandsStreamCount;
+            out_ext->maxIndirectCommandsTokenOffset = in_ext->maxIndirectCommandsTokenOffset;
+            out_ext->maxIndirectCommandsStreamStride = in_ext->maxIndirectCommandsStreamStride;
+            out_ext->minSequencesCountBufferOffsetAlignment = in_ext->minSequencesCountBufferOffsetAlignment;
+            out_ext->minSequencesIndexBufferOffsetAlignment = in_ext->minSequencesIndexBufferOffsetAlignment;
+            out_ext->minIndirectCommandsBufferOffsetAlignment = in_ext->minIndirectCommandsBufferOffsetAlignment;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDiscardRectanglePropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT);
+            const VkPhysicalDeviceDiscardRectanglePropertiesEXT *in_ext = (const VkPhysicalDeviceDiscardRectanglePropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT;
+            out_ext->maxDiscardRectangles = in_ext->maxDiscardRectangles;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES:
+        {
+            VkPhysicalDeviceDriverProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES);
+            const VkPhysicalDeviceDriverProperties *in_ext = (const VkPhysicalDeviceDriverProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
+            out_ext->driverID = in_ext->driverID;
+            memcpy(out_ext->driverName, in_ext->driverName, VK_MAX_DRIVER_NAME_SIZE * sizeof(char));
+            memcpy(out_ext->driverInfo, in_ext->driverInfo, VK_MAX_DRIVER_INFO_SIZE * sizeof(char));
+            out_ext->conformanceVersion = in_ext->conformanceVersion;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT);
+            const VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *in_ext = (const VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT;
+            out_ext->dynamicPrimitiveTopologyUnrestricted = in_ext->dynamicPrimitiveTopologyUnrestricted;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV);
+            const VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV *in_ext = (const VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV;
+            out_ext->extendedSparseAddressSpaceSize = in_ext->extendedSparseAddressSpaceSize;
+            out_ext->extendedSparseImageUsageFlags = in_ext->extendedSparseImageUsageFlags;
+            out_ext->extendedSparseBufferUsageFlags = in_ext->extendedSparseBufferUsageFlags;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceExternalMemoryHostPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT);
+            const VkPhysicalDeviceExternalMemoryHostPropertiesEXT *in_ext = (const VkPhysicalDeviceExternalMemoryHostPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
+            out_ext->minImportedHostPointerAlignment = in_ext->minImportedHostPointerAlignment;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFaultPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR);
+            const VkPhysicalDeviceFaultPropertiesKHR *in_ext = (const VkPhysicalDeviceFaultPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR;
+            out_ext->maxDeviceFaultCount = in_ext->maxDeviceFaultCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES:
+        {
+            VkPhysicalDeviceFloatControlsProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES);
+            const VkPhysicalDeviceFloatControlsProperties *in_ext = (const VkPhysicalDeviceFloatControlsProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
+            out_ext->denormBehaviorIndependence = in_ext->denormBehaviorIndependence;
+            out_ext->roundingModeIndependence = in_ext->roundingModeIndependence;
+            out_ext->shaderSignedZeroInfNanPreserveFloat16 = in_ext->shaderSignedZeroInfNanPreserveFloat16;
+            out_ext->shaderSignedZeroInfNanPreserveFloat32 = in_ext->shaderSignedZeroInfNanPreserveFloat32;
+            out_ext->shaderSignedZeroInfNanPreserveFloat64 = in_ext->shaderSignedZeroInfNanPreserveFloat64;
+            out_ext->shaderDenormPreserveFloat16 = in_ext->shaderDenormPreserveFloat16;
+            out_ext->shaderDenormPreserveFloat32 = in_ext->shaderDenormPreserveFloat32;
+            out_ext->shaderDenormPreserveFloat64 = in_ext->shaderDenormPreserveFloat64;
+            out_ext->shaderDenormFlushToZeroFloat16 = in_ext->shaderDenormFlushToZeroFloat16;
+            out_ext->shaderDenormFlushToZeroFloat32 = in_ext->shaderDenormFlushToZeroFloat32;
+            out_ext->shaderDenormFlushToZeroFloat64 = in_ext->shaderDenormFlushToZeroFloat64;
+            out_ext->shaderRoundingModeRTEFloat16 = in_ext->shaderRoundingModeRTEFloat16;
+            out_ext->shaderRoundingModeRTEFloat32 = in_ext->shaderRoundingModeRTEFloat32;
+            out_ext->shaderRoundingModeRTEFloat64 = in_ext->shaderRoundingModeRTEFloat64;
+            out_ext->shaderRoundingModeRTZFloat16 = in_ext->shaderRoundingModeRTZFloat16;
+            out_ext->shaderRoundingModeRTZFloat32 = in_ext->shaderRoundingModeRTZFloat32;
+            out_ext->shaderRoundingModeRTZFloat64 = in_ext->shaderRoundingModeRTZFloat64;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT);
+            const VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT;
+            out_ext->subsampledLoads = in_ext->subsampledLoads;
+            out_ext->subsampledCoarseReconstructionEarlyAccess = in_ext->subsampledCoarseReconstructionEarlyAccess;
+            out_ext->maxSubsampledArrayLayers = in_ext->maxSubsampledArrayLayers;
+            out_ext->maxDescriptorSetSubsampledSamplers = in_ext->maxDescriptorSetSubsampledSamplers;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_PROPERTIES_VALVE:
+        {
+            VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_PROPERTIES_VALVE);
+            const VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE *in_ext = (const VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_PROPERTIES_VALVE;
+            out_ext->maxFragmentDensityMapLayers = in_ext->maxFragmentDensityMapLayers;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT);
+            const VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT;
+            out_ext->fragmentDensityOffsetGranularity = in_ext->fragmentDensityOffsetGranularity;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceFragmentDensityMapPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT);
+            const VkPhysicalDeviceFragmentDensityMapPropertiesEXT *in_ext = (const VkPhysicalDeviceFragmentDensityMapPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT;
+            out_ext->minFragmentDensityTexelSize = in_ext->minFragmentDensityTexelSize;
+            out_ext->maxFragmentDensityTexelSize = in_ext->maxFragmentDensityTexelSize;
+            out_ext->fragmentDensityInvocations = in_ext->fragmentDensityInvocations;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR);
+            const VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *in_ext = (const VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR;
+            out_ext->triStripVertexOrderIndependentOfProvokingVertex = in_ext->triStripVertexOrderIndependentOfProvokingVertex;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV);
+            const VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *in_ext = (const VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV;
+            out_ext->maxFragmentShadingRateInvocationCount = in_ext->maxFragmentShadingRateInvocationCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFragmentShadingRatePropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR);
+            const VkPhysicalDeviceFragmentShadingRatePropertiesKHR *in_ext = (const VkPhysicalDeviceFragmentShadingRatePropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
+            out_ext->minFragmentShadingRateAttachmentTexelSize = in_ext->minFragmentShadingRateAttachmentTexelSize;
+            out_ext->maxFragmentShadingRateAttachmentTexelSize = in_ext->maxFragmentShadingRateAttachmentTexelSize;
+            out_ext->maxFragmentShadingRateAttachmentTexelSizeAspectRatio = in_ext->maxFragmentShadingRateAttachmentTexelSizeAspectRatio;
+            out_ext->primitiveFragmentShadingRateWithMultipleViewports = in_ext->primitiveFragmentShadingRateWithMultipleViewports;
+            out_ext->layeredShadingRateAttachments = in_ext->layeredShadingRateAttachments;
+            out_ext->fragmentShadingRateNonTrivialCombinerOps = in_ext->fragmentShadingRateNonTrivialCombinerOps;
+            out_ext->maxFragmentSize = in_ext->maxFragmentSize;
+            out_ext->maxFragmentSizeAspectRatio = in_ext->maxFragmentSizeAspectRatio;
+            out_ext->maxFragmentShadingRateCoverageSamples = in_ext->maxFragmentShadingRateCoverageSamples;
+            out_ext->maxFragmentShadingRateRasterizationSamples = in_ext->maxFragmentShadingRateRasterizationSamples;
+            out_ext->fragmentShadingRateWithShaderDepthStencilWrites = in_ext->fragmentShadingRateWithShaderDepthStencilWrites;
+            out_ext->fragmentShadingRateWithSampleMask = in_ext->fragmentShadingRateWithSampleMask;
+            out_ext->fragmentShadingRateWithShaderSampleMask = in_ext->fragmentShadingRateWithShaderSampleMask;
+            out_ext->fragmentShadingRateWithConservativeRasterization = in_ext->fragmentShadingRateWithConservativeRasterization;
+            out_ext->fragmentShadingRateWithFragmentShaderInterlock = in_ext->fragmentShadingRateWithFragmentShaderInterlock;
+            out_ext->fragmentShadingRateWithCustomSampleLocations = in_ext->fragmentShadingRateWithCustomSampleLocations;
+            out_ext->fragmentShadingRateStrictMultiplyCombiner = in_ext->fragmentShadingRateStrictMultiplyCombiner;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT);
+            const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *in_ext = (const VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT;
+            out_ext->graphicsPipelineLibraryFastLinking = in_ext->graphicsPipelineLibraryFastLinking;
+            out_ext->graphicsPipelineLibraryIndependentInterpolationDecoration = in_ext->graphicsPipelineLibraryIndependentInterpolationDecoration;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES:
+        {
+            VkPhysicalDeviceHostImageCopyProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES);
+            const VkPhysicalDeviceHostImageCopyProperties *in_ext = (const VkPhysicalDeviceHostImageCopyProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES;
+            out_ext->copySrcLayoutCount = in_ext->copySrcLayoutCount;
+            out_ext->pCopySrcLayouts = in_ext->pCopySrcLayouts;
+            out_ext->copyDstLayoutCount = in_ext->copyDstLayoutCount;
+            out_ext->pCopyDstLayouts = in_ext->pCopyDstLayouts;
+            memcpy(out_ext->optimalTilingLayoutUUID, in_ext->optimalTilingLayoutUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_ext->identicalMemoryTypeRequirements = in_ext->identicalMemoryTypeRequirements;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES:
+        {
+            VkPhysicalDeviceIDProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES);
+            const VkPhysicalDeviceIDProperties *in_ext = (const VkPhysicalDeviceIDProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+            memcpy(out_ext->deviceUUID, in_ext->deviceUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            memcpy(out_ext->driverUUID, in_ext->driverUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            memcpy(out_ext->deviceLUID, in_ext->deviceLUID, VK_LUID_SIZE * sizeof(uint8_t));
+            out_ext->deviceNodeMask = in_ext->deviceNodeMask;
+            out_ext->deviceLUIDValid = in_ext->deviceLUIDValid;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA:
+        {
+            VkPhysicalDeviceImageAlignmentControlPropertiesMESA *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA);
+            const VkPhysicalDeviceImageAlignmentControlPropertiesMESA *in_ext = (const VkPhysicalDeviceImageAlignmentControlPropertiesMESA *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA;
+            out_ext->supportedImageAlignmentMask = in_ext->supportedImageAlignmentMask;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceImageProcessing2PropertiesQCOM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM);
+            const VkPhysicalDeviceImageProcessing2PropertiesQCOM *in_ext = (const VkPhysicalDeviceImageProcessing2PropertiesQCOM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM;
+            out_ext->maxBlockMatchWindow = in_ext->maxBlockMatchWindow;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceImageProcessingPropertiesQCOM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM);
+            const VkPhysicalDeviceImageProcessingPropertiesQCOM *in_ext = (const VkPhysicalDeviceImageProcessingPropertiesQCOM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM;
+            out_ext->maxWeightFilterPhases = in_ext->maxWeightFilterPhases;
+            out_ext->maxWeightFilterDimension = in_ext->maxWeightFilterDimension;
+            out_ext->maxBlockMatchRegion = in_ext->maxBlockMatchRegion;
+            out_ext->maxBoxFilterBlockSize = in_ext->maxBoxFilterBlockSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES:
+        {
+            VkPhysicalDeviceInlineUniformBlockProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES);
+            const VkPhysicalDeviceInlineUniformBlockProperties *in_ext = (const VkPhysicalDeviceInlineUniformBlockProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES;
+            out_ext->maxInlineUniformBlockSize = in_ext->maxInlineUniformBlockSize;
+            out_ext->maxPerStageDescriptorInlineUniformBlocks = in_ext->maxPerStageDescriptorInlineUniformBlocks;
+            out_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = in_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
+            out_ext->maxDescriptorSetInlineUniformBlocks = in_ext->maxDescriptorSetInlineUniformBlocks;
+            out_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = in_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR:
+        {
+            VkPhysicalDeviceLayeredApiPropertiesListKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR);
+            const VkPhysicalDeviceLayeredApiPropertiesListKHR *in_ext = (const VkPhysicalDeviceLayeredApiPropertiesListKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR;
+            out_ext->layeredApiCount = in_ext->layeredApiCount;
+            convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_host_to_win64(in_ext->pLayeredApis, out_ext->pLayeredApis, in_ext->layeredApiCount);
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT:
+        {
+            VkPhysicalDeviceLayeredDriverPropertiesMSFT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT);
+            const VkPhysicalDeviceLayeredDriverPropertiesMSFT *in_ext = (const VkPhysicalDeviceLayeredDriverPropertiesMSFT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT;
+            out_ext->underlyingAPI = in_ext->underlyingAPI;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT);
+            const VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT *in_ext = (const VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT;
+            out_ext->nativeUnalignedPerformance = in_ext->nativeUnalignedPerformance;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES:
+        {
+            VkPhysicalDeviceLineRasterizationProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES);
+            const VkPhysicalDeviceLineRasterizationProperties *in_ext = (const VkPhysicalDeviceLineRasterizationProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES;
+            out_ext->lineSubPixelPrecisionBits = in_ext->lineSubPixelPrecisionBits;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceMaintenance10PropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_PROPERTIES_KHR);
+            const VkPhysicalDeviceMaintenance10PropertiesKHR *in_ext = (const VkPhysicalDeviceMaintenance10PropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_PROPERTIES_KHR;
+            out_ext->rgba4OpaqueBlackSwizzled = in_ext->rgba4OpaqueBlackSwizzled;
+            out_ext->resolveSrgbFormatAppliesTransferFunction = in_ext->resolveSrgbFormatAppliesTransferFunction;
+            out_ext->resolveSrgbFormatSupportsTransferFunctionControl = in_ext->resolveSrgbFormatSupportsTransferFunctionControl;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance3Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES);
+            const VkPhysicalDeviceMaintenance3Properties *in_ext = (const VkPhysicalDeviceMaintenance3Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
+            out_ext->maxPerSetDescriptors = in_ext->maxPerSetDescriptors;
+            out_ext->maxMemoryAllocationSize = in_ext->maxMemoryAllocationSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance4Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES);
+            const VkPhysicalDeviceMaintenance4Properties *in_ext = (const VkPhysicalDeviceMaintenance4Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES;
+            out_ext->maxBufferSize = in_ext->maxBufferSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance5Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES);
+            const VkPhysicalDeviceMaintenance5Properties *in_ext = (const VkPhysicalDeviceMaintenance5Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES;
+            out_ext->earlyFragmentMultisampleCoverageAfterSampleCounting = in_ext->earlyFragmentMultisampleCoverageAfterSampleCounting;
+            out_ext->earlyFragmentSampleMaskTestBeforeSampleCounting = in_ext->earlyFragmentSampleMaskTestBeforeSampleCounting;
+            out_ext->depthStencilSwizzleOneSupport = in_ext->depthStencilSwizzleOneSupport;
+            out_ext->polygonModePointSize = in_ext->polygonModePointSize;
+            out_ext->nonStrictSinglePixelWideLinesUseParallelogram = in_ext->nonStrictSinglePixelWideLinesUseParallelogram;
+            out_ext->nonStrictWideLinesUseParallelogram = in_ext->nonStrictWideLinesUseParallelogram;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance6Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES);
+            const VkPhysicalDeviceMaintenance6Properties *in_ext = (const VkPhysicalDeviceMaintenance6Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES;
+            out_ext->blockTexelViewCompatibleMultipleLayers = in_ext->blockTexelViewCompatibleMultipleLayers;
+            out_ext->maxCombinedImageSamplerDescriptorCount = in_ext->maxCombinedImageSamplerDescriptorCount;
+            out_ext->fragmentShadingRateClampCombinerInputs = in_ext->fragmentShadingRateClampCombinerInputs;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceMaintenance7PropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR);
+            const VkPhysicalDeviceMaintenance7PropertiesKHR *in_ext = (const VkPhysicalDeviceMaintenance7PropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR;
+            out_ext->robustFragmentShadingRateAttachmentAccess = in_ext->robustFragmentShadingRateAttachmentAccess;
+            out_ext->separateDepthStencilAttachmentAccess = in_ext->separateDepthStencilAttachmentAccess;
+            out_ext->maxDescriptorSetTotalUniformBuffersDynamic = in_ext->maxDescriptorSetTotalUniformBuffersDynamic;
+            out_ext->maxDescriptorSetTotalStorageBuffersDynamic = in_ext->maxDescriptorSetTotalStorageBuffersDynamic;
+            out_ext->maxDescriptorSetTotalBuffersDynamic = in_ext->maxDescriptorSetTotalBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindTotalUniformBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindTotalStorageBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindTotalBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindTotalBuffersDynamic;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceMaintenance9PropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_PROPERTIES_KHR);
+            const VkPhysicalDeviceMaintenance9PropertiesKHR *in_ext = (const VkPhysicalDeviceMaintenance9PropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_PROPERTIES_KHR;
+            out_ext->image2DViewOf3DSparse = in_ext->image2DViewOf3DSparse;
+            out_ext->defaultVertexAttributeValue = in_ext->defaultVertexAttributeValue;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceMemoryDecompressionPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT);
+            const VkPhysicalDeviceMemoryDecompressionPropertiesEXT *in_ext = (const VkPhysicalDeviceMemoryDecompressionPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT;
+            out_ext->decompressionMethods = in_ext->decompressionMethods;
+            out_ext->maxDecompressionIndirectCount = in_ext->maxDecompressionIndirectCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceMeshShaderPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT);
+            const VkPhysicalDeviceMeshShaderPropertiesEXT *in_ext = (const VkPhysicalDeviceMeshShaderPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT;
+            out_ext->maxTaskWorkGroupTotalCount = in_ext->maxTaskWorkGroupTotalCount;
+            memcpy(out_ext->maxTaskWorkGroupCount, in_ext->maxTaskWorkGroupCount, 3 * sizeof(uint32_t));
+            out_ext->maxTaskWorkGroupInvocations = in_ext->maxTaskWorkGroupInvocations;
+            memcpy(out_ext->maxTaskWorkGroupSize, in_ext->maxTaskWorkGroupSize, 3 * sizeof(uint32_t));
+            out_ext->maxTaskPayloadSize = in_ext->maxTaskPayloadSize;
+            out_ext->maxTaskSharedMemorySize = in_ext->maxTaskSharedMemorySize;
+            out_ext->maxTaskPayloadAndSharedMemorySize = in_ext->maxTaskPayloadAndSharedMemorySize;
+            out_ext->maxMeshWorkGroupTotalCount = in_ext->maxMeshWorkGroupTotalCount;
+            memcpy(out_ext->maxMeshWorkGroupCount, in_ext->maxMeshWorkGroupCount, 3 * sizeof(uint32_t));
+            out_ext->maxMeshWorkGroupInvocations = in_ext->maxMeshWorkGroupInvocations;
+            memcpy(out_ext->maxMeshWorkGroupSize, in_ext->maxMeshWorkGroupSize, 3 * sizeof(uint32_t));
+            out_ext->maxMeshSharedMemorySize = in_ext->maxMeshSharedMemorySize;
+            out_ext->maxMeshPayloadAndSharedMemorySize = in_ext->maxMeshPayloadAndSharedMemorySize;
+            out_ext->maxMeshOutputMemorySize = in_ext->maxMeshOutputMemorySize;
+            out_ext->maxMeshPayloadAndOutputMemorySize = in_ext->maxMeshPayloadAndOutputMemorySize;
+            out_ext->maxMeshOutputComponents = in_ext->maxMeshOutputComponents;
+            out_ext->maxMeshOutputVertices = in_ext->maxMeshOutputVertices;
+            out_ext->maxMeshOutputPrimitives = in_ext->maxMeshOutputPrimitives;
+            out_ext->maxMeshOutputLayers = in_ext->maxMeshOutputLayers;
+            out_ext->maxMeshMultiviewViewCount = in_ext->maxMeshMultiviewViewCount;
+            out_ext->meshOutputPerVertexGranularity = in_ext->meshOutputPerVertexGranularity;
+            out_ext->meshOutputPerPrimitiveGranularity = in_ext->meshOutputPerPrimitiveGranularity;
+            out_ext->maxPreferredTaskWorkGroupInvocations = in_ext->maxPreferredTaskWorkGroupInvocations;
+            out_ext->maxPreferredMeshWorkGroupInvocations = in_ext->maxPreferredMeshWorkGroupInvocations;
+            out_ext->prefersLocalInvocationVertexOutput = in_ext->prefersLocalInvocationVertexOutput;
+            out_ext->prefersLocalInvocationPrimitiveOutput = in_ext->prefersLocalInvocationPrimitiveOutput;
+            out_ext->prefersCompactVertexOutput = in_ext->prefersCompactVertexOutput;
+            out_ext->prefersCompactPrimitiveOutput = in_ext->prefersCompactPrimitiveOutput;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceMeshShaderPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV);
+            const VkPhysicalDeviceMeshShaderPropertiesNV *in_ext = (const VkPhysicalDeviceMeshShaderPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV;
+            out_ext->maxDrawMeshTasksCount = in_ext->maxDrawMeshTasksCount;
+            out_ext->maxTaskWorkGroupInvocations = in_ext->maxTaskWorkGroupInvocations;
+            memcpy(out_ext->maxTaskWorkGroupSize, in_ext->maxTaskWorkGroupSize, 3 * sizeof(uint32_t));
+            out_ext->maxTaskTotalMemorySize = in_ext->maxTaskTotalMemorySize;
+            out_ext->maxTaskOutputCount = in_ext->maxTaskOutputCount;
+            out_ext->maxMeshWorkGroupInvocations = in_ext->maxMeshWorkGroupInvocations;
+            memcpy(out_ext->maxMeshWorkGroupSize, in_ext->maxMeshWorkGroupSize, 3 * sizeof(uint32_t));
+            out_ext->maxMeshTotalMemorySize = in_ext->maxMeshTotalMemorySize;
+            out_ext->maxMeshOutputVertices = in_ext->maxMeshOutputVertices;
+            out_ext->maxMeshOutputPrimitives = in_ext->maxMeshOutputPrimitives;
+            out_ext->maxMeshMultiviewViewCount = in_ext->maxMeshMultiviewViewCount;
+            out_ext->meshOutputPerVertexGranularity = in_ext->meshOutputPerVertexGranularity;
+            out_ext->meshOutputPerPrimitiveGranularity = in_ext->meshOutputPerPrimitiveGranularity;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceMultiDrawPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT);
+            const VkPhysicalDeviceMultiDrawPropertiesEXT *in_ext = (const VkPhysicalDeviceMultiDrawPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT;
+            out_ext->maxMultiDrawCount = in_ext->maxMultiDrawCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES:
+        {
+            VkPhysicalDeviceMultiviewProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES);
+            const VkPhysicalDeviceMultiviewProperties *in_ext = (const VkPhysicalDeviceMultiviewProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+            out_ext->maxMultiviewViewCount = in_ext->maxMultiviewViewCount;
+            out_ext->maxMultiviewInstanceIndex = in_ext->maxMultiviewInstanceIndex;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceNestedCommandBufferPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT);
+            const VkPhysicalDeviceNestedCommandBufferPropertiesEXT *in_ext = (const VkPhysicalDeviceNestedCommandBufferPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT;
+            out_ext->maxCommandBufferNestingLevel = in_ext->maxCommandBufferNestingLevel;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceOpacityMicromapPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT);
+            const VkPhysicalDeviceOpacityMicromapPropertiesEXT *in_ext = (const VkPhysicalDeviceOpacityMicromapPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT;
+            out_ext->maxOpacity2StateSubdivisionLevel = in_ext->maxOpacity2StateSubdivisionLevel;
+            out_ext->maxOpacity4StateSubdivisionLevel = in_ext->maxOpacity4StateSubdivisionLevel;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceOpticalFlowPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV);
+            const VkPhysicalDeviceOpticalFlowPropertiesNV *in_ext = (const VkPhysicalDeviceOpticalFlowPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV;
+            out_ext->supportedOutputGridSizes = in_ext->supportedOutputGridSizes;
+            out_ext->supportedHintGridSizes = in_ext->supportedHintGridSizes;
+            out_ext->hintSupported = in_ext->hintSupported;
+            out_ext->costSupported = in_ext->costSupported;
+            out_ext->bidirectionalFlowSupported = in_ext->bidirectionalFlowSupported;
+            out_ext->globalFlowSupported = in_ext->globalFlowSupported;
+            out_ext->minWidth = in_ext->minWidth;
+            out_ext->minHeight = in_ext->minHeight;
+            out_ext->maxWidth = in_ext->maxWidth;
+            out_ext->maxHeight = in_ext->maxHeight;
+            out_ext->maxNumRegionsOfInterest = in_ext->maxNumRegionsOfInterest;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
+        {
+            VkPhysicalDevicePCIBusInfoPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT);
+            const VkPhysicalDevicePCIBusInfoPropertiesEXT *in_ext = (const VkPhysicalDevicePCIBusInfoPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT;
+            out_ext->pciDomain = in_ext->pciDomain;
+            out_ext->pciBus = in_ext->pciBus;
+            out_ext->pciDevice = in_ext->pciDevice;
+            out_ext->pciFunction = in_ext->pciFunction;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV:
+        {
+            VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV);
+            const VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV *in_ext = (const VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV;
+            out_ext->maxPartitionCount = in_ext->maxPartitionCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_PROPERTIES_ARM:
+        {
+            VkPhysicalDevicePerformanceCountersByRegionPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_PROPERTIES_ARM);
+            const VkPhysicalDevicePerformanceCountersByRegionPropertiesARM *in_ext = (const VkPhysicalDevicePerformanceCountersByRegionPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_PROPERTIES_ARM;
+            out_ext->maxPerRegionPerformanceCounters = in_ext->maxPerRegionPerformanceCounters;
+            out_ext->performanceCounterRegionSize = in_ext->performanceCounterRegionSize;
+            out_ext->rowStrideAlignment = in_ext->rowStrideAlignment;
+            out_ext->regionAlignment = in_ext->regionAlignment;
+            out_ext->identityTransformOrder = in_ext->identityTransformOrder;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR:
+        {
+            VkPhysicalDevicePerformanceQueryPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR);
+            const VkPhysicalDevicePerformanceQueryPropertiesKHR *in_ext = (const VkPhysicalDevicePerformanceQueryPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR;
+            out_ext->allowCommandBufferQueryCopies = in_ext->allowCommandBufferQueryCopies;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR:
+        {
+            VkPhysicalDevicePipelineBinaryPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR);
+            const VkPhysicalDevicePipelineBinaryPropertiesKHR *in_ext = (const VkPhysicalDevicePipelineBinaryPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR;
+            out_ext->pipelineBinaryInternalCache = in_ext->pipelineBinaryInternalCache;
+            out_ext->pipelineBinaryInternalCacheControl = in_ext->pipelineBinaryInternalCacheControl;
+            out_ext->pipelineBinaryPrefersInternalCache = in_ext->pipelineBinaryPrefersInternalCache;
+            out_ext->pipelineBinaryPrecompiledInternalCache = in_ext->pipelineBinaryPrecompiledInternalCache;
+            out_ext->pipelineBinaryCompressedData = in_ext->pipelineBinaryCompressedData;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES:
+        {
+            VkPhysicalDevicePipelineRobustnessProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES);
+            const VkPhysicalDevicePipelineRobustnessProperties *in_ext = (const VkPhysicalDevicePipelineRobustnessProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES;
+            out_ext->defaultRobustnessStorageBuffers = in_ext->defaultRobustnessStorageBuffers;
+            out_ext->defaultRobustnessUniformBuffers = in_ext->defaultRobustnessUniformBuffers;
+            out_ext->defaultRobustnessVertexInputs = in_ext->defaultRobustnessVertexInputs;
+            out_ext->defaultRobustnessImages = in_ext->defaultRobustnessImages;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES:
+        {
+            VkPhysicalDevicePointClippingProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES);
+            const VkPhysicalDevicePointClippingProperties *in_ext = (const VkPhysicalDevicePointClippingProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
+            out_ext->pointClippingBehavior = in_ext->pointClippingBehavior;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES:
+        {
+            VkPhysicalDeviceProtectedMemoryProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES);
+            const VkPhysicalDeviceProtectedMemoryProperties *in_ext = (const VkPhysicalDeviceProtectedMemoryProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES;
+            out_ext->protectedNoFault = in_ext->protectedNoFault;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceProvokingVertexPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT);
+            const VkPhysicalDeviceProvokingVertexPropertiesEXT *in_ext = (const VkPhysicalDeviceProvokingVertexPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT;
+            out_ext->provokingVertexModePerPipeline = in_ext->provokingVertexModePerPipeline;
+            out_ext->transformFeedbackPreservesTriangleFanProvokingVertex = in_ext->transformFeedbackPreservesTriangleFanProvokingVertex;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_PROPERTIES_NV:
+        {
+            VkPhysicalDevicePushConstantBankPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_PROPERTIES_NV);
+            const VkPhysicalDevicePushConstantBankPropertiesNV *in_ext = (const VkPhysicalDevicePushConstantBankPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_PROPERTIES_NV;
+            out_ext->maxGraphicsPushConstantBanks = in_ext->maxGraphicsPushConstantBanks;
+            out_ext->maxComputePushConstantBanks = in_ext->maxComputePushConstantBanks;
+            out_ext->maxGraphicsPushDataBanks = in_ext->maxGraphicsPushDataBanks;
+            out_ext->maxComputePushDataBanks = in_ext->maxComputePushDataBanks;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES:
+        {
+            VkPhysicalDevicePushDescriptorProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES);
+            const VkPhysicalDevicePushDescriptorProperties *in_ext = (const VkPhysicalDevicePushDescriptorProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES;
+            out_ext->maxPushDescriptors = in_ext->maxPushDescriptors;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_EXT);
+            const VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_EXT;
+            out_ext->rayTracingInvocationReorderReorderingHint = in_ext->rayTracingInvocationReorderReorderingHint;
+            out_ext->maxShaderBindingTableRecordIndex = in_ext->maxShaderBindingTableRecordIndex;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV);
+            const VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *in_ext = (const VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV;
+            out_ext->rayTracingInvocationReorderReorderingHint = in_ext->rayTracingInvocationReorderReorderingHint;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceRayTracingPipelinePropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR);
+            const VkPhysicalDeviceRayTracingPipelinePropertiesKHR *in_ext = (const VkPhysicalDeviceRayTracingPipelinePropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
+            out_ext->shaderGroupHandleSize = in_ext->shaderGroupHandleSize;
+            out_ext->maxRayRecursionDepth = in_ext->maxRayRecursionDepth;
+            out_ext->maxShaderGroupStride = in_ext->maxShaderGroupStride;
+            out_ext->shaderGroupBaseAlignment = in_ext->shaderGroupBaseAlignment;
+            out_ext->shaderGroupHandleCaptureReplaySize = in_ext->shaderGroupHandleCaptureReplaySize;
+            out_ext->maxRayDispatchInvocationCount = in_ext->maxRayDispatchInvocationCount;
+            out_ext->shaderGroupHandleAlignment = in_ext->shaderGroupHandleAlignment;
+            out_ext->maxRayHitAttributeSize = in_ext->maxRayHitAttributeSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceRayTracingPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV);
+            const VkPhysicalDeviceRayTracingPropertiesNV *in_ext = (const VkPhysicalDeviceRayTracingPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
+            out_ext->shaderGroupHandleSize = in_ext->shaderGroupHandleSize;
+            out_ext->maxRecursionDepth = in_ext->maxRecursionDepth;
+            out_ext->maxShaderGroupStride = in_ext->maxShaderGroupStride;
+            out_ext->shaderGroupBaseAlignment = in_ext->shaderGroupBaseAlignment;
+            out_ext->maxGeometryCount = in_ext->maxGeometryCount;
+            out_ext->maxInstanceCount = in_ext->maxInstanceCount;
+            out_ext->maxTriangleCount = in_ext->maxTriangleCount;
+            out_ext->maxDescriptorSetAccelerationStructures = in_ext->maxDescriptorSetAccelerationStructures;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceRenderPassStripedPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM);
+            const VkPhysicalDeviceRenderPassStripedPropertiesARM *in_ext = (const VkPhysicalDeviceRenderPassStripedPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM;
+            out_ext->renderPassStripeGranularity = in_ext->renderPassStripeGranularity;
+            out_ext->maxRenderPassStripes = in_ext->maxRenderPassStripes;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceRobustness2PropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR);
+            const VkPhysicalDeviceRobustness2PropertiesKHR *in_ext = (const VkPhysicalDeviceRobustness2PropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR;
+            out_ext->robustStorageBufferAccessSizeAlignment = in_ext->robustStorageBufferAccessSizeAlignment;
+            out_ext->robustUniformBufferAccessSizeAlignment = in_ext->robustUniformBufferAccessSizeAlignment;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceSampleLocationsPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT);
+            const VkPhysicalDeviceSampleLocationsPropertiesEXT *in_ext = (const VkPhysicalDeviceSampleLocationsPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
+            out_ext->sampleLocationSampleCounts = in_ext->sampleLocationSampleCounts;
+            out_ext->maxSampleLocationGridSize = in_ext->maxSampleLocationGridSize;
+            memcpy(out_ext->sampleLocationCoordinateRange, in_ext->sampleLocationCoordinateRange, 2 * sizeof(float));
+            out_ext->sampleLocationSubPixelBits = in_ext->sampleLocationSubPixelBits;
+            out_ext->variableSampleLocations = in_ext->variableSampleLocations;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES:
+        {
+            VkPhysicalDeviceSamplerFilterMinmaxProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES);
+            const VkPhysicalDeviceSamplerFilterMinmaxProperties *in_ext = (const VkPhysicalDeviceSamplerFilterMinmaxProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES;
+            out_ext->filterMinmaxSingleComponentFormats = in_ext->filterMinmaxSingleComponentFormats;
+            out_ext->filterMinmaxImageComponentMapping = in_ext->filterMinmaxImageComponentMapping;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceSchedulingControlsPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM);
+            const VkPhysicalDeviceSchedulingControlsPropertiesARM *in_ext = (const VkPhysicalDeviceSchedulingControlsPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM;
+            out_ext->schedulingControlsFlags = in_ext->schedulingControlsFlags;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortPropertiesKHR *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR);
+            const VkPhysicalDeviceShaderAbortPropertiesKHR *in_ext = (const VkPhysicalDeviceShaderAbortPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR;
+            out_ext->maxShaderAbortMessageSize = in_ext->maxShaderAbortMessageSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM);
+            const VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *in_ext = (const VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM;
+            out_ext->shaderCoreMask = in_ext->shaderCoreMask;
+            out_ext->shaderCoreCount = in_ext->shaderCoreCount;
+            out_ext->shaderWarpsPerCore = in_ext->shaderWarpsPerCore;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD:
+        {
+            VkPhysicalDeviceShaderCoreProperties2AMD *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD);
+            const VkPhysicalDeviceShaderCoreProperties2AMD *in_ext = (const VkPhysicalDeviceShaderCoreProperties2AMD *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD;
+            out_ext->shaderCoreFeatures = in_ext->shaderCoreFeatures;
+            out_ext->activeComputeUnitCount = in_ext->activeComputeUnitCount;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD:
+        {
+            VkPhysicalDeviceShaderCorePropertiesAMD *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD);
+            const VkPhysicalDeviceShaderCorePropertiesAMD *in_ext = (const VkPhysicalDeviceShaderCorePropertiesAMD *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD;
+            out_ext->shaderEngineCount = in_ext->shaderEngineCount;
+            out_ext->shaderArraysPerEngineCount = in_ext->shaderArraysPerEngineCount;
+            out_ext->computeUnitsPerShaderArray = in_ext->computeUnitsPerShaderArray;
+            out_ext->simdPerComputeUnit = in_ext->simdPerComputeUnit;
+            out_ext->wavefrontsPerSimd = in_ext->wavefrontsPerSimd;
+            out_ext->wavefrontSize = in_ext->wavefrontSize;
+            out_ext->sgprsPerSimd = in_ext->sgprsPerSimd;
+            out_ext->minSgprAllocation = in_ext->minSgprAllocation;
+            out_ext->maxSgprAllocation = in_ext->maxSgprAllocation;
+            out_ext->sgprAllocationGranularity = in_ext->sgprAllocationGranularity;
+            out_ext->vgprsPerSimd = in_ext->vgprsPerSimd;
+            out_ext->minVgprAllocation = in_ext->minVgprAllocation;
+            out_ext->maxVgprAllocation = in_ext->maxVgprAllocation;
+            out_ext->vgprAllocationGranularity = in_ext->vgprAllocationGranularity;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceShaderCorePropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM);
+            const VkPhysicalDeviceShaderCorePropertiesARM *in_ext = (const VkPhysicalDeviceShaderCorePropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM;
+            out_ext->pixelRate = in_ext->pixelRate;
+            out_ext->texelRate = in_ext->texelRate;
+            out_ext->fmaRate = in_ext->fmaRate;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceShaderInstrumentationPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM);
+            const VkPhysicalDeviceShaderInstrumentationPropertiesARM *in_ext = (const VkPhysicalDeviceShaderInstrumentationPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM;
+            out_ext->numMetrics = in_ext->numMetrics;
+            out_ext->perBasicBlockGranularity = in_ext->perBasicBlockGranularity;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES:
+        {
+            VkPhysicalDeviceShaderIntegerDotProductProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES);
+            const VkPhysicalDeviceShaderIntegerDotProductProperties *in_ext = (const VkPhysicalDeviceShaderIntegerDotProductProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES;
+            out_ext->integerDotProduct8BitUnsignedAccelerated = in_ext->integerDotProduct8BitUnsignedAccelerated;
+            out_ext->integerDotProduct8BitSignedAccelerated = in_ext->integerDotProduct8BitSignedAccelerated;
+            out_ext->integerDotProduct8BitMixedSignednessAccelerated = in_ext->integerDotProduct8BitMixedSignednessAccelerated;
+            out_ext->integerDotProduct4x8BitPackedUnsignedAccelerated = in_ext->integerDotProduct4x8BitPackedUnsignedAccelerated;
+            out_ext->integerDotProduct4x8BitPackedSignedAccelerated = in_ext->integerDotProduct4x8BitPackedSignedAccelerated;
+            out_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated;
+            out_ext->integerDotProduct16BitUnsignedAccelerated = in_ext->integerDotProduct16BitUnsignedAccelerated;
+            out_ext->integerDotProduct16BitSignedAccelerated = in_ext->integerDotProduct16BitSignedAccelerated;
+            out_ext->integerDotProduct16BitMixedSignednessAccelerated = in_ext->integerDotProduct16BitMixedSignednessAccelerated;
+            out_ext->integerDotProduct32BitUnsignedAccelerated = in_ext->integerDotProduct32BitUnsignedAccelerated;
+            out_ext->integerDotProduct32BitSignedAccelerated = in_ext->integerDotProduct32BitSignedAccelerated;
+            out_ext->integerDotProduct32BitMixedSignednessAccelerated = in_ext->integerDotProduct32BitMixedSignednessAccelerated;
+            out_ext->integerDotProduct64BitUnsignedAccelerated = in_ext->integerDotProduct64BitUnsignedAccelerated;
+            out_ext->integerDotProduct64BitSignedAccelerated = in_ext->integerDotProduct64BitSignedAccelerated;
+            out_ext->integerDotProduct64BitMixedSignednessAccelerated = in_ext->integerDotProduct64BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderLongVectorPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_PROPERTIES_EXT);
+            const VkPhysicalDeviceShaderLongVectorPropertiesEXT *in_ext = (const VkPhysicalDeviceShaderLongVectorPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_PROPERTIES_EXT;
+            out_ext->maxVectorComponents = in_ext->maxVectorComponents;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT);
+            const VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *in_ext = (const VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT;
+            memcpy(out_ext->shaderModuleIdentifierAlgorithmUUID, in_ext->shaderModuleIdentifierAlgorithmUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderObjectPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT);
+            const VkPhysicalDeviceShaderObjectPropertiesEXT *in_ext = (const VkPhysicalDeviceShaderObjectPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT;
+            memcpy(out_ext->shaderBinaryUUID, in_ext->shaderBinaryUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_ext->shaderBinaryVersion = in_ext->shaderBinaryVersion;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV);
+            const VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *in_ext = (const VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV;
+            out_ext->shaderSMCount = in_ext->shaderSMCount;
+            out_ext->shaderWarpsPerSM = in_ext->shaderWarpsPerSM;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderTileImagePropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT);
+            const VkPhysicalDeviceShaderTileImagePropertiesEXT *in_ext = (const VkPhysicalDeviceShaderTileImagePropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT;
+            out_ext->shaderTileImageCoherentReadAccelerated = in_ext->shaderTileImageCoherentReadAccelerated;
+            out_ext->shaderTileImageReadSampleFromPixelRateInvocation = in_ext->shaderTileImageReadSampleFromPixelRateInvocation;
+            out_ext->shaderTileImageReadFromHelperInvocation = in_ext->shaderTileImageReadFromHelperInvocation;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceShadingRateImagePropertiesNV *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV);
+            const VkPhysicalDeviceShadingRateImagePropertiesNV *in_ext = (const VkPhysicalDeviceShadingRateImagePropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV;
+            out_ext->shadingRateTexelSize = in_ext->shadingRateTexelSize;
+            out_ext->shadingRatePaletteSize = in_ext->shadingRatePaletteSize;
+            out_ext->shadingRateMaxCoarseSamples = in_ext->shadingRateMaxCoarseSamples;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES:
+        {
+            VkPhysicalDeviceSubgroupProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES);
+            const VkPhysicalDeviceSubgroupProperties *in_ext = (const VkPhysicalDeviceSubgroupProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+            out_ext->subgroupSize = in_ext->subgroupSize;
+            out_ext->supportedStages = in_ext->supportedStages;
+            out_ext->supportedOperations = in_ext->supportedOperations;
+            out_ext->quadOperationsInAllStages = in_ext->quadOperationsInAllStages;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES:
+        {
+            VkPhysicalDeviceSubgroupSizeControlProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES);
+            const VkPhysicalDeviceSubgroupSizeControlProperties *in_ext = (const VkPhysicalDeviceSubgroupSizeControlProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
+            out_ext->minSubgroupSize = in_ext->minSubgroupSize;
+            out_ext->maxSubgroupSize = in_ext->maxSubgroupSize;
+            out_ext->maxComputeWorkgroupSubgroups = in_ext->maxComputeWorkgroupSubgroups;
+            out_ext->requiredSubgroupSizeStages = in_ext->requiredSubgroupSizeStages;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI:
+        {
+            VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI);
+            const VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *in_ext = (const VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI;
+            out_ext->maxSubpassShadingWorkgroupSizeAspectRatio = in_ext->maxSubpassShadingWorkgroupSizeAspectRatio;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceTensorPropertiesARM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_PROPERTIES_ARM);
+            const VkPhysicalDeviceTensorPropertiesARM *in_ext = (const VkPhysicalDeviceTensorPropertiesARM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_PROPERTIES_ARM;
+            out_ext->maxTensorDimensionCount = in_ext->maxTensorDimensionCount;
+            out_ext->maxTensorElements = in_ext->maxTensorElements;
+            out_ext->maxPerDimensionTensorElements = in_ext->maxPerDimensionTensorElements;
+            out_ext->maxTensorStride = in_ext->maxTensorStride;
+            out_ext->maxTensorSize = in_ext->maxTensorSize;
+            out_ext->maxTensorShaderAccessArrayLength = in_ext->maxTensorShaderAccessArrayLength;
+            out_ext->maxTensorShaderAccessSize = in_ext->maxTensorShaderAccessSize;
+            out_ext->maxDescriptorSetStorageTensors = in_ext->maxDescriptorSetStorageTensors;
+            out_ext->maxPerStageDescriptorSetStorageTensors = in_ext->maxPerStageDescriptorSetStorageTensors;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageTensors = in_ext->maxDescriptorSetUpdateAfterBindStorageTensors;
+            out_ext->maxPerStageDescriptorUpdateAfterBindStorageTensors = in_ext->maxPerStageDescriptorUpdateAfterBindStorageTensors;
+            out_ext->shaderStorageTensorArrayNonUniformIndexingNative = in_ext->shaderStorageTensorArrayNonUniformIndexingNative;
+            out_ext->shaderTensorSupportedStages = in_ext->shaderTensorSupportedStages;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES:
+        {
+            VkPhysicalDeviceTexelBufferAlignmentProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES);
+            const VkPhysicalDeviceTexelBufferAlignmentProperties *in_ext = (const VkPhysicalDeviceTexelBufferAlignmentProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES;
+            out_ext->storageTexelBufferOffsetAlignmentBytes = in_ext->storageTexelBufferOffsetAlignmentBytes;
+            out_ext->storageTexelBufferOffsetSingleTexelAlignment = in_ext->storageTexelBufferOffsetSingleTexelAlignment;
+            out_ext->uniformTexelBufferOffsetAlignmentBytes = in_ext->uniformTexelBufferOffsetAlignmentBytes;
+            out_ext->uniformTexelBufferOffsetSingleTexelAlignment = in_ext->uniformTexelBufferOffsetSingleTexelAlignment;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM);
+            const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *in_ext = (const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM;
+            out_ext->queueSubmitBoundary = in_ext->queueSubmitBoundary;
+            out_ext->tileBufferTransfers = in_ext->tileBufferTransfers;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceTileShadingPropertiesQCOM *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM);
+            const VkPhysicalDeviceTileShadingPropertiesQCOM *in_ext = (const VkPhysicalDeviceTileShadingPropertiesQCOM *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM;
+            out_ext->maxApronSize = in_ext->maxApronSize;
+            out_ext->preferNonCoherent = in_ext->preferNonCoherent;
+            out_ext->tileGranularity = in_ext->tileGranularity;
+            out_ext->maxTileShadingRate = in_ext->maxTileShadingRate;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES:
+        {
+            VkPhysicalDeviceTimelineSemaphoreProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES);
+            const VkPhysicalDeviceTimelineSemaphoreProperties *in_ext = (const VkPhysicalDeviceTimelineSemaphoreProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES;
+            out_ext->maxTimelineSemaphoreValueDifference = in_ext->maxTimelineSemaphoreValueDifference;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceTransformFeedbackPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT);
+            const VkPhysicalDeviceTransformFeedbackPropertiesEXT *in_ext = (const VkPhysicalDeviceTransformFeedbackPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
+            out_ext->maxTransformFeedbackStreams = in_ext->maxTransformFeedbackStreams;
+            out_ext->maxTransformFeedbackBuffers = in_ext->maxTransformFeedbackBuffers;
+            out_ext->maxTransformFeedbackBufferSize = in_ext->maxTransformFeedbackBufferSize;
+            out_ext->maxTransformFeedbackStreamDataSize = in_ext->maxTransformFeedbackStreamDataSize;
+            out_ext->maxTransformFeedbackBufferDataSize = in_ext->maxTransformFeedbackBufferDataSize;
+            out_ext->maxTransformFeedbackBufferDataStride = in_ext->maxTransformFeedbackBufferDataStride;
+            out_ext->transformFeedbackQueries = in_ext->transformFeedbackQueries;
+            out_ext->transformFeedbackStreamsLinesTriangles = in_ext->transformFeedbackStreamsLinesTriangles;
+            out_ext->transformFeedbackRasterizationStreamSelect = in_ext->transformFeedbackRasterizationStreamSelect;
+            out_ext->transformFeedbackDraw = in_ext->transformFeedbackDraw;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES:
+        {
+            VkPhysicalDeviceVertexAttributeDivisorProperties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES);
+            const VkPhysicalDeviceVertexAttributeDivisorProperties *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES;
+            out_ext->maxVertexAttribDivisor = in_ext->maxVertexAttribDivisor;
+            out_ext->supportsNonZeroFirstInstance = in_ext->supportsNonZeroFirstInstance;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT);
+            const VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *in_ext = (const VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
+            out_ext->maxVertexAttribDivisor = in_ext->maxVertexAttribDivisor;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan11Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES);
+            const VkPhysicalDeviceVulkan11Properties *in_ext = (const VkPhysicalDeviceVulkan11Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
+            memcpy(out_ext->deviceUUID, in_ext->deviceUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            memcpy(out_ext->driverUUID, in_ext->driverUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            memcpy(out_ext->deviceLUID, in_ext->deviceLUID, VK_LUID_SIZE * sizeof(uint8_t));
+            out_ext->deviceNodeMask = in_ext->deviceNodeMask;
+            out_ext->deviceLUIDValid = in_ext->deviceLUIDValid;
+            out_ext->subgroupSize = in_ext->subgroupSize;
+            out_ext->subgroupSupportedStages = in_ext->subgroupSupportedStages;
+            out_ext->subgroupSupportedOperations = in_ext->subgroupSupportedOperations;
+            out_ext->subgroupQuadOperationsInAllStages = in_ext->subgroupQuadOperationsInAllStages;
+            out_ext->pointClippingBehavior = in_ext->pointClippingBehavior;
+            out_ext->maxMultiviewViewCount = in_ext->maxMultiviewViewCount;
+            out_ext->maxMultiviewInstanceIndex = in_ext->maxMultiviewInstanceIndex;
+            out_ext->protectedNoFault = in_ext->protectedNoFault;
+            out_ext->maxPerSetDescriptors = in_ext->maxPerSetDescriptors;
+            out_ext->maxMemoryAllocationSize = in_ext->maxMemoryAllocationSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan12Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES);
+            const VkPhysicalDeviceVulkan12Properties *in_ext = (const VkPhysicalDeviceVulkan12Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES;
+            out_ext->driverID = in_ext->driverID;
+            memcpy(out_ext->driverName, in_ext->driverName, VK_MAX_DRIVER_NAME_SIZE * sizeof(char));
+            memcpy(out_ext->driverInfo, in_ext->driverInfo, VK_MAX_DRIVER_INFO_SIZE * sizeof(char));
+            out_ext->conformanceVersion = in_ext->conformanceVersion;
+            out_ext->denormBehaviorIndependence = in_ext->denormBehaviorIndependence;
+            out_ext->roundingModeIndependence = in_ext->roundingModeIndependence;
+            out_ext->shaderSignedZeroInfNanPreserveFloat16 = in_ext->shaderSignedZeroInfNanPreserveFloat16;
+            out_ext->shaderSignedZeroInfNanPreserveFloat32 = in_ext->shaderSignedZeroInfNanPreserveFloat32;
+            out_ext->shaderSignedZeroInfNanPreserveFloat64 = in_ext->shaderSignedZeroInfNanPreserveFloat64;
+            out_ext->shaderDenormPreserveFloat16 = in_ext->shaderDenormPreserveFloat16;
+            out_ext->shaderDenormPreserveFloat32 = in_ext->shaderDenormPreserveFloat32;
+            out_ext->shaderDenormPreserveFloat64 = in_ext->shaderDenormPreserveFloat64;
+            out_ext->shaderDenormFlushToZeroFloat16 = in_ext->shaderDenormFlushToZeroFloat16;
+            out_ext->shaderDenormFlushToZeroFloat32 = in_ext->shaderDenormFlushToZeroFloat32;
+            out_ext->shaderDenormFlushToZeroFloat64 = in_ext->shaderDenormFlushToZeroFloat64;
+            out_ext->shaderRoundingModeRTEFloat16 = in_ext->shaderRoundingModeRTEFloat16;
+            out_ext->shaderRoundingModeRTEFloat32 = in_ext->shaderRoundingModeRTEFloat32;
+            out_ext->shaderRoundingModeRTEFloat64 = in_ext->shaderRoundingModeRTEFloat64;
+            out_ext->shaderRoundingModeRTZFloat16 = in_ext->shaderRoundingModeRTZFloat16;
+            out_ext->shaderRoundingModeRTZFloat32 = in_ext->shaderRoundingModeRTZFloat32;
+            out_ext->shaderRoundingModeRTZFloat64 = in_ext->shaderRoundingModeRTZFloat64;
+            out_ext->maxUpdateAfterBindDescriptorsInAllPools = in_ext->maxUpdateAfterBindDescriptorsInAllPools;
+            out_ext->shaderUniformBufferArrayNonUniformIndexingNative = in_ext->shaderUniformBufferArrayNonUniformIndexingNative;
+            out_ext->shaderSampledImageArrayNonUniformIndexingNative = in_ext->shaderSampledImageArrayNonUniformIndexingNative;
+            out_ext->shaderStorageBufferArrayNonUniformIndexingNative = in_ext->shaderStorageBufferArrayNonUniformIndexingNative;
+            out_ext->shaderStorageImageArrayNonUniformIndexingNative = in_ext->shaderStorageImageArrayNonUniformIndexingNative;
+            out_ext->shaderInputAttachmentArrayNonUniformIndexingNative = in_ext->shaderInputAttachmentArrayNonUniformIndexingNative;
+            out_ext->robustBufferAccessUpdateAfterBind = in_ext->robustBufferAccessUpdateAfterBind;
+            out_ext->quadDivergentImplicitLod = in_ext->quadDivergentImplicitLod;
+            out_ext->maxPerStageDescriptorUpdateAfterBindSamplers = in_ext->maxPerStageDescriptorUpdateAfterBindSamplers;
+            out_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindUniformBuffers;
+            out_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers = in_ext->maxPerStageDescriptorUpdateAfterBindStorageBuffers;
+            out_ext->maxPerStageDescriptorUpdateAfterBindSampledImages = in_ext->maxPerStageDescriptorUpdateAfterBindSampledImages;
+            out_ext->maxPerStageDescriptorUpdateAfterBindStorageImages = in_ext->maxPerStageDescriptorUpdateAfterBindStorageImages;
+            out_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments = in_ext->maxPerStageDescriptorUpdateAfterBindInputAttachments;
+            out_ext->maxPerStageUpdateAfterBindResources = in_ext->maxPerStageUpdateAfterBindResources;
+            out_ext->maxDescriptorSetUpdateAfterBindSamplers = in_ext->maxDescriptorSetUpdateAfterBindSamplers;
+            out_ext->maxDescriptorSetUpdateAfterBindUniformBuffers = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffers;
+            out_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindUniformBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageBuffers = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffers;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic = in_ext->maxDescriptorSetUpdateAfterBindStorageBuffersDynamic;
+            out_ext->maxDescriptorSetUpdateAfterBindSampledImages = in_ext->maxDescriptorSetUpdateAfterBindSampledImages;
+            out_ext->maxDescriptorSetUpdateAfterBindStorageImages = in_ext->maxDescriptorSetUpdateAfterBindStorageImages;
+            out_ext->maxDescriptorSetUpdateAfterBindInputAttachments = in_ext->maxDescriptorSetUpdateAfterBindInputAttachments;
+            out_ext->supportedDepthResolveModes = in_ext->supportedDepthResolveModes;
+            out_ext->supportedStencilResolveModes = in_ext->supportedStencilResolveModes;
+            out_ext->independentResolveNone = in_ext->independentResolveNone;
+            out_ext->independentResolve = in_ext->independentResolve;
+            out_ext->filterMinmaxSingleComponentFormats = in_ext->filterMinmaxSingleComponentFormats;
+            out_ext->filterMinmaxImageComponentMapping = in_ext->filterMinmaxImageComponentMapping;
+            out_ext->maxTimelineSemaphoreValueDifference = in_ext->maxTimelineSemaphoreValueDifference;
+            out_ext->framebufferIntegerColorSampleCounts = in_ext->framebufferIntegerColorSampleCounts;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan13Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES);
+            const VkPhysicalDeviceVulkan13Properties *in_ext = (const VkPhysicalDeviceVulkan13Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES;
+            out_ext->minSubgroupSize = in_ext->minSubgroupSize;
+            out_ext->maxSubgroupSize = in_ext->maxSubgroupSize;
+            out_ext->maxComputeWorkgroupSubgroups = in_ext->maxComputeWorkgroupSubgroups;
+            out_ext->requiredSubgroupSizeStages = in_ext->requiredSubgroupSizeStages;
+            out_ext->maxInlineUniformBlockSize = in_ext->maxInlineUniformBlockSize;
+            out_ext->maxPerStageDescriptorInlineUniformBlocks = in_ext->maxPerStageDescriptorInlineUniformBlocks;
+            out_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks = in_ext->maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
+            out_ext->maxDescriptorSetInlineUniformBlocks = in_ext->maxDescriptorSetInlineUniformBlocks;
+            out_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks = in_ext->maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
+            out_ext->maxInlineUniformTotalSize = in_ext->maxInlineUniformTotalSize;
+            out_ext->integerDotProduct8BitUnsignedAccelerated = in_ext->integerDotProduct8BitUnsignedAccelerated;
+            out_ext->integerDotProduct8BitSignedAccelerated = in_ext->integerDotProduct8BitSignedAccelerated;
+            out_ext->integerDotProduct8BitMixedSignednessAccelerated = in_ext->integerDotProduct8BitMixedSignednessAccelerated;
+            out_ext->integerDotProduct4x8BitPackedUnsignedAccelerated = in_ext->integerDotProduct4x8BitPackedUnsignedAccelerated;
+            out_ext->integerDotProduct4x8BitPackedSignedAccelerated = in_ext->integerDotProduct4x8BitPackedSignedAccelerated;
+            out_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProduct4x8BitPackedMixedSignednessAccelerated;
+            out_ext->integerDotProduct16BitUnsignedAccelerated = in_ext->integerDotProduct16BitUnsignedAccelerated;
+            out_ext->integerDotProduct16BitSignedAccelerated = in_ext->integerDotProduct16BitSignedAccelerated;
+            out_ext->integerDotProduct16BitMixedSignednessAccelerated = in_ext->integerDotProduct16BitMixedSignednessAccelerated;
+            out_ext->integerDotProduct32BitUnsignedAccelerated = in_ext->integerDotProduct32BitUnsignedAccelerated;
+            out_ext->integerDotProduct32BitSignedAccelerated = in_ext->integerDotProduct32BitSignedAccelerated;
+            out_ext->integerDotProduct32BitMixedSignednessAccelerated = in_ext->integerDotProduct32BitMixedSignednessAccelerated;
+            out_ext->integerDotProduct64BitUnsignedAccelerated = in_ext->integerDotProduct64BitUnsignedAccelerated;
+            out_ext->integerDotProduct64BitSignedAccelerated = in_ext->integerDotProduct64BitSignedAccelerated;
+            out_ext->integerDotProduct64BitMixedSignednessAccelerated = in_ext->integerDotProduct64BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating8BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating4x8BitPackedMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating16BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating32BitMixedSignednessAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitUnsignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitSignedAccelerated;
+            out_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated = in_ext->integerDotProductAccumulatingSaturating64BitMixedSignednessAccelerated;
+            out_ext->storageTexelBufferOffsetAlignmentBytes = in_ext->storageTexelBufferOffsetAlignmentBytes;
+            out_ext->storageTexelBufferOffsetSingleTexelAlignment = in_ext->storageTexelBufferOffsetSingleTexelAlignment;
+            out_ext->uniformTexelBufferOffsetAlignmentBytes = in_ext->uniformTexelBufferOffsetAlignmentBytes;
+            out_ext->uniformTexelBufferOffsetSingleTexelAlignment = in_ext->uniformTexelBufferOffsetSingleTexelAlignment;
+            out_ext->maxBufferSize = in_ext->maxBufferSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan14Properties *out_ext = find_next_struct(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES);
+            const VkPhysicalDeviceVulkan14Properties *in_ext = (const VkPhysicalDeviceVulkan14Properties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES;
+            out_ext->lineSubPixelPrecisionBits = in_ext->lineSubPixelPrecisionBits;
+            out_ext->maxVertexAttribDivisor = in_ext->maxVertexAttribDivisor;
+            out_ext->supportsNonZeroFirstInstance = in_ext->supportsNonZeroFirstInstance;
+            out_ext->maxPushDescriptors = in_ext->maxPushDescriptors;
+            out_ext->dynamicRenderingLocalReadDepthStencilAttachments = in_ext->dynamicRenderingLocalReadDepthStencilAttachments;
+            out_ext->dynamicRenderingLocalReadMultisampledAttachments = in_ext->dynamicRenderingLocalReadMultisampledAttachments;
+            out_ext->earlyFragmentMultisampleCoverageAfterSampleCounting = in_ext->earlyFragmentMultisampleCoverageAfterSampleCounting;
+            out_ext->earlyFragmentSampleMaskTestBeforeSampleCounting = in_ext->earlyFragmentSampleMaskTestBeforeSampleCounting;
+            out_ext->depthStencilSwizzleOneSupport = in_ext->depthStencilSwizzleOneSupport;
+            out_ext->polygonModePointSize = in_ext->polygonModePointSize;
+            out_ext->nonStrictSinglePixelWideLinesUseParallelogram = in_ext->nonStrictSinglePixelWideLinesUseParallelogram;
+            out_ext->nonStrictWideLinesUseParallelogram = in_ext->nonStrictWideLinesUseParallelogram;
+            out_ext->blockTexelViewCompatibleMultipleLayers = in_ext->blockTexelViewCompatibleMultipleLayers;
+            out_ext->maxCombinedImageSamplerDescriptorCount = in_ext->maxCombinedImageSamplerDescriptorCount;
+            out_ext->fragmentShadingRateClampCombinerInputs = in_ext->fragmentShadingRateClampCombinerInputs;
+            out_ext->defaultRobustnessStorageBuffers = in_ext->defaultRobustnessStorageBuffers;
+            out_ext->defaultRobustnessUniformBuffers = in_ext->defaultRobustnessUniformBuffers;
+            out_ext->defaultRobustnessVertexInputs = in_ext->defaultRobustnessVertexInputs;
+            out_ext->defaultRobustnessImages = in_ext->defaultRobustnessImages;
+            out_ext->copySrcLayoutCount = in_ext->copySrcLayoutCount;
+            out_ext->pCopySrcLayouts = in_ext->pCopySrcLayouts;
+            out_ext->copyDstLayoutCount = in_ext->copyDstLayoutCount;
+            out_ext->pCopyDstLayouts = in_ext->pCopyDstLayouts;
+            memcpy(out_ext->optimalTilingLayoutUUID, in_ext->optimalTilingLayoutUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_ext->identicalMemoryTypeRequirements = in_ext->identicalMemoryTypeRequirements;
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            break;
+        }
+    }
+}
+#endif /* _WIN64 */
+
+static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceLayeredApiPropertiesKHR32 *in, VkPhysicalDeviceLayeredApiPropertiesKHR *out)
+{
+    const VkBaseInStructure32 *in_header;
+    VkBaseOutStructure *out_header = (void *)out;
+
+    if (!in) return;
+
+    out->sType = in->sType;
+    out->pNext = NULL;
+
+    for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext))
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            FIXME("Unhandled sType %u.\n", in_header->sType);
+            break;
+        }
+    }
+}
+
+static VkPhysicalDeviceLayeredApiPropertiesKHR *convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceLayeredApiPropertiesKHR32 *in, uint32_t count)
+{
+    VkPhysicalDeviceLayeredApiPropertiesKHR *out;
+    unsigned int i;
+
+    if (!in || !count) return NULL;
+
+    out = conversion_context_alloc(ctx, count * sizeof(*out));
+    for (i = 0; i < count; i++)
+    {
+        convert_VkPhysicalDeviceLayeredApiPropertiesKHR_win32_to_host(ctx, &in[i], &out[i]);
+    }
+
+    return out;
+}
+
+static void convert_VkPhysicalDeviceProperties2_win32_to_host(struct conversion_context *ctx, const VkPhysicalDeviceProperties232 *in, VkPhysicalDeviceProperties2 *out)
+{
+    const VkBaseInStructure32 *in_header;
+    VkBaseOutStructure *out_header = (void *)out;
+
+    if (!in) return;
+
+    out->sType = in->sType;
+    out->pNext = NULL;
+
+    for (in_header = UlongToPtr(in->pNext); in_header; in_header = UlongToPtr(in_header->pNext))
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceAccelerationStructurePropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceClusterAccelerationStructurePropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI:
+        {
+            VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceConservativeRasterizationPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceCooperativeMatrix2PropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceCooperativeMatrixPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceCooperativeMatrixPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceCooperativeVectorPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceCustomBorderColorPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES:
+        {
+            VkPhysicalDeviceDepthStencilResolveProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDescriptorBufferPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceDescriptorBufferTensorPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM32 *in_ext = (const VkPhysicalDeviceDescriptorBufferTensorPropertiesARM32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_TENSOR_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_ext->tensorCaptureReplayDescriptorDataSize = in_ext->tensorCaptureReplayDescriptorDataSize;
+            out_ext->tensorViewCaptureReplayDescriptorDataSize = in_ext->tensorViewCaptureReplayDescriptorDataSize;
+            out_ext->tensorDescriptorSize = in_ext->tensorDescriptorSize;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDescriptorHeapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_TENSOR_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceDescriptorHeapTensorPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_HEAP_TENSOR_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES:
+        {
+            VkPhysicalDeviceDescriptorIndexingProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDeviceGeneratedCommandsPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_GENERATED_COMMANDS_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDiscardRectanglePropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES:
+        {
+            VkPhysicalDeviceDriverProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceExtendedDynamicState3PropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceExtendedSparseAddressSpacePropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceExternalMemoryHostPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFaultPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES:
+        {
+            VkPhysicalDeviceFloatControlsProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceFragmentDensityMap2PropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_2_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_PROPERTIES_VALVE:
+        {
+            VkPhysicalDeviceFragmentDensityMapLayeredPropertiesVALVE *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_LAYERED_PROPERTIES_VALVE;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceFragmentDensityMapOffsetPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_OFFSET_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceFragmentDensityMapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFragmentShaderBarycentricPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_BARYCENTRIC_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceFragmentShadingRateEnumsPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_ENUMS_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFragmentShadingRatePropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceGraphicsPipelineLibraryPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES:
+        {
+            VkPhysicalDeviceHostImageCopyProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceHostImageCopyProperties32 *in_ext = (const VkPhysicalDeviceHostImageCopyProperties32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_ext->copySrcLayoutCount = in_ext->copySrcLayoutCount;
+            out_ext->pCopySrcLayouts = UlongToPtr(in_ext->pCopySrcLayouts);
+            out_ext->copyDstLayoutCount = in_ext->copyDstLayoutCount;
+            out_ext->pCopyDstLayouts = UlongToPtr(in_ext->pCopyDstLayouts);
+            memcpy(out_ext->optimalTilingLayoutUUID, in_ext->optimalTilingLayoutUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_ext->identicalMemoryTypeRequirements = in_ext->identicalMemoryTypeRequirements;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES:
+        {
+            VkPhysicalDeviceIDProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA:
+        {
+            VkPhysicalDeviceImageAlignmentControlPropertiesMESA *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_PROPERTIES_MESA;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceImageProcessing2PropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_2_PROPERTIES_QCOM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceImageProcessingPropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_PROCESSING_PROPERTIES_QCOM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES:
+        {
+            VkPhysicalDeviceInlineUniformBlockProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR:
+        {
+            VkPhysicalDeviceLayeredApiPropertiesListKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceLayeredApiPropertiesListKHR32 *in_ext = (const VkPhysicalDeviceLayeredApiPropertiesListKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR;
+            out_ext->pNext = NULL;
+            out_ext->layeredApiCount = in_ext->layeredApiCount;
+            out_ext->pLayeredApis = convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_win32_to_host(ctx, (VkPhysicalDeviceLayeredApiPropertiesKHR32 *)UlongToPtr(in_ext->pLayeredApis), in_ext->layeredApiCount);
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT:
+        {
+            VkPhysicalDeviceLayeredDriverPropertiesMSFT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_DRIVER_PROPERTIES_MSFT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceLegacyVertexAttributesPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_VERTEX_ATTRIBUTES_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES:
+        {
+            VkPhysicalDeviceLineRasterizationProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceMaintenance10PropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_10_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance3Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance4Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_4_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance5Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES:
+        {
+            VkPhysicalDeviceMaintenance6Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_6_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceMaintenance7PropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_7_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceMaintenance9PropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_9_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceMemoryDecompressionPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_DECOMPRESSION_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceMeshShaderPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceMeshShaderPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceMultiDrawPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES:
+        {
+            VkPhysicalDeviceMultiviewProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceNestedCommandBufferPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NESTED_COMMAND_BUFFER_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceOpacityMicromapPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPACITY_MICROMAP_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceOpticalFlowPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_OPTICAL_FLOW_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT:
+        {
+            VkPhysicalDevicePCIBusInfoPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV:
+        {
+            VkPhysicalDevicePartitionedAccelerationStructurePropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PARTITIONED_ACCELERATION_STRUCTURE_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_PROPERTIES_ARM:
+        {
+            VkPhysicalDevicePerformanceCountersByRegionPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_COUNTERS_BY_REGION_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR:
+        {
+            VkPhysicalDevicePerformanceQueryPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PERFORMANCE_QUERY_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR:
+        {
+            VkPhysicalDevicePipelineBinaryPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES:
+        {
+            VkPhysicalDevicePipelineRobustnessProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES:
+        {
+            VkPhysicalDevicePointClippingProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES:
+        {
+            VkPhysicalDeviceProtectedMemoryProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceProvokingVertexPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_PROPERTIES_NV:
+        {
+            VkPhysicalDevicePushConstantBankPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_CONSTANT_BANK_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES:
+        {
+            VkPhysicalDevicePushDescriptorProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceRayTracingInvocationReorderPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceRayTracingInvocationReorderPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_INVOCATION_REORDER_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceRayTracingPipelinePropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceRayTracingPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceRenderPassStripedPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RENDER_PASS_STRIPED_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceRobustness2PropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceSampleLocationsPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES:
+        {
+            VkPhysicalDeviceSamplerFilterMinmaxProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceSchedulingControlsPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCHEDULING_CONTROLS_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortPropertiesKHR *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceShaderAbortPropertiesKHR32 *in_ext = (const VkPhysicalDeviceShaderAbortPropertiesKHR32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR;
+            out_ext->pNext = NULL;
+            out_ext->maxShaderAbortMessageSize = in_ext->maxShaderAbortMessageSize;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD:
+        {
+            VkPhysicalDeviceShaderCoreProperties2AMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD:
+        {
+            VkPhysicalDeviceShaderCorePropertiesAMD *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceShaderCorePropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceShaderInstrumentationPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INSTRUMENTATION_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES:
+        {
+            VkPhysicalDeviceShaderIntegerDotProductProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_INTEGER_DOT_PRODUCT_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderLongVectorPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_LONG_VECTOR_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderModuleIdentifierPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_MODULE_IDENTIFIER_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderObjectPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceShaderSMBuiltinsPropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SM_BUILTINS_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceShaderTileImagePropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_TILE_IMAGE_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceShadingRateImagePropertiesNV *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES:
+        {
+            VkPhysicalDeviceSubgroupProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES:
+        {
+            VkPhysicalDeviceSubgroupSizeControlProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_SIZE_CONTROL_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI:
+        {
+            VkPhysicalDeviceSubpassShadingPropertiesHUAWEI *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBPASS_SHADING_PROPERTIES_HUAWEI;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_PROPERTIES_ARM:
+        {
+            VkPhysicalDeviceTensorPropertiesARM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TENSOR_PROPERTIES_ARM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES:
+        {
+            VkPhysicalDeviceTexelBufferAlignmentProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXEL_BUFFER_ALIGNMENT_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceTileMemoryHeapPropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM32 *in_ext = (const VkPhysicalDeviceTileMemoryHeapPropertiesQCOM32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_MEMORY_HEAP_PROPERTIES_QCOM;
+            out_ext->pNext = NULL;
+            out_ext->queueSubmitBoundary = in_ext->queueSubmitBoundary;
+            out_ext->tileBufferTransfers = in_ext->tileBufferTransfers;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM:
+        {
+            VkPhysicalDeviceTileShadingPropertiesQCOM *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TILE_SHADING_PROPERTIES_QCOM;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES:
+        {
+            VkPhysicalDeviceTimelineSemaphoreProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceTransformFeedbackPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES:
+        {
+            VkPhysicalDeviceVertexAttributeDivisorProperties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan11Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan12Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan13Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES:
+        {
+            VkPhysicalDeviceVulkan14Properties *out_ext = conversion_context_alloc(ctx, sizeof(*out_ext));
+            const VkPhysicalDeviceVulkan14Properties32 *in_ext = (const VkPhysicalDeviceVulkan14Properties32 *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES;
+            out_ext->pNext = NULL;
+            out_ext->lineSubPixelPrecisionBits = in_ext->lineSubPixelPrecisionBits;
+            out_ext->maxVertexAttribDivisor = in_ext->maxVertexAttribDivisor;
+            out_ext->supportsNonZeroFirstInstance = in_ext->supportsNonZeroFirstInstance;
+            out_ext->maxPushDescriptors = in_ext->maxPushDescriptors;
+            out_ext->dynamicRenderingLocalReadDepthStencilAttachments = in_ext->dynamicRenderingLocalReadDepthStencilAttachments;
+            out_ext->dynamicRenderingLocalReadMultisampledAttachments = in_ext->dynamicRenderingLocalReadMultisampledAttachments;
+            out_ext->earlyFragmentMultisampleCoverageAfterSampleCounting = in_ext->earlyFragmentMultisampleCoverageAfterSampleCounting;
+            out_ext->earlyFragmentSampleMaskTestBeforeSampleCounting = in_ext->earlyFragmentSampleMaskTestBeforeSampleCounting;
+            out_ext->depthStencilSwizzleOneSupport = in_ext->depthStencilSwizzleOneSupport;
+            out_ext->polygonModePointSize = in_ext->polygonModePointSize;
+            out_ext->nonStrictSinglePixelWideLinesUseParallelogram = in_ext->nonStrictSinglePixelWideLinesUseParallelogram;
+            out_ext->nonStrictWideLinesUseParallelogram = in_ext->nonStrictWideLinesUseParallelogram;
+            out_ext->blockTexelViewCompatibleMultipleLayers = in_ext->blockTexelViewCompatibleMultipleLayers;
+            out_ext->maxCombinedImageSamplerDescriptorCount = in_ext->maxCombinedImageSamplerDescriptorCount;
+            out_ext->fragmentShadingRateClampCombinerInputs = in_ext->fragmentShadingRateClampCombinerInputs;
+            out_ext->defaultRobustnessStorageBuffers = in_ext->defaultRobustnessStorageBuffers;
+            out_ext->defaultRobustnessUniformBuffers = in_ext->defaultRobustnessUniformBuffers;
+            out_ext->defaultRobustnessVertexInputs = in_ext->defaultRobustnessVertexInputs;
+            out_ext->defaultRobustnessImages = in_ext->defaultRobustnessImages;
+            out_ext->copySrcLayoutCount = in_ext->copySrcLayoutCount;
+            out_ext->pCopySrcLayouts = UlongToPtr(in_ext->pCopySrcLayouts);
+            out_ext->copyDstLayoutCount = in_ext->copyDstLayoutCount;
+            out_ext->pCopyDstLayouts = UlongToPtr(in_ext->pCopyDstLayouts);
+            memcpy(out_ext->optimalTilingLayoutUUID, in_ext->optimalTilingLayoutUUID, VK_UUID_SIZE * sizeof(uint8_t));
+            out_ext->identicalMemoryTypeRequirements = in_ext->identicalMemoryTypeRequirements;
+            out_header->pNext = (void *)out_ext;
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            FIXME("Unhandled sType %u.\n", in_header->sType);
+            break;
+        }
+    }
+}
+
+static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_host_to_win32(const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR32 *out)
+{
+    const VkBaseInStructure *in_header;
+    VkBaseOutStructure32 *out_header = (void *)out;
+
+    if (!in) return;
+
+    out->vendorID = in->vendorID;
+    out->deviceID = in->deviceID;
+    out->layeredAPI = in->layeredAPI;
+    memcpy(out->deviceName, in->deviceName, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE * sizeof(char));
+
+    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceLayeredApiVulkanPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR);
+            const VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *in_ext = (const VkPhysicalDeviceLayeredApiVulkanPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR;
+            convert_VkPhysicalDeviceProperties2_host_to_win32(&in_ext->properties, &out_ext->properties);
+            out_header = (void *)out_ext;
+            break;
+        }
+        default:
+            break;
+        }
+    }
+}
+
+static void convert_VkPhysicalDeviceLayeredApiPropertiesKHR_array_host_to_win32(const VkPhysicalDeviceLayeredApiPropertiesKHR *in, VkPhysicalDeviceLayeredApiPropertiesKHR32 *out, uint32_t count)
+{
+    unsigned int i;
+
+    if (!in) return;
+
+    for (i = 0; i < count; i++)
+    {
+        convert_VkPhysicalDeviceLayeredApiPropertiesKHR_host_to_win32(&in[i], &out[i]);
+    }
+}
+
+static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDeviceProperties2 *in, VkPhysicalDeviceProperties232 *out)
+{
+    const VkBaseInStructure *in_header;
+    VkBaseOutStructure32 *out_header = (void *)out;
+
+    if (!in) return;
+
+    convert_VkPhysicalDeviceProperties_host_to_win32(&in->properties, &out->properties);
+
+    for (in_header = (void *)in->pNext; in_header; in_header = (void *)in_header->pNext)
+    {
+        switch (in_header->sType)
+        {
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceAccelerationStructurePropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR);
+            const VkPhysicalDeviceAccelerationStructurePropertiesKHR *in_ext = (const VkPhysicalDeviceAccelerationStructurePropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
+            out_ext->maxGeometryCount = in_ext->maxGeometryCount;
+            out_ext->maxInstanceCount = in_ext->maxInstanceCount;
+            out_ext->maxPrimitiveCount = in_ext->maxPrimitiveCount;
+            out_ext->maxPerStageDescriptorAccelerationStructures = in_ext->maxPerStageDescriptorAccelerationStructures;
+            out_ext->maxPerStageDescriptorUpdateAfterBindAccelerationStructures = in_ext->maxPerStageDescriptorUpdateAfterBindAccelerationStructures;
+            out_ext->maxDescriptorSetAccelerationStructures = in_ext->maxDescriptorSetAccelerationStructures;
+            out_ext->maxDescriptorSetUpdateAfterBindAccelerationStructures = in_ext->maxDescriptorSetUpdateAfterBindAccelerationStructures;
+            out_ext->minAccelerationStructureScratchOffsetAlignment = in_ext->minAccelerationStructureScratchOffsetAlignment;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT);
+            const VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *in_ext = (const VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT;
+            out_ext->advancedBlendMaxColorAttachments = in_ext->advancedBlendMaxColorAttachments;
+            out_ext->advancedBlendIndependentBlend = in_ext->advancedBlendIndependentBlend;
+            out_ext->advancedBlendNonPremultipliedSrcColor = in_ext->advancedBlendNonPremultipliedSrcColor;
+            out_ext->advancedBlendNonPremultipliedDstColor = in_ext->advancedBlendNonPremultipliedDstColor;
+            out_ext->advancedBlendCorrelatedOverlap = in_ext->advancedBlendCorrelatedOverlap;
+            out_ext->advancedBlendAllOperations = in_ext->advancedBlendAllOperations;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceClusterAccelerationStructurePropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV);
+            const VkPhysicalDeviceClusterAccelerationStructurePropertiesNV *in_ext = (const VkPhysicalDeviceClusterAccelerationStructurePropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_ACCELERATION_STRUCTURE_PROPERTIES_NV;
+            out_ext->maxVerticesPerCluster = in_ext->maxVerticesPerCluster;
+            out_ext->maxTrianglesPerCluster = in_ext->maxTrianglesPerCluster;
+            out_ext->clusterScratchByteAlignment = in_ext->clusterScratchByteAlignment;
+            out_ext->clusterByteAlignment = in_ext->clusterByteAlignment;
+            out_ext->clusterTemplateByteAlignment = in_ext->clusterTemplateByteAlignment;
+            out_ext->clusterBottomLevelByteAlignment = in_ext->clusterBottomLevelByteAlignment;
+            out_ext->clusterTemplateBoundsByteAlignment = in_ext->clusterTemplateBoundsByteAlignment;
+            out_ext->maxClusterGeometryIndex = in_ext->maxClusterGeometryIndex;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI:
+        {
+            VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI);
+            const VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI *in_ext = (const VkPhysicalDeviceClusterCullingShaderPropertiesHUAWEI *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CLUSTER_CULLING_SHADER_PROPERTIES_HUAWEI;
+            memcpy(out_ext->maxWorkGroupCount, in_ext->maxWorkGroupCount, 3 * sizeof(uint32_t));
+            memcpy(out_ext->maxWorkGroupSize, in_ext->maxWorkGroupSize, 3 * sizeof(uint32_t));
+            out_ext->maxOutputClusterCount = in_ext->maxOutputClusterCount;
+            out_ext->indirectBufferOffsetAlignment = in_ext->indirectBufferOffsetAlignment;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR);
+            const VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR *in_ext = (const VkPhysicalDeviceComputeShaderDerivativesPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COMPUTE_SHADER_DERIVATIVES_PROPERTIES_KHR;
+            out_ext->meshAndTaskShaderDerivatives = in_ext->meshAndTaskShaderDerivatives;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceConservativeRasterizationPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT);
+            const VkPhysicalDeviceConservativeRasterizationPropertiesEXT *in_ext = (const VkPhysicalDeviceConservativeRasterizationPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT;
+            out_ext->primitiveOverestimationSize = in_ext->primitiveOverestimationSize;
+            out_ext->maxExtraPrimitiveOverestimationSize = in_ext->maxExtraPrimitiveOverestimationSize;
+            out_ext->extraPrimitiveOverestimationSizeGranularity = in_ext->extraPrimitiveOverestimationSizeGranularity;
+            out_ext->primitiveUnderestimation = in_ext->primitiveUnderestimation;
+            out_ext->conservativePointAndLineRasterization = in_ext->conservativePointAndLineRasterization;
+            out_ext->degenerateTrianglesRasterized = in_ext->degenerateTrianglesRasterized;
+            out_ext->degenerateLinesRasterized = in_ext->degenerateLinesRasterized;
+            out_ext->fullyCoveredFragmentShaderInputVariable = in_ext->fullyCoveredFragmentShaderInputVariable;
+            out_ext->conservativeRasterizationPostDepthCoverage = in_ext->conservativeRasterizationPostDepthCoverage;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceCooperativeMatrix2PropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV);
+            const VkPhysicalDeviceCooperativeMatrix2PropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrix2PropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_2_PROPERTIES_NV;
+            out_ext->cooperativeMatrixWorkgroupScopeMaxWorkgroupSize = in_ext->cooperativeMatrixWorkgroupScopeMaxWorkgroupSize;
+            out_ext->cooperativeMatrixFlexibleDimensionsMaxDimension = in_ext->cooperativeMatrixFlexibleDimensionsMaxDimension;
+            out_ext->cooperativeMatrixWorkgroupScopeReservedSharedMemory = in_ext->cooperativeMatrixWorkgroupScopeReservedSharedMemory;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceCooperativeMatrixPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR);
+            const VkPhysicalDeviceCooperativeMatrixPropertiesKHR *in_ext = (const VkPhysicalDeviceCooperativeMatrixPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR;
+            out_ext->cooperativeMatrixSupportedStages = in_ext->cooperativeMatrixSupportedStages;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceCooperativeMatrixPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV);
+            const VkPhysicalDeviceCooperativeMatrixPropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeMatrixPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_NV;
+            out_ext->cooperativeMatrixSupportedStages = in_ext->cooperativeMatrixSupportedStages;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV:
+        {
+            VkPhysicalDeviceCooperativeVectorPropertiesNV32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV);
+            const VkPhysicalDeviceCooperativeVectorPropertiesNV *in_ext = (const VkPhysicalDeviceCooperativeVectorPropertiesNV *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_VECTOR_PROPERTIES_NV;
+            out_ext->cooperativeVectorSupportedStages = in_ext->cooperativeVectorSupportedStages;
+            out_ext->cooperativeVectorTrainingFloat16Accumulation = in_ext->cooperativeVectorTrainingFloat16Accumulation;
+            out_ext->cooperativeVectorTrainingFloat32Accumulation = in_ext->cooperativeVectorTrainingFloat32Accumulation;
+            out_ext->maxCooperativeVectorComponents = in_ext->maxCooperativeVectorComponents;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR);
+            const VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR *in_ext = (const VkPhysicalDeviceCopyMemoryIndirectPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COPY_MEMORY_INDIRECT_PROPERTIES_KHR;
+            out_ext->supportedQueues = in_ext->supportedQueues;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceCustomBorderColorPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT);
+            const VkPhysicalDeviceCustomBorderColorPropertiesEXT *in_ext = (const VkPhysicalDeviceCustomBorderColorPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_PROPERTIES_EXT;
+            out_ext->maxCustomBorderColorSamplers = in_ext->maxCustomBorderColorSamplers;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES:
+        {
+            VkPhysicalDeviceDepthStencilResolveProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES);
+            const VkPhysicalDeviceDepthStencilResolveProperties *in_ext = (const VkPhysicalDeviceDepthStencilResolveProperties *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
+            out_ext->supportedDepthResolveModes = in_ext->supportedDepthResolveModes;
+            out_ext->supportedStencilResolveModes = in_ext->supportedStencilResolveModes;
+            out_ext->independentResolveNone = in_ext->independentResolveNone;
+            out_ext->independentResolve = in_ext->independentResolve;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT);
+            const VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferDensityMapPropertiesEXT *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_DENSITY_MAP_PROPERTIES_EXT;
+            out_ext->combinedImageSamplerDensityMapDescriptorSize = in_ext->combinedImageSamplerDensityMapDescriptorSize;
+            out_header = (void *)out_ext;
+            break;
+        }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT:
+        {
+            VkPhysicalDeviceDescriptorBufferPropertiesEXT32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT);
             const VkPhysicalDeviceDescriptorBufferPropertiesEXT *in_ext = (const VkPhysicalDeviceDescriptorBufferPropertiesEXT *)in_header;
             out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT;
             out_ext->combinedImageSamplerDescriptorSingleArray = in_ext->combinedImageSamplerDescriptorSingleArray;
@@ -39321,6 +42401,15 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceFaultPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR);
+            const VkPhysicalDeviceFaultPropertiesKHR *in_ext = (const VkPhysicalDeviceFaultPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR;
+            out_ext->maxDeviceFaultCount = in_ext->maxDeviceFaultCount;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES:
         {
             VkPhysicalDeviceFloatControlsProperties32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES);
@@ -39972,6 +43061,15 @@ static void convert_VkPhysicalDeviceProperties2_host_to_win32(const VkPhysicalDe
             out_header = (void *)out_ext;
             break;
         }
+        case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR:
+        {
+            VkPhysicalDeviceShaderAbortPropertiesKHR32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR);
+            const VkPhysicalDeviceShaderAbortPropertiesKHR *in_ext = (const VkPhysicalDeviceShaderAbortPropertiesKHR *)in_header;
+            out_ext->sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR;
+            out_ext->maxShaderAbortMessageSize = in_ext->maxShaderAbortMessageSize;
+            out_header = (void *)out_ext;
+            break;
+        }
         case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM:
         {
             VkPhysicalDeviceShaderCoreBuiltinsPropertiesARM32 *out_ext = find_next_struct32(out_header, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_BUILTINS_PROPERTIES_ARM);
@@ -58409,6 +61507,40 @@ static NTSTATUS thunk32_vkGetDeviceCombinedImageSamplerIndexNVX(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkGetDeviceFaultDebugInfoKHR(void *args)
+{
+    struct vkGetDeviceFaultDebugInfoKHR_params *params = args;
+
+    TRACE("%p, %p\n", params->device, params->pDebugInfo);
+
+    params->result = vulkan_device_from_handle(params->device)->p_vkGetDeviceFaultDebugInfoKHR(vulkan_device_from_handle(params->device)->host.device, params->pDebugInfo);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkGetDeviceFaultDebugInfoKHR(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        PTR32 pDebugInfo;
+        VkResult result;
+    } *params = args;
+    VkDeviceFaultDebugInfoKHR pDebugInfo_host;
+    struct conversion_context local_ctx;
+    struct conversion_context *ctx = &local_ctx;
+
+    TRACE("%#x, %#x\n", params->device, params->pDebugInfo);
+
+    init_conversion_context(ctx);
+    convert_VkDeviceFaultDebugInfoKHR_win32_to_host(ctx, (VkDeviceFaultDebugInfoKHR32 *)UlongToPtr(params->pDebugInfo), &pDebugInfo_host);
+    params->result = vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkGetDeviceFaultDebugInfoKHR(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, &pDebugInfo_host);
+    convert_VkDeviceFaultDebugInfoKHR_host_to_win32(&pDebugInfo_host, (VkDeviceFaultDebugInfoKHR32 *)UlongToPtr(params->pDebugInfo));
+    free_conversion_context(ctx);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkGetDeviceFaultInfoEXT(void *args)
 {
@@ -58451,6 +61583,42 @@ static NTSTATUS thunk32_vkGetDeviceFaultInfoEXT(void *args)
     return STATUS_SUCCESS;
 }
 
+#ifdef _WIN64
+static NTSTATUS thunk64_vkGetDeviceFaultReportsKHR(void *args)
+{
+    struct vkGetDeviceFaultReportsKHR_params *params = args;
+
+    TRACE("%p, 0x%s, %p, %p\n", params->device, wine_dbgstr_longlong(params->timeout), params->pFaultCounts, params->pFaultInfo);
+
+    params->result = vulkan_device_from_handle(params->device)->p_vkGetDeviceFaultReportsKHR(vulkan_device_from_handle(params->device)->host.device, params->timeout, params->pFaultCounts, params->pFaultInfo);
+    return STATUS_SUCCESS;
+}
+#endif /* _WIN64 */
+
+static NTSTATUS thunk32_vkGetDeviceFaultReportsKHR(void *args)
+{
+    struct
+    {
+        PTR32 device;
+        uint64_t DECLSPEC_ALIGN(8) timeout;
+        PTR32 pFaultCounts;
+        PTR32 pFaultInfo;
+        VkResult result;
+    } *params = args;
+    VkDeviceFaultInfoKHR *pFaultInfo_host;
+    struct conversion_context local_ctx;
+    struct conversion_context *ctx = &local_ctx;
+
+    TRACE("%#x, 0x%s, %#x, %#x\n", params->device, wine_dbgstr_longlong(params->timeout), params->pFaultCounts, params->pFaultInfo);
+
+    init_conversion_context(ctx);
+    pFaultInfo_host = convert_VkDeviceFaultInfoKHR_array_win32_to_host(ctx, (VkDeviceFaultInfoKHR32 *)UlongToPtr(params->pFaultInfo), *(uint32_t *)UlongToPtr(params->pFaultCounts));
+    params->result = vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->p_vkGetDeviceFaultReportsKHR(vulkan_device_from_handle((VkDevice)UlongToPtr(params->device))->host.device, params->timeout, (uint32_t *)UlongToPtr(params->pFaultCounts), pFaultInfo_host);
+    convert_VkDeviceFaultInfoKHR_array_host_to_win32(pFaultInfo_host, (VkDeviceFaultInfoKHR32 *)UlongToPtr(params->pFaultInfo), *(uint32_t *)UlongToPtr(params->pFaultCounts));
+    free_conversion_context(ctx);
+    return STATUS_SUCCESS;
+}
+
 #ifdef _WIN64
 static NTSTATUS thunk64_vkGetDeviceGroupPeerMemoryFeatures(void *args)
 {
@@ -61199,10 +64367,17 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceProperties(void *args)
 static NTSTATUS thunk64_vkGetPhysicalDeviceProperties2(void *args)
 {
     struct vkGetPhysicalDeviceProperties2_params *params = args;
+    VkPhysicalDeviceProperties2 pProperties_host;
+    struct conversion_context local_ctx;
+    struct conversion_context *ctx = &local_ctx;
 
     TRACE("%p, %p\n", params->physicalDevice, params->pProperties);
 
-    vk_funcs->p_vkGetPhysicalDeviceProperties2(params->physicalDevice, params->pProperties);
+    init_conversion_context(ctx);
+    convert_VkPhysicalDeviceProperties2_win64_to_host(ctx, params->pProperties, &pProperties_host);
+    vk_funcs->p_vkGetPhysicalDeviceProperties2(params->physicalDevice, &pProperties_host);
+    convert_VkPhysicalDeviceProperties2_host_to_win64(&pProperties_host, params->pProperties);
+    free_conversion_context(ctx);
     return STATUS_SUCCESS;
 }
 #endif /* _WIN64 */
@@ -61232,10 +64407,17 @@ static NTSTATUS thunk32_vkGetPhysicalDeviceProperties2(void *args)
 static NTSTATUS thunk64_vkGetPhysicalDeviceProperties2KHR(void *args)
 {
     struct vkGetPhysicalDeviceProperties2KHR_params *params = args;
+    VkPhysicalDeviceProperties2 pProperties_host;
+    struct conversion_context local_ctx;
+    struct conversion_context *ctx = &local_ctx;
 
     TRACE("%p, %p\n", params->physicalDevice, params->pProperties);
 
-    vk_funcs->p_vkGetPhysicalDeviceProperties2KHR(params->physicalDevice, params->pProperties);
+    init_conversion_context(ctx);
+    convert_VkPhysicalDeviceProperties2_win64_to_host(ctx, params->pProperties, &pProperties_host);
+    vk_funcs->p_vkGetPhysicalDeviceProperties2KHR(params->physicalDevice, &pProperties_host);
+    convert_VkPhysicalDeviceProperties2_host_to_win64(&pProperties_host, params->pProperties);
+    free_conversion_context(ctx);
     return STATUS_SUCCESS;
 }
 #endif /* _WIN64 */
@@ -66001,7 +69183,9 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk64_vkGetDeviceBufferMemoryRequirements,
     thunk64_vkGetDeviceBufferMemoryRequirementsKHR,
     thunk64_vkGetDeviceCombinedImageSamplerIndexNVX,
+    thunk64_vkGetDeviceFaultDebugInfoKHR,
     thunk64_vkGetDeviceFaultInfoEXT,
+    thunk64_vkGetDeviceFaultReportsKHR,
     thunk64_vkGetDeviceGroupPeerMemoryFeatures,
     thunk64_vkGetDeviceGroupPeerMemoryFeaturesKHR,
     thunk64_vkGetDeviceGroupPresentCapabilitiesKHR,
@@ -66731,7 +69915,9 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     thunk32_vkGetDeviceBufferMemoryRequirements,
     thunk32_vkGetDeviceBufferMemoryRequirementsKHR,
     thunk32_vkGetDeviceCombinedImageSamplerIndexNVX,
+    thunk32_vkGetDeviceFaultDebugInfoKHR,
     thunk32_vkGetDeviceFaultInfoEXT,
+    thunk32_vkGetDeviceFaultReportsKHR,
     thunk32_vkGetDeviceGroupPeerMemoryFeatures,
     thunk32_vkGetDeviceGroupPeerMemoryFeaturesKHR,
     thunk32_vkGetDeviceGroupPresentCapabilitiesKHR,
diff --git a/dlls/winevulkan/winevulkan.json b/dlls/winevulkan/winevulkan.json
index 4f809f8a1323..121873b64f7a 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.346"
+        "api_version": "1.4.347"
     }
 }
diff --git a/dlls/winewayland.drv/wayland_keyboard.c b/dlls/winewayland.drv/wayland_keyboard.c
index 648b7f9cc2f9..0a6eea2fa734 100644
--- a/dlls/winewayland.drv/wayland_keyboard.c
+++ b/dlls/winewayland.drv/wayland_keyboard.c
@@ -38,6 +38,40 @@
 WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
 WINE_DECLARE_DEBUG_CHANNEL(key);
 
+static BOOL is_ime_hkl(HKL hkl)
+{
+    /* See https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values#input-method-editors */
+    switch (HIWORD(hkl))
+    {
+    case MAKELANGID(LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_BENGALI, SUBLANG_BENGALI_INDIA): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): return TRUE;
+    case MAKELANGID(LANG_GUJARATI, SUBLANG_GUJARATI_INDIA): return TRUE;
+    case MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA): return TRUE;
+    case MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN): return TRUE;
+    case MAKELANGID(LANG_KANNADA, SUBLANG_KANNADA_INDIA): return TRUE;
+    case MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN): return TRUE;
+    case MAKELANGID(LANG_MALAYALAM, SUBLANG_MALAYALAM_INDIA): return TRUE;
+    case MAKELANGID(LANG_MARATHI, SUBLANG_MARATHI_INDIA): return TRUE;
+    case MAKELANGID(LANG_NEPALI, SUBLANG_NEPALI_NEPAL): return TRUE;
+    case MAKELANGID(LANG_ODIA, SUBLANG_ODIA_INDIA): return TRUE;
+    case MAKELANGID(LANG_PUNJABI, SUBLANG_PUNJABI_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA): return TRUE;
+    case MAKELANGID(LANG_TELUGU, SUBLANG_TELUGU_INDIA): return TRUE;
+    case MAKELANGID(LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM): return TRUE;
+    case MAKELANGID(LANG_YI, SUBLANG_YI_PRC): return TRUE;
+    default: return (HIWORD(hkl) & 0xe000) == 0xe000;
+    }
+}
+
+static HKL get_ime_hkl(LCID locale)
+{
+    return ULongToHandle(MAKELONG(locale, 0xe001));
+}
+
 struct layout
 {
     struct list entry;
@@ -76,6 +110,13 @@ static struct list xkb_layouts = LIST_INIT(xkb_layouts);
 static struct rxkb_context *rxkb_context;
 static HKL keyboard_hkl; /* the HKL matching the currently active xkb group */
 
+void activate_keyboard_hkl(HWND hwnd, BOOL ime)
+{
+    HKL hkl = ime && !is_ime_hkl(keyboard_hkl) ? get_ime_hkl(LOWORD(keyboard_hkl)) : keyboard_hkl;
+    TRACE("Changing keyboard layout to %p\n", hkl);
+    NtUserPostMessage(hwnd, WM_INPUTLANGCHANGEREQUEST, 0 /*FIXME*/, (LPARAM)hkl);
+}
+
 static void xkb_layout_addref(struct layout *layout)
 {
     InterlockedIncrement(&layout->ref);
@@ -573,9 +614,11 @@ static void add_xkb_layout(const char *xkb_layout, struct xkb_keymap *xkb_keymap
 
 static void set_current_xkb_group(xkb_layout_index_t xkb_group)
 {
+    struct wayland_text_input *text_input = &process_wayland.text_input;
     struct wayland_keyboard *keyboard = &process_wayland.keyboard;
     LCID locale = LOWORD(NtUserGetKeyboardLayout(0));
     struct layout *layout;
+    BOOL ime;
     HKL hkl;
 
     pthread_mutex_lock(&xkb_layouts_mutex);
@@ -595,9 +638,11 @@ static void set_current_xkb_group(xkb_layout_index_t xkb_group)
     if (hkl == keyboard_hkl) return;
     keyboard_hkl = hkl;
 
-    TRACE("Changing keyboard layout to %p\n", hkl);
-    NtUserPostMessage(keyboard->focused_hwnd, WM_INPUTLANGCHANGEREQUEST, 0 /*FIXME*/,
-                      (LPARAM)keyboard_hkl);
+    pthread_mutex_lock(&text_input->mutex);
+    ime = text_input->focused_hwnd == keyboard->focused_hwnd;
+    pthread_mutex_unlock(&text_input->mutex);
+
+    activate_keyboard_hkl(keyboard->focused_hwnd, ime);
 }
 
 static BOOL find_xkb_layout_variant(const char *name, const char **layout, const char **variant)
@@ -962,6 +1007,8 @@ const KBDTABLES *WAYLAND_KbdLayerDescriptor(HKL hkl)
 
     TRACE("hkl=%p\n", hkl);
 
+    if (hkl == get_ime_hkl(LOWORD(hkl))) hkl = keyboard_hkl;
+
     pthread_mutex_lock(&xkb_layouts_mutex);
 
     LIST_FOR_EACH_ENTRY(layout, &xkb_layouts, struct layout, entry)
diff --git a/dlls/winewayland.drv/wayland_text_input.c b/dlls/winewayland.drv/wayland_text_input.c
index 52cfef27e500..f92f051f918d 100644
--- a/dlls/winewayland.drv/wayland_text_input.c
+++ b/dlls/winewayland.drv/wayland_text_input.c
@@ -97,6 +97,8 @@ static void text_input_enter(void *data, struct zwp_text_input_v3 *zwp_text_inpu
     zwp_text_input_v3_set_cursor_rectangle(text_input->zwp_text_input_v3, 0, 0, 0, 0);
     zwp_text_input_v3_commit(text_input->zwp_text_input_v3);
     pthread_mutex_unlock(&text_input->mutex);
+
+    activate_keyboard_hkl(hwnd, TRUE);
 }
 
 static void text_input_leave(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h
index ad41a1b474e4..3b0c300a1f6f 100644
--- a/dlls/winewayland.drv/waylanddrv.h
+++ b/dlls/winewayland.drv/waylanddrv.h
@@ -392,6 +392,7 @@ void wayland_keyboard_init(struct wl_keyboard *wl_keyboard);
 void wayland_keyboard_deinit(void);
 const KBDTABLES *WAYLAND_KbdLayerDescriptor(HKL hkl);
 void WAYLAND_ReleaseKbdTables(const KBDTABLES *);
+void activate_keyboard_hkl(HWND hwnd, BOOL ime);
 
 /**********************************************************************
  *          Wayland pointer
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index fdb6b635898e..2983d7bfe8a6 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -752,6 +752,13 @@ static void handle_wm_protocols( HWND hwnd, XClientMessageEvent *event )
                 NtUserIsWindowEnabled( hwnd ), NtUserIsWindowVisible( hwnd ), NtUserGetWindowLongW( hwnd, GWL_STYLE ),
                 get_focus(), get_active_window(), last_focus );
 
+        if (event_time) SERVER_START_REQ( set_user_input_time )
+        {
+            req->set = 1;
+            wine_server_call( req );
+        }
+        SERVER_END_REQ;
+
         if (can_activate_window(hwnd))
         {
             set_focus( event->display, hwnd, event_time );
diff --git a/dlls/winex11.drv/keyboard.c b/dlls/winex11.drv/keyboard.c
index 25836fe835d7..e2281bef0172 100644
--- a/dlls/winex11.drv/keyboard.c
+++ b/dlls/winex11.drv/keyboard.c
@@ -1823,7 +1823,7 @@ void X11DRV_InitKeyboard( Display *display )
  */
 BOOL X11DRV_ActivateKeyboardLayout(HKL hkl, UINT flags)
 {
-    FIXME("%p, %04x: semi-stub!\n", hkl, flags);
+    WARN("%p, %04x: semi-stub!\n", hkl, flags);
 
     if (flags & KLF_SETFORPROCESS)
     {
diff --git a/dlls/winex11.drv/xim.c b/dlls/winex11.drv/xim.c
index 0bb30e9ccead..2c2049ac7637 100644
--- a/dlls/winex11.drv/xim.c
+++ b/dlls/winex11.drv/xim.c
@@ -74,8 +74,49 @@ BOOL xim_in_compose_mode(void)
     return !!ime_comp_buf;
 }
 
+static BOOL is_ime_hkl( HKL hkl )
+{
+    /* See https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values#input-method-editors */
+    switch (HIWORD(hkl))
+    {
+    case MAKELANGID(LANG_AMHARIC, SUBLANG_AMHARIC_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_BENGALI, SUBLANG_BENGALI_INDIA): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED): return TRUE;
+    case MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL): return TRUE;
+    case MAKELANGID(LANG_GUJARATI, SUBLANG_GUJARATI_INDIA): return TRUE;
+    case MAKELANGID(LANG_HINDI, SUBLANG_HINDI_INDIA): return TRUE;
+    case MAKELANGID(LANG_JAPANESE, SUBLANG_JAPANESE_JAPAN): return TRUE;
+    case MAKELANGID(LANG_KANNADA, SUBLANG_KANNADA_INDIA): return TRUE;
+    case MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN): return TRUE;
+    case MAKELANGID(LANG_MALAYALAM, SUBLANG_MALAYALAM_INDIA): return TRUE;
+    case MAKELANGID(LANG_MARATHI, SUBLANG_MARATHI_INDIA): return TRUE;
+    case MAKELANGID(LANG_NEPALI, SUBLANG_NEPALI_NEPAL): return TRUE;
+    case MAKELANGID(LANG_ODIA, SUBLANG_ODIA_INDIA): return TRUE;
+    case MAKELANGID(LANG_PUNJABI, SUBLANG_PUNJABI_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_INDIA): return TRUE;
+    case MAKELANGID(LANG_TAMIL, SUBLANG_TAMIL_SRI_LANKA): return TRUE;
+    case MAKELANGID(LANG_TELUGU, SUBLANG_TELUGU_INDIA): return TRUE;
+    case MAKELANGID(LANG_TIGRINYA, SUBLANG_TIGRINYA_ETHIOPIA): return TRUE;
+    case MAKELANGID(LANG_VIETNAMESE, SUBLANG_VIETNAMESE_VIETNAM): return TRUE;
+    case MAKELANGID(LANG_YI, SUBLANG_YI_PRC): return TRUE;
+    default: return (HIWORD(hkl) & 0xe000) == 0xe000;
+    }
+}
+
+static HKL get_ime_hkl( LCID locale )
+{
+    return ULongToHandle( MAKELONG( locale, 0xe001 ) );
+}
+
+static void activate_ime_hkl( HWND hwnd )
+{
+    HKL hkl = NtUserGetKeyboardLayout( 0 );
+    if (!is_ime_hkl( hkl )) NtUserActivateKeyboardLayout( get_ime_hkl( LOWORD(hkl) ), 0 );
+}
+
 static void post_ime_update( HWND hwnd, UINT cursor_pos, WCHAR *comp_str, WCHAR *result_str )
 {
+    activate_ime_hkl( hwnd );
     NtUserMessageCall( hwnd, WINE_IME_POST_UPDATE, cursor_pos, (LPARAM)comp_str,
                        result_str, NtUserImeDriverCall, FALSE );
 }
@@ -128,6 +169,7 @@ static BOOL xic_preedit_state_notify( XIC xic, XPointer user, XPointer arg )
     switch (state)
     {
     case XIMPreeditEnable:
+        activate_ime_hkl( hwnd );
         NtUserPostMessage( hwnd, WM_WINE_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE );
         break;
     case XIMPreeditDisable:
@@ -147,6 +189,7 @@ static int xic_preedit_start( XIC xic, XPointer user, XPointer arg )
     if ((ime_comp_buf = realloc( ime_comp_buf, sizeof(WCHAR) ))) *ime_comp_buf = 0;
     else ERR( "Failed to allocate preedit buffer\n" );
 
+    activate_ime_hkl( hwnd );
     NtUserPostMessage( hwnd, WM_WINE_IME_NOTIFY, IMN_WINE_SET_OPEN_STATUS, TRUE );
     post_ime_update( hwnd, 0, ime_comp_buf, NULL );
 
diff --git a/dlls/winhttp/Makefile.in b/dlls/winhttp/Makefile.in
index 6a8d5e9b90a5..814766a4989e 100644
--- a/dlls/winhttp/Makefile.in
+++ b/dlls/winhttp/Makefile.in
@@ -15,5 +15,6 @@ SOURCES = \
 	net.c \
 	request.c \
 	session.c \
+	socket.c \
 	url.c \
 	winhttp_tlb.idl
diff --git a/dlls/winhttp/net.c b/dlls/winhttp/net.c
index 68c5029beb3d..b0f405a9f52e 100644
--- a/dlls/winhttp/net.c
+++ b/dlls/winhttp/net.c
@@ -672,11 +672,6 @@ void netconn_cancel_io( struct netconn *conn )
     closesocket( socket );
 }
 
-ULONG netconn_query_data_available( struct netconn *conn )
-{
-    return conn->secure ? conn->peek_len : 0;
-}
-
 DWORD netconn_set_timeout( struct netconn *netconn, BOOL send, int value )
 {
     int opt = send ? SO_SNDTIMEO : SO_RCVTIMEO;
diff --git a/dlls/winhttp/request.c b/dlls/winhttp/request.c
index 7ae05db92a50..54896eed72aa 100644
--- a/dlls/winhttp/request.c
+++ b/dlls/winhttp/request.c
@@ -35,7 +35,6 @@
 #include "schannel.h"
 #include "winhttp.h"
 #include "ntsecapi.h"
-#include "winternl.h"
 
 #include "wine/debug.h"
 #include "winhttp_private.h"
@@ -47,21 +46,40 @@ WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
 #define ACTUAL_DEFAULT_RECEIVE_RESPONSE_TIMEOUT 21000
 
 /* return the size of data available to be read immediately */
-static DWORD query_data_stream( struct request *request )
+static DWORD query_data_stream( struct request *request, DWORD *size )
 {
-    return request->data_stream->vtbl->query_data( request->data_stream, request );
+    DWORD ret = ERROR_SUCCESS;
+
+    if (!request->read.size)
+        ret = request->data_stream->vtbl->fill_buffer( request->data_stream, request, &request->read );
+
+    *size = request->read.size;
+    return ret;
 }
 
 static BOOL end_of_data_stream( struct request *request )
 {
-    return !request->read_size && request->data_stream->vtbl->end_of_data( request->data_stream, request );
+    return !request->read.size && request->data_stream->vtbl->end_of_data( request->data_stream, request );
 }
 
 static DWORD read_data_stream( struct request *request, char *buf, DWORD to_read, DWORD *read )
 {
-    DWORD ret = request->data_stream->vtbl->read_data( request->data_stream, request, buf, to_read, read );
-    if (ret) *read = 0;
-    request->content_read += *read;
+    DWORD ret = ERROR_SUCCESS, size = 0;
+
+    if (request->read.size < to_read)
+        ret = request->data_stream->vtbl->fill_buffer( request->data_stream, request, &request->read );
+    if (ret) return ret;
+
+    if (request->read.size)
+    {
+        size = min( to_read, request->read.size );
+        memcpy( buf, request->read.buf + request->read.pos, size );
+        request->read.size -= size;
+        request->read.pos += size;
+        request->content_read += size;
+    }
+
+    *read = size;
     return ret;
 }
 
@@ -79,64 +97,50 @@ static void reset_data_stream( struct request *request )
 {
     destroy_data_stream( request->data_stream );
     request->data_stream = &request->netconn_stream.data_stream;
-    request->read_pos = request->read_size = request->netconn_stream.content_read = 0;
-}
-
-static DWORD netconn_query_data( struct data_stream *stream, struct request *request )
-{
-    return request->read_size + netconn_query_data_available( request->netconn );
+    request->read.pos = request->read.size = 0;
 }
 
 static BOOL netconn_end_of_data( struct data_stream *stream, struct request *request )
 {
-    struct netconn_stream *netconn_stream = (struct netconn_stream *)stream;
-    return netconn_stream->content_read == netconn_stream->content_length || !netconn_is_valid( request->netconn );
+    return request->content_read == request->content_length || !netconn_is_valid( request->netconn );
 }
 
-static DWORD netconn_read_data( struct data_stream *stream, struct request *request, char *buf, DWORD to_read, DWORD *read )
+static DWORD netconn_fill_buffer( struct data_stream *stream, struct request *request, struct read_buffer *buf )
 {
-    struct netconn_stream *netconn_stream = (struct netconn_stream *)stream;
-    DWORD size = 0, ret = ERROR_SUCCESS;
-    int received = 0;
+    DWORD to_read, ret = ERROR_SUCCESS;
+    int received;
 
-    to_read = min( to_read, netconn_stream->content_length - netconn_stream->content_read );
+    if (netconn_end_of_data( stream, request )) return ERROR_SUCCESS;
 
-    if (request->read_size)
+    if (buf->pos)
     {
-        size = min( to_read, request->read_size );
-        memcpy( buf, request->read_buf + request->read_pos, size );
-        request->read_size -= size;
-        request->read_pos += size;
-        to_read -= size;
-        netconn_stream->content_read += size;
+        if (buf->size) memmove( buf->buf, buf->buf + buf->pos, buf->size );
+        buf->pos = 0;
     }
 
-    if (to_read && netconn_is_valid( request->netconn ))
+    to_read = sizeof(buf->buf) - buf->size;
+    to_read = min( to_read, request->content_length - request->content_read );
+
+    if (to_read > buf->size && netconn_is_valid( request->netconn ))
     {
-        if (!(ret = netconn_recv( request->netconn, buf, to_read, 0, &received )))
+        if (!(ret = netconn_recv( request->netconn, buf->buf + buf->size, to_read, 0, &received )))
         {
-            if (!received) netconn_stream->content_length = netconn_stream->content_read;
-            netconn_stream->content_read += received;
+            if (!received) request->content_length = request->content_read;
+            buf->size += received;
         }
     }
-
-    *read = size + received;
     return ret;
 }
 
 static DWORD netconn_drain_data( struct data_stream *stream, struct request *request )
 {
-    struct netconn_stream *netconn_stream = (struct netconn_stream *)stream;
-
-    while (netconn_stream->content_read < netconn_stream->content_length)
+    for (;;)
     {
-        DWORD ret, to_read, read;
-        char buf[1024];
-
-        to_read = min( sizeof(buf), netconn_stream->content_length - netconn_stream->content_read );
-        if ((ret = netconn_read_data( stream, request, buf, to_read, &read ))) return ret;
-        if (!read) return WSAECONNABORTED;
-        netconn_stream->content_read += read;
+        DWORD ret;
+        if ((ret = netconn_fill_buffer( stream, request, &request->read ))) return ret;
+        if (!request->read.size) break;
+        request->content_read += request->read.size;
+        request->read.size = request->read.pos = 0;
     }
     return ERROR_SUCCESS;
 }
@@ -147,9 +151,8 @@ static void netconn_destroy( struct data_stream *stream )
 
 const struct data_stream_vtbl netconn_stream_vtbl =
 {
-    netconn_query_data,
+    netconn_fill_buffer,
     netconn_end_of_data,
-    netconn_read_data,
     netconn_drain_data,
     netconn_destroy
 };
@@ -157,9 +160,7 @@ const struct data_stream_vtbl netconn_stream_vtbl =
 struct chunked_stream
 {
     struct data_stream data_stream;
-    char  buf[READ_BUFFER_SIZE];
-    DWORD buf_size;
-    DWORD buf_pos;
+    struct read_buffer buf;
     DWORD chunk_size;
     enum
     {
@@ -173,14 +174,6 @@ struct chunked_stream
     } state;
 };
 
-static DWORD chunked_query_data( struct data_stream *stream, struct request *request )
-{
-    struct chunked_stream *chunked_stream = (struct chunked_stream *)stream;
-
-    if (chunked_stream->state != CHUNKED_STREAM_STATE_READING_CHUNK ) return 0;
-    return min( chunked_stream->chunk_size, chunked_stream->buf_size - chunked_stream->buf_pos );
-}
-
 static BOOL chunked_end_of_data( struct data_stream *stream, struct request *request )
 {
     struct chunked_stream *chunked_stream = (struct chunked_stream *)stream;
@@ -198,25 +191,34 @@ static BOOL chunked_end_of_data( struct data_stream *stream, struct request *req
 
 static char next_chunked_data_char( struct chunked_stream *stream )
 {
-    assert( stream->buf_size );
-    stream->buf_size--;
-    return stream->buf[stream->buf_pos++];
+    assert( stream->buf.size );
+    stream->buf.size--;
+    return stream->buf.buf[stream->buf.pos++];
 }
 
-static DWORD chunked_read_data( struct data_stream *stream, struct request *request, char *buf, DWORD to_read, DWORD *read )
+static DWORD chunked_fill_buffer( struct data_stream *stream, struct request *request, struct read_buffer *buf )
 {
     struct chunked_stream *chunked_stream = (struct chunked_stream *)stream;
-    DWORD ret_read = 0, ret = ERROR_SUCCESS;
+    DWORD to_read, offset = 0, ret = ERROR_SUCCESS;
     BOOL continue_read = TRUE;
     int read_bytes;
     char ch;
 
+    if (chunked_end_of_data( stream, request )) return ERROR_SUCCESS;
+
+    if (buf->pos)
+    {
+        if (buf->size) memmove( buf->buf, buf->buf + buf->pos, buf->size );
+        buf->pos = 0;
+    }
+    to_read = sizeof(buf->buf) - buf->size;
+
     do
     {
         TRACE( "state %d\n", chunked_stream->state );
 
         /* ensure that we have data in the buffer for states that need it */
-        if (!chunked_stream->buf_size)
+        if (!chunked_stream->buf.size)
         {
             switch (chunked_stream->state)
             {
@@ -224,10 +226,11 @@ static DWORD chunked_read_data( struct data_stream *stream, struct request *requ
             case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_SIZE:
             case CHUNKED_STREAM_STATE_READING_CHUNK_SIZE:
             case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA:
-                chunked_stream->buf_pos = 0;
-                ret = netconn_recv( request->netconn, chunked_stream->buf, sizeof(chunked_stream->buf), 0, &read_bytes );
+                chunked_stream->buf.pos = 0;
+                ret = netconn_recv( request->netconn, chunked_stream->buf.buf, sizeof(chunked_stream->buf.buf), 0,
+                                    &read_bytes );
                 if (ret == ERROR_SUCCESS)
-                    chunked_stream->buf_size += read_bytes;
+                    chunked_stream->buf.size += read_bytes;
                 else
                     chunked_stream->state = CHUNKED_STREAM_STATE_ERROR;
                 break;
@@ -247,8 +250,8 @@ static DWORD chunked_read_data( struct data_stream *stream, struct request *requ
             else if (ch == ';' || ch == '\r' || ch == '\n')
             {
                 TRACE( "reading %lu byte chunk\n", chunked_stream->chunk_size );
-                chunked_stream->buf_size++;
-                chunked_stream->buf_pos--;
+                chunked_stream->buf.size++;
+                chunked_stream->buf.pos--;
                 if (request->content_length == ~0) request->content_length = chunked_stream->chunk_size;
                 else request->content_length += chunked_stream->chunk_size;
                 chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_SIZE;
@@ -276,17 +279,17 @@ static DWORD chunked_read_data( struct data_stream *stream, struct request *requ
             }
             read_bytes = min( to_read, chunked_stream->chunk_size );
 
-            if (chunked_stream->buf_size)
+            if (chunked_stream->buf.size)
             {
-                if (read_bytes > chunked_stream->buf_size) read_bytes = chunked_stream->buf_size;
+                if (read_bytes > chunked_stream->buf.size) read_bytes = chunked_stream->buf.size;
 
-                memcpy( buf + ret_read, chunked_stream->buf + chunked_stream->buf_pos, read_bytes );
-                chunked_stream->buf_pos += read_bytes;
-                chunked_stream->buf_size -= read_bytes;
+                memcpy( buf->buf + offset, chunked_stream->buf.buf + chunked_stream->buf.pos, read_bytes );
+                chunked_stream->buf.pos += read_bytes;
+                chunked_stream->buf.size -= read_bytes;
             }
             else
             {
-                ret = netconn_recv( request->netconn, buf + ret_read, read_bytes, 0, (int *)&read_bytes );
+                ret = netconn_recv( request->netconn, buf->buf + offset, read_bytes, 0, (int *)&read_bytes );
                 if (ret != ERROR_SUCCESS)
                 {
                     continue_read = FALSE;
@@ -300,8 +303,9 @@ static DWORD chunked_read_data( struct data_stream *stream, struct request *requ
             }
 
             chunked_stream->chunk_size -= read_bytes;
+            buf->size += read_bytes;
             to_read -= read_bytes;
-            ret_read += read_bytes;
+            offset += read_bytes;
             if (!chunked_stream->chunk_size) chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA;
             break;
 
@@ -324,26 +328,19 @@ static DWORD chunked_read_data( struct data_stream *stream, struct request *requ
         }
     } while (continue_read);
 
-    if (ret_read) ret = ERROR_SUCCESS;
-    if (ret != ERROR_SUCCESS) return ret;
-
-    *read = ret_read;
-    return ERROR_SUCCESS;
+    return ret;
 }
 
 static DWORD chunked_drain_data( struct data_stream *stream, struct request *request )
 {
-    struct chunked_stream *chunked_stream = (struct chunked_stream *)stream;
-    char buf[1024];
-    DWORD size, ret;
-
-    while (chunked_stream->state != CHUNKED_STREAM_STATE_END_OF_STREAM &&
-           chunked_stream->state != CHUNKED_STREAM_STATE_ERROR)
+    for (;;)
     {
-        if ((ret = chunked_read_data( stream, request, buf, sizeof(buf), &size ))) return ret;
+        DWORD ret;
+        if ((ret = chunked_fill_buffer( stream, request, &request->read ))) return ret;
+        if (!request->read.size) break;
+        request->content_read += request->read.size;
+        request->read.size = request->read.pos = 0;
     }
-
-    if (chunked_stream->state != CHUNKED_STREAM_STATE_END_OF_STREAM) return ERROR_NO_DATA;
     return ERROR_SUCCESS;
 }
 
@@ -355,9 +352,8 @@ static void chunked_destroy( struct data_stream *stream )
 
 const struct data_stream_vtbl chunked_stream_vtbl =
 {
-    chunked_query_data,
+    chunked_fill_buffer,
     chunked_end_of_data,
-    chunked_read_data,
     chunked_drain_data,
     chunked_destroy
 };
@@ -365,68 +361,66 @@ const struct data_stream_vtbl chunked_stream_vtbl =
 struct gzip_stream
 {
     struct data_stream data_stream;
-    struct data_stream *parent_stream;
+    struct data_stream *parent;
     z_stream zstream;
-    BYTE buf[READ_BUFFER_SIZE];
-    DWORD buf_size;
-    DWORD buf_pos;
+    struct read_buffer buf;
     BOOL end_of_data;
 };
 
-static DWORD gzip_query_data( struct data_stream *stream, struct request *request )
-{
-    struct gzip_stream *gzip_stream = (struct gzip_stream *)stream;
-    return gzip_stream->buf_size;
-}
-
 static BOOL gzip_end_of_data( struct data_stream *stream, struct request *request )
 {
     struct gzip_stream *gzip_stream = (struct gzip_stream *)stream;
     return gzip_stream->end_of_data ||
-           (!gzip_stream->buf_size && gzip_stream->parent_stream->vtbl->end_of_data( gzip_stream->parent_stream, request ));
+           (!gzip_stream->buf.size && gzip_stream->parent->vtbl->end_of_data( gzip_stream->parent, request ));
 }
 
-static DWORD gzip_read( struct data_stream *stream, struct request *request, char *buf, DWORD to_read, DWORD *read )
+static DWORD gzip_fill_buffer( struct data_stream *stream, struct request *request, struct read_buffer *buf )
 {
     struct gzip_stream *gzip_stream = (struct gzip_stream *)stream;
     z_stream *zstream = &gzip_stream->zstream;
-    DWORD size, ret_read = 0;
+    DWORD size, to_read, offset = 0, ret = ERROR_SUCCESS;
     int zres;
-    DWORD ret = ERROR_SUCCESS;
+
+    if (gzip_end_of_data( stream, request )) return ERROR_SUCCESS;
+
+    if (buf->pos)
+    {
+        if (buf->size) memmove( buf->buf, buf->buf + buf->pos, buf->size );
+        buf->pos = 0;
+    }
+    to_read = sizeof(buf->buf) - buf->size;
 
     while (to_read && !gzip_stream->end_of_data)
     {
-        if (!gzip_stream->buf_size)
+        if (!gzip_stream->buf.size)
         {
-            if (gzip_stream->buf_pos)
+            if (gzip_stream->buf.pos)
             {
-                if (gzip_stream->buf_size)
-                    memmove( gzip_stream->buf, gzip_stream->buf + gzip_stream->buf_pos, gzip_stream->buf_size );
-                gzip_stream->buf_pos = 0;
+                if (gzip_stream->buf.size)
+                    memmove( gzip_stream->buf.buf, gzip_stream->buf.buf + gzip_stream->buf.pos, gzip_stream->buf.size );
+                gzip_stream->buf.pos = 0;
             }
-            ret = gzip_stream->parent_stream->vtbl->read_data( gzip_stream->parent_stream, request,
-                                                               (char *)gzip_stream->buf + gzip_stream->buf_size,
-                                                               sizeof(gzip_stream->buf) - gzip_stream->buf_size, &size );
-            if (ret) break;
-            gzip_stream->buf_size += size;
-            if (!size)
+            if ((ret = gzip_stream->parent->vtbl->fill_buffer( gzip_stream->parent, request, &gzip_stream->buf )))
+                return ret;
+            if (!gzip_stream->buf.size)
             {
                 WARN( "unexpected end of data\n" );
                 gzip_stream->end_of_data = TRUE;
-                break;
+                return ERROR_NO_DATA;
             }
         }
 
-        zstream->next_in = gzip_stream->buf + gzip_stream->buf_pos;
-        zstream->avail_in = gzip_stream->buf_size;
-        zstream->next_out = (Bytef *)buf + ret_read;
+        zstream->next_in = gzip_stream->buf.buf + gzip_stream->buf.pos;
+        zstream->avail_in = gzip_stream->buf.size;
+        zstream->next_out = (Bytef *)buf->buf + offset;
         zstream->avail_out = to_read;
         zres = inflate( &gzip_stream->zstream, 0 );
         size = to_read - zstream->avail_out;
+        buf->size += size;
         to_read -= size;
-        ret_read += size;
-        gzip_stream->buf_size -= zstream->next_in - (gzip_stream->buf + gzip_stream->buf_pos);
-        gzip_stream->buf_pos = zstream->next_in - gzip_stream->buf;
+        offset += size;
+        gzip_stream->buf.size -= zstream->next_in - (gzip_stream->buf.buf + gzip_stream->buf.pos);
+        gzip_stream->buf.pos = zstream->next_in - gzip_stream->buf.buf;
         if (zres == Z_STREAM_END)
         {
             TRACE( "end of data\n" );
@@ -436,36 +430,33 @@ static DWORD gzip_read( struct data_stream *stream, struct request *request, cha
         else if (zres != Z_OK)
         {
             WARN( "inflate failed %d: %s\n", zres, debugstr_a(zstream->msg) );
-            if (!ret_read) ret = ERROR_NO_DATA;
+            if (!offset) ret = ERROR_NO_DATA;
             break;
         }
     }
 
-    if (ret_read) ret = ERROR_SUCCESS;
-    *read = ret_read;
     return ret;
 }
 
-static DWORD gzip_drain_content( struct data_stream *stream, struct request *request )
+static DWORD gzip_drain_data( struct data_stream *stream, struct request *request )
 {
     struct gzip_stream *gzip_stream = (struct gzip_stream *)stream;
-    return gzip_stream->parent_stream->vtbl->drain_data( gzip_stream->parent_stream, request );
+    return gzip_stream->parent->vtbl->drain_data( gzip_stream->parent, request );
 }
 
 static void gzip_destroy( struct data_stream *stream )
 {
     struct gzip_stream *gzip_stream = (struct gzip_stream *)stream;
-    destroy_data_stream( gzip_stream->parent_stream );
+    destroy_data_stream( gzip_stream->parent );
     if (!gzip_stream->end_of_data) inflateEnd( &gzip_stream->zstream );
     free( gzip_stream );
 }
 
 static const struct data_stream_vtbl gzip_stream_vtbl =
 {
-    gzip_query_data,
+    gzip_fill_buffer,
     gzip_end_of_data,
-    gzip_read,
-    gzip_drain_content,
+    gzip_drain_data,
     gzip_destroy
 };
 
@@ -479,37 +470,6 @@ static void gzip_zfree( voidpf opaque, voidpf address )
     free( address );
 }
 
-static DWORD init_gzip_stream( struct request *request, BOOL is_gzip )
-{
-    struct gzip_stream *gzip_stream;
-    int zres;
-
-    if (!(gzip_stream = calloc( 1, sizeof(*gzip_stream) ))) return ERROR_OUTOFMEMORY;
-
-    gzip_stream->data_stream.vtbl = &gzip_stream_vtbl;
-    gzip_stream->zstream.zalloc = gzip_zalloc;
-    gzip_stream->zstream.zfree = gzip_zfree;
-
-    zres = inflateInit2( &gzip_stream->zstream, is_gzip ? 31 : -15 );
-    if (zres != Z_OK)
-    {
-        ERR( "inflateInit failed: %d\n", zres );
-        free( gzip_stream );
-        return ERROR_OUTOFMEMORY;
-    }
-
-    if (request->read_size)
-    {
-        memcpy( gzip_stream->buf, request->read_buf + request->read_pos, request->read_size );
-        gzip_stream->buf_size = request->read_size;
-        request->read_pos = request->read_size = 0;
-    }
-
-    gzip_stream->parent_stream = request->data_stream;
-    request->data_stream = &gzip_stream->data_stream;
-    return ERROR_SUCCESS;
-}
-
 static int request_receive_response_timeout( struct request *req )
 {
     if (req->receive_response_timeout == -1) return ACTUAL_DEFAULT_RECEIVE_RESPONSE_TIMEOUT;
@@ -665,8 +625,7 @@ static void CALLBACK task_callback( TP_CALLBACK_INSTANCE *instance, void *ctx )
     TRACE( "instance %p exiting.\n", instance );
 }
 
-static DWORD queue_task( struct queue *queue, TASK_CALLBACK task, struct task_header *task_hdr,
-                         struct object_header *obj )
+DWORD queue_task( struct queue *queue, TASK_CALLBACK task, struct task_header *task_hdr, struct object_header *obj )
 {
     BOOL callback_running;
 
@@ -698,12 +657,12 @@ static DWORD queue_task( struct queue *queue, TASK_CALLBACK task, struct task_he
     return ERROR_SUCCESS;
 }
 
-static BOOL task_needs_completion( struct task_header *task_hdr )
+BOOL task_needs_completion( struct task_header *task_hdr )
 {
     return !InterlockedExchange( &task_hdr->completion_sent, 1 );
 }
 
-static BOOL cancel_queue( struct queue *queue )
+BOOL cancel_queue( struct queue *queue )
 {
     struct task_header *task_hdr, *found;
     BOOL cancelled = FALSE;
@@ -2277,62 +2236,6 @@ static void finished_reading( struct request *request )
     request->netconn = NULL;
 }
 
-/* read some more data into the read buffer */
-static DWORD read_more_data( struct request *request, int max_len, BOOL notify )
-{
-    int len;
-    DWORD ret;
-
-    if (request->read_pos)
-    {
-        if (request->read_size) memmove( request->read_buf, request->read_buf + request->read_pos, request->read_size );
-        request->read_pos = 0;
-    }
-    if (max_len == -1) max_len = sizeof(request->read_buf);
-
-    if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 );
-
-    ret = netconn_recv( request->netconn, request->read_buf + request->read_size, max_len - request->read_size, 0, &len );
-
-    if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) );
-
-    request->read_reply_len += len;
-    request->read_size += len;
-    return ret;
-}
-
-static DWORD refill_buffer( struct request *request, BOOL notify )
-{
-    DWORD ret;
-    if ((ret = read_more_data( request, -1, notify ))) return ret;
-    if (!request->read_size) request->content_length = request->content_read = 0;
-    return ERROR_SUCCESS;
-}
-
-static DWORD read_data( struct request *request, void *buffer, DWORD size, DWORD *read, BOOL async )
-{
-    DWORD bytes_read = 0, ret;
-
-    ret = read_data_stream( request, buffer, size, &bytes_read );
-
-    TRACE( "retrieved %lu bytes (%I64u/%I64u)\n", bytes_read, request->content_read, request->content_length );
-    if (end_of_data_stream( request )) finished_reading( request );
-    if (async)
-    {
-        if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read );
-        else
-        {
-            WINHTTP_ASYNC_RESULT result;
-            result.dwResult = API_READ_DATA;
-            result.dwError  = ret;
-            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
-        }
-    }
-
-    if (!ret && read) *read = bytes_read;
-    return ret;
-}
-
 enum escape_flags
 {
     ESCAPE_FLAG_NON_PRINTABLE = 0x01,
@@ -2848,6 +2751,40 @@ static DWORD handle_authorization( struct request *request, DWORD status )
     return ERROR_WINHTTP_LOGIN_FAILURE;
 }
 
+static DWORD init_gzip_stream( struct request *request, BOOL is_gzip )
+{
+    struct gzip_stream *gzip_stream;
+    int zres;
+
+    if (!(gzip_stream = calloc( 1, sizeof(*gzip_stream) ))) return ERROR_OUTOFMEMORY;
+
+    gzip_stream->data_stream.vtbl = &gzip_stream_vtbl;
+    gzip_stream->zstream.zalloc = gzip_zalloc;
+    gzip_stream->zstream.zfree = gzip_zfree;
+
+    zres = inflateInit2( &gzip_stream->zstream, is_gzip ? 31 : 15 );
+    if (zres != Z_OK)
+    {
+        ERR( "inflateInit failed: %d\n", zres );
+        free( gzip_stream );
+        return ERROR_OUTOFMEMORY;
+    }
+
+    if (request->read.size)
+    {
+        memcpy( gzip_stream->buf.buf, request->read.buf + request->read.pos, request->read.size );
+        gzip_stream->buf.size = request->read.size;
+        request->read.pos = request->read.size = 0;
+    }
+
+    gzip_stream->parent = request->data_stream;
+    request->data_stream = &gzip_stream->data_stream;
+
+    remove_header( request, L"Content-Length", FALSE );
+    request->content_length = ~0ull;
+    return ERROR_SUCCESS;
+}
+
 /* set the request content length based on the headers */
 static DWORD set_content_length( struct request *request, DWORD status )
 {
@@ -2862,13 +2799,10 @@ static DWORD set_content_length( struct request *request, DWORD status )
     else
     {
         if (query_headers( request, WINHTTP_QUERY_CONTENT_LENGTH, NULL, buf, &buflen, NULL ))
-            request->content_length = request->netconn_stream.content_length = ~0ull;
+            request->content_length = ~0ull;
         else
             request->content_length = wcstoull( buf, NULL, 10 );
 
-        request->netconn_stream.content_length = request->content_length;
-        request->netconn_stream.content_read = 0;
-
         buflen = sizeof(buf);
         if (!query_headers( request, WINHTTP_QUERY_TRANSFER_ENCODING, NULL, buf, &buflen, NULL ) &&
             !wcsicmp( buf, L"chunked" ))
@@ -2878,30 +2812,28 @@ static DWORD set_content_length( struct request *request, DWORD status )
             if (!(chunked_stream = malloc( sizeof(*chunked_stream) ))) return ERROR_OUTOFMEMORY;
 
             chunked_stream->data_stream.vtbl = &chunked_stream_vtbl;
-            chunked_stream->buf_size = chunked_stream->buf_pos = 0;
+            chunked_stream->buf.size = chunked_stream->buf.pos = 0;
             chunked_stream->chunk_size = 0;
             chunked_stream->state = CHUNKED_STREAM_STATE_READING_CHUNK_SIZE;
 
-            if (request->read_size)
+            if (request->read.size)
             {
-                memcpy( chunked_stream->buf, request->read_buf + request->read_pos, request->read_size );
-                chunked_stream->buf_size = request->read_size;
-                request->read_size = request->read_pos = 0;
+                memcpy( chunked_stream->buf.buf, request->read.buf + request->read.pos, request->read.size );
+                chunked_stream->buf.size = request->read.size;
+                request->read.size = request->read.pos = 0;
             }
             request->data_stream = &chunked_stream->data_stream;
             request->content_length = ~0ull;
         }
 
-        buflen = sizeof(buf);
-        if (!query_headers( request, WINHTTP_QUERY_CONTENT_ENCODING, NULL, buf, &buflen, NULL ))
+        if (request->hdr.decompression)
         {
-            if (!wcsicmp( buf, L"gzip" )) ret = init_gzip_stream( request, TRUE );
-            else if (!wcsicmp( buf, L"deflate" )) ret = init_gzip_stream( request, FALSE );
-            else ret = ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
-            if (!ret)
+            buflen = sizeof(buf);
+            if (!query_headers( request, WINHTTP_QUERY_CONTENT_ENCODING, NULL, buf, &buflen, NULL ))
             {
-                remove_header( request, L"Content-Length", FALSE );
-                request->content_length = ~0ull;
+                if (!wcsicmp( buf, L"gzip" )) ret = init_gzip_stream( request, TRUE );
+                else if (!wcsicmp( buf, L"deflate" )) ret = init_gzip_stream( request, FALSE );
+                else WARN( "unexpected content encoding %s\n", debugstr_w(buf) );
             }
         }
     }
@@ -2912,8 +2844,32 @@ static DWORD set_content_length( struct request *request, DWORD status )
 /* remove some amount of data from the read buffer */
 static void remove_data( struct request *request, int count )
 {
-    if (!(request->read_size -= count)) request->read_pos = 0;
-    else request->read_pos += count;
+    if (!(request->read.size -= count)) request->read.pos = 0;
+    else request->read.pos += count;
+}
+
+/* read some more data into the read buffer */
+static DWORD read_more_data( struct request *request, int max_len, BOOL notify )
+{
+    int len;
+    DWORD ret;
+
+    if (request->read.pos)
+    {
+        if (request->read.size) memmove( request->read.buf, request->read.buf + request->read.pos, request->read.size );
+        request->read.pos = 0;
+    }
+    if (max_len == -1) max_len = sizeof(request->read.buf);
+
+    if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE, NULL, 0 );
+
+    ret = netconn_recv( request->netconn, request->read.buf + request->read.size, max_len - request->read.size, 0, &len );
+
+    if (notify) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED, &len, sizeof(len) );
+
+    request->read_reply_len += len;
+    request->read.size += len;
+    return ret;
 }
 
 static DWORD read_line( struct request *request, char *buffer, DWORD *len )
@@ -2923,22 +2879,22 @@ static DWORD read_line( struct request *request, char *buffer, DWORD *len )
 
     for (;;)
     {
-        char *eol = memchr( request->read_buf + request->read_pos, '\n', request->read_size );
+        char *eol = memchr( request->read.buf + request->read.pos, '\n', request->read.size );
         if (eol)
         {
-            count = eol - (request->read_buf + request->read_pos);
+            count = eol - (char *)(request->read.buf + request->read.pos);
             bytes_read = count + 1;
         }
-        else count = bytes_read = request->read_size;
+        else count = bytes_read = request->read.size;
 
         count = min( count, *len - pos );
-        memcpy( buffer + pos, request->read_buf + request->read_pos, count );
+        memcpy( buffer + pos, request->read.buf + request->read.pos, count );
         pos += count;
         remove_data( request, bytes_read );
         if (eol) break;
 
         if ((ret = read_more_data( request, -1, FALSE ))) return ret;
-        if (!request->read_size)
+        if (!request->read.size)
         {
             *len = 0;
             TRACE("returning empty string\n");
@@ -3432,7 +3388,7 @@ BOOL WINAPI WinHttpReceiveResponse( HINTERNET hrequest, LPVOID reserved )
 static BOOL skip_async_queue( struct request *request, BOOL *wont_block, DWORD to_read )
 {
     to_read = min( to_read, request->content_length - request->content_read );
-    *wont_block = end_of_data_stream( request ) || query_data_stream( request ) >= to_read;
+    *wont_block = end_of_data_stream( request ) || request->read.size >= to_read;
     return request->hdr.recursion_count < 3 && *wont_block;
 }
 
@@ -3442,11 +3398,7 @@ static DWORD query_data_available( struct request *request, DWORD *available, BO
 
     if (!request->content_length || end_of_data_stream( request )) goto done;
 
-    if (!(count = query_data_stream( request )))
-    {
-        if ((ret = refill_buffer( request, async ))) goto done;
-        count = query_data_stream( request );
-    }
+    ret = query_data_stream( request, &count );
 
 done:
     TRACE( "%lu bytes available\n", count );
@@ -3568,6 +3520,30 @@ BOOL WINAPI WinHttpQueryDataAvailable( HINTERNET hrequest, LPDWORD available )
     return !ret || ret == ERROR_IO_PENDING;
 }
 
+static DWORD read_data( struct request *request, void *buffer, DWORD size, DWORD *read, BOOL async )
+{
+    DWORD bytes_read = 0, ret;
+
+    ret = read_data_stream( request, buffer, size, &bytes_read );
+
+    TRACE( "%lu bytes read\n", bytes_read );
+    if (end_of_data_stream( request )) finished_reading( request );
+    if (async)
+    {
+        if (!ret) send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, buffer, bytes_read );
+        else
+        {
+            WINHTTP_ASYNC_RESULT result;
+            result.dwResult = API_READ_DATA;
+            result.dwError  = ret;
+            send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+        }
+    }
+
+    if (!ret && read) *read = bytes_read;
+    return ret;
+}
+
 static void task_read_data( void *ctx, BOOL abort )
 {
     struct read_data *r = ctx;
@@ -3744,1189 +3720,6 @@ BOOL WINAPI WinHttpWriteData( HINTERNET hrequest, const void *buffer, DWORD to_w
     return !ret;
 }
 
-static void socket_handle_closing( struct object_header *hdr )
-{
-    struct socket *socket = (struct socket *)hdr;
-    BOOL pending_tasks;
-
-    pending_tasks = cancel_queue( &socket->send_q );
-    pending_tasks = cancel_queue( &socket->recv_q ) || pending_tasks;
-
-    if (pending_tasks)
-        netconn_cancel_io( socket->netconn );
-}
-
-static BOOL socket_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
-{
-    switch (option)
-    {
-        case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL:
-            SetLastError( ERROR_INVALID_PARAMETER );
-            return FALSE;
-    }
-
-    FIXME( "unimplemented option %lu\n", option );
-    SetLastError( ERROR_WINHTTP_INVALID_OPTION );
-    return FALSE;
-}
-
-static void socket_destroy( struct object_header *hdr )
-{
-    struct socket *socket = (struct socket *)hdr;
-
-    TRACE("%p\n", socket);
-
-    stop_queue( &socket->send_q );
-    stop_queue( &socket->recv_q );
-
-    netconn_release( socket->netconn );
-    free( socket->read_buffer );
-    free( socket->send_frame_buffer );
-    free( socket );
-}
-
-static BOOL socket_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
-{
-    struct socket *socket = (struct socket *)hdr;
-
-    switch (option)
-    {
-    case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL:
-    {
-        DWORD interval;
-
-        if (buflen != sizeof(DWORD) || (interval = *(DWORD *)buffer) < 15000)
-        {
-            WARN( "Invalid parameters for WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL.\n" );
-            SetLastError( ERROR_INVALID_PARAMETER );
-            return FALSE;
-        }
-        socket->keepalive_interval = interval;
-        netconn_set_timeout( socket->netconn, FALSE, socket->keepalive_interval );
-        SetLastError( ERROR_SUCCESS );
-        TRACE( "WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL %lu.\n", interval);
-        return TRUE;
-    }
-    }
-
-    FIXME( "unimplemented option %lu\n", option );
-    SetLastError( ERROR_WINHTTP_INVALID_OPTION );
-    return FALSE;
-}
-
-static const struct object_vtbl socket_vtbl =
-{
-    socket_handle_closing,
-    socket_destroy,
-    socket_query_option,
-    socket_set_option,
-};
-
-HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR context )
-{
-    struct socket *socket;
-    struct request *request;
-    HINTERNET hsocket = NULL;
-
-    TRACE( "%p, %Ix\n", hrequest, context );
-
-    if (!(request = (struct request *)grab_object( hrequest )))
-    {
-        SetLastError( ERROR_INVALID_HANDLE );
-        return NULL;
-    }
-    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
-    {
-        release_object( &request->hdr );
-        SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
-        return NULL;
-    }
-    if (!(socket = calloc( 1, sizeof(*socket) )))
-    {
-        release_object( &request->hdr );
-        return NULL;
-    }
-    socket->hdr.type = WINHTTP_HANDLE_TYPE_SOCKET;
-    socket->hdr.vtbl = &socket_vtbl;
-    socket->hdr.refs = 1;
-    socket->hdr.callback = request->hdr.callback;
-    socket->hdr.notify_mask = request->hdr.notify_mask;
-    socket->hdr.context = context;
-    socket->hdr.flags = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC;
-    socket->keepalive_interval = 30000;
-    socket->send_buffer_size = request->websocket_send_buffer_size;
-    if (request->read_size)
-    {
-        if (!(socket->read_buffer = malloc( request->read_size )))
-        {
-            ERR( "No memory.\n" );
-            free( socket );
-            release_object( &request->hdr );
-            return NULL;
-        }
-        socket->bytes_in_read_buffer = request->read_size;
-        memcpy( socket->read_buffer, request->read_buf + request->read_pos, request->read_size );
-        request->read_pos = request->read_size = 0;
-    }
-    InitializeSRWLock( &socket->send_lock );
-    init_queue( &socket->send_q );
-    init_queue( &socket->recv_q );
-    netconn_addref( request->netconn );
-    socket->netconn = request->netconn;
-
-    netconn_set_timeout( socket->netconn, FALSE, socket->keepalive_interval );
-
-    if ((hsocket = alloc_handle( &socket->hdr )))
-    {
-        send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hsocket, sizeof(hsocket) );
-    }
-
-    release_object( &socket->hdr );
-    release_object( &request->hdr );
-    TRACE("returning %p\n", hsocket);
-    if (hsocket) SetLastError( ERROR_SUCCESS );
-    return hsocket;
-}
-
-static DWORD send_bytes( struct socket *socket, char *bytes, int len, int *sent, WSAOVERLAPPED *ovr )
-{
-    int count;
-    DWORD err;
-    err = netconn_send( socket->netconn, bytes, len, &count, ovr );
-    if (sent) *sent = count;
-    if (err) return err;
-    return (count == len || (ovr && count)) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
-}
-
-#define FIN_BIT (1 << 7)
-#define MASK_BIT (1 << 7)
-#define RESERVED_BIT (7 << 4)
-#define CONTROL_BIT (1 << 3)
-
-static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf,
-                         DWORD buflen, BOOL final, WSAOVERLAPPED *ovr )
-{
-    DWORD i, offset = 2, len = buflen, buffer_size, ret = 0;
-    int sent_size;
-    char hdr[14];
-    char *ptr;
-
-    TRACE( "sending %02x frame, len %lu\n", opcode, len );
-
-    if (opcode == SOCKET_OPCODE_CLOSE) len += sizeof(status);
-
-    hdr[0] = final ? (char)FIN_BIT : 0;
-    hdr[0] |= opcode;
-    hdr[1] = (char)MASK_BIT;
-    if (len < 126) hdr[1] |= len;
-    else if (len < 65536)
-    {
-        hdr[1] |= 126;
-        hdr[2] = len >> 8;
-        hdr[3] = len & 0xff;
-        offset += 2;
-    }
-    else
-    {
-        hdr[1] |= 127;
-        hdr[2] = hdr[3] = hdr[4] = hdr[5] = 0;
-        hdr[6] = len >> 24;
-        hdr[7] = (len >> 16) & 0xff;
-        hdr[8] = (len >> 8) & 0xff;
-        hdr[9] = len & 0xff;
-        offset += 8;
-    }
-
-    buffer_size = len + offset + 4;
-    assert( buffer_size - len < socket->send_buffer_size );
-    if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < socket->send_buffer_size)
-    {
-        DWORD new_size;
-        void *new;
-
-        new_size = min( buffer_size, socket->send_buffer_size );
-        if (!(new = realloc( socket->send_frame_buffer, new_size )))
-        {
-            ERR( "out of memory, buffer_size %lu\n", buffer_size);
-            return ERROR_OUTOFMEMORY;
-        }
-        socket->send_frame_buffer = new;
-        socket->send_frame_buffer_size = new_size;
-    }
-    ptr = socket->send_frame_buffer;
-
-    memcpy(ptr, hdr, offset);
-    ptr += offset;
-
-    RtlGenRandom( socket->mask, 4 );
-    memcpy( ptr, socket->mask, 4 );
-    ptr += 4;
-    socket->mask_index = 0;
-
-    if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */
-    {
-        *ptr++ = (status >> 8) ^ socket->mask[socket->mask_index++ % 4];
-        *ptr++ = (status & 0xff) ^ socket->mask[socket->mask_index++ % 4];
-    }
-
-    offset = ptr - socket->send_frame_buffer;
-    socket->send_remaining_size = offset + buflen;
-    socket->client_buffer_offset = 0;
-    while (socket->send_remaining_size)
-    {
-        len = min( buflen, socket->send_buffer_size - offset );
-        for (i = 0; i < len; ++i)
-        {
-            socket->send_frame_buffer[offset++] = buf[socket->client_buffer_offset++]
-                                                  ^ socket->mask[socket->mask_index++ % 4];
-        }
-
-        sent_size = 0;
-        ret = send_bytes( socket, socket->send_frame_buffer, offset, &sent_size, ovr );
-        socket->send_remaining_size -= sent_size;
-        if (ret)
-        {
-            if (ovr && ret == WSA_IO_PENDING)
-            {
-                memmove( socket->send_frame_buffer, socket->send_frame_buffer + sent_size, offset - sent_size );
-                socket->bytes_in_send_frame_buffer = offset - sent_size;
-            }
-            return ret;
-        }
-        assert( sent_size == offset );
-        offset = 0;
-        buflen -= len;
-    }
-    return ERROR_SUCCESS;
-}
-
-static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf )
-{
-    DWORD ret, len, i;
-
-    if (!netconn_wait_overlapped_result( socket->netconn, ovr, &len ))
-        return WSAGetLastError();
-
-    if (socket->bytes_in_send_frame_buffer)
-    {
-        ret = send_bytes( socket, socket->send_frame_buffer, socket->bytes_in_send_frame_buffer, NULL, NULL );
-        if (ret) return ret;
-    }
-
-    assert( socket->bytes_in_send_frame_buffer <= socket->send_remaining_size );
-    socket->send_remaining_size -= socket->bytes_in_send_frame_buffer;
-
-    while (socket->send_remaining_size)
-    {
-        len = min( socket->send_remaining_size, socket->send_buffer_size );
-        for (i = 0; i < len; ++i)
-        {
-            socket->send_frame_buffer[i] = buf[socket->client_buffer_offset++]
-                                           ^ socket->mask[socket->mask_index++ % 4];
-        }
-        ret = send_bytes( socket, socket->send_frame_buffer, len, NULL, NULL );
-        if (ret) return ret;
-        socket->send_remaining_size -= len;
-    }
-    return ERROR_SUCCESS;
-}
-
-static void send_io_complete( struct object_header *hdr )
-{
-    LONG count = InterlockedDecrement( &hdr->pending_sends );
-    assert( count >= 0 );
-}
-
-/* returns FALSE if sending callback should be omitted. */
-static void receive_io_complete( struct socket *socket )
-{
-    LONG count = InterlockedDecrement( &socket->hdr.pending_receives );
-    assert( count >= 0 );
-}
-
-static BOOL socket_can_send( struct socket *socket )
-{
-    return socket->state == SOCKET_STATE_OPEN && !socket->close_frame_received;
-}
-
-static BOOL socket_can_receive( struct socket *socket )
-{
-    return socket->state <= SOCKET_STATE_SHUTDOWN && !socket->close_frame_received;
-}
-
-static BOOL validate_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type, enum fragment_type current_fragment )
-{
-    switch (current_fragment)
-    {
-        case SOCKET_FRAGMENT_NONE:
-            return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE
-                   || type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE
-                   || type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE
-                   || type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
-        case SOCKET_FRAGMENT_BINARY:
-            return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE
-                   || type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
-        case SOCKET_FRAGMENT_UTF8:
-            return type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE
-                   || type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
-    }
-    assert( 0 );
-    return FALSE;
-}
-
-static enum socket_opcode map_buffer_type( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type )
-{
-    switch (type)
-    {
-    case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
-        if (socket->sending_fragment_type)
-        {
-            socket->sending_fragment_type = SOCKET_FRAGMENT_NONE;
-            return SOCKET_OPCODE_CONTINUE;
-        }
-        return SOCKET_OPCODE_TEXT;
-
-    case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE:
-        if (socket->sending_fragment_type)
-        {
-            socket->sending_fragment_type = SOCKET_FRAGMENT_NONE;
-            return SOCKET_OPCODE_CONTINUE;
-        }
-        return SOCKET_OPCODE_BINARY;
-
-    case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
-        if (!socket->sending_fragment_type)
-        {
-            socket->sending_fragment_type = SOCKET_FRAGMENT_UTF8;
-            return SOCKET_OPCODE_TEXT;
-        }
-        return SOCKET_OPCODE_CONTINUE;
-
-    case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE:
-        if (!socket->sending_fragment_type)
-        {
-            socket->sending_fragment_type = SOCKET_FRAGMENT_BINARY;
-            return SOCKET_OPCODE_BINARY;
-        }
-        return SOCKET_OPCODE_CONTINUE;
-
-    case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
-        return SOCKET_OPCODE_CLOSE;
-
-    default:
-        FIXME("buffer type %u not supported\n", type);
-        return SOCKET_OPCODE_INVALID;
-    }
-}
-
-static void socket_send_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, DWORD len )
-{
-    if (!ret)
-    {
-        WINHTTP_WEB_SOCKET_STATUS status;
-        status.dwBytesTransferred = len;
-        status.eBufferType        = type;
-        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &status, sizeof(status) );
-    }
-    else
-    {
-        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
-        result.AsyncResult.dwResult = API_WRITE_DATA;
-        result.AsyncResult.dwError  = ret;
-        result.Operation = WINHTTP_WEB_SOCKET_SEND_OPERATION;
-        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
-    }
-}
-
-static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len,
-                          WSAOVERLAPPED *ovr )
-{
-    enum socket_opcode opcode = map_buffer_type( socket, type );
-    BOOL final = (type != WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE &&
-                  type != WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE);
-
-    return send_frame( socket, opcode, 0, buf, len, final, ovr );
-}
-
-static void task_socket_send( void *ctx, BOOL abort )
-{
-    struct socket_send *s = ctx;
-    struct socket *socket = (struct socket *)s->task_hdr.obj;
-    DWORD ret;
-
-    if (abort) return;
-
-    TRACE("running %p\n", ctx);
-
-    if (s->complete_async) ret = complete_send_frame( socket, &s->ovr, s->buf );
-    else                   ret = socket_send( socket, s->type, s->buf, s->len, NULL );
-
-    send_io_complete( &socket->hdr );
-    InterlockedExchange( &socket->pending_noncontrol_send, 0 );
-    socket_send_complete( socket, ret, s->type, s->len );
-}
-
-DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len )
-{
-    struct socket *socket;
-    DWORD ret = 0;
-
-    TRACE( "%p, %u, %p, %lu\n", hsocket, type, buf, len );
-
-    if (len && !buf) return ERROR_INVALID_PARAMETER;
-
-    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
-    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET)
-    {
-        release_object( &socket->hdr );
-        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
-    }
-    if (!socket_can_send( socket ))
-    {
-        release_object( &socket->hdr );
-        return ERROR_INVALID_OPERATION;
-    }
-
-    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-    {
-        BOOL async_send, complete_async = FALSE;
-        struct socket_send *s;
-
-        if (InterlockedCompareExchange( &socket->pending_noncontrol_send, 1, 0 ))
-        {
-            WARN( "Previous send is still queued.\n" );
-            release_object( &socket->hdr );
-            return ERROR_INVALID_OPERATION;
-        }
-        if (!validate_buffer_type( type, socket->sending_fragment_type ))
-        {
-            WARN( "Invalid buffer type %u, sending_fragment_type %u.\n", type, socket->sending_fragment_type );
-            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
-            release_object( &socket->hdr );
-            return ERROR_INVALID_PARAMETER;
-        }
-
-        if (!(s = malloc( sizeof(*s) )))
-        {
-            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
-            release_object( &socket->hdr );
-            return ERROR_OUTOFMEMORY;
-        }
-
-        AcquireSRWLockExclusive( &socket->send_lock );
-        async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1 || socket->hdr.recursion_count >= 3;
-        if (!async_send)
-        {
-            memset( &s->ovr, 0, sizeof(s->ovr) );
-            if ((ret = socket_send( socket, type, buf, len, &s->ovr )) == WSA_IO_PENDING)
-            {
-                async_send = TRUE;
-                complete_async = TRUE;
-            }
-        }
-
-        if (async_send)
-        {
-            s->complete_async = complete_async;
-            TRACE("queueing, complete_async %#x.\n", complete_async);
-            s->type   = type;
-            s->buf    = buf;
-            s->len    = len;
-
-            if ((ret = queue_task( &socket->send_q, task_socket_send, &s->task_hdr, &socket->hdr )))
-                free( s );
-        }
-        if (!async_send || ret)
-        {
-            InterlockedDecrement( &socket->hdr.pending_sends );
-            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
-        }
-        ReleaseSRWLockExclusive( &socket->send_lock );
-        if (!async_send)
-        {
-            TRACE("sent sync.\n");
-            free( s );
-            socket_send_complete( socket, ret, type, len );
-            ret = ERROR_SUCCESS;
-        }
-    }
-    else
-    {
-        if (validate_buffer_type( type, socket->sending_fragment_type ))
-        {
-            ret = socket_send( socket, type, buf, len, NULL );
-        }
-        else
-        {
-            WARN( "Invalid buffer type %u, sending_fragment_type %u.\n", type, socket->sending_fragment_type );
-            ret = ERROR_INVALID_PARAMETER;
-        }
-    }
-
-    release_object( &socket->hdr );
-    return ret;
-}
-
-static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len, BOOL read_full_buffer )
-{
-    DWORD err, size = 0, needed = len;
-    char *ptr = buf;
-    int received;
-
-    if (socket->bytes_in_read_buffer)
-    {
-        size = min( needed, socket->bytes_in_read_buffer );
-        memcpy( ptr, socket->read_buffer, size );
-        memmove( socket->read_buffer, socket->read_buffer + size, socket->bytes_in_read_buffer - size );
-        socket->bytes_in_read_buffer -= size;
-        needed -= size;
-        ptr += size;
-    }
-    while (size != len)
-    {
-        if ((err = netconn_recv( socket->netconn, ptr, needed, 0, &received ))) return err;
-        if (!received) break;
-        size += received;
-        if (!read_full_buffer) break;
-        needed -= received;
-        ptr += received;
-    }
-    *ret_len = size;
-    if (size != len && (read_full_buffer || !size)) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
-    return ERROR_SUCCESS;
-}
-
-static BOOL is_supported_opcode( enum socket_opcode opcode )
-{
-    switch (opcode)
-    {
-    case SOCKET_OPCODE_CONTINUE:
-    case SOCKET_OPCODE_TEXT:
-    case SOCKET_OPCODE_BINARY:
-    case SOCKET_OPCODE_CLOSE:
-    case SOCKET_OPCODE_PING:
-    case SOCKET_OPCODE_PONG:
-        return TRUE;
-    default:
-        FIXME( "opcode %02x not handled\n", opcode );
-        return FALSE;
-    }
-}
-
-static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_opcode *opcode, BOOL *final )
-{
-    DWORD ret, len, count;
-    char hdr[2];
-
-    if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count, TRUE ))) return ret;
-    if ((hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT) || !is_supported_opcode( hdr[0] & 0xf ))
-    {
-        return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
-    }
-    *opcode = hdr[0] & 0xf;
-    *final = hdr[0] & FIN_BIT;
-    TRACE("received %02x frame, final %#x\n", *opcode, *final);
-
-    len = hdr[1] & ~MASK_BIT;
-    if (len == 126)
-    {
-        USHORT len16;
-        if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count, TRUE ))) return ret;
-        len = RtlUshortByteSwap( len16 );
-    }
-    else if (len == 127)
-    {
-        ULONGLONG len64;
-        if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count, TRUE ))) return ret;
-        if ((len64 = RtlUlonglongByteSwap( len64 )) > ~0u) return ERROR_NOT_SUPPORTED;
-        len = len64;
-    }
-
-    *ret_len = len;
-    return ERROR_SUCCESS;
-}
-
-static void task_socket_send_pong( void *ctx, BOOL abort )
-{
-    struct socket_send *s = ctx;
-    struct socket *socket = (struct socket *)s->task_hdr.obj;
-
-    if (abort) return;
-
-    TRACE("running %p\n", ctx);
-
-    if (s->complete_async) complete_send_frame( socket, &s->ovr, NULL );
-    else                   send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
-
-    send_io_complete( &socket->hdr );
-}
-
-static DWORD socket_send_pong( struct socket *socket )
-{
-    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-    {
-        BOOL async_send, complete_async = FALSE;
-        struct socket_send *s;
-        DWORD ret = 0;
-
-        if (!(s = malloc( sizeof(*s) ))) return ERROR_OUTOFMEMORY;
-
-        AcquireSRWLockExclusive( &socket->send_lock );
-        async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1;
-        if (!async_send)
-        {
-            memset( &s->ovr, 0, sizeof(s->ovr) );
-            if ((ret = send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, &s->ovr )) == WSA_IO_PENDING)
-            {
-                async_send = TRUE;
-                complete_async = TRUE;
-            }
-        }
-
-        if (async_send)
-        {
-            s->complete_async = complete_async;
-            if ((ret = queue_task( &socket->send_q, task_socket_send_pong, &s->task_hdr, &socket->hdr )))
-            {
-                InterlockedDecrement( &socket->hdr.pending_sends );
-                free( s );
-            }
-        }
-        else
-        {
-            InterlockedDecrement( &socket->hdr.pending_sends );
-            free( s );
-        }
-        ReleaseSRWLockExclusive( &socket->send_lock );
-        return ret;
-    }
-    return send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
-}
-
-static DWORD socket_drain( struct socket *socket )
-{
-    DWORD ret, count;
-
-    while (socket->read_size)
-    {
-        char buf[1024];
-        if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count, TRUE ))) return ret;
-        socket->read_size -= count;
-    }
-    return ERROR_SUCCESS;
-}
-
-static DWORD receive_close_status( struct socket *socket, DWORD len )
-{
-    DWORD reason_len, ret;
-
-    socket->close_frame_received = TRUE;
-    if ((len && (len < sizeof(socket->status) || len > sizeof(socket->status) + sizeof(socket->reason))))
-        return (socket->close_frame_receive_err = ERROR_WINHTTP_INVALID_SERVER_RESPONSE);
-
-    if (!len) return (socket->close_frame_receive_err = ERROR_SUCCESS);
-
-    reason_len = len - sizeof(socket->status);
-    if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &len, TRUE )))
-        return (socket->close_frame_receive_err = ret);
-    socket->status = RtlUshortByteSwap( socket->status );
-    return (socket->close_frame_receive_err
-            = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len, TRUE ));
-}
-
-static DWORD handle_control_frame( struct socket *socket )
-{
-    DWORD ret;
-
-    TRACE( "opcode %u.\n", socket->opcode );
-
-    switch (socket->opcode)
-    {
-    case SOCKET_OPCODE_PING:
-        return socket_send_pong( socket );
-
-    case SOCKET_OPCODE_PONG:
-        return socket_drain( socket );
-
-    case SOCKET_OPCODE_CLOSE:
-        if (socket->state < SOCKET_STATE_SHUTDOWN)
-            WARN( "SOCKET_OPCODE_CLOSE received, socket->state %u.\n", socket->state );
-        if (socket->close_frame_received)
-        {
-            FIXME( "Close frame already received.\n" );
-            return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
-        }
-
-        ret = receive_close_status( socket, socket->read_size );
-        socket->read_size = 0;
-        return ret;
-
-    default:
-        ERR("unhandled control opcode %02x\n", socket->opcode);
-        return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
-    }
-
-    return ERROR_SUCCESS;
-}
-
-static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( struct socket *socket, enum socket_opcode opcode, BOOL fragment )
-{
-    enum fragment_type frag_type = socket->receiving_fragment_type;
-
-    switch (opcode)
-    {
-    case SOCKET_OPCODE_TEXT:
-        if (frag_type && frag_type != SOCKET_FRAGMENT_UTF8)
-            FIXME( "Received SOCKET_OPCODE_TEXT with prev fragment %u.\n", frag_type );
-        if (fragment)
-        {
-            socket->receiving_fragment_type = SOCKET_FRAGMENT_UTF8;
-            return WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
-        }
-        socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE;
-        return WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
-
-    case SOCKET_OPCODE_BINARY:
-        if (frag_type && frag_type != SOCKET_FRAGMENT_BINARY)
-            FIXME( "Received SOCKET_OPCODE_BINARY with prev fragment %u.\n", frag_type );
-        if (fragment)
-        {
-            socket->receiving_fragment_type = SOCKET_FRAGMENT_BINARY;
-            return WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
-        }
-        socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE;
-        return WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
-
-    case SOCKET_OPCODE_CONTINUE:
-        if (!frag_type)
-        {
-            FIXME( "Received SOCKET_OPCODE_CONTINUE without starting fragment.\n" );
-            return ~0u;
-        }
-        if (fragment)
-        {
-            return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE
-                                                       : WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
-        }
-        socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE;
-        return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE
-                                                   : WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
-
-    case SOCKET_OPCODE_CLOSE:
-        return WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
-
-    default:
-        FIXME("opcode %02x not handled\n", opcode);
-        return ~0u;
-    }
-}
-
-static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD *ret_len,
-                             WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type )
-{
-    BOOL final = socket->last_receive_final;
-    DWORD count, ret = ERROR_SUCCESS;
-
-    if (!socket->read_size)
-    {
-        for (;;)
-        {
-            if (!(ret = receive_frame( socket, &socket->read_size, &socket->opcode, &final )))
-            {
-                if (!(socket->opcode & CONTROL_BIT) || (ret = handle_control_frame( socket ))
-                    || socket->opcode == SOCKET_OPCODE_CLOSE) break;
-            }
-            else if (ret == WSAETIMEDOUT) ret = socket_send_pong( socket );
-            if (ret) break;
-        }
-    }
-    if (!ret)
-    {
-        socket->last_receive_final = final;
-        ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE );
-    }
-    if (!ret)
-    {
-        if (count < socket->read_size)
-            WARN("Short read.\n");
-
-        socket->read_size -= count;
-        *ret_len = count;
-        *ret_type = map_opcode( socket, socket->opcode, !final || socket->read_size != 0 );
-        TRACE( "len %lu, *ret_len %lu, *ret_type %u.\n", len, *ret_len, *ret_type );
-        if (*ret_type == ~0u)
-        {
-            FIXME( "Unexpected opcode %u.\n", socket->opcode );
-            socket->read_size = 0;
-            return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
-        }
-    }
-    return ret;
-}
-
-static void socket_receive_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, DWORD len )
-{
-    if (!ret)
-    {
-        WINHTTP_WEB_SOCKET_STATUS status;
-        status.dwBytesTransferred = len;
-        status.eBufferType        = type;
-        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, &status, sizeof(status) );
-    }
-    else
-    {
-        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
-        result.AsyncResult.dwResult = 0;
-        result.AsyncResult.dwError  = ret;
-        result.Operation = WINHTTP_WEB_SOCKET_RECEIVE_OPERATION;
-        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
-    }
-}
-
-static void task_socket_receive( void *ctx, BOOL abort )
-{
-    struct socket_receive *r = ctx;
-    struct socket *socket = (struct socket *)r->task_hdr.obj;
-    DWORD ret, count;
-    WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
-
-    if (abort)
-    {
-        socket_receive_complete( socket, ERROR_WINHTTP_OPERATION_CANCELLED, 0, 0 );
-        return;
-    }
-
-    TRACE("running %p\n", ctx);
-    ret = socket_receive( socket, r->buf, r->len, &count, &type );
-    receive_io_complete( socket );
-    if (task_needs_completion( &r->task_hdr ))
-        socket_receive_complete( socket, ret, type, count );
-}
-
-DWORD WINAPI WinHttpWebSocketReceive( HINTERNET hsocket, void *buf, DWORD len, DWORD *ret_len,
-                                      WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type )
-{
-    struct socket *socket;
-    DWORD ret;
-
-    TRACE( "%p, %p, %lu, %p, %p\n", hsocket, buf, len, ret_len, ret_type );
-
-    if (!buf || !len) return ERROR_INVALID_PARAMETER;
-
-    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
-    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET)
-    {
-        release_object( &socket->hdr );
-        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
-    }
-    if (!socket_can_receive( socket ))
-    {
-        release_object( &socket->hdr );
-        return ERROR_INVALID_OPERATION;
-    }
-
-    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-    {
-        struct socket_receive *r;
-
-        if (InterlockedIncrement( &socket->hdr.pending_receives ) > 1)
-        {
-            InterlockedDecrement( &socket->hdr.pending_receives );
-            WARN( "Attempt to queue receive while another is pending.\n" );
-            release_object( &socket->hdr );
-            return ERROR_INVALID_OPERATION;
-        }
-
-        if (!(r = malloc( sizeof(*r) )))
-        {
-            InterlockedDecrement( &socket->hdr.pending_receives );
-            release_object( &socket->hdr );
-            return ERROR_OUTOFMEMORY;
-        }
-        r->buf = buf;
-        r->len = len;
-
-        if ((ret = queue_task( &socket->recv_q, task_socket_receive, &r->task_hdr, &socket->hdr )))
-        {
-            InterlockedDecrement( &socket->hdr.pending_receives );
-            free( r );
-        }
-    }
-    else ret = socket_receive( socket, buf, len, ret_len, ret_type );
-
-    release_object( &socket->hdr );
-    return ret;
-}
-
-static void socket_shutdown_complete( struct socket *socket, DWORD ret )
-{
-    if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NULL, 0 );
-    else
-    {
-        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
-        result.AsyncResult.dwResult = API_WRITE_DATA;
-        result.AsyncResult.dwError  = ret;
-        result.Operation = WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION;
-        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
-    }
-}
-
-static void task_socket_shutdown( void *ctx, BOOL abort )
-{
-    struct socket_shutdown *s = ctx;
-    struct socket *socket = (struct socket *)s->task_hdr.obj;
-    DWORD ret;
-
-    if (abort) return;
-
-    TRACE("running %p\n", ctx);
-
-    if (s->complete_async) ret = complete_send_frame( socket, &s->ovr, s->reason );
-    else                   ret = send_frame( socket, SOCKET_OPCODE_CLOSE, s->status, s->reason, s->len, TRUE, NULL );
-
-    send_io_complete( &socket->hdr );
-    if (s->send_callback) socket_shutdown_complete( socket, ret );
-}
-
-static DWORD send_socket_shutdown( struct socket *socket, USHORT status, const void *reason, DWORD len,
-                                   BOOL send_callback)
-{
-    DWORD ret;
-
-    if (socket->state < SOCKET_STATE_SHUTDOWN) socket->state = SOCKET_STATE_SHUTDOWN;
-
-    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-    {
-        BOOL async_send, complete_async = FALSE;
-        struct socket_shutdown *s;
-
-        if (!(s = malloc( sizeof(*s) ))) return FALSE;
-
-        AcquireSRWLockExclusive( &socket->send_lock );
-        async_send = InterlockedIncrement( &socket->hdr.pending_sends ) > 1 || socket->hdr.recursion_count >= 3;
-        if (!async_send)
-        {
-            memset( &s->ovr, 0, sizeof(s->ovr) );
-            if ((ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, &s->ovr )) == WSA_IO_PENDING)
-            {
-                async_send = TRUE;
-                complete_async = TRUE;
-            }
-        }
-
-        if (async_send)
-        {
-            s->complete_async = complete_async;
-            s->status = status;
-            memcpy( s->reason, reason, len );
-            s->len    = len;
-            s->send_callback = send_callback;
-
-            if ((ret = queue_task( &socket->send_q, task_socket_shutdown, &s->task_hdr, &socket->hdr )))
-            {
-                InterlockedDecrement( &socket->hdr.pending_sends );
-                free( s );
-            }
-        }
-        else InterlockedDecrement( &socket->hdr.pending_sends );
-        ReleaseSRWLockExclusive( &socket->send_lock );
-        if (!async_send)
-        {
-            free( s );
-            if (send_callback)
-            {
-                socket_shutdown_complete( socket, ret );
-                ret = ERROR_SUCCESS;
-            }
-        }
-    }
-    else ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, NULL );
-
-    return ret;
-}
-
-DWORD WINAPI WinHttpWebSocketShutdown( HINTERNET hsocket, USHORT status, void *reason, DWORD len )
-{
-    struct socket *socket;
-    DWORD ret;
-
-    TRACE( "%p, %u, %p, %lu\n", hsocket, status, reason, len );
-
-    if ((len && !reason) || len > sizeof(socket->reason)) return ERROR_INVALID_PARAMETER;
-
-    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
-    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET)
-    {
-        release_object( &socket->hdr );
-        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
-    }
-    if (socket->state >= SOCKET_STATE_SHUTDOWN)
-    {
-        release_object( &socket->hdr );
-        return ERROR_INVALID_OPERATION;
-    }
-
-    ret = send_socket_shutdown( socket, status, reason, len, TRUE );
-    release_object( &socket->hdr );
-    return ret;
-}
-
-static DWORD socket_close( struct socket *socket )
-{
-    BOOL final = FALSE;
-    DWORD ret, count;
-
-    if (socket->close_frame_received) return socket->close_frame_receive_err;
-
-    if ((ret = socket_drain( socket ))) return ret;
-
-    while (1)
-    {
-        if ((ret = receive_frame( socket, &count, &socket->opcode, &final ))) return ret;
-        if (socket->opcode == SOCKET_OPCODE_CLOSE) break;
-
-        socket->read_size = count;
-        if ((ret = socket_drain( socket ))) return ret;
-    }
-    if (!final)
-        FIXME( "Received close opcode without FIN bit.\n" );
-
-    return receive_close_status( socket, count );
-}
-
-static void socket_close_complete( struct socket *socket, DWORD ret )
-{
-    if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NULL, 0 );
-    else
-    {
-        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
-        result.AsyncResult.dwResult = API_READ_DATA; /* FIXME */
-        result.AsyncResult.dwError  = ret;
-        result.Operation = WINHTTP_WEB_SOCKET_CLOSE_OPERATION;
-        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
-    }
-}
-
-static void task_socket_close( void *ctx, BOOL abort )
-{
-    struct socket_shutdown *s = ctx;
-    struct socket *socket = (struct socket *)s->task_hdr.obj;
-    DWORD ret;
-
-    if (abort)
-    {
-        socket_close_complete( socket, ERROR_WINHTTP_OPERATION_CANCELLED );
-        return;
-    }
-
-    TRACE("running %p\n", ctx);
-
-    ret = socket_close( socket );
-    receive_io_complete( socket );
-    if (task_needs_completion( &s->task_hdr ))
-        socket_close_complete( socket, ret );
-}
-
-DWORD WINAPI WinHttpWebSocketClose( HINTERNET hsocket, USHORT status, void *reason, DWORD len )
-{
-    enum socket_state prev_state;
-    LONG pending_receives = 0;
-    struct socket *socket;
-    DWORD ret;
-
-    TRACE( "%p, %u, %p, %lu\n", hsocket, status, reason, len );
-
-    if ((len && !reason) || len > sizeof(socket->reason)) return ERROR_INVALID_PARAMETER;
-
-    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
-    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET)
-    {
-        release_object( &socket->hdr );
-        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
-    }
-    if (socket->state >= SOCKET_STATE_CLOSED)
-    {
-        release_object( &socket->hdr );
-        return ERROR_INVALID_OPERATION;
-    }
-
-    prev_state = socket->state;
-    socket->state = SOCKET_STATE_CLOSED;
-
-    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-    {
-        pending_receives = InterlockedIncrement( &socket->hdr.pending_receives );
-        cancel_queue( &socket->recv_q );
-    }
-
-    if (prev_state < SOCKET_STATE_SHUTDOWN && (ret = send_socket_shutdown( socket, status, reason, len, FALSE )))
-        goto done;
-
-    if (pending_receives == 1 && socket->close_frame_received)
-    {
-        if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-            socket_close_complete( socket, socket->close_frame_receive_err );
-        goto done;
-    }
-
-    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
-    {
-        struct socket_shutdown *s;
-
-        if (!(s = calloc( 1, sizeof(*s) )))
-        {
-            ret = ERROR_OUTOFMEMORY;
-            goto done;
-        }
-        if ((ret = queue_task( &socket->recv_q, task_socket_close, &s->task_hdr, &socket->hdr )))
-        {
-            InterlockedDecrement( &socket->hdr.pending_receives );
-            free( s );
-        }
-    }
-    else ret = socket_close( socket );
-
-done:
-    release_object( &socket->hdr );
-    return ret;
-}
-
-DWORD WINAPI WinHttpWebSocketQueryCloseStatus( HINTERNET hsocket, USHORT *status, void *reason, DWORD len,
-                                               DWORD *ret_len )
-{
-    struct socket *socket;
-    DWORD ret;
-
-    TRACE( "%p, %p, %p, %lu, %p\n", hsocket, status, reason, len, ret_len );
-
-    if (!status || (len && !reason) || !ret_len) return ERROR_INVALID_PARAMETER;
-
-    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
-    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_SOCKET)
-    {
-        release_object( &socket->hdr );
-        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
-    }
-
-    if (!socket->close_frame_received || socket->close_frame_receive_err)
-    {
-        ret = socket->close_frame_received ? socket->close_frame_receive_err : ERROR_INVALID_OPERATION;
-        release_object( &socket->hdr );
-        return ret;
-    }
-    *status = socket->status;
-    *ret_len = socket->reason_len;
-    if (socket->reason_len > len) ret = ERROR_INSUFFICIENT_BUFFER;
-    else
-    {
-        memcpy( reason, socket->reason, socket->reason_len );
-        ret = ERROR_SUCCESS;
-    }
-
-    release_object( &socket->hdr );
-    return ret;
-}
-
 enum request_state
 {
     REQUEST_STATE_INITIALIZED,
diff --git a/dlls/winhttp/session.c b/dlls/winhttp/session.c
index 6348ec67b821..2face5115b23 100644
--- a/dlls/winhttp/session.c
+++ b/dlls/winhttp/session.c
@@ -23,6 +23,7 @@
 #include "winsock2.h"
 #include "ws2ipdef.h"
 #include "ws2tcpip.h"
+#include "schannel.h"
 #include "winhttp.h"
 #include "winreg.h"
 #include "winternl.h"
@@ -175,22 +176,19 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b
     {
         WINHTTP_PROXY_INFO *pi = buffer;
 
-        FIXME( "%lu %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass) );
+        FIXME( "dwAccessType %lu lpszProxy %s lpszProxyBypass %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy),
+               debugstr_w(pi->lpszProxyBypass) );
         return TRUE;
     }
     case WINHTTP_OPTION_REDIRECT_POLICY:
     {
-        DWORD policy;
-
-        if (buflen != sizeof(policy))
+        if (buflen != sizeof(hdr->redirect_policy))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        policy = *(DWORD *)buffer;
-        TRACE( "%#lx\n", policy );
-        hdr->redirect_policy = policy;
+        hdr->redirect_policy = *(DWORD *)buffer;
+        TRACE( "redirect_policy %#lx\n", hdr->redirect_policy );
         return TRUE;
     }
     case WINHTTP_OPTION_SECURE_PROTOCOLS:
@@ -203,7 +201,7 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b
         EnterCriticalSection( &session->cs );
         session->secure_protocols = *(DWORD *)buffer;
         LeaveCriticalSection( &session->cs );
-        TRACE( "%#lx\n", session->secure_protocols );
+        TRACE( "secure_protocols %#lx\n", session->secure_protocols );
         return TRUE;
     }
     case WINHTTP_OPTION_DISABLE_FEATURE:
@@ -211,70 +209,113 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b
         return FALSE;
 
     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
+        if (buflen != sizeof(session->resolve_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->resolve_timeout = *(DWORD *)buffer;
+        TRACE( "resolve_timeout %u\n", session->resolve_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_CONNECT_TIMEOUT:
+        if (buflen != sizeof(session->connect_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->connect_timeout = *(DWORD *)buffer;
+        TRACE( "connect_timeout %u\n", session->connect_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_SEND_TIMEOUT:
+        if (buflen != sizeof(session->send_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->send_timeout = *(DWORD *)buffer;
+        TRACE( "send_timeout %u\n", session->send_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
+        if (buflen != sizeof(session->receive_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->receive_timeout = *(DWORD *)buffer;
+        TRACE( "receive_timeout %u\n", session->receive_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
+        if (buflen != sizeof(session->receive_response_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->receive_response_timeout = *(DWORD *)buffer;
+        TRACE( "receive_response_timeout %u\n", session->receive_response_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_CONFIGURE_PASSPORT_AUTH:
+        if (buflen != sizeof(session->passport_flags))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->passport_flags = *(DWORD *)buffer;
+        TRACE( "passport_flags %#lx\n", session->passport_flags );
         return TRUE;
 
     case WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT:
-        TRACE("WINHTTP_OPTION_UNLOAD_NOTIFY_EVENT: %p\n", *(HANDLE *)buffer);
+        if (buflen != sizeof(session->unload_event))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         session->unload_event = *(HANDLE *)buffer;
+        TRACE( "unload_event %p\n", session->unload_event );
         return TRUE;
 
     case WINHTTP_OPTION_MAX_CONNS_PER_SERVER:
+        if (buflen != sizeof(DWORD))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_SERVER: %lu\n", *(DWORD *)buffer );
         return TRUE;
 
     case WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER:
+        if (buflen != sizeof(DWORD))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         FIXME( "WINHTTP_OPTION_MAX_CONNS_PER_1_0_SERVER: %lu\n", *(DWORD *)buffer );
         return TRUE;
 
     case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE:
     {
-        DWORD buffer_size;
-
-        if (buflen != sizeof(buffer_size))
+        if (buflen != sizeof(session->websocket_receive_buffer_size))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        buffer_size = *(DWORD *)buffer;
-        TRACE( "%#lx\n", buffer_size );
-        session->websocket_receive_buffer_size = buffer_size;
+        session->websocket_receive_buffer_size = *(DWORD *)buffer;
+        TRACE( "websocket_receive_buffer_size %u\n", session->websocket_receive_buffer_size );
         return TRUE;
     }
     case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
     {
-        DWORD buffer_size;
-
-        if (buflen != sizeof(buffer_size))
+        if (buflen != sizeof(session->websocket_send_buffer_size))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        buffer_size = *(DWORD *)buffer;
-        TRACE( "%#lx\n", buffer_size );
-        session->websocket_send_buffer_size = buffer_size;
+        session->websocket_send_buffer_size = *(DWORD *)buffer;
+        TRACE( "websocket_send_buffer_size %#x\n", session->websocket_send_buffer_size );
         return TRUE;
     }
     case WINHTTP_OPTION_DECOMPRESSION:
@@ -292,10 +333,19 @@ static BOOL session_set_option( struct object_header *hdr, DWORD option, void *b
             FIXME( "unknown compression types %lx\n", decompression );
             return FALSE;
         }
-        TRACE( "%#lx\n", decompression );
+        TRACE( "decompression %#lx\n", decompression );
         session->hdr.decompression = decompression;
         return TRUE;
     }
+    case WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL:
+        if (buflen != sizeof(DWORD))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
+        FIXME( "WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL: %lx\n", *(DWORD *)buffer );
+        return TRUE;
+
     default:
         FIXME( "unimplemented option %lu\n", option );
         SetLastError( ERROR_WINHTTP_INVALID_OPTION );
@@ -320,6 +370,7 @@ HINTERNET WINAPI WinHttpOpen( LPCWSTR agent, DWORD access, LPCWSTR proxy, LPCWST
     HINTERNET handle = NULL;
 
     TRACE( "%s, %lu, %s, %s, %#lx\n", debugstr_w(agent), access, debugstr_w(proxy), debugstr_w(bypass), flags );
+    if (flags & ~WINHTTP_FLAG_ASYNC) FIXME( "flags %#lx not supported\n", flags );
 
     if (!(session = calloc( 1, sizeof(*session) ))) return NULL;
 
@@ -821,6 +872,24 @@ static BOOL request_query_option( struct object_header *hdr, DWORD option, void
         *buflen = sizeof(flags);
         return TRUE;
     }
+    case WINHTTP_OPTION_SECURITY_INFO:
+    {
+        WINHTTP_SECURITY_INFO *info = (WINHTTP_SECURITY_INFO *)buffer;
+        SECURITY_STATUS res;
+
+        if (!validate_buffer( buffer, buflen, sizeof(WINHTTP_SECURITY_INFO) )) return FALSE;
+
+        memset(info, 0 , sizeof(WINHTTP_SECURITY_INFO));
+        if (!request->netconn || !request->netconn->secure) return TRUE;
+        res = QueryContextAttributesW( &request->netconn->ssl_ctx, SECPKG_ATTR_CONNECTION_INFO,
+                                      (void*)&info->ConnectionInfo );
+        if(res != SEC_E_OK)
+            WARN( "QueryContextAttributesW failed: %#lx\n", res );
+        res = QueryContextAttributesW( &request->netconn->ssl_ctx, SECPKG_ATTR_CIPHER_INFO, (void*)&info->CipherInfo );
+        if(res != SEC_E_OK)
+            WARN( "QueryContextAttributesW failed: %#lx\n", res );
+        return TRUE;
+    }
     case WINHTTP_OPTION_SERVER_CERT_CONTEXT:
     {
         const CERT_CONTEXT *cert;
@@ -1023,52 +1092,46 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
     {
         WINHTTP_PROXY_INFO *pi = buffer;
 
-        FIXME( "%lu %s %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy), debugstr_w(pi->lpszProxyBypass) );
+        if (buflen != sizeof(*pi))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
+        FIXME( "dwAccessType %lu lpszProxy %s lpszProxyBypass %s\n", pi->dwAccessType, debugstr_w(pi->lpszProxy),
+               debugstr_w(pi->lpszProxyBypass) );
         return TRUE;
     }
     case WINHTTP_OPTION_DISABLE_FEATURE:
     {
-        DWORD disable;
-
-        if (buflen != sizeof(DWORD))
+        if (buflen != sizeof(hdr->disable_flags))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        disable = *(DWORD *)buffer;
-        TRACE( "%#lx\n", disable );
-        hdr->disable_flags |= disable;
+        hdr->disable_flags |= *(DWORD *)buffer;
+        TRACE( "disable_flags %#lx\n", hdr->disable_flags );
         return TRUE;
     }
     case WINHTTP_OPTION_AUTOLOGON_POLICY:
     {
-        DWORD policy;
-
-        if (buflen != sizeof(DWORD))
+        if (buflen != sizeof(hdr->logon_policy))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        policy = *(DWORD *)buffer;
-        TRACE( "%#lx\n", policy );
-        hdr->logon_policy = policy;
+        hdr->logon_policy = *(DWORD *)buffer;
+        TRACE( "logon_policy %#lx\n", hdr->logon_policy );
         return TRUE;
     }
     case WINHTTP_OPTION_REDIRECT_POLICY:
     {
-        DWORD policy;
-
-        if (buflen != sizeof(DWORD))
+        if (buflen != sizeof(hdr->redirect_policy))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        policy = *(DWORD *)buffer;
-        TRACE( "%#lx\n", policy );
-        hdr->redirect_policy = policy;
+        hdr->redirect_policy = *(DWORD *)buffer;
+        TRACE( "redirect_policy %#lx\n", hdr->redirect_policy );
         return TRUE;
     }
     case WINHTTP_OPTION_SECURITY_FLAGS:
@@ -1079,39 +1142,69 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
                                       SECURITY_FLAG_IGNORE_UNKNOWN_CA        |
                                       SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE;
 
-        if (buflen < sizeof(DWORD))
+        if (buflen < sizeof(flags))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
         flags = *(DWORD *)buffer;
-        TRACE( "%#lx\n", flags );
         if (flags && (flags & ~accepted))
         {
             SetLastError( ERROR_INVALID_PARAMETER );
             return FALSE;
         }
         request->security_flags = flags;
+        TRACE( "security_flags %#lx\n", flags );
         return TRUE;
     }
     case WINHTTP_OPTION_RESOLVE_TIMEOUT:
+        if (buflen != sizeof(request->resolve_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         request->resolve_timeout = *(DWORD *)buffer;
+        TRACE( "resolve_timeout %u\n", request->resolve_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_CONNECT_TIMEOUT:
+        if (buflen != sizeof(request->connect_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         request->connect_timeout = *(DWORD *)buffer;
+        TRACE( "connect_timeout %u\n", request->connect_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_SEND_TIMEOUT:
+        if (buflen != sizeof(request->send_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         request->send_timeout = *(DWORD *)buffer;
+        TRACE( "send_timeout %u\n", request->send_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_RECEIVE_TIMEOUT:
+        if (buflen != sizeof(request->receive_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         request->receive_timeout = *(DWORD *)buffer;
+        TRACE( "receive_timeout %u\n", request->receive_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_RECEIVE_RESPONSE_TIMEOUT:
+        if (buflen != sizeof(request->receive_response_timeout))
+        {
+            SetLastError( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
         request->receive_response_timeout = *(DWORD *)buffer;
+        TRACE( "receive_response_timeout %u\n", request->receive_response_timeout );
         return TRUE;
 
     case WINHTTP_OPTION_USERNAME:
@@ -1120,6 +1213,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
 
         free( connect->username );
         if (!(connect->username = buffer_to_str( buffer, buflen ))) return FALSE;
+        TRACE( "username %s\n", debugstr_w(connect->username) );
         return TRUE;
     }
     case WINHTTP_OPTION_PASSWORD:
@@ -1136,6 +1230,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
 
         free( session->proxy_username );
         if (!(session->proxy_username = buffer_to_str( buffer, buflen ))) return FALSE;
+        TRACE( "proxy_username %s\n", debugstr_w(session->proxy_username) );
         return TRUE;
     }
     case WINHTTP_OPTION_PROXY_PASSWORD:
@@ -1171,19 +1266,19 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
             SetLastError( ERROR_INVALID_PARAMETER );
             return FALSE;
         }
-
         if (request->cred_handle_initialized)
         {
             FreeCredentialsHandle( &request->cred_handle );
             request->cred_handle_initialized = FALSE;
         }
-
+        TRACE( "client_cert %p\n", request->client_cert );
         return TRUE;
     }
     case WINHTTP_OPTION_ENABLE_FEATURE:
-        if(buflen == sizeof( DWORD ) && *(DWORD *)buffer == WINHTTP_ENABLE_SSL_REVOCATION)
+        if (buflen == sizeof( DWORD ) && *(DWORD *)buffer == WINHTTP_ENABLE_SSL_REVOCATION)
         {
             request->check_revocation = TRUE;
+            TRACE( "SSL revocation enabled\n" );
             SetLastError( NO_ERROR );
             return TRUE;
         }
@@ -1195,68 +1290,77 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
 
     case WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET:
         request->flags |= REQUEST_FLAG_WEBSOCKET_UPGRADE;
+        TRACE( "enabled upgrade to web socket\n" );
         return TRUE;
 
     case WINHTTP_OPTION_CONNECT_RETRIES:
-        FIXME("WINHTTP_OPTION_CONNECT_RETRIES\n");
+        if (buflen != sizeof(DWORD))
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+        FIXME( "WINHTTP_OPTION_CONNECT_RETRIES %lu\n", *(DWORD *)buffer );
         return TRUE;
 
     case WINHTTP_OPTION_MAX_HTTP_AUTOMATIC_REDIRECTS:
-        if (buflen == sizeof(DWORD))
+        if (buflen != sizeof(request->max_redirects))
         {
-            request->max_redirects = *(DWORD *)buffer;
-            SetLastError(NO_ERROR);
-            return TRUE;
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
         }
-
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        request->max_redirects = *(DWORD *)buffer;
+        TRACE( "max_redirects %lu\n", request->max_redirects );
+        SetLastError(NO_ERROR);
+        return TRUE;
 
     case WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE:
-        FIXME("WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE\n");
+        if (buflen != sizeof(DWORD))
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+        FIXME("WINHTTP_OPTION_MAX_RESPONSE_HEADER_SIZE %#lx\n", *(DWORD *)buffer );
         return TRUE;
 
     case WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE:
-        FIXME("WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE\n");
+        if (buflen != sizeof(DWORD))
+        {
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+        FIXME("WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE %#lx\n", *(DWORD *)buffer );
         return TRUE;
 
     case WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL:
-        if (buflen == sizeof(DWORD))
+        if (buflen != sizeof(DWORD))
         {
-            FIXME( "WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL %#lx\n", *(DWORD *)buffer );
-            return TRUE;
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
         }
-        SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        FIXME( "WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL %#lx\n", *(DWORD *)buffer );
+        return TRUE;
 
     case WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE:
     {
-        DWORD buffer_size;
-
-        if (buflen != sizeof(buffer_size))
+        if (buflen != sizeof(request->websocket_receive_buffer_size))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        buffer_size = *(DWORD *)buffer;
-        WARN( "Setting websocket receive buffer size currently has not effct, size %lu\n", buffer_size );
-        request->websocket_receive_buffer_size = buffer_size;
+        WARN( "currently has no effect\n" );
+        request->websocket_receive_buffer_size = *(DWORD *)buffer;
+        TRACE( "websocket_receive_buffer_size %u\n", request->websocket_set_send_buffer_size);
         return TRUE;
     }
     case WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE:
     {
-        DWORD buffer_size;
-
-        if (buflen != sizeof(buffer_size))
+        if (buflen != sizeof(request->websocket_set_send_buffer_size))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
-        buffer_size = *(DWORD *)buffer;
-        request->websocket_set_send_buffer_size = buffer_size;
-        TRACE( "Websocket send buffer size %lu.\n", buffer_size);
+        request->websocket_set_send_buffer_size = *(DWORD *)buffer;
+        TRACE( "websocket_set_send_buffer_size %u\n", request->websocket_set_send_buffer_size);
         return TRUE;
     }
     case WINHTTP_OPTION_DECOMPRESSION:
@@ -1274,7 +1378,7 @@ static BOOL request_set_option( struct object_header *hdr, DWORD option, void *b
             FIXME( "unknown compression types %lx\n", decompression );
             return FALSE;
         }
-        TRACE( "%#lx\n", decompression );
+        TRACE( "decompression %#lx\n", decompression );
         request->hdr.decompression = decompression;
         return TRUE;
     }
@@ -1325,12 +1429,16 @@ static WCHAR *get_request_path( const WCHAR *object )
 HINTERNET WINAPI WinHttpOpenRequest( HINTERNET hconnect, const WCHAR *verb, const WCHAR *object, const WCHAR *version,
                                      const WCHAR *referrer, const WCHAR **types, DWORD flags )
 {
+    static const DWORD supported_flags = WINHTTP_FLAG_ESCAPE_PERCENT | WINHTTP_FLAG_ESCAPE_DISABLE |
+                                         WINHTTP_FLAG_ESCAPE_DISABLE_QUERY | WINHTTP_FLAG_REFRESH |
+                                         WINHTTP_FLAG_SECURE;
     struct request *request;
     struct connect *connect;
     HINTERNET hrequest = NULL;
 
     TRACE( "%p, %s, %s, %s, %s, %p, %#lx\n", hconnect, debugstr_w(verb), debugstr_w(object),
           debugstr_w(version), debugstr_w(referrer), types, flags );
+    if (flags & ~supported_flags) FIXME( "flags %lx not supported\n", flags );
 
     if (types && TRACE_ON(winhttp))
     {
@@ -1502,12 +1610,11 @@ static BOOL set_option( struct object_header *hdr, DWORD option, void *buffer, D
     {
     case WINHTTP_OPTION_CONTEXT_VALUE:
     {
-        if (buflen != sizeof(DWORD_PTR))
+        if (buflen != sizeof(hdr->context))
         {
             SetLastError( ERROR_INSUFFICIENT_BUFFER );
             return FALSE;
         }
-
         hdr->context = *(DWORD_PTR *)buffer;
         return TRUE;
     }
diff --git a/dlls/winhttp/socket.c b/dlls/winhttp/socket.c
new file mode 100644
index 000000000000..c4ac1984deff
--- /dev/null
+++ b/dlls/winhttp/socket.c
@@ -0,0 +1,1214 @@
+/*
+ * Copyright 2004 Mike McCormack for CodeWeavers
+ * Copyright 2006 Rob Shearman for CodeWeavers
+ * Copyright 2008, 2011 Hans Leidekker for CodeWeavers
+ * Copyright 2009 Juan Lang
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "ws2tcpip.h"
+#include "ntsecapi.h"
+#include "winternl.h"
+#include "winhttp.h"
+
+#include "wine/debug.h"
+#include "winhttp_private.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
+
+static void socket_handle_closing( struct object_header *hdr )
+{
+    struct socket *socket = (struct socket *)hdr;
+    BOOL pending_tasks;
+
+    pending_tasks = cancel_queue( &socket->send_q );
+    pending_tasks = cancel_queue( &socket->recv_q ) || pending_tasks;
+
+    if (pending_tasks) netconn_cancel_io( socket->netconn );
+}
+
+static BOOL socket_query_option( struct object_header *hdr, DWORD option, void *buffer, DWORD *buflen )
+{
+    switch (option)
+    {
+    case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL:
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    default:
+        break;
+    }
+
+    FIXME( "unimplemented option %lu\n", option );
+    SetLastError( ERROR_WINHTTP_INVALID_OPTION );
+    return FALSE;
+}
+
+static void socket_destroy( struct object_header *hdr )
+{
+    struct socket *socket = (struct socket *)hdr;
+
+    TRACE("%p\n", socket);
+
+    stop_queue( &socket->send_q );
+    stop_queue( &socket->recv_q );
+
+    netconn_release( socket->netconn );
+    free( socket->read_buffer );
+    free( socket->send_frame_buffer );
+    free( socket );
+}
+
+static BOOL socket_set_option( struct object_header *hdr, DWORD option, void *buffer, DWORD buflen )
+{
+    struct socket *socket = (struct socket *)hdr;
+
+    switch (option)
+    {
+    case WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL:
+    {
+        DWORD interval;
+
+        if (buflen != sizeof(DWORD) || (interval = *(DWORD *)buffer) < 15000)
+        {
+            WARN( "invalid parameters for WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL\n" );
+            SetLastError( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+        socket->keepalive_interval = interval;
+        netconn_set_timeout( socket->netconn, FALSE, socket->keepalive_interval );
+        SetLastError( ERROR_SUCCESS );
+        TRACE( "WINHTTP_OPTION_WEB_SOCKET_KEEPALIVE_INTERVAL %lu\n", interval);
+        return TRUE;
+    }
+    default:
+        break;
+    }
+
+    FIXME( "unimplemented option %lu\n", option );
+    SetLastError( ERROR_WINHTTP_INVALID_OPTION );
+    return FALSE;
+}
+
+static const struct object_vtbl socket_vtbl =
+{
+    socket_handle_closing,
+    socket_destroy,
+    socket_query_option,
+    socket_set_option,
+};
+
+HINTERNET WINAPI WinHttpWebSocketCompleteUpgrade( HINTERNET hrequest, DWORD_PTR context )
+{
+    struct socket *socket;
+    struct request *request;
+    HINTERNET hsocket = NULL;
+
+    TRACE( "%p, %Ix\n", hrequest, context );
+
+    if (!(request = (struct request *)grab_object( hrequest )))
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return NULL;
+    }
+    if (request->hdr.type != WINHTTP_HANDLE_TYPE_REQUEST)
+    {
+        release_object( &request->hdr );
+        SetLastError( ERROR_WINHTTP_INCORRECT_HANDLE_TYPE );
+        return NULL;
+    }
+    if (!(socket = calloc( 1, sizeof(*socket) )))
+    {
+        release_object( &request->hdr );
+        return NULL;
+    }
+    socket->hdr.type = WINHTTP_HANDLE_TYPE_WEBSOCKET;
+    socket->hdr.vtbl = &socket_vtbl;
+    socket->hdr.refs = 1;
+    socket->hdr.callback = request->hdr.callback;
+    socket->hdr.notify_mask = request->hdr.notify_mask;
+    socket->hdr.context = context;
+    socket->hdr.flags = request->connect->hdr.flags & WINHTTP_FLAG_ASYNC;
+    socket->keepalive_interval = 30000;
+    socket->send_buffer_size = request->websocket_send_buffer_size;
+    if (request->read.size)
+    {
+        if (!(socket->read_buffer = malloc( request->read.size )))
+        {
+            free( socket );
+            release_object( &request->hdr );
+            return NULL;
+        }
+        socket->bytes_in_read_buffer = request->read.size;
+        memcpy( socket->read_buffer, request->read.buf + request->read.pos, request->read.size );
+        request->read.pos = request->read.size = 0;
+    }
+    InitializeSRWLock( &socket->send_lock );
+    init_queue( &socket->send_q );
+    init_queue( &socket->recv_q );
+    netconn_addref( request->netconn );
+    socket->netconn = request->netconn;
+
+    netconn_set_timeout( socket->netconn, FALSE, socket->keepalive_interval );
+
+    if ((hsocket = alloc_handle( &socket->hdr )))
+    {
+        send_callback( &request->hdr, WINHTTP_CALLBACK_STATUS_HANDLE_CREATED, &hsocket, sizeof(hsocket) );
+    }
+
+    release_object( &socket->hdr );
+    release_object( &request->hdr );
+    TRACE("returning %p\n", hsocket);
+    if (hsocket) SetLastError( ERROR_SUCCESS );
+    return hsocket;
+}
+
+static DWORD send_bytes( struct socket *socket, char *bytes, int len, int *sent, WSAOVERLAPPED *ovr )
+{
+    int count;
+    DWORD err;
+    err = netconn_send( socket->netconn, bytes, len, &count, ovr );
+    if (sent) *sent = count;
+    if (err) return err;
+    return (count == len || (ovr && count)) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR;
+}
+
+#define FIN_BIT      (1 << 7)
+#define MASK_BIT     (1 << 7)
+#define RESERVED_BIT (7 << 4)
+#define CONTROL_BIT  (1 << 3)
+
+static DWORD send_frame( struct socket *socket, enum socket_opcode opcode, USHORT status, const char *buf,
+                         DWORD buflen, BOOL final, WSAOVERLAPPED *ovr )
+{
+    DWORD i, offset = 2, len = buflen, buffer_size, ret = 0;
+    int sent_size;
+    char hdr[14];
+    char *ptr;
+
+    TRACE( "sending %02x frame, len %lu\n", opcode, len );
+
+    if (opcode == SOCKET_OPCODE_CLOSE) len += sizeof(status);
+
+    hdr[0] = final ? (char)FIN_BIT : 0;
+    hdr[0] |= opcode;
+    hdr[1] = (char)MASK_BIT;
+    if (len < 126) hdr[1] |= len;
+    else if (len < 65536)
+    {
+        hdr[1] |= 126;
+        hdr[2] = len >> 8;
+        hdr[3] = len & 0xff;
+        offset += 2;
+    }
+    else
+    {
+        hdr[1] |= 127;
+        hdr[2] = hdr[3] = hdr[4] = hdr[5] = 0;
+        hdr[6] = len >> 24;
+        hdr[7] = (len >> 16) & 0xff;
+        hdr[8] = (len >> 8) & 0xff;
+        hdr[9] = len & 0xff;
+        offset += 8;
+    }
+
+    buffer_size = len + offset + 4;
+    assert( buffer_size - len < socket->send_buffer_size );
+    if (buffer_size > socket->send_frame_buffer_size && socket->send_frame_buffer_size < socket->send_buffer_size)
+    {
+        DWORD new_size;
+        void *new;
+
+        new_size = min( buffer_size, socket->send_buffer_size );
+        if (!(new = realloc( socket->send_frame_buffer, new_size )))
+        {
+            ERR( "out of memory, buffer_size %lu\n", buffer_size );
+            return ERROR_OUTOFMEMORY;
+        }
+        socket->send_frame_buffer = new;
+        socket->send_frame_buffer_size = new_size;
+    }
+    ptr = socket->send_frame_buffer;
+
+    memcpy(ptr, hdr, offset);
+    ptr += offset;
+
+    RtlGenRandom( socket->mask, 4 );
+    memcpy( ptr, socket->mask, 4 );
+    ptr += 4;
+    socket->mask_index = 0;
+
+    if (opcode == SOCKET_OPCODE_CLOSE) /* prepend status code */
+    {
+        *ptr++ = (status >> 8) ^ socket->mask[socket->mask_index++ % 4];
+        *ptr++ = (status & 0xff) ^ socket->mask[socket->mask_index++ % 4];
+    }
+
+    offset = ptr - socket->send_frame_buffer;
+    socket->send_remaining_size = offset + buflen;
+    socket->client_buffer_offset = 0;
+    while (socket->send_remaining_size)
+    {
+        len = min( buflen, socket->send_buffer_size - offset );
+        for (i = 0; i < len; ++i)
+        {
+            socket->send_frame_buffer[offset++] = buf[socket->client_buffer_offset++]
+                                                  ^ socket->mask[socket->mask_index++ % 4];
+        }
+
+        sent_size = 0;
+        ret = send_bytes( socket, socket->send_frame_buffer, offset, &sent_size, ovr );
+        socket->send_remaining_size -= sent_size;
+        if (ret)
+        {
+            if (ovr && ret == WSA_IO_PENDING)
+            {
+                memmove( socket->send_frame_buffer, socket->send_frame_buffer + sent_size, offset - sent_size );
+                socket->bytes_in_send_frame_buffer = offset - sent_size;
+            }
+            return ret;
+        }
+        assert( sent_size == offset );
+        offset = 0;
+        buflen -= len;
+    }
+    return ERROR_SUCCESS;
+}
+
+static DWORD complete_send_frame( struct socket *socket, WSAOVERLAPPED *ovr, const char *buf )
+{
+    DWORD ret, len, i;
+
+    if (!netconn_wait_overlapped_result( socket->netconn, ovr, &len )) return WSAGetLastError();
+
+    if (socket->bytes_in_send_frame_buffer)
+    {
+        ret = send_bytes( socket, socket->send_frame_buffer, socket->bytes_in_send_frame_buffer, NULL, NULL );
+        if (ret) return ret;
+    }
+
+    assert( socket->bytes_in_send_frame_buffer <= socket->send_remaining_size );
+    socket->send_remaining_size -= socket->bytes_in_send_frame_buffer;
+
+    while (socket->send_remaining_size)
+    {
+        len = min( socket->send_remaining_size, socket->send_buffer_size );
+        for (i = 0; i < len; ++i)
+        {
+            socket->send_frame_buffer[i] = buf[socket->client_buffer_offset++]
+                                           ^ socket->mask[socket->mask_index++ % 4];
+        }
+        ret = send_bytes( socket, socket->send_frame_buffer, len, NULL, NULL );
+        if (ret) return ret;
+        socket->send_remaining_size -= len;
+    }
+    return ERROR_SUCCESS;
+}
+
+static void send_io_complete( struct socket *socket )
+{
+    LONG count = InterlockedDecrement( &socket->pending_sends );
+    assert( count >= 0 );
+}
+
+static void receive_io_complete( struct socket *socket )
+{
+    LONG count = InterlockedDecrement( &socket->pending_receives );
+    assert( count >= 0 );
+}
+
+static BOOL socket_can_send( struct socket *socket )
+{
+    return socket->state == SOCKET_STATE_OPEN && !socket->close_frame_received;
+}
+
+static BOOL socket_can_receive( struct socket *socket )
+{
+    return socket->state <= SOCKET_STATE_SHUTDOWN && !socket->close_frame_received;
+}
+
+static BOOL validate_buffer_type( WINHTTP_WEB_SOCKET_BUFFER_TYPE type, enum fragment_type current_fragment )
+{
+    switch (current_fragment)
+    {
+    case SOCKET_FRAGMENT_NONE:
+        return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE ||
+               type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE ||
+               type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE ||
+               type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
+
+    case SOCKET_FRAGMENT_BINARY:
+        return type == WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE ||
+               type == WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
+
+    case SOCKET_FRAGMENT_UTF8:
+        return type == WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE ||
+               type == WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
+    }
+    assert( 0 );
+    return FALSE;
+}
+
+static enum socket_opcode map_buffer_type( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type )
+{
+    switch (type)
+    {
+    case WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE:
+        if (socket->sending_fragment_type)
+        {
+            socket->sending_fragment_type = SOCKET_FRAGMENT_NONE;
+            return SOCKET_OPCODE_CONTINUE;
+        }
+        return SOCKET_OPCODE_TEXT;
+
+    case WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE:
+        if (socket->sending_fragment_type)
+        {
+            socket->sending_fragment_type = SOCKET_FRAGMENT_NONE;
+            return SOCKET_OPCODE_CONTINUE;
+        }
+        return SOCKET_OPCODE_BINARY;
+
+    case WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE:
+        if (!socket->sending_fragment_type)
+        {
+            socket->sending_fragment_type = SOCKET_FRAGMENT_UTF8;
+            return SOCKET_OPCODE_TEXT;
+        }
+        return SOCKET_OPCODE_CONTINUE;
+
+    case WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE:
+        if (!socket->sending_fragment_type)
+        {
+            socket->sending_fragment_type = SOCKET_FRAGMENT_BINARY;
+            return SOCKET_OPCODE_BINARY;
+        }
+        return SOCKET_OPCODE_CONTINUE;
+
+    case WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE:
+        return SOCKET_OPCODE_CLOSE;
+
+    default:
+        FIXME("buffer type %u not supported\n", type);
+        return SOCKET_OPCODE_INVALID;
+    }
+}
+
+static void socket_send_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, DWORD len )
+{
+    if (!ret)
+    {
+        WINHTTP_WEB_SOCKET_STATUS status;
+        status.dwBytesTransferred = len;
+        status.eBufferType        = type;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE, &status, sizeof(status) );
+    }
+    else
+    {
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
+        result.AsyncResult.dwResult = API_WRITE_DATA;
+        result.AsyncResult.dwError  = ret;
+        result.Operation = WINHTTP_WEB_SOCKET_SEND_OPERATION;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+    }
+}
+
+static DWORD socket_send( struct socket *socket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, const void *buf, DWORD len,
+                          WSAOVERLAPPED *ovr )
+{
+    enum socket_opcode opcode = map_buffer_type( socket, type );
+    BOOL final = (type != WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE &&
+                  type != WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE);
+
+    return send_frame( socket, opcode, 0, buf, len, final, ovr );
+}
+
+static void task_socket_send( void *ctx, BOOL abort )
+{
+    struct socket_send *s = ctx;
+    struct socket *socket = (struct socket *)s->task_hdr.obj;
+    DWORD ret;
+
+    if (abort) return;
+
+    TRACE("running %p\n", ctx);
+
+    if (s->complete_async) ret = complete_send_frame( socket, &s->ovr, s->buf );
+    else ret = socket_send( socket, s->type, s->buf, s->len, NULL );
+
+    send_io_complete( socket );
+    InterlockedExchange( &socket->pending_noncontrol_send, 0 );
+    socket_send_complete( socket, ret, s->type, s->len );
+}
+
+DWORD WINAPI WinHttpWebSocketSend( HINTERNET hsocket, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, void *buf, DWORD len )
+{
+    struct socket *socket;
+    DWORD ret = 0;
+
+    TRACE( "%p, %u, %p, %lu\n", hsocket, type, buf, len );
+
+    if (len && !buf) return ERROR_INVALID_PARAMETER;
+
+    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
+    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_WEBSOCKET)
+    {
+        release_object( &socket->hdr );
+        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
+    }
+    if (!socket_can_send( socket ))
+    {
+        release_object( &socket->hdr );
+        return ERROR_INVALID_OPERATION;
+    }
+
+    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
+    {
+        BOOL async_send, complete_async = FALSE;
+        struct socket_send *s;
+
+        if (InterlockedCompareExchange( &socket->pending_noncontrol_send, 1, 0 ))
+        {
+            WARN( "previous send is still queued\n" );
+            release_object( &socket->hdr );
+            return ERROR_INVALID_OPERATION;
+        }
+        if (!validate_buffer_type( type, socket->sending_fragment_type ))
+        {
+            WARN( "invalid buffer type %u, sending_fragment_type %u\n", type, socket->sending_fragment_type );
+            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
+            release_object( &socket->hdr );
+            return ERROR_INVALID_PARAMETER;
+        }
+
+        if (!(s = malloc( sizeof(*s) )))
+        {
+            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
+            release_object( &socket->hdr );
+            return ERROR_OUTOFMEMORY;
+        }
+
+        AcquireSRWLockExclusive( &socket->send_lock );
+        async_send = InterlockedIncrement( &socket->pending_sends ) > 1 || socket->hdr.recursion_count >= 3;
+        if (!async_send)
+        {
+            memset( &s->ovr, 0, sizeof(s->ovr) );
+            if ((ret = socket_send( socket, type, buf, len, &s->ovr )) == WSA_IO_PENDING)
+            {
+                async_send = TRUE;
+                complete_async = TRUE;
+            }
+        }
+
+        if (async_send)
+        {
+            s->complete_async = complete_async;
+            TRACE( "queueing complete_async %#x\n", complete_async );
+            s->type   = type;
+            s->buf    = buf;
+            s->len    = len;
+
+            if ((ret = queue_task( &socket->send_q, task_socket_send, &s->task_hdr, &socket->hdr )))
+                free( s );
+        }
+        if (!async_send || ret)
+        {
+            InterlockedDecrement( &socket->pending_sends );
+            InterlockedExchange( &socket->pending_noncontrol_send, 0 );
+        }
+        ReleaseSRWLockExclusive( &socket->send_lock );
+        if (!async_send)
+        {
+            TRACE( "sent sync\n" );
+            free( s );
+            socket_send_complete( socket, ret, type, len );
+            ret = ERROR_SUCCESS;
+        }
+    }
+    else
+    {
+        if (validate_buffer_type( type, socket->sending_fragment_type ))
+        {
+            ret = socket_send( socket, type, buf, len, NULL );
+        }
+        else
+        {
+            WARN( "invalid buffer type %u, sending_fragment_type %u\n", type, socket->sending_fragment_type );
+            ret = ERROR_INVALID_PARAMETER;
+        }
+    }
+
+    release_object( &socket->hdr );
+    return ret;
+}
+
+static DWORD receive_bytes( struct socket *socket, char *buf, DWORD len, DWORD *ret_len, BOOL read_full_buffer )
+{
+    DWORD err, size = 0, needed = len;
+    char *ptr = buf;
+    int received;
+
+    if (socket->bytes_in_read_buffer)
+    {
+        size = min( needed, socket->bytes_in_read_buffer );
+        memcpy( ptr, socket->read_buffer, size );
+        memmove( socket->read_buffer, socket->read_buffer + size, socket->bytes_in_read_buffer - size );
+        socket->bytes_in_read_buffer -= size;
+        needed -= size;
+        ptr += size;
+    }
+    while (size != len)
+    {
+        if ((err = netconn_recv( socket->netconn, ptr, needed, 0, &received ))) return err;
+        if (!received) break;
+        size += received;
+        if (!read_full_buffer) break;
+        needed -= received;
+        ptr += received;
+    }
+    *ret_len = size;
+    if (size != len && (read_full_buffer || !size)) return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
+    return ERROR_SUCCESS;
+}
+
+static BOOL is_supported_opcode( enum socket_opcode opcode )
+{
+    switch (opcode)
+    {
+    case SOCKET_OPCODE_CONTINUE:
+    case SOCKET_OPCODE_TEXT:
+    case SOCKET_OPCODE_BINARY:
+    case SOCKET_OPCODE_CLOSE:
+    case SOCKET_OPCODE_PING:
+    case SOCKET_OPCODE_PONG:
+        return TRUE;
+    default:
+        FIXME( "opcode %02x not handled\n", opcode );
+        return FALSE;
+    }
+}
+
+static DWORD receive_frame( struct socket *socket, DWORD *ret_len, enum socket_opcode *opcode, BOOL *final )
+{
+    DWORD ret, len, count;
+    char hdr[2];
+
+    if ((ret = receive_bytes( socket, hdr, sizeof(hdr), &count, TRUE ))) return ret;
+    if ((hdr[0] & RESERVED_BIT) || (hdr[1] & MASK_BIT) || !is_supported_opcode( hdr[0] & 0xf ))
+    {
+        return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
+    }
+    *opcode = hdr[0] & 0xf;
+    *final = hdr[0] & FIN_BIT;
+    TRACE("received %02x frame, final %#x\n", *opcode, *final);
+
+    len = hdr[1] & ~MASK_BIT;
+    if (len == 126)
+    {
+        USHORT len16;
+        if ((ret = receive_bytes( socket, (char *)&len16, sizeof(len16), &count, TRUE ))) return ret;
+        len = RtlUshortByteSwap( len16 );
+    }
+    else if (len == 127)
+    {
+        ULONGLONG len64;
+        if ((ret = receive_bytes( socket, (char *)&len64, sizeof(len64), &count, TRUE ))) return ret;
+        if ((len64 = RtlUlonglongByteSwap( len64 )) > ~0u) return ERROR_NOT_SUPPORTED;
+        len = len64;
+    }
+
+    *ret_len = len;
+    return ERROR_SUCCESS;
+}
+
+static void task_socket_send_pong( void *ctx, BOOL abort )
+{
+    struct socket_send *s = ctx;
+    struct socket *socket = (struct socket *)s->task_hdr.obj;
+
+    if (abort) return;
+
+    TRACE("running %p\n", ctx);
+
+    if (s->complete_async) complete_send_frame( socket, &s->ovr, NULL );
+    else send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
+
+    send_io_complete( socket );
+}
+
+static DWORD socket_send_pong( struct socket *socket )
+{
+    BOOL async_send, complete_async = FALSE;
+    struct socket_send *s;
+    DWORD ret = 0;
+
+    if (!(socket->hdr.flags & WINHTTP_FLAG_ASYNC))
+        return send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, NULL );
+
+    if (!(s = malloc( sizeof(*s) ))) return ERROR_OUTOFMEMORY;
+
+    AcquireSRWLockExclusive( &socket->send_lock );
+    async_send = InterlockedIncrement( &socket->pending_sends ) > 1;
+    if (!async_send)
+    {
+        memset( &s->ovr, 0, sizeof(s->ovr) );
+        if ((ret = send_frame( socket, SOCKET_OPCODE_PONG, 0, NULL, 0, TRUE, &s->ovr )) == WSA_IO_PENDING)
+        {
+            async_send = TRUE;
+            complete_async = TRUE;
+        }
+    }
+
+    if (async_send)
+    {
+        s->complete_async = complete_async;
+        if ((ret = queue_task( &socket->send_q, task_socket_send_pong, &s->task_hdr, &socket->hdr )))
+        {
+            InterlockedDecrement( &socket->pending_sends );
+            free( s );
+        }
+    }
+    else
+    {
+        InterlockedDecrement( &socket->pending_sends );
+        free( s );
+    }
+    ReleaseSRWLockExclusive( &socket->send_lock );
+    return ret;
+}
+
+static DWORD socket_drain( struct socket *socket )
+{
+    DWORD ret, count;
+
+    while (socket->read_size)
+    {
+        char buf[1024];
+        if ((ret = receive_bytes( socket, buf, min(socket->read_size, sizeof(buf)), &count, TRUE ))) return ret;
+        socket->read_size -= count;
+    }
+    return ERROR_SUCCESS;
+}
+
+static DWORD receive_close_status( struct socket *socket, DWORD len )
+{
+    DWORD reason_len, ret;
+
+    socket->close_frame_received = TRUE;
+    if ((len && (len < sizeof(socket->status) || len > sizeof(socket->status) + sizeof(socket->reason))))
+        return (socket->close_frame_receive_err = ERROR_WINHTTP_INVALID_SERVER_RESPONSE);
+
+    if (!len) return (socket->close_frame_receive_err = ERROR_SUCCESS);
+
+    reason_len = len - sizeof(socket->status);
+    if ((ret = receive_bytes( socket, (char *)&socket->status, sizeof(socket->status), &len, TRUE )))
+        return (socket->close_frame_receive_err = ret);
+
+    socket->status = RtlUshortByteSwap( socket->status );
+    return (socket->close_frame_receive_err
+            = receive_bytes( socket, socket->reason, reason_len, &socket->reason_len, TRUE ));
+}
+
+static DWORD handle_control_frame( struct socket *socket )
+{
+    DWORD ret;
+
+    TRACE( "opcode %u\n", socket->opcode );
+
+    switch (socket->opcode)
+    {
+    case SOCKET_OPCODE_PING:
+        return socket_send_pong( socket );
+
+    case SOCKET_OPCODE_PONG:
+        return socket_drain( socket );
+
+    case SOCKET_OPCODE_CLOSE:
+        if (socket->state < SOCKET_STATE_SHUTDOWN)
+            WARN( "SOCKET_OPCODE_CLOSE received, socket->state %u\n", socket->state );
+        if (socket->close_frame_received)
+        {
+            FIXME( "close frame already received\n" );
+            return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
+        }
+
+        ret = receive_close_status( socket, socket->read_size );
+        socket->read_size = 0;
+        return ret;
+
+    default:
+        ERR( "unhandled control opcode %02x\n", socket->opcode );
+        return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static WINHTTP_WEB_SOCKET_BUFFER_TYPE map_opcode( struct socket *socket, enum socket_opcode opcode, BOOL fragment )
+{
+    enum fragment_type frag_type = socket->receiving_fragment_type;
+
+    switch (opcode)
+    {
+    case SOCKET_OPCODE_TEXT:
+        if (frag_type && frag_type != SOCKET_FRAGMENT_UTF8)
+            FIXME( "received SOCKET_OPCODE_TEXT with prev fragment %u\n", frag_type );
+        if (fragment)
+        {
+            socket->receiving_fragment_type = SOCKET_FRAGMENT_UTF8;
+            return WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
+        }
+        socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE;
+        return WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
+
+    case SOCKET_OPCODE_BINARY:
+        if (frag_type && frag_type != SOCKET_FRAGMENT_BINARY)
+            FIXME( "received SOCKET_OPCODE_BINARY with prev fragment %u\n", frag_type );
+        if (fragment)
+        {
+            socket->receiving_fragment_type = SOCKET_FRAGMENT_BINARY;
+            return WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE;
+        }
+        socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE;
+        return WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE;
+
+    case SOCKET_OPCODE_CONTINUE:
+        if (!frag_type)
+        {
+            FIXME( "received SOCKET_OPCODE_CONTINUE without starting fragment\n" );
+            return ~0u;
+        }
+        if (fragment)
+        {
+            return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_FRAGMENT_BUFFER_TYPE
+                                                       : WINHTTP_WEB_SOCKET_UTF8_FRAGMENT_BUFFER_TYPE;
+        }
+        socket->receiving_fragment_type = SOCKET_FRAGMENT_NONE;
+        return frag_type == SOCKET_FRAGMENT_BINARY ? WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE
+                                                   : WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE;
+
+    case SOCKET_OPCODE_CLOSE:
+        return WINHTTP_WEB_SOCKET_CLOSE_BUFFER_TYPE;
+
+    default:
+        FIXME( "opcode %02x not handled\n", opcode );
+        return ~0u;
+    }
+}
+
+static DWORD socket_receive( struct socket *socket, void *buf, DWORD len, DWORD *ret_len,
+                             WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type )
+{
+    BOOL final = socket->last_receive_final;
+    DWORD count, ret = ERROR_SUCCESS;
+
+    if (!socket->read_size)
+    {
+        for (;;)
+        {
+            if (!(ret = receive_frame( socket, &socket->read_size, &socket->opcode, &final )))
+            {
+                if (!(socket->opcode & CONTROL_BIT) || (ret = handle_control_frame( socket ))
+                    || socket->opcode == SOCKET_OPCODE_CLOSE) break;
+            }
+            else if (ret == WSAETIMEDOUT) ret = socket_send_pong( socket );
+            if (ret) break;
+        }
+    }
+    if (!ret)
+    {
+        socket->last_receive_final = final;
+        ret = receive_bytes( socket, buf, min(len, socket->read_size), &count, FALSE );
+    }
+    if (!ret)
+    {
+        if (count < socket->read_size) WARN( "short read\n" );
+
+        socket->read_size -= count;
+        *ret_len = count;
+        *ret_type = map_opcode( socket, socket->opcode, !final || socket->read_size != 0 );
+        TRACE( "len %lu, *ret_len %lu, *ret_type %u\n", len, *ret_len, *ret_type );
+        if (*ret_type == ~0u)
+        {
+            FIXME( "unexpected opcode %u\n", socket->opcode );
+            socket->read_size = 0;
+            return ERROR_WINHTTP_INVALID_SERVER_RESPONSE;
+        }
+    }
+    return ret;
+}
+
+static void socket_receive_complete( struct socket *socket, DWORD ret, WINHTTP_WEB_SOCKET_BUFFER_TYPE type, DWORD len )
+{
+    if (!ret)
+    {
+        WINHTTP_WEB_SOCKET_STATUS status;
+        status.dwBytesTransferred = len;
+        status.eBufferType        = type;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_READ_COMPLETE, &status, sizeof(status) );
+    }
+    else
+    {
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
+        result.AsyncResult.dwResult = 0;
+        result.AsyncResult.dwError  = ret;
+        result.Operation = WINHTTP_WEB_SOCKET_RECEIVE_OPERATION;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+    }
+}
+
+static void task_socket_receive( void *ctx, BOOL abort )
+{
+    struct socket_receive *r = ctx;
+    struct socket *socket = (struct socket *)r->task_hdr.obj;
+    DWORD ret, count;
+    WINHTTP_WEB_SOCKET_BUFFER_TYPE type;
+
+    if (abort)
+    {
+        socket_receive_complete( socket, ERROR_WINHTTP_OPERATION_CANCELLED, 0, 0 );
+        return;
+    }
+
+    TRACE( "running %p\n", ctx );
+    ret = socket_receive( socket, r->buf, r->len, &count, &type );
+    receive_io_complete( socket );
+    if (task_needs_completion( &r->task_hdr )) socket_receive_complete( socket, ret, type, count );
+}
+
+DWORD WINAPI WinHttpWebSocketReceive( HINTERNET hsocket, void *buf, DWORD len, DWORD *ret_len,
+                                      WINHTTP_WEB_SOCKET_BUFFER_TYPE *ret_type )
+{
+    struct socket *socket;
+    DWORD ret;
+
+    TRACE( "%p, %p, %lu, %p, %p\n", hsocket, buf, len, ret_len, ret_type );
+
+    if (!buf || !len) return ERROR_INVALID_PARAMETER;
+
+    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
+    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_WEBSOCKET)
+    {
+        release_object( &socket->hdr );
+        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
+    }
+    if (!socket_can_receive( socket ))
+    {
+        release_object( &socket->hdr );
+        return ERROR_INVALID_OPERATION;
+    }
+
+    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
+    {
+        struct socket_receive *r;
+
+        if (InterlockedIncrement( &socket->pending_receives ) > 1)
+        {
+            InterlockedDecrement( &socket->pending_receives );
+            WARN( "attempt to queue receive while another is pending\n" );
+            release_object( &socket->hdr );
+            return ERROR_INVALID_OPERATION;
+        }
+
+        if (!(r = malloc( sizeof(*r) )))
+        {
+            InterlockedDecrement( &socket->pending_receives );
+            release_object( &socket->hdr );
+            return ERROR_OUTOFMEMORY;
+        }
+        r->buf = buf;
+        r->len = len;
+
+        if ((ret = queue_task( &socket->recv_q, task_socket_receive, &r->task_hdr, &socket->hdr )))
+        {
+            InterlockedDecrement( &socket->pending_receives );
+            free( r );
+        }
+    }
+    else ret = socket_receive( socket, buf, len, ret_len, ret_type );
+
+    release_object( &socket->hdr );
+    return ret;
+}
+
+static void socket_shutdown_complete( struct socket *socket, DWORD ret )
+{
+    if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE, NULL, 0 );
+    else
+    {
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
+        result.AsyncResult.dwResult = API_WRITE_DATA;
+        result.AsyncResult.dwError  = ret;
+        result.Operation = WINHTTP_WEB_SOCKET_SHUTDOWN_OPERATION;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+    }
+}
+
+static void task_socket_shutdown( void *ctx, BOOL abort )
+{
+    struct socket_shutdown *s = ctx;
+    struct socket *socket = (struct socket *)s->task_hdr.obj;
+    DWORD ret;
+
+    if (abort) return;
+
+    TRACE( "running %p\n", ctx );
+
+    if (s->complete_async) ret = complete_send_frame( socket, &s->ovr, s->reason );
+    else ret = send_frame( socket, SOCKET_OPCODE_CLOSE, s->status, s->reason, s->len, TRUE, NULL );
+
+    send_io_complete( socket );
+    if (s->send_callback) socket_shutdown_complete( socket, ret );
+}
+
+static DWORD send_socket_shutdown( struct socket *socket, USHORT status, const void *reason, DWORD len,
+                                   BOOL send_callback)
+{
+    BOOL async_send, complete_async = FALSE;
+    struct socket_shutdown *s;
+    DWORD ret;
+
+    if (socket->state < SOCKET_STATE_SHUTDOWN) socket->state = SOCKET_STATE_SHUTDOWN;
+
+    if (!(socket->hdr.flags & WINHTTP_FLAG_ASYNC))
+        return send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, NULL );
+
+    if (!(s = malloc( sizeof(*s) ))) return FALSE;
+
+    AcquireSRWLockExclusive( &socket->send_lock );
+    async_send = InterlockedIncrement( &socket->pending_sends ) > 1 || socket->hdr.recursion_count >= 3;
+    if (!async_send)
+    {
+        memset( &s->ovr, 0, sizeof(s->ovr) );
+        if ((ret = send_frame( socket, SOCKET_OPCODE_CLOSE, status, reason, len, TRUE, &s->ovr )) == WSA_IO_PENDING)
+        {
+            async_send = TRUE;
+            complete_async = TRUE;
+        }
+    }
+
+    if (async_send)
+    {
+        s->complete_async = complete_async;
+        s->status = status;
+        memcpy( s->reason, reason, len );
+        s->len    = len;
+        s->send_callback = send_callback;
+
+        if ((ret = queue_task( &socket->send_q, task_socket_shutdown, &s->task_hdr, &socket->hdr )))
+        {
+            InterlockedDecrement( &socket->pending_sends );
+            free( s );
+        }
+    }
+    else InterlockedDecrement( &socket->pending_sends );
+
+    ReleaseSRWLockExclusive( &socket->send_lock );
+    if (!async_send)
+    {
+        free( s );
+        if (send_callback)
+        {
+            socket_shutdown_complete( socket, ret );
+            ret = ERROR_SUCCESS;
+        }
+    }
+    return ret;
+}
+
+DWORD WINAPI WinHttpWebSocketShutdown( HINTERNET hsocket, USHORT status, void *reason, DWORD len )
+{
+    struct socket *socket;
+    DWORD ret;
+
+    TRACE( "%p, %u, %p, %lu\n", hsocket, status, reason, len );
+
+    if ((len && !reason) || len > sizeof(socket->reason)) return ERROR_INVALID_PARAMETER;
+
+    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
+    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_WEBSOCKET)
+    {
+        release_object( &socket->hdr );
+        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
+    }
+    if (socket->state >= SOCKET_STATE_SHUTDOWN)
+    {
+        release_object( &socket->hdr );
+        return ERROR_INVALID_OPERATION;
+    }
+
+    ret = send_socket_shutdown( socket, status, reason, len, TRUE );
+    release_object( &socket->hdr );
+    return ret;
+}
+
+static DWORD socket_close( struct socket *socket )
+{
+    BOOL final = FALSE;
+    DWORD ret, count;
+
+    if (socket->close_frame_received) return socket->close_frame_receive_err;
+
+    if ((ret = socket_drain( socket ))) return ret;
+
+    while (1)
+    {
+        if ((ret = receive_frame( socket, &count, &socket->opcode, &final ))) return ret;
+        if (socket->opcode == SOCKET_OPCODE_CLOSE) break;
+
+        socket->read_size = count;
+        if ((ret = socket_drain( socket ))) return ret;
+    }
+    if (!final) FIXME( "received close opcode without FIN bit\n" );
+
+    return receive_close_status( socket, count );
+}
+
+static void socket_close_complete( struct socket *socket, DWORD ret )
+{
+    if (!ret) send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE, NULL, 0 );
+    else
+    {
+        WINHTTP_WEB_SOCKET_ASYNC_RESULT result;
+        result.AsyncResult.dwResult = API_READ_DATA; /* FIXME */
+        result.AsyncResult.dwError  = ret;
+        result.Operation = WINHTTP_WEB_SOCKET_CLOSE_OPERATION;
+        send_callback( &socket->hdr, WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, &result, sizeof(result) );
+    }
+}
+
+static void task_socket_close( void *ctx, BOOL abort )
+{
+    struct socket_shutdown *s = ctx;
+    struct socket *socket = (struct socket *)s->task_hdr.obj;
+    DWORD ret;
+
+    if (abort)
+    {
+        socket_close_complete( socket, ERROR_WINHTTP_OPERATION_CANCELLED );
+        return;
+    }
+
+    TRACE( "running %p\n", ctx );
+
+    ret = socket_close( socket );
+    receive_io_complete( socket );
+    if (task_needs_completion( &s->task_hdr )) socket_close_complete( socket, ret );
+}
+
+DWORD WINAPI WinHttpWebSocketClose( HINTERNET hsocket, USHORT status, void *reason, DWORD len )
+{
+    enum socket_state prev_state;
+    LONG pending_receives = 0;
+    struct socket *socket;
+    DWORD ret;
+
+    TRACE( "%p, %u, %p, %lu\n", hsocket, status, reason, len );
+
+    if ((len && !reason) || len > sizeof(socket->reason)) return ERROR_INVALID_PARAMETER;
+
+    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
+    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_WEBSOCKET)
+    {
+        release_object( &socket->hdr );
+        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
+    }
+    if (socket->state >= SOCKET_STATE_CLOSED)
+    {
+        release_object( &socket->hdr );
+        return ERROR_INVALID_OPERATION;
+    }
+
+    prev_state = socket->state;
+    socket->state = SOCKET_STATE_CLOSED;
+
+    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
+    {
+        pending_receives = InterlockedIncrement( &socket->pending_receives );
+        cancel_queue( &socket->recv_q );
+    }
+
+    if (prev_state < SOCKET_STATE_SHUTDOWN && (ret = send_socket_shutdown( socket, status, reason, len, FALSE )))
+        goto done;
+
+    if (pending_receives == 1 && socket->close_frame_received)
+    {
+        if (socket->hdr.flags & WINHTTP_FLAG_ASYNC) socket_close_complete( socket, socket->close_frame_receive_err );
+        goto done;
+    }
+
+    if (socket->hdr.flags & WINHTTP_FLAG_ASYNC)
+    {
+        struct socket_shutdown *s;
+
+        if (!(s = calloc( 1, sizeof(*s) )))
+        {
+            ret = ERROR_OUTOFMEMORY;
+            goto done;
+        }
+        if ((ret = queue_task( &socket->recv_q, task_socket_close, &s->task_hdr, &socket->hdr )))
+        {
+            InterlockedDecrement( &socket->pending_receives );
+            free( s );
+        }
+    }
+    else ret = socket_close( socket );
+
+done:
+    release_object( &socket->hdr );
+    return ret;
+}
+
+DWORD WINAPI WinHttpWebSocketQueryCloseStatus( HINTERNET hsocket, USHORT *status, void *reason, DWORD len,
+                                               DWORD *ret_len )
+{
+    struct socket *socket;
+    DWORD ret;
+
+    TRACE( "%p, %p, %p, %lu, %p\n", hsocket, status, reason, len, ret_len );
+
+    if (!status || (len && !reason) || !ret_len) return ERROR_INVALID_PARAMETER;
+
+    if (!(socket = (struct socket *)grab_object( hsocket ))) return ERROR_INVALID_HANDLE;
+    if (socket->hdr.type != WINHTTP_HANDLE_TYPE_WEBSOCKET)
+    {
+        release_object( &socket->hdr );
+        return ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
+    }
+
+    if (!socket->close_frame_received || socket->close_frame_receive_err)
+    {
+        ret = socket->close_frame_received ? socket->close_frame_receive_err : ERROR_INVALID_OPERATION;
+        release_object( &socket->hdr );
+        return ret;
+    }
+
+    *status = socket->status;
+    *ret_len = socket->reason_len;
+    if (socket->reason_len > len) ret = ERROR_INSUFFICIENT_BUFFER;
+    else
+    {
+        memcpy( reason, socket->reason, socket->reason_len );
+        ret = ERROR_SUCCESS;
+    }
+
+    release_object( &socket->hdr );
+    return ret;
+}
diff --git a/dlls/winhttp/tests/notification.c b/dlls/winhttp/tests/notification.c
index 138b02b88763..b4d942ff30f8 100644
--- a/dlls/winhttp/tests/notification.c
+++ b/dlls/winhttp/tests/notification.c
@@ -644,20 +644,20 @@ static void test_async( void )
     SetLastError( 0xdeadbeef );
     WinHttpSetStatusCallback( ses, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
     err = GetLastError();
-    ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     SetLastError( 0xdeadbeef );
     ret = WinHttpSetOption( ses, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(struct info *) );
     err = GetLastError();
     ok( ret, "failed to set context value %lu\n", err );
-    ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     setup_test( &info, winhttp_connect, __LINE__ );
     SetLastError( 0xdeadbeef );
     con = WinHttpConnect( ses, L"test.winehq.org", 0, 0 );
     err = GetLastError();
     ok( con != NULL, "failed to open a connection %lu\n", err );
-    ok( err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     setup_test( &info, winhttp_open_request, __LINE__ );
     SetLastError( 0xdeadbeef );
@@ -709,14 +709,14 @@ static void test_async( void )
     err = GetLastError();
     ok( ret, "failed unexpectedly %lu\n", err );
     ok( status == 200, "request failed unexpectedly %lu\n", status );
-    ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     setup_test( &info, winhttp_query_data, __LINE__ );
     SetLastError( 0xdeadbeef );
     ret = WinHttpQueryDataAvailable( req, NULL );
     err = GetLastError();
     ok( ret, "failed to query data available %lu\n", err );
-    ok( err == ERROR_SUCCESS || err == ERROR_IO_PENDING || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS || err == ERROR_IO_PENDING, "got %lu\n", err );
 
     WaitForSingleObject( info.wait, INFINITE );
     ok( info.last_status == WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE, "got status %#lx\n", status );
@@ -924,20 +924,20 @@ static void test_websocket(void)
     SetLastError( 0xdeadbeef );
     WinHttpSetStatusCallback( session, check_notification, WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS, 0 );
     err = GetLastError();
-    ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     SetLastError( 0xdeadbeef );
     ret = WinHttpSetOption( session, WINHTTP_OPTION_CONTEXT_VALUE, &context, sizeof(context) );
     err = GetLastError();
     ok( ret, "got %lu\n", err );
-    ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     setup_test( &info, winhttp_connect, __LINE__ );
     SetLastError( 0xdeadbeef );
     connection = WinHttpConnect( session, L"ws.ifelse.io", 0, 0 );
     err = GetLastError();
     ok( connection != NULL, "got %lu\n", err );
-    ok( err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     setup_test( &info, winhttp_open_request, __LINE__ );
     SetLastError( 0xdeadbeef );
@@ -999,7 +999,7 @@ static void test_websocket(void)
     err = GetLastError();
     ok( ret, "failed unexpectedly %lu\n", err );
     ok( status == 101, "got %lu\n", status );
-    ok( err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err );
+    ok( err == ERROR_SUCCESS, "got %lu\n", err );
 
     setup_test( &info, winhttp_websocket_complete_upgrade, __LINE__ );
     SetLastError( 0xdeadbeef );
@@ -1838,8 +1838,7 @@ struct test_recursion_context
     BYTE *send_buffer;
 };
 
-/* The limit is 128 before Win7 and 3 on newer Windows. */
-#define TEST_RECURSION_LIMIT 128
+#define TEST_RECURSION_LIMIT 3
 
 static void CALLBACK test_recursion_callback( HINTERNET handle, DWORD_PTR context_ptr,
                                               DWORD status, void *buffer, DWORD buflen )
@@ -1939,7 +1938,7 @@ static void CALLBACK test_recursion_callback( HINTERNET handle, DWORD_PTR contex
             err = GetLastError();
             ok( ret, "failed to query data available, GetLastError() %lu\n", err );
             ok( err == ERROR_SUCCESS || err == ERROR_IO_PENDING, "got %lu\n", err );
-            ok( len != 0xdeadbeef || broken( len == 0xdeadbeef ) /* Win7 */, "got %lu.\n", len );
+            ok( len != 0xdeadbeef, "got %lu\n", len );
             if (err == ERROR_SUCCESS) context->have_sync_callback = TRUE;
             InterlockedDecrement( &context->recursion_count );
             break;
@@ -2122,7 +2121,6 @@ START_TEST (notification)
 
     test_persistent_connection( si.port );
 
-    /* send the basic request again to shutdown the server thread */
     test_basic_request( si.port, NULL, L"/quit" );
 
     WaitForSingleObject( thread, 3000 );
diff --git a/dlls/winhttp/tests/winhttp.c b/dlls/winhttp/tests/winhttp.c
index b4ad4a678038..a6c77eba3e96 100644
--- a/dlls/winhttp/tests/winhttp.c
+++ b/dlls/winhttp/tests/winhttp.c
@@ -24,6 +24,7 @@
 #include <windef.h>
 #include <winsock2.h>
 #include <ws2tcpip.h>
+#include <schannel.h>
 #include <winhttp.h>
 #include <wincrypt.h>
 #include <winreg.h>
@@ -50,8 +51,7 @@ static BOOL proxy_active(void)
     SetLastError(0xdeadbeef);
     if (WinHttpGetDefaultProxyConfiguration(&proxy_info))
     {
-        ok( GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */,
-            "got %lu\n", GetLastError() );
+        ok( GetLastError() == ERROR_SUCCESS, "got %lu\n", GetLastError() );
         active = (proxy_info.lpszProxy != NULL);
         if (active)
             GlobalFree(proxy_info.lpszProxy);
@@ -69,6 +69,7 @@ static void test_WinHttpQueryOption(void)
     BOOL ret;
     HINTERNET session, request, connection;
     DWORD feature, size;
+    WINHTTP_SECURITY_INFO info;
 
     SetLastError(0xdeadbeef);
     session = WinHttpOpen(L"winetest", 0, 0, 0, 0);
@@ -108,8 +109,7 @@ static void test_WinHttpQueryOption(void)
     SetLastError(0xdeadbeef);
     ret = WinHttpQueryOption(session, WINHTTP_OPTION_REDIRECT_POLICY, &feature, &size);
     ok(ret, "failed to query option %lu\n", GetLastError());
-    ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */,
-       "got %lu\n", GetLastError());
+    ok(GetLastError() == ERROR_SUCCESS, "got %lu\n", GetLastError());
     ok(size == sizeof(feature), "WinHttpQueryOption should set the size: %lu\n", size);
     ok(feature == WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP,
        "expected WINHTTP_OPTION_REDIRECT_POLICY_DISALLOW_HTTPS_TO_HTTP, got %#lx\n", feature);
@@ -283,6 +283,17 @@ static void test_WinHttpQueryOption(void)
     ok(!ret, "should fail to query option\n");
     ok( GetLastError() == ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER, got %lu\n", GetLastError() );
 
+    size = sizeof(info);
+    info.ConnectionInfo.dwProtocol = 0xdeadbeef;
+    info.ConnectionInfo.dwCipherStrength = 0xdeadbeef;
+    ret = WinHttpQueryOption(request, WINHTTP_OPTION_SECURITY_INFO, &info, &size);
+    ok(ret, "got %lu\n", GetLastError());
+    if (ret)
+    {
+        ok(info.ConnectionInfo.dwProtocol == 0, "got %lu\n", info.ConnectionInfo.dwProtocol);
+        ok(info.ConnectionInfo.dwCipherStrength == 0, "got %lu\n", info.ConnectionInfo.dwCipherStrength);
+    }
+
     SetLastError(0xdeadbeef);
     ret = WinHttpCloseHandle(request);
     ok(ret, "WinHttpCloseHandle failed on closing request: %lu\n", GetLastError());
@@ -321,7 +332,7 @@ static void test_WinHttpOpenRequest (void)
     connection = WinHttpConnect (session, L"test.winehq.org", INTERNET_DEFAULT_HTTP_PORT, 0);
     err = GetLastError();
     ok(connection != NULL, "WinHttpConnect failed to open a connection, error: %lu.\n", err);
-    ok(err == ERROR_SUCCESS || broken(err == WSAEINVAL) /* < win7 */, "got %lu\n", err);
+    ok(err == ERROR_SUCCESS, "got %lu\n", err);
 
     SetLastError(0xdeadbeef);
     request = WinHttpOpenRequest(connection, NULL, NULL, NULL, WINHTTP_NO_REFERER,
@@ -476,8 +487,7 @@ static void test_WinHttpSendRequest (void)
 
     SetLastError(0xdeadbeef);
     ret = WinHttpReceiveResponse(request, NULL);
-    ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == ERROR_NO_TOKEN) /* < win7 */,
-       "Expected ERROR_SUCCESS got %lu\n", GetLastError());
+    ok(GetLastError() == ERROR_SUCCESS, "got %lu\n", GetLastError());
     ok(ret == TRUE, "WinHttpReceiveResponse failed: %lu\n", GetLastError());
 
     SetLastError(0xdeadbeef);
@@ -562,7 +572,7 @@ static void test_WinHttpTimeFromSystemTime(void)
     ret = WinHttpTimeFromSystemTime(&time, time_string);
     err = GetLastError();
     ok(ret, "WinHttpTimeFromSystemTime failed: %lu\n", err);
-    ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err);
+    ok(err == ERROR_SUCCESS, "got %lu\n", err);
     ok(!memcmp(time_string, L"Mon, 28 Jul 2008 10:05:52 GMT", sizeof(L"Mon, 28 Jul 2008 10:05:52 GMT")),
         "Time string returned did not match expected time string.\n");
 }
@@ -590,7 +600,7 @@ static void test_WinHttpTimeToSystemTime(void)
     ret = WinHttpTimeToSystemTime(L"Mon, 28 Jul 2008 10:05:52 GMT\n", &time);
     err = GetLastError();
     ok(ret, "WinHttpTimeToSystemTime failed: %lu\n", err);
-    ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err);
+    ok(err == ERROR_SUCCESS, "got %lu\n", err);
     ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0,
         "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n");
 
@@ -598,7 +608,7 @@ static void test_WinHttpTimeToSystemTime(void)
     ret = WinHttpTimeToSystemTime(L" mon 28 jul 2008 10 05 52\n", &time);
     err = GetLastError();
     ok(ret, "WinHttpTimeToSystemTime failed: %lu\n", err);
-    ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err);
+    ok(err == ERROR_SUCCESS, "got %lu\n", err);
     ok(memcmp(&time, &expected_time, sizeof(SYSTEMTIME)) == 0,
         "Returned SYSTEMTIME structure did not match expected SYSTEMTIME structure.\n");
 }
@@ -666,7 +676,7 @@ static void test_WinHttpAddHeaders(void)
     ret = WinHttpAddRequestHeaders(request, test_headers[0], -1L, WINHTTP_ADDREQ_FLAG_ADD);
     err = GetLastError();
     ok(ret, "WinHttpAddRequestHeaders failed to add new header, got %d with error %lu\n", ret, err);
-    ok(err == ERROR_SUCCESS || broken(err == 0xdeadbeef) /* < win7 */, "got %lu\n", err);
+    ok(err == ERROR_SUCCESS, "got %lu\n", err);
 
     index = 0;
     len = sizeof(buffer);
@@ -1088,6 +1098,7 @@ static void test_secure_connection(void)
     BOOL ret;
     CERT_CONTEXT *cert;
     WINHTTP_CERTIFICATE_INFO info;
+    WINHTTP_SECURITY_INFO secinfo;
     char buffer[32];
 
     ses = WinHttpOpen(L"winetest", 0, NULL, NULL, 0);
@@ -1100,7 +1111,7 @@ static void test_secure_connection(void)
     protocols = WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2;
     ret = WinHttpSetOption(ses, WINHTTP_OPTION_SECURE_PROTOCOLS, &protocols, sizeof(protocols));
     err = GetLastError();
-    ok(ret || err == ERROR_INVALID_PARAMETER /* < win7 */, "failed to set protocols %lu\n", err);
+    ok(ret, "failed to set protocols %lu\n", err);
 
     con = WinHttpConnect(ses, L"test.winehq.org", 443, 0);
     ok(con != NULL, "failed to open a connection %lu\n", GetLastError());
@@ -1119,8 +1130,7 @@ static void test_secure_connection(void)
     ret = WinHttpSetOption(req, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);
     err = GetLastError();
     ok(!ret, "unexpected success\n");
-    ok(err == ERROR_WINHTTP_INCORRECT_HANDLE_STATE || broken(err == ERROR_INVALID_PARAMETER) /* winxp */,
-       "setting client cert context returned %lu\n", err);
+    ok(err == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "setting client cert context returned %lu\n", err);
 
     ret = WinHttpSendRequest(req, NULL, 0, NULL, 0, 0, 0);
     err = GetLastError();
@@ -1174,7 +1184,7 @@ static void test_secure_connection(void)
 
     ret = WinHttpSetOption(req, WINHTTP_OPTION_CLIENT_CERT_CONTEXT, WINHTTP_NO_CLIENT_CERT_CONTEXT, 0);
     err = GetLastError();
-    ok(ret || broken(!ret && err == ERROR_INVALID_PARAMETER) /* winxp */, "failed to set client cert context %lu\n", err);
+    ok(ret, "failed to set client cert context %lu\n", err);
 
     WinHttpSetStatusCallback(req, cert_error, WINHTTP_CALLBACK_STATUS_SECURE_FAILURE, 0);
 
@@ -1213,6 +1223,15 @@ static void test_secure_connection(void)
         LocalFree( info.lpszIssuerInfo );
     }
 
+    size = sizeof(secinfo);
+    ret = WinHttpQueryOption(req, WINHTTP_OPTION_SECURITY_INFO, &secinfo, &size);
+    ok(ret, "got %lu\n", GetLastError());
+    if (ret)
+    {
+        ok(secinfo.ConnectionInfo.dwProtocol == SP_PROT_TLS1_2_CLIENT, "got %lu\n", secinfo.ConnectionInfo.dwProtocol);
+        ok(secinfo.ConnectionInfo.dwCipherStrength == info.dwKeySize, "got %lu\n", secinfo.ConnectionInfo.dwCipherStrength);
+    }
+
     ret = WinHttpReceiveResponse(req, NULL);
     if (!ret && GetLastError() == ERROR_WINHTTP_CONNECTION_ERROR)
     {
@@ -1478,8 +1497,7 @@ static void test_set_default_proxy_config(void)
     else
     {
         ok(ret, "WinHttpSetDefaultProxyConfiguration failed: %lu\n", GetLastError());
-        ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */,
-           "got %lu\n", GetLastError());
+        ok(GetLastError() == ERROR_SUCCESS, "got %lu\n", GetLastError());
     }
     set_default_proxy_reg_value( saved_proxy_settings, len, type );
 }
@@ -1516,8 +1534,7 @@ static void test_timeouts(void)
     SetLastError(0xdeadbeef);
     ret = WinHttpSetTimeouts(ses, -1, -1, -1, -1);
     ok(ret, "%lu\n", GetLastError());
-    ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */,
-       "expected ERROR_SUCCESS, got %lu\n", GetLastError());
+    ok(GetLastError() == ERROR_SUCCESS, "got %lu\n", GetLastError());
 
     SetLastError(0xdeadbeef);
     ret = WinHttpSetTimeouts(ses, 0, 0, 0, 0);
@@ -2174,9 +2191,7 @@ static void test_resolve_timeout(void)
            "expected ERROR_WINHTTP_NAME_NOT_RESOLVED got %lu\n", GetLastError());
 
         ret = WinHttpReceiveResponse( req, NULL );
-        ok( !ret && (GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_STATE ||
-                     GetLastError() == ERROR_WINHTTP_OPERATION_CANCELLED /* < win7 */),
-            "got %lu\n", GetLastError() );
+        ok( !ret && GetLastError() == ERROR_WINHTTP_INCORRECT_HANDLE_STATE, "got %lu\n", GetLastError() );
 
         WinHttpCloseHandle(req);
         WinHttpCloseHandle(con);
@@ -2891,7 +2906,7 @@ static void test_basic_authentication(int port)
     ret = WinHttpQueryAuthSchemes(req, &supported, &first, &target);
     error = GetLastError();
     ok(ret, "failed to query authentication schemes %lu\n", error);
-    ok(error == ERROR_SUCCESS || broken(error == 0xdeadbeef) /* < win7 */, "expected ERROR_SUCCESS, got %lu\n", error);
+    ok(error == ERROR_SUCCESS, "got %lu\n", error);
     ok(supported == WINHTTP_AUTH_SCHEME_BASIC, "got %lu\n", supported);
     ok(first == WINHTTP_AUTH_SCHEME_BASIC, "got %lu\n", first);
     ok(target == WINHTTP_AUTH_TARGET_SERVER, "got %lu\n", target);
@@ -2900,7 +2915,7 @@ static void test_basic_authentication(int port)
     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_NTLM, NULL, NULL, NULL);
     error = GetLastError();
     ok(ret, "failed to set credentials %lu\n", error);
-    ok(error == ERROR_SUCCESS || broken(error == 0xdeadbeef) /* < win7 */, "expected ERROR_SUCCESS, got %lu\n", error);
+    ok(error == ERROR_SUCCESS, "got %lu\n", error);
 
     ret = WinHttpSetCredentials(req, WINHTTP_AUTH_TARGET_SERVER, WINHTTP_AUTH_SCHEME_PASSPORT, NULL, NULL, NULL);
     ok(ret, "failed to set credentials %lu\n", GetLastError());
@@ -3272,15 +3287,13 @@ static void test_no_content(int port)
     size = 12345;
     ret = WinHttpQueryDataAvailable(req, &size);
     ok(ret, "expected success\n");
-    ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */,
-       "wrong error %lu\n", GetLastError());
+    ok(GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError());
     ok(!size, "expected 0, got %lu\n", size);
 
     SetLastError(0xdeadbeef);
     ret = WinHttpReadData(req, buf, len, &bytes_read);
     ok(ret, "expected success\n");
-    ok(GetLastError() == ERROR_SUCCESS || broken(GetLastError() == 0xdeadbeef) /* < win7 */,
-       "wrong error %lu\n", GetLastError());
+    ok(GetLastError() == ERROR_SUCCESS, "wrong error %lu\n", GetLastError());
     ok(!bytes_read, "expected 0, got %lu\n", bytes_read);
 
     size = 12345;
@@ -4238,8 +4251,7 @@ static void test_cookies( int port )
     size = sizeof(status);
     ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
     ok( ret, "failed to query status code %lu\n", GetLastError() );
-    ok( status == HTTP_STATUS_OK || broken(status == HTTP_STATUS_BAD_REQUEST) /* < win7 */,
-        "request failed unexpectedly %lu\n", status );
+    todo_wine ok( status == HTTP_STATUS_BAD_REQUEST, "request failed unexpectedly %lu\n", status );
 
     WinHttpCloseHandle( req );
     WinHttpCloseHandle( con );
@@ -4265,8 +4277,7 @@ static void do_request( HINTERNET con, const WCHAR *obj, DWORD flags )
     size = sizeof(status);
     ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_CODE|WINHTTP_QUERY_FLAG_NUMBER, NULL, &status, &size, NULL );
     ok( ret, "failed to query status code %lu\n", GetLastError() );
-    ok( status == HTTP_STATUS_OK || broken(status == HTTP_STATUS_BAD_REQUEST) /* < win7 */,
-        "request %s with flags %#lx failed %lu\n", wine_dbgstr_w(obj), flags, status );
+    ok( status == HTTP_STATUS_OK, "request %s with flags %#lx failed %lu\n", wine_dbgstr_w(obj), flags, status );
     WinHttpCloseHandle( req );
 }
 
@@ -4399,8 +4410,7 @@ static void test_passport_auth( int port )
 
     ret = WinHttpReceiveResponse( req, NULL );
     err = GetLastError();
-    ok( ret || broken(!ret && err == ERROR_WINHTTP_LOGIN_FAILURE) /* winxp */
-            || broken(!ret && err == ERROR_WINHTTP_INVALID_SERVER_RESPONSE ), "got %lu\n", err );
+    ok( ret || broken(!ret && err == ERROR_WINHTTP_INVALID_SERVER_RESPONSE ), "got %lu\n", err );
     if (!ret)
     {
         win_skip("no support for Passport redirects\n");
@@ -4417,13 +4427,12 @@ static void test_passport_auth( int port )
     size = sizeof(buf);
     ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_STATUS_TEXT, NULL, buf, &size, NULL );
     ok( ret, "got %lu\n", GetLastError() );
-    ok( !lstrcmpW(L"Found", buf) || broken(!lstrcmpW(L"Unauthorized", buf)) /* < win7 */, "got %s\n",
-        wine_dbgstr_w(buf) );
+    ok( !lstrcmpW(L"Found", buf), "got %s\n", wine_dbgstr_w(buf) );
 
     buf[0] = 0;
     size = sizeof(buf);
     ret = WinHttpQueryHeaders( req, WINHTTP_QUERY_RAW_HEADERS_CRLF, NULL, buf, &size, NULL );
-    ok( ret || broken(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER) /* < win7 */, "got %lu\n", GetLastError() );
+    ok( ret, "got %lu\n", GetLastError() );
     if (ret)
     {
         ok( size == lstrlenW(headersW) * sizeof(WCHAR), "got %lu\n", size );
@@ -5243,9 +5252,7 @@ static void test_IWinHttpRequest(int port)
     SysFreeString( url );
 
     hr = IWinHttpRequest_Send( req, empty );
-    ok( hr == S_OK ||
-        hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ) ||
-        hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_SECURE_CHANNEL_ERROR ) /* win7 */, "got %#lx\n", hr );
+    ok( hr == S_OK || hr == HRESULT_FROM_WIN32( ERROR_WINHTTP_INVALID_SERVER_RESPONSE ), "got %#lx\n", hr );
     if (hr != S_OK) goto done;
 
     hr = IWinHttpRequest_get_ResponseText( req, &response );
@@ -5601,7 +5608,7 @@ static void test_WinHttpGetIEProxyConfigForCurrentUser(void)
     ret = WinHttpGetIEProxyConfigForCurrentUser( &cfg );
     error = GetLastError();
     ok( ret, "expected success\n" );
-    ok( error == ERROR_SUCCESS || broken(error == ERROR_NO_TOKEN) /* < win7 */, "got %lu\n", error );
+    ok( error == ERROR_SUCCESS, "got %lu\n", error );
 
     trace("IEProxy.AutoDetect=%d\n", cfg.fAutoDetect);
     trace("IEProxy.AutoConfigUrl=%s\n", wine_dbgstr_w(cfg.lpszAutoConfigUrl));
@@ -6218,8 +6225,7 @@ static void test_client_cert_authentication(void)
     ok( req != NULL, "failed to open a request %lu\n", GetLastError() );
 
     ret = WinHttpSendRequest( req, NULL, 0, NULL, 0, 0, 0 );
-    ok( ret || broken(!ret && GetLastError() == ERROR_WINHTTP_SECURE_FAILURE) /* win7 */,
-        "failed to send request %lu\n", GetLastError() );
+    ok( ret, "failed to send request %lu\n", GetLastError() );
     if (!ret) goto done;
 
     SetLastError( 0xdeadbeef );
diff --git a/dlls/winhttp/winhttp_private.h b/dlls/winhttp/winhttp_private.h
index 6e078fcd2ec8..44a91a37d6fd 100644
--- a/dlls/winhttp/winhttp_private.h
+++ b/dlls/winhttp/winhttp_private.h
@@ -25,8 +25,6 @@
 
 #include "wine/list.h"
 
-#define WINHTTP_HANDLE_TYPE_SOCKET 4
-
 struct object_header;
 struct object_vtbl
 {
@@ -53,8 +51,6 @@ struct object_header
     DWORD notify_mask;
     LONG recursion_count;
     struct list entry;
-    volatile LONG pending_sends;
-    volatile LONG pending_receives;
 };
 
 struct hostdata
@@ -190,14 +186,20 @@ enum request_response_state
 
 #define READ_BUFFER_SIZE 8192
 
+struct read_buffer
+{
+    DWORD pos;  /* current read position in buf */
+    DWORD size; /* valid data size in buf */
+    BYTE  buf[READ_BUFFER_SIZE]; /* buffer for already read but not returned data */
+};
+
 struct data_stream;
 struct request;
 
 struct data_stream_vtbl
 {
-    DWORD (*query_data)( struct data_stream *, struct request * );
+    DWORD (*fill_buffer)( struct data_stream *, struct request *, struct read_buffer * );
     BOOL  (*end_of_data)( struct data_stream *, struct request * );
-    DWORD (*read_data)( struct data_stream *, struct request *, char *, DWORD, DWORD * );
     DWORD (*drain_data)( struct data_stream *, struct request * );
     void  (*destroy)( struct data_stream * );
 };
@@ -210,8 +212,6 @@ struct data_stream
 struct netconn_stream
 {
     struct data_stream data_stream;
-    UINT64 content_length;
-    UINT64 content_read;
 };
 
 extern const struct data_stream_vtbl netconn_stream_vtbl;
@@ -244,9 +244,7 @@ struct request
     WCHAR *status_text;
     UINT64 content_length; /* total number of bytes to be read */
     UINT64 content_read;   /* bytes read so far */
-    DWORD read_pos;       /* current read position in read_buf */
-    DWORD read_size;      /* valid data size in read_buf */
-    char  read_buf[READ_BUFFER_SIZE]; /* buffer for already read but not returned data */
+    struct read_buffer read;
     struct data_stream *data_stream;
     struct netconn_stream netconn_stream;
     struct header *headers;
@@ -324,6 +322,8 @@ struct socket
     unsigned int bytes_in_read_buffer;
     SRWLOCK send_lock;
     volatile LONG pending_noncontrol_send;
+    volatile LONG pending_sends;
+    volatile LONG pending_receives;
     enum fragment_type sending_fragment_type;
     enum fragment_type receiving_fragment_type;
     BOOL last_receive_final;
@@ -427,14 +427,16 @@ BOOL free_handle( HINTERNET );
 
 void send_callback( struct object_header *, DWORD, LPVOID, DWORD );
 void close_connection( struct request * );
-void init_queue( struct queue *queue );
+void init_queue( struct queue * );
+BOOL cancel_queue( struct queue * );
 void stop_queue( struct queue * );
+DWORD queue_task( struct queue *, TASK_CALLBACK, struct task_header *, struct object_header * );
+BOOL task_needs_completion( struct task_header * );
 
 void netconn_addref( struct netconn * );
 void netconn_release( struct netconn * );
 DWORD netconn_create( struct hostdata *, const struct sockaddr_storage *, int, struct netconn ** );
 void netconn_unload( void );
-ULONG netconn_query_data_available( struct netconn * );
 DWORD netconn_recv( struct netconn *, void *, size_t, int, int * );
 DWORD netconn_resolve( const WCHAR *, INTERNET_PORT, DWORD, struct sockaddr_storage *, int );
 DWORD netconn_secure_connect( struct netconn *, WCHAR *, DWORD, CredHandle *, BOOL );
diff --git a/dlls/winmm/tests/wave.c b/dlls/winmm/tests/wave.c
index 6585c98ff3a6..f6917799207c 100644
--- a/dlls/winmm/tests/wave.c
+++ b/dlls/winmm/tests/wave.c
@@ -1901,13 +1901,14 @@ static void test_PlaySound(void)
 
 static MMRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL direct)
 {
-    WAVEFORMATEXTENSIBLE fmt2 = *fmt;
+    WAVEFORMATEXTENSIBLE fmt2;
     BOOL extensible = TRUE;
     MMRESULT ret;
 
     /* Reduce non-extensible formats to extensible ones. */
-    if (fmt2.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
+    if (fmt->Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE)
     {
+        fmt2.Format = fmt->Format;
         extensible = FALSE;
 
         switch (fmt2.Format.wFormatTag)
@@ -1926,10 +1927,14 @@ static MMRESULT validate_fmt(const WAVEFORMATEXTENSIBLE *fmt, BOOL direct)
         fmt2.Samples.wValidBitsPerSample = fmt2.Format.wBitsPerSample;
         fmt2.Format.cbSize = sizeof(fmt2) - sizeof(fmt2.Format);
     }
+    else
+    {
+        if (fmt->Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format))
+            return WAVERR_BADFORMAT;
+        fmt2 = *fmt;
+    }
 
-    if (fmt2.Format.cbSize < sizeof(fmt2) - sizeof(fmt2.Format))
-        ret = direct ? MMSYSERR_INVALPARAM : WAVERR_BADFORMAT;
-    else if ((fmt2.Format.nChannels == 0) || fmt2.Format.nSamplesPerSec == 0)
+    if ((fmt2.Format.nChannels == 0) || fmt2.Format.nSamplesPerSec == 0)
         ret = WAVERR_BADFORMAT;
     else if (fmt2.Format.nBlockAlign != fmt2.Format.nChannels * fmt2.Format.wBitsPerSample / 8)
         ret = WAVERR_BADFORMAT;
diff --git a/dlls/wmvcore/tests/Makefile.in b/dlls/wmvcore/tests/Makefile.in
index 8d78d50601e0..826245a64c38 100644
--- a/dlls/wmvcore/tests/Makefile.in
+++ b/dlls/wmvcore/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = wmvcore.dll
-IMPORTS   = ole32 wmvcore
+IMPORTS   = ole32 shcore wmvcore
 
 SOURCES = \
 	rsrc.rc \
diff --git a/dlls/wmvcore/tests/rsrc.rc b/dlls/wmvcore/tests/rsrc.rc
index cd642ceb1d0e..2593a75274e4 100644
--- a/dlls/wmvcore/tests/rsrc.rc
+++ b/dlls/wmvcore/tests/rsrc.rc
@@ -23,3 +23,7 @@
 /* ffmpeg -f lavfi -i smptebars -f lavfi -i "sine=frequency=700" -t 2.0 -f asf -vcodec wmv1 -vf scale=64x48 -acodec wmav1 test.wmv */
 /* @makedep: test.wmv */
 test.wmv RCDATA "test.wmv"
+
+/* ffmpeg -f lavfi -i smptebars -f asf -vcodec rawvideo -pix_fmt yuv420p -vf scale=64x48 -t 2.0 test_rawvideo.wmv */
+/* @makedep: test_rawvideo.wmv */
+test_rawvideo.wmv RCDATA "test_rawvideo.wmv"
diff --git a/dlls/wmvcore/tests/test_rawvideo.wmv b/dlls/wmvcore/tests/test_rawvideo.wmv
new file mode 100644
index 0000000000000000000000000000000000000000..f594c7ec6d5954c2772a2905aaa49eef5fafd8ee
GIT binary patch
literal 234341
zcmeI53s6*7n#V5>p#h~I+6szMd=PmF7^9&liHdH}DKn)A(H+OZ7a2oL;v;bknC5oV
z2qp@&P-;b7h)JbT9?4LNuW?*!Dp50&kx^l4O;RZ;$xcm8vc{T9ZKh_kTl<}J&%N~c
zpn+~^y8Hj7(k=J&?R)#&=l^&A-*+;TI$o-Ny3_dfP3fex@#@x<p%RZ#^coWS#%C@2
zb5C>{tG|*ij-I-zXp7Q#*K1K-m@-X%y!-QC9Sd0|K5=nQw9=5C6~ZPZj8+=hLS*_k
z`(HA|O7DmLd*N)hoG+E-G$<dFjMs0poMY4ftW1xPo~M?-{{HVDzO(k1OC7&Bxqrz&
zmj8}TW5K>PM4BjtN#XRbMbb`bn^Yuil3tYZqz&}?jP!!EhJS`$+<x+3#U~fO^~dXx
zUtTvJzAZI<^z-Hwo7v11A<`^qwe+NvA^i)j)h7Dx&9sE)rC&&^XsIvq<*~nZ@=qs7
z%V`~UNl#1jq)chHltu6CHIx36BxmGjr%${5P8**`k}iH5fBwm}oyO+>mE^*oElHJD
z|IgF{*T2Q*9un`olck097yH)GS+t6h_GgGRT3R-DPNrm{iFd@pylZ<WXZ_Lm=3De5
z!<PQ{k45{UJEpS*gh)}+4*D^_q@VK){pce4=`6zex6iv{hw7*my9WPE?~A&NgoM~>
z;yR_l#(#j0ts&c0-dE%8<4U|$YcJ>F*z>|R9y^Njl_*%Xcu|fLDbr>s@tzvm{59(Q
zrDFc=uJbQaB4yfiCDhs9Q|EuPulaMt?29lz`j7Vj_8-v$IDVA#7tSAjoPTlt9BJ2|
z(`q!orNrA#<?>tZ*t2~HkDbr1QX)TZvAF!^%$ky@#0fQy9#-PWzA`1`U0a^vQCzfI
zi8W6xeC%-^k7cFLz9SMRKfq(s!nMk$*Djbak;jBgo6Nt`wtI?s0*mqHeeGhoVl@&I
z#~F+~Vjo$ptnKP-y@^L`N`-^}roE+;jLIZK-Ffl5#bs>z^zkO6fyJ2l1$lXS`33oF
zEQYZ>^l5u594spLB$)UVlTn+0rW*0)N&Jo^F?Um8;rjd)EAz8WW*++F($W$Zdv?<D
zl`p7jYgS^u8uMoF{_;~6pZE0id{K~`k&&LlB6X(06fYt!TBp++4d%GGDG8I6$X3IW
zW&i$L7PlyF7tBmeP2-WCWH7|4p^J=+HR#Rp@ngq`N$Tv`*;(>;UyJzWRzZ?7cUl^o
zUk$xBzgaJ)VScp-{JsA&UAF&!^|k%k{%2Nq3H8@!XAf?Eo6S~Hn4FfD>S#LF_-gLb
zWsCP;ID4++*-b@-&QH3#yQ$qF+8bE=(#5Y`IK$dEQ+roe7jK_M^OrX%?K#wbwxjr;
z+ev?faQ!h$vfDzQCf%V4kk?1Kn;GqWckccBhtAsN>mE!^Nhxn^Xx#Ti?o!$~v~i0!
zZvMIRQ`)$dm6fj*Wz3l~r}B8?8wZvze=>LfuTPzRcWcqp8)|P{y?V8?v-3vVOC=>Q
zpFDf|%!yJujXIke8yjS+)oQ1CE3aL<*4<HNx7kjdI(4qq;i$0H9)11wBX-%QTrrxO
zn%-!vmt~uyy#Ae*=H`>NGF=E*vl2%sjvc0U`4wkdOKWTUL95I{ZEv7Bc8L9Lb+)&(
zw6r^|Y7>9=R=X@)Y56TJZBAwRd?l3ikoVS9*VN|F5t8vEi)C*0A1+<Ge51SjX4~_0
zZKjpr?KO*7yTxL8NNMlty4m)eXs@WLu134>`iF171xd-t>2#``Q`33n%12$@-Ji6x
z?ZfVB9MuP^tAG6P{6{Pc7c9u$ck$f0^B-Tmdi~@JJC%63oVM~izxnlV+Db}Ft$B0j
zJ^ZMxs<P6-=H0%1`?g(WvRwB5haX%%Ww)2_U74PlG4Ex%UE=%jMi#|3*;Y|;;K-qa
z2kWZXjYz4se{Y~zzlGXmYh@ipeU)sdpb1K7?Y6S2dfr|pTD;lL_IB<2)m@*z+d>&L
z;-~5*bk05#p~9l~RkaCP1hu8m!h6s@sLhe4HbKik%Xkl{=kFk)Wn6!-2Q^H8gr13T
zxu`9T36w_>DoHvGlmwInl%(`PP@=TKp&<W2N%yB6q=_7bZc!BGzaLE^K?_>c584D;
z<U5)()HDsWh`}d~2Hk@;^+Aic3yIUBtwf8WLqLmEwaNWgE4Ts678XqoEUlLm)57r}
z(P4oiwZKu-JsbNk?*SaY;NX75!GVf|?+C6V7uN|~N5SX10xIIJrhB@U0tXfG=O0Xe
zu;(9P+s3#EklJwO3cA~}HTWM7j?_Qb5;zh#5?n{j^+Xmbm$0$aLWPjj6G!@OBsdb(
zHt&HTb1i_DDJl)L4aYx@f9e4ro&P+iMO=UE7WyOnw~;QF_s63}CK(dgkiZ7lk{`R4
zfRcg%C4m+pM~&scA;-;oIeu^*dEh!?WwaDpbe?F@xKPj{sKq<gBKKc4u^mOSjT#r~
zvcK?$_T>&_uPL>@TxxY8dk@)rya!NgO_)W*dDUke#^0CkIY$C2;^mG|>j<tTzeZ(1
zML<PVOKO0|BmXrP@#h~*e=z^msFGM00kSttNwV=)EhBfelHfXm>j<u+d$^9MD1<mH
zzaozGu?`#w9O+Ju1X{#;0JQAx%J!gTpk<(C)B|3lg`h>=%TeR{<BHH95g+SZZgl2G
zp=`EbDM48)2xYT-%dYpo>^5okVJMqD_#7<MLh8E~l>ee6&>~dURw|EsS_=uTBM)3h
zWMLOKQKKoF_JJ_aBG4kxBI<#A=BRN0)opgjNVdoas7@HKf5na*ZaaeONE=}h90?o=
z90?o=BdlSBHD!#i-m=X8j%s|p{%{?^brejlBcLJ`74hdEOn)%{Ris1jB0%<pddg9P
zeSUBx4>%G%iW58ITvEe-iULOhM*>H>A4dW$q8<P(11;k{P_PQL(A%^St|RZcj$kZO
zjYV94#L>7POn>P96y<Wum!d=2ZT~B~4U`0w1eDb7v?`2Aym~8#4LNGaQA3W}J#y6O
z#zEXV{ETSPtZ>jG&?3+x(4u?0u6k)1_g^g}{Xzb#s998BpZl-aIfQ`(a0GA^Z*vrJ
zUcQeXuy@Z4)cp?}2^>jr?)cjEg5~!nc=-ag0Tlri0TlriRsSJ)%VzWEA54F+=O0nk
z1{VRcBgA5{JT&mmf$PWv*HN^_ksPD}d!oUSz>&a_z>(Z>q(D{c!A>ji`$Z4jGkbOD
zX%%P@Xc1@;>w%%6Ra}2;5&9##hi-rQ0}yueJ2f&bJxR&5W3PH$WMr&CZ;p>Q>%~-M
z!wlWZ^?&(5NkB<JNkB;hrzOZytFEbCkd&O9PUrDCHJw+keALz5{Yg7Z5TsgQWsd3t
z)zv?Kcs^W5_i!D>Xtb!6E|_yhffo5zEkLcI|9KDiNUdW38|ePW{a3Y$|0-q<jabR$
z2Roah){i%9{RI1-362Dgq~MC7;VAt_6<9u8N4ZOvE#80O?75C-Hx(5+Kk4r7raU1>
zA?3EDI+_|d%31u{g)^*uGqrbhb@BFDD0`h+F8XJHBcyrSe<+LH&~WUKEMpM0z)e7N
zhr$BUSj3-yF#W;&S20J7E&^nWB$7968z|Oqapx*>*Dh0(Rn^zsgCo(fYGT1%q<sDw
z1CBIM9SOAvwdlPOmV#X^<M-qI!+Rh|IVxxoXc1`9NHF&JnwAZ<v54!BGeUoi{wqCD
z<_|!a3>Y7wxvmW6xHz*gT^UG~V1zY4MqxlnKuPXUOQ5$0B1#%IT13|dahdpm{`qJG
zXc5#}Fsn7O^@Fye3VuJ1|G^&rTz~Wk{W0dz2$u`X2Qdr+VCV8|=K@LsN&-p(O3Kb2
zYLo<86o@%+phciXflh<m{XWnl54=UO8ZDYZ|E!iq7A@lWAG%Psj<(opm20szJ%0T7
zn>F@w9*)u%c&Q1D@KnqS%}}5+F)9;t&)Xuno~8+f2~^=3szCqww*P>NfQo>MfQo>M
zhA+p9KmTC*gXMq3en*KI+<(Oc$mmgL&UO?BN&+4@5;&4O&JyVD;7A^DB)!Iwmea}c
ziO7+~kwA+;%Rmc3OIZ(q7K4@#ePwFz&@!$+GKK!oKM^VP2fM_ci>5^kG64@L2`C9D
z2`C9DY4}hQXwkb{i=N(4d*kZWtDT*lH`-n*DS7$i+0$oEl$Ms3IGY+98)U21YOkcY
zcI{esN15GbJ8|mNxmJgx!d83q_1BNsslJd*q^hi`sp*ZzdMY>MD6fB~rMdZJtxPv|
ztXYYp6vqxzyZnl?t);cK{h*bVSJB!VDEd>b$Xz)jckQxlrRBG@v^kaK^OaE6L*}$0
zhm{NZk;O7ssZ8D7eY5R(s;o@Eg16T!3f^);Bb_#Z7I{F6XdpXrEBhkd${q;;E%NQN
z<@>1>(jU^gHKaete`PpAc_94p2is=Q(clQ+2>!wm29FBvcV@ux9~{R&P!UiOP!UiO
zP!UkkU=rv&GZyjZA54ER|CQnYsGf-?KtjX8kyK7p3ywq_&0?`U<bNZ)fg^dqk*FZI
zI3+X?lUShxM;e(N32HGo)FNmBjz8W5gEXdK|MBnrC(vjS*B`RbAI23rmz#}uql~eS
ztX{=qb++EbBQ~YN!CjVnOD7qXNrt-fqE`e+nm&EJ$;hkqj+tMOmzS4ckiW)a7|TPS
zwztB;qH<4yiBB;ZwfSeN5pSL}gGFNQrozJY`72iDXPeAC^vU!royDG=w0z|Ys@j^B
zn6JjX*}K2|l*Q*gJw0C(Bxhu#r?5z!X)wi$h>O<g^hQ=$cuK-#B@_%qua+$P_usO(
zMRB`eW@>604>lfrtQy*Q@MFh_N!t8FG*~?bS)=|}L$CF}SuduIoc>3xqrspQQu~fV
zKdx-;>H2$ylCHvaBwR(HMgHrm0xj}@7MV0!^a0VL<DsBM{;f6wUoDdUkk&Pm{viLA
z={UXf#~*C(MXf8;x<ail)H(~yT5o~Ik${STioX8lRzZ>i%F=+U`irW7ihzo8moCkD
z?ZQA3=zxm)m*D0uL5=iB2-hFXe`V59krz#X{5=#L2^{G+Z6zh8*1Wm%9)8qTRaxnv
z1FvlR_U+qtmC<PS?|=Bg<x_Th`QDZ3nHlq5rqoTIfw_@IF>#!ViUUUu9Xwc9#hzJ}
zYT20^DAsSGcG+54M^RrT+bJ0M;i0wL%Bt#ldzonQW;@H()V^O$+~n`Ju^LDEhLreE
zqrj2Ck$4Zl^+1KTC{URlmFc++0<JgYNDh6DBxq5f=BRP~@ke^@!Su)2pGFD&!EU?W
z*1>h8xvu=e^^+xk_q7P0pfI2$pd_HAcBl29)Uvl~A-O|IphciXK}n0oX|!k@@zd5Y
z&?3+x&?4#qKcHo#KcsbkC;dVGt8uMiLVmF07$fXqgguO~$9o_pP)67TM+#Jq1XKi6
zL_NR~6xHZ6K@O-0s0gSCsL0plg!uChra##8k8vg{o6P-JOn}@9@%73LeEG;;^B{Z8
ztZ}4AY4dN621f!%0!Q)>js#i+S_E1IT9lKMGiyqs5+~F+dRU1g`<Q#0Lf*CI86L$&
ztCd*u)WXLe=kZup`s_O*aq<H^CM{g6e0uGI2@`ot$W+G5DYNaKVxGWaym?={Sgu%&
z#Kdt1BM+1_LOG*5j5%C?Or_@@On;a+M+^PIZa^C%Rgz-p6Q%gt_2cX110?|^0VM$?
z4V;#Y^byd8di_9)JfKD6HCnWpF4m{QL5o0(K#M?&{K0kAOUp=qNb8o8{viL=_*3CR
zey}szqJVLoi1U(P_~ClD4Eo<&t|z#T;5t%DGy57<VEIT;%U!x`@%{^E&viVzsi@HT
zNq2WQWeYh9DR(8+Ax1!3OtpAe`(|qI>gwX{L0p#F*T0`07?iJjFf}Emys@Ei-xIm4
zRuXN$;*Fbs?);RtUu9+GYegAz=FF))-uT9W<;$PU-T&)Tr{CRL^z??>8&^>lo3@|K
zQ3D21!ysyRlr!SbKbZbt&p*Z|&~Rhif5imIR}y<v7x1-?CTJXKKmF+EW5AKXk-(9_
zk^GAzfmV2nR)ALd_WTc81X=`I#CjkYXcgBV+l2m@@O+HWAM95AU_@Udyuoz@*AZMt
za2>&Qbm`LN8(m#D+n(F8V+TWh?p#Z79eLn7iqmM(dvuAqI104Lw`u`u4gJr1zz=FI
z!CNx&a^$%FI3n~%+{IBsf3TDL!qGUn`1i>LC<!PDC@EM_5@^vt2NCnNv1g<&AI2l^
z46=sG*r<#hl$EjLHCpr;2?~>RH!b4%9~YJUk9ZS(oZGM1r)$*_miCAdc6RiR2fla_
z)mdPXGHr$ucS)7EYSj5l?;fFNu_)C6*8p4tibS|;|G@}neH=d{k7Ho_`8TS-_Vexb
z11bV40xAM3%FYfhV-bJ;!Sn~q|A^l`+C_j=jY0yPcM<@>k-(AMxpD%%9j+q}Tt^c%
zjucK6(tj6mH%9_3;=^&5V?6G=X&-0>Dia4*Wn$10-_jEA^*`4ie-Zj);_o7a{$Q86
zc`?V8@G}$*lmwInlmwI%Y$yq|2(*YCUA6{_V~1qfX0tlmTUuI>qlO$c<fySDLx~L(
z>$kY0LGIdRin6Nuy1KghsxtP67Pd(mElQ)?=!6i^qWh~Q?!Pin-Ce4`J1HSV$Pd<U
z;3(TzZ0~iQfg^z<fg@25pfa~m_}=3{{)u`#{rx~iKt(`BKt(`BqVhIXc0O~qqd0g_
z5`X@|^at}_O|p-15g^uZDogG`*>Sjz`p2PU+3IW~PSxhLY8smTgVZ|8X4h0#*DONz
zT2N-MC1@NepLj@DBskLjITC0QXc1@`Xd!56J`dEo@;)se3R=YV$0I_2By>dz{lPBy
zY0;!0DCAvRp5akkv|5QZPc3}xaUPFlrO&=25+^^vW75L4%BR;Zm@tvYgiM>vztOgP
zig^Ny@#cN)CzME3W1PXrBleNit9Y!=)|+_5rc^k%%Xe?-B%?CPP<LMRiU3K|r;j%o
z`MB+4<`?AU<>eRTudx`$^3bR4t#GiY+>>D9Q%pu}{+VjTn<w#<`o!E#g@x<$SFFs>
zHko<olS@lWSnSzJ%U8ajs;yax`D)CYz5B~gS$y8p)AL0^az;ja3X9a422;F<xM-bD
zZ#0<W;-(}_Rzkr*^lHhnfB!9uTNJkoW~Qd5@kmcH7-H4XYTb+-BPMC{2SwRv?f0AY
zd}A97`2A`R1XluE@Sq~kXb{niK4}u2m@&v&KU_<oMgB{J+~wFIN6iD*(PWJl?V+2;
zq)^Zz&?4RgeO6}X{;Tzh|7vnlsE{9Q4}y+lJpdi;eI4zoYXkG+%;x^gHgeBjL&1?a
z*8wU5Dq^gPp(-`>KsAxE2E92xegvW_pdt*S7TklV@#h~*e=z^m<o&TO0_4RoWUpB)
zmWPnNhU_(wx<+q9p1t;f#*yA43h=oO90_X6pVgMwdhcO8`QXg)!S=`b%b(9*phZKO
zqsH||mCzp#e6ADvgWdW}i-PM2D9K+?8c-5YQgEXr&?3;H!O$|ejy!N3P0?u4$8^h-
z83tMewdK!hOKiPiqea|*^{(Q-nvzL%c=`B)>{vprBh)%Vts~TW^418M;7CKsk${ST
zihzn#)0shWov{Q<vpS8QT~`!R?n<ho=@>&b%NFmyaQ0lsvzv;jY;$*aH&2jK+8a2^
zSxmKvSo>!0ly&Cc??E}AV4oieYJphJh(G^e`h)qerW~Si&ou#39D4aiSJ%z9=XUJa
zK|8<fE_*B3+rg1M;7C(7j`SUA-@inGBY`7<BT*0ZnY}l1b6kd-qk)!zmVuUekCuTJ
zffgwRZL;L=z83M#t%4+_7?Rg=%((ve51~J%{v}H24|Wq6r{m}V32c!_U^4(E1yEUT
zprk-VNuWgop=F>&9?+shjTR*sCCL&FS_E1IS_E1&a9YOwSJEhUKCvZQNQdypAMC86
z=s$2QoLO*Y8T^?A90?q0I5-ke5%s``MrBA)LxLI-)Y_d^^3wE11I4j^l)bjutj@j?
z+)x(VKg(kC=O0XeF#lCz6Fv6O1jzaj+D+WLuE3Ez;7HRnj<kdn-`}Fak)ZaV_6D!^
z#NGqf5?otKv8gv}?0m$iaz`mfXv7GO?nY<?Ednh9En+<|w63dOTE_LqETKQ9{ViJP
z4|Y2o8;P>nNMP$I4wM8uxQ_aVnt+o06D5HbZP>7Wi#r<Ru3e@mtE#W7tE;anV}EF2
zo37EKt#o-@G77W^v<S2av}oY2BY2Bg53pm0`>$3g{;TOr=$$|QVCPpHSvax=dt`wl
zfg^z<4JSteDgr73Dk^$<L+y>LSFd(<cHU@vsifrPlV?w#IZ;|#TH<VKY;2INR;#^|
z;@Y)q-5q6io9)D@Q|DS8jtX1t(br!;VwcJA!AA0IYHE6;v0j#Kj`I3<TAG_r*2?r4
zjWsKAl;YT7YL{PewzagjwjZ=|nX0yX%T)x|QQ)E=cjcOb!&t<he=z;Q{8!UYlJ3w1
z$WxNWfz;!QzxQthHg-H}^J@%={lhjx<4E<iydPq~k+{}_YXq(lxJFnHz%>Kc5VuXi
zH8mWrG0-B=BG4kxqU`M9&r#$0W4F*BGk%B>`hy9B@CatpBFTZW*?wHM8?Ga`j@+S^
zKyMEYl%&xf@6w`~8ZA0c7lofhfEIxk!5aZ@#9+M<;^+Zw1#KnN$n{5)&>u5@5+U>l
zyVP{V07VWI#R4S(B>^P?CHVp+ffjXjk@RvDf)>Gel*5cWKeAZnR{!DBrOP+EyKlBV
zFUB!rG@@ov@EUtYI&A_i@*qboNuxzy(Jg$FG}37i&;PhW`h)84CN<G3w_mY!cULO{
zI#%=mbS(4Cz%>Kc5L`oW4N(vHhieL`2&f3C2&f3CsHwqsm9hEr52im@{zp>87#9KZ
zkMOj#)N)_0+~AiF*AZMtBc1aM_4<J$dBBk#WJHFun9(LlS`#_aITC2mw(Z5raPavB
zt8&C}=-wL-8ng|xjrRa(BWNRNtJi2V*B`fq{&;Xrq{~IOIl8|n3n&RF2`C9D2`I@w
zX^pR4OQ1!dMMF(vM*8=I7I{F6W@)r&F43ZsA)rP6LJPS6Dvr`V$bU8KWQdR-Y%Au2
zBY~rVBPu<RGEFE<a8Q3av*G-8ujc?jML<PBML<PBML<P^ab0;E74hdEOn)%{)ht7-
zivYPDhO*hnUSrvNU0pZZo)g)7;7C+g`uz_-xO~cPFW<W|Ju_q8%TzO-mxkZSqL?^N
zMa6+5hYlXBt12xiDJj*;#%q<UWoso3a7H7X$#x0`et2l@Hcx69dBBm9HIDQ%A`lyO
z;7Cwgya(Vqf$IdW6R){W`fDr!?F#PmZ{X7+u0IwE{gJ#;C-euq{rI;iQ*26wgQryP
zEuCaE@i5e#7ri1t()8)$O-4ST`k46zd3kyH1^H_%hOs>KX?rUiEGqXTnD`WvQJa6J
z8u8{yGgu_%ZYnHXpTA;dezwWXL!V4T2eH_*la{Z1K~-C`67$uVH+%P&pR)M8r>EzO
zg5->h^b{7UGYzJA5pmHvo!)4mL8_)COjbg{K=f+KvVZ?Ai(3@83udOKrtwHmG8kgj
z&_zbZ@<G1FjuDfz`G;+=`jI-wSeE?V*CM{TRgk3gURoOKKQ;7P|C#k-THy5G@R!YI
zT}YAzm9bIl2(^w->xgPSSuB=^6j}yaROuj0Tef}s_HDap2>XDgMJXCBa?tJCd!e93
z!L3&OQLS?S)fUBnmGWMwkRNP+CgTZQCve^H9`MIK8~ZPgU)41i_#6qS2&hPKoq$F?
zo}w<GqQSUs2zB{&S!++%-`lPu7>iV65r6){^at}_rA*Yj2#`OAqGmQ+M?t`mQZ<g$
zO1gV%6gUz%67K=Hj^H|i>j<tRR8}9>%Ics+!IPuL^+&DHAE{fTg#KVRV)eS%Sj{y9
z*HOT^hJccQf^wHG&3Wy@nX?_mn>H6ZKj|9!5!`^1Q0r)<=a3Ec`k~g52RUkK8ZGLg
zo0JP-phciXpheUJeo4!?|LTn5ze>9hCgcY@vZqfM`?a6`GORzgpXdR<JTg7sf5DN0
zha&+MX{am!6U=~$fQo>MPS(nljBHn{wb+hQ96Kz_Hu)82TT5$e`$4PBg4|X-8Yqq(
zVt-qm?JX@W?M|!O<kfarw$k!jTH2h-^7%?A>mhU0fCRPsCaCe}A54ER|5e%ygNp$9
zEM%xTkf+}dj^qJHO4m5j52QACMS~*+w_1T(#rEet5Tt4y`#<)7U+({)MW97WNghvW
zgFnsB^+%7;AL+ZIh5lf-q_0NC10~(%x<UdQP}IOt6kJFBLs39U$@fJ?p3)j$&ktJU
z0WF%X(V`h+CFx2yXc5$sFV&LheRyL)Ydp#k<o+ui4SP=G56-?4F60M0$N8t9%yZWY
zjx7H^vx6gnBLyEv0xG(@tT#{*P!UiOTu1&_mO6+~ktBtzWBP;nuV&9Sx(JZ#QUH#y
zmZ5Q^<)pFX7;q&2RvS=@*nYeRz@a?iP@qjp_Z>&ABh)%t&0_6>2@`ot$h6S_vlO=7
zQ_K@sj5qIVKcPgT8siK`9<h(CUd3Z|wq6-A4TGquW2m8=kvfPRj77p&#Qj&9LVsk)
zF+zXvoAZd?5#oT7fRcccfRcccE?v5OV<02E!FA+;>nKyBMK2O9x;_fD2($sTfqDS6
z1+<0rfZx*+u0PfY{gHWnl+YjSbU%A^&9I^nacafEHOP|-j7KmY!Fa@az@HNEhQc@n
zS_E1IS_E1IS_E3uTk&fH#riGoXpp;hR@|$ss=ltSuD+^Ft@Op;ZCM&EY9RSAL+TGL
z;`tx4lK+u4gT6o~QR+FHzc^osf>nzb<tULdZH5weNrkuik}8X7C~6)UPhH$0-_?J9
zuVee#{yEtG*#B7%;P}V!&wC))&woHgKt(`BKt<Wv!H$af^ADy!SpG-WtD{{6$gWXM
z4d6)NNZ?4|NZ?4r$dTq~9O(n%K%YhQha-U&sk98VL*O2$eW-n?ed>W=ryV2t_mloG
zu6rz`S$P6toAVi!;^mJ(*rjhq%nRFiZ126ijl9!4U=m;wU=m;wU=n!IV0am7W1}{<
zuL}<Odilsw8@%s`(IUhkd!SY)J@l*p>@@ECPHOrnY}xNO-sgMdLq~W^D7|v6Lhm7b
Q%0ItO<<pn&*IfSk|E;W@&Hw-a

literal 0
HcmV?d00001

diff --git a/dlls/wmvcore/tests/wmvcore.c b/dlls/wmvcore/tests/wmvcore.c
index d16947db6bb7..bbc37c525f3e 100644
--- a/dlls/wmvcore/tests/wmvcore.c
+++ b/dlls/wmvcore/tests/wmvcore.c
@@ -27,6 +27,7 @@
 #include "amvideo.h"
 #include "uuids.h"
 #include "wmcodecdsp.h"
+#include "shlwapi.h"
 
 #include "wine/test.h"
 
@@ -129,6 +130,24 @@ static WCHAR *load_resource(const WCHAR *name)
     return pathW;
 }
 
+static IStream *load_resource_as_stream(const WCHAR *name)
+{
+    IStream *stream;
+    DWORD size;
+    HRSRC res;
+    void *ptr;
+
+    res = FindResourceW(NULL, name, (LPCWSTR)RT_RCDATA);
+    ok(!!res, "Failed to load resource, error %lu.\n", GetLastError());
+    size = SizeofResource(NULL, res);
+    ptr = LockResource(LoadResource(NULL, res));
+
+    stream = SHCreateMemStream(ptr, size);
+    ok(!!stream, "Failed to create stream");
+
+    return stream;
+}
+
 #define check_interface(a, b, c) check_interface_(__LINE__, a, b, c)
 static HRESULT check_interface_(unsigned int line, void *iface, REFIID riid, BOOL supported)
 {
@@ -2038,6 +2057,27 @@ static void test_sync_reader_compressed_output(void)
     IWMProfile_Release(profile);
 }
 
+void test_sync_reader_rawvideo_file(void)
+{
+    IWMSyncReader *reader;
+    IStream *stream;
+    HRESULT hr;
+
+    stream = load_resource_as_stream(L"test_rawvideo.wmv");
+
+    hr = WMCreateSyncReader(NULL, WMT_RIGHT_PLAYBACK, &reader);
+    ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+    hr = IWMSyncReader_OpenStream(reader, stream);
+    ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+    hr = IWMSyncReader_Close(reader);
+    ok(hr == S_OK, "Got hr %#lx.\n", hr);
+
+    IStream_Release(stream);
+    IWMSyncReader_Release(reader);
+}
+
 struct callback
 {
     IWMReaderCallback IWMReaderCallback_iface;
@@ -4290,6 +4330,7 @@ START_TEST(wmvcore)
     test_sync_reader_types();
     test_sync_reader_file();
     test_sync_reader_compressed_output();
+    test_sync_reader_rawvideo_file();
     test_async_reader_settings();
     test_async_reader_streaming();
     test_async_reader_types();
diff --git a/dlls/wow64/system.c b/dlls/wow64/system.c
index 335fed158c59..644c3ae99456 100644
--- a/dlls/wow64/system.c
+++ b/dlls/wow64/system.c
@@ -680,6 +680,7 @@ NTSTATUS WINAPI wow64_NtQuerySystemInformationEx( UINT *args )
 
     case SystemCpuSetInformation:  /* SYSTEM_CPU_SET_INFORMATION */
     case SystemSupportedProcessorArchitectures:  /* SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION */
+    case SystemSupportedProcessorArchitectures2: /* SYSTEM_SUPPORTED_PROCESSOR_ARCHITECTURES_INFORMATION */
         if (!query || query_len < sizeof(LONG)) return STATUS_INVALID_PARAMETER;
         handle = LongToHandle( *(LONG *)query );
         return NtQuerySystemInformationEx( class, &handle, sizeof(handle), ptr, len, retlen );
diff --git a/dlls/wow64/virtual.c b/dlls/wow64/virtual.c
index 7981d9a0d1a2..b22e9010f2e4 100644
--- a/dlls/wow64/virtual.c
+++ b/dlls/wow64/virtual.c
@@ -285,14 +285,15 @@ NTSTATUS WINAPI wow64_NtFlushVirtualMemory( UINT *args )
     HANDLE process = get_handle( &args );
     ULONG *addr32 = get_ptr( &args );
     ULONG *size32 = get_ptr( &args );
-    ULONG unknown = get_ulong( &args );
+    IO_STATUS_BLOCK32 *io32 = get_ptr( &args );
+    IO_STATUS_BLOCK io;
 
     void *addr;
     SIZE_T size;
     NTSTATUS status;
 
     status = NtFlushVirtualMemory( process, (const void **)addr_32to64( &addr, addr32 ),
-                                   size_32to64( &size, size32 ), unknown );
+                                   size_32to64( &size, size32 ), iosb_32to64( &io, io32 ) );
     if (!status)
     {
         put_addr( addr32, addr );
diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c
index 49d74b42afcd..66d8d01669c2 100644
--- a/dlls/wtsapi32/tests/wtsapi.c
+++ b/dlls/wtsapi32/tests/wtsapi.c
@@ -75,7 +75,7 @@ static void check_wts_process_info(const WTS_PROCESS_INFOW *info, DWORD count)
         DWORD size;
 
         nt_process = find_nt_process_info(nt_info, info[i].ProcessId);
-        ok(!!nt_process, "failed to find pid %#lx\n", info[i].ProcessId);
+        if (!nt_process) continue;
 
         winetest_push_context("pid %#lx", info[i].ProcessId);
 
diff --git a/include/Makefile.in b/include/Makefile.in
index db9578e8baaa..fcf8011a1ba0 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -92,6 +92,7 @@ SOURCES = \
 	common.ver \
 	commoncontrols.idl \
 	compobj.h \
+	compressapi.h \
 	comsvcs.idl \
 	concurrencysal.h \
 	config.h.in \
@@ -1040,6 +1041,7 @@ SOURCES = \
 	windows.graphics.capture.idl \
 	windows.graphics.capture.interop.idl \
 	windows.graphics.directx.direct3d11.idl \
+	windows.graphics.directx.direct3d11.interop.idl \
 	windows.graphics.directx.idl \
 	windows.graphics.display.idl \
 	windows.graphics.effects.idl \
diff --git a/include/bcrypt.h b/include/bcrypt.h
index b0cdf6e27a36..bf22f6dfb9b0 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -44,6 +44,10 @@ typedef LONG NTSTATUS;
 #define BCRYPT_SUCCESS(st) ((NTSTATUS)(st) >= 0)
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #if defined(_MSC_VER) || defined(__MINGW32__)
 #define BCRYPT_ALGORITHM_NAME       L"AlgorithmName"
 #define BCRYPT_AUTH_TAG_LENGTH      L"AuthTagLength"
@@ -604,4 +608,8 @@ NTSTATUS WINAPI BCryptSetProperty(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG);
 NTSTATUS WINAPI BCryptSignHash(BCRYPT_KEY_HANDLE, void *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG *, ULONG);
 NTSTATUS WINAPI BCryptVerifySignature(BCRYPT_KEY_HANDLE, void *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif  /* __WINE_BCRYPT_H */
diff --git a/include/bluetoothleapis.h b/include/bluetoothleapis.h
index e790eb32aa4b..510a35aad2a0 100644
--- a/include/bluetoothleapis.h
+++ b/include/bluetoothleapis.h
@@ -26,6 +26,7 @@ extern "C" {
 
 HRESULT WINAPI BluetoothGATTGetServices( HANDLE, USHORT, BTH_LE_GATT_SERVICE *, USHORT *, ULONG );
 HRESULT WINAPI BluetoothGATTGetCharacteristics( HANDLE, BTH_LE_GATT_SERVICE *, USHORT, BTH_LE_GATT_CHARACTERISTIC *, USHORT *, ULONG );
+HRESULT WINAPI BluetoothGATTGetCharacteristicValue( HANDLE, BTH_LE_GATT_CHARACTERISTIC *, ULONG, BTH_LE_GATT_CHARACTERISTIC_VALUE *, USHORT *, ULONG );
 
 #ifdef __cplusplus
 }
diff --git a/include/bthledef.h b/include/bthledef.h
index 32585c06f8ec..aa2121cb10dd 100644
--- a/include/bthledef.h
+++ b/include/bthledef.h
@@ -22,6 +22,10 @@
 extern "C" {
 #endif
 
+#define BLUETOOTH_GATT_FLAG_NONE                   0
+#define BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE 0x0004
+#define BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE  0x0008
+
 typedef struct _BTH_LE_UUID
 {
     BOOLEAN IsShortUuid;
@@ -54,6 +58,12 @@ typedef struct _BTH_LE_GATT_CHARACTERISTIC
     BOOLEAN HasExtendedProperties;
 } BTH_LE_GATT_CHARACTERISTIC, *PBTH_LE_GATT_CHARACTERISTIC;
 
+typedef struct _BTH_LE_GATT_CHARACTERISTIC_VALUE
+{
+    ULONG DataSize;
+    UCHAR Data[1];
+} BTH_LE_GATT_CHARACTERISTIC_VALUE, *PBTH_LE_GATT_CHARACTERISTIC_VALUE;
+
 DEFINE_GUID( GUID_BLUETOOTHLE_DEVICE_INTERFACE, 0x781aee18, 0x7733, 0x4ce4, 0xad, 0xd0, 0x91, 0xf4, 0x1c, 0x67, 0xb5, 0x92 );
 DEFINE_GUID( GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE, 0x6e3bb679, 0x4372, 0x40c8, 0x9e, 0xaa, 0x45, 0x09, 0xdf, 0x26, 0x0c, 0xd8 );
 DEFINE_GUID( BTH_LE_ATT_BLUETOOTH_BASE_GUID, 0, 0, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb );
diff --git a/include/cfgmgr32.h b/include/cfgmgr32.h
index 43a2157f1cfe..88adf285b1ed 100644
--- a/include/cfgmgr32.h
+++ b/include/cfgmgr32.h
@@ -360,8 +360,8 @@ CMAPI CONFIGRET WINAPI CM_Create_DevNodeA( DEVINST *node, DEVINSTID_A instance_i
 CMAPI CONFIGRET WINAPI CM_Create_DevNodeW( DEVINST *node, DEVINSTID_W instance_id, DEVINST parent, ULONG flags );
 #define                CM_Create_DevNode WINELIB_NAME_AW(CM_Create_DevNode)
 CMAPI CONFIGRET WINAPI CM_Create_Range_List( RANGE_LIST *ranges, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Delete_Class_Key( GUID *class, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Delete_Class_Key_Ex( GUID *class, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Delete_Class_Key( GUID *class_, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Delete_Class_Key_Ex( GUID *class_, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Delete_Device_Interface_Key_ExA( const char *iface, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Delete_Device_Interface_Key_ExW( const WCHAR *iface, ULONG flags, HMACHINE machine );
 #define                CM_Delete_Device_Interface_Key_Ex WINELIB_NAME_AW(CM_Delete_Device_Interface_Key_Ex)
@@ -379,8 +379,8 @@ CMAPI CONFIGRET WINAPI CM_Disconnect_Machine( HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Dup_Range_List( RANGE_LIST old_ranges, RANGE_LIST new_ranges, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Enable_DevNode( DEVINST node, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Enable_DevNode_Ex( DEVINST node, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Enumerate_Classes( ULONG index, GUID *class, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Enumerate_Classes_Ex( ULONG index, GUID *class, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Enumerate_Classes( ULONG index, GUID *class_, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Enumerate_Classes_Ex( ULONG index, GUID *class_, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Enumerate_Enumerators_ExA( ULONG index, char *buffer, ULONG *len, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Enumerate_Enumerators_ExW( ULONG index, WCHAR *buffer, ULONG *len, ULONG flags, HMACHINE machine );
 #define                CM_Enumerate_Enumerators_Ex WINELIB_NAME_AW(CM_Enumerate_Enumerators_Ex)
@@ -399,24 +399,24 @@ CMAPI CONFIGRET WINAPI CM_Free_Res_Des_Handle( RES_DES desc );
 CMAPI CONFIGRET WINAPI CM_Free_Resource_Conflict_Handle( CONFLICT_LIST conflicts );
 CMAPI CONFIGRET WINAPI CM_Get_Child( DEVINST *child, DEVINST node, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Get_Child_Ex( DEVINST *child, DEVINST node, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Key_Name_ExA( GUID *class, char *name, ULONG *len, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Key_Name_ExW( GUID *class, WCHAR *name, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Key_Name_ExA( GUID *class_, char *name, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Key_Name_ExW( GUID *class_, WCHAR *name, ULONG *len, ULONG flags, HMACHINE machine );
 #define                CM_Get_Class_Key_Name_Ex WINELIB_NAME_AW(CM_Get_Class_Key_Name_Ex)
-CMAPI CONFIGRET WINAPI CM_Get_Class_Key_NameA( GUID *class, char *name, ULONG *len, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Key_NameW( GUID *class, WCHAR *name, ULONG *len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Key_NameA( GUID *class_, char *name, ULONG *len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Key_NameW( GUID *class_, WCHAR *name, ULONG *len, ULONG flags );
 #define                CM_Get_Class_Key_Name WINELIB_NAME_AW(CM_Get_Class_Key_Name)
-CMAPI CONFIGRET WINAPI CM_Get_Class_Name_ExA( GUID *class, char *buffer, ULONG *len, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Name_ExW( GUID *class, WCHAR *buffer, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Name_ExA( GUID *class_, char *buffer, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Name_ExW( GUID *class_, WCHAR *buffer, ULONG *len, ULONG flags, HMACHINE machine );
 #define                CM_Get_Class_Name_Ex WINELIB_NAME_AW(CM_Get_Class_Name_Ex)
-CMAPI CONFIGRET WINAPI CM_Get_Class_NameA( GUID *class, char *buffer, ULONG *len, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Get_Class_NameW( GUID *class, WCHAR *buffer, ULONG *len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Class_NameA( GUID *class_, char *buffer, ULONG *len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Class_NameW( GUID *class_, WCHAR *buffer, ULONG *len, ULONG flags );
 #define                CM_Get_Class_Name WINELIB_NAME_AW(CM_Get_Class_Name)
-CMAPI CONFIGRET WINAPI CM_Get_Class_Property_ExW( const GUID *class, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Property_Keys( const GUID *class, DEVPROPKEY *keys, ULONG *count, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Property_Keys_Ex( const GUID *class, DEVPROPKEY *keys, ULONG *count, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Class_PropertyW( const GUID *class, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Registry_PropertyA( GUID *class, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Class_Registry_PropertyW( GUID *class, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Property_ExW( const GUID *class_, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Property_Keys( const GUID *class_, DEVPROPKEY *keys, ULONG *count, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Property_Keys_Ex( const GUID *class_, DEVPROPKEY *keys, ULONG *count, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_PropertyW( const GUID *class_, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Registry_PropertyA( GUID *class_, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Class_Registry_PropertyW( GUID *class_, ULONG property, ULONG *type, void *buffer, ULONG *len, ULONG flags, HMACHINE machine );
 #define                CM_Get_Class_Registry_Property WINELIB_NAME_AW(CM_Get_Class_Registry_Property)
 CMAPI CONFIGRET WINAPI CM_Get_Depth( ULONG *depth, DEVINST node, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Get_Depth_Ex( ULONG *depth, DEVINST node, ULONG flags, HMACHINE machine );
@@ -446,17 +446,17 @@ CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_Alias_ExW( const WCHAR *iface, GU
 CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_AliasA( const char *iface, GUID *alias_guid, char *alias_iface, ULONG *len, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_AliasW( const WCHAR *iface, GUID *alias_guid, WCHAR *alias_iface, ULONG *len, ULONG flags );
 #define                CM_Get_Device_Interface_Alias WINELIB_NAME_AW(CM_Get_Device_Interface_Alias)
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_ExA( GUID *class, DEVINSTID_A instance_id, char *buffer, ULONG len, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_ExW( GUID *class, DEVINSTID_W instance_id, WCHAR *buffer, ULONG len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_ExA( GUID *class_, DEVINSTID_A instance_id, char *buffer, ULONG len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_ExW( GUID *class_, DEVINSTID_W instance_id, WCHAR *buffer, ULONG len, ULONG flags, HMACHINE machine );
 #define                CM_Get_Device_Interface_List_Ex WINELIB_NAME_AW(CM_Get_Device_Interface_List_Ex)
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA( ULONG *len, GUID *class, DEVINSTID_A instance_id, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExW( ULONG *len, GUID *class, DEVINSTID_W instance_id, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExA( ULONG *len, GUID *class_, DEVINSTID_A instance_id, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_Size_ExW( ULONG *len, GUID *class_, DEVINSTID_W instance_id, ULONG flags, HMACHINE machine );
 #define                CM_Get_Device_Interface_List_Size_Ex WINELIB_NAME_AW(CM_Get_Device_Interface_List_Size_Ex)
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA( ULONG *len, GUID *class, DEVINSTID_A instance_id, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeW( ULONG *len, GUID *class, DEVINSTID_W instance_id, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeA( ULONG *len, GUID *class_, DEVINSTID_A instance_id, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_List_SizeW( ULONG *len, GUID *class_, DEVINSTID_W instance_id, ULONG flags );
 #define                CM_Get_Device_Interface_List_Size WINELIB_NAME_AW(CM_Get_Device_Interface_List_Size)
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_ListA( GUID *class, DEVINSTID_A instance_id, char *buffer, ULONG len, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_ListW( GUID *class, DEVINSTID_W instance_id, WCHAR *buffer, ULONG len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_ListA( GUID *class_, DEVINSTID_A instance_id, char *buffer, ULONG len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_ListW( GUID *class_, DEVINSTID_W instance_id, WCHAR *buffer, ULONG len, ULONG flags );
 #define                CM_Get_Device_Interface_List WINELIB_NAME_AW(CM_Get_Device_Interface_List)
 CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_Property_ExW( const WCHAR *iface, const DEVPROPKEY *key, DEVPROPTYPE *type, BYTE *buffer, ULONG *size, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Get_Device_Interface_Property_Keys_ExW( const WCHAR *iface, DEVPROPKEY *keys, ULONG *count, ULONG flags, HMACHINE machine );
@@ -535,11 +535,11 @@ CMAPI CONFIGRET WINAPI CM_Modify_Res_Des_Ex( RES_DES *new_desc, RES_DES old_desc
 CMAPI CONFIGRET WINAPI CM_Move_DevNode( DEVINST node_src, DEVINST node_dst, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Move_DevNode_Ex( DEVINST node_src, DEVINST node_dst, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Next_Range( RANGE_ELEMENT *element, DWORDLONG *start, DWORDLONG *end, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Open_Class_Key_ExA( GUID *class, const char *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Open_Class_Key_ExW( GUID *class, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Open_Class_Key_ExA( GUID *class_, const char *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Open_Class_Key_ExW( GUID *class_, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine );
 #define                CM_Open_Class_Key_Ex WINELIB_NAME_AW(CM_Open_Class_Key_Ex)
-CMAPI CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class, const char *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Open_Class_KeyW( GUID *class, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Open_Class_KeyA( GUID *class_, const char *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Open_Class_KeyW( GUID *class_, const WCHAR *name, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags );
 #define                CM_Open_Class_Key WINELIB_NAME_AW(CM_Open_Class_Key)
 CMAPI CONFIGRET WINAPI CM_Open_Device_Interface_Key_ExA( const char *iface, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Open_Device_Interface_Key_ExW( const WCHAR *iface, REGSAM access, REGDISPOSITION disposition, HKEY *hkey, ULONG flags, HMACHINE machine );
@@ -566,11 +566,11 @@ CMAPI CONFIGRET WINAPI CM_Reenumerate_DevNode( DEVINST node, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Reenumerate_DevNode_Ex( DEVINST node, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Register_Device_Driver( DEVINST node, ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Register_Device_Driver_Ex( DEVINST node, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Register_Device_Interface_ExA( DEVINST node, GUID *class, const char *reference, char *iface, ULONG *len, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Register_Device_Interface_ExW( DEVINST node, GUID *class, const WCHAR *reference, WCHAR *iface, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Register_Device_Interface_ExA( DEVINST node, GUID *class_, const char *reference, char *iface, ULONG *len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Register_Device_Interface_ExW( DEVINST node, GUID *class_, const WCHAR *reference, WCHAR *iface, ULONG *len, ULONG flags, HMACHINE machine );
 #define                CM_Register_Device_Interface_Ex WINELIB_NAME_AW(CM_Register_Device_Interface_Ex)
-CMAPI CONFIGRET WINAPI CM_Register_Device_InterfaceA( DEVINST node, GUID *class, const char *reference, char *iface, ULONG *len, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Register_Device_InterfaceW( DEVINST node, GUID *class, const WCHAR *reference, WCHAR *iface, ULONG *len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Register_Device_InterfaceA( DEVINST node, GUID *class_, const char *reference, char *iface, ULONG *len, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Register_Device_InterfaceW( DEVINST node, GUID *class_, const WCHAR *reference, WCHAR *iface, ULONG *len, ULONG flags );
 #define                CM_Register_Device_Interface WINELIB_NAME_AW(CM_Register_Device_Interface)
 CMAPI CONFIGRET WINAPI CM_Register_Notification( CM_NOTIFY_FILTER *filter, void *context, PCM_NOTIFY_CALLBACK callback, HCMNOTIFICATION *notify );
 CMAPI CONFIGRET WINAPI CM_Remove_SubTree( DEVINST ancestor, ULONG flags );
@@ -585,10 +585,10 @@ CMAPI CONFIGRET WINAPI CM_Request_Eject_PC(void);
 CMAPI CONFIGRET WINAPI CM_Request_Eject_PC_Ex( HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Run_Detection( ULONG flags );
 CMAPI CONFIGRET WINAPI CM_Run_Detection_Ex( ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Set_Class_Property_ExW( const GUID *class, const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buffer, ULONG size, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Set_Class_PropertyW( const GUID *class, const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buffer, ULONG size, ULONG flags );
-CMAPI CONFIGRET WINAPI CM_Set_Class_Registry_PropertyA( GUID *class, ULONG property, const void *buffer, ULONG len, ULONG flags, HMACHINE machine );
-CMAPI CONFIGRET WINAPI CM_Set_Class_Registry_PropertyW( GUID *class, ULONG property, const void *buffer, ULONG len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Set_Class_Property_ExW( const GUID *class_, const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buffer, ULONG size, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Set_Class_PropertyW( const GUID *class_, const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buffer, ULONG size, ULONG flags );
+CMAPI CONFIGRET WINAPI CM_Set_Class_Registry_PropertyA( GUID *class_, ULONG property, const void *buffer, ULONG len, ULONG flags, HMACHINE machine );
+CMAPI CONFIGRET WINAPI CM_Set_Class_Registry_PropertyW( GUID *class_, ULONG property, const void *buffer, ULONG len, ULONG flags, HMACHINE machine );
 #define                CM_Set_Class_Registry_Property WINELIB_NAME_AW(CM_Set_Class_Registry_Property)
 CMAPI CONFIGRET WINAPI CM_Set_Device_Interface_Property_ExW( const WCHAR *iface, const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buffer, ULONG size, ULONG flags, HMACHINE machine );
 CMAPI CONFIGRET WINAPI CM_Set_Device_Interface_PropertyW( const WCHAR *iface, const DEVPROPKEY *key, DEVPROPTYPE type, const BYTE *buffer, ULONG size, ULONG flags );
diff --git a/include/compressapi.h b/include/compressapi.h
new file mode 100644
index 000000000000..a23d65444d66
--- /dev/null
+++ b/include/compressapi.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2026 Chris Kadar
+ *
+ * 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 __WINE_COMPRESSAPI_H
+#define __WINE_COMPRESSAPI_H
+
+#include <windef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**********************************************************************/
+
+DECLARE_HANDLE(COMPRESSOR_HANDLE);
+DECLARE_HANDLE(DECOMPRESSOR_HANDLE);
+
+/**********************************************************************/
+
+typedef void* (CALLBACK *PFN_COMPRESS_ALLOCATE)(void *, SIZE_T);
+typedef void (CALLBACK *PFN_COMPRESS_FREE)(void *, void *);
+
+typedef struct
+{
+    PFN_COMPRESS_ALLOCATE Allocate;
+    PFN_COMPRESS_FREE Free;
+    void *UserContext;
+} COMPRESS_ALLOCATION_ROUTINES;
+
+/**********************************************************************/
+
+#define COMPRESS_ALGORITHM_NULL         0
+#define COMPRESS_ALGORITHM_INVALID      1
+#define COMPRESS_ALGORITHM_MSZIP        2
+#define COMPRESS_ALGORITHM_XPRESS       3
+#define COMPRESS_ALGORITHM_XPRESS_HUFF  4
+#define COMPRESS_ALGORITHM_LZMS         5
+
+/**********************************************************************/
+
+BOOL WINAPI CreateCompressor( DWORD, COMPRESS_ALLOCATION_ROUTINES*, COMPRESSOR_HANDLE* );
+BOOL WINAPI Compress( COMPRESSOR_HANDLE, const VOID*, SIZE_T, VOID*, SIZE_T, SIZE_T* );
+BOOL WINAPI CloseCompressor( COMPRESSOR_HANDLE );
+
+BOOL WINAPI CreateDecompressor( DWORD, COMPRESS_ALLOCATION_ROUTINES*, DECOMPRESSOR_HANDLE* );
+BOOL WINAPI Decompress( DECOMPRESSOR_HANDLE, const VOID*, SIZE_T, VOID*, SIZE_T, SIZE_T* );
+BOOL WINAPI CloseDecompressor( DECOMPRESSOR_HANDLE );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WINE_COMPRESSAPI_H */
diff --git a/include/config.h.in b/include/config.h.in
index 8b8d7a465049..0343acc8d36a 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -144,9 +144,6 @@
 /* Define to 1 if you have the <libudev.h> header file. */
 #undef HAVE_LIBUDEV_H
 
-/* Define to 1 if you have the 'unwind' library (-lunwind). */
-#undef HAVE_LIBUNWIND
-
 /* Define if we have the wayland-egl development environment */
 #undef HAVE_LIBWAYLAND_EGL
 
diff --git a/include/ddk/hidport.h b/include/ddk/hidport.h
index bd3ddb3f2a57..6574aba75bb6 100644
--- a/include/ddk/hidport.h
+++ b/include/ddk/hidport.h
@@ -68,6 +68,14 @@ typedef struct _HID_DESCRIPTOR
 #define HID_HID_DESCRIPTOR_TYPE 0x21
 #define HID_REPORT_DESCRIPTOR_TYPE 0x22
 
+/*
+ * String IDs used with IOCTL_HID_GET_STRING.
+ * These values match the string field offsets in chapter 9 of the USB spec.
+ */
+#define HID_STRING_ID_IMANUFACTURER 14
+#define HID_STRING_ID_IPRODUCT      15
+#define HID_STRING_ID_ISERIALNUMBER 16
+
 #define IOCTL_HID_GET_DEVICE_DESCRIPTOR          HID_CTL_CODE(0)
 #define IOCTL_HID_GET_REPORT_DESCRIPTOR          HID_CTL_CODE(1)
 #define IOCTL_HID_READ_REPORT                    HID_CTL_CODE(2)
diff --git a/include/ddk/hidtypes.h b/include/ddk/hidtypes.h
index dfd1061de18a..8e6f76955e97 100644
--- a/include/ddk/hidtypes.h
+++ b/include/ddk/hidtypes.h
@@ -20,9 +20,6 @@
 
 typedef enum _HID_STRING_TYPE {
     HID_STRING_INDEXED = 0,
-    HID_STRING_ID_IMANUFACTURER,
-    HID_STRING_ID_IPRODUCT,
-    HID_STRING_ID_ISERIALNUMBER,
     HID_STRING_MAX
 } HID_STRING_TYPE;
 
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 9bbba22d2feb..406870d8f067 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -1942,7 +1942,7 @@ NTSTATUS  WINAPI ZwEnumerateKey(HANDLE,ULONG,KEY_INFORMATION_CLASS,void *,DWORD,
 NTSTATUS  WINAPI ZwEnumerateValueKey(HANDLE,ULONG,KEY_VALUE_INFORMATION_CLASS,PVOID,ULONG,PULONG);
 NTSTATUS  WINAPI ZwFlushInstructionCache(HANDLE,LPCVOID,SIZE_T);
 NTSTATUS  WINAPI ZwFlushKey(HANDLE);
-NTSTATUS  WINAPI ZwFlushVirtualMemory(HANDLE,LPCVOID*,SIZE_T*,ULONG);
+NTSTATUS  WINAPI ZwFlushVirtualMemory(HANDLE,LPCVOID*,SIZE_T*,IO_STATUS_BLOCK*);
 NTSTATUS  WINAPI ZwFreeVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG);
 NTSTATUS  WINAPI ZwFsControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG);
 NTSTATUS  WINAPI ZwInitiatePowerAction(POWER_ACTION,SYSTEM_POWER_STATE,ULONG,BOOLEAN);
diff --git a/include/memoryapi.h b/include/memoryapi.h
index 2cfcdd5a273a..79c01aaed239 100644
--- a/include/memoryapi.h
+++ b/include/memoryapi.h
@@ -14,6 +14,13 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#ifndef _MEMORY_API_H_
+#define _MEMORY_API_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef enum WIN32_MEMORY_INFORMATION_CLASS
 {
     MemoryRegionInfo
@@ -44,3 +51,9 @@ typedef struct WIN32_MEMORY_REGION_INFORMATION
 WINBASEAPI HANDLE WINAPI CreateFileMapping2(HANDLE,LPSECURITY_ATTRIBUTES,ULONG,ULONG,ULONG,ULONG64,const WCHAR*,MEM_EXTENDED_PARAMETER*,ULONG);
 WINBASEAPI DWORD  WINAPI DiscardVirtualMemory(void *addr, SIZE_T size);
 WINBASEAPI BOOL   WINAPI QueryVirtualMemoryInformation(HANDLE process,const void *addr, WIN32_MEMORY_INFORMATION_CLASS info_class, void *info, SIZE_T size, SIZE_T *ret_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MEMORY_API_H_ */
diff --git a/include/mfidl.idl b/include/mfidl.idl
index e7258f26ed6f..e1f539630826 100644
--- a/include/mfidl.idl
+++ b/include/mfidl.idl
@@ -739,6 +739,7 @@ cpp_quote("HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample);")
 cpp_quote("HRESULT WINAPI MFRequireProtectedEnvironment(IMFPresentationDescriptor *pd);")
 cpp_quote("HRESULT WINAPI MFTranscodeGetAudioOutputAvailableTypes(REFGUID subtype, DWORD flags,")
 cpp_quote("        IMFAttributes *config, IMFCollection **types);")
+cpp_quote("HRESULT WINAPI MFCreateDeviceSource(IMFAttributes *, IMFMediaSource **);")
 
 typedef enum _MFMEDIASOURCE_CHARACTERISTICS
 {
diff --git a/include/mfobjects.idl b/include/mfobjects.idl
index 33b4bbad008b..7dbdc5796aca 100644
--- a/include/mfobjects.idl
+++ b/include/mfobjects.idl
@@ -88,6 +88,9 @@ enum MF_ATTRIBUTE_SERIALIZE_OPTIONS {
     MF_ATTRIBUTE_SERIALIZE_UNKNOWN_BYREF = 0x00000001
 };
 
+cpp_quote( "STDAPI MFSerializeAttributesToStream(IMFAttributes *, DWORD, IStream *);")
+cpp_quote( "STDAPI MFDeserializeAttributesFromStream(IMFAttributes *, DWORD, IStream *);")
+
 [
     object,
     uuid(045fa593-8799-42b8-bc8d-8968c6453507),
diff --git a/include/msvcrt/stdlib.h b/include/msvcrt/stdlib.h
index 057fdbb94ac5..0072b0d5882a 100644
--- a/include/msvcrt/stdlib.h
+++ b/include/msvcrt/stdlib.h
@@ -39,6 +39,7 @@ typedef struct
 #define _MAX_DIR            _MAX_FNAME
 #define _MAX_EXT            _MAX_FNAME
 #define _MAX_PATH           260
+#define _MAX_ENV            32767
 #endif
 
 /* Make the secure string functions (names end in "_s") truncate their output */
diff --git a/include/roerrorapi.h b/include/roerrorapi.h
index 0bab6651d2b8..f154c679418c 100644
--- a/include/roerrorapi.h
+++ b/include/roerrorapi.h
@@ -23,6 +23,10 @@
 #include <restrictederrorinfo.h>
 #include <rpc.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef enum
 {
     RO_ERROR_REPORTING_NONE                 = 0x0,
@@ -42,4 +46,8 @@ HRESULT WINAPI RoReportUnhandledError(IRestrictedErrorInfo *info);
 HRESULT WINAPI RoSetErrorReportingFlags(UINT32 flags);
 HRESULT WINAPI SetRestrictedErrorInfo(IRestrictedErrorInfo *info);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _ROERROR_H */
diff --git a/include/sqlucode.h b/include/sqlucode.h
index 1a17f3af63f8..e36b9269e8eb 100644
--- a/include/sqlucode.h
+++ b/include/sqlucode.h
@@ -60,7 +60,7 @@ SQLRETURN WINAPI SQLDataSourcesW(SQLHENV,SQLUSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLS
 SQLRETURN WINAPI SQLDescribeColW(SQLHSTMT,SQLUSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*,SQLSMALLINT*,SQLULEN*,
                                  SQLSMALLINT*,SQLSMALLINT*);
 
-SQLRETURN WINAPI SQLDriverConnectW(SQLHDBC,SQLHWND,WCHAR*,SQLSMALLINT,WCHAR*,SQLSMALLINT,SQLSMALLINT*,SQLUSMALLINT);
+SQLRETURN WINAPI SQLDriverConnectW(SQLHDBC,SQLHWND,SQLWCHAR*,SQLSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*,SQLUSMALLINT);
 
 SQLRETURN WINAPI SQLDriversW(SQLHENV,SQLUSMALLINT,SQLWCHAR*,SQLSMALLINT,SQLSMALLINT*,SQLWCHAR*,SQLSMALLINT,
                              SQLSMALLINT*);
diff --git a/include/winbase.h b/include/winbase.h
index d02b2bd9b2f6..b4d7a0ef6a26 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -1473,6 +1473,7 @@ WINBASEAPI ATOM        WINAPI AddAtomW(LPCWSTR);
 #define                       AddAtom WINELIB_NAME_AW(AddAtom)
 WINADVAPI  BOOL        WINAPI AddAuditAccessAce(PACL,DWORD,DWORD,PSID,BOOL,BOOL);
 WINADVAPI  BOOL        WINAPI AddAuditAccessAceEx(PACL,DWORD,DWORD,DWORD,PSID,BOOL,BOOL);
+WINADVAPI  BOOL        WINAPI AddConditionalAce(PACL,DWORD,DWORD,UCHAR,DWORD,PSID,PWCHAR,DWORD *);
 WINADVAPI  BOOL        WINAPI AddMandatoryAce(PACL,DWORD,DWORD,DWORD,PSID);
 WINBASEAPI VOID        WINAPI AddRefActCtx(HANDLE);
 WINBASEAPI PVOID       WINAPI AddVectoredExceptionHandler(ULONG,PVECTORED_EXCEPTION_HANDLER);
diff --git a/include/wincrypt.h b/include/wincrypt.h
index 9c42586700fb..6ee077cd5526 100644
--- a/include/wincrypt.h
+++ b/include/wincrypt.h
@@ -1942,6 +1942,7 @@ static const WCHAR MS_ENH_RSA_AES_PROV_XP_W[] = { 'M','i','c','r','o','s','o','f
 /* Key Specs*/
 #define AT_KEYEXCHANGE          1
 #define AT_SIGNATURE            2
+#define CERT_NCRYPT_KEY_SPEC    0xffffffff
 
 /* Provider Types */
 #define PROV_RSA_FULL             1
diff --git a/include/windows.graphics.directx.direct3d11.interop.idl b/include/windows.graphics.directx.direct3d11.interop.idl
new file mode 100644
index 000000000000..b5ca72e40d60
--- /dev/null
+++ b/include/windows.graphics.directx.direct3d11.interop.idl
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+
+#ifdef __WIDL__
+#pragma winrt ns_prefix
+#endif
+
+import "dxgi.idl";
+import "inspectable.idl";
+import "windows.graphics.directx.direct3d11.idl";
+
+namespace Windows.Graphics.DirectX.Direct3D11 {
+    HRESULT CreateDirect3D11DeviceFromDXGIDevice([in] IDXGIDevice* dxgiDevice, [out] IInspectable** graphicsDevice);
+
+    [
+        uuid(A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1)
+    ]
+    interface IDirect3DDxgiInterfaceAccess : IUnknown {
+        HRESULT GetInterface([in] REFIID iid, [out, iid_is(iid)] void **object);
+    };
+}
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index dc1ceeb142e6..85f636dd995f 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2211,10 +2211,13 @@ struct get_mapping_info_reply
     unsigned int flags;
     obj_handle_t shared_file;
     data_size_t  name_len;
+    data_size_t  ver_len;
     data_size_t  total;
     /* VARARG(image,pe_image_info); */
+    /* VARARG(version,version_res,ver_len); */
     /* VARARG(name,unicode_str,name_len); */
     /* VARARG(exp_name,string); */
+    char __pad_36[4];
 };
 
 
@@ -4243,12 +4246,12 @@ struct get_thread_input_reply
 
 
 
-struct get_last_input_time_request
+struct set_user_input_time_request
 {
     struct request_header __header;
-    char __pad_12[4];
+    int          set;
 };
-struct get_last_input_time_reply
+struct set_user_input_time_reply
 {
     struct reply_header __header;
     unsigned int time;
@@ -6350,7 +6353,7 @@ enum request
     REQ_unregister_hotkey,
     REQ_attach_thread_input,
     REQ_get_thread_input,
-    REQ_get_last_input_time,
+    REQ_set_user_input_time,
     REQ_get_key_state,
     REQ_set_key_state,
     REQ_set_foreground_window,
@@ -6663,7 +6666,7 @@ union generic_request
     struct unregister_hotkey_request unregister_hotkey_request;
     struct attach_thread_input_request attach_thread_input_request;
     struct get_thread_input_request get_thread_input_request;
-    struct get_last_input_time_request get_last_input_time_request;
+    struct set_user_input_time_request set_user_input_time_request;
     struct get_key_state_request get_key_state_request;
     struct set_key_state_request set_key_state_request;
     struct set_foreground_window_request set_foreground_window_request;
@@ -6974,7 +6977,7 @@ union generic_reply
     struct unregister_hotkey_reply unregister_hotkey_reply;
     struct attach_thread_input_reply attach_thread_input_reply;
     struct get_thread_input_reply get_thread_input_reply;
-    struct get_last_input_time_reply get_last_input_time_reply;
+    struct set_user_input_time_reply set_user_input_time_reply;
     struct get_key_state_reply get_key_state_reply;
     struct set_key_state_reply set_key_state_reply;
     struct set_foreground_window_reply set_foreground_window_reply;
@@ -7093,6 +7096,6 @@ union generic_reply
     struct d3dkmt_mutex_release_reply d3dkmt_mutex_release_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 930
+#define SERVER_PROTOCOL_VERSION 931
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/wine/vulkan.h b/include/wine/vulkan.h
index 67b8cbd61b53..b0e3fe8e4415 100644
--- a/include/wine/vulkan.h
+++ b/include/wine/vulkan.h
@@ -121,7 +121,7 @@ struct OH_NativeBuffer;
     #endif
 #endif
 #define VK_FALSE 0
-#define VK_HEADER_VERSION 346
+#define VK_HEADER_VERSION 347
 #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
@@ -642,6 +642,8 @@ typedef void* VkRemoteAddressNV;
 #define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
 #define VK_KHR_DEVICE_ADDRESS_COMMANDS_EXTENSION_NAME "VK_KHR_device_address_commands"
 #define VK_KHR_DEVICE_ADDRESS_COMMANDS_SPEC_VERSION 1
+#define VK_KHR_DEVICE_FAULT_EXTENSION_NAME "VK_KHR_device_fault"
+#define VK_KHR_DEVICE_FAULT_SPEC_VERSION 1
 #define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation"
 #define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1
 #define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group"
@@ -776,12 +778,16 @@ typedef void* VkRemoteAddressNV;
 #define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 14
 #define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_EXTENSION_NAME "VK_KHR_separate_depth_stencil_layouts"
 #define VK_KHR_SEPARATE_DEPTH_STENCIL_LAYOUTS_SPEC_VERSION 1
+#define VK_KHR_SHADER_ABORT_EXTENSION_NAME "VK_KHR_shader_abort"
+#define VK_KHR_SHADER_ABORT_SPEC_VERSION 1
 #define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
 #define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
 #define VK_KHR_SHADER_BFLOAT16_EXTENSION_NAME "VK_KHR_shader_bfloat16"
 #define VK_KHR_SHADER_BFLOAT16_SPEC_VERSION 1
 #define VK_KHR_SHADER_CLOCK_EXTENSION_NAME "VK_KHR_shader_clock"
 #define VK_KHR_SHADER_CLOCK_SPEC_VERSION 1
+#define VK_KHR_SHADER_CONSTANT_DATA_EXTENSION_NAME "VK_KHR_shader_constant_data"
+#define VK_KHR_SHADER_CONSTANT_DATA_SPEC_VERSION 1
 #define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
 #define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
 #define VK_KHR_SHADER_EXPECT_ASSUME_EXTENSION_NAME "VK_KHR_shader_expect_assume"
@@ -1218,6 +1224,7 @@ typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFl
 typedef VkFlags VkDeviceAddressBindingFlagsEXT;
 typedef VkFlags VkDeviceCreateFlags;
 typedef VkFlags VkDeviceDiagnosticsConfigFlagsNV;
+typedef VkFlags VkDeviceFaultFlagsKHR;
 typedef VkFlags VkDeviceGroupPresentModeFlagsKHR;
 typedef VkFlags VkEventCreateFlags;
 typedef VkFlags VkExternalFenceFeatureFlags;
@@ -2849,23 +2856,44 @@ typedef enum VkDeviceDiagnosticsConfigFlagBitsNV
     VK_DEVICE_DIAGNOSTICS_CONFIG_FLAG_BITS_NV_MAX_ENUM = 0x7fffffff,
 } VkDeviceDiagnosticsConfigFlagBitsNV;
 
-typedef enum VkDeviceFaultAddressTypeEXT
-{
-    VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = 0,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = 1,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = 2,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = 3,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = 4,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = 5,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = 6,
-    VK_DEVICE_FAULT_ADDRESS_TYPE_EXT_MAX_ENUM = 0x7fffffff,
-} VkDeviceFaultAddressTypeEXT;
-
-typedef enum VkDeviceFaultVendorBinaryHeaderVersionEXT
-{
-    VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = 1,
-    VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_EXT_MAX_ENUM = 0x7fffffff,
-} VkDeviceFaultVendorBinaryHeaderVersionEXT;
+typedef enum VkDeviceFaultAddressTypeKHR
+{
+    VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_KHR = 0,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_KHR = 1,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_KHR = 2,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_KHR = 3,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_KHR = 4,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_KHR = 5,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_KHR = 6,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_KHR_MAX_ENUM = 0x7fffffff,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_KHR,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_KHR,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_KHR,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_KHR,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_KHR,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_KHR,
+    VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT = VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_KHR,
+} VkDeviceFaultAddressTypeKHR;
+typedef VkDeviceFaultAddressTypeKHR VkDeviceFaultAddressTypeEXT;
+
+typedef enum VkDeviceFaultFlagBitsKHR
+{
+    VK_DEVICE_FAULT_FLAG_DEVICE_LOST_KHR = 0x00000001,
+    VK_DEVICE_FAULT_FLAG_MEMORY_ADDRESS_KHR = 0x00000002,
+    VK_DEVICE_FAULT_FLAG_INSTRUCTION_ADDRESS_KHR = 0x00000004,
+    VK_DEVICE_FAULT_FLAG_VENDOR_KHR = 0x00000008,
+    VK_DEVICE_FAULT_FLAG_WATCHDOG_TIMEOUT_KHR = 0x00000010,
+    VK_DEVICE_FAULT_FLAG_OVERFLOW_KHR = 0x00000020,
+    VK_DEVICE_FAULT_FLAG_BITS_KHR_MAX_ENUM = 0x7fffffff,
+} VkDeviceFaultFlagBitsKHR;
+
+typedef enum VkDeviceFaultVendorBinaryHeaderVersionKHR
+{
+    VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_KHR = 1,
+    VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_KHR_MAX_ENUM = 0x7fffffff,
+    VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_EXT = VK_DEVICE_FAULT_VENDOR_BINARY_HEADER_VERSION_ONE_KHR,
+} VkDeviceFaultVendorBinaryHeaderVersionKHR;
+typedef VkDeviceFaultVendorBinaryHeaderVersionKHR VkDeviceFaultVendorBinaryHeaderVersionEXT;
 
 typedef enum VkDeviceGroupPresentModeFlagBitsKHR
 {
@@ -5924,9 +5952,13 @@ typedef enum VkStructureType
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR = 1000226004,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_2_AMD = 1000227000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD = 1000229000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CONSTANT_DATA_FEATURES_KHR = 1000231000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES = 1000232000,
     VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO = 1000232001,
     VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO = 1000232002,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_FEATURES_KHR = 1000233000,
+    VK_STRUCTURE_TYPE_DEVICE_FAULT_SHADER_ABORT_MESSAGE_INFO_KHR = 1000233001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ABORT_PROPERTIES_KHR = 1000233002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_IMAGE_ATOMIC_INT64_FEATURES_EXT = 1000234000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_QUAD_CONTROL_FEATURES_KHR = 1000235000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT = 1000237000,
@@ -6480,6 +6512,10 @@ typedef enum VkStructureType
     VK_STRUCTURE_TYPE_INDIRECT_EXECUTION_SET_SHADER_LAYOUT_INFO_EXT = 1000572012,
     VK_STRUCTURE_TYPE_GENERATED_COMMANDS_PIPELINE_INFO_EXT = 1000572013,
     VK_STRUCTURE_TYPE_GENERATED_COMMANDS_SHADER_INFO_EXT = 1000572014,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_KHR = 1000573000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_PROPERTIES_KHR = 1000573001,
+    VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_KHR = 1000573002,
+    VK_STRUCTURE_TYPE_DEVICE_FAULT_DEBUG_INFO_KHR = 1000573003,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_8_FEATURES_KHR = 1000574000,
     VK_STRUCTURE_TYPE_MEMORY_BARRIER_ACCESS_FLAGS_3_KHR = 1000574002,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_ALIGNMENT_CONTROL_FEATURES_MESA = 1000575000,
@@ -9838,19 +9874,21 @@ typedef struct VkDescriptorUpdateTemplateEntry
 } VkDescriptorUpdateTemplateEntry;
 typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR;
 
-typedef struct VkDeviceFaultAddressInfoEXT
+typedef struct VkDeviceFaultAddressInfoKHR
 {
-    VkDeviceFaultAddressTypeEXT addressType;
+    VkDeviceFaultAddressTypeKHR addressType;
     VkDeviceAddress WINE_VK_ALIGN(8) reportedAddress;
     VkDeviceSize WINE_VK_ALIGN(8) addressPrecision;
-} VkDeviceFaultAddressInfoEXT;
+} VkDeviceFaultAddressInfoKHR;
+typedef VkDeviceFaultAddressInfoKHR VkDeviceFaultAddressInfoEXT;
 
-typedef struct VkDeviceFaultVendorInfoEXT
+typedef struct VkDeviceFaultVendorInfoKHR
 {
     char description[VK_MAX_DESCRIPTION_SIZE];
     uint64_t WINE_VK_ALIGN(8) vendorFaultCode;
     uint64_t WINE_VK_ALIGN(8) vendorFaultData;
-} VkDeviceFaultVendorInfoEXT;
+} VkDeviceFaultVendorInfoKHR;
+typedef VkDeviceFaultVendorInfoKHR VkDeviceFaultVendorInfoEXT;
 
 typedef struct VkDeviceMemoryCopyKHR
 {
@@ -12517,20 +12555,48 @@ typedef struct VkDeviceFaultCountsEXT
     VkDeviceSize WINE_VK_ALIGN(8) vendorBinarySize;
 } VkDeviceFaultCountsEXT;
 
+typedef struct VkDeviceFaultDebugInfoKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    uint32_t vendorBinarySize;
+    void *pVendorBinaryData;
+} VkDeviceFaultDebugInfoKHR;
+
 typedef struct VkDeviceFaultInfoEXT
 {
     VkStructureType sType;
     void *pNext;
     char description[VK_MAX_DESCRIPTION_SIZE];
-    VkDeviceFaultAddressInfoEXT *pAddressInfos;
-    VkDeviceFaultVendorInfoEXT *pVendorInfos;
+    VkDeviceFaultAddressInfoKHR *pAddressInfos;
+    VkDeviceFaultVendorInfoKHR *pVendorInfos;
     void *pVendorBinaryData;
 } VkDeviceFaultInfoEXT;
 
-typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneEXT
+typedef struct VkDeviceFaultInfoKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    VkDeviceFaultFlagsKHR flags;
+    uint64_t WINE_VK_ALIGN(8) groupId;
+    char description[VK_MAX_DESCRIPTION_SIZE];
+    VkDeviceFaultAddressInfoKHR WINE_VK_ALIGN(8) faultAddressInfo;
+    VkDeviceFaultAddressInfoKHR WINE_VK_ALIGN(8) instructionAddressInfo;
+    VkDeviceFaultVendorInfoKHR WINE_VK_ALIGN(8) vendorInfo;
+} VkDeviceFaultInfoKHR;
+
+typedef struct VkDeviceFaultShaderAbortMessageInfoKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    uint64_t WINE_VK_ALIGN(8) messageDataSize;
+    void *pMessageData;
+} VkDeviceFaultShaderAbortMessageInfoKHR;
+
+typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneKHR
 {
     uint32_t headerSize;
-    VkDeviceFaultVendorBinaryHeaderVersionEXT headerVersion;
+    VkDeviceFaultVendorBinaryHeaderVersionKHR headerVersion;
     uint32_t vendorID;
     uint32_t deviceID;
     uint32_t driverVersion;
@@ -12540,7 +12606,8 @@ typedef struct VkDeviceFaultVendorBinaryHeaderVersionOneEXT
     uint32_t engineNameOffset;
     uint32_t engineVersion;
     uint32_t apiVersion;
-} VkDeviceFaultVendorBinaryHeaderVersionOneEXT;
+} VkDeviceFaultVendorBinaryHeaderVersionOneKHR;
+typedef VkDeviceFaultVendorBinaryHeaderVersionOneKHR VkDeviceFaultVendorBinaryHeaderVersionOneEXT;
 
 typedef struct VkDeviceGroupBindSparseInfo
 {
@@ -15038,6 +15105,23 @@ typedef struct VkPhysicalDeviceFaultFeaturesEXT
     VkBool32 deviceFaultVendorBinary;
 } VkPhysicalDeviceFaultFeaturesEXT;
 
+typedef struct VkPhysicalDeviceFaultFeaturesKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    VkBool32 deviceFault;
+    VkBool32 deviceFaultVendorBinary;
+    VkBool32 deviceFaultReportMasked;
+    VkBool32 deviceFaultDeviceLostOnMasked;
+} VkPhysicalDeviceFaultFeaturesKHR;
+
+typedef struct VkPhysicalDeviceFaultPropertiesKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    uint32_t maxDeviceFaultCount;
+} VkPhysicalDeviceFaultPropertiesKHR;
+
 typedef struct VkPhysicalDeviceFeatures2
 {
     VkStructureType sType;
@@ -16501,6 +16585,20 @@ typedef struct VkPhysicalDeviceShader64BitIndexingFeaturesEXT
     VkBool32 shader64BitIndexing;
 } VkPhysicalDeviceShader64BitIndexingFeaturesEXT;
 
+typedef struct VkPhysicalDeviceShaderAbortFeaturesKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    VkBool32 shaderAbort;
+} VkPhysicalDeviceShaderAbortFeaturesKHR;
+
+typedef struct VkPhysicalDeviceShaderAbortPropertiesKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    uint64_t WINE_VK_ALIGN(8) maxShaderAbortMessageSize;
+} VkPhysicalDeviceShaderAbortPropertiesKHR;
+
 typedef struct VkPhysicalDeviceShaderAtomicFloat16VectorFeaturesNV
 {
     VkStructureType sType;
@@ -16570,6 +16668,13 @@ typedef struct VkPhysicalDeviceShaderClockFeaturesKHR
     VkBool32 shaderDeviceClock;
 } VkPhysicalDeviceShaderClockFeaturesKHR;
 
+typedef struct VkPhysicalDeviceShaderConstantDataFeaturesKHR
+{
+    VkStructureType sType;
+    void *pNext;
+    VkBool32 shaderConstantData;
+} VkPhysicalDeviceShaderConstantDataFeaturesKHR;
+
 typedef struct VkPhysicalDeviceShaderCoreBuiltinsFeaturesARM
 {
     VkStructureType sType;
@@ -20617,7 +20722,9 @@ typedef void (VKAPI_PTR *PFN_vkGetDeviceAccelerationStructureCompatibilityKHR)(V
 typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirements)(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements);
 typedef void (VKAPI_PTR *PFN_vkGetDeviceBufferMemoryRequirementsKHR)(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements);
 typedef uint64_t (VKAPI_PTR *PFN_vkGetDeviceCombinedImageSamplerIndexNVX)(VkDevice device, uint64_t imageViewIndex, uint64_t samplerIndex);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultDebugInfoKHR)(VkDevice device, VkDeviceFaultDebugInfoKHR *pDebugInfo);
 typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultInfoEXT)(VkDevice device, VkDeviceFaultCountsEXT *pFaultCounts, VkDeviceFaultInfoEXT *pFaultInfo);
+typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceFaultReportsKHR)(VkDevice device, uint64_t timeout, uint32_t *pFaultCounts, VkDeviceFaultInfoKHR *pFaultInfo);
 typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeatures)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures);
 typedef void (VKAPI_PTR *PFN_vkGetDeviceGroupPeerMemoryFeaturesKHR)(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures);
 typedef VkResult (VKAPI_PTR *PFN_vkGetDeviceGroupPresentCapabilitiesKHR)(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities);
@@ -21354,7 +21461,9 @@ void VKAPI_CALL vkGetDeviceAccelerationStructureCompatibilityKHR(VkDevice device
 void VKAPI_CALL vkGetDeviceBufferMemoryRequirements(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements);
 void VKAPI_CALL vkGetDeviceBufferMemoryRequirementsKHR(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements);
 uint64_t VKAPI_CALL vkGetDeviceCombinedImageSamplerIndexNVX(VkDevice device, uint64_t imageViewIndex, uint64_t samplerIndex);
+VkResult VKAPI_CALL vkGetDeviceFaultDebugInfoKHR(VkDevice device, VkDeviceFaultDebugInfoKHR *pDebugInfo);
 VkResult VKAPI_CALL vkGetDeviceFaultInfoEXT(VkDevice device, VkDeviceFaultCountsEXT *pFaultCounts, VkDeviceFaultInfoEXT *pFaultInfo);
+VkResult VKAPI_CALL vkGetDeviceFaultReportsKHR(VkDevice device, uint64_t timeout, uint32_t *pFaultCounts, VkDeviceFaultInfoKHR *pFaultInfo);
 void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures);
 void VKAPI_CALL vkGetDeviceGroupPeerMemoryFeaturesKHR(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures);
 VkResult VKAPI_CALL vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities);
@@ -22066,7 +22175,9 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_FUNC(vkGetDeviceBufferMemoryRequirements) \
     USE_VK_FUNC(vkGetDeviceBufferMemoryRequirementsKHR) \
     USE_VK_FUNC(vkGetDeviceCombinedImageSamplerIndexNVX) \
+    USE_VK_FUNC(vkGetDeviceFaultDebugInfoKHR) \
     USE_VK_FUNC(vkGetDeviceFaultInfoEXT) \
+    USE_VK_FUNC(vkGetDeviceFaultReportsKHR) \
     USE_VK_FUNC(vkGetDeviceGroupPeerMemoryFeatures) \
     USE_VK_FUNC(vkGetDeviceGroupPeerMemoryFeaturesKHR) \
     USE_VK_FUNC(vkGetDeviceGroupPresentCapabilitiesKHR) \
@@ -22422,6 +22533,7 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_EXT(VK_KHR_depth_stencil_resolve) \
     USE_VK_EXT(VK_KHR_descriptor_update_template) \
     USE_VK_EXT(VK_KHR_device_address_commands) \
+    USE_VK_EXT(VK_KHR_device_fault) \
     USE_VK_EXT(VK_KHR_device_group) \
     USE_VK_EXT(VK_KHR_draw_indirect_count) \
     USE_VK_EXT(VK_KHR_driver_properties) \
@@ -22476,9 +22588,11 @@ VkResult VKAPI_CALL vkWriteSamplerDescriptorsEXT(VkDevice device, uint32_t sampl
     USE_VK_EXT(VK_KHR_sampler_mirror_clamp_to_edge) \
     USE_VK_EXT(VK_KHR_sampler_ycbcr_conversion) \
     USE_VK_EXT(VK_KHR_separate_depth_stencil_layouts) \
+    USE_VK_EXT(VK_KHR_shader_abort) \
     USE_VK_EXT(VK_KHR_shader_atomic_int64) \
     USE_VK_EXT(VK_KHR_shader_bfloat16) \
     USE_VK_EXT(VK_KHR_shader_clock) \
+    USE_VK_EXT(VK_KHR_shader_constant_data) \
     USE_VK_EXT(VK_KHR_shader_draw_parameters) \
     USE_VK_EXT(VK_KHR_shader_expect_assume) \
     USE_VK_EXT(VK_KHR_shader_float16_int8) \
diff --git a/include/wine/winebth.h b/include/wine/winebth.h
index 572be91bb451..c41f0362f55f 100644
--- a/include/wine/winebth.h
+++ b/include/wine/winebth.h
@@ -41,6 +41,9 @@
 /* Get all characteristics for a GATT service */
 #define IOCTL_WINEBTH_LE_DEVICE_GET_GATT_CHARACTERISTICS CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xc1, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
+/* Read the associated value for a GATT characteristic */
+#define IOCTL_WINEBTH_GATT_SERVICE_READ_CHARACTERISITIC_VALUE CTL_CODE(FILE_DEVICE_BLUETOOTH, 0xd0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
 DEFINE_GUID( GUID_WINEBTH_AUTHENTICATION_REQUEST, 0xca67235f, 0xf621, 0x4c27, 0x85, 0x65, 0xa4,
              0xd5, 0x5e, 0xa1, 0x26, 0xe8 );
 
@@ -93,6 +96,15 @@ struct winebth_le_device_get_gatt_characteristics_params
     BTH_LE_GATT_CHARACTERISTIC characteristics[0];
 };
 
+struct winebth_gatt_service_read_characterisitic_value_params
+{
+    BTH_LE_UUID uuid;
+    UINT16 handle;
+    unsigned int from_device : 1;
+    ULONG size;
+    BYTE buf[1];
+};
+
 #pragma pack(pop)
 
 #endif /* __WINEBTH_H__ */
diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h
index 9918ac68838d..cfb098adfb0c 100644
--- a/include/wine/wined3d.h
+++ b/include/wine/wined3d.h
@@ -2565,7 +2565,8 @@ HRESULT __cdecl wined3d_device_context_map(struct wined3d_device_context *contex
 void __cdecl wined3d_device_context_reset_state(struct wined3d_device_context *context);
 void __cdecl wined3d_device_context_resolve_sub_resource(struct wined3d_device_context *context,
         struct wined3d_resource *dst_resource, unsigned int dst_sub_resource_idx,
-        struct wined3d_resource *src_resource, unsigned int src_sub_resource_idx, enum wined3d_format_id format_id);
+        struct wined3d_resource *src_resource, unsigned int src_sub_resource_idx,
+        uint32_t flags, enum wined3d_format_id format_id);
 void __cdecl wined3d_device_context_set_blend_state(struct wined3d_device_context *context,
         struct wined3d_blend_state *state, const struct wined3d_color *blend_factor, unsigned int sample_mask);
 void __cdecl wined3d_device_context_set_constant_buffers(struct wined3d_device_context *context,
diff --git a/include/winevt.h b/include/winevt.h
index 25bd4efc20c6..92f9e409d16d 100644
--- a/include/winevt.h
+++ b/include/winevt.h
@@ -162,6 +162,7 @@ EVT_HANDLE WINAPI EvtSubscribe(EVT_HANDLE Session, HANDLE SignalEvent, LPCWSTR C
                                EVT_SUBSCRIBE_CALLBACK Callback, DWORD Flags);
 EVT_HANDLE WINAPI EvtOpenChannelConfig(EVT_HANDLE Session, LPCWSTR ChannelPath, DWORD Flags);
 BOOL WINAPI EvtSaveChannelConfig(EVT_HANDLE,DWORD);
+BOOL WINAPI EvtRender(EVT_HANDLE, EVT_HANDLE, DWORD, DWORD, void *, DWORD *, DWORD *);
 
 #ifdef __cplusplus
 } /* extern "C" */
diff --git a/include/winhttp.h b/include/winhttp.h
index 4ee599fc7da6..c8b081e2c0da 100644
--- a/include/winhttp.h
+++ b/include/winhttp.h
@@ -55,7 +55,8 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define ICU_REJECT_USERPWD   0x00004000
 
 /* flags for WinHttpOpen */
-#define WINHTTP_FLAG_ASYNC                  0x10000000
+#define WINHTTP_FLAG_ASYNC              0x10000000
+#define WINHTTP_FLAG_SECURE_DEFAULTS    0x30000000
 
 /* flags for WinHttpOpenRequest */
 #define WINHTTP_FLAG_ESCAPE_PERCENT         0x00000004
@@ -64,6 +65,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define WINHTTP_FLAG_ESCAPE_DISABLE_QUERY   0x00000080
 #define WINHTTP_FLAG_BYPASS_PROXY_CACHE     0x00000100
 #define WINHTTP_FLAG_REFRESH                WINHTTP_FLAG_BYPASS_PROXY_CACHE
+#define WINHTTP_FLAG_AUTOMATIC_CHUNKING     0x00000200
 #define WINHTTP_FLAG_SECURE                 0x00800000
 
 #define WINHTTP_ACCESS_TYPE_DEFAULT_PROXY   0
@@ -168,6 +170,7 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL             133
 #define WINHTTP_OPTION_HTTP_PROTOCOL_USED               134
 #define WINHTTP_OPTION_KDC_PROXY_SETTINGS               136
+#define WINHTTP_OPTION_PROXY_DISABLE_SERVICE_CALLS      137
 #define WINHTTP_OPTION_ENCODE_EXTRA                     138
 #define WINHTTP_OPTION_DISABLE_STREAM_QUEUE             139
 #define WINHTTP_OPTION_IPV6_FAST_FALLBACK               140
@@ -330,7 +333,11 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define ERROR_WINHTTP_SECURE_FAILURE_PROXY                  (WINHTTP_ERROR_BASE + 188)
 #define ERROR_WINHTTP_RESERVED_189                          (WINHTTP_ERROR_BASE + 189)
 #define ERROR_WINHTTP_HTTP_PROTOCOL_MISMATCH                (WINHTTP_ERROR_BASE + 190)
-#define WINHTTP_ERROR_LAST                                  (WINHTTP_ERROR_BASE + 188)
+#define ERROR_WINHTTP_GLOBAL_CALLBACK_FAILED                (WINHTTP_ERROR_BASE + 191)
+#define ERROR_WINHTTP_FEATURE_DISABLED                      (WINHTTP_ERROR_BASE + 192)
+#define ERROR_WINHTTP_FAST_FORWARDING_NOT_SUPPORTED         (WINHTTP_ERROR_BASE + 193)
+
+#define WINHTTP_ERROR_LAST                                  (WINHTTP_ERROR_BASE + 193)
 
 #define WINHTTP_RESET_STATE                     0x00000001
 #define WINHTTP_RESET_SWPAD_CURRENT_NETWORK     0x00000002
@@ -511,8 +518,10 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE 0x01000000
 #define WINHTTP_CALLBACK_STATUS_CLOSE_COMPLETE          0x02000000
 #define WINHTTP_CALLBACK_STATUS_SHUTDOWN_COMPLETE       0x04000000
+#define WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE 0x08000000
 #define WINHTTP_CALLBACK_STATUS_SETTINGS_WRITE_COMPLETE 0x10000000
 #define WINHTTP_CALLBACK_STATUS_SETTINGS_READ_COMPLETE  0x20000000
+
 #define WINHTTP_CALLBACK_FLAG_RESOLVE_NAME              (WINHTTP_CALLBACK_STATUS_RESOLVING_NAME | WINHTTP_CALLBACK_STATUS_NAME_RESOLVED)
 #define WINHTTP_CALLBACK_FLAG_CONNECT_TO_SERVER         (WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER | WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER)
 #define WINHTTP_CALLBACK_FLAG_SEND_REQUEST              (WINHTTP_CALLBACK_STATUS_SENDING_REQUEST | WINHTTP_CALLBACK_STATUS_REQUEST_SENT)
@@ -530,10 +539,14 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE            WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE
 #define WINHTTP_CALLBACK_FLAG_REQUEST_ERROR             WINHTTP_CALLBACK_STATUS_REQUEST_ERROR
 #define WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE   WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE
+#define WINHTTP_CALLBACK_FLAG_GETPROXYSETTINGS_COMPLETE WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE
+
 #define WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS           (WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE | WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE \
                                                         | WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE | WINHTTP_CALLBACK_STATUS_READ_COMPLETE          \
                                                         | WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE | WINHTTP_CALLBACK_STATUS_REQUEST_ERROR \
-                                                        | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE)
+                                                        | WINHTTP_CALLBACK_STATUS_GETPROXYFORURL_COMPLETE \
+                                                        | WINHTTP_CALLBACK_STATUS_GETPROXYSETTINGS_COMPLETE)
+
 #define WINHTTP_CALLBACK_FLAG_ALL_NOTIFICATIONS         0xffffffff
 #define WINHTTP_INVALID_STATUS_CALLBACK                 ((WINHTTP_STATUS_CALLBACK)(-1))
 
@@ -547,6 +560,9 @@ typedef int INTERNET_SCHEME, *LPINTERNET_SCHEME;
 #define WINHTTP_HANDLE_TYPE_SESSION                  1
 #define WINHTTP_HANDLE_TYPE_CONNECT                  2
 #define WINHTTP_HANDLE_TYPE_REQUEST                  3
+#define WINHTTP_HANDLE_TYPE_PROXY_RESOLVER           4
+#define WINHTTP_HANDLE_TYPE_WEBSOCKET                5
+#define WINHTTP_HANDLE_TYPE_PROTOCOL                 6
 
 #define WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED         0x00000001
 #define WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CERT            0x00000002
diff --git a/include/winternl.h b/include/winternl.h
index 7a4f7a892dde..a20aca55a0ed 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -4507,10 +4507,166 @@ typedef struct _KCONTINUE_ARGUMENT
 #define HASH_STRING_ALGORITHM_X65599   1
 #define HASH_STRING_ALGORITHM_INVALID  0xffffffff
 
+/* ALPC */
+/* Connection flags */
+#define ALPC_SYNC_CONNECTION                    0x00020000 /* Synchronous connection request message, note that this doesn't affect normal messages */
+
+/* Port attribute flags */
+#define ALPC_PORTFLG_ALLOWIMPERSONATION         0x00010000 /* Allow server to impersonate the client */
+#define ALPC_PORTFLG_NON_BLOCKING_RECEIVE       0x00040000 /* Return immediately when there is no data to receive */
+#define ALPC_PORTFLG_ALLOW_DUP_OBJECT           0x00080000 /* Allow duplicating objects */
+
+/* Message flags */
+#define ALPC_MSGFLG_NONE                        0x00000000
+#define ALPC_MSGFLG_REPLY_MESSAGE               0x00010000 /* Message is a reply */
+#define ALPC_MSGFLG_SYNC_REQUEST                0x00020000 /* Synchronously send and receive message */
+
+/* Message attribute flags */
+#define ALPC_MESSAGE_SECURITY_ATTRIBUTE         0x80000000
+#define ALPC_MESSAGE_VIEW_ATTRIBUTE             0x40000000
+#define ALPC_MESSAGE_CONTEXT_ATTRIBUTE          0x20000000
+#define ALPC_MESSAGE_HANDLE_ATTRIBUTE           0x10000000
+#define ALPC_MESSAGE_TOKEN_ATTRIBUTE            0x08000000
+#define ALPC_MESSAGE_DIRECT_ATTRIBUTE           0x04000000
+#define ALPC_MESSAGE_WORK_ON_BEHALF_ATTRIBUTE   0x02000000
+#define ALPC_MESSAGE_ATTRIBUTE_ALL              0xfe000000
+
+/* Message types */
+typedef enum _ALPC_MESSAGE_TYPE
+{
+    ALPC_MESSAGE_TYPE_REQUEST = 1,
+    ALPC_MESSAGE_TYPE_REPLY,
+    ALPC_MESSAGE_TYPE_DATAGRAM,
+    ALPC_MESSAGE_TYPE_LOST_REPLY,
+    ALPC_MESSAGE_TYPE_PORT_CLOSED,
+    ALPC_MESSAGE_TYPE_CLIENT_DIED,
+    ALPC_MESSAGE_TYPE_EXCEPTION,
+    ALPC_MESSAGE_TYPE_DEBUG_EVENT,
+    ALPC_MESSAGE_TYPE_ERROR_EVENT,
+    ALPC_MESSAGE_TYPE_CONNECTION_REQUEST,
+    ALPC_MESSAGE_TYPE_CONNECTION_REPLY,
+    ALPC_MESSAGE_TYPE_CANCELED,
+    ALPC_MESSAGE_TYPE_UNREGISTER_PROCESS
+} ALPC_MESSAGE_TYPE;
+
+typedef struct _ALPC_PORT_MESSAGE
+{
+    union
+    {
+        struct
+        {
+            USHORT DataLength;
+            USHORT TotalLength;
+        } DUMMYSTRUCTNAME1;
+        ULONG Length;
+    } DUMMYUNIONNAME1;
+    union
+    {
+        struct
+        {
+            USHORT Type;
+            USHORT DataInfoOffset;
+        } DUMMYSTRUCTNAME2;
+        ULONG ZeroInit;
+    } DUMMYUNIONNAME2;
+    union
+    {
+        CLIENT_ID ClientId;
+        double DoNotUseThisField;
+    } DUMMYUNIONNAME3;
+    ULONG MessageId;
+    union
+    {
+        SIZE_T ClientViewSize;
+        ULONG CallbackId;
+    } DUMMYUNIONNAME4;
+} ALPC_PORT_MESSAGE, *PALPC_PORT_MESSAGE, ALPC_PORT_MESSAGE_HEADER, *PALPC_PORT_MESSAGE_HEADER;
+
+typedef struct _ALPC_MESSAGE_ATTRIBUTES
+{
+    ULONG AllocatedAttributes;
+    ULONG ValidAttributes;
+} ALPC_MESSAGE_ATTRIBUTES, *PALPC_MESSAGE_ATTRIBUTES;
+
+typedef struct _ALPC_SECURITY_ATTR
+{
+    ULONG Flags;
+    SECURITY_QUALITY_OF_SERVICE *QoS;
+    HANDLE ContextHandle;
+} ALPC_SECURITY_ATTR, *PALPC_SECURITY_ATTR;
+
+typedef struct _ALPC_VIEW_ATTR
+{
+    ULONG Flags;
+    HANDLE SectionHandle;
+    void *ViewBase;
+    SIZE_T ViewSize;
+} ALPC_VIEW_ATTR, *PALPC_VIEW_ATTR;
+
+typedef struct _ALPC_CONTEXT_ATTR
+{
+    void *PortContext;
+    void *MessageContext;
+    ULONG Sequence;
+    ULONG MessageId;
+    ULONG CallbackId;
+} ALPC_CONTEXT_ATTR, * PALPC_CONTEXT_ATTR;
+
+typedef struct _ALPC_HANDLE_ATTR
+{
+    ULONG Flags;
+    HANDLE Handle;
+    ULONG ObjectType;
+    ACCESS_MASK DesiredAccess;
+} ALPC_HANDLE_ATTR, *PALPC_HANDLE_ATTR;
+
+typedef struct _ALPC_TOKEN_ATTR
+{
+    ULONGLONG TokenId;
+    ULONGLONG AuthenticationId;
+    ULONGLONG ModifiedId;
+} ALPC_TOKEN_ATTR, *PALPC_TOKEN_ATTR;
+
+typedef struct _ALPC_DIRECT_ATTR
+{
+    HANDLE Event;
+} ALPC_DIRECT_ATTR, *PALPC_DIRECT_ATTR;
+
+typedef struct _ALPC_WORK_ON_BEHALF_ATTR
+{
+    ULONGLONG Ticket;
+} ALPC_WORK_ON_BEHALF_ATTR, *PALPC_WORK_ON_BEHALF_ATTR;
+
+typedef struct _ALPC_BASIC_INFORMATION
+{
+    ULONG Flags;
+    ULONG SequenceNo;
+    PVOID PortContext;
+} ALPC_BASIC_INFORMATION, *PALPC_BASIC_INFORMATION;
+
+typedef struct _ALPC_PORT_ATTRIBUTES
+{
+    ULONG Flags;
+    SECURITY_QUALITY_OF_SERVICE SecurityQos;
+    SIZE_T MaxMessageLength;
+    SIZE_T MemoryBandwidth;
+    SIZE_T MaxPoolUsage;
+    SIZE_T MaxSectionSize;
+    SIZE_T MaxViewSize;
+    SIZE_T MaxTotalSectionSize;
+    ULONG DupObjectTypes;
+#ifdef _WIN64
+    ULONG Reserved;
+#endif
+} ALPC_PORT_ATTRIBUTES, *PALPC_PORT_ATTRIBUTES;
+
 /***********************************************************************
  * Function declarations
  */
 
+NTSYSAPI SIZE_T    WINAPI AlpcGetHeaderSize(ULONG);
+NTSYSAPI void *    WINAPI AlpcGetMessageAttribute(ALPC_MESSAGE_ATTRIBUTES *,ULONG);
+NTSYSAPI NTSTATUS  WINAPI AlpcInitializeMessageAttribute(ULONG,ALPC_MESSAGE_ATTRIBUTES *,SIZE_T,SIZE_T *);
 NTSYSAPI NTSTATUS  WINAPI ApiSetQueryApiSetPresence(const UNICODE_STRING*,BOOLEAN*);
 NTSYSAPI NTSTATUS  WINAPI ApiSetQueryApiSetPresenceEx(const UNICODE_STRING*,BOOLEAN*,BOOLEAN*);
 NTSYSAPI void      WINAPI DbgBreakPoint(void);
@@ -4570,6 +4726,18 @@ NTSYSAPI NTSTATUS  WINAPI NtAllocateReserveObject(HANDLE *handle,const OBJECT_AT
 NTSYSAPI NTSTATUS  WINAPI NtAllocateUuids(PULARGE_INTEGER,PULONG,PULONG,PUCHAR);
 NTSYSAPI NTSTATUS  WINAPI NtAllocateVirtualMemory(HANDLE,PVOID*,ULONG_PTR,SIZE_T*,ULONG,ULONG);
 NTSYSAPI NTSTATUS  WINAPI NtAllocateVirtualMemoryEx(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG,MEM_EXTENDED_PARAMETER*,ULONG);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcAcceptConnectPort(HANDLE*,HANDLE,DWORD,OBJECT_ATTRIBUTES*,ALPC_PORT_ATTRIBUTES*,void*,ALPC_PORT_MESSAGE*,ALPC_MESSAGE_ATTRIBUTES*,BOOLEAN);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcConnectPort(HANDLE*,UNICODE_STRING*,OBJECT_ATTRIBUTES*,ALPC_PORT_ATTRIBUTES*,DWORD,PSID,ALPC_PORT_MESSAGE*,SIZE_T*, ALPC_MESSAGE_ATTRIBUTES*,ALPC_MESSAGE_ATTRIBUTES*,LARGE_INTEGER*);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcCreatePort(HANDLE*,OBJECT_ATTRIBUTES*,ALPC_PORT_ATTRIBUTES*);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcCreatePortSection(HANDLE,ULONG,HANDLE,SIZE_T,HANDLE*,SIZE_T*);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcCreateSectionView(HANDLE,ULONG,ALPC_VIEW_ATTR *);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcCreateSecurityContext(HANDLE,ULONG,ALPC_SECURITY_ATTR *);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcDeletePortSection(HANDLE, ULONG, HANDLE);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcDeleteSectionView(HANDLE,ULONG,PVOID);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcDeleteSecurityContext(HANDLE,ULONG,HANDLE);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcDisconnectPort(HANDLE,ULONG);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcImpersonateClientOfPort(HANDLE,ALPC_PORT_MESSAGE*,void*);
+NTSYSAPI NTSTATUS  WINAPI NtAlpcSendWaitReceivePort(HANDLE,DWORD,ALPC_PORT_MESSAGE*,ALPC_MESSAGE_ATTRIBUTES*,ALPC_PORT_MESSAGE*, SIZE_T*,ALPC_MESSAGE_ATTRIBUTES*,LARGE_INTEGER*);
 NTSYSAPI NTSTATUS  WINAPI NtAreMappedFilesTheSame(PVOID,PVOID);
 NTSYSAPI NTSTATUS  WINAPI NtAssignProcessToJobObject(HANDLE,HANDLE);
 NTSYSAPI NTSTATUS  WINAPI NtCallbackReturn(PVOID,ULONG,NTSTATUS);
@@ -4637,7 +4805,7 @@ NTSYSAPI NTSTATUS  WINAPI NtFlushBuffersFileEx(HANDLE,ULONG,void*,ULONG,IO_STATU
 NTSYSAPI NTSTATUS  WINAPI NtFlushInstructionCache(HANDLE,LPCVOID,SIZE_T);
 NTSYSAPI NTSTATUS  WINAPI NtFlushKey(HANDLE);
 NTSYSAPI NTSTATUS  WINAPI NtFlushProcessWriteBuffers(void);
-NTSYSAPI NTSTATUS  WINAPI NtFlushVirtualMemory(HANDLE,LPCVOID*,SIZE_T*,ULONG);
+NTSYSAPI NTSTATUS  WINAPI NtFlushVirtualMemory(HANDLE,LPCVOID*,SIZE_T*,IO_STATUS_BLOCK*);
 NTSYSAPI NTSTATUS  WINAPI NtFlushWriteBuffer(VOID);
 NTSYSAPI NTSTATUS  WINAPI NtFreeVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG);
 NTSYSAPI NTSTATUS  WINAPI NtFsControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG);
diff --git a/libs/adsiid/adsiid.c b/libs/adsiid/adsiid.c
index fc0b8b1bf4e1..ddc4fe699cd5 100644
--- a/libs/adsiid/adsiid.c
+++ b/libs/adsiid/adsiid.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/dmoguids/dmoguids.c b/libs/dmoguids/dmoguids.c
index 15a0540170df..ef1276cb01b8 100644
--- a/libs/dmoguids/dmoguids.c
+++ b/libs/dmoguids/dmoguids.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/dxguid/dx10guid.c b/libs/dxguid/dx10guid.c
index bd80025c02fa..13af8dfdb182 100644
--- a/libs/dxguid/dx10guid.c
+++ b/libs/dxguid/dx10guid.c
@@ -10,6 +10,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/dxguid/dx8guid.c b/libs/dxguid/dx8guid.c
index 76d8cd1fe0fb..0f5af0bacc40 100644
--- a/libs/dxguid/dx8guid.c
+++ b/libs/dxguid/dx8guid.c
@@ -9,6 +9,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/dxguid/dx9guid.c b/libs/dxguid/dx9guid.c
index d64e6906cfc6..ae71e39b5952 100644
--- a/libs/dxguid/dx9guid.c
+++ b/libs/dxguid/dx9guid.c
@@ -10,6 +10,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/dxguid/dxguid.c b/libs/dxguid/dxguid.c
index 77d419410715..2af0ae8e0940 100644
--- a/libs/dxguid/dxguid.c
+++ b/libs/dxguid/dxguid.c
@@ -9,6 +9,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/lcms2/include/lcms2.h b/libs/lcms2/include/lcms2.h
index 548ffcc3bf77..c4de8666a343 100644
--- a/libs/lcms2/include/lcms2.h
+++ b/libs/lcms2/include/lcms2.h
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2025 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -23,7 +23,7 @@
 //
 //---------------------------------------------------------------------------------
 //
-// Version 2.17
+// Version 2.18
 //
 
 #ifndef _lcms2_H
@@ -87,7 +87,7 @@ extern "C" {
 #endif
 
 // Version/release
-#define LCMS_VERSION        2170
+#define LCMS_VERSION        2180
 
 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant
 #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
diff --git a/libs/lcms2/include/lcms2_plugin.h b/libs/lcms2/include/lcms2_plugin.h
index 71fdda909c6b..917ee1c31971 100644
--- a/libs/lcms2/include/lcms2_plugin.h
+++ b/libs/lcms2/include/lcms2_plugin.h
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsalpha.c b/libs/lcms2/src/cmsalpha.c
index 8979a5f364b1..adaab7acb906 100644
--- a/libs/lcms2/src/cmsalpha.c
+++ b/libs/lcms2/src/cmsalpha.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -377,7 +377,7 @@ int FormatterPos(cmsUInt32Number frm)
 static
 cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)
 {
-static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
+static const cmsFormatterAlphaFn FormattersAlpha[6][6] = {
 
        /* from 8 */  { copy8,       from8to16,   from8to16SE,   from8toHLF,   from8toFLT,    from8toDBL    },
        /* from 16*/  { from16to8,   copy16,      from16to16,    from16toHLF,  from16toFLT,   from16toDBL   },
diff --git a/libs/lcms2/src/cmscnvrt.c b/libs/lcms2/src/cmscnvrt.c
index 5f9aec8e6b9d..8416dc41c42a 100644
--- a/libs/lcms2/src/cmscnvrt.c
+++ b/libs/lcms2/src/cmscnvrt.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmserr.c b/libs/lcms2/src/cmserr.c
index 2603b876438b..e1e06bf6def1 100644
--- a/libs/lcms2/src/cmserr.c
+++ b/libs/lcms2/src/cmserr.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsgamma.c b/libs/lcms2/src/cmsgamma.c
index 3a8352d72d28..2fdd21ec5969 100644
--- a/libs/lcms2/src/cmsgamma.c
+++ b/libs/lcms2/src/cmsgamma.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -1158,6 +1158,7 @@ cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[]
     cmsFloat32Number *c, *d, *e;
     cmsBool st;
 
+    if (m < 4 || lambda < MATRIX_DET_TOLERANCE) return FALSE;
 
     c = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
     d = (cmsFloat32Number*) _cmsCalloc(ContextID, MAX_NODES_IN_CURVE, sizeof(cmsFloat32Number));
diff --git a/libs/lcms2/src/cmsgmt.c b/libs/lcms2/src/cmsgmt.c
index b4003e55bb97..f82f7854937d 100644
--- a/libs/lcms2/src/cmsgmt.c
+++ b/libs/lcms2/src/cmsgmt.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmshalf.c b/libs/lcms2/src/cmshalf.c
index f15230873ba9..43a3f9b38adf 100644
--- a/libs/lcms2/src/cmshalf.c
+++ b/libs/lcms2/src/cmshalf.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsintrp.c b/libs/lcms2/src/cmsintrp.c
index d1dedddd057f..a9934b78ae95 100644
--- a/libs/lcms2/src/cmsintrp.c
+++ b/libs/lcms2/src/cmsintrp.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -955,9 +955,9 @@ void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[],
                                 c1 = c2 = c3 = 0;
                             }
 
-        Rest = c1 * rx + c2 * ry + c3 * rz;
+        Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
 
-        Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
+        Tmp1[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
     }
 
 
@@ -1019,9 +1019,9 @@ void Eval4Inputs(CMSREGISTER const cmsUInt16Number Input[],
                                 c1 = c2 = c3 = 0;
                             }
 
-        Rest = c1 * rx + c2 * ry + c3 * rz;
+        Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
 
-        Tmp2[OutChan] = (cmsUInt16Number) (c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
+        Tmp2[OutChan] = (cmsUInt16Number) c0 + ((Rest + (Rest >> 16)) >> 16);
     }
 
 
diff --git a/libs/lcms2/src/cmsio0.c b/libs/lcms2/src/cmsio0.c
index a4a7397be5bd..aee9ba3464e6 100644
--- a/libs/lcms2/src/cmsio0.c
+++ b/libs/lcms2/src/cmsio0.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -656,6 +656,7 @@ void _cmsDeleteTagByPos(_cmsICCPROFILE* Icc, int i)
         // Free previous version
         if (Icc ->TagSaveAsRaw[i]) {
             _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]);
+            Icc->TagSaveAsRaw[i] = FALSE;
         }
         else {
             cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i];
@@ -1576,6 +1577,8 @@ void freeOneTag(_cmsICCPROFILE* Icc, cmsUInt32Number i)
         else
             _cmsFree(Icc->ContextID, Icc->TagPtrs[i]);
     }
+
+    Icc->TagPtrs[i] = NULL;
 }
 
 // Closes a profile freeing any involved resources
@@ -1818,8 +1821,11 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
 
     if (!_cmsNewTag(Icc, sig, &i)) goto Error;
 
-    // This is not raw
-    Icc ->TagSaveAsRaw[i] = FALSE;
+    // This cannot be RAW
+    if (Icc->TagSaveAsRaw[i]) {
+        cmsSignalError(Icc->ContextID, cmsERROR_ALREADY_DEFINED, "Tag  '%x' was already saved as RAW", sig);
+        goto Error;
+    }
 
     // This is not a link
     Icc ->TagLinked[i] = (cmsTagSignature) 0;
diff --git a/libs/lcms2/src/cmsio1.c b/libs/lcms2/src/cmsio1.c
index 90fbf71f57e5..ba101d39e9e8 100644
--- a/libs/lcms2/src/cmsio1.c
+++ b/libs/lcms2/src/cmsio1.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -983,7 +983,13 @@ const cmsMLU* GetInfo(cmsHPROFILE hProfile, cmsInfoType Info)
     switch (Info) {
 
     case cmsInfoDescription:
-        sig = cmsSigProfileDescriptionTag;
+        /**
+        * Add for MacOS, which uses propiertary tags for description
+        */
+        if (cmsIsTag(hProfile, cmsSigProfileDescriptionMLTag))
+            sig = cmsSigProfileDescriptionMLTag;
+        else
+            sig = cmsSigProfileDescriptionTag;
         break;
 
     case cmsInfoManufacturer:
diff --git a/libs/lcms2/src/cmslut.c b/libs/lcms2/src/cmslut.c
index 6842884ff4f7..380d31b27291 100644
--- a/libs/lcms2/src/cmslut.c
+++ b/libs/lcms2/src/cmslut.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsmtrx.c b/libs/lcms2/src/cmsmtrx.c
index a4df2a4aa214..4462aca64528 100644
--- a/libs/lcms2/src/cmsmtrx.c
+++ b/libs/lcms2/src/cmsmtrx.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsnamed.c b/libs/lcms2/src/cmsnamed.c
index f718f54ffad5..9dad6d1e7caf 100644
--- a/libs/lcms2/src/cmsnamed.c
+++ b/libs/lcms2/src/cmsnamed.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -274,7 +274,7 @@ cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wch
     cmsUInt32Number size = 0;
     cmsUInt32Number len_w = 0;
 
-    while (*in && len_w < max_wchars)
+    while (len_w < max_wchars && *in)
     {
         if (*in >= 0xd800 && *in <= 0xdbff)
             codepoint = ((*in - 0xd800) << 10) + 0x10000;
@@ -1042,17 +1042,17 @@ cmsSEQ* CMSEXPORT cmsDupProfileSequenceDescription(const cmsSEQ* pseq)
     if (pseq == NULL)
         return NULL;
 
-    NewSeq = (cmsSEQ*) _cmsMalloc(pseq -> ContextID, sizeof(cmsSEQ));
+    NewSeq = (cmsSEQ*)_cmsMallocZero(pseq->ContextID, sizeof(cmsSEQ));
     if (NewSeq == NULL) return NULL;
 
+    NewSeq->ContextID = pseq->ContextID;
 
-    NewSeq -> seq      = (cmsPSEQDESC*) _cmsCalloc(pseq ->ContextID, pseq ->n, sizeof(cmsPSEQDESC));
-    if (NewSeq ->seq == NULL) goto Error;
+    NewSeq->seq = (cmsPSEQDESC*)_cmsCalloc(pseq->ContextID, pseq->n, sizeof(cmsPSEQDESC));
+    if (NewSeq->seq == NULL) goto Error;
 
-    NewSeq -> ContextID = pseq ->ContextID;
-    NewSeq -> n        = pseq ->n;
+    NewSeq->n = pseq->n;
 
-    for (i=0; i < pseq->n; i++) {
+    for (i = 0; i < pseq->n; i++) {
 
         memmove(&NewSeq ->seq[i].attributes, &pseq ->seq[i].attributes, sizeof(cmsUInt64Number));
 
diff --git a/libs/lcms2/src/cmsopt.c b/libs/lcms2/src/cmsopt.c
index 71ae0416774c..6d1ca89db5f1 100644
--- a/libs/lcms2/src/cmsopt.c
+++ b/libs/lcms2/src/cmsopt.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -669,11 +669,16 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
     if (ColorSpace == (cmsColorSpaceSignature)0 ||
         OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
 
-    nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
-
     // For empty LUTs, 2 points are enough
     if (cmsPipelineStageCount(*Lut) == 0)
         nGridPoints = 2;
+    else
+    {
+        nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
+
+        // Lab16 as input cannot be optimized by a CLUT due to centering issues, thanks to Mike Chaney for discovering this.
+        if (!(*dwFlags & cmsFLAGS_FORCE_CLUT) && (ColorSpace == cmsSigLabData) && (T_BYTES(*InputFormat) == 2)) return FALSE;
+    }
 
     Src = *Lut;
 
@@ -784,6 +789,11 @@ Error:
             Dest ->OutputChannels,
             DataSetOut);
 
+        if (p16 == NULL) {
+            cmsPipelineFree(Dest);
+            return FALSE;
+        }
+
         _cmsPipelineSetOptimizationParameters(Dest, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup);
     }
 
diff --git a/libs/lcms2/src/cmspack.c b/libs/lcms2/src/cmspack.c
index cb773ee96231..84edcd6737e9 100644
--- a/libs/lcms2/src/cmspack.c
+++ b/libs/lcms2/src/cmspack.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmspcs.c b/libs/lcms2/src/cmspcs.c
index 5c2b0280920e..f9ef707d7548 100644
--- a/libs/lcms2/src/cmspcs.c
+++ b/libs/lcms2/src/cmspcs.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsplugin.c b/libs/lcms2/src/cmsplugin.c
index 40c4ec231c21..cb61d215e867 100644
--- a/libs/lcms2/src/cmsplugin.c
+++ b/libs/lcms2/src/cmsplugin.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -493,7 +493,7 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
     va_start(args, frm);
 
     len = vsnprintf((char*) Buffer, 2047, frm, args);
-    if (len < 0) {
+    if (len < 0 || len >= 2047) {
         va_end(args);
         return FALSE;   // Truncated, which is a fatal error for us
     }
diff --git a/libs/lcms2/src/cmssamp.c b/libs/lcms2/src/cmssamp.c
index ab1a3abbf1bf..b3e78ba4e4e5 100644
--- a/libs/lcms2/src/cmssamp.c
+++ b/libs/lcms2/src/cmssamp.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -123,9 +123,12 @@ cmsBool  BlackPointAsDarkerColorant(cmsHPROFILE    hInput,
     // Convert black to Lab
     cmsDoTransform(xform, Black, &Lab, 1);
 
-    // Force it to be neutral, check for inconsistencies
-    Lab.a = Lab.b = 0;
-    if (Lab.L > 50 || Lab.L < 0) Lab.L = 0;
+    if (Lab.L > 95)
+        Lab.L = 0;  // for synthetical negative profiles
+    else if (Lab.L < 0)
+        Lab.L = 0;
+    else if (Lab.L > 50)
+        Lab.L = 50;
 
     // Free the resources
     cmsDeleteTransform(xform);
@@ -323,7 +326,7 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[]
     if (fabs(a) < 1.0E-10) {
     
         if (fabs(b) < 1.0E-10) return 0;
-        return cmsmin(0, cmsmax(50, -c/b ));
+        return cmsmax(0, cmsmin(50, -c/b ));
     }
     else {
 
diff --git a/libs/lcms2/src/cmstypes.c b/libs/lcms2/src/cmstypes.c
index d6edcc0e6080..ee7923c0895c 100644
--- a/libs/lcms2/src/cmstypes.c
+++ b/libs/lcms2/src/cmstypes.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -4757,7 +4757,6 @@ cmsBool ReadMPEElem(struct _cms_typehandler_struct* self,
 
     return TRUE;
 
-    cmsUNUSED_PARAMETER(SizeOfTag);
     cmsUNUSED_PARAMETER(n);
 }
 
@@ -4865,9 +4864,11 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v
                  goto Error;
         }
 
+         Before = io ->Tell(io);
+
         if (!_cmsWriteUInt32Number(io, ElementSig)) goto Error;
         if (!_cmsWriteUInt32Number(io, 0)) goto Error;
-        Before = io ->Tell(io);
+
         if (!TypeHandler ->WritePtr(self, io, Elem, 1)) goto Error;
         if (!_cmsWriteAlignment(io)) goto Error;
 
@@ -5616,9 +5617,7 @@ void* Type_VideoSignal_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER*
 {
     cmsVideoSignalType* cicp = NULL;
 
-    if (SizeOfTag != 8) return NULL;
-
-    if (!_cmsReadUInt32Number(io, NULL)) return NULL;
+    if (SizeOfTag != 4) return NULL;
 
     cicp = (cmsVideoSignalType*)_cmsCalloc(self->ContextID, 1, sizeof(cmsVideoSignalType));
     if (cicp == NULL) return NULL;
@@ -5642,7 +5641,6 @@ cmsBool Type_VideoSignal_Write(struct _cms_typehandler_struct* self, cmsIOHANDLE
 {
     cmsVideoSignalType* cicp = (cmsVideoSignalType*)Ptr;
 
-    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
     if (!_cmsWriteUInt8Number(io, cicp->ColourPrimaries)) return FALSE;
     if (!_cmsWriteUInt8Number(io, cicp->TransferCharacteristics)) return FALSE;
     if (!_cmsWriteUInt8Number(io, cicp->MatrixCoefficients)) return FALSE;
@@ -5715,11 +5713,11 @@ void Type_MHC2_Free(struct _cms_typehandler_struct* self, void* Ptr)
 
 void* Type_MHC2_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
 {
-    cmsMHC2Type* mhc2 = _cmsDupMem(self->ContextID, Ptr, sizeof(cmsMHC2Type));
+    cmsMHC2Type* mhc2 = (cmsMHC2Type*)_cmsDupMem(self->ContextID, Ptr, sizeof(cmsMHC2Type));
 
-    mhc2->RedCurve = _cmsDupMem(self->ContextID,   mhc2->RedCurve, mhc2->CurveEntries*sizeof(cmsFloat64Number));
-    mhc2->GreenCurve = _cmsDupMem(self->ContextID, mhc2->GreenCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
-    mhc2->BlueCurve = _cmsDupMem(self->ContextID,  mhc2->BlueCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
+    mhc2->RedCurve = (cmsFloat64Number*) _cmsDupMem(self->ContextID,   mhc2->RedCurve, mhc2->CurveEntries*sizeof(cmsFloat64Number));
+    mhc2->GreenCurve = (cmsFloat64Number*) _cmsDupMem(self->ContextID, mhc2->GreenCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
+    mhc2->BlueCurve = (cmsFloat64Number*) _cmsDupMem(self->ContextID,  mhc2->BlueCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
 
     if (mhc2->RedCurve == NULL ||
         mhc2->GreenCurve == NULL ||
@@ -5757,7 +5755,6 @@ cmsBool Type_MHC2_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
     cmsUInt32Number MatrixOffset;
     cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable;
 
-    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
     if (!_cmsWriteUInt32Number(io, mhc2->CurveEntries)) return FALSE;
 
     if (!_cmsWrite15Fixed16Number(io, mhc2->MinLuminance)) return FALSE;
@@ -5782,10 +5779,20 @@ cmsBool Type_MHC2_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
     }
 
     OffsetRedTable = io->Tell(io) - BaseOffset;
+
+    if(!_cmsWriteUInt32Number(io, cmsSigS15Fixed16ArrayType)) return FALSE;
+    if(!_cmsWriteUInt32Number(io, 0)) return FALSE;
+
     if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->RedCurve)) return FALSE;
+
     OffsetGreenTable = io->Tell(io) - BaseOffset;
+    if (!_cmsWriteUInt32Number(io, cmsSigS15Fixed16ArrayType)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
     if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->GreenCurve)) return FALSE;
+
     OffsetBlueTable = io->Tell(io) - BaseOffset;
+    if (!_cmsWriteUInt32Number(io, cmsSigS15Fixed16ArrayType)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
     if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->BlueCurve)) return FALSE;
 
     if (!io->Seek(io, TablesOffsetPos)) return FALSE;
@@ -5829,8 +5836,6 @@ void* Type_MHC2_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
     cmsUInt32Number MatrixOffset;
     cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable;
 
-    if (!_cmsReadUInt32Number(io, NULL)) return NULL;
-
     mhc2 = (cmsMHC2Type*)_cmsCalloc(self->ContextID, 1, sizeof(cmsMHC2Type));
     if (mhc2 == NULL) return NULL;
 
@@ -5861,9 +5866,10 @@ void* Type_MHC2_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
         if (!ReadDoublesAt(io, BaseOffset + MatrixOffset, 3*4, &mhc2->XYZ2XYZmatrix[0][0])) goto Error;
     }
 
-    if (!ReadDoublesAt(io, BaseOffset + OffsetRedTable, mhc2->CurveEntries, mhc2->RedCurve)) goto Error;
-    if (!ReadDoublesAt(io, BaseOffset + OffsetGreenTable, mhc2->CurveEntries, mhc2->GreenCurve)) goto Error;
-    if (!ReadDoublesAt(io, BaseOffset + OffsetBlueTable, mhc2->CurveEntries, mhc2->BlueCurve)) goto Error;
+    // Skip sf32 tag and filler (8bytes)
+    if (!ReadDoublesAt(io, BaseOffset + OffsetRedTable + 8, mhc2->CurveEntries, mhc2->RedCurve)) goto Error;
+    if (!ReadDoublesAt(io, BaseOffset + OffsetGreenTable + 8, mhc2->CurveEntries, mhc2->GreenCurve)) goto Error;
+    if (!ReadDoublesAt(io, BaseOffset + OffsetBlueTable + 8, mhc2->CurveEntries, mhc2->BlueCurve)) goto Error;
 
     // Success
     *nItems = 1;
diff --git a/libs/lcms2/src/cmsvirt.c b/libs/lcms2/src/cmsvirt.c
index 0338c5f0be7e..8718e883fd89 100644
--- a/libs/lcms2/src/cmsvirt.c
+++ b/libs/lcms2/src/cmsvirt.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -371,7 +371,7 @@ int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUI
     SumCMY   = (cmsFloat64Number) In[0]  + In[1] + In[2];
     SumCMYK  = SumCMY + In[3];
 
-    if (SumCMYK > InkLimit) {
+    if (SumCMYK > InkLimit && SumCMY > 0) {
 
         Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY);
         if (Ratio < 0)
@@ -484,16 +484,20 @@ cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIE
     cmsSetColorSpace(hProfile,  cmsSigLabData);
     cmsSetPCS(hProfile,         cmsSigLabData);
 
-    if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL;
+    if (!SetTextTags(hProfile, L"Lab identity built-in"))
+        goto Error;
 
     // An identity LUT is all we need
     LUT = cmsPipelineAlloc(ContextID, 3, 3);
-    if (LUT == NULL) goto Error;
+    if (LUT == NULL)
+        goto Error;
 
     if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)))
         goto Error;
 
-    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
+    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT))
+        goto Error;
+
     cmsPipelineFree(LUT);
 
     return hProfile;
@@ -521,8 +525,14 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE
 {
     cmsHPROFILE hProfile;
     cmsPipeline* LUT = NULL;
+    cmsCIEXYZ xyz;
 
-    hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
+    if (WhitePoint == NULL)
+        xyz = *cmsD50_XYZ();
+    else
+        cmsxyY2XYZ(&xyz, WhitePoint);
+
+    hProfile = cmsCreateRGBProfileTHR(ContextID, NULL, NULL, NULL);
     if (hProfile == NULL) return NULL;
 
     cmsSetProfileVersion(hProfile, 4.4);
@@ -531,6 +541,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE
     cmsSetColorSpace(hProfile,  cmsSigLabData);
     cmsSetPCS(hProfile,         cmsSigLabData);
 
+    if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xyz)) goto Error;
     if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error;
 
     // An empty LUTs is all we need
@@ -900,25 +911,24 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
 
     for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints;
     CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
-    if (CLUT == NULL) goto Error;
-
-
-    if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
+    if (CLUT == NULL)
+        goto Error;
 
-        // Shouldn't reach here
+    if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0))
         goto Error;
-    }
 
-    if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) {
+    if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT))
         goto Error;
-    }
 
     // Create tags
-    if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
+    if (!SetTextTags(hICC, L"BCHS built-in"))
+        goto Error;
 
-    cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
+    if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*)cmsD50_XYZ()))
+        goto Error;
 
-    cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
+    if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*)Pipeline))
+        goto Error;
 
     // Pipeline is already on virtual profile
     cmsPipelineFree(Pipeline);
diff --git a/libs/lcms2/src/cmswtpnt.c b/libs/lcms2/src/cmswtpnt.c
index ed2e5491f281..40868edcb7c8 100644
--- a/libs/lcms2/src/cmswtpnt.c
+++ b/libs/lcms2/src/cmswtpnt.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/lcms2/src/cmsxform.c b/libs/lcms2/src/cmsxform.c
index 87641b4a339f..600792e2e2af 100644
--- a/libs/lcms2/src/cmsxform.c
+++ b/libs/lcms2/src/cmsxform.c
@@ -1,7 +1,7 @@
 //---------------------------------------------------------------------------------
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
@@ -1072,7 +1072,9 @@ cmsBool  IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwForm
     int Space1 = (int) T_COLORSPACE(dwFormat);
     int Space2 = _cmsLCMScolorSpace(Check);
 
-    if (Space1 == PT_ANY) return TRUE;
+    if (dwFormat == 0) return TRUE; // Bypass used by linkicc
+
+    if (Space1 == PT_ANY) return (T_CHANNELS(dwFormat) == cmsChannelsOf(Check));
     if (Space1 == Space2) return TRUE;
 
     if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
@@ -1154,6 +1156,11 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
         if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
     }
 
+    if ((dwFlags & cmsFLAGS_GAMUTCHECK) && (nGamutPCSposition <= 0 || nGamutPCSposition >= nProfiles - 1)) {
+        cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong gamut PCS position '%d'", nGamutPCSposition);
+        return NULL;
+    }
+
     // On floating point transforms, inhibit cache
     if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
         dwFlags |= cmsFLAGS_NOCACHE;
diff --git a/libs/lcms2/src/lcms2_internal.h b/libs/lcms2/src/lcms2_internal.h
index e7d8f8426a50..358308466142 100644
--- a/libs/lcms2/src/lcms2_internal.h
+++ b/libs/lcms2/src/lcms2_internal.h
@@ -1,7 +1,7 @@
 
 //
 //  Little Color Management System
-//  Copyright (c) 1998-2024 Marti Maria Saguer
+//  Copyright (c) 1998-2026 Marti Maria Saguer
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the "Software"),
diff --git a/libs/ldap/libldap/tls_w.c b/libs/ldap/libldap/tls_w.c
index 39cb5436053f..ec08908ddbbc 100644
--- a/libs/ldap/libldap/tls_w.c
+++ b/libs/ldap/libldap/tls_w.c
@@ -571,7 +571,7 @@ restart:
 	}
 	else if ( status == SEC_E_INCOMPLETE_MESSAGE ) {
 		assert( bufs[1].BufferType == SECBUFFER_MISSING );
-		expected = bufs[1].cbBuffer;
+		expected += bufs[1].cbBuffer;
 		goto restart;
 	}
 
diff --git a/libs/mfuuid/mfplay.c b/libs/mfuuid/mfplay.c
index d73e52607c40..fa663302b9ba 100644
--- a/libs/mfuuid/mfplay.c
+++ b/libs/mfuuid/mfplay.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/mfuuid/mfuuid.c b/libs/mfuuid/mfuuid.c
index d7fdcf18a20c..0e9e757e73ba 100644
--- a/libs/mfuuid/mfuuid.c
+++ b/libs/mfuuid/mfuuid.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/png/AUTHORS b/libs/png/AUTHORS
index b9c0fffcfd7d..8278a447dcc9 100644
--- a/libs/png/AUTHORS
+++ b/libs/png/AUTHORS
@@ -15,8 +15,10 @@ Authors, for copyright and licensing purposes.
  * Glenn Randers-Pehrson
  * Greg Roelofs
  * Guy Eric Schalnat
+ * Halil Oktay
  * James Yu
  * John Bowler
+ * Joshua Inscoe
  * Kevin Bracey
  * Lucas Chollet
  * Magnus Holmgren
@@ -33,12 +35,14 @@ Authors, for copyright and licensing purposes.
  * Sam Bushell
  * Samuel Williams
  * Simon-Pierre Cadieux
+ * Taegu Ha (하태구)
  * Tim Wegner
  * Tobias Stoeckmann
  * Tom Lane
  * Tom Tanner
  * Vadim Barkov
  * Willem van Schaik
+ * Yuelin Wang (王跃林)
  * Zhijie Liang
  * Apple Inc.
     - Zixu Wang (王子旭)
diff --git a/libs/png/png.c b/libs/png/png.c
index d184a306d543..fda0a8e6ae06 100644
--- a/libs/png/png.c
+++ b/libs/png/png.c
@@ -13,7 +13,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_54 Your_png_h_is_not_version_1_6_54;
+typedef png_libpng_version_1_6_56 Your_png_h_is_not_version_1_6_56;
 
 /* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
  * corresponding macro definitions.  This causes a compile time failure if
@@ -820,7 +820,7 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.54" PNG_STRING_NEWLINE \
+      "libpng version 1.6.56" PNG_STRING_NEWLINE \
       "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
@@ -1170,7 +1170,7 @@ png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ)
       return 1;
 
    /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so
-    * the fillowing calculates (X+Y+Z) of the reference white (media white,
+    * the following calculates (X+Y+Z) of the reference white (media white,
     * encoding white) itself:
     */
    d = dblue;
@@ -1215,9 +1215,9 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     * (-0.0770) because the PNG spec itself requires the xy values to be
     * unsigned.  whitey is also required to be 5 or more to avoid overflow.
     *
-    * Instead the upper limits have been relaxed to accomodate ACES AP1 where
+    * Instead the upper limits have been relaxed to accommodate ACES AP1 where
     * redz ends up as -600 (-0.006).  ProPhotoRGB was already "in range."
-    * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy.
+    * The new limit accommodates the AP0 and AP1 ranges for z but not AP0 redy.
     */
    const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10);
    if (xy->redx   < 0 || xy->redx > fpLimit) return 1;
@@ -1328,7 +1328,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy)
     *    red-scale + green-scale + blue-scale = 1/white-y = white-scale
     *
     * So now we have a Cramer's rule solution where the determinants are just
-    * 3x3 - far more tractible.  Unfortunately 3x3 determinants still involve
+    * 3x3 - far more tractable.  Unfortunately 3x3 determinants still involve
     * multiplication of three coefficients so we can't guarantee to avoid
     * overflow in the libpng fixed point representation.  Using Cramer's rule in
     * floating point is probably a good choice here, but it's not an option for
@@ -1697,7 +1697,7 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name,
     * into R, G and B channels.
     *
     * Previously it was suggested that an RGB profile on grayscale data could be
-    * handled.  However it it is clear that using an RGB profile in this context
+    * handled.  However it is clear that using an RGB profile in this context
     * must be an error - there is no specification of what it means.  Thus it is
     * almost certainly more correct to ignore the profile.
     */
@@ -2915,7 +2915,7 @@ png_gamma_significant(png_fixed_point gamma_val)
     *
     *    2.2/(2+51/256) == 1.00035524
     *
-    * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/-
+    * I.e. vanishingly small (<4E-4) but still detectable in 16-bit linear (+/-
     * 23).  Note that the Adobe choice seems to be something intended to give an
     * exact number with 8 binary fractional digits - it is the closest to 2.2
     * that is possible a base 2 .8p representation.
diff --git a/libs/png/png.h b/libs/png/png.h
index 84ddff1980b1..385de4b42d4e 100644
--- a/libs/png/png.h
+++ b/libs/png/png.h
@@ -1,6 +1,6 @@
 /* png.h - header file for PNG reference library
  *
- * libpng version 1.6.54
+ * libpng version 1.6.56
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -14,7 +14,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.54, January 2026:
+ *   libpng versions 1.6.36, December 2018, through 1.6.56, March 2026:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -238,7 +238,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.54                  16    10654  16.so.16.54[.0]
+ *    1.6.56                  16    10656  16.so.16.56[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -274,7 +274,7 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.54"
+#define PNG_LIBPNG_VER_STRING "1.6.56"
 #define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
 
 /* The versions of shared library builds should stay in sync, going forward */
@@ -285,7 +285,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 54
+#define PNG_LIBPNG_VER_RELEASE 56
 
 /* This should be zero for a public release, or non-zero for a
  * development version.
@@ -316,7 +316,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10654 /* 1.6.54 */
+#define PNG_LIBPNG_VER 10656 /* 1.6.56 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -426,7 +426,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char *png_libpng_version_1_6_54;
+typedef char *png_libpng_version_1_6_56;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
@@ -2341,7 +2341,7 @@ PNG_EXPORT(162, int, png_get_text,
 #endif
 
 /* Note while png_set_text() will accept a structure whose text,
- * language, and  translated keywords are NULL pointers, the structure
+ * language, and translated keywords are NULL pointers, the structure
  * returned by png_get_text will always contain regular
  * zero-terminated C strings.  They might be empty strings but
  * they will never be NULL pointers.
diff --git a/libs/png/pngconf.h b/libs/png/pngconf.h
index 1f511f57c1f2..d878ee84143a 100644
--- a/libs/png/pngconf.h
+++ b/libs/png/pngconf.h
@@ -1,6 +1,6 @@
 /* pngconf.h - machine-configurable file for libpng
  *
- * libpng version 1.6.54
+ * libpng version 1.6.56
  *
  * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/libs/png/pnglibconf.h b/libs/png/pnglibconf.h
index 0593f41b9896..686ba8f82f52 100644
--- a/libs/png/pnglibconf.h
+++ b/libs/png/pnglibconf.h
@@ -1,6 +1,6 @@
 /* pnglibconf.h - library build configuration */
 
-/* libpng version 1.6.54 */
+/* libpng version 1.6.56 */
 
 /* Copyright (c) 2018-2026 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/libs/png/pngpriv.h b/libs/png/pngpriv.h
index f91666c70009..a6c91ac2c7a8 100644
--- a/libs/png/pngpriv.h
+++ b/libs/png/pngpriv.h
@@ -957,7 +957,7 @@
  *
  * At present these index values are not exported (not part of the public API)
  * so can be changed at will.  For convenience the names are in lexical sort
- * order but with the critical chunks at the start in the order of occurence in
+ * order but with the critical chunks at the start in the order of occurrence in
  * a PNG.
  *
  * PNG_INFO_ values do not exist for every one of these chunk handles; for
@@ -2086,7 +2086,7 @@ PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed,
  * not valid it will be the index of a character in the supposed number.
  *
  * The format of a number is defined in the PNG extensions specification
- * and this API is strictly conformant to that spec, not anyone elses!
+ * and this API is strictly conformant to that spec, not anyone else's!
  *
  * The format as a regular expression is:
  *
diff --git a/libs/png/pngread.c b/libs/png/pngread.c
index af2f44c9ca8e..24199689a76b 100644
--- a/libs/png/pngread.c
+++ b/libs/png/pngread.c
@@ -691,7 +691,7 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr)
       png_read_finish_IDAT(png_ptr);
 
 #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
-   /* Report invalid palette index; added at libng-1.5.10 */
+   /* Report invalid palette index; added at libpng-1.5.10 */
    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
        png_ptr->num_palette_max >= png_ptr->num_palette)
       png_benign_error(png_ptr, "Read palette index exceeding num_palette");
@@ -779,21 +779,19 @@ png_read_destroy(png_structrp png_ptr)
    png_ptr->quantize_index = NULL;
 #endif
 
-   if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)
-   {
-      png_zfree(png_ptr, png_ptr->palette);
-      png_ptr->palette = NULL;
-   }
-   png_ptr->free_me &= ~PNG_FREE_PLTE;
+   /* png_ptr->palette is always independently allocated (not aliased
+    * with info_ptr->palette), so free it unconditionally.
+    */
+   png_free(png_ptr, png_ptr->palette);
+   png_ptr->palette = NULL;
 
 #if defined(PNG_tRNS_SUPPORTED) || \
     defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
-   if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
-   {
-      png_free(png_ptr, png_ptr->trans_alpha);
-      png_ptr->trans_alpha = NULL;
-   }
-   png_ptr->free_me &= ~PNG_FREE_TRNS;
+   /* png_ptr->trans_alpha is always independently allocated (not aliased
+    * with info_ptr->trans_alpha), so free it unconditionally.
+    */
+   png_free(png_ptr, png_ptr->trans_alpha);
+   png_ptr->trans_alpha = NULL;
 #endif
 
    inflateEnd(&png_ptr->zstream);
@@ -1256,7 +1254,7 @@ png_image_is_not_sRGB(png_const_structrp png_ptr)
     * png_struct::chromaticities always exists since the simplified API
     * requires rgb-to-gray.  The mDCV, cICP and cHRM chunks may all set it to
     * a non-sRGB value, so it needs to be checked but **only** if one of
-    * those chunks occured in the file.
+    * those chunks occurred in the file.
     */
    /* Highest priority: check to be safe. */
    if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV))
@@ -2596,7 +2594,7 @@ png_image_read_colormap(png_voidp argument)
                   {
                      r = back_r;
                      g = back_g;
-                     b = back_g;
+                     b = back_b;
                   }
 
                   /* Compare the newly-created color-map entry with the one the
@@ -2874,9 +2872,9 @@ png_image_read_and_map(png_voidp argument)
          {
             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
             png_bytep outrow = first_row + y * row_step;
-            png_const_bytep end_row = outrow + width;
+            png_const_bytep row_end = outrow + width;
 
-            /* Read read the libpng data into the temporary buffer. */
+            /* Read the libpng data into the temporary buffer. */
             png_read_row(png_ptr, inrow, NULL);
 
             /* Now process the row according to the processing option, note
@@ -2887,7 +2885,7 @@ png_image_read_and_map(png_voidp argument)
             switch (proc)
             {
                case PNG_CMAP_GA:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      /* The data is always in the PNG order */
                      unsigned int gray = *inrow++;
@@ -2916,7 +2914,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_TRANS:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      png_byte gray = *inrow++;
                      png_byte alpha = *inrow++;
@@ -2933,7 +2931,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_RGB:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);
                      inrow += 3;
@@ -2941,7 +2939,7 @@ png_image_read_and_map(png_voidp argument)
                   break;
 
                case PNG_CMAP_RGB_ALPHA:
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      unsigned int alpha = inrow[3];
 
@@ -2978,10 +2976,10 @@ png_image_read_and_map(png_voidp argument)
                          */
                         if (inrow[0] & 0x80) back_i += 9; /* red */
                         if (inrow[0] & 0x40) back_i += 9;
-                        if (inrow[0] & 0x80) back_i += 3; /* green */
-                        if (inrow[0] & 0x40) back_i += 3;
-                        if (inrow[0] & 0x80) back_i += 1; /* blue */
-                        if (inrow[0] & 0x40) back_i += 1;
+                        if (inrow[1] & 0x80) back_i += 3; /* green */
+                        if (inrow[1] & 0x40) back_i += 3;
+                        if (inrow[2] & 0x80) back_i += 1; /* blue */
+                        if (inrow[2] & 0x40) back_i += 1;
 
                         *outrow = (png_byte)back_i;
                      }
@@ -3248,18 +3246,18 @@ png_image_read_composite(png_voidp argument)
          {
             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
             png_bytep outrow;
-            png_const_bytep end_row;
+            png_const_bytep row_end;
 
             /* Read the row, which is packed: */
             png_read_row(png_ptr, inrow, NULL);
 
             outrow = png_voidcast(png_bytep, display->first_row);
             outrow += y * row_step;
-            end_row = outrow + width * channels;
+            row_end = outrow + width * channels;
 
             /* Now do the composition on each pixel in this row. */
             outrow += startx;
-            for (; outrow < end_row; outrow += stepx)
+            for (; outrow < row_end; outrow += stepx)
             {
                png_byte alpha = inrow[channels];
 
@@ -3432,14 +3430,14 @@ png_image_read_background(png_voidp argument)
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
                      png_bytep outrow = first_row + y * row_step;
-                     png_const_bytep end_row = outrow + width;
+                     png_const_bytep row_end = outrow + width;
 
                      /* Read the row, which is packed: */
                      png_read_row(png_ptr, inrow, NULL);
 
                      /* Now do the composition on each pixel in this row. */
                      outrow += startx;
-                     for (; outrow < end_row; outrow += stepx)
+                     for (; outrow < row_end; outrow += stepx)
                      {
                         png_byte alpha = inrow[1];
 
@@ -3477,14 +3475,14 @@ png_image_read_background(png_voidp argument)
                      png_bytep inrow = png_voidcast(png_bytep,
                          display->local_row);
                      png_bytep outrow = first_row + y * row_step;
-                     png_const_bytep end_row = outrow + width;
+                     png_const_bytep row_end = outrow + width;
 
                      /* Read the row, which is packed: */
                      png_read_row(png_ptr, inrow, NULL);
 
                      /* Now do the composition on each pixel in this row. */
                      outrow += startx;
-                     for (; outrow < end_row; outrow += stepx)
+                     for (; outrow < row_end; outrow += stepx)
                      {
                         png_byte alpha = inrow[1];
 
@@ -3567,7 +3565,7 @@ png_image_read_background(png_voidp argument)
                {
                   png_const_uint_16p inrow;
                   png_uint_16p outrow = first_row + y * row_step;
-                  png_uint_16p end_row = outrow + width * outchannels;
+                  png_uint_16p row_end = outrow + width * outchannels;
 
                   /* Read the row, which is packed: */
                   png_read_row(png_ptr, png_voidcast(png_bytep,
@@ -3577,7 +3575,7 @@ png_image_read_background(png_voidp argument)
                   /* Now do the pre-multiplication on each pixel in this row.
                    */
                   outrow += startx;
-                  for (; outrow < end_row; outrow += stepx)
+                  for (; outrow < row_end; outrow += stepx)
                   {
                      png_uint_32 component = inrow[0];
                      png_uint_16 alpha = inrow[1];
@@ -4113,7 +4111,7 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
             row_stride = (png_int_32)/*SAFE*/png_row_stride;
 
          if (row_stride < 0)
-            check = (png_uint_32)(-row_stride);
+            check = -(png_uint_32)row_stride;
 
          else
             check = (png_uint_32)row_stride;
diff --git a/libs/png/pngrtran.c b/libs/png/pngrtran.c
index fe8f9d32c980..978dac588801 100644
--- a/libs/png/pngrtran.c
+++ b/libs/png/pngrtran.c
@@ -1,6 +1,6 @@
 /* pngrtran.c - transforms the data in a row for PNG readers
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -230,7 +230,7 @@ png_set_strip_alpha(png_structrp png_ptr)
  *
  * Terminology (assuming power law, "gamma", encodings):
  *    "screen" gamma: a power law imposed by the output device when digital
- *    samples are converted to visible light output.  The EOTF - volage to
+ *    samples are converted to visible light output.  The EOTF - voltage to
  *    luminance on output.
  *
  *    "file" gamma: a power law used to encode luminance levels from the input
@@ -495,6 +495,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    if (png_rtran_ok(png_ptr, 0) == 0)
       return;
 
+   if (palette == NULL)
+      return;
+
    png_ptr->transformations |= PNG_QUANTIZE;
 
    if (full_quantize == 0)
@@ -708,8 +711,8 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
                          break;
 
                      t->next = hash[d];
-                     t->left = (png_byte)i;
-                     t->right = (png_byte)j;
+                     t->left = png_ptr->palette_to_index[i];
+                     t->right = png_ptr->palette_to_index[j];
                      hash[d] = t;
                   }
                }
@@ -811,7 +814,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette,
    }
    if (png_ptr->palette == NULL)
    {
-      png_ptr->palette = palette;
+      /* Allocate an owned copy rather than aliasing the caller's pointer,
+       * so that png_read_destroy can free png_ptr->palette unconditionally.
+       */
+      png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+          PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
    }
    png_ptr->num_palette = (png_uint_16)num_palette;
 
@@ -1364,7 +1373,7 @@ png_resolve_file_gamma(png_const_structrp png_ptr)
    if (file_gamma != 0)
       return file_gamma;
 
-   /* If png_reciprocal oveflows it returns 0 which indicates to the caller that
+   /* If png_reciprocal overflows, it returns 0, indicating to the caller that
     * there is no usable file gamma.  (The checks added to png_set_gamma and
     * png_set_alpha_mode should prevent a screen_gamma which would overflow.)
     */
@@ -2061,6 +2070,21 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
 {
    png_debug(1, "in png_read_transform_info");
 
+   if (png_ptr->transformations != 0)
+   {
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+          info_ptr->palette != NULL && png_ptr->palette != NULL)
+      {
+         /* Sync info_ptr->palette with png_ptr->palette.
+          * The function png_init_read_transformations may have modified
+          * png_ptr->palette in place (e.g. for gamma correction or for
+          * background compositing).
+          */
+         memcpy(info_ptr->palette, png_ptr->palette,
+             PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)));
+      }
+   }
+
 #ifdef PNG_READ_EXPAND_SUPPORTED
    if ((png_ptr->transformations & PNG_EXPAND) != 0)
    {
diff --git a/libs/png/pngrutil.c b/libs/png/pngrutil.c
index a4eda54c8cb3..3a35fe9de2d9 100644
--- a/libs/png/pngrutil.c
+++ b/libs/png/pngrutil.c
@@ -436,7 +436,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner)
     * be gained by using this when it is known *if* the zlib stream itself does
     * not record the number; however, this is an illusion: the original writer
     * of the PNG may have selected a lower window size, and we really must
-    * follow that because, for systems with with limited capabilities, we
+    * follow that because, for systems with limited capabilities, we
     * would otherwise reject the application's attempts to use a smaller window
     * size (zlib doesn't have an interface to say "this or lower"!).
     *
@@ -1006,7 +1006,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
     * in the case of an 8-bit display with a decoder which controls the palette.
     *
     * The alternative here is to ignore the error and store the palette anyway;
-    * destroying the tRNS will definately cause problems.
+    * destroying the tRNS will definitely cause problems.
     *
     * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because
     * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and
@@ -1053,19 +1053,6 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       /* A valid PLTE chunk has been read */
       png_ptr->mode |= PNG_HAVE_PLTE;
 
-      /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to
-       * its own copy of the palette.  This has the side effect that when
-       * png_start_row is called (this happens after any call to
-       * png_read_update_info) the info_ptr palette gets changed.  This is
-       * extremely unexpected and confusing.
-       *
-       * REVIEW: there have been consistent bugs in the past about gamma and
-       * similar transforms to colour mapped images being useless because the
-       * modified palette cannot be accessed because of the above.
-       *
-       * CONSIDER: Fix this by not sharing the palette in this way.  But does
-       * this completely fix the problem?
-       */
       png_set_PLTE(png_ptr, info_ptr, palette, num);
       return handled_ok;
    }
@@ -1267,7 +1254,7 @@ png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 
    /* png_set_cHRM may complain about some of the values but this doesn't matter
     * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous)
-    * values.  Ridiculousity will be checked if the values are used later.
+    * values.  Ridiculosity will be checked if the values are used later.
     */
    png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy,
          xy.greenx, xy.greeny, xy.bluex, xy.bluey);
@@ -1564,7 +1551,8 @@ static png_handle_result_code /* PRIVATE */
 png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 /* Note: this does not properly handle chunks that are > 64K under DOS */
 {
-   png_bytep entry_start, buffer;
+   png_bytep buffer;
+   png_bytep entry_start;
    png_sPLT_t new_palette;
    png_sPLT_entryp pp;
    png_uint_32 data_length;
@@ -1771,10 +1759,6 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       return handled_error;
    }
 
-   /* TODO: this is a horrible side effect in the palette case because the
-    * png_struct ends up with a pointer to the tRNS buffer owned by the
-    * png_info.  Fix this.
-    */
    png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
        &(png_ptr->trans_color));
    return handled_ok;
@@ -2033,7 +2017,7 @@ png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
       return handled_error;
 
    /* PNGv3: the code used to check the byte order mark at the start for MM or
-    * II, however PNGv3 states that the the first 4 bytes should be checked.
+    * II, however PNGv3 states that the first 4 bytes should be checked.
     * The caller ensures that there are four bytes available.
     */
    {
@@ -2155,9 +2139,13 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 static png_handle_result_code /* PRIVATE */
 png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length)
 {
+   png_bytep buffer;
+   png_bytep buf;
+   png_bytep endptr;
    png_int_32 X0, X1;
-   png_byte type, nparams;
-   png_bytep buffer, buf, units, endptr;
+   png_byte type;
+   png_byte nparams;
+   png_byte *units;
    png_charpp params;
    int i;
 
@@ -3011,7 +2999,7 @@ static const struct
    png_uint_32 max_length :12; /* Length min, max in bytes */
    png_uint_32 min_length :8;
       /* Length errors on critical chunks have special handling to preserve the
-       * existing behaviour in libpng 1.6.  Anciallary chunks are checked below
+       * existing behaviour in libpng 1.6.  Ancillary chunks are checked below
        * and produce a 'benign' error.
        */
    png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */
@@ -3019,7 +3007,7 @@ static const struct
       /* NOTE: PLTE, tRNS and bKGD require special handling which depends on
        * the colour type of the base image.
        */
-   png_uint_32 multiple   :1; /* Multiple occurences permitted */
+   png_uint_32 multiple   :1; /* Multiple occurrences permitted */
       /* This is enabled for PLTE because PLTE may, in practice, be optional */
 }
 read_chunks[PNG_INDEX_unknown] =
@@ -3053,7 +3041,7 @@ read_chunks[PNG_INDEX_unknown] =
 #  define CDIHDR      13U,   13U,  hIHDR,     0,        0
 #  define CDPLTE  NoCheck,    0U,      0, hIHDR,        1
       /* PLTE errors are only critical for colour-map images, consequently the
-       * hander does all the checks.
+       * handler does all the checks.
        */
 #  define CDIDAT  NoCheck,    0U,  aIDAT, hIHDR,        1
 #  define CDIEND  NoCheck,    0U,      0, aIDAT,        0
diff --git a/libs/png/pngset.c b/libs/png/pngset.c
index 3e63c2724ec8..b9ccb7fb156d 100644
--- a/libs/png/pngset.c
+++ b/libs/png/pngset.c
@@ -1,6 +1,6 @@
 /* pngset.c - storage of image information into info struct
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -333,7 +333,8 @@ png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
    png_debug1(1, "in %s storage function", "eXIf");
 
    if (png_ptr == NULL || info_ptr == NULL ||
-       (png_ptr->mode & PNG_WROTE_eXIf) != 0)
+       (png_ptr->mode & PNG_WROTE_eXIf) != 0 ||
+       exif == NULL)
       return;
 
    new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
@@ -388,7 +389,7 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
 
    png_debug1(1, "in %s storage function", "hIST");
 
-   if (png_ptr == NULL || info_ptr == NULL)
+   if (png_ptr == NULL || info_ptr == NULL || hist == NULL)
       return;
 
    if (info_ptr->num_palette == 0 || info_ptr->num_palette
@@ -775,28 +776,38 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
       png_error(png_ptr, "Invalid palette");
    }
 
-   /* It may not actually be necessary to set png_ptr->palette here;
-    * we do it for backward compatibility with the way the png_handle_tRNS
-    * function used to do the allocation.
-    *
-    * 1.6.0: the above statement appears to be incorrect; something has to set
-    * the palette inside png_struct on read.
-    */
    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
 
    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
     * of num_palette entries, in case of an invalid PNG file or incorrect
     * call to png_set_PLTE() with too-large sample values.
+    *
+    * Allocate independent buffers for info_ptr and png_ptr so that the
+    * lifetime of png_ptr->palette is decoupled from the lifetime of
+    * info_ptr->palette.  Previously, these two pointers were aliased,
+    * which caused a use-after-free vulnerability if png_free_data freed
+    * info_ptr->palette while png_ptr->palette was still in use by the
+    * row transform functions (e.g. png_do_expand_palette).
+    *
+    * Both buffers are allocated with png_calloc to zero-fill, because
+    * the ARM NEON palette riffle reads all 256 entries unconditionally,
+    * regardless of num_palette.
     */
+   png_free(png_ptr, png_ptr->palette);
    png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
        PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
+       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
+   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
 
    if (num_palette > 0)
+   {
+      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
+          (sizeof (png_color)));
       memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
           (sizeof (png_color)));
+   }
 
-   info_ptr->palette = png_ptr->palette;
-   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
    info_ptr->free_me |= PNG_FREE_PLTE;
    info_ptr->valid |= PNG_INFO_PLTE;
 }
@@ -1154,28 +1165,40 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 
    if (trans_alpha != NULL)
    {
-       /* It may not actually be necessary to set png_ptr->trans_alpha here;
-        * we do it for backward compatibility with the way the png_handle_tRNS
-        * function used to do the allocation.
-        *
-        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
-        * relies on png_set_tRNS storing the information in png_struct
-        * (otherwise it won't be there for the code in pngrtran.c).
-        */
-
        png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
 
        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
        {
-         /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
+          /* Allocate info_ptr's copy of the transparency data.
+           * Initialize all entries to fully opaque (0xff), then overwrite
+           * the first num_trans entries with the actual values.
+           */
           info_ptr->trans_alpha = png_voidcast(png_bytep,
               png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
           memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
-
           info_ptr->free_me |= PNG_FREE_TRNS;
           info_ptr->valid |= PNG_INFO_tRNS;
+
+          /* Allocate an independent copy for png_struct, so that the
+           * lifetime of png_ptr->trans_alpha is decoupled from the
+           * lifetime of info_ptr->trans_alpha.  Previously these two
+           * pointers were aliased, which caused a use-after-free if
+           * png_free_data freed info_ptr->trans_alpha while
+           * png_ptr->trans_alpha was still in use by the row transform
+           * functions (e.g. png_do_expand_palette).
+           */
+          png_free(png_ptr, png_ptr->trans_alpha);
+          png_ptr->trans_alpha = png_voidcast(png_bytep,
+              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
+          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
+          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
+       }
+       else
+       {
+          png_free(png_ptr, png_ptr->trans_alpha);
+          png_ptr->trans_alpha = NULL;
        }
-       png_ptr->trans_alpha = info_ptr->trans_alpha;
    }
 
    if (trans_color != NULL)
@@ -1873,7 +1896,7 @@ png_set_benign_errors(png_structrp png_ptr, int allowed)
 #endif /* BENIGN_ERRORS */
 
 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
-   /* Whether to report invalid palette index; added at libng-1.5.10.
+   /* Whether to report invalid palette index; added at libpng-1.5.10.
     * It is possible for an indexed (color-type==3) PNG file to contain
     * pixels with invalid (out-of-range) indexes if the PLTE chunk has
     * fewer entries than the image's bit-depth would allow. We recover
diff --git a/libs/png/pngstruct.h b/libs/png/pngstruct.h
index fe5fa0415548..5cd7ddb45a43 100644
--- a/libs/png/pngstruct.h
+++ b/libs/png/pngstruct.h
@@ -1,6 +1,6 @@
 /* pngstruct.h - internal structures for libpng
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -106,7 +106,7 @@ typedef enum
  * TODO: C23: convert these macros to C23 inlines (which are static).
  */
 #define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i)))
-   /* The flag coresponding to the given png_index enum value.  This is defined
+   /* The flag corresponding to the given png_index enum value.  This is defined
     * for png_unknown as well (until it reaches the value 32) but this should
     * not be relied on.
     */
@@ -115,7 +115,7 @@ typedef enum
    (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0)
    /* The chunk has been recorded in png_struct */
 
-#define png_file_add_chunk(pnt_ptr, i)\
+#define png_file_add_chunk(png_ptr, i)\
    ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i)))
    /* Record the chunk in the png_struct */
 
diff --git a/libs/png/pngtrans.c b/libs/png/pngtrans.c
index 19f5c641b2e8..32a5fd3c0f4b 100644
--- a/libs/png/pngtrans.c
+++ b/libs/png/pngtrans.c
@@ -1,6 +1,6 @@
 /* pngtrans.c - transforms the data in a row (used by both readers and writers)
  *
- * Copyright (c) 2018-2024 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -84,9 +84,38 @@ png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits)
 {
    png_debug(1, "in png_set_shift");
 
-   if (png_ptr == NULL)
+   if (png_ptr == NULL || true_bits == NULL)
       return;
 
+   /* Check the shift values before passing them on to png_do_shift. */
+   {
+      png_byte bit_depth = png_ptr->bit_depth;
+      int invalid = 0;
+
+      if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
+      {
+         if (true_bits->red == 0 || true_bits->red > bit_depth ||
+             true_bits->green == 0 || true_bits->green > bit_depth ||
+             true_bits->blue == 0 || true_bits->blue > bit_depth)
+            invalid = 1;
+      }
+      else
+      {
+         if (true_bits->gray == 0 || true_bits->gray > bit_depth)
+            invalid = 1;
+      }
+
+      if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 &&
+          (true_bits->alpha == 0 || true_bits->alpha > bit_depth))
+         invalid = 1;
+
+      if (invalid)
+      {
+         png_app_error(png_ptr, "png_set_shift: invalid shift values");
+         return;
+      }
+   }
+
    png_ptr->transformations |= PNG_SHIFT;
    png_ptr->shift = *true_bits;
 }
@@ -457,10 +486,9 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
 
    if (row_info->bit_depth < 8)
    {
+      png_const_bytep table;
       png_bytep rp;
-      png_const_bytep end, table;
-
-      end = row + row_info->rowbytes;
+      png_bytep row_end = row + row_info->rowbytes;
 
       if (row_info->bit_depth == 1)
          table = onebppswaptable;
@@ -474,7 +502,7 @@ png_do_packswap(png_row_infop row_info, png_bytep row)
       else
          return;
 
-      for (rp = row; rp < end; rp++)
+      for (rp = row; rp < row_end; rp++)
          *rp = table[*rp];
    }
 }
diff --git a/libs/png/pngwrite.c b/libs/png/pngwrite.c
index 362a8c3e16e6..2c95eb66ca74 100644
--- a/libs/png/pngwrite.c
+++ b/libs/png/pngwrite.c
@@ -159,7 +159,7 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr)
     * them.
     *
     * PNG v3: Chunks mDCV and cLLI provide ancillary information for the
-    * interpretation of the colourspace chunkgs but do not require support for
+    * interpretation of the colourspace chunks but do not require support for
     * those chunks so are outside the "COLORSPACE" check but before the write of
     * the colourspace chunks themselves.
     */
@@ -1010,6 +1010,16 @@ png_write_destroy(png_structrp png_ptr)
    png_ptr->chunk_list = NULL;
 #endif
 
+#if defined(PNG_tRNS_SUPPORTED)
+   /* Free the independent copy of trans_alpha owned by png_struct. */
+   png_free(png_ptr, png_ptr->trans_alpha);
+   png_ptr->trans_alpha = NULL;
+#endif
+
+   /* Free the independent copy of the palette owned by png_struct. */
+   png_free(png_ptr, png_ptr->palette);
+   png_ptr->palette = NULL;
+
    /* The error handling and memory handling information is left intact at this
     * point: the jmp_buf may still have to be freed.  See png_destroy_png_struct
     * for how this happens.
@@ -2020,7 +2030,7 @@ png_image_write_main(png_voidp argument)
             display->row_stride = (png_int_32)/*SAFE*/png_row_stride;
 
          if (display->row_stride < 0)
-            check = (png_uint_32)(-display->row_stride);
+            check = -(png_uint_32)display->row_stride;
 
          else
             check = (png_uint_32)display->row_stride;
@@ -2219,7 +2229,7 @@ png_image_write_main(png_voidp argument)
 
 
 static void (PNGCBAPI
-image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size)
+image_memory_write)(png_structp png_ptr, png_bytep data, size_t size)
 {
    png_image_write_control *display = png_voidcast(png_image_write_control*,
        png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/);
diff --git a/libs/png/pngwutil.c b/libs/png/pngwutil.c
index b4b845a7b6b7..e16c387c209f 100644
--- a/libs/png/pngwutil.c
+++ b/libs/png/pngwutil.c
@@ -1,6 +1,6 @@
 /* pngwutil.c - utilities to write a PNG file
  *
- * Copyright (c) 2018-2025 Cosmin Truta
+ * Copyright (c) 2018-2026 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -898,7 +898,6 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
    png_debug1(3, "num_palette = %d", png_ptr->num_palette);
 
    png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3));
-#ifdef PNG_POINTER_INDEXING_SUPPORTED
 
    for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
    {
@@ -908,21 +907,6 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
       png_write_chunk_data(png_ptr, buf, 3);
    }
 
-#else
-   /* This is a little slower but some buggy compilers need to do this
-    * instead
-    */
-   pal_ptr=palette;
-
-   for (i = 0; i < num_pal; i++)
-   {
-      buf[0] = pal_ptr[i].red;
-      buf[1] = pal_ptr[i].green;
-      buf[2] = pal_ptr[i].blue;
-      png_write_chunk_data(png_ptr, buf, 3);
-   }
-
-#endif
    png_write_chunk_end(png_ptr);
    png_ptr->mode |= PNG_HAVE_PLTE;
 }
@@ -1201,9 +1185,6 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
    size_t entry_size = (spalette->depth == 8 ? 6 : 10);
    size_t palette_size = entry_size * (size_t)spalette->nentries;
    png_sPLT_entryp ep;
-#ifndef PNG_POINTER_INDEXING_SUPPORTED
-   int i;
-#endif
 
    png_debug(1, "in png_write_sPLT");
 
@@ -1221,7 +1202,6 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
    png_write_chunk_data(png_ptr, &spalette->depth, 1);
 
    /* Loop through each palette entry, writing appropriately */
-#ifdef PNG_POINTER_INDEXING_SUPPORTED
    for (ep = spalette->entries; ep<spalette->entries + spalette->nentries; ep++)
    {
       if (spalette->depth == 8)
@@ -1244,31 +1224,6 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette)
 
       png_write_chunk_data(png_ptr, entrybuf, entry_size);
    }
-#else
-   ep=spalette->entries;
-   for (i = 0; i>spalette->nentries; i++)
-   {
-      if (spalette->depth == 8)
-      {
-         entrybuf[0] = (png_byte)ep[i].red;
-         entrybuf[1] = (png_byte)ep[i].green;
-         entrybuf[2] = (png_byte)ep[i].blue;
-         entrybuf[3] = (png_byte)ep[i].alpha;
-         png_save_uint_16(entrybuf + 4, ep[i].frequency);
-      }
-
-      else
-      {
-         png_save_uint_16(entrybuf + 0, ep[i].red);
-         png_save_uint_16(entrybuf + 2, ep[i].green);
-         png_save_uint_16(entrybuf + 4, ep[i].blue);
-         png_save_uint_16(entrybuf + 6, ep[i].alpha);
-         png_save_uint_16(entrybuf + 8, ep[i].frequency);
-      }
-
-      png_write_chunk_data(png_ptr, entrybuf, entry_size);
-   }
-#endif
 
    png_write_chunk_end(png_ptr);
 }
@@ -1738,7 +1693,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key,
    }
 
    new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE;
-   ++key_len; /* for the keywod separator */
+   ++key_len; /* for the keyword separator */
 
    /* We leave it to the application to meet PNG-1.0 requirements on the
     * contents of the text.  PNG-1.0 through PNG-1.2 discourage the use of
diff --git a/libs/strmiids/evr.c b/libs/strmiids/evr.c
index 3213b054a460..7dd83ba24871 100644
--- a/libs/strmiids/evr.c
+++ b/libs/strmiids/evr.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/strmiids/strmiids.c b/libs/strmiids/strmiids.c
index 1a7005bde3c5..6c1dd6a95863 100644
--- a/libs/strmiids/strmiids.c
+++ b/libs/strmiids/strmiids.c
@@ -9,6 +9,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/strsafe/strsafe.c b/libs/strsafe/strsafe.c
index bea913ef7c0d..f813b46247ee 100644
--- a/libs/strsafe/strsafe.c
+++ b/libs/strsafe/strsafe.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/uuid/d2d.c b/libs/uuid/d2d.c
index d8d97fb79136..532ecbf5b247 100644
--- a/libs/uuid/d2d.c
+++ b/libs/uuid/d2d.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/uuid/uuid.c b/libs/uuid/uuid.c
index ce97520eee05..dd12c7699221 100644
--- a/libs/uuid/uuid.c
+++ b/libs/uuid/uuid.c
@@ -9,6 +9,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/wbemuuid/wbemuuid.c b/libs/wbemuuid/wbemuuid.c
index 8fc3314d8dce..2a8ed959a23f 100644
--- a/libs/wbemuuid/wbemuuid.c
+++ b/libs/wbemuuid/wbemuuid.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/arm64ec.c b/libs/winecrt0/arm64ec.c
index a3af06b380d4..1930a27d6279 100644
--- a/libs/winecrt0/arm64ec.c
+++ b/libs/winecrt0/arm64ec.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/crt_dllmain.c b/libs/winecrt0/crt_dllmain.c
index 02dccdec511a..d14607fb0bbc 100644
--- a/libs/winecrt0/crt_dllmain.c
+++ b/libs/winecrt0/crt_dllmain.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/crt_fltused.c b/libs/winecrt0/crt_fltused.c
index 75abdfb3fa53..0803e785e760 100644
--- a/libs/winecrt0/crt_fltused.c
+++ b/libs/winecrt0/crt_fltused.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/debug.c b/libs/winecrt0/debug.c
index a7bf864aee52..5f8657112568 100644
--- a/libs/winecrt0/debug.c
+++ b/libs/winecrt0/debug.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/delay_load.c b/libs/winecrt0/delay_load.c
index 3044fa4431f6..bbd23a338981 100644
--- a/libs/winecrt0/delay_load.c
+++ b/libs/winecrt0/delay_load.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/dll_canunload.c b/libs/winecrt0/dll_canunload.c
index 08a60c347e1a..9ad7aa2ab0a4 100644
--- a/libs/winecrt0/dll_canunload.c
+++ b/libs/winecrt0/dll_canunload.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/dll_entry.c b/libs/winecrt0/dll_entry.c
index b5b6e2e61599..c6c8efa4a4ee 100644
--- a/libs/winecrt0/dll_entry.c
+++ b/libs/winecrt0/dll_entry.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/dll_main.c b/libs/winecrt0/dll_main.c
index a177438584c4..3b2acab975c1 100644
--- a/libs/winecrt0/dll_main.c
+++ b/libs/winecrt0/dll_main.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/dll_register.c b/libs/winecrt0/dll_register.c
index 0adb1d716d9a..c73a3ddd87e8 100644
--- a/libs/winecrt0/dll_register.c
+++ b/libs/winecrt0/dll_register.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/dll_soinit.c b/libs/winecrt0/dll_soinit.c
index 77f5db3d2844..88d00d1fd3b7 100644
--- a/libs/winecrt0/dll_soinit.c
+++ b/libs/winecrt0/dll_soinit.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/dll_version.c b/libs/winecrt0/dll_version.c
index a96976e54173..a90385aa88cb 100644
--- a/libs/winecrt0/dll_version.c
+++ b/libs/winecrt0/dll_version.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/exception.c b/libs/winecrt0/exception.c
index 193981c583f3..4127312c64f0 100644
--- a/libs/winecrt0/exception.c
+++ b/libs/winecrt0/exception.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/exe16_entry.c b/libs/winecrt0/exe16_entry.c
index 02992ab049e3..a1db3a2707a0 100644
--- a/libs/winecrt0/exe16_entry.c
+++ b/libs/winecrt0/exe16_entry.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/exe_entry.c b/libs/winecrt0/exe_entry.c
index def7b57c38d5..f54081b0c9a7 100644
--- a/libs/winecrt0/exe_entry.c
+++ b/libs/winecrt0/exe_entry.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/exe_main.c b/libs/winecrt0/exe_main.c
index 2465c83bdf04..591a29dab3ec 100644
--- a/libs/winecrt0/exe_main.c
+++ b/libs/winecrt0/exe_main.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/exe_wentry.c b/libs/winecrt0/exe_wentry.c
index 303e9e5a69be..9c1aa46c86cd 100644
--- a/libs/winecrt0/exe_wentry.c
+++ b/libs/winecrt0/exe_wentry.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/exe_wmain.c b/libs/winecrt0/exe_wmain.c
index 4a567661ea50..2f08ddaeaa92 100644
--- a/libs/winecrt0/exe_wmain.c
+++ b/libs/winecrt0/exe_wmain.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/gcc_ctors.c b/libs/winecrt0/gcc_ctors.c
index 21b7778d38c5..ed0ab9d3335c 100644
--- a/libs/winecrt0/gcc_ctors.c
+++ b/libs/winecrt0/gcc_ctors.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/register.c b/libs/winecrt0/register.c
index 757e424fed50..73a5e726ff76 100644
--- a/libs/winecrt0/register.c
+++ b/libs/winecrt0/register.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/setjmp.c b/libs/winecrt0/setjmp.c
index a79deebf05ef..d534f08984f7 100644
--- a/libs/winecrt0/setjmp.c
+++ b/libs/winecrt0/setjmp.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/stub.c b/libs/winecrt0/stub.c
index c1198561886a..2cc7f508a874 100644
--- a/libs/winecrt0/stub.c
+++ b/libs/winecrt0/stub.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/tls.c b/libs/winecrt0/tls.c
index 67f52e0e5da5..bc40a9e10188 100644
--- a/libs/winecrt0/tls.c
+++ b/libs/winecrt0/tls.c
@@ -6,6 +6,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/winecrt0/unix_lib.c b/libs/winecrt0/unix_lib.c
index 037a763e53be..32d8884492ec 100644
--- a/libs/winecrt0/unix_lib.c
+++ b/libs/winecrt0/unix_lib.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/wmcodecdspuuid/wmcodecdspuuid.c b/libs/wmcodecdspuuid/wmcodecdspuuid.c
index c715641dda29..62d57e491b7c 100644
--- a/libs/wmcodecdspuuid/wmcodecdspuuid.c
+++ b/libs/wmcodecdspuuid/wmcodecdspuuid.c
@@ -8,6 +8,14 @@
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
+ * In addition to the permissions in the GNU Lesser General Public License,
+ * the authors give you unlimited permission to link the compiled version
+ * of this file with other programs, and to distribute those programs
+ * without any restriction coming from the use of this file.  (The GNU
+ * Lesser General Public License restrictions do apply in other respects;
+ * for example, they cover modification of the file, and distribution when
+ * not linked into another program.)
+ *
  * 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
diff --git a/libs/zlib/LICENSE b/libs/zlib/LICENSE
index ab8ee6f71428..b7a69d058e61 100644
--- a/libs/zlib/LICENSE
+++ b/libs/zlib/LICENSE
@@ -1,6 +1,6 @@
 Copyright notice:
 
- (C) 1995-2022 Jean-loup Gailly and Mark Adler
+ (C) 1995-2026 Jean-loup Gailly and Mark Adler
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
diff --git a/libs/zlib/crc32.c b/libs/zlib/crc32.c
index 6c38f5c04c6a..d9ade5150239 100644
--- a/libs/zlib/crc32.c
+++ b/libs/zlib/crc32.c
@@ -1,5 +1,5 @@
 /* crc32.c -- compute the CRC-32 of a data stream
- * Copyright (C) 1995-2022 Mark Adler
+ * Copyright (C) 1995-2026 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  *
  * This interleaved implementation of a CRC makes use of pipelined multiple
@@ -24,11 +24,18 @@
 #  include <stdio.h>
 #  ifndef DYNAMIC_CRC_TABLE
 #    define DYNAMIC_CRC_TABLE
-#  endif /* !DYNAMIC_CRC_TABLE */
-#endif /* MAKECRCH */
+#  endif
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+#  define Z_ONCE
+#endif
 
 #include "zutil.h"      /* for Z_U4, Z_U8, z_crc_t, and FAR definitions */
 
+#ifdef HAVE_S390X_VX
+#  include "contrib/crc32vx/crc32_vx_hooks.h"
+#endif
+
  /*
   A CRC of a message is computed on N braids of words in the message, where
   each word consists of W bytes (4 or 8). If N is 3, for example, then three
@@ -99,7 +106,8 @@
 #endif
 
 /* If available, use the ARM processor CRC32 instruction. */
-#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8
+#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && \
+    defined(W) && W == 8
 #  define ARMCRC32
 #endif
 
@@ -152,10 +160,10 @@ local z_word_t byte_swap(z_word_t word) {
   Return a(x) multiplied by b(x) modulo p(x), where p(x) is the CRC polynomial,
   reflected. For speed, this requires that a not be zero.
  */
-local z_crc_t multmodp(z_crc_t a, z_crc_t b) {
-    z_crc_t m, p;
+local uLong multmodp(uLong a, uLong b) {
+    uLong m, p;
 
-    m = (z_crc_t)1 << 31;
+    m = (uLong)1 << 31;
     p = 0;
     for (;;) {
         if (a & m) {
@@ -171,12 +179,12 @@ local z_crc_t multmodp(z_crc_t a, z_crc_t b) {
 
 /*
   Return x^(n * 2^k) modulo p(x). Requires that x2n_table[] has been
-  initialized.
+  initialized. n must not be negative.
  */
-local z_crc_t x2nmodp(z_off64_t n, unsigned k) {
-    z_crc_t p;
+local uLong x2nmodp(z_off64_t n, unsigned k) {
+    uLong p;
 
-    p = (z_crc_t)1 << 31;           /* x^0 == 1 */
+    p = (uLong)1 << 31;             /* x^0 == 1 */
     while (n) {
         if (n & 1)
             p = multmodp(x2n_table[k & 31], p);
@@ -204,83 +212,8 @@ local z_crc_t FAR crc_table[256];
    local void write_table64(FILE *, const z_word_t FAR *, int);
 #endif /* MAKECRCH */
 
-/*
-  Define a once() function depending on the availability of atomics. If this is
-  compiled with DYNAMIC_CRC_TABLE defined, and if CRCs will be computed in
-  multiple threads, and if atomics are not available, then get_crc_table() must
-  be called to initialize the tables and must return before any threads are
-  allowed to compute or combine CRCs.
- */
-
-/* Definition of once functionality. */
-typedef struct once_s once_t;
-
-/* Check for the availability of atomics. */
-#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
-    !defined(__STDC_NO_ATOMICS__)
-
-#include <stdatomic.h>
-
-/* Structure for once(), which must be initialized with ONCE_INIT. */
-struct once_s {
-    atomic_flag begun;
-    atomic_int done;
-};
-#define ONCE_INIT {ATOMIC_FLAG_INIT, 0}
-
-/*
-  Run the provided init() function exactly once, even if multiple threads
-  invoke once() at the same time. The state must be a once_t initialized with
-  ONCE_INIT.
- */
-local void once(once_t *state, void (*init)(void)) {
-    if (!atomic_load(&state->done)) {
-        if (atomic_flag_test_and_set(&state->begun))
-            while (!atomic_load(&state->done))
-                ;
-        else {
-            init();
-            atomic_store(&state->done, 1);
-        }
-    }
-}
-
-#else   /* no atomics */
-
-/* Structure for once(), which must be initialized with ONCE_INIT. */
-struct once_s {
-    volatile int begun;
-    volatile int done;
-};
-#define ONCE_INIT {0, 0}
-
-/* Test and set. Alas, not atomic, but tries to minimize the period of
-   vulnerability. */
-local int test_and_set(int volatile *flag) {
-    int was;
-
-    was = *flag;
-    *flag = 1;
-    return was;
-}
-
-/* Run the provided init() function once. This is not thread-safe. */
-local void once(once_t *state, void (*init)(void)) {
-    if (!state->done) {
-        if (test_and_set(&state->begun))
-            while (!state->done)
-                ;
-        else {
-            init();
-            state->done = 1;
-        }
-    }
-}
-
-#endif
-
 /* State for once(). */
-local once_t made = ONCE_INIT;
+local z_once_t made = Z_ONCE_INIT;
 
 /*
   Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
@@ -326,7 +259,7 @@ local void make_crc_table(void) {
     p = (z_crc_t)1 << 30;         /* x^1 */
     x2n_table[0] = p;
     for (n = 1; n < 32; n++)
-        x2n_table[n] = p = multmodp(p, p);
+        x2n_table[n] = p = (z_crc_t)multmodp(p, p);
 
 #ifdef W
     /* initialize the braiding tables -- needs x2n_table[] */
@@ -529,11 +462,11 @@ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {
     int k;
     z_crc_t i, p, q;
     for (k = 0; k < w; k++) {
-        p = x2nmodp((n * w + 3 - k) << 3, 0);
+        p = (z_crc_t)x2nmodp((n * w + 3 - k) << 3, 0);
         ltl[k][0] = 0;
         big[w - 1 - k][0] = 0;
         for (i = 1; i < 256; i++) {
-            ltl[k][i] = q = multmodp(i << 24, p);
+            ltl[k][i] = q = (z_crc_t)multmodp(i << 24, p);
             big[w - 1 - k][i] = byte_swap(q);
         }
     }
@@ -548,7 +481,7 @@ local void braid(z_crc_t ltl[][256], z_word_t big[][256], int n, int w) {
  */
 const z_crc_t FAR * ZEXPORT get_crc_table(void) {
 #ifdef DYNAMIC_CRC_TABLE
-    once(&made, make_crc_table);
+    z_once(&made, make_crc_table);
 #endif /* DYNAMIC_CRC_TABLE */
     return (const z_crc_t FAR *)crc_table;
 }
@@ -572,9 +505,8 @@ const z_crc_t FAR * ZEXPORT get_crc_table(void) {
 #define Z_BATCH_ZEROS 0xa10d3d0c    /* computed from Z_BATCH = 3990 */
 #define Z_BATCH_MIN 800             /* fewest words in a final batch */
 
-unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
-                              z_size_t len) {
-    z_crc_t val;
+uLong ZEXPORT crc32_z(uLong crc, const unsigned char FAR *buf, z_size_t len) {
+    uLong val;
     z_word_t crc1, crc2;
     const z_word_t *word;
     z_word_t val0, val1, val2;
@@ -585,7 +517,7 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
     if (buf == Z_NULL) return 0;
 
 #ifdef DYNAMIC_CRC_TABLE
-    once(&made, make_crc_table);
+    z_once(&made, make_crc_table);
 #endif /* DYNAMIC_CRC_TABLE */
 
     /* Pre-condition the CRC */
@@ -640,7 +572,7 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
         }
         word += 3 * last;
         num -= 3 * last;
-        val = x2nmodp(last, 6);
+        val = x2nmodp((int)last, 6);
         crc = multmodp(val, crc) ^ crc1;
         crc = multmodp(val, crc) ^ crc2;
     }
@@ -691,13 +623,12 @@ local z_word_t crc_word_big(z_word_t data) {
 #endif
 
 /* ========================================================================= */
-unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
-                              z_size_t len) {
+uLong ZEXPORT crc32_z(uLong crc, const unsigned char FAR *buf, z_size_t len) {
     /* Return initial CRC, if requested. */
     if (buf == Z_NULL) return 0;
 
 #ifdef DYNAMIC_CRC_TABLE
-    once(&made, make_crc_table);
+    z_once(&made, make_crc_table);
 #endif /* DYNAMIC_CRC_TABLE */
 
     /* Pre-condition the CRC */
@@ -1012,38 +943,41 @@ unsigned long ZEXPORT crc32_z(unsigned long crc, const unsigned char FAR *buf,
 #endif
 
 /* ========================================================================= */
-unsigned long ZEXPORT crc32(unsigned long crc, const unsigned char FAR *buf,
-                            uInt len) {
+uLong ZEXPORT crc32(uLong crc, const unsigned char FAR *buf, uInt len) {
+    #ifdef HAVE_S390X_VX
+    return crc32_z_hook(crc, buf, len);
+    #endif
     return crc32_z(crc, buf, len);
 }
 
 /* ========================================================================= */
-uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {
+uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {
+    if (len2 < 0)
+        return 0;
 #ifdef DYNAMIC_CRC_TABLE
-    once(&made, make_crc_table);
+    z_once(&made, make_crc_table);
 #endif /* DYNAMIC_CRC_TABLE */
-    return multmodp(x2nmodp(len2, 3), crc1) ^ (crc2 & 0xffffffff);
+    return x2nmodp(len2, 3);
 }
 
 /* ========================================================================= */
-uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {
-    return crc32_combine64(crc1, crc2, (z_off64_t)len2);
+uLong ZEXPORT crc32_combine_gen(z_off_t len2) {
+    return crc32_combine_gen64((z_off64_t)len2);
 }
 
 /* ========================================================================= */
-uLong ZEXPORT crc32_combine_gen64(z_off64_t len2) {
-#ifdef DYNAMIC_CRC_TABLE
-    once(&made, make_crc_table);
-#endif /* DYNAMIC_CRC_TABLE */
-    return x2nmodp(len2, 3);
+uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) {
+    if (op == 0)
+        return 0;
+    return multmodp(op, crc1 & 0xffffffff) ^ (crc2 & 0xffffffff);
 }
 
 /* ========================================================================= */
-uLong ZEXPORT crc32_combine_gen(z_off_t len2) {
-    return crc32_combine_gen64((z_off64_t)len2);
+uLong ZEXPORT crc32_combine64(uLong crc1, uLong crc2, z_off64_t len2) {
+    return crc32_combine_op(crc1, crc2, crc32_combine_gen64(len2));
 }
 
 /* ========================================================================= */
-uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op) {
-    return multmodp(op, crc1) ^ (crc2 & 0xffffffff);
+uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2) {
+    return crc32_combine64(crc1, crc2, (z_off64_t)len2);
 }
diff --git a/libs/zlib/deflate.c b/libs/zlib/deflate.c
index 012ea8148e8d..d7d2c7c1ee4e 100644
--- a/libs/zlib/deflate.c
+++ b/libs/zlib/deflate.c
@@ -1,5 +1,5 @@
 /* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
+ * Copyright (C) 1995-2026 Jean-loup Gailly and Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -37,7 +37,7 @@
  *  REFERENCES
  *
  *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
- *      Available in http://tools.ietf.org/html/rfc1951
+ *      Available at https://datatracker.ietf.org/doc/html/rfc1951
  *
  *      A description of the Rabin and Karp algorithm is given in the book
  *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
@@ -52,7 +52,7 @@
 #include "deflate.h"
 
 const char deflate_copyright[] =
-   " deflate 1.3.1 Copyright 1995-2024 Jean-loup Gailly and Mark Adler ";
+   " deflate 1.3.2 Copyright 1995-2026 Jean-loup Gailly and Mark Adler ";
 /*
   If you use the zlib library in a product, an acknowledgment is welcome
   in the documentation of your product. If for some reason you cannot
@@ -170,8 +170,8 @@ local const config configuration_table[10] = {
 #define CLEAR_HASH(s) \
     do { \
         s->head[s->hash_size - 1] = NIL; \
-        zmemzero((Bytef *)s->head, \
-                 (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \
+        zmemzero(s->head, (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \
+        s->slid = 0; \
     } while (0)
 
 /* ===========================================================================
@@ -195,8 +195,8 @@ local void slide_hash(deflate_state *s) {
         m = *--p;
         *p = (Pos)(m >= wsize ? m - wsize : NIL);
     } while (--n);
-    n = wsize;
 #ifndef FASTEST
+    n = wsize;
     p = &s->prev[n];
     do {
         m = *--p;
@@ -206,6 +206,7 @@ local void slide_hash(deflate_state *s) {
          */
     } while (--n);
 #endif
+    s->slid = 1;
 }
 
 /* ===========================================================================
@@ -259,7 +260,14 @@ local void fill_window(deflate_state *s) {
         more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
 
         /* Deal with !@#$% 64K limit: */
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable: 4127)
+#endif
         if (sizeof(int) <= 2) {
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
             if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
                 more = wsize;
 
@@ -431,6 +439,7 @@ int ZEXPORT deflateInit2_(z_streamp strm, int level, int method,
     if (windowBits == 8) windowBits = 9;  /* until 256-byte window bug fixed */
     s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
     if (s == Z_NULL) return Z_MEM_ERROR;
+    zmemzero(s, sizeof(deflate_state));
     strm->state = (struct internal_state FAR *)s;
     s->strm = strm;
     s->status = INIT_STATE;     /* to pass state test in deflateReset() */
@@ -712,10 +721,23 @@ int ZEXPORT deflateSetHeader(z_streamp strm, gz_headerp head) {
 /* ========================================================================= */
 int ZEXPORT deflatePending(z_streamp strm, unsigned *pending, int *bits) {
     if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
-    if (pending != Z_NULL)
-        *pending = strm->state->pending;
     if (bits != Z_NULL)
         *bits = strm->state->bi_valid;
+    if (pending != Z_NULL) {
+        *pending = (unsigned)strm->state->pending;
+        if (*pending != strm->state->pending) {
+            *pending = (unsigned)-1;
+            return Z_BUF_ERROR;
+        }
+    }
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateUsed(z_streamp strm, int *bits) {
+    if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
+    if (bits != Z_NULL)
+        *bits = strm->state->bi_used;
     return Z_OK;
 }
 
@@ -831,28 +853,34 @@ int ZEXPORT deflateTune(z_streamp strm, int good_length, int max_lazy,
  *
  * Shifts are used to approximate divisions, for speed.
  */
-uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
+z_size_t ZEXPORT deflateBound_z(z_streamp strm, z_size_t sourceLen) {
     deflate_state *s;
-    uLong fixedlen, storelen, wraplen;
+    z_size_t fixedlen, storelen, wraplen, bound;
 
     /* upper bound for fixed blocks with 9-bit literals and length 255
        (memLevel == 2, which is the lowest that may not use stored blocks) --
        ~13% overhead plus a small constant */
     fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) +
                (sourceLen >> 9) + 4;
+    if (fixedlen < sourceLen)
+        fixedlen = (z_size_t)-1;
 
     /* upper bound for stored blocks with length 127 (memLevel == 1) --
        ~4% overhead plus a small constant */
     storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) +
                (sourceLen >> 11) + 7;
+    if (storelen < sourceLen)
+        storelen = (z_size_t)-1;
 
-    /* if can't get parameters, return larger bound plus a zlib wrapper */
-    if (deflateStateCheck(strm))
-        return (fixedlen > storelen ? fixedlen : storelen) + 6;
+    /* if can't get parameters, return larger bound plus a wrapper */
+    if (deflateStateCheck(strm)) {
+        bound = fixedlen > storelen ? fixedlen : storelen;
+        return bound + 18 < bound ? (z_size_t)-1 : bound + 18;
+    }
 
     /* compute wrapper length */
     s = strm->state;
-    switch (s->wrap) {
+    switch (s->wrap < 0 ? -s->wrap : s->wrap) {
     case 0:                                 /* raw deflate */
         wraplen = 0;
         break;
@@ -882,18 +910,25 @@ uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
         break;
 #endif
     default:                                /* for compiler happiness */
-        wraplen = 6;
+        wraplen = 18;
     }
 
     /* if not default parameters, return one of the conservative bounds */
-    if (s->w_bits != 15 || s->hash_bits != 8 + 7)
-        return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) +
-               wraplen;
+    if (s->w_bits != 15 || s->hash_bits != 8 + 7) {
+        bound = s->w_bits <= s->hash_bits && s->level ? fixedlen :
+                                                        storelen;
+        return bound + wraplen < bound ? (z_size_t)-1 : bound + wraplen;
+    }
 
     /* default settings: return tight bound for that case -- ~0.03% overhead
        plus a small constant */
-    return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
-           (sourceLen >> 25) + 13 - 6 + wraplen;
+    bound = sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+            (sourceLen >> 25) + 13 - 6 + wraplen;
+    return bound < sourceLen ? (z_size_t)-1 : bound;
+}
+uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen) {
+    z_size_t bound = deflateBound_z(strm, sourceLen);
+    return (uLong)bound != bound ? (uLong)-1 : (uLong)bound;
 }
 
 /* =========================================================================
@@ -917,8 +952,8 @@ local void flush_pending(z_streamp strm) {
     deflate_state *s = strm->state;
 
     _tr_flush_bits(s);
-    len = s->pending;
-    if (len > strm->avail_out) len = strm->avail_out;
+    len = s->pending > strm->avail_out ? strm->avail_out :
+                                         (unsigned)s->pending;
     if (len == 0) return;
 
     zmemcpy(strm->next_out, s->pending_out, len);
@@ -938,8 +973,8 @@ local void flush_pending(z_streamp strm) {
 #define HCRC_UPDATE(beg) \
     do { \
         if (s->gzhead->hcrc && s->pending > (beg)) \
-            strm->adler = crc32(strm->adler, s->pending_buf + (beg), \
-                                s->pending - (beg)); \
+            strm->adler = crc32_z(strm->adler, s->pending_buf + (beg), \
+                                  s->pending - (beg)); \
     } while (0)
 
 /* ========================================================================= */
@@ -1073,8 +1108,8 @@ int ZEXPORT deflate(z_streamp strm, int flush) {
                 put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
             }
             if (s->gzhead->hcrc)
-                strm->adler = crc32(strm->adler, s->pending_buf,
-                                    s->pending);
+                strm->adler = crc32_z(strm->adler, s->pending_buf,
+                                      s->pending);
             s->gzindex = 0;
             s->status = EXTRA_STATE;
         }
@@ -1082,9 +1117,9 @@ int ZEXPORT deflate(z_streamp strm, int flush) {
     if (s->status == EXTRA_STATE) {
         if (s->gzhead->extra != Z_NULL) {
             ulg beg = s->pending;   /* start of bytes to update crc */
-            uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
+            ulg left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
             while (s->pending + left > s->pending_buf_size) {
-                uInt copy = s->pending_buf_size - s->pending;
+                ulg copy = s->pending_buf_size - s->pending;
                 zmemcpy(s->pending_buf + s->pending,
                         s->gzhead->extra + s->gzindex, copy);
                 s->pending = s->pending_buf_size;
@@ -1295,12 +1330,13 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
 
     ss = source->state;
 
-    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+    zmemcpy(dest, source, sizeof(z_stream));
 
     ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
     if (ds == Z_NULL) return Z_MEM_ERROR;
+    zmemzero(ds, sizeof(deflate_state));
     dest->state = (struct internal_state FAR *) ds;
-    zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
+    zmemcpy(ds, ss, sizeof(deflate_state));
     ds->strm = dest;
 
     ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
@@ -1313,18 +1349,23 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
         deflateEnd (dest);
         return Z_MEM_ERROR;
     }
-    /* following zmemcpy do not work for 16-bit MSDOS */
-    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
-    zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
-    zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
-    zmemcpy(ds->pending_buf, ss->pending_buf, ds->lit_bufsize * LIT_BUFS);
+    /* following zmemcpy's do not work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ss->high_water);
+    zmemcpy(ds->prev, ss->prev,
+            (ss->slid || ss->strstart - ss->insert > ds->w_size ? ds->w_size :
+                ss->strstart - ss->insert) * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
 
     ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    zmemcpy(ds->pending_out, ss->pending_out, ss->pending);
 #ifdef LIT_MEM
     ds->d_buf = (ushf *)(ds->pending_buf + (ds->lit_bufsize << 1));
     ds->l_buf = ds->pending_buf + (ds->lit_bufsize << 2);
+    zmemcpy(ds->d_buf, ss->d_buf, ss->sym_next * sizeof(ush));
+    zmemcpy(ds->l_buf, ss->l_buf, ss->sym_next);
 #else
     ds->sym_buf = ds->pending_buf + ds->lit_bufsize;
+    zmemcpy(ds->sym_buf, ss->sym_buf, ss->sym_next);
 #endif
 
     ds->l_desc.dyn_tree = ds->dyn_ltree;
@@ -1347,9 +1388,9 @@ int ZEXPORT deflateCopy(z_streamp dest, z_streamp source) {
  */
 local uInt longest_match(deflate_state *s, IPos cur_match) {
     unsigned chain_length = s->max_chain_length;/* max hash chain length */
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                      /* matched string */
-    register int len;                           /* length of current match */
+    Bytef *scan = s->window + s->strstart;      /* current string */
+    Bytef *match;                               /* matched string */
+    int len;                                    /* length of current match */
     int best_len = (int)s->prev_length;         /* best match length so far */
     int nice_match = s->nice_match;             /* stop if match long enough */
     IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
@@ -1364,13 +1405,13 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
     /* Compare two bytes at a time. Note: this is not always beneficial.
      * Try with and without -DUNALIGNED_OK to check.
      */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
-    register ush scan_start = *(ushf*)scan;
-    register ush scan_end   = *(ushf*)(scan + best_len - 1);
+    Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    ush scan_start = *(ushf*)scan;
+    ush scan_end   = *(ushf*)(scan + best_len - 1);
 #else
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
-    register Byte scan_end1  = scan[best_len - 1];
-    register Byte scan_end   = scan[best_len];
+    Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    Byte scan_end1  = scan[best_len - 1];
+    Byte scan_end   = scan[best_len];
 #endif
 
     /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
@@ -1494,10 +1535,10 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
  * Optimized version for FASTEST only
  */
 local uInt longest_match(deflate_state *s, IPos cur_match) {
-    register Bytef *scan = s->window + s->strstart; /* current string */
-    register Bytef *match;                       /* matched string */
-    register int len;                           /* length of current match */
-    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    Bytef *scan = s->window + s->strstart;      /* current string */
+    Bytef *match;                               /* matched string */
+    int len;                                    /* length of current match */
+    Bytef *strend = s->window + s->strstart + MAX_MATCH;
 
     /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
      * It is easy to get rid of this optimization if necessary.
@@ -1557,7 +1598,7 @@ local uInt longest_match(deflate_state *s, IPos cur_match) {
 local void check_match(deflate_state *s, IPos start, IPos match, int length) {
     /* check that the match is indeed a match */
     Bytef *back = s->window + (int)match, *here = s->window + start;
-    IPos len = length;
+    IPos len = (IPos)length;
     if (match == (IPos)-1) {
         /* match starts one byte before the current window -- just compare the
            subsequent length-1 bytes */
@@ -1629,13 +1670,14 @@ local block_state deflate_stored(deflate_state *s, int flush) {
      * this is 32K. This can be as small as 507 bytes for memLevel == 1. For
      * large input and output buffers, the stored block size will be larger.
      */
-    unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);
+    unsigned min_block = (unsigned)(MIN(s->pending_buf_size - 5, s->w_size));
 
     /* Copy as many min_block or larger stored blocks directly to next_out as
      * possible. If flushing, copy the remaining available input to next_out as
      * stored blocks, if there is enough space.
      */
-    unsigned len, left, have, last = 0;
+    int last = 0;
+    unsigned len, left, have;
     unsigned used = s->strm->avail_in;
     do {
         /* Set len to the maximum size block that we can copy directly with the
@@ -1643,12 +1685,12 @@ local block_state deflate_stored(deflate_state *s, int flush) {
          * would be copied from what's left in the window.
          */
         len = MAX_STORED;       /* maximum deflate stored block length */
-        have = (s->bi_valid + 42) >> 3;         /* number of header bytes */
+        have = ((unsigned)s->bi_valid + 42) >> 3;   /* bytes in header */
         if (s->strm->avail_out < have)          /* need room for header */
             break;
             /* maximum stored block length that will fit in avail_out: */
         have = s->strm->avail_out - have;
-        left = s->strstart - s->block_start;    /* bytes left in window */
+        left = (unsigned)(s->strstart - s->block_start);    /* window bytes */
         if (len > (ulg)left + s->strm->avail_in)
             len = left + s->strm->avail_in;     /* limit len to the input */
         if (len > have)
@@ -1671,10 +1713,10 @@ local block_state deflate_stored(deflate_state *s, int flush) {
         _tr_stored_block(s, (char *)0, 0L, last);
 
         /* Replace the lengths in the dummy stored block with len. */
-        s->pending_buf[s->pending - 4] = len;
-        s->pending_buf[s->pending - 3] = len >> 8;
-        s->pending_buf[s->pending - 2] = ~len;
-        s->pending_buf[s->pending - 1] = ~len >> 8;
+        s->pending_buf[s->pending - 4] = (Bytef)len;
+        s->pending_buf[s->pending - 3] = (Bytef)(len >> 8);
+        s->pending_buf[s->pending - 2] = (Bytef)~len;
+        s->pending_buf[s->pending - 1] = (Bytef)(~len >> 8);
 
         /* Write the stored block header bytes. */
         flush_pending(s->strm);
@@ -1745,8 +1787,10 @@ local block_state deflate_stored(deflate_state *s, int flush) {
         s->high_water = s->strstart;
 
     /* If the last block was written to next_out, then done. */
-    if (last)
+    if (last) {
+        s->bi_used = 8;
         return finish_done;
+    }
 
     /* If flushing and all input has been consumed, then done. */
     if (flush != Z_NO_FLUSH && flush != Z_FINISH &&
@@ -1754,7 +1798,7 @@ local block_state deflate_stored(deflate_state *s, int flush) {
         return block_done;
 
     /* Fill the window with any remaining input. */
-    have = s->window_size - s->strstart;
+    have = (unsigned)(s->window_size - s->strstart);
     if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {
         /* Slide the window down. */
         s->block_start -= s->w_size;
@@ -1781,11 +1825,11 @@ local block_state deflate_stored(deflate_state *s, int flush) {
      * have enough input for a worthy block, or if flushing and there is enough
      * room for the remaining input as a stored block in the pending buffer.
      */
-    have = (s->bi_valid + 42) >> 3;         /* number of header bytes */
+    have = ((unsigned)s->bi_valid + 42) >> 3;   /* bytes in header */
         /* maximum stored block length that will fit in pending: */
-    have = MIN(s->pending_buf_size - have, MAX_STORED);
+    have = (unsigned)MIN(s->pending_buf_size - have, MAX_STORED);
     min_block = MIN(have, s->w_size);
-    left = s->strstart - s->block_start;
+    left = (unsigned)(s->strstart - s->block_start);
     if (left >= min_block ||
         ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&
          s->strm->avail_in == 0 && left <= have)) {
@@ -1798,6 +1842,8 @@ local block_state deflate_stored(deflate_state *s, int flush) {
     }
 
     /* We've done all we can with the available input and output. */
+    if (last)
+        s->bi_used = 8;
     return last ? finish_started : need_more;
 }
 
@@ -1846,7 +1892,7 @@ local block_state deflate_fast(deflate_state *s, int flush) {
             /* longest_match() sets match_start */
         }
         if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->match_start, s->match_length);
+            check_match(s, s->strstart, s->match_start, (int)s->match_length);
 
             _tr_tally_dist(s, s->strstart - s->match_start,
                            s->match_length - MIN_MATCH, bflush);
@@ -1968,7 +2014,7 @@ local block_state deflate_slow(deflate_state *s, int flush) {
             uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
             /* Do not insert strings in hash table beyond this. */
 
-            check_match(s, s->strstart - 1, s->prev_match, s->prev_length);
+            check_match(s, s->strstart - 1, s->prev_match, (int)s->prev_length);
 
             _tr_tally_dist(s, s->strstart - 1 - s->prev_match,
                            s->prev_length - MIN_MATCH, bflush);
@@ -2076,7 +2122,7 @@ local block_state deflate_rle(deflate_state *s, int flush) {
 
         /* Emit match if have run of MIN_MATCH or longer, else emit literal */
         if (s->match_length >= MIN_MATCH) {
-            check_match(s, s->strstart, s->strstart - 1, s->match_length);
+            check_match(s, s->strstart, s->strstart - 1, (int)s->match_length);
 
             _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
 
diff --git a/libs/zlib/deflate.h b/libs/zlib/deflate.h
index 300c6ada62b8..0732ba83adbd 100644
--- a/libs/zlib/deflate.h
+++ b/libs/zlib/deflate.h
@@ -1,5 +1,5 @@
 /* deflate.h -- internal compression state
- * Copyright (C) 1995-2024 Jean-loup Gailly
+ * Copyright (C) 1995-2026 Jean-loup Gailly
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -271,6 +271,9 @@ typedef struct internal_state {
     /* Number of valid bits in bi_buf.  All bits above the last valid bit
      * are always zero.
      */
+    int bi_used;
+    /* Last number of used bits when going to a byte boundary.
+     */
 
     ulg high_water;
     /* High water mark offset in window for initialized bytes -- bytes above
@@ -279,6 +282,9 @@ typedef struct internal_state {
      * updated to the new high water mark.
      */
 
+    int slid;
+    /* True if the hash table has been slid since it was cleared. */
+
 } FAR deflate_state;
 
 /* Output a byte on the stream.
diff --git a/libs/zlib/inffast.c b/libs/zlib/inffast.c
index 9354676e786e..d1657f3f3034 100644
--- a/libs/zlib/inffast.c
+++ b/libs/zlib/inffast.c
@@ -1,5 +1,5 @@
 /* inffast.c -- fast decoding
- * Copyright (C) 1995-2017 Mark Adler
+ * Copyright (C) 1995-2026 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -155,7 +155,8 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
                 dist += (unsigned)hold & ((1U << op) - 1);
 #ifdef INFLATE_STRICT
                 if (dist > dmax) {
-                    strm->msg = (char *)"invalid distance too far back";
+                    strm->msg = (z_const char *)
+                        "invalid distance too far back";
                     state->mode = BAD;
                     break;
                 }
@@ -168,8 +169,8 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
                     op = dist - op;             /* distance back in window */
                     if (op > whave) {
                         if (state->sane) {
-                            strm->msg =
-                                (char *)"invalid distance too far back";
+                            strm->msg = (z_const char *)
+                                "invalid distance too far back";
                             state->mode = BAD;
                             break;
                         }
@@ -265,7 +266,7 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
                 goto dodist;
             }
             else {
-                strm->msg = (char *)"invalid distance code";
+                strm->msg = (z_const char *)"invalid distance code";
                 state->mode = BAD;
                 break;
             }
@@ -280,7 +281,7 @@ void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
             break;
         }
         else {
-            strm->msg = (char *)"invalid literal/length code";
+            strm->msg = (z_const char *)"invalid literal/length code";
             state->mode = BAD;
             break;
         }
diff --git a/libs/zlib/inffixed.h b/libs/zlib/inffixed.h
index d62832776948..05ce88e4ff5c 100644
--- a/libs/zlib/inffixed.h
+++ b/libs/zlib/inffixed.h
@@ -1,94 +1,94 @@
-    /* inffixed.h -- table for decoding fixed codes
-     * Generated automatically by makefixed().
-     */
+/* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
 
-    /* WARNING: this file should *not* be used by applications.
-       It is part of the implementation of this library and is
-       subject to change. Applications should only use zlib.h.
-     */
+/* WARNING: this file should *not* be used by applications.
+   It is part of the implementation of this library and is
+   subject to change. Applications should only use zlib.h.
+ */
 
-    static const code lenfix[512] = {
-        {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
-        {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
-        {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
-        {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
-        {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
-        {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
-        {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
-        {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
-        {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
-        {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
-        {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
-        {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
-        {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
-        {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
-        {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
-        {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
-        {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
-        {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
-        {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
-        {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
-        {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
-        {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
-        {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
-        {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
-        {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
-        {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
-        {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
-        {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
-        {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
-        {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
-        {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
-        {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
-        {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
-        {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
-        {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
-        {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
-        {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
-        {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
-        {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
-        {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
-        {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
-        {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
-        {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
-        {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
-        {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
-        {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
-        {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
-        {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
-        {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
-        {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
-        {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
-        {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
-        {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
-        {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
-        {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
-        {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
-        {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
-        {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
-        {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
-        {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
-        {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
-        {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
-        {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
-        {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
-        {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
-        {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
-        {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
-        {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
-        {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
-        {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
-        {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
-        {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
-        {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
-        {0,9,255}
-    };
+static const code lenfix[512] = {
+    {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+    {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+    {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+    {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+    {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+    {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+    {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+    {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+    {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+    {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+    {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+    {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+    {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+    {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+    {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+    {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+    {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+    {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+    {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+    {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+    {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+    {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+    {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+    {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+    {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+    {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+    {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+    {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+    {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+    {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+    {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+    {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+    {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+    {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+    {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+    {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+    {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+    {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+    {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+    {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+    {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+    {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+    {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+    {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+    {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+    {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+    {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+    {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+    {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+    {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+    {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+    {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+    {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+    {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+    {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+    {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+    {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+    {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+    {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+    {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+    {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+    {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+    {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+    {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+    {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+    {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+    {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+    {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+    {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+    {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+    {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+    {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+    {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+    {0,9,255}
+};
 
-    static const code distfix[32] = {
-        {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
-        {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
-        {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
-        {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
-        {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
-        {22,5,193},{64,5,0}
-    };
+static const code distfix[32] = {
+    {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+    {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+    {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+    {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+    {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+    {22,5,193},{64,5,0}
+};
diff --git a/libs/zlib/inflate.c b/libs/zlib/inflate.c
index 94ecff015a9b..5f5d4922b715 100644
--- a/libs/zlib/inflate.c
+++ b/libs/zlib/inflate.c
@@ -1,5 +1,5 @@
 /* inflate.c -- zlib decompression
- * Copyright (C) 1995-2022 Mark Adler
+ * Copyright (C) 1995-2026 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -85,12 +85,6 @@
 #include "inflate.h"
 #include "inffast.h"
 
-#ifdef MAKEFIXED
-#  ifndef BUILDFIXED
-#    define BUILDFIXED
-#  endif
-#endif
-
 local int inflateStateCheck(z_streamp strm) {
     struct inflate_state FAR *state;
     if (strm == Z_NULL ||
@@ -110,6 +104,7 @@ int ZEXPORT inflateResetKeep(z_streamp strm) {
     state = (struct inflate_state FAR *)strm->state;
     strm->total_in = strm->total_out = state->total = 0;
     strm->msg = Z_NULL;
+    strm->data_type = 0;
     if (state->wrap)        /* to support ill-conceived Java test suite */
         strm->adler = state->wrap & 1;
     state->mode = HEAD;
@@ -202,6 +197,7 @@ int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
     state = (struct inflate_state FAR *)
             ZALLOC(strm, 1, sizeof(struct inflate_state));
     if (state == Z_NULL) return Z_MEM_ERROR;
+    zmemzero(state, sizeof(struct inflate_state));
     Tracev((stderr, "inflate: allocated\n"));
     strm->state = (struct internal_state FAR *)state;
     state->strm = strm;
@@ -234,123 +230,11 @@ int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) {
     }
     if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
     value &= (1L << bits) - 1;
-    state->hold += (unsigned)value << state->bits;
+    state->hold += (unsigned long)value << state->bits;
     state->bits += (uInt)bits;
     return Z_OK;
 }
 
-/*
-   Return state with length and distance decoding tables and index sizes set to
-   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
-   If BUILDFIXED is defined, then instead this routine builds the tables the
-   first time it's called, and returns those tables the first time and
-   thereafter.  This reduces the size of the code by about 2K bytes, in
-   exchange for a little execution time.  However, BUILDFIXED should not be
-   used for threaded applications, since the rewriting of the tables and virgin
-   may not be thread-safe.
- */
-local void fixedtables(struct inflate_state FAR *state) {
-#ifdef BUILDFIXED
-    static int virgin = 1;
-    static code *lenfix, *distfix;
-    static code fixed[544];
-
-    /* build fixed huffman tables if first call (may not be thread safe) */
-    if (virgin) {
-        unsigned sym, bits;
-        static code *next;
-
-        /* literal/length table */
-        sym = 0;
-        while (sym < 144) state->lens[sym++] = 8;
-        while (sym < 256) state->lens[sym++] = 9;
-        while (sym < 280) state->lens[sym++] = 7;
-        while (sym < 288) state->lens[sym++] = 8;
-        next = fixed;
-        lenfix = next;
-        bits = 9;
-        inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
-
-        /* distance table */
-        sym = 0;
-        while (sym < 32) state->lens[sym++] = 5;
-        distfix = next;
-        bits = 5;
-        inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
-
-        /* do this just once */
-        virgin = 0;
-    }
-#else /* !BUILDFIXED */
-#   include "inffixed.h"
-#endif /* BUILDFIXED */
-    state->lencode = lenfix;
-    state->lenbits = 9;
-    state->distcode = distfix;
-    state->distbits = 5;
-}
-
-#ifdef MAKEFIXED
-#include <stdio.h>
-
-/*
-   Write out the inffixed.h that is #include'd above.  Defining MAKEFIXED also
-   defines BUILDFIXED, so the tables are built on the fly.  makefixed() writes
-   those tables to stdout, which would be piped to inffixed.h.  A small program
-   can simply call makefixed to do this:
-
-    void makefixed(void);
-
-    int main(void)
-    {
-        makefixed();
-        return 0;
-    }
-
-   Then that can be linked with zlib built with MAKEFIXED defined and run:
-
-    a.out > inffixed.h
- */
-void makefixed(void)
-{
-    unsigned low, size;
-    struct inflate_state state;
-
-    fixedtables(&state);
-    puts("    /* inffixed.h -- table for decoding fixed codes");
-    puts("     * Generated automatically by makefixed().");
-    puts("     */");
-    puts("");
-    puts("    /* WARNING: this file should *not* be used by applications.");
-    puts("       It is part of the implementation of this library and is");
-    puts("       subject to change. Applications should only use zlib.h.");
-    puts("     */");
-    puts("");
-    size = 1U << 9;
-    printf("    static const code lenfix[%u] = {", size);
-    low = 0;
-    for (;;) {
-        if ((low % 7) == 0) printf("\n        ");
-        printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
-               state.lencode[low].bits, state.lencode[low].val);
-        if (++low == size) break;
-        putchar(',');
-    }
-    puts("\n    };");
-    size = 1U << 5;
-    printf("\n    static const code distfix[%u] = {", size);
-    low = 0;
-    for (;;) {
-        if ((low % 6) == 0) printf("\n        ");
-        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
-               state.distcode[low].val);
-        if (++low == size) break;
-        putchar(',');
-    }
-    puts("\n    };");
-}
-#endif /* MAKEFIXED */
-
 /*
    Update the window with the last wsize (normally 32K) bytes written before
    returning.  If window does not exist yet, create it.  This is only called
@@ -642,12 +526,12 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             if (
 #endif
                 ((BITS(8) << 8) + (hold >> 8)) % 31) {
-                strm->msg = (char *)"incorrect header check";
+                strm->msg = (z_const char *)"incorrect header check";
                 state->mode = BAD;
                 break;
             }
             if (BITS(4) != Z_DEFLATED) {
-                strm->msg = (char *)"unknown compression method";
+                strm->msg = (z_const char *)"unknown compression method";
                 state->mode = BAD;
                 break;
             }
@@ -656,7 +540,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             if (state->wbits == 0)
                 state->wbits = len;
             if (len > 15 || len > state->wbits) {
-                strm->msg = (char *)"invalid window size";
+                strm->msg = (z_const char *)"invalid window size";
                 state->mode = BAD;
                 break;
             }
@@ -672,12 +556,12 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             NEEDBITS(16);
             state->flags = (int)(hold);
             if ((state->flags & 0xff) != Z_DEFLATED) {
-                strm->msg = (char *)"unknown compression method";
+                strm->msg = (z_const char *)"unknown compression method";
                 state->mode = BAD;
                 break;
             }
             if (state->flags & 0xe000) {
-                strm->msg = (char *)"unknown header flags set";
+                strm->msg = (z_const char *)"unknown header flags set";
                 state->mode = BAD;
                 break;
             }
@@ -793,7 +677,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             if (state->flags & 0x0200) {
                 NEEDBITS(16);
                 if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
-                    strm->msg = (char *)"header crc mismatch";
+                    strm->msg = (z_const char *)"header crc mismatch";
                     state->mode = BAD;
                     break;
                 }
@@ -840,7 +724,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                 state->mode = STORED;
                 break;
             case 1:                             /* fixed block */
-                fixedtables(state);
+                inflate_fixed(state);
                 Tracev((stderr, "inflate:     fixed codes block%s\n",
                         state->last ? " (last)" : ""));
                 state->mode = LEN_;             /* decode codes */
@@ -854,8 +738,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                         state->last ? " (last)" : ""));
                 state->mode = TABLE;
                 break;
-            case 3:
-                strm->msg = (char *)"invalid block type";
+            default:
+                strm->msg = (z_const char *)"invalid block type";
                 state->mode = BAD;
             }
             DROPBITS(2);
@@ -864,7 +748,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             BYTEBITS();                         /* go to byte boundary */
             NEEDBITS(32);
             if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
-                strm->msg = (char *)"invalid stored block lengths";
+                strm->msg = (z_const char *)"invalid stored block lengths";
                 state->mode = BAD;
                 break;
             }
@@ -905,7 +789,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             DROPBITS(4);
 #ifndef PKZIP_BUG_WORKAROUND
             if (state->nlen > 286 || state->ndist > 30) {
-                strm->msg = (char *)"too many length or distance symbols";
+                strm->msg = (z_const char *)
+                    "too many length or distance symbols";
                 state->mode = BAD;
                 break;
             }
@@ -923,12 +808,12 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             while (state->have < 19)
                 state->lens[order[state->have++]] = 0;
             state->next = state->codes;
-            state->lencode = (const code FAR *)(state->next);
+            state->lencode = state->distcode = (const code FAR *)(state->next);
             state->lenbits = 7;
             ret = inflate_table(CODES, state->lens, 19, &(state->next),
                                 &(state->lenbits), state->work);
             if (ret) {
-                strm->msg = (char *)"invalid code lengths set";
+                strm->msg = (z_const char *)"invalid code lengths set";
                 state->mode = BAD;
                 break;
             }
@@ -952,7 +837,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                         NEEDBITS(here.bits + 2);
                         DROPBITS(here.bits);
                         if (state->have == 0) {
-                            strm->msg = (char *)"invalid bit length repeat";
+                            strm->msg = (z_const char *)
+                                "invalid bit length repeat";
                             state->mode = BAD;
                             break;
                         }
@@ -975,7 +861,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                         DROPBITS(7);
                     }
                     if (state->have + copy > state->nlen + state->ndist) {
-                        strm->msg = (char *)"invalid bit length repeat";
+                        strm->msg = (z_const char *)
+                            "invalid bit length repeat";
                         state->mode = BAD;
                         break;
                     }
@@ -989,7 +876,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
 
             /* check for end-of-block code (better have one) */
             if (state->lens[256] == 0) {
-                strm->msg = (char *)"invalid code -- missing end-of-block";
+                strm->msg = (z_const char *)
+                    "invalid code -- missing end-of-block";
                 state->mode = BAD;
                 break;
             }
@@ -1003,7 +891,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
                                 &(state->lenbits), state->work);
             if (ret) {
-                strm->msg = (char *)"invalid literal/lengths set";
+                strm->msg = (z_const char *)"invalid literal/lengths set";
                 state->mode = BAD;
                 break;
             }
@@ -1012,7 +900,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
                             &(state->next), &(state->distbits), state->work);
             if (ret) {
-                strm->msg = (char *)"invalid distances set";
+                strm->msg = (z_const char *)"invalid distances set";
                 state->mode = BAD;
                 break;
             }
@@ -1066,7 +954,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                 break;
             }
             if (here.op & 64) {
-                strm->msg = (char *)"invalid literal/length code";
+                strm->msg = (z_const char *)"invalid literal/length code";
                 state->mode = BAD;
                 break;
             }
@@ -1104,7 +992,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             DROPBITS(here.bits);
             state->back += here.bits;
             if (here.op & 64) {
-                strm->msg = (char *)"invalid distance code";
+                strm->msg = (z_const char *)"invalid distance code";
                 state->mode = BAD;
                 break;
             }
@@ -1121,7 +1009,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             }
 #ifdef INFLATE_STRICT
             if (state->offset > state->dmax) {
-                strm->msg = (char *)"invalid distance too far back";
+                strm->msg = (z_const char *)"invalid distance too far back";
                 state->mode = BAD;
                 break;
             }
@@ -1136,7 +1024,8 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                 copy = state->offset - copy;
                 if (copy > state->whave) {
                     if (state->sane) {
-                        strm->msg = (char *)"invalid distance too far back";
+                        strm->msg = (z_const char *)
+                            "invalid distance too far back";
                         state->mode = BAD;
                         break;
                     }
@@ -1195,7 +1084,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
                      state->flags ? hold :
 #endif
                      ZSWAP32(hold)) != state->check) {
-                    strm->msg = (char *)"incorrect data check";
+                    strm->msg = (z_const char *)"incorrect data check";
                     state->mode = BAD;
                     break;
                 }
@@ -1209,7 +1098,7 @@ int ZEXPORT inflate(z_streamp strm, int flush) {
             if (state->wrap && state->flags) {
                 NEEDBITS(32);
                 if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
-                    strm->msg = (char *)"incorrect length check";
+                    strm->msg = (z_const char *)"incorrect length check";
                     state->mode = BAD;
                     break;
                 }
@@ -1440,7 +1329,6 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
     struct inflate_state FAR *state;
     struct inflate_state FAR *copy;
     unsigned char FAR *window;
-    unsigned wsize;
 
     /* check input */
     if (inflateStateCheck(source) || dest == Z_NULL)
@@ -1451,6 +1339,7 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
     copy = (struct inflate_state FAR *)
            ZALLOC(source, 1, sizeof(struct inflate_state));
     if (copy == Z_NULL) return Z_MEM_ERROR;
+    zmemzero(copy, sizeof(struct inflate_state));
     window = Z_NULL;
     if (state->window != Z_NULL) {
         window = (unsigned char FAR *)
@@ -1462,8 +1351,8 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
     }
 
     /* copy state */
-    zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
-    zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+    zmemcpy(dest, source, sizeof(z_stream));
+    zmemcpy(copy, state, sizeof(struct inflate_state));
     copy->strm = dest;
     if (state->lencode >= state->codes &&
         state->lencode <= state->codes + ENOUGH - 1) {
@@ -1471,10 +1360,8 @@ int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
         copy->distcode = copy->codes + (state->distcode - state->codes);
     }
     copy->next = copy->codes + (state->next - state->codes);
-    if (window != Z_NULL) {
-        wsize = 1U << state->wbits;
-        zmemcpy(window, state->window, wsize);
-    }
+    if (window != Z_NULL)
+        zmemcpy(window, state->window, state->whave);
     copy->window = window;
     dest->state = (struct internal_state FAR *)copy;
     return Z_OK;
diff --git a/libs/zlib/inflate.h b/libs/zlib/inflate.h
index f127b6b1fa5f..f758e0dcc18d 100644
--- a/libs/zlib/inflate.h
+++ b/libs/zlib/inflate.h
@@ -100,7 +100,7 @@ struct inflate_state {
     unsigned char FAR *window;  /* allocated sliding window, if needed */
         /* bit accumulator */
     unsigned long hold;         /* input bit accumulator */
-    unsigned bits;              /* number of bits in "in" */
+    unsigned bits;              /* number of bits in hold */
         /* for string and stored block copying */
     unsigned length;            /* literal or length of data to copy */
     unsigned offset;            /* distance back to copy string from */
diff --git a/libs/zlib/inftrees.c b/libs/zlib/inftrees.c
index 98cfe164458c..dcbc64e05b15 100644
--- a/libs/zlib/inftrees.c
+++ b/libs/zlib/inftrees.c
@@ -1,15 +1,29 @@
 /* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-2024 Mark Adler
+ * Copyright (C) 1995-2026 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
+#ifdef MAKEFIXED
+#  ifndef BUILDFIXED
+#    define BUILDFIXED
+#  endif
+#endif
+#ifdef BUILDFIXED
+#  define Z_ONCE
+#endif
+
 #include "zutil.h"
 #include "inftrees.h"
+#include "inflate.h"
+
+#ifndef NULL
+#  define NULL 0
+#endif
 
 #define MAXBITS 15
 
 const char inflate_copyright[] =
-   " inflate 1.3.1 Copyright 1995-2024 Mark Adler ";
+   " inflate 1.3.2 Copyright 1995-2026 Mark Adler ";
 /*
   If you use the zlib library in a product, an acknowledgment is welcome
   in the documentation of your product. If for some reason you cannot
@@ -47,9 +61,9 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
     unsigned mask;              /* mask for low root bits */
     code here;                  /* table entry for duplication */
     code FAR *next;             /* next available space in table */
-    const unsigned short FAR *base;     /* base value table to use */
-    const unsigned short FAR *extra;    /* extra bits table to use */
-    unsigned match;             /* use base and extra for symbol >= match */
+    const unsigned short FAR *base = NULL;  /* base value table to use */
+    const unsigned short FAR *extra = NULL; /* extra bits table to use */
+    unsigned match = 0;         /* use base and extra for symbol >= match */
     unsigned short count[MAXBITS+1];    /* number of codes of each length */
     unsigned short offs[MAXBITS+1];     /* offsets in table for each length */
     static const unsigned short lbase[31] = { /* Length codes 257..285 base */
@@ -57,7 +71,7 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
         35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
     static const unsigned short lext[31] = { /* Length codes 257..285 extra */
         16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
-        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 203, 77};
+        19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 75};
     static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
         1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
         257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
@@ -175,7 +189,6 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
     /* set up for code type */
     switch (type) {
     case CODES:
-        base = extra = work;    /* dummy value--not used */
         match = 20;
         break;
     case LENS:
@@ -183,10 +196,9 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
         extra = lext;
         match = 257;
         break;
-    default:    /* DISTS */
+    case DISTS:
         base = dbase;
         extra = dext;
-        match = 0;
     }
 
     /* initialize state for loop */
@@ -297,3 +309,116 @@ int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
     *bits = root;
     return 0;
 }
+
+#ifdef BUILDFIXED
+/*
+  If this is compiled with BUILDFIXED defined, and if inflate will be used in
+  multiple threads, and if atomics are not available, then inflate() must be
+  called with a fixed block (e.g. 0x03 0x00) to initialize the tables and must
+  return before any other threads are allowed to call inflate.
+ */
+
+static code *lenfix, *distfix;
+static code fixed[544];
+
+/* State for z_once(). */
+local z_once_t built = Z_ONCE_INIT;
+
+local void buildtables(void) {
+    unsigned sym, bits;
+    static code *next;
+    unsigned short lens[288], work[288];
+
+    /* literal/length table */
+    sym = 0;
+    while (sym < 144) lens[sym++] = 8;
+    while (sym < 256) lens[sym++] = 9;
+    while (sym < 280) lens[sym++] = 7;
+    while (sym < 288) lens[sym++] = 8;
+    next = fixed;
+    lenfix = next;
+    bits = 9;
+    inflate_table(LENS, lens, 288, &(next), &(bits), work);
+
+    /* distance table */
+    sym = 0;
+    while (sym < 32) lens[sym++] = 5;
+    distfix = next;
+    bits = 5;
+    inflate_table(DISTS, lens, 32, &(next), &(bits), work);
+}
+#else /* !BUILDFIXED */
+#  include "inffixed.h"
+#endif /* BUILDFIXED */
+
+/*
+   Return state with length and distance decoding tables and index sizes set to
+   fixed code decoding.  Normally this returns fixed tables from inffixed.h.
+   If BUILDFIXED is defined, then instead this routine builds the tables the
+   first time it's called, and returns those tables the first time and
+   thereafter.  This reduces the size of the code by about 2K bytes, in
+   exchange for a little execution time.  However, BUILDFIXED should not be
+   used for threaded applications if atomics are not available, as it will
+   not be thread-safe.
+ */
+void inflate_fixed(struct inflate_state FAR *state) {
+#ifdef BUILDFIXED
+    z_once(&built, buildtables);
+#endif /* BUILDFIXED */
+    state->lencode = lenfix;
+    state->lenbits = 9;
+    state->distcode = distfix;
+    state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+   Write out the inffixed.h that will be #include'd above.  Defining MAKEFIXED
+   also defines BUILDFIXED, so the tables are built on the fly.  main() writes
+   those tables to stdout, which would directed to inffixed.h. Compile this
+   along with zutil.c:
+
+       cc -DMAKEFIXED -o fix inftrees.c zutil.c
+       ./fix > inffixed.h
+ */
+int main(void) {
+    unsigned low, size;
+    struct inflate_state state;
+
+    inflate_fixed(&state);
+    puts("/* inffixed.h -- table for decoding fixed codes");
+    puts(" * Generated automatically by makefixed().");
+    puts(" */");
+    puts("");
+    puts("/* WARNING: this file should *not* be used by applications.");
+    puts("   It is part of the implementation of this library and is");
+    puts("   subject to change. Applications should only use zlib.h.");
+    puts(" */");
+    puts("");
+    size = 1U << 9;
+    printf("static const code lenfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 7) == 0) printf("\n    ");
+        printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
+               state.lencode[low].bits, state.lencode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n};");
+    size = 1U << 5;
+    printf("\nstatic const code distfix[%u] = {", size);
+    low = 0;
+    for (;;) {
+        if ((low % 6) == 0) printf("\n    ");
+        printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+               state.distcode[low].val);
+        if (++low == size) break;
+        putchar(',');
+    }
+    puts("\n};");
+    return 0;
+}
+#endif /* MAKEFIXED */
diff --git a/libs/zlib/inftrees.h b/libs/zlib/inftrees.h
index 396f74b5da79..84d053697cd8 100644
--- a/libs/zlib/inftrees.h
+++ b/libs/zlib/inftrees.h
@@ -1,5 +1,5 @@
 /* inftrees.h -- header to use inftrees.c
- * Copyright (C) 1995-2005, 2010 Mark Adler
+ * Copyright (C) 1995-2026 Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -60,3 +60,5 @@ typedef enum {
 int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
                                 unsigned codes, code FAR * FAR *table,
                                 unsigned FAR *bits, unsigned short FAR *work);
+struct inflate_state;
+void ZLIB_INTERNAL inflate_fixed(struct inflate_state FAR *state);
diff --git a/libs/zlib/trees.c b/libs/zlib/trees.c
index 6a523ef34e3c..8e4da01e9f47 100644
--- a/libs/zlib/trees.c
+++ b/libs/zlib/trees.c
@@ -1,5 +1,5 @@
 /* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-2024 Jean-loup Gailly
+ * Copyright (C) 1995-2026 Jean-loup Gailly
  * detect_data_type() function provided freely by Cosmin Truta, 2006
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
@@ -112,7 +112,7 @@ local int base_dist[D_CODES];
 
 #else
 #  include "trees.h"
-#endif /* GEN_TREES_H */
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
 
 struct static_tree_desc_s {
     const ct_data *static_tree;  /* static tree or NULL */
@@ -152,7 +152,7 @@ local TCONST static_tree_desc static_bl_desc =
  * IN assertion: 1 <= len <= 15
  */
 local unsigned bi_reverse(unsigned code, int len) {
-    register unsigned res = 0;
+    unsigned res = 0;
     do {
         res |= code & 1;
         code >>= 1, res <<= 1;
@@ -184,10 +184,11 @@ local void bi_windup(deflate_state *s) {
     } else if (s->bi_valid > 0) {
         put_byte(s, (Byte)s->bi_buf);
     }
+    s->bi_used = ((s->bi_valid - 1) & 7) + 1;
     s->bi_buf = 0;
     s->bi_valid = 0;
 #ifdef ZLIB_DEBUG
-    s->bits_sent = (s->bits_sent + 7) & ~7;
+    s->bits_sent = (s->bits_sent + 7) & ~(ulg)7;
 #endif
 }
 
@@ -466,6 +467,7 @@ void ZLIB_INTERNAL _tr_init(deflate_state *s) {
 
     s->bi_buf = 0;
     s->bi_valid = 0;
+    s->bi_used = 0;
 #ifdef ZLIB_DEBUG
     s->compressed_len = 0L;
     s->bits_sent = 0L;
@@ -724,7 +726,7 @@ local void scan_tree(deflate_state *s, ct_data *tree, int max_code) {
         if (++count < max_count && curlen == nextlen) {
             continue;
         } else if (count < min_count) {
-            s->bl_tree[curlen].Freq += count;
+            s->bl_tree[curlen].Freq += (ush)count;
         } else if (curlen != 0) {
             if (curlen != prevlen) s->bl_tree[curlen].Freq++;
             s->bl_tree[REP_3_6].Freq++;
@@ -817,7 +819,7 @@ local int build_bl_tree(deflate_state *s) {
     }
     /* Update opt_len to include the bit length tree and counts */
     s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4;
-    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+    Tracev((stderr, "\ndyn trees: dyn %lu, stat %lu",
             s->opt_len, s->static_len));
 
     return max_blindex;
@@ -843,13 +845,13 @@ local void send_all_trees(deflate_state *s, int lcodes, int dcodes,
         Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
         send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
     }
-    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+    Tracev((stderr, "\nbl tree: sent %lu", s->bits_sent));
 
     send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1);  /* literal tree */
-    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+    Tracev((stderr, "\nlit tree: sent %lu", s->bits_sent));
 
     send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1);  /* distance tree */
-    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+    Tracev((stderr, "\ndist tree: sent %lu", s->bits_sent));
 }
 
 /* ===========================================================================
@@ -932,7 +934,7 @@ local void compress_block(deflate_state *s, const ct_data *ltree,
             extra = extra_dbits[code];
             if (extra != 0) {
                 dist -= (unsigned)base_dist[code];
-                send_bits(s, dist, extra);   /* send the extra distance bits */
+                send_bits(s, (int)dist, extra); /* send the extra bits */
             }
         } /* literal or match pair ? */
 
@@ -1006,11 +1008,11 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
 
         /* Construct the literal and distance trees */
         build_tree(s, (tree_desc *)(&(s->l_desc)));
-        Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+        Tracev((stderr, "\nlit data: dyn %lu, stat %lu", s->opt_len,
                 s->static_len));
 
         build_tree(s, (tree_desc *)(&(s->d_desc)));
-        Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+        Tracev((stderr, "\ndist data: dyn %lu, stat %lu", s->opt_len,
                 s->static_len));
         /* At this point, opt_len and static_len are the total bit lengths of
          * the compressed block data, excluding the tree representations.
@@ -1083,7 +1085,7 @@ void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
 #endif
     }
     Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3,
-           s->compressed_len - 7*last));
+           s->compressed_len - 7*(ulg)last));
 }
 
 /* ===========================================================================
diff --git a/libs/zlib/zconf.h b/libs/zlib/zconf.h
index 62adc8d8431f..828ca617e907 100644
--- a/libs/zlib/zconf.h
+++ b/libs/zlib/zconf.h
@@ -1,5 +1,5 @@
 /* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
+ * Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -33,7 +33,10 @@
 #  ifndef Z_SOLO
 #    define compress              z_compress
 #    define compress2             z_compress2
+#    define compress_z            z_compress_z
+#    define compress2_z           z_compress2_z
 #    define compressBound         z_compressBound
+#    define compressBound_z       z_compressBound_z
 #  endif
 #  define crc32                 z_crc32
 #  define crc32_combine         z_crc32_combine
@@ -44,6 +47,7 @@
 #  define crc32_z               z_crc32_z
 #  define deflate               z_deflate
 #  define deflateBound          z_deflateBound
+#  define deflateBound_z        z_deflateBound_z
 #  define deflateCopy           z_deflateCopy
 #  define deflateEnd            z_deflateEnd
 #  define deflateGetDictionary  z_deflateGetDictionary
@@ -59,6 +63,7 @@
 #  define deflateSetDictionary  z_deflateSetDictionary
 #  define deflateSetHeader      z_deflateSetHeader
 #  define deflateTune           z_deflateTune
+#  define deflateUsed           z_deflateUsed
 #  define deflate_copyright     z_deflate_copyright
 #  define get_crc_table         z_get_crc_table
 #  ifndef Z_SOLO
@@ -128,9 +133,12 @@
 #  define inflate_copyright     z_inflate_copyright
 #  define inflate_fast          z_inflate_fast
 #  define inflate_table         z_inflate_table
+#  define inflate_fixed         z_inflate_fixed
 #  ifndef Z_SOLO
 #    define uncompress            z_uncompress
 #    define uncompress2           z_uncompress2
+#    define uncompress_z          z_uncompress_z
+#    define uncompress2_z         z_uncompress2_z
 #  endif
 #  define zError                z_zError
 #  ifndef Z_SOLO
@@ -234,10 +242,12 @@
 #  endif
 #endif
 
-#if defined(ZLIB_CONST) && !defined(z_const)
-#  define z_const const
-#else
-#  define z_const
+#ifndef z_const
+#  ifdef ZLIB_CONST
+#    define z_const const
+#  else
+#    define z_const
+#  endif
 #endif
 
 #ifdef Z_SOLO
@@ -433,11 +443,11 @@ typedef uLong FAR uLongf;
    typedef unsigned long z_crc_t;
 #endif
 
-#ifdef HAVE_UNISTD_H    /* may be set to #if 1 by ./configure */
+#if HAVE_UNISTD_H-0     /* may be set to #if 1 by ./configure */
 #  define Z_HAVE_UNISTD_H
 #endif
 
-#ifdef HAVE_STDARG_H    /* may be set to #if 1 by ./configure */
+#if HAVE_STDARG_H-0     /* may be set to #if 1 by ./configure */
 #  define Z_HAVE_STDARG_H
 #endif
 
@@ -470,12 +480,8 @@ typedef uLong FAR uLongf;
 #endif
 
 #ifndef Z_HAVE_UNISTD_H
-#  ifdef __WATCOMC__
-#    define Z_HAVE_UNISTD_H
-#  endif
-#endif
-#ifndef Z_HAVE_UNISTD_H
-#  if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
+#  if defined(__WATCOMC__) || defined(__GO32__) || \
+      (defined(_LARGEFILE64_SOURCE) && !defined(_WIN32))
 #    define Z_HAVE_UNISTD_H
 #  endif
 #endif
@@ -510,17 +516,19 @@ typedef uLong FAR uLongf;
 #endif
 
 #ifndef z_off_t
-#  define z_off_t long
+#  define z_off_t long long
 #endif
 
 #if !defined(_WIN32) && defined(Z_LARGE64)
 #  define z_off64_t off64_t
+#elif defined(__MINGW32__)
+#  define z_off64_t long long
+#elif defined(_WIN32) && !defined(__GNUC__)
+#  define z_off64_t __int64
+#elif defined(__GO32__)
+#  define z_off64_t offset_t
 #else
-#  if defined(_WIN32) && !defined(__GNUC__)
-#    define z_off64_t __int64
-#  else
-#    define z_off64_t z_off_t
-#  endif
+#  define z_off64_t z_off_t
 #endif
 
 /* MVS linker does not support external names larger than 8 bytes */
diff --git a/libs/zlib/zlib.h b/libs/zlib/zlib.h
index 8d4b932eaf6a..a57d33613421 100644
--- a/libs/zlib/zlib.h
+++ b/libs/zlib/zlib.h
@@ -1,7 +1,7 @@
 /* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.3.1, January 22nd, 2024
+  version 1.3.2, February 17th, 2026
 
-  Copyright (C) 1995-2024 Jean-loup Gailly and Mark Adler
+  Copyright (C) 1995-2026 Jean-loup Gailly and Mark Adler
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -24,24 +24,28 @@
 
 
   The data format used by the zlib library is described by RFCs (Request for
-  Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+  Comments) 1950 to 1952 at https://datatracker.ietf.org/doc/html/rfc1950
   (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
 */
 
 #ifndef ZLIB_H
 #define ZLIB_H
 
-#include "zconf.h"
+#ifdef ZLIB_BUILD
+#  include <zconf.h>
+#else
+# include "zconf.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#define ZLIB_VERSION "1.3.1"
-#define ZLIB_VERNUM 0x1310
+#define ZLIB_VERSION "1.3.2"
+#define ZLIB_VERNUM 0x1320
 #define ZLIB_VER_MAJOR 1
 #define ZLIB_VER_MINOR 3
-#define ZLIB_VER_REVISION 1
+#define ZLIB_VER_REVISION 2
 #define ZLIB_VER_SUBREVISION 0
 
 /*
@@ -441,7 +445,7 @@ ZEXTERN int ZEXPORT inflate(z_streamp strm, int flush);
 
     The Z_BLOCK option assists in appending to or combining deflate streams.
   To assist in this, on return inflate() always sets strm->data_type to the
-  number of unused bits in the last byte taken from strm->next_in, plus 64 if
+  number of unused bits in the input taken from strm->next_in, plus 64 if
   inflate() is currently decoding the last block in the deflate stream, plus
   128 if inflate() returned immediately after decoding an end-of-block code or
   decoding the complete header up to just before the first byte of the deflate
@@ -587,18 +591,21 @@ ZEXTERN int ZEXPORT deflateInit2(z_streamp strm,
 
      The strategy parameter is used to tune the compression algorithm.  Use the
    value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
-   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
-   string match), or Z_RLE to limit match distances to one (run-length
-   encoding).  Filtered data consists mostly of small values with a somewhat
-   random distribution.  In this case, the compression algorithm is tuned to
-   compress them better.  The effect of Z_FILTERED is to force more Huffman
-   coding and less string matching; it is somewhat intermediate between
-   Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.  Z_RLE is designed to be almost as
-   fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data.  The
-   strategy parameter only affects the compression ratio but not the
-   correctness of the compressed output even if it is not set appropriately.
-   Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
-   decoder for special applications.
+   filter (or predictor), Z_RLE to limit match distances to one (run-length
+   encoding), or Z_HUFFMAN_ONLY to force Huffman encoding only (no string
+   matching).  Filtered data consists mostly of small values with a somewhat
+   random distribution, as produced by the PNG filters.  In this case, the
+   compression algorithm is tuned to compress them better.  The effect of
+   Z_FILTERED is to force more Huffman coding and less string matching than the
+   default; it is intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY.
+   Z_RLE is almost as fast as Z_HUFFMAN_ONLY, but should give better
+   compression for PNG image data than Huffman only.  The degree of string
+   matching from most to none is: Z_DEFAULT_STRATEGY, Z_FILTERED, Z_RLE, then
+   Z_HUFFMAN_ONLY. The strategy parameter affects the compression ratio but
+   never the correctness of the compressed output, even if it is not set
+   optimally for the given data.  Z_FIXED uses the default string matching, but
+   prevents the use of dynamic Huffman codes, allowing for a simpler decoder
+   for special applications.
 
      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
    memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
@@ -758,8 +765,8 @@ ZEXTERN int ZEXPORT deflateTune(z_streamp strm,
    returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
  */
 
-ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,
-                                   uLong sourceLen);
+ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm, uLong sourceLen);
+ZEXTERN z_size_t ZEXPORT deflateBound_z(z_streamp strm, z_size_t sourceLen);
 /*
      deflateBound() returns an upper bound on the compressed size after
    deflation of sourceLen bytes.  It must be called after deflateInit() or
@@ -771,6 +778,9 @@ ZEXTERN uLong ZEXPORT deflateBound(z_streamp strm,
    to return Z_STREAM_END.  Note that it is possible for the compressed size to
    be larger than the value returned by deflateBound() if flush options other
    than Z_FINISH or Z_NO_FLUSH are used.
+
+     delfateBound_z() is the same, but takes and returns a size_t length.  Note
+   that a long is 32 bits on Windows.
 */
 
 ZEXTERN int ZEXPORT deflatePending(z_streamp strm,
@@ -785,6 +795,21 @@ ZEXTERN int ZEXPORT deflatePending(z_streamp strm,
    or bits are Z_NULL, then those values are not set.
 
      deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.  If an int is 16 bits and memLevel is 9, then
+   it is possible for the number of pending bytes to not fit in an unsigned. In
+   that case Z_BUF_ERROR is returned and *pending is set to the maximum value
+   of an unsigned.
+ */
+
+ZEXTERN int ZEXPORT deflateUsed(z_streamp strm,
+                                int *bits);
+/*
+     deflateUsed() returns in *bits the most recent number of deflate bits used
+   in the last byte when flushing to a byte boundary. The result is in 1..8, or
+   0 if there has not yet been a flush. This helps determine the location of
+   the last bit of a deflate stream.
+
+     deflateUsed returns Z_OK if success, or Z_STREAM_ERROR if the source
    stream state was inconsistent.
  */
 
@@ -987,13 +1012,15 @@ ZEXTERN int ZEXPORT inflatePrime(z_streamp strm,
                                  int bits,
                                  int value);
 /*
-     This function inserts bits in the inflate input stream.  The intent is
-   that this function is used to start inflating at a bit position in the
-   middle of a byte.  The provided bits will be used before any bytes are used
-   from next_in.  This function should only be used with raw inflate, and
-   should be used before the first inflate() call after inflateInit2() or
-   inflateReset().  bits must be less than or equal to 16, and that many of the
-   least significant bits of value will be inserted in the input.
+     This function inserts bits in the inflate input stream.  The intent is to
+   use inflatePrime() to start inflating at a bit position in the middle of a
+   byte.  The provided bits will be used before any bytes are used from
+   next_in.  This function should be used with raw inflate, before the first
+   inflate() call, after inflateInit2() or inflateReset().  It can also be used
+   after an inflate() return indicates the end of a deflate block or header
+   when using Z_BLOCK.  bits must be less than or equal to 16, and that many of
+   the least significant bits of value will be inserted in the input.  The
+   other bits in value can be non-zero, and will be ignored.
 
      If bits is negative, then the input stream bit buffer is emptied.  Then
    inflatePrime() can be called again to put bits in the buffer.  This is used
@@ -1001,7 +1028,15 @@ ZEXTERN int ZEXPORT inflatePrime(z_streamp strm,
    to feeding inflate codes.
 
      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
-   stream state was inconsistent.
+   stream state was inconsistent, or if bits is out of range.  If inflate was
+   in the middle of processing a header, trailer, or stored block lengths, then
+   it is possible for there to be only eight bits available in the bit buffer.
+   In that case, bits > 8 is considered out of range.  However, when used as
+   outlined above, there will always be 16 bits available in the buffer for
+   insertion.  As noted in its documentation above, inflate records the number
+   of bits in the bit buffer on return in data_type. 32 minus that is the
+   number of bits available for insertion.  inflatePrime does not update
+   data_type with the new number of bits in buffer.
 */
 
 ZEXTERN long ZEXPORT inflateMark(z_streamp strm);
@@ -1047,20 +1082,22 @@ ZEXTERN int ZEXPORT inflateGetHeader(z_streamp strm,
 
      The text, time, xflags, and os fields are filled in with the gzip header
    contents.  hcrc is set to true if there is a header CRC.  (The header CRC
-   was valid if done is set to one.) If extra is not Z_NULL, then extra_max
-   contains the maximum number of bytes to write to extra.  Once done is true,
-   extra_len contains the actual extra field length, and extra contains the
-   extra field, or that field truncated if extra_max is less than extra_len.
-   If name is not Z_NULL, then up to name_max characters are written there,
-   terminated with a zero unless the length is greater than name_max.  If
-   comment is not Z_NULL, then up to comm_max characters are written there,
-   terminated with a zero unless the length is greater than comm_max.  When any
-   of extra, name, or comment are not Z_NULL and the respective field is not
-   present in the header, then that field is set to Z_NULL to signal its
-   absence.  This allows the use of deflateSetHeader() with the returned
-   structure to duplicate the header.  However if those fields are set to
-   allocated memory, then the application will need to save those pointers
-   elsewhere so that they can be eventually freed.
+   was valid if done is set to one.)  The extra, name, and comment pointers
+   much each be either Z_NULL or point to space to store that information from
+   the header.  If extra is not Z_NULL, then extra_max contains the maximum
+   number of bytes that can be written to extra.  Once done is true, extra_len
+   contains the actual extra field length, and extra contains the extra field,
+   or that field truncated if extra_max is less than extra_len.  If name is not
+   Z_NULL, then up to name_max characters, including the terminating zero, are
+   written there.  If comment is not Z_NULL, then up to comm_max characters,
+   including the terminating zero, are written there.  The application can tell
+   that the name or comment did not fit in the provided space by the absence of
+   a terminating zero.  If any of extra, name, or comment are not present in
+   the header, then that field's pointer is set to Z_NULL.  This allows the use
+   of deflateSetHeader() with the returned structure to duplicate the header.
+   Note that if those fields initially pointed to allocated memory, then the
+   application will need to save them elsewhere so that they can be eventually
+   freed.
 
      If inflateGetHeader is not used, then the header information is simply
    discarded.  The header is always checked for validity, including the header
@@ -1208,13 +1245,14 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags(void);
      21: FASTEST -- deflate algorithm with only one, lowest compression level
      22,23: 0 (reserved)
 
-    The sprintf variant used by gzprintf (zero is best):
+    The sprintf variant used by gzprintf (all zeros is best):
      24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
-     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() is not secure!
      26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+     27: 0 = gzprintf() present, 1 = not -- 1 means gzprintf() returns an error
 
     Remainder:
-     27-31: 0 (reserved)
+     28-31: 0 (reserved)
  */
 
 #ifndef Z_SOLO
@@ -1226,11 +1264,14 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags(void);
    stream-oriented functions.  To simplify the interface, some default options
    are assumed (compression level and memory usage, standard memory allocation
    functions).  The source code of these utility functions can be modified if
-   you need special options.
+   you need special options.  The _z versions of the functions use the size_t
+   type for lengths.  Note that a long is 32 bits on Windows.
 */
 
-ZEXTERN int ZEXPORT compress(Bytef *dest,   uLongf *destLen,
+ZEXTERN int ZEXPORT compress(Bytef *dest, uLongf *destLen,
                              const Bytef *source, uLong sourceLen);
+ZEXTERN int ZEXPORT compress_z(Bytef *dest, z_size_t *destLen,
+                               const Bytef *source, z_size_t sourceLen);
 /*
      Compresses the source buffer into the destination buffer.  sourceLen is
    the byte length of the source buffer.  Upon entry, destLen is the total size
@@ -1244,9 +1285,12 @@ ZEXTERN int ZEXPORT compress(Bytef *dest,   uLongf *destLen,
    buffer.
 */
 
-ZEXTERN int ZEXPORT compress2(Bytef *dest,   uLongf *destLen,
+ZEXTERN int ZEXPORT compress2(Bytef *dest, uLongf *destLen,
                               const Bytef *source, uLong sourceLen,
                               int level);
+ZEXTERN int ZEXPORT compress2_z(Bytef *dest, z_size_t *destLen,
+                                const Bytef *source, z_size_t sourceLen,
+                                int level);
 /*
      Compresses the source buffer into the destination buffer.  The level
    parameter has the same meaning as in deflateInit.  sourceLen is the byte
@@ -1261,21 +1305,24 @@ ZEXTERN int ZEXPORT compress2(Bytef *dest,   uLongf *destLen,
 */
 
 ZEXTERN uLong ZEXPORT compressBound(uLong sourceLen);
+ZEXTERN z_size_t ZEXPORT compressBound_z(z_size_t sourceLen);
 /*
      compressBound() returns an upper bound on the compressed size after
    compress() or compress2() on sourceLen bytes.  It would be used before a
    compress() or compress2() call to allocate the destination buffer.
 */
 
-ZEXTERN int ZEXPORT uncompress(Bytef *dest,   uLongf *destLen,
+ZEXTERN int ZEXPORT uncompress(Bytef *dest, uLongf *destLen,
                                const Bytef *source, uLong sourceLen);
+ZEXTERN int ZEXPORT uncompress_z(Bytef *dest, z_size_t *destLen,
+                                 const Bytef *source, z_size_t sourceLen);
 /*
      Decompresses the source buffer into the destination buffer.  sourceLen is
-   the byte length of the source buffer.  Upon entry, destLen is the total size
+   the byte length of the source buffer.  On entry, *destLen is the total size
    of the destination buffer, which must be large enough to hold the entire
    uncompressed data.  (The size of the uncompressed data must have been saved
    previously by the compressor and transmitted to the decompressor by some
-   mechanism outside the scope of this compression library.) Upon exit, destLen
+   mechanism outside the scope of this compression library.)  On exit, *destLen
    is the actual size of the uncompressed data.
 
      uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
@@ -1285,8 +1332,10 @@ ZEXTERN int ZEXPORT uncompress(Bytef *dest,   uLongf *destLen,
    buffer with the uncompressed data up to that point.
 */
 
-ZEXTERN int ZEXPORT uncompress2(Bytef *dest,   uLongf *destLen,
+ZEXTERN int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen,
                                 const Bytef *source, uLong *sourceLen);
+ZEXTERN int ZEXPORT uncompress2_z(Bytef *dest, z_size_t *destLen,
+                                  const Bytef *source, z_size_t *sourceLen);
 /*
      Same as uncompress, except that sourceLen is a pointer, where the
    length of the source is *sourceLen.  On return, *sourceLen is the number of
@@ -1314,13 +1363,17 @@ ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
    'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression
    as in "wb9F".  (See the description of deflateInit2 for more information
    about the strategy parameter.)  'T' will request transparent writing or
-   appending with no compression and not using the gzip format.
-
-     "a" can be used instead of "w" to request that the gzip stream that will
-   be written be appended to the file.  "+" will result in an error, since
+   appending with no compression and not using the gzip format. 'T' cannot be
+   used to force transparent reading. Transparent reading is automatically
+   performed if there is no gzip header at the start. Transparent reading can
+   be disabled with the 'G' option, which will instead return an error if there
+   is no gzip header. 'N' will open the file in non-blocking mode.
+
+     'a' can be used instead of 'w' to request that the gzip stream that will
+   be written be appended to the file.  '+' will result in an error, since
    reading and writing to the same gzip file is not supported.  The addition of
-   "x" when writing will create the file exclusively, which fails if the file
-   already exists.  On systems that support it, the addition of "e" when
+   'x' when writing will create the file exclusively, which fails if the file
+   already exists.  On systems that support it, the addition of 'e' when
    reading or writing will set the flag to close the file on an execve() call.
 
      These functions, as well as gzip, will read and decode a sequence of gzip
@@ -1339,14 +1392,22 @@ ZEXTERN gzFile ZEXPORT gzopen(const char *path, const char *mode);
    insufficient memory to allocate the gzFile state, or if an invalid mode was
    specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
    errno can be checked to determine if the reason gzopen failed was that the
-   file could not be opened.
+   file could not be opened. Note that if 'N' is in mode for non-blocking, the
+   open() itself can fail in order to not block. In that case gzopen() will
+   return NULL and errno will be EAGAIN or ENONBLOCK. The call to gzopen() can
+   then be re-tried. If the application would like to block on opening the
+   file, then it can use open() without O_NONBLOCK, and then gzdopen() with the
+   resulting file descriptor and 'N' in the mode, which will set it to non-
+   blocking.
 */
 
 ZEXTERN gzFile ZEXPORT gzdopen(int fd, const char *mode);
 /*
      Associate a gzFile with the file descriptor fd.  File descriptors are
    obtained from calls like open, dup, creat, pipe or fileno (if the file has
-   been previously opened with fopen).  The mode parameter is as in gzopen.
+   been previously opened with fopen).  The mode parameter is as in gzopen. An
+   'e' in mode will set fd's flag to close the file on an execve() call. An 'N'
+   in mode will set fd's non-blocking flag.
 
      The next call of gzclose on the returned gzFile will also close the file
    descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
@@ -1416,10 +1477,16 @@ ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
    stream.  Alternatively, gzerror can be used before gzclose to detect this
    case.
 
+     gzread can be used to read a gzip file on a non-blocking device. If the
+   input stalls and there is no uncompressed data to return, then gzread() will
+   return -1, and errno will be EAGAIN or EWOULDBLOCK. gzread() can then be
+   called again.
+
      gzread returns the number of uncompressed bytes actually read, less than
    len for end of file, or -1 for error.  If len is too large to fit in an int,
    then nothing is read, -1 is returned, and the error state is set to
-   Z_STREAM_ERROR.
+   Z_STREAM_ERROR. If some data was read before an error, then that data is
+   returned until exhausted, after which the next call will signal the error.
 */
 
 ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
@@ -1443,15 +1510,20 @@ ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
    multiple of size, then the final partial item is nevertheless read into buf
    and the end-of-file flag is set.  The length of the partial item read is not
    provided, but could be inferred from the result of gztell().  This behavior
-   is the same as the behavior of fread() implementations in common libraries,
-   but it prevents the direct use of gzfread() to read a concurrently written
-   file, resetting and retrying on end-of-file, when size is not 1.
+   is the same as that of fread() implementations in common libraries. This
+   could result in data loss if used with size != 1 when reading a concurrently
+   written file or a non-blocking file. In that case, use size == 1 or gzread()
+   instead.
 */
 
 ZEXTERN int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len);
 /*
      Compress and write the len uncompressed bytes at buf to file. gzwrite
-   returns the number of uncompressed bytes written or 0 in case of error.
+   returns the number of uncompressed bytes written, or 0 in case of error or
+   if len is 0.  If the write destination is non-blocking, then gzwrite() may
+   return a number of bytes written that is not 0 and less than len.
+
+     If len does not fit in an int, then 0 is returned and nothing is written.
 */
 
 ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
@@ -1466,9 +1538,18 @@ ZEXTERN z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size,
    if there was an error.  If the multiplication of size and nitems overflows,
    i.e. the product does not fit in a z_size_t, then nothing is written, zero
    is returned, and the error state is set to Z_STREAM_ERROR.
+
+     If writing a concurrently read file or a non-blocking file with size != 1,
+   a partial item could be written, with no way of knowing how much of it was
+   not written, resulting in data loss.  In that case, use size == 1 or
+   gzwrite() instead.
 */
 
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
 ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
+#else
+ZEXTERN int ZEXPORTVA gzprintf();
+#endif
 /*
      Convert, format, compress, and write the arguments (...) to file under
    control of the string format, as in fprintf.  gzprintf returns the number of
@@ -1476,11 +1557,19 @@ ZEXTERN int ZEXPORTVA gzprintf(gzFile file, const char *format, ...);
    of error.  The number of uncompressed bytes written is limited to 8191, or
    one less than the buffer size given to gzbuffer().  The caller should assure
    that this limit is not exceeded.  If it is exceeded, then gzprintf() will
-   return an error (0) with nothing written.  In this case, there may also be a
-   buffer overflow with unpredictable consequences, which is possible only if
-   zlib was compiled with the insecure functions sprintf() or vsprintf(),
-   because the secure snprintf() or vsnprintf() functions were not available.
-   This can be determined using zlibCompileFlags().
+   return an error (0) with nothing written.
+
+     In that last case, there may also be a buffer overflow with unpredictable
+   consequences, which is possible only if zlib was compiled with the insecure
+   functions sprintf() or vsprintf(), because the secure snprintf() and
+   vsnprintf() functions were not available. That would only be the case for
+   a non-ANSI C compiler. zlib may have been built without gzprintf() because
+   secure functions were not available and having gzprintf() be insecure was
+   not an option, in which case, gzprintf() returns Z_STREAM_ERROR. All of
+   these possibilities can be determined using zlibCompileFlags().
+
+     If a Z_BUF_ERROR is returned, then nothing was written due to a stall on
+   the non-blocking write destination.
 */
 
 ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
@@ -1489,6 +1578,11 @@ ZEXTERN int ZEXPORT gzputs(gzFile file, const char *s);
    the terminating null character.
 
      gzputs returns the number of characters written, or -1 in case of error.
+   The number of characters written may be less than the length of the string
+   if the write destination is non-blocking.
+
+     If the length of the string does not fit in an int, then -1 is returned
+   and nothing is written.
 */
 
 ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
@@ -1501,8 +1595,13 @@ ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
    left untouched.
 
      gzgets returns buf which is a null-terminated string, or it returns NULL
-   for end-of-file or in case of error.  If there was an error, the contents at
-   buf are indeterminate.
+   for end-of-file or in case of error. If some data was read before an error,
+   then that data is returned until exhausted, after which the next call will
+   return NULL to signal the error.
+
+     gzgets can be used on a file being concurrently written, and on a non-
+   blocking device, both as for gzread(). However lines may be broken in the
+   middle, leaving it up to the application to reassemble them as needed.
 */
 
 ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
@@ -1513,11 +1612,19 @@ ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
 
 ZEXTERN int ZEXPORT gzgetc(gzFile file);
 /*
-     Read and decompress one byte from file.  gzgetc returns this byte or -1
-   in case of end of file or error.  This is implemented as a macro for speed.
-   As such, it does not do all of the checking the other functions do.  I.e.
-   it does not check to see if file is NULL, nor whether the structure file
-   points to has been clobbered or not.
+     Read and decompress one byte from file. gzgetc returns this byte or -1 in
+   case of end of file or error. If some data was read before an error, then
+   that data is returned until exhausted, after which the next call will return
+   -1 to signal the error.
+
+     This is implemented as a macro for speed. As such, it does not do all of
+   the checking the other functions do. I.e. it does not check to see if file
+   is NULL, nor whether the structure file points to has been clobbered or not.
+
+     gzgetc can be used to read a gzip file on a non-blocking device. If the
+   input stalls and there is no uncompressed data to return, then gzgetc() will
+   return -1, and errno will be EAGAIN or EWOULDBLOCK. gzread() can then be
+   called again.
 */
 
 ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
@@ -1530,6 +1637,11 @@ ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);
    output buffer size of pushed characters is allowed.  (See gzbuffer above.)
    The pushed character will be discarded if the stream is repositioned with
    gzseek() or gzrewind().
+
+     gzungetc(-1, file) will force any pending seek to execute. Then gztell()
+   will report the position, even if the requested seek reached end of file.
+   This can be used to determine the number of uncompressed bytes in a gzip
+   file without having to read it into a buffer.
 */
 
 ZEXTERN int ZEXPORT gzflush(gzFile file, int flush);
@@ -1559,7 +1671,8 @@ ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
      If the file is opened for reading, this function is emulated but can be
    extremely slow.  If the file is opened for writing, only forward seeks are
    supported; gzseek then compresses a sequence of zeroes up to the new
-   starting position.
+   starting position. For reading or writing, any actual seeking is deferred
+   until the next read or write operation, or close operation when writing.
 
      gzseek returns the resulting offset location as measured in bytes from
    the beginning of the uncompressed stream, or -1 in case of error, in
@@ -1567,7 +1680,7 @@ ZEXTERN z_off_t ZEXPORT gzseek(gzFile file,
    would be before the current position.
 */
 
-ZEXTERN int ZEXPORT    gzrewind(gzFile file);
+ZEXTERN int ZEXPORT gzrewind(gzFile file);
 /*
      Rewind file. This function is supported only for reading.
 
@@ -1575,7 +1688,7 @@ ZEXTERN int ZEXPORT    gzrewind(gzFile file);
 */
 
 /*
-ZEXTERN z_off_t ZEXPORT    gztell(gzFile file);
+ZEXTERN z_off_t ZEXPORT gztell(gzFile file);
 
      Return the starting position for the next gzread or gzwrite on file.
    This position represents a number of bytes in the uncompressed data stream,
@@ -1620,8 +1733,11 @@ ZEXTERN int ZEXPORT gzdirect(gzFile file);
 
      If gzdirect() is used immediately after gzopen() or gzdopen() it will
    cause buffers to be allocated to allow reading the file to determine if it
-   is a gzip file.  Therefore if gzbuffer() is used, it should be called before
-   gzdirect().
+   is a gzip file. Therefore if gzbuffer() is used, it should be called before
+   gzdirect(). If the input is being written concurrently or the device is non-
+   blocking, then gzdirect() may give a different answer once four bytes of
+   input have been accumulated, which is what is needed to confirm or deny a
+   gzip header. Before this, gzdirect() will return true (1).
 
      When writing, gzdirect() returns true (1) if transparent writing was
    requested ("wT" for the gzopen() mode), or false (0) otherwise.  (Note:
@@ -1631,7 +1747,7 @@ ZEXTERN int ZEXPORT gzdirect(gzFile file);
    gzip file reading and decompression, which may not be desired.)
 */
 
-ZEXTERN int ZEXPORT    gzclose(gzFile file);
+ZEXTERN int ZEXPORT gzclose(gzFile file);
 /*
      Flush all pending output for file, if necessary, close file and
    deallocate the (de)compression state.  Note that once file is closed, you
@@ -1659,9 +1775,10 @@ ZEXTERN int ZEXPORT gzclose_w(gzFile file);
 ZEXTERN const char * ZEXPORT gzerror(gzFile file, int *errnum);
 /*
      Return the error message for the last error which occurred on file.
-   errnum is set to zlib error number.  If an error occurred in the file system
-   and not in the compression library, errnum is set to Z_ERRNO and the
-   application may consult errno to get the exact error code.
+   If errnum is not NULL, *errnum is set to zlib error number.  If an error
+   occurred in the file system and not in the compression library, *errnum is
+   set to Z_ERRNO and the application may consult errno to get the exact error
+   code.
 
      The application must not modify the returned string.  Future calls to
    this function may invalidate the previously returned string.  If file is
@@ -1712,7 +1829,8 @@ ZEXTERN uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len);
 ZEXTERN uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf,
                                 z_size_t len);
 /*
-     Same as adler32(), but with a size_t length.
+     Same as adler32(), but with a size_t length.  Note that a long is 32 bits
+   on Windows.
 */
 
 /*
@@ -1748,7 +1866,8 @@ ZEXTERN uLong ZEXPORT crc32(uLong crc, const Bytef *buf, uInt len);
 ZEXTERN uLong ZEXPORT crc32_z(uLong crc, const Bytef *buf,
                               z_size_t len);
 /*
-     Same as crc32(), but with a size_t length.
+     Same as crc32(), but with a size_t length.  Note that a long is 32 bits on
+   Windows.
 */
 
 /*
@@ -1758,14 +1877,14 @@ ZEXTERN uLong ZEXPORT crc32_combine(uLong crc1, uLong crc2, z_off_t len2);
    seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
    calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
    check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
-   len2. len2 must be non-negative.
+   len2. len2 must be non-negative, otherwise zero is returned.
 */
 
 /*
 ZEXTERN uLong ZEXPORT crc32_combine_gen(z_off_t len2);
 
      Return the operator corresponding to length len2, to be used with
-   crc32_combine_op(). len2 must be non-negative.
+   crc32_combine_op(). len2 must be non-negative, otherwise zero is returned.
 */
 
 ZEXTERN uLong ZEXPORT crc32_combine_op(uLong crc1, uLong crc2, uLong op);
@@ -1888,9 +2007,9 @@ ZEXTERN int ZEXPORT gzgetc_(gzFile file);       /* backward compatibility */
      ZEXTERN z_off_t ZEXPORT gzseek64(gzFile, z_off_t, int);
      ZEXTERN z_off_t ZEXPORT gztell64(gzFile);
      ZEXTERN z_off_t ZEXPORT gzoffset64(gzFile);
-     ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
-     ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
-     ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
+     ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
+     ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
+     ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
 #  endif
 #else
    ZEXTERN gzFile ZEXPORT gzopen(const char *, const char *);
diff --git a/libs/zlib/zutil.c b/libs/zlib/zutil.c
index b1c5d2d3c6da..4ea02a9c3644 100644
--- a/libs/zlib/zutil.c
+++ b/libs/zlib/zutil.c
@@ -1,5 +1,5 @@
 /* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-2017 Jean-loup Gailly
+ * Copyright (C) 1995-2026 Jean-loup Gailly
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -86,28 +86,36 @@ uLong ZEXPORT zlibCompileFlags(void) {
     flags += 1L << 21;
 #endif
 #if defined(STDC) || defined(Z_HAVE_STDARG_H)
-#  ifdef NO_vsnprintf
-    flags += 1L << 25;
-#    ifdef HAS_vsprintf_void
-    flags += 1L << 26;
-#    endif
-#  else
-#    ifdef HAS_vsnprintf_void
-    flags += 1L << 26;
-#    endif
-#  endif
+#   ifdef NO_vsnprintf
+#       ifdef ZLIB_INSECURE
+            flags += 1L << 25;
+#       else
+            flags += 1L << 27;
+#       endif
+#       ifdef HAS_vsprintf_void
+            flags += 1L << 26;
+#       endif
+#   else
+#       ifdef HAS_vsnprintf_void
+            flags += 1L << 26;
+#       endif
+#   endif
 #else
     flags += 1L << 24;
-#  ifdef NO_snprintf
-    flags += 1L << 25;
-#    ifdef HAS_sprintf_void
-    flags += 1L << 26;
-#    endif
-#  else
-#    ifdef HAS_snprintf_void
-    flags += 1L << 26;
-#    endif
-#  endif
+#   ifdef NO_snprintf
+#       ifdef ZLIB_INSECURE
+            flags += 1L << 25;
+#       else
+            flags += 1L << 27;
+#       endif
+#       ifdef HAS_sprintf_void
+            flags += 1L << 26;
+#       endif
+#   else
+#       ifdef HAS_snprintf_void
+            flags += 1L << 26;
+#       endif
+#   endif
 #endif
     return flags;
 }
@@ -142,28 +150,34 @@ const char * ZEXPORT zError(int err) {
 
 #ifndef HAVE_MEMCPY
 
-void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {
-    if (len == 0) return;
-    do {
-        *dest++ = *source++; /* ??? to be unrolled */
-    } while (--len != 0);
+void ZLIB_INTERNAL zmemcpy(void FAR *dst, const void FAR *src, z_size_t n) {
+    uchf *p = dst;
+    const uchf *q = src;
+    while (n) {
+        *p++ = *q++;
+        n--;
+    }
 }
 
-int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {
-    uInt j;
-
-    for (j = 0; j < len; j++) {
-        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+int ZLIB_INTERNAL zmemcmp(const void FAR *s1, const void FAR *s2, z_size_t n) {
+    const uchf *p = s1, *q = s2;
+    while (n) {
+        if (*p++ != *q++)
+            return (int)p[-1] - (int)q[-1];
+        n--;
     }
     return 0;
 }
 
-void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {
+void ZLIB_INTERNAL zmemzero(void FAR *b, z_size_t len) {
+    uchf *p = b;
     if (len == 0) return;
-    do {
-        *dest++ = 0;  /* ??? to be unrolled */
-    } while (--len != 0);
+    while (len) {
+        *p++ = 0;
+        len--;
+    }
 }
+
 #endif
 
 #ifndef Z_SOLO
diff --git a/libs/zlib/zutil.h b/libs/zlib/zutil.h
index 48dd7febae65..a9bc23ca6295 100644
--- a/libs/zlib/zutil.h
+++ b/libs/zlib/zutil.h
@@ -1,5 +1,5 @@
 /* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-2024 Jean-loup Gailly, Mark Adler
+ * Copyright (C) 1995-2026 Jean-loup Gailly, Mark Adler
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
@@ -36,6 +36,10 @@
    define "local" for the non-static meaning of "static", for readability
    (compile with -Dlocal if your debugger can't find static symbols) */
 
+extern const char deflate_copyright[];
+extern const char inflate_copyright[];
+extern const char inflate9_copyright[];
+
 typedef unsigned char  uch;
 typedef uch FAR uchf;
 typedef unsigned short ush;
@@ -48,6 +52,8 @@ typedef unsigned long  ulg;
 #    define Z_U8 unsigned long
 #  elif (ULLONG_MAX == 0xffffffffffffffff)
 #    define Z_U8 unsigned long long
+#  elif (ULONG_LONG_MAX == 0xffffffffffffffff)
+#    define Z_U8 unsigned long long
 #  elif (UINT_MAX == 0xffffffffffffffff)
 #    define Z_U8 unsigned
 #  endif
@@ -63,7 +69,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
 /* To be used only when the state is known to be valid */
 
         /* common constants */
-
+#if MAX_WBITS < 9 || MAX_WBITS > 15
+#  error MAX_WBITS must be in 9..15
+#endif
 #ifndef DEF_WBITS
 #  define DEF_WBITS MAX_WBITS
 #endif
@@ -141,7 +149,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
 #  define OS_CODE  7
 #endif
 
-#ifdef __acorn
+#if defined(__acorn) || defined(__riscos)
 #  define OS_CODE 13
 #endif
 
@@ -168,11 +176,10 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
 #endif
 
 /* provide prototypes for these when building zlib without LFS */
-#if !defined(_WIN32) && \
-    (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
-    ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
-    ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
-    ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
+#ifndef Z_LARGE64
+   ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off64_t);
+   ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off64_t);
+   ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off64_t);
 #endif
 
         /* common defaults */
@@ -211,9 +218,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
 #    define zmemzero(dest, len) memset(dest, 0, len)
 #  endif
 #else
-   void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);
-   int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);
-   void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);
+   void ZLIB_INTERNAL zmemcpy(void FAR *, const void FAR *, z_size_t);
+   int ZLIB_INTERNAL zmemcmp(const void FAR *, const void FAR *, z_size_t);
+   void ZLIB_INTERNAL zmemzero(void FAR *, z_size_t);
 #endif
 
 /* Diagnostic functions */
@@ -251,4 +258,74 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
 #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
                     (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
 
+#ifdef Z_ONCE
+/*
+  Create a local z_once() function depending on the availability of atomics.
+ */
+
+/* Check for the availability of atomics. */
+#if defined(__STDC__) && __STDC_VERSION__ >= 201112L && \
+    !defined(__STDC_NO_ATOMICS__)
+
+#include <stdatomic.h>
+typedef struct {
+    atomic_flag begun;
+    atomic_int done;
+} z_once_t;
+#define Z_ONCE_INIT {ATOMIC_FLAG_INIT, 0}
+
+/*
+  Run the provided init() function exactly once, even if multiple threads
+  invoke once() at the same time. The state must be a once_t initialized with
+  Z_ONCE_INIT.
+ */
+local void z_once(z_once_t *state, void (*init)(void)) {
+    if (!atomic_load(&state->done)) {
+        if (atomic_flag_test_and_set(&state->begun))
+            while (!atomic_load(&state->done))
+                ;
+        else {
+            init();
+            atomic_store(&state->done, 1);
+        }
+    }
+}
+
+#else   /* no atomics */
+
+#warning zlib not thread-safe
+
+typedef struct z_once_s {
+    volatile int begun;
+    volatile int done;
+} z_once_t;
+#define Z_ONCE_INIT {0, 0}
+
+/* Test and set. Alas, not atomic, but tries to limit the period of
+   vulnerability. */
+local int test_and_set(int volatile *flag) {
+    int was;
+
+    was = *flag;
+    *flag = 1;
+    return was;
+}
+
+/* Run the provided init() function once. This is not thread-safe. */
+local void z_once(z_once_t *state, void (*init)(void)) {
+    if (!state->done) {
+        if (test_and_set(&state->begun))
+            while (!state->done)
+                ;
+        else {
+            init();
+            state->done = 1;
+        }
+    }
+}
+
+#endif /* ?atomics */
+
+#endif /* Z_ONCE */
+
 #endif /* ZUTIL_H */
diff --git a/loader/wine.inf.in b/loader/wine.inf.in
index 8c58fb781e45..fc3f085e68bb 100644
--- a/loader/wine.inf.in
+++ b/loader/wine.inf.in
@@ -887,6 +887,8 @@ system.ini, drivers32,,"vidc.mrle=msrle32.dll"
 system.ini, drivers32,,"vidc.msvc=msvidc32.dll"
 system.ini, drivers32,,"vidc.cvid=iccvid.dll"
 system.ini, drivers32,,"vidc.IV50=ir50_32.dll"
+system.ini, drivers32,,"vidc.i420=iyuv_32.dll"
+system.ini, drivers32,,"vidc.iyuv=iyuv_32.dll"
 system.ini, drivers32,,"; vidc.IV31=ir32_32.dll"
 system.ini, drivers32,,"; vidc.IV32=ir32_32.dll"
 
diff --git a/po/ar.po b/po/ar.po
index 8f7dcd39e858..4b3d4c655c40 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -4028,7 +4028,7 @@ msgstr "الأمر خارج المدى"
 msgid "Out of stack space"
 msgstr "لا يوجد أوراق; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "العنصر ضروري"
 
@@ -4036,25 +4036,25 @@ msgstr "العنصر ضروري"
 msgid "Automation server can't create object"
 msgstr "لم يستطع الخادم إنشاء العنصر"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "العنصر لا يدعم هذه الآلية"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "العنصر لا يدعم هذه الحركة"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "المتغير ليس اختياريًا"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "انتهاك في فئة العنصر"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "خطأ بنيوي"
 
@@ -4062,7 +4062,7 @@ msgstr "خطأ بنيوي"
 msgid "Expected ';'"
 msgstr "متوقع ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "متوقع '('"
 
@@ -4070,23 +4070,23 @@ msgstr "متوقع '('"
 msgid "Expected ')'"
 msgstr "متوقع ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Subject Key Identifier"
 msgid "Expected identifier"
 msgstr "معرف مفتاح الموضوع"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "متوقع ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "محرف غير سليم"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "قيمة غير منتهية"
 
@@ -4134,7 +4134,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14080,75 +14080,225 @@ msgstr "(القيمة غير مضبوطة)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "عنصر UUID غير موجود .\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "التدفق الشخصي غير سليم.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "لم يستطع الخادم إنشاء العنصر"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "العنصر لا يدعم هذه الحركة"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "العنصر لا يدعم هذه الحركة"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "العنصر لا يدعم هذه الحركة"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "العنصر غير موجود.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "المتحكم المحدد غير موجود في الرسالة"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' غير معرف"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "معمول متوقع.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "قيمة غير منتهية"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "رقم العلم غير سليم.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "حالة الطابعة غير سليمة.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "وسم معاد تعريفه"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "عامل متوقع.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "متوقع ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/ast.po b/po/ast.po
index 8d78687ebdc7..0de98d09dd8a 100644
--- a/po/ast.po
+++ b/po/ast.po
@@ -3983,7 +3983,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3991,23 +3991,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr "El sirvidor d'automatización nun pue crear l'oxetu"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "L'oxetu nun sofita esta propiedá o métodu"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "L'oxetu nun sofita esta aición"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "L'argumentu nun ye opcional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Error de la sintaxis"
 
@@ -4015,7 +4015,7 @@ msgstr "Error de la sintaxis"
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -4023,19 +4023,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "El caráuter ye inválidu"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4079,7 +4079,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12958,62 +12958,202 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected 'To'"
+msgstr "Esperábase un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'End'"
+msgstr "Esperábase un operandu.\n"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected 'Then'"
+msgstr "Esperábase un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Wend'"
+msgstr "Esperábase un operandu.\n"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Loop'"
+msgstr "Esperábase un operandu.\n"
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected 'Case'"
+msgstr "Esperábase un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected statement"
+msgstr "Esperábase un operandu.\n"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Esperábase un operandu.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected integer constant"
+msgstr "Esperábase un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid member.\n"
+msgid "Invalid number"
+msgstr "El miembru ye inválidu.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "L'estáu de la imprentadora ye inválidu.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Esperábase un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected 'In'"
+msgstr "Esperábase un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Unexpected 'Next'"
+msgstr "Nun s'esperaba l'error de rede.\n"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/bg.po b/po/bg.po
index 340dad2aaffa..a34e7237aa4f 100644
--- a/po/bg.po
+++ b/po/bg.po
@@ -4022,7 +4022,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "Няма хартия; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -4030,23 +4030,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -4054,7 +4054,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -4062,20 +4062,20 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 msgid "Invalid character"
 msgstr "Невалидни знаци в пътя.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4120,7 +4120,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 msgid "Unknown runtime error"
 msgstr "Пре&гледай изходния код"
@@ -13313,64 +13313,179 @@ msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "пътят %s не е намерен.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 msgid "Invalid use of Null"
 msgstr "Невалидни знаци в пътя.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "Файлът не е намерен.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 msgid "Specified DLL function not found"
 msgstr "Файлът не е намерен.\n"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+msgid "Invalid number"
+msgstr "Невалидни знаци в пътя"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+msgid "Invalid 'exit' statement"
+msgstr "Невалидни знаци в пътя.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/ca.po b/po/ca.po
index a3bdc4bf4ce0..3f983dd47ca3 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -4012,7 +4012,7 @@ msgstr "El subíndex és fora d'interval"
 msgid "Out of stack space"
 msgstr "No queda espai de pila"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Es requereix un objecte"
 
@@ -4020,23 +4020,23 @@ msgstr "Es requereix un objecte"
 msgid "Automation server can't create object"
 msgstr "El servidor d'automatització no pot crear l'objecte"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "L'objecte no accepta aquesta propietat o mètode"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "L'objecte no accepta aquesta acció"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument no opcional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "L'objecte no és una colecció"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Error de sintaxi"
 
@@ -4044,7 +4044,7 @@ msgstr "Error de sintaxi"
 msgid "Expected ';'"
 msgstr "S'esperava ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "S'esperava '('"
 
@@ -4052,19 +4052,19 @@ msgstr "S'esperava '('"
 msgid "Expected ')'"
 msgstr "S'esperava ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "S'esperava un identificador"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "S'esperava '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Caràcter no vàlid"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Cadena constant no terminat"
 
@@ -4108,7 +4108,7 @@ msgstr "Error de compilació de Microsoft JScript"
 msgid "Microsoft JScript runtime error"
 msgstr "Error d'entorn d'execució de Microsoft JScript"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Error d'entorn d'execució desconegut"
 
@@ -13073,66 +13073,216 @@ msgid "Object variable not set"
 msgstr "La variable d'objecte no està establerta"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "No s'ha inicialitzat l'objecte.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Ús no vàlid de Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "No es pot crear el fitxer temporal necessari"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "El component d'ActiveX no pot crear l'objecte"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "La classe no permet l'automatització"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 "No s'ha trobat el nom de fitxer o nom de classe durant l'operació "
 "d'automatització"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "L'objecte no accepta arguments nombrats"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "L'objecte no accepta la configuració de localització actual"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "No s'ha trobat el argument anomenat"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 "El nombre d'arguments és incorrecte o l'assignació de propietat no és vàlida"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "No s'ha trobat la funció especificada de la DLL"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 "La variable utilitza un tipus d'automatització que no s'admet en VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "La maquinà de servidor remota no existeix o no està disponible"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' no està definit"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Referència no vàlida o no qualificada"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "S'esperava '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "S'esperava '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "S'esperava '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "S'esperava '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "S'esperava un operant.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Cadena constant no terminat"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "El número d'opció no és vàlid.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "L'estat d'impressora no és vàlid.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "S'ha redefinit l'etiqueta"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "S'esperava un operador.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "S'esperava ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Error de compilació de Microsoft VBScript"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Error d'entorn d'execució de Microsoft VBScript"
 
diff --git a/po/cs.po b/po/cs.po
index 012ea1481161..9ca98931de1d 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -3976,7 +3976,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "Došel papír; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Vyžadován objekt"
 
@@ -3984,23 +3984,23 @@ msgstr "Vyžadován objekt"
 msgid "Automation server can't create object"
 msgstr "Automatizační server nemůže vytvořit objekt"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objekt nepodporuje tuto akci"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument je povinný"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Chybná syntaxe"
 
@@ -4008,7 +4008,7 @@ msgstr "Chybná syntaxe"
 msgid "Expected ';'"
 msgstr "Očekáváno „;“"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Očekáváno „(“"
 
@@ -4016,19 +4016,19 @@ msgstr "Očekáváno „(“"
 msgid "Expected ')'"
 msgstr "Očekáváno „)“"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Očekáván identifikátor"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Očekáváno „=“"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Chybný znak"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4072,7 +4072,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13911,75 +13911,225 @@ msgstr "(hodnota nenastavena)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID objektu nebylo nalezeno.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid separator file.\n"
 msgid "Invalid use of Null"
 msgstr "Neplatný oddělovací soubor.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Automatizační server nemůže vytvořit objekt"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Objekt nepodporuje tuto akci"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Objekt nepodporuje tuto akci"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Objekt nepodporuje tuto akci"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Prvek nenalezen.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Určený ovládací prvek nebyl ve zprávě nalezen"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "„|“ není definováno"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Očekáváno „@end“"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Očekáváno „@end“"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Očekáváno „@end“"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Očekáváno „@end“"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Očekáván operand.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Expected identifier"
+msgid "Expected integer constant"
+msgstr "Očekáván identifikátor"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid member.\n"
+msgid "Invalid number"
+msgstr "Neplatný člen.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Neplatný stav tiskárny.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Označení bylo znovu definováno"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Očekáván operátor.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Očekáváno „;“"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/da.po b/po/da.po
index 5d0e82acafa1..f67577cfabd2 100644
--- a/po/da.po
+++ b/po/da.po
@@ -4055,7 +4055,7 @@ msgstr "Indekset er uden for grænserne"
 msgid "Out of stack space"
 msgstr "Ikke mere papir; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objekt krævet"
 
@@ -4063,25 +4063,25 @@ msgstr "Objekt krævet"
 msgid "Automation server can't create object"
 msgstr "Automations-serveren kan ikke oprette objektet"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objektet understøtter ikke denne egenskab eller metode"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objektet understøtter ikke denne metode"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument ikke valgfrit"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Objektklasse overtrædelse"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntaksfejl"
 
@@ -4089,7 +4089,7 @@ msgstr "Syntaksfejl"
 msgid "Expected ';'"
 msgstr "Forventet ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Forventet '('"
 
@@ -4097,23 +4097,23 @@ msgstr "Forventet '('"
 msgid "Expected ')'"
 msgstr "Forventet ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Subject Key Identifier"
 msgid "Expected identifier"
 msgstr "Emne nøgle identificering"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Forventet ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Ugyldig karakter"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Uafsluttet strengkonstant"
 
@@ -4161,7 +4161,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14164,75 +14164,225 @@ msgstr "(værdi ikke sat)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "Objekt UUID ikke fundet.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Ugyldig bruger buffer.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Automations-serveren kan ikke oprette objektet"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Objektet understøtter ikke denne metode"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Objektet understøtter ikke denne metode"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Objektet understøtter ikke denne metode"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Indgang ikke fundet.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Den specificerede kontroller blev ikke fundet i beskeden"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "«|» er ikke defineret"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected end of statement"
+msgstr "Uventet netværksfejl.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Uafsluttet strengkonstant"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Ugyldigt flag nummer.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Ugyldig printer tilstand.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etiket omdefineret"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Uventet netværksfejl.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/de.po b/po/de.po
index f96341a6a050..adb3aacd46c2 100644
--- a/po/de.po
+++ b/po/de.po
@@ -4000,7 +4000,7 @@ msgstr "Index außerhalb des Bereichs"
 msgid "Out of stack space"
 msgstr "Stackspeicher voll"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objekt benötigt"
 
@@ -4008,23 +4008,23 @@ msgstr "Objekt benötigt"
 msgid "Automation server can't create object"
 msgstr "Automatisierungsserver konnte das Objekt nicht erstellen"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Das Objekt unterstützt diese Eigenschaft oder Methode nicht"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Das Objekt unterstützt diese Aktion nicht"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument nicht optional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Objekt ist keine Kollektion"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntaxfehler"
 
@@ -4032,7 +4032,7 @@ msgstr "Syntaxfehler"
 msgid "Expected ';'"
 msgstr "';' erwartet"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "'(' erwartet"
 
@@ -4040,19 +4040,19 @@ msgstr "'(' erwartet"
 msgid "Expected ')'"
 msgstr "')' erwartet"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Bezeichner erwartet"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "'=' erwartet"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Ungültiges Zeichen"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "konstante Zeichenkette nicht terminiert"
 
@@ -4096,7 +4096,7 @@ msgstr "Microsoft JScript Übersetzungsfehler"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript Laufzeitfehler"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Unbekannter Laufzeitfehler"
 
@@ -13054,63 +13054,213 @@ msgid "Object variable not set"
 msgstr "Objektvariable nicht gesetzt"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Objekt nicht initialisiert.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Ungültige Verwendung von Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Notwendige temporäre Datei konnte nicht erzeugt werden"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX-Komponente konnte Objekt nicht erstellen"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Klasse unterstützt keine Automation"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "Datei- oder Klassenname nicht gefunden während Automationsablauf"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Objekt unterstützt keine benannten Argumente"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Objekt unterstützt aktuelle Regionseinstellung nicht"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Benanntes Argument nicht gefunden"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Falsche Anzahl an Argumenten oder ungültige Merkmalszuweisung"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Angegebene DLL-Funktion nicht gefunden"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 "Variable verwendet einen in VBScript nicht unterstützten Automationstyp"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Remoteserver existiert nicht oder ist nicht verfügbar"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' nicht definiert"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Ungültige oder unqualifizierte Referenz"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "'@end' erwartet"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "'@end' erwartet"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "'@end' erwartet"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "'@end' erwartet"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Operand erwartet.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "konstante Zeichenkette nicht terminiert"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Ungültige Flag-Nummer.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Ungültiger Druckerzustand.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Label neu definiert"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Operator erwartet.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "';' erwartet"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript Übersetzungsfehler"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript Laufzeitfehler"
 
diff --git a/po/el.po b/po/el.po
index ddc2bb235163..51318d1d9686 100644
--- a/po/el.po
+++ b/po/el.po
@@ -3913,7 +3913,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "Τέλος χαρτιού, "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3921,23 +3921,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3945,7 +3945,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3953,20 +3953,20 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 msgid "Invalid character"
 msgstr "Μη έγγυρος(οι) χαρακτήρας(ες) στο μονοπάτι.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4011,7 +4011,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 msgid "Unknown runtime error"
 msgstr "&Περιεχόμενα"
@@ -13056,64 +13056,179 @@ msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "Το αρχείο δε βρέθηκε.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 msgid "Invalid use of Null"
 msgstr "Μη έγγυρος(οι) χαρακτήρας(ες) στο μονοπάτι.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "Το αρχείο δε βρέθηκε.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 msgid "Specified DLL function not found"
 msgstr "Το αρχείο δε βρέθηκε.\n"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+msgid "Invalid number"
+msgstr "Μη έγγυρος(οι) χαρακτήρας(ες) στο μονοπάτι"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+msgid "Invalid 'exit' statement"
+msgstr "Μη έγγυρος(οι) χαρακτήρας(ες) στο μονοπάτι.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/en.po b/po/en.po
index c6924003a2e0..6e5d1f130bed 100644
--- a/po/en.po
+++ b/po/en.po
@@ -3955,7 +3955,7 @@ msgstr "Subscript out of range"
 msgid "Out of stack space"
 msgstr "Out of stack space"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Object required"
 
@@ -3963,23 +3963,23 @@ msgstr "Object required"
 msgid "Automation server can't create object"
 msgstr "Automation server can't create object"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Object doesn't support this property or method"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Object doesn't support this action"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument not optional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Object not a collection"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntax error"
 
@@ -3987,7 +3987,7 @@ msgstr "Syntax error"
 msgid "Expected ';'"
 msgstr "Expected ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Expected '('"
 
@@ -3995,19 +3995,19 @@ msgstr "Expected '('"
 msgid "Expected ')'"
 msgstr "Expected ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Expected identifier"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Expected '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Invalid character"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Unterminated string constant"
 
@@ -4051,7 +4051,7 @@ msgstr "Microsoft JScript compilation error"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript runtime error"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Unknown runtime error"
 
@@ -12921,62 +12921,174 @@ msgid "Object variable not set"
 msgstr "Object variable not set"
 
 #: dlls/vbscript/vbscript.rc:45
+msgid "For loop not initialized"
+msgstr "For loop not initialized"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Invalid use of Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Can't create necessary temporary file"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX component can't create object"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Class doesn't support Automation"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "File name or class name not found during Automation operation"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Object doesn't support named arguments"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Object doesn't support current locale setting"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Named argument not found"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Wrong number of arguments or invalid property assignment"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Specified DLL function not found"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Variable uses an Automation type not supported in VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "The remote server machine does not exist or is unavailable"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
+msgstr "Variable is undefined"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Invalid or unqualified reference"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr "Expected 'To'"
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr "Expected 'End'"
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr "Expected 'Then'"
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr "Expected 'Wend'"
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr "Expected 'Loop'"
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr "Expected 'Next'"
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr "Expected 'Case'"
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr "Expected statement"
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr "Expected end of statement"
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr "Expected integer constant"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr "Expected 'While', 'Until' or end of statement"
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr "Invalid number"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr "'loop' without 'do'"
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr "Invalid 'exit' statement"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr "Name redefined"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr "Must be first statement on the line"
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr "Cannot use parentheses when calling a Sub"
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr "Expected literal constant"
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr "Expected 'In'"
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr "Expected 'Class'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr "Must be defined inside a Class"
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr "Expected Let or Set or Get in property declaration"
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr "Class initialize or terminate do not have arguments"
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr "Property set or let must have at least one argument"
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr "Unexpected 'Next'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr "'Default' specification must also specify 'Public'"
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript compilation error"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript runtime error"
 
diff --git a/po/en_US.po b/po/en_US.po
index 91b1f5226bd1..dc5f6ea6c2b2 100644
--- a/po/en_US.po
+++ b/po/en_US.po
@@ -3955,7 +3955,7 @@ msgstr "Subscript out of range"
 msgid "Out of stack space"
 msgstr "Out of stack space"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Object required"
 
@@ -3963,23 +3963,23 @@ msgstr "Object required"
 msgid "Automation server can't create object"
 msgstr "Automation server can't create object"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Object doesn't support this property or method"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Object doesn't support this action"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument not optional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Object not a collection"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntax error"
 
@@ -3987,7 +3987,7 @@ msgstr "Syntax error"
 msgid "Expected ';'"
 msgstr "Expected ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Expected '('"
 
@@ -3995,19 +3995,19 @@ msgstr "Expected '('"
 msgid "Expected ')'"
 msgstr "Expected ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Expected identifier"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Expected '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Invalid character"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Unterminated string constant"
 
@@ -4051,7 +4051,7 @@ msgstr "Microsoft JScript compilation error"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript runtime error"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Unknown runtime error"
 
@@ -12921,62 +12921,174 @@ msgid "Object variable not set"
 msgstr "Object variable not set"
 
 #: dlls/vbscript/vbscript.rc:45
+msgid "For loop not initialized"
+msgstr "For loop not initialized"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Invalid use of Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Can't create necessary temporary file"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX component can't create object"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Class doesn't support Automation"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "File name or class name not found during Automation operation"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Object doesn't support named arguments"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Object doesn't support current locale setting"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Named argument not found"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Wrong number of arguments or invalid property assignment"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Specified DLL function not found"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Variable uses an Automation type not supported in VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "The remote server machine does not exist or is unavailable"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
+msgstr "Variable is undefined"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Invalid or unqualified reference"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr "Expected 'To'"
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr "Expected 'End'"
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr "Expected 'Then'"
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr "Expected 'Wend'"
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr "Expected 'Loop'"
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr "Expected 'Next'"
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr "Expected 'Case'"
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr "Expected statement"
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr "Expected end of statement"
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr "Expected integer constant"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr "Expected 'While', 'Until' or end of statement"
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr "Invalid number"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr "'loop' without 'do'"
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr "Invalid 'exit' statement"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr "Name redefined"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr "Must be first statement on the line"
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr "Cannot use parentheses when calling a Sub"
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr "Expected literal constant"
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr "Expected 'In'"
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr "Expected 'Class'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr "Must be defined inside a Class"
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr "Expected Let or Set or Get in property declaration"
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr "Class initialize or terminate do not have arguments"
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr "Property set or let must have at least one argument"
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr "Unexpected 'Next'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr "'Default' specification must also specify 'Public'"
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript compilation error"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript runtime error"
 
diff --git a/po/eo.po b/po/eo.po
index a0050f6acc44..aa53e299fac4 100644
--- a/po/eo.po
+++ b/po/eo.po
@@ -3937,7 +3937,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "Elĉerpita papero; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3945,23 +3945,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3969,7 +3969,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3977,21 +3977,21 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 #| msgid "Invalid parameter.\n"
 msgid "Invalid character"
 msgstr "Nevalida parametro.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4035,7 +4035,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown printer driver."
 msgid "Unknown runtime error"
@@ -13695,69 +13695,187 @@ msgstr "Mi ne trovis la vojon.\n"
 msgid "Object variable not set"
 msgstr "(valoro ne elektita)"
 
+# FIXME: Invalid formatting directive
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "Mi ne trovis la objektan UUID-on %s.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid message box style.\n"
 msgid "Invalid use of Null"
 msgstr "Nevalida stilo de la mesaĝa dialogujo.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Elemento ne estis trovita.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Sector not found.\n"
 msgid "Specified DLL function not found"
 msgstr "Sektoro ne estis trovita.\n"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid number format."
+msgid "Invalid number"
+msgstr "Malĝusta nombra formato."
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Nevalida printila stato.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/es.po b/po/es.po
index e687eb2d43ac..1d1ddf107e34 100644
--- a/po/es.po
+++ b/po/es.po
@@ -4015,7 +4015,7 @@ msgstr "Subíndice fuera de rango"
 msgid "Out of stack space"
 msgstr "Sin espacio de pila"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objeto esperado"
 
@@ -4023,25 +4023,25 @@ msgstr "Objeto esperado"
 msgid "Automation server can't create object"
 msgstr "Servidor de automatización no puede crear el objeto"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "El objeto no acepta esta propiedad o método"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "El objeto no acepta esta acción"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumento no opcional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Violación de clase de objeto"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Error de sintaxis"
 
@@ -4049,7 +4049,7 @@ msgstr "Error de sintaxis"
 msgid "Expected ';'"
 msgstr "Esperado ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Esperado '('"
 
@@ -4057,19 +4057,19 @@ msgstr "Esperado '('"
 msgid "Expected ')'"
 msgstr "Esperado ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Identificador esperado"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Esperado '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Caractere inválido"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Constante de cadena no terminada"
 
@@ -4113,7 +4113,7 @@ msgstr "Error de compilación Microsoft JScript"
 msgid "Microsoft JScript runtime error"
 msgstr "Error de ejecución  Microsoft JScript"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Error desconocido en tiempo de ejecución"
 
@@ -13625,72 +13625,222 @@ msgid "Object variable not set"
 msgstr "(valor no definido)"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID del objeto no encontrado.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Uso inválido de Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Servidor de automatización no puede crear el objeto"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "El objeto no acepta esta acción"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "El objeto no acepta esta acción"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "El objeto no acepta esta acción"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Argumento con nombre no encontrado"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Control especificado no se ha encontrado en el mensaje"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' no está definido"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Referencia no válida o no calificada"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Se esperaba un operando.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Constante de cadena no terminada"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Número de bandera inválido.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Estado inválido de la impresora.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etiqueta vuelta a definir"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Error de red inesperado.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/fa.po b/po/fa.po
index 89252ef1eba2..7bee03f94e3d 100644
--- a/po/fa.po
+++ b/po/fa.po
@@ -3937,7 +3937,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3945,23 +3945,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3969,7 +3969,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3977,19 +3977,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4034,7 +4034,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -13217,63 +13217,175 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "'%s' پیدا نشد."
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/fi.po b/po/fi.po
index 07cf5f3d77e5..e07faee3a341 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -3952,7 +3952,7 @@ msgstr "Indeksi alueen ulkopuolella"
 msgid "Out of stack space"
 msgstr "Pinosta loppui tila"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Vaaditaan objekti"
 
@@ -3960,23 +3960,23 @@ msgstr "Vaaditaan objekti"
 msgid "Automation server can't create object"
 msgstr "Automaatiopalvelin ei voi luoda objektia"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objekti ei tue tätä ominaisuutta tai metodia"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objekti ei tue tätä toimintoa"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumentti ei ole valinnainen"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Objekti ei ole kokoelma"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntaksivirhe"
 
@@ -3984,7 +3984,7 @@ msgstr "Syntaksivirhe"
 msgid "Expected ';'"
 msgstr "Odotettiin merkkiä ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Odotettiin merkkiä '('"
 
@@ -3992,19 +3992,19 @@ msgstr "Odotettiin merkkiä '('"
 msgid "Expected ')'"
 msgstr "Odotettiin merkkiä ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Odotettiin tunnistetta"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Odotettiin merkkiä '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Virheellinen merkki"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Päättymätön merkkijonovakio"
 
@@ -4048,7 +4048,7 @@ msgstr "Microsoft JScript -käännösvirhe"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript -suoritusvirhe"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Tuntematon ajonaikainen virhe"
 
@@ -12969,62 +12969,212 @@ msgid "Object variable not set"
 msgstr "Objektimuuttujaa ei ole asetettu"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Objektia ei ole alustettu.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Null-arvon käyttö ei kelpaa"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Tarvittavaa väliaikaistiedostoa ei voida luoda"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX-komponentti ei voi luoda objektia"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Luokka ei tue automaatiota"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "Tiedostonimeä tai luokan nimeä ei löydy automaatio-operaatiossa"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Objekti ei tue nimettyjä argumentteja"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Objekti ei tue nykyistä alueellista asetusta"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Nimettyä argumenttia ei löydy"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Väärä määrä argumentteja tai virhe ominaisuuden asettamisessa"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Määriteltyä DLL-funktiota ei löydy"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Muuttuja käyttää automaatiotyyppiä, jota VBScript ei tue"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Etäpalvelinta ei ole tai se ei ole tavoitettavissa"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' on määrittelemätön"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Viallinen tai määrittämätön viittaus"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Odotettiin sanaa '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Odotettiin sanaa '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Odotettiin sanaa '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Odotettiin sanaa '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Odotettiin operandia.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Päättymätön merkkijonovakio"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Valitsimen numero ei kelpaa.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Tulostimen tila ei kelpaa.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Nimiö määritelty toistamiseen"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Odotettiin operaattoria.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Odotettiin merkkiä ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript -käännösvirhe"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript -suoritusvirhe"
 
diff --git a/po/fr.po b/po/fr.po
index 7f39ebc9b08b..43f4543469ef 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -4012,7 +4012,7 @@ msgstr "Indice hors limites"
 msgid "Out of stack space"
 msgstr "Dépassement de capacité de pile"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objet requis"
 
@@ -4020,23 +4020,23 @@ msgstr "Objet requis"
 msgid "Automation server can't create object"
 msgstr "Le serveur d'automatisation ne peut créer l'objet"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Cet objet ne supporte pas cette propriété ou méthode"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Cet objet ne supporte pas cette action"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument non optionnel"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "L'objet n'est pas une collection"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Erreur de syntaxe"
 
@@ -4044,7 +4044,7 @@ msgstr "Erreur de syntaxe"
 msgid "Expected ';'"
 msgstr "« ; » attendu"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "« ( » attendu"
 
@@ -4052,19 +4052,19 @@ msgstr "« ( » attendu"
 msgid "Expected ')'"
 msgstr "« ) » attendu"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Identifiant attendu"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "« = » attendu"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Caractère non valide"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Constante chaîne de caractères non clôturée"
 
@@ -4108,7 +4108,7 @@ msgstr "Erreur de compilation Microsoft JScript"
 msgid "Microsoft JScript runtime error"
 msgstr "Erreur d'exécution de Microsoft JScript"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Erreur d'exécution inconnue"
 
@@ -13559,65 +13559,215 @@ msgid "Object variable not set"
 msgstr "(valeur non définie)"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "L'objet n'est pas été initialisé.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Utilisation non valide de Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Impossible de créer le fichier temporaire nécessaire"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "Le composant ActiveX ne peut créer l'objet"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "La classe ne supporte pas l'automatisation"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 "Le nom de fichier ou de classe n'a pas été trouvé pendant l'opération "
 "d'automatisation."
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Cet objet ne supporte pas les arguments nommés"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Cet objet ne supporte pas les paramètres régionaux actuels"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Élément nommé introuvable"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "La fonction spécifiée n'a pas été trouvée dans la DLL"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 "La variable utilise un type d'automatisation non pris en charge dans VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Le serveur distant soit n'existe pas soit n'est pas disponible"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "« | » n'est pas défini"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Référence non validée ou non qualifiée"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "« @end » attendu"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "« @end » attendu"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "« @end » attendu"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "« @end » attendu"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Opérande attendu.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Constante chaîne de caractères non clôturée"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Numéro d'indicateur non valide.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "État d'imprimante non valide.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Étiquette redéfinie"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Opérateur attendu.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "« ; » attendu"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Erreur de compilation Microsoft VBScript"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Erreur d'exécution Microsoft VBScript"
 
diff --git a/po/he.po b/po/he.po
index aeb85b150135..53e663309bfb 100644
--- a/po/he.po
+++ b/po/he.po
@@ -4010,7 +4010,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "נגמר הנייר; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -4018,23 +4018,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "שגיאת תחביר"
 
@@ -4042,7 +4042,7 @@ msgstr "שגיאת תחביר"
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -4050,22 +4050,22 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Expected an operand.\n"
 msgid "Expected identifier"
 msgstr "Expected an operand.\n"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 msgid "Invalid character"
 msgstr "Error: Invalid command line parameters.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4112,7 +4112,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14056,65 +14056,208 @@ msgstr "(לא הוגדר ערך)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "הקובץ לא נמצא.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 msgid "Invalid use of Null"
 msgstr "תבנית המספרים שגויה.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "PATH not found.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "הפקד שצוין לא נמצא בהודעה"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' אינו מוגדר"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'To'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'End'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Then'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Wend'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Loop'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Next'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Case'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected statement"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected integer constant"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+msgid "Invalid number"
+msgstr "תבנית המספרים שגויה.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+msgid "Invalid 'exit' statement"
+msgstr "תבנית המספרים שגויה.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'In'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected 'Class'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Unexpected 'Next'"
+msgstr "Expected an operand.\n"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/hi.po b/po/hi.po
index 41d0b0b2ced5..d589b854c743 100644
--- a/po/hi.po
+++ b/po/hi.po
@@ -3863,7 +3863,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3871,23 +3871,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3895,7 +3895,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3903,19 +3903,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3959,7 +3959,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12777,62 +12777,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/hr.po b/po/hr.po
index 29ca8e858943..89aefabe0a71 100644
--- a/po/hr.po
+++ b/po/hr.po
@@ -4031,7 +4031,7 @@ msgstr "Potpis je van dometa"
 msgid "Out of stack space"
 msgstr "Nema papira; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Potreban objekt"
 
@@ -4039,25 +4039,25 @@ msgstr "Potreban objekt"
 msgid "Automation server can't create object"
 msgstr "Poslužitelj automatizacije ne može stvoriti objekt"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objekt ne podržava ovo svojstvo ili metodu"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objekt ne podržava ovu radnju"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument nije opcionalan"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Kršenje klase objekata"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Greška u sintaksi"
 
@@ -4065,7 +4065,7 @@ msgstr "Greška u sintaksi"
 msgid "Expected ';'"
 msgstr "Očekivano ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Očekivano '('"
 
@@ -4073,23 +4073,23 @@ msgstr "Očekivano '('"
 msgid "Expected ')'"
 msgstr "Očekivano ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Expected an operand.\n"
 msgid "Expected identifier"
 msgstr "Očekivan operand.\n"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Očekivano ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Neispravan znak"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Nezavršen niz znakova"
 
@@ -4137,7 +4137,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14085,75 +14085,225 @@ msgstr "(vrijednost nije postavljena)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID objekta nije pronađen.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Neispravan korisnički međuspremnik.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Poslužitelj automatizacije ne može stvoriti objekt"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Objekt ne podržava ovu radnju"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Objekt ne podržava ovu radnju"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Objekt ne podržava ovu radnju"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Element nije pronađen.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Navedena kontrola nije pronađena u poruci"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' nije definiran"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Očekivan operand.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Nezavršen niz znakova"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Neispravan broj zastavica.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Neispravno stanje pisača.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Oznaka redefinirana"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Očekivan operator.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/hu.po b/po/hu.po
index 40a950001654..2352c96799c2 100644
--- a/po/hu.po
+++ b/po/hu.po
@@ -4071,7 +4071,7 @@ msgstr "Érvénytelen alszkript"
 msgid "Out of stack space"
 msgstr "Elfogyott a papír; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objektum szükséges"
 
@@ -4079,25 +4079,25 @@ msgstr "Objektum szükséges"
 msgid "Automation server can't create object"
 msgstr "Az automatizáló (automation) kiszolgáló nem tud objektumot létrehozni"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Az objektum nem támogatja ezt a tulajdonságot vagy metódust"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Az objektum nem támogatja ezt a műveletet"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Az argumentum nem opcionális"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Objektum osztály összeférhetetlenség"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Szinttaktikai hiba"
 
@@ -4105,7 +4105,7 @@ msgstr "Szinttaktikai hiba"
 msgid "Expected ';'"
 msgstr "Hiányzó ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Hiányzó '('"
 
@@ -4113,25 +4113,25 @@ msgstr "Hiányzó '('"
 msgid "Expected ')'"
 msgstr "Hiányzó ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Subject Key Identifier"
 msgid "Expected identifier"
 msgstr "Tárgy kulcs azonosító"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Hiányzó ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 #| msgid "Invalid parameter.\n"
 msgid "Invalid character"
 msgstr "Érvénytelen paraméter.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Lezáratlan sztring konstans"
 
@@ -4179,7 +4179,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14123,75 +14123,225 @@ msgstr "(nem beállított)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID objektum nem található.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Érvénytelen felhasználói puffer.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Az automatizáló (automation) kiszolgáló nem tud objektumot létrehozni"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Az objektum nem támogatja ezt a műveletet"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Az objektum nem támogatja ezt a műveletet"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Az objektum nem támogatja ezt a műveletet"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "A tétel nem található.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "A megadott vezérlő nem található az üzenetben"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "A '|' nem definiált"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected end of statement"
+msgstr "Nem várt hálózati hiba.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Lezáratlan sztring konstans"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Nem valós flag szám.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Érvénytelen nyomtató állapot.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Címke újradefiniált"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Nem várt hálózati hiba.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Hiányzó ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/it.po b/po/it.po
index 5eb3b3a52fad..cde3bb9a2478 100644
--- a/po/it.po
+++ b/po/it.po
@@ -4079,7 +4079,7 @@ msgstr "Sottoscript fuori portata"
 msgid "Out of stack space"
 msgstr "Carta esaurita; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Richiesto un oggetto"
 
@@ -4087,25 +4087,25 @@ msgstr "Richiesto un oggetto"
 msgid "Automation server can't create object"
 msgstr "Il server di automazione non può creare l'oggetto"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "L'oggetto non supporta questa proprietà o metodo"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "L'oggetto non supporta questa azione"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argomento non opzionale"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Violazione di classe dell'oggetto"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Errore di sintassi"
 
@@ -4113,7 +4113,7 @@ msgstr "Errore di sintassi"
 msgid "Expected ';'"
 msgstr "Richiesto ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Richiesto '('"
 
@@ -4121,25 +4121,25 @@ msgstr "Richiesto '('"
 msgid "Expected ')'"
 msgstr "Richiesto ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Subject Key Identifier"
 msgid "Expected identifier"
 msgstr "Identificatore della chiave del soggetto"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Richiesto ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 #| msgid "Invalid parameter.\n"
 msgid "Invalid character"
 msgstr "Parametro non valido.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Costante stringa non terminata"
 
@@ -4187,7 +4187,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14187,75 +14187,225 @@ msgstr "(valore non immesso)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID dell'oggetto non trovato.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Buffer utente non valido.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Il server di automazione non può creare l'oggetto"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "L'oggetto non supporta questa azione"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "L'oggetto non supporta questa azione"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "L'oggetto non supporta questa azione"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Elemento non trovato.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Il controllo specificato non è stato trovato nel messaggio"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' non è definito"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected end of statement"
+msgstr "Errore del network inaspettato.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Costante stringa non terminata"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Numero di flag non valido.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Stato della stampante non valido.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etichetta ridefinita"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Errore del network inaspettato.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Richiesto ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/ja.po b/po/ja.po
index 22880fdff08d..ab007c17a7be 100644
--- a/po/ja.po
+++ b/po/ja.po
@@ -3949,7 +3949,7 @@ msgstr "添字が範囲外です"
 msgid "Out of stack space"
 msgstr "スタック スペースが不足しています"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "オブジェクトが必要です"
 
@@ -3957,23 +3957,23 @@ msgstr "オブジェクトが必要です"
 msgid "Automation server can't create object"
 msgstr "オートメーション サーバーはオブジェクトを生成できません"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "オブジェクトはこのプロパティまたはメソッドをサポートしていません"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "オブジェクトはこの操作をサポートしていません"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "引数は省略できません"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "オブジェクトはコレクションではありません"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "構文エラー"
 
@@ -3981,7 +3981,7 @@ msgstr "構文エラー"
 msgid "Expected ';'"
 msgstr "「;」が必要です"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "「(」が必要です"
 
@@ -3989,19 +3989,19 @@ msgstr "「(」が必要です"
 msgid "Expected ')'"
 msgstr "「)」が必要です"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "識別子が必要です"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "「=」が必要です"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "使用できない文字です"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "文字列定数が終端していません"
 
@@ -4045,7 +4045,7 @@ msgstr "Microsoft JScript コンパイル エラー"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript 実行時エラー"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "未知の実行時エラー"
 
@@ -12918,62 +12918,212 @@ msgid "Object variable not set"
 msgstr "オブジェクト変数は設定されていません"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "オブジェクトが初期化されていません。\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Null の使い方が正しくありません"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "必要な一時ファイルを作成できません"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX コンポーネントはオブジェクトを生成できません"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "クラスはこのオートメーションをサポートしていません"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "オートメーション操作中にファイル名またはクラス名が見つかりません"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "オブジェクトは名前付き引数をサポートしていません"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "オブジェクトは現在のロケール設定をサポートしていません"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "名前付き引数が見つかりません"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "引数の数に誤りがあるかプロパティの代入が正しくありません"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "指定された DLL 関数が見つかりません"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "VBScript ではオートメーション型を使う変数はサポートされていません"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "リモートのサーバー機が存在しないか使用できません"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|'は未定義です"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "正しくないか資格のない参照です"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "「@end」が必要です"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "「@end」が必要です"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "「@end」が必要です"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "「@end」が必要です"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected end of input data stream\n"
+msgid "Expected end of statement"
+msgstr "予期しない入力データ ストリームの終端です\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "文字列定数が終端していません"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "フラグの値は正しくありません。\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "プリンターの状態が正しくありません。\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "ラベルが再定義されました"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected whitespace character\n"
+msgid "Expected literal constant"
+msgstr "空白文字が必要です\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "「;」が必要です"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript コンパイル エラー"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript 実行時エラー"
 
diff --git a/po/ka.po b/po/ka.po
index e95b9af800eb..809581016571 100644
--- a/po/ka.po
+++ b/po/ka.po
@@ -3968,7 +3968,7 @@ msgstr "ინდექსი დიაპაზონს გარეთაა"
 msgid "Out of stack space"
 msgstr "სტეკის სივრცე გადაივსო"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "ობიექტი მიღებულია"
 
@@ -3976,23 +3976,23 @@ msgstr "ობიექტი მიღებულია"
 msgid "Automation server can't create object"
 msgstr "ავტომატიზაციის სერვერს ობიექტის შექმნა არ შეუძლია"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "ობიექტს თვისების ან მეთოდის მხარდაჭერა არ გააჩნია"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "ობიექტს ამ ქმედების მხარდაჭერა არ გააჩნია"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "არგუმენტი არასავალდებულო არაა"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "ობიექტი კოლექცია არაა"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "სინტაქსური შეცდომა"
 
@@ -4000,7 +4000,7 @@ msgstr "სინტაქსური შეცდომა"
 msgid "Expected ';'"
 msgstr "მოველოდი ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "მოველოდი '('"
 
@@ -4008,19 +4008,19 @@ msgstr "მოველოდი '('"
 msgid "Expected ')'"
 msgstr "მოველოდი ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "მოველოდი იდენტიფიკატორს"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "მოველოდი '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "არასწორი სიმბოლო"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "დაუსრულებელი სტრიქონი კონსტანტა"
 
@@ -4064,7 +4064,7 @@ msgstr "Microsoft JScript აგების შეცდომა"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript გაშვების გარემოს შეცდომა"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "უცნობი გაშვების გარემოს შეცდომა"
 
@@ -12952,63 +12952,213 @@ msgid "Object variable not set"
 msgstr "ობიექტის ცვლადი დაყენებული არაა"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "ობიექტი ინიციალიზებული არაა.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "ნულოვანი მნიშვნელობის არასწორი გამოყენება"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "საჭირო დროებით ფაილის შექმნის შეცდომა"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX კომპონენტს ობიექტის შექმნა არ შეუძლია"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "კლასს ავტომატიზაცის მხარდაჭერა არ გააჩნია"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "ფაილის ან კლასის სახელი ავტომატიზაციის ოპერაციისას აღმოჩენილი არაა"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "ობიექტს სახელიანი არგუმენტების მხარდაჭერა არ გააჩნია"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "ობიექტს მიმდინარე ენის პარამეტრის მხარდაჭერა არ გააჩნია"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "მითითებული არგუმენტი ვერ ვიპოვე"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "არგუმენტების არასწორი რაოდენობა ან არასწორი თვისების მინიჭება"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "მითითებული DLL-ის ფუნქცია ვერ ვიპოვე"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 "ცვლადი იყენებს ავტომატიზაციის ტიპს, რომელიც VBScript-ში მარდაჭერილი არაა"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "დაშორებული სერვერის მანქანა არ არსებობს ან ხელმიუწვდომელია"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' აღწერილი არაა"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "არასწორი ან შეუსაბამო მიმართვა"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "მოველოდი '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "მოველოდი '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "მოველოდი '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "მოველოდი '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "მოველოდი ოპერანდს.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "დაუსრულებელი სტრიქონი კონსტანტა"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "ალმის ნომერი არასწორია.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "არასწორი პრინტერის მდგომარეობა.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "ჭდე თავიდან აღიწერა"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "მოველოდი ოპერატორს.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "მოველოდი ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript აგების შეცდომა"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript გაშვების გარემოს შეცდომა"
 
diff --git a/po/ko.po b/po/ko.po
index 8bf0225e80be..33d9d771cc38 100644
--- a/po/ko.po
+++ b/po/ko.po
@@ -3938,7 +3938,7 @@ msgstr "첨자가 범위를 벗어남"
 msgid "Out of stack space"
 msgstr "스택 공간이 부족함"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "개체가 필요함"
 
@@ -3946,23 +3946,23 @@ msgstr "개체가 필요함"
 msgid "Automation server can't create object"
 msgstr "자동화 서버가 개체를 만들 수 없음"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "개체가 이 속성이나 메소드를 지원하지 않습니다"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "개체는 이 행동을 지원하지 않음"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "인수는 옵션이 아닙니다"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "컬렉션이 아닌 개체입니다"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "문법 오류"
 
@@ -3970,7 +3970,7 @@ msgstr "문법 오류"
 msgid "Expected ';'"
 msgstr "';' 필요"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "'(' 필요"
 
@@ -3978,19 +3978,19 @@ msgstr "'(' 필요"
 msgid "Expected ')'"
 msgstr "')' 필요"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "필요한 식별자"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "'=' 필요"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "잘못된 문자"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "끝나지 않은 문자열 상수"
 
@@ -4034,7 +4034,7 @@ msgstr "Microsoft JScript 컴파일 오류"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript 런타임 오류"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "알 수 없는 런타임 오류"
 
@@ -12950,62 +12950,212 @@ msgid "Object variable not set"
 msgstr "개체 변수가 설정되어 있지 않습니다"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "개체가 초기화되지 않았습니다.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "잘못된 널 사용"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "필요한 임시 파일을 만들 수 없습니다"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX 구성 요소는 개체를 만들 수 없습니다"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "클래스는 자동화를 지원하지 않습니다"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "자동화 작업 중에 파일 이름 또는 클래스 이름을 찾을 수 없습니다"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "개체는 명명된 인수를 지원하지 않습니다"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "개체는 현재 로캘 설정을 지원하지 않습니다"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "명명된 인수를 찾을 수 없습니다"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "인수의 개수나 속성 할당이 잘못되었습니다"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "지정한 DLL 함수를 찾을 수 없습니다"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "변수에 VBScript에서 지원되지 않는 자동화 형식이 사용되었습니다"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "원격 서버가 없거나 사용할 수 없습니다"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|'이(가) 정의되지 않았습니다"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "잘못된 참조입니다"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "'@end'가 필요합니다"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "'@end'가 필요합니다"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "'@end'가 필요합니다"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "'@end'가 필요합니다"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "피연산자가 필요합니다.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "끝나지 않은 문자열 상수"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "잘못된 플래그.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "프린터 상태가 잘못되었습니다.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "레이블이 재정의되었습니다"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "연산자가 필요합니다.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "';' 필요"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript 컴파일 오류"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript 런타임 오류"
 
diff --git a/po/lt.po b/po/lt.po
index 492249b02eb5..8d9b3b892054 100644
--- a/po/lt.po
+++ b/po/lt.po
@@ -6,7 +6,7 @@ msgstr ""
 "Project-Id-Version: Wine\n"
 "Report-Msgid-Bugs-To: https://bugs.winehq.org\n"
 "POT-Creation-Date: N/A\n"
-"PO-Revision-Date: 2026-02-28 23:50+0200\n"
+"PO-Revision-Date: 2026-03-20 22:52+0200\n"
 "Last-Translator: Aurimas Fišeras <aurimas@members.fsf.org>\n"
 "Language-Team: Lithuanian <komp_lt@konf.lt>\n"
 "Language: lt\n"
@@ -3962,7 +3962,7 @@ msgstr "Indeksas nepatenka į rėžius"
 msgid "Out of stack space"
 msgstr "Trūksta vietos dėkle"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Reikalingas objektas"
 
@@ -3970,23 +3970,23 @@ msgstr "Reikalingas objektas"
 msgid "Automation server can't create object"
 msgstr "Automatizavimo serveriui nepavyko sukurti objekto"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objektas nepalaiko šios savybės ar metodo"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objektas nepalaiko šio veiksmo"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumentas yra privalomas"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Objektas nėra rinkinys"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Sintaksės klaida"
 
@@ -3994,7 +3994,7 @@ msgstr "Sintaksės klaida"
 msgid "Expected ';'"
 msgstr "Tikėtasi „;“"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Tikėtasi „(“"
 
@@ -4002,19 +4002,19 @@ msgstr "Tikėtasi „(“"
 msgid "Expected ')'"
 msgstr "Tikėtasi „)“"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Tikėtasi identifikatoriaus"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Tikėtasi „=“"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Neteisingas ženklas"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Nebaigta eilutės konstanta"
 
@@ -4058,7 +4058,7 @@ msgstr "Microsoft JScript kompiliavimo klaida"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript vykdymo klaida"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Nežinoma vykdymo klaida"
 
@@ -12885,10 +12885,8 @@ msgid "This array is fixed or temporarily locked"
 msgstr "Šis masyvas yra fiksuotas arba laikinai užblokuotas"
 
 #: dlls/vbscript/vbscript.rc:34
-#, fuzzy
-#| msgid "Division by zero error.\n"
 msgid "Division by zero"
-msgstr "Dalybos iš nulio klaida.\n"
+msgstr "Dalyba iš nulio"
 
 #: dlls/vbscript/vbscript.rc:35
 msgid "Type mismatch"
@@ -12927,63 +12925,213 @@ msgid "Object variable not set"
 msgstr "Objekto kintamasis nenustatytas"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Objektas neinicijuotas.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Netinkamas Null naudojimas"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Nepavyko sukurti reikalingo laikinojo failo"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX komponentui nepavyko sukurti objekto"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Klasė nepalaiko Automatizavimo"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 "Failo vardas arba klasės vardas nerastas vykdant Automatizavimo operaciją"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Objektas nepalaiko įvardytų argumentų"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Objektas nepalaiko dabartinės lokalės nuostatos"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Įvardytas elementas nerastas"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Neteisingas argumentų skaičius ar neteisingas savybės priskyrimas"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Nurodyta DLL funkcija nerasta"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Kintamasis naudoja Automatizavimo tipą nepalaikomą VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Nutolęs serveris neegzistuoja arba nepasiekiamas"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "„|“ neapibrėžtas"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Netinkama arba nepatikslinta nuoroda"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Tikėtasi „@end“"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Tikėtasi „@end“"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Tikėtasi „@end“"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Tikėtasi „@end“"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected end of input data stream\n"
+msgid "Expected end of statement"
+msgstr "Netikėta duomenų srauto įvesties pabaiga\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Nebaigta eilutės konstanta"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Neteisingas žymos bito numeris.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Neteisinga spausdintuvo būsena.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Žymė apibrėžta iš naujo"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected whitespace character\n"
+msgid "Expected literal constant"
+msgstr "Tikėtasi matomo tarpo ženklo\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Tikėtasi „;“"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript kompiliavimo klaida"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript vykdymo klaida"
 
diff --git a/po/ml.po b/po/ml.po
index 3f3c4f624788..93ef74b91c10 100644
--- a/po/ml.po
+++ b/po/ml.po
@@ -3867,7 +3867,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3875,23 +3875,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3899,7 +3899,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3907,19 +3907,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3963,7 +3963,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12784,62 +12784,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/nb_NO.po b/po/nb_NO.po
index 42f2a670f80a..9fb56b1e6f7b 100644
--- a/po/nb_NO.po
+++ b/po/nb_NO.po
@@ -4011,7 +4011,7 @@ msgstr "ID'ene er utenfor rekkevidde"
 msgid "Out of stack space"
 msgstr "Tom for papir; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Trenger et objekt"
 
@@ -4019,25 +4019,25 @@ msgstr "Trenger et objekt"
 msgid "Automation server can't create object"
 msgstr "Automatiseringstjeneren klarte ikke opprette objekt"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objektet støtter ikke denne egenskapen eller metoden"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objektet støtter ikke denne handlingen"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumentet er ikke valgfritt"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Objektklasseovertredelse"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntaksfeil"
 
@@ -4045,7 +4045,7 @@ msgstr "Syntaksfeil"
 msgid "Expected ';'"
 msgstr "Forventet ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Forventet '('"
 
@@ -4053,19 +4053,19 @@ msgstr "Forventet '('"
 msgid "Expected ')'"
 msgstr "Forventet ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Forventet identifiserer"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Forventet '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Ugyldig tegn"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Uavsluttet strengkonstant"
 
@@ -4109,7 +4109,7 @@ msgstr "Microsoft JScript kompileringsfeil"
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13826,75 +13826,225 @@ msgstr "(verdi ikke oppgitt)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Objekt er ikke lastet.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Ugyldig lagringsplass for brukerminne.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Automatiseringstjeneren klarte ikke opprette objekt"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Objektet støtter ikke denne handlingen"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Objektet støtter ikke denne handlingen"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Objektet støtter ikke denne handlingen"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Kan ikke finne elementet.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Den oppgitte kontrolleren ble ikke funnet i meldingen"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' er udefinert"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Forventet '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Forventet '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Forventet '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Forventet '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Forventet en operand.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Uavsluttet strengkonstant"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Ugyldig flaggnummer.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Ugyldig skriverstatus.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etiketten ble omdefinert"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Forventet en operator.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Forventet ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/nl.po b/po/nl.po
index d1ef90728f35..826b571b9cc0 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -3969,7 +3969,7 @@ msgstr "Index buiten bereik"
 msgid "Out of stack space"
 msgstr "Geen stapelruimte"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Object noodzakelijk"
 
@@ -3977,23 +3977,23 @@ msgstr "Object noodzakelijk"
 msgid "Automation server can't create object"
 msgstr "Automatiseringsserver kan het object niet creëren"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Dit object ondersteunt deze eigenschap of methode niet"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Dit object ondersteunt deze actie niet"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument is niet optioneel"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Dit object is geen collectie"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Formuleringsfout"
 
@@ -4001,7 +4001,7 @@ msgstr "Formuleringsfout"
 msgid "Expected ';'"
 msgstr "';' verwacht"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "'(' verwacht"
 
@@ -4009,19 +4009,19 @@ msgstr "'(' verwacht"
 msgid "Expected ')'"
 msgstr "')' verwacht"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Verwachte ID"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Verwacht '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Ongeldig teken"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Onafgesloten tekenreeksconstante"
 
@@ -4065,7 +4065,7 @@ msgstr "Microsoft JScript compilatie fout"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript runtime-fout"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Onbekende runtime-fout"
 
@@ -12997,66 +12997,216 @@ msgid "Object variable not set"
 msgstr "De objectvariabele is niet ingesteld"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Object is niet geïnitialiseerd.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Ongeldig gebruik van Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Kan het tijdelijke bestand niet maken"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX-onderdeel kan geen object maken"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Automatisering wordt niet ondersteund door deze klasse"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 "Kan een bestandsnaam of klassenaam niet vinden tijdens een "
 "automatiseringsbewerking"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Benoemde argumenten worden niet ondersteund door het object"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "De huidige landinstellingen worden niet ondersteund door het object"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Kan benoemd argument niet vinden"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Onjuist aantal argumenten of ongeldige eigenschappentoewijzing"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Kan opgegeven DLL-functie niet vinden"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 "Variabele maakt gebruik van een automatiseringstype dat niet in VBScript "
 "wordt ondersteund"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "De externe servercomputer bestaat niet of is niet beschikbaar"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' is ongedefinieerd"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Ongeldige of niet-gekwalificeerde verwijzing"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Verwacht '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Verwacht '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Verwacht '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Verwacht '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Verwacht een operand.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Onafgesloten tekenreeksconstante"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Ongeldig vlagnumer.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Ongeldige printerstatus.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Label hergedefinieerd"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Verwacht een operator.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "';' verwacht"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Compilatiefout Microsoft VBScript"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Runtimefout Microsoft VBScript"
 
diff --git a/po/or.po b/po/or.po
index fa8b4728241b..286ff4c74eb9 100644
--- a/po/or.po
+++ b/po/or.po
@@ -3863,7 +3863,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3871,23 +3871,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3895,7 +3895,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3903,19 +3903,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3959,7 +3959,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12762,62 +12762,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/pa.po b/po/pa.po
index 30aeea08c627..dd9b2385eeac 100644
--- a/po/pa.po
+++ b/po/pa.po
@@ -3863,7 +3863,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3871,23 +3871,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3895,7 +3895,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3903,19 +3903,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3959,7 +3959,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12762,62 +12762,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/pl.po b/po/pl.po
index e68c21256ddf..45f8fa95bf71 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -10,7 +10,7 @@ msgstr ""
 "Project-Id-Version: Wine\n"
 "Report-Msgid-Bugs-To: https://bugs.winehq.org\n"
 "POT-Creation-Date: N/A\n"
-"PO-Revision-Date: 2026-02-26 09:02+0100\n"
+"PO-Revision-Date: 2026-04-02 16:58+0200\n"
 "Last-Translator: Adam Markowski <wbcwknvstb@proton.me>\n"
 "Language-Team: Polish <kde-i18n-doc@kde.org>\n"
 "Language: pl\n"
@@ -19,7 +19,7 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
-"X-Generator: Poedit 3.8\n"
+"X-Generator: Poedit 3.9\n"
 
 #: dlls/aclui/aclui.rc:29 dlls/inetcpl.cpl/inetcpl.rc:90
 #: programs/winefile/winefile.rc:114
@@ -3979,7 +3979,7 @@ msgstr "Indeks dolny poza zakresem"
 msgid "Out of stack space"
 msgstr "Wyczerpano pamięć stosu"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Wymagany obiekt"
 
@@ -3987,23 +3987,23 @@ msgstr "Wymagany obiekt"
 msgid "Automation server can't create object"
 msgstr "Serwer automatyzacji nie może stworzyć obiektu"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Obiekt nie wspiera tej właściwości lub metody"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Obiekt nie wspiera tej akcji"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument nieopcjonalny"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Obiekt nie jest zbiorem"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Błąd składni"
 
@@ -4011,7 +4011,7 @@ msgstr "Błąd składni"
 msgid "Expected ';'"
 msgstr "Oczekiwano ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Oczekiwano '('"
 
@@ -4019,19 +4019,19 @@ msgstr "Oczekiwano '('"
 msgid "Expected ')'"
 msgstr "Oczekiwano ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Oczekiwano identyfikatora"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Oczekiwano ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Nieprawidłowy znak"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Niezakończona stała znakowa"
 
@@ -4075,7 +4075,7 @@ msgstr "Błąd kompilacji Microsoft JScript"
 msgid "Microsoft JScript runtime error"
 msgstr "Błąd biblioteki uruchomieniowej Microsoft JScript"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Nieznany błąd biblioteki uruchomieniowej"
 
@@ -12917,10 +12917,8 @@ msgid "This array is fixed or temporarily locked"
 msgstr "Ta macierz jest sztywna lub tymczasowo zablokowana"
 
 #: dlls/vbscript/vbscript.rc:34
-#, fuzzy
-#| msgid "Division by zero error.\n"
 msgid "Division by zero"
-msgstr "Błąd dzielenia przez zero.\n"
+msgstr "Dzielenie przez zero"
 
 #: dlls/vbscript/vbscript.rc:35
 msgid "Type mismatch"
@@ -12959,62 +12957,174 @@ msgid "Object variable not set"
 msgstr "Nie ustawiono zmiennej obiektu"
 
 #: dlls/vbscript/vbscript.rc:45
+msgid "For loop not initialized"
+msgstr "Pętla for nie została zainicjowana"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Nieprawidłowe użycie Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Nie można utworzyć potrzebnego pliku tymczasowego"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "Składnik ActiveX nie może utworzyć obiektu"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Klasa nie obsługuje Automation"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "Nie znaleziono nazwy pliku lub klasy podczas działania Automation"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Obiekt nie obsługuje nazwanych argumentów"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Obiekt nie obsługuje ustawień bieżącego regionu"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Nie znaleziono nazwanego argumentu"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Zła liczba argumentów lub nieprawidłowe przypisanie własności"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Nie odnaleziono danej funkcji DLL"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Zmienna używa rodzaju Automation nieobsługiwanego w VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Komputer serwera zdalnego nie istnieje lub jest niedostępny"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
+msgstr "Zmienna jest niezdefiniowana"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Nieprawidłowe lub niezwartościowane odniesienie"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr "Oczekiwano 'To'"
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr "Oczekiwano 'End'"
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr "Oczekiwano 'Then'"
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr "Oczekiwano 'Wend'"
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr "Oczekiwano 'Loop'"
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr "Oczekiwano 'Next'"
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr "Oczekiwano 'Case'"
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr "Oczekiwano instrukcji"
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr "Oczekiwano końca instrukcji"
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr "Oczekiwano stałej całkowitej"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr "Oczekiwano 'While', 'Until' lub końca instrukcji"
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr "Nieprawidłowa liczba"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr "'loop' bez 'do'"
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr "Nieprawidłowa instrukcja 'Exit'"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr "Nazwa zdefiniowana na nowo"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr "Musi być pierwszą instrukcją w wierszu"
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr "Nie można używać nawiasów podczas wywoływania funkcji Sub"
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr "Oczekiwano stałej literałowej"
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr "Oczekiwano 'In'"
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr "Oczekiwano 'Class'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr "Musi być określone wewnątrz funkcji 'Class'"
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr "Oczekiwano Let, Set lub Get w deklaracji właściwości"
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr "Inicjalizacja lub zakończenie funkcji Class nie ma argumentów"
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr "Właściwość Set lub Let musi mieć co najmniej jeden argument"
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr "Oczekiwano 'Next'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr "Specyfikacja 'Default' musi również określać 'Public'"
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Błąd kompilacji Microsoft VBScript"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Błąd biblioteki uruchomieniowej Microsoft VBScript"
 
diff --git a/po/pt_BR.po b/po/pt_BR.po
index db9b4c2b1409..2e55ab04b9f0 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -4010,7 +4010,7 @@ msgstr "Índice fora do intervalo"
 msgid "Out of stack space"
 msgstr "Sem espaço na pilha"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objeto requerido"
 
@@ -4018,23 +4018,23 @@ msgstr "Objeto requerido"
 msgid "Automation server can't create object"
 msgstr "O servidor de automação não conseguiu criar o objeto"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "O objeto não suporta esta propriedade ou método"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "O objeto não suporta esta ação"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumento não opcional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Objeto não é coleção"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Erro de sintaxe"
 
@@ -4042,7 +4042,7 @@ msgstr "Erro de sintaxe"
 msgid "Expected ';'"
 msgstr "Esperado ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Esperado '('"
 
@@ -4050,19 +4050,19 @@ msgstr "Esperado '('"
 msgid "Expected ')'"
 msgstr "Esperado ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Identificador esperado"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Esperado '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Caractere inválido"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Cadeia constante não terminada"
 
@@ -4106,7 +4106,7 @@ msgstr "Microsoft JScript erro de compilação"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript erro de execução"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Erro de execução desconhecido"
 
@@ -13194,62 +13194,212 @@ msgid "Object variable not set"
 msgstr "Objeto variável não setado"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Objeto não inicializado.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Usuo inválido de Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Arquivo temporário não pode ser criado"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "Componente ActiveX não pode criar objeto"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Classe não suporta nomeação automática"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "Nome de arquivo ou classe não encontrado durante operação automática"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "O objeto não suporta argumentos nomeados"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "O objeto não suporta esta ação"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Argumento nomeado não encontrado"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Numero de argumento errado ou propriedade inválida"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "DLL de função não encontrada"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Variável usa um tipo de automação não suportado em VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Servidor remoto não existe ou esta inacessível"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' é indefinido"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Referência inválida"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Esperado um operando.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Cadeia constante não terminada"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Número de flag inválido.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Estado de impressora inválido.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Rótulo redefinido"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Um operador é esperado.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Esperado ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript erro de compilação"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript erro de execução"
 
diff --git a/po/pt_PT.po b/po/pt_PT.po
index c4a93ad17679..35fcce5a6dc9 100644
--- a/po/pt_PT.po
+++ b/po/pt_PT.po
@@ -4057,7 +4057,7 @@ msgstr "Subscripto fora de alcance"
 msgid "Out of stack space"
 msgstr "Sem papel; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objecto esperado"
 
@@ -4065,25 +4065,25 @@ msgstr "Objecto esperado"
 msgid "Automation server can't create object"
 msgstr "O servidor de automação não conseguiu criar o objecto"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "O objecto não suporta esta propriedade ou método"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "O objecto não suporta esta acção"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumento não opcional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Violação da Classe de Objecto"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Erro de sintaxe"
 
@@ -4091,7 +4091,7 @@ msgstr "Erro de sintaxe"
 msgid "Expected ';'"
 msgstr "';' esperado"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "'(' esperado"
 
@@ -4099,19 +4099,19 @@ msgstr "'(' esperado"
 msgid "Expected ')'"
 msgstr "')' esperado"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Identificador esperado"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Esperado '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Caractere inválido"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Constante de string não terminada"
 
@@ -4155,7 +4155,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13962,75 +13962,225 @@ msgstr "(valor não definido)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID do objecto não encontrado.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Buffer de utilizador inválido.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "O servidor de automação não conseguiu criar o objecto"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "O objecto não suporta esta acção"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "O objecto não suporta esta acção"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "O objecto não suporta esta acção"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Elemento não encontrado.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "O controlo especificado não foi encontrado na mensagem"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' é indefinido"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Esperado '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected end of statement"
+msgstr "Operador esperado.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Constante de string não terminada"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Número de flag inválido.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Estado de impressora inválido.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etiqueta redefinida"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Operador esperado.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "';' esperado"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/rm.po b/po/rm.po
index b1e4e140be26..8dc404a5d155 100644
--- a/po/rm.po
+++ b/po/rm.po
@@ -3901,7 +3901,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3909,23 +3909,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3933,7 +3933,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3941,19 +3941,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3997,7 +3997,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12855,62 +12855,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/ro.po b/po/ro.po
index f3af78ade5d2..d7ced88be200 100644
--- a/po/ro.po
+++ b/po/ro.po
@@ -4008,7 +4008,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "Fără hârtia; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Se necesită un obiect"
 
@@ -4016,25 +4016,25 @@ msgstr "Se necesită un obiect"
 msgid "Automation server can't create object"
 msgstr "Serverul de automatizare nu poate crea obiectul"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Obiectul nu suportă această proprietate sau metodă"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Obiectul nu suportă această acțiune"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumentul nu este opțional"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Violare de clasă de obiect"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Eroare de sintaxă"
 
@@ -4042,7 +4042,7 @@ msgstr "Eroare de sintaxă"
 msgid "Expected ';'"
 msgstr "Se așteaptă „;”"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Se așteaptă „(”"
 
@@ -4050,19 +4050,19 @@ msgstr "Se așteaptă „(”"
 msgid "Expected ')'"
 msgstr "Se așteaptă „)”"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Se așteaptă un identificator"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Se așteaptă „=”"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Caracter invalid"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Șir constant neterminat"
 
@@ -4106,7 +4106,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14058,74 +14058,223 @@ msgstr "(valoare nestabilită)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "calea %s nu a fost găsită.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 msgid "Invalid use of Null"
 msgstr "Formatul de număr nu este valid."
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Serverul de automatizare nu poate crea obiectul"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Obiectul nu suportă această acțiune"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Obiectul nu suportă această acțiune"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Obiectul nu suportă această acțiune"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Element negăsit.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Controlul specificat nu a fost găsit în mesaj"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "„|” nu este definit"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Se așteaptă „@end”"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Se așteaptă „@end”"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Se așteaptă „@end”"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Se așteaptă „@end”"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Se așteaptă un operand.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Șir constant neterminat"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Număr de fanion nevalid.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Stare de imprimantă nevalidă.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etichetă redefinită"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Se așteaptă un operator.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Se așteaptă „;”"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/ru.po b/po/ru.po
index 2c4c58d74d83..74dcba316a86 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -3997,7 +3997,7 @@ msgstr "Индекс вне диапазона"
 msgid "Out of stack space"
 msgstr "Превышен размер стека"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Требуется объект"
 
@@ -4005,25 +4005,25 @@ msgstr "Требуется объект"
 msgid "Automation server can't create object"
 msgstr "Сервер автоматизации не может создать объект"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Объект не поддерживает это свойство или метод"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Объект не поддерживает это действие"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Отсутствует обязательный аргумент"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Нарушение класса объекта"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Синтаксическая ошибка"
 
@@ -4031,7 +4031,7 @@ msgstr "Синтаксическая ошибка"
 msgid "Expected ';'"
 msgstr "Ожидается «;»"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Ожидается «(»"
 
@@ -4039,19 +4039,19 @@ msgstr "Ожидается «(»"
 msgid "Expected ')'"
 msgstr "Ожидается «)»"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Ожидается идентификатор"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Ожидается «=»"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Неверный символ"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Незавершённая строковая константа"
 
@@ -4095,7 +4095,7 @@ msgstr "Ошибка компиляции Microsoft JScript"
 msgid "Microsoft JScript runtime error"
 msgstr "Ошибка выполнения Microsoft JScript"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Неизвестная ошибка времени выполнения"
 
@@ -13323,62 +13323,212 @@ msgid "Object variable not set"
 msgstr "Значение переменной (значение не задано)"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Объект не инициализирован.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Некорректное использование Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Не удалось создать временный файл"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "Компонент ActiveX не смог создать объект"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Класс не поддерживает автоматизацию"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Объект не поддерживает именованные аргументы"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Объект не поддерживает выбор локали"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Именованный аргумент не найден"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Указанная функция не найдена в библиотеке"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "«|» не определён"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Некорректная или неполная ссылка"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Ожидается «@end»"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Ожидается «@end»"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Ожидается «@end»"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Ожидается «@end»"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Ожидается операнд.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Незавершённая строковая константа"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Неверный номер флага.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Неверное состояние принтера.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Метка переопределена"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Ожидается оператор.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Ожидается «;»"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Ошибка компиляции Microsoft VBScript"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Ошибка выполнения Microsoft VBScript"
 
diff --git a/po/si.po b/po/si.po
index 302cc06ae896..674902fab2c7 100644
--- a/po/si.po
+++ b/po/si.po
@@ -3939,7 +3939,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "කඩදාසි ඉවරයි; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "වස්තුවක් ඕනේ"
 
@@ -3947,23 +3947,23 @@ msgstr "වස්තුවක් ඕනේ"
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "වාග් රීතියේ දෝෂයක්"
 
@@ -3971,7 +3971,7 @@ msgstr "වාග් රීතියේ දෝෂයක්"
 msgid "Expected ';'"
 msgstr "අපේක්ෂා කරේ ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "අපේක්ෂා කරේ '('"
 
@@ -3979,19 +3979,19 @@ msgstr "අපේක්ෂා කරේ '('"
 msgid "Expected ')'"
 msgstr "අපේක්ෂා කරේ ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "අපේක්ෂා කරේ අනන්යකාරකයක්"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "අපේක්ෂා කරේ '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "අවලංගු අනුලකුණක්"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4036,7 +4036,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13362,65 +13362,214 @@ msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "වස්තුව ආරම්භනය කරල නැහැ.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "අවලංගු පරිශීලක බෆරය.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "මූලාංගය හම්බු උනේ නැහැ.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' නිර්ණය නොකළ"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "අපේක්ෂා කරේ '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "අපේක්ෂා කරේ '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "අපේක්ෂා කරේ '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "අපේක්ෂා කරේ '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "අපේක්ෂා කරේ කර්තව්‍යයක්.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Expected identifier"
+msgid "Expected integer constant"
+msgstr "අපේක්ෂා කරේ අනන්යකාරකයක්"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "අවලංගු සලකුණ නොම්බරය.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "අවලංගු මුද්‍රකය තත්වය.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+msgid "Name redefined"
+msgstr "ලේබලය"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "අපේක්ෂා කරේ මෙහෙයුම්කාරකයක්.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "අපේක්ෂා කරේ ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/sk.po b/po/sk.po
index a33e43f6f371..878050d0994d 100644
--- a/po/sk.po
+++ b/po/sk.po
@@ -3972,7 +3972,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "Chýba papier; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3980,23 +3980,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -4004,7 +4004,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -4012,21 +4012,21 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 #| msgid "Invalid parameter.\n"
 msgid "Invalid character"
 msgstr "Nesprávny parameter.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4070,7 +4070,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13849,65 +13849,200 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+msgid "For loop not initialized"
+msgstr "Súbor nenájdený.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "Súbor nenájdený.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Sector not found.\n"
 msgid "Specified DLL function not found"
 msgstr "Sektor nenájdený.\n"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected 'To'"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected 'Then'"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected 'Case'"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected statement"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected end of statement"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected integer constant"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid name.\n"
+msgid "Invalid number"
+msgstr "Nesprávny názov.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid name.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Nesprávny názov.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected 'In'"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Unexpected 'Next'"
+msgstr "Neočakávaná sieťová chyba.\n"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/sl.po b/po/sl.po
index b0a0e70a5015..d18cb9c5cb31 100644
--- a/po/sl.po
+++ b/po/sl.po
@@ -4073,7 +4073,7 @@ msgstr "Podskript je izven obsega"
 msgid "Out of stack space"
 msgstr "Zmanjkalo je papirja; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Zahtevan je predmet"
 
@@ -4081,25 +4081,25 @@ msgstr "Zahtevan je predmet"
 msgid "Automation server can't create object"
 msgstr "Strežnik izvajanja ne more ustvariti predmeta"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Predmet ne podpira te lastnosti ali načina"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Predmet ne podpira tega dejanja"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument je obvezen"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Prekršitev razreda predmetov"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Skladenjska napaka"
 
@@ -4107,7 +4107,7 @@ msgstr "Skladenjska napaka"
 msgid "Expected ';'"
 msgstr "Pričakovan je bil ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Pričakovan je bil '('"
 
@@ -4115,25 +4115,25 @@ msgstr "Pričakovan je bil '('"
 msgid "Expected ')'"
 msgstr "Pričakovan je bil ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Subject Key Identifier"
 msgid "Expected identifier"
 msgstr "Določilo ključa zahteve"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Pričakovan je bil ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 #| msgid "Invalid parameter.\n"
 msgid "Invalid character"
 msgstr "Neveljaven parameter.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Nedoločena konstanta niza"
 
@@ -4181,7 +4181,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -14178,75 +14178,225 @@ msgstr "(vrednost ni nastavljena)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "UUID predmeta ni mogoče najti.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Neveljaven uporabniški medpomnilnik.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Strežnik izvajanja ne more ustvariti predmeta"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Predmet ne podpira tega dejanja"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Predmet ne podpira tega dejanja"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Predmet ne podpira tega dejanja"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Predmeta ni mogoče najti.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Navedenega nadzornika v sporočilu ni bilo mogoče najti"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' ni določen"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected end of statement"
+msgstr "Nepričakovana napaka omrežja.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Nedoločena konstanta niza"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Neveljavna številka zastavice.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Neveljavno stanje tiskalnika.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Ponovna definicija oznake"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Nepričakovana napaka omrežja.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Pričakovan je bil ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/sr_RS@cyrillic.po b/po/sr_RS@cyrillic.po
index cc2151a94f5a..4676924a16c2 100644
--- a/po/sr_RS@cyrillic.po
+++ b/po/sr_RS@cyrillic.po
@@ -4036,7 +4036,7 @@ msgstr "Потпис је ван домета"
 msgid "Out of stack space"
 msgstr "Нема папира; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 #, fuzzy
 msgid "Object required"
 msgstr "Очекивани објекат"
@@ -4045,25 +4045,25 @@ msgstr "Очекивани објекат"
 msgid "Automation server can't create object"
 msgstr "Аутоматизовани сервер не може да створи објекат"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Објекат не подржава ово својство или методу"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Објекат не подржава ову радњу"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Аргумент је обавезан"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Кршење класе објеката"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Грешка у синтакси"
 
@@ -4071,7 +4071,7 @@ msgstr "Грешка у синтакси"
 msgid "Expected ';'"
 msgstr "Очекивано ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Очекивано '('"
 
@@ -4079,23 +4079,23 @@ msgstr "Очекивано '('"
 msgid "Expected ')'"
 msgstr "Очекивано ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Очекивано ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 msgid "Invalid character"
 msgstr ""
 "Грешка: унесени су непознати или неисправни параметри наредбене линије.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Незавршена константа ниски"
 
@@ -4144,7 +4144,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 msgid "Unknown runtime error"
 msgstr "Непознат извор"
@@ -13856,73 +13856,218 @@ msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "%s путања није пронађена.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 msgid "Invalid use of Null"
 msgstr "Неисправни акредитиви.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Аутоматизовани сервер не може да створи објекат"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Објекат не подржава ову радњу"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Објекат не подржава ову радњу"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Објекат не подржава ову радњу"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "Датотека није пронађена.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Наведена контрола није пронађена у поруци"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "„|“ није одређено"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected end of statement"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Незавршена константа ниски"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+msgid "Invalid number"
+msgstr "Неисправна синтакса.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+msgid "Invalid 'exit' statement"
+msgstr "Неисправна синтакса.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected literal constant"
+msgstr "Незавршена константа ниски"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Очекивано ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/sr_RS@latin.po b/po/sr_RS@latin.po
index de77ad1fbb1f..d086191fced5 100644
--- a/po/sr_RS@latin.po
+++ b/po/sr_RS@latin.po
@@ -4129,7 +4129,7 @@ msgstr "Potpis je van dometa"
 msgid "Out of stack space"
 msgstr "Nema papira; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 #, fuzzy
 msgid "Object required"
 msgstr "Očekivani objekat"
@@ -4138,25 +4138,25 @@ msgstr "Očekivani objekat"
 msgid "Automation server can't create object"
 msgstr "Automatizovani server ne može da stvori objekat"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objekat ne podržava ovo svojstvo ili metodu"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objekat ne podržava ovu radnju"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argument je obavezan"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 #, fuzzy
 #| msgid "Object Class Violation"
 msgid "Object not a collection"
 msgstr "Kršenje klase objekata"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Greška u sintaksi"
 
@@ -4164,7 +4164,7 @@ msgstr "Greška u sintaksi"
 msgid "Expected ';'"
 msgstr "Očekivano ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Očekivano '('"
 
@@ -4172,23 +4172,23 @@ msgstr "Očekivano '('"
 msgid "Expected ')'"
 msgstr "Očekivano ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Očekivano ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 #, fuzzy
 msgid "Invalid character"
 msgstr ""
 "Greška: uneseni su nepoznati ili neispravni parametri naredbene linije.\n"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Nezavršena konstanta niski"
 
@@ -4237,7 +4237,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 msgid "Unknown runtime error"
 msgstr "Nepoznat izvor"
@@ -14003,73 +14003,218 @@ msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+msgid "For loop not initialized"
+msgstr "%s putanja nije pronađena.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 msgid "Invalid use of Null"
 msgstr "Neispravni akreditivi.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Automatizovani server ne može da stvori objekat"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Objekat ne podržava ovu radnju"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Objekat ne podržava ovu radnju"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Objekat ne podržava ovu radnju"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "Datoteka nije pronađena.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Specified control was not found in message"
 msgid "Specified DLL function not found"
 msgstr "Navedena kontrola nije pronađena u poruci"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "„|“ nije određeno"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected end of statement"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Nezavršena konstanta niski"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+msgid "Invalid number"
+msgstr "Neispravna sintaksa.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+msgid "Invalid 'exit' statement"
+msgstr "Neispravna sintaksa.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected literal constant"
+msgstr "Nezavršena konstanta niski"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Očekivano ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/sv.po b/po/sv.po
index af92a1cf1830..d4910b0c7376 100644
--- a/po/sv.po
+++ b/po/sv.po
@@ -4036,7 +4036,7 @@ msgstr "Index utanför giltigt intervall"
 msgid "Out of stack space"
 msgstr "Slut på papper; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Objekt krävs"
 
@@ -4044,23 +4044,23 @@ msgstr "Objekt krävs"
 msgid "Automation server can't create object"
 msgstr "Automationsservern kunde inte skapa objekt"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Objektet stöder inte denna egenskap eller metod"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Objektet stöder inte denna handling"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Argumentet är inte valfritt"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Syntaxfel"
 
@@ -4068,7 +4068,7 @@ msgstr "Syntaxfel"
 msgid "Expected ';'"
 msgstr "';' förväntades"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "'(' förväntades"
 
@@ -4076,19 +4076,19 @@ msgstr "'(' förväntades"
 msgid "Expected ')'"
 msgstr "')' förväntades"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Identifierare förväntades"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "'=' förväntades"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Ogiltigt tecken"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Oterminerad strängkonstant"
 
@@ -4132,7 +4132,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13929,75 +13929,225 @@ msgstr "(värde ej angivet)"
 
 #: dlls/vbscript/vbscript.rc:45
 #, fuzzy
+#| msgid "Object UUID not found.\n"
+msgid "For loop not initialized"
+msgstr "Objekt-UUID ej funnet.\n"
+
+#: dlls/vbscript/vbscript.rc:46
+#, fuzzy
 #| msgid "Invalid user buffer.\n"
 msgid "Invalid use of Null"
 msgstr "Ogiltig användarbuffert.\n"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 #, fuzzy
 #| msgid "Automation server can't create object"
 msgid "ActiveX component can't create object"
 msgstr "Automationsservern kunde inte skapa objekt"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Class doesn't support Automation"
 msgstr "Objektet stöder inte denna handling"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support named arguments"
 msgstr "Objektet stöder inte denna handling"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 #, fuzzy
 #| msgid "Object doesn't support this action"
 msgid "Object doesn't support current locale setting"
 msgstr "Objektet stöder inte denna handling"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 #| msgid "Element not found.\n"
 msgid "Named argument not found"
 msgstr "Elementet hittades inte.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 #| msgid "Sector not found.\n"
 msgid "Specified DLL function not found"
 msgstr "Sektor hittades inte.\n"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' är odefinierat"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "'@end' förväntades"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "'@end' förväntades"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "'@end' förväntades"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "'@end' förväntades"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "En operand förväntades.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Oterminerad strängkonstant"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Ogiltigt flaggnummer.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Ogiltigt skrivartillstånd.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etiketten är redan definierat"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Operator förväntades.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "';' förväntades"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/ta.po b/po/ta.po
index 21ecb897515c..1609b9646c02 100644
--- a/po/ta.po
+++ b/po/ta.po
@@ -3895,7 +3895,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3903,23 +3903,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3927,7 +3927,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3935,19 +3935,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3991,7 +3991,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12786,62 +12786,176 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid character(s) in path"
+msgid "Invalid number"
+msgstr "பாதையில் தவறான எழுத்து(கள்)."
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/te.po b/po/te.po
index ce5a8b8ab724..dfdce89321bf 100644
--- a/po/te.po
+++ b/po/te.po
@@ -3863,7 +3863,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3871,23 +3871,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3895,7 +3895,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3903,19 +3903,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3959,7 +3959,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12762,62 +12762,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/th.po b/po/th.po
index 8e66a97caf32..0a76fb6c2d17 100644
--- a/po/th.po
+++ b/po/th.po
@@ -3931,7 +3931,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr "กระดาษหมด; "
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3939,23 +3939,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3963,7 +3963,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3971,19 +3971,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4028,7 +4028,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown printer driver."
 msgid "Unknown runtime error"
@@ -13307,64 +13307,177 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+msgid "For loop not initialized"
+msgstr "ไม่พบแฟ้ม.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "ไม่พบแฟ้ม.\n"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 #, fuzzy
 msgid "Specified DLL function not found"
 msgstr "ไม่พบแฟ้ม.\n"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/tr.po b/po/tr.po
index 49c1ced30474..ea03b27bd19c 100644
--- a/po/tr.po
+++ b/po/tr.po
@@ -3994,7 +3994,7 @@ msgstr "Alt indis kapsama dışında"
 msgid "Out of stack space"
 msgstr "Yetersiz yığın alanı"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Nesne gerekli"
 
@@ -4002,23 +4002,23 @@ msgstr "Nesne gerekli"
 msgid "Automation server can't create object"
 msgstr "Otomasyon sunucusu nesneyi oluşturamadı"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Nesne bu özelliği veya yöntemi desteklemiyor"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Nesne bu işlemi desteklemiyor"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Değişken isteğe bağlı değil"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Nesne bir koleksiyon değil"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Sözdizimi hatası"
 
@@ -4026,7 +4026,7 @@ msgstr "Sözdizimi hatası"
 msgid "Expected ';'"
 msgstr "Beklenen ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Beklenen '('"
 
@@ -4034,19 +4034,19 @@ msgstr "Beklenen '('"
 msgid "Expected ')'"
 msgstr "Beklenen ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "Beklenen kimlik"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "Beklenen '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Geçersiz karakter"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Sonlandırılmamış dize sabiti"
 
@@ -4090,7 +4090,7 @@ msgstr "Microsoft JScript derleme hatası"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript çalışma zamanı hatası"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "Bilinmeyen çalışma zamanı hatası"
 
@@ -13037,62 +13037,212 @@ msgid "Object variable not set"
 msgstr "Nesne değişkeni belirlenmemiş"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Nesne başlatılmadı.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "'Null' hatalı kullanılmış"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Gereken geçici dosya oluşturulamıyor"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX bileşeni nesneyi oluşturamadı"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Sınıf otomasyonu desteklemiyor"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "Otomasyon işlemi sırasında dosya adı veya sınıf adı bulunamadı"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Nesne isimlendirilmiş değişkenleri desteklemiyor"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Nesne şimdiki konum ayarını desteklemiyor"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "İsimlendirilmiş değişken bulunamadı"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Hatalı değişken sayısı veya geçersiz özellik ataması"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Belirtilen DLL fonksiyonu bulunamadı"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "Değişken, VBScript'te desteklenmeyeb bir otomasyon türü kullanıyor"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Uzak sunucu makinesi yok veya kullanılamıyor"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' tanımsız"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Geçersiz veya yetersiz referans"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "Beklenen '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "Beklenen '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "Beklenen '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "Beklenen '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "Bir terim bekleniyor.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Sonlandırılmamış dize sabiti"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Geçersiz bayrak numarası.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Geçersiz yazıcı durumu.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Etiket tekrar tanımlandı"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "Bir işleç bekleniyor.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Beklenen ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript derleme hatası"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript çalışma zamanı hatası"
 
diff --git a/po/uk.po b/po/uk.po
index 2b64378d1c95..0e986594b0a3 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -4002,7 +4002,7 @@ msgstr "Індекс поза діапазоном"
 msgid "Out of stack space"
 msgstr "В стеку немає місця"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "Вимагається об'єкт"
 
@@ -4010,23 +4010,23 @@ msgstr "Вимагається об'єкт"
 msgid "Automation server can't create object"
 msgstr "Сервер автоматизації не може створити об'єкт"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "Об'єкт не підтримує цю властивість чи метод"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "Об'єкт не підтримує цю дію"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "Відсутній обов'язковий аргумент"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "Об'єкт не є набором"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "Синтаксична помилка"
 
@@ -4034,7 +4034,7 @@ msgstr "Синтаксична помилка"
 msgid "Expected ';'"
 msgstr "Очікується ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "Очікується '('"
 
@@ -4042,23 +4042,23 @@ msgstr "Очікується '('"
 msgid "Expected ')'"
 msgstr "Очікується ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 #, fuzzy
 #| msgid "Subject Key Identifier"
 msgid "Expected identifier"
 msgstr "Ідентифікатор ключа суб’єкта"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 #, fuzzy
 #| msgid "Expected ';'"
 msgid "Expected '='"
 msgstr "Очікується ';'"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "Невірний символ"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "Незавершена рядкова константа"
 
@@ -4106,7 +4106,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 #, fuzzy
 #| msgid "Unknown error"
 msgid "Unknown runtime error"
@@ -13334,63 +13334,213 @@ msgid "Object variable not set"
 msgstr "Не встановлена ​​змінна об'єкта"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "Об'єкт не ініціалізований.\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Неправильне використання Null"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "Не вдається створити необхідний тимчасовий файл"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "Компонент ActiveX не може створити об’єкт"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "Клас не підтримує автоматизацію"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "Ім'я файлу або ім'я класу не знайдено під час операції автоматизації"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "Об'єкт не підтримує названі аргументи"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "Об’єкт не підтримує поточні налаштування мови"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "Названий аргумент не знайдено"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "Неправильна кількість аргументів або недійсне призначення властивості"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "Вказану функцію DLL не знайдено"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 "Змінна використовує тип автоматизації, який не підтримується у VBScript"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "Віддалений сервер не існує або недоступний"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' не визначено"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "Недійсне або невизначене посилання"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'End'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Then'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Wend'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected statement"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected end of statement"
+msgstr "Неочікувана помилка мережі.\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "Незавершена рядкова константа"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "Невірний номер прапорця.\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid server state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "Невірний стан сервера.\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "Мітка перевизначена"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Unexpected network error.\n"
+msgid "Expected literal constant"
+msgstr "Неочікувана помилка мережі.\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "Очікується ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Помилка компіляції Microsoft VBScript"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Помилка виконання Microsoft VBScript"
 
diff --git a/po/wa.po b/po/wa.po
index d853c5d4a594..b9800548a38c 100644
--- a/po/wa.po
+++ b/po/wa.po
@@ -3942,7 +3942,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3950,23 +3950,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3974,7 +3974,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3982,19 +3982,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -4039,7 +4039,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -13207,63 +13207,175 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 #, fuzzy
 msgid "Named argument not found"
 msgstr "'%s' pout nén esse trové."
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/wine.pot b/po/wine.pot
index 75d1d4151f47..5b378ddd6c10 100644
--- a/po/wine.pot
+++ b/po/wine.pot
@@ -3817,7 +3817,7 @@ msgstr ""
 msgid "Out of stack space"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr ""
 
@@ -3825,23 +3825,23 @@ msgstr ""
 msgid "Automation server can't create object"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr ""
 
@@ -3849,7 +3849,7 @@ msgstr ""
 msgid "Expected ';'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr ""
 
@@ -3857,19 +3857,19 @@ msgstr ""
 msgid "Expected ')'"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr ""
 
@@ -3913,7 +3913,7 @@ msgstr ""
 msgid "Microsoft JScript runtime error"
 msgstr ""
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr ""
 
@@ -12678,62 +12678,174 @@ msgid "Object variable not set"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:45
-msgid "Invalid use of Null"
+msgid "For loop not initialized"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:46
+msgid "Invalid use of Null"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:62
-msgid "Invalid or unqualified reference"
+#: dlls/vbscript/vbscript.rc:63
+msgid "Variable is undefined"
 msgstr ""
 
 #: dlls/vbscript/vbscript.rc:64
+msgid "Invalid or unqualified reference"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:69
+msgid "Expected 'To'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:70
+msgid "Expected 'End'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:71
+msgid "Expected 'Then'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:72
+msgid "Expected 'Wend'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:73
+msgid "Expected 'Loop'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:74
+msgid "Expected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:75
+msgid "Expected 'Case'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:76
+msgid "Expected statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:77
+msgid "Expected end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:78
+msgid "Expected integer constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+msgid "Invalid number"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+msgid "Invalid 'exit' statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:85
+msgid "Name redefined"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+msgid "Expected literal constant"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:89
+msgid "Expected 'In'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:90
+msgid "Expected 'Class'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+msgid "Unexpected 'Next'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr ""
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr ""
 
diff --git a/po/zh_CN.po b/po/zh_CN.po
index ea9c30e1e060..04e7b716306f 100644
--- a/po/zh_CN.po
+++ b/po/zh_CN.po
@@ -3905,7 +3905,7 @@ msgstr "标记越界"
 msgid "Out of stack space"
 msgstr "堆栈空间不足"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "需要对象"
 
@@ -3913,23 +3913,23 @@ msgstr "需要对象"
 msgid "Automation server can't create object"
 msgstr "自动化服务器无法创建对象"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "对象不支持此属性或方式"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "对象不支持此动作"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "参数不是可选参数"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "对象不是集合"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "语法错误"
 
@@ -3937,7 +3937,7 @@ msgstr "语法错误"
 msgid "Expected ';'"
 msgstr "期望得到 ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "期望得到 '('"
 
@@ -3945,19 +3945,19 @@ msgstr "期望得到 '('"
 msgid "Expected ')'"
 msgstr "期望得到 ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "期望标识符"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "期望得到 '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "无效字符"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "未终止的字符串常量"
 
@@ -4001,7 +4001,7 @@ msgstr "Microsoft JScript 编译错误"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript 运行时错误"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "未知运行时错误"
 
@@ -12891,62 +12891,212 @@ msgid "Object variable not set"
 msgstr "未设置对象变量"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "对象未初始化。\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Null 使用无效"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "无法创建必要的临时文件"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX 组件无法创建对象"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "类不支持自动化"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "自动化操作期间无法找到文件名或类名"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "对象不支持命名参数"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "对象不支持当前 locale 设置"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "未找到命名参数"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "参数数量错误或无效的指定属性"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "未找到指定的 DLL 函数"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "变量使用了 VBScript 中不支持的自动化类型"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "远程服务器不存在或不可用"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' 未被定义"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "无效或不合格引用"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "期望 '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "期望 '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "期望 '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "期望 '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "期望一个操作数。\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "未终止的字符串常量"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "标志数无效。\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "打印机状态无效。\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "标签被重复定义"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "期望一个操作符。\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "期望得到 ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript 编译错误"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript 运行时错误"
 
diff --git a/po/zh_TW.po b/po/zh_TW.po
index bbe04b7f6d19..fe4244f41821 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -3953,7 +3953,7 @@ msgstr "註標超出範圍"
 msgid "Out of stack space"
 msgstr "堆疊空間不足"
 
-#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:47
+#: dlls/jscript/jscript.rc:32 dlls/vbscript/vbscript.rc:48
 msgid "Object required"
 msgstr "需要物件"
 
@@ -3961,23 +3961,23 @@ msgstr "需要物件"
 msgid "Automation server can't create object"
 msgstr "自動作業伺服器無法建立物件"
 
-#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:51
+#: dlls/jscript/jscript.rc:34 dlls/vbscript/vbscript.rc:52
 msgid "Object doesn't support this property or method"
 msgstr "物件不支援這個屬性或方法"
 
-#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:52
+#: dlls/jscript/jscript.rc:35 dlls/vbscript/vbscript.rc:53
 msgid "Object doesn't support this action"
 msgstr "物件不支援這個動作"
 
-#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:56
+#: dlls/jscript/jscript.rc:36 dlls/vbscript/vbscript.rc:57
 msgid "Argument not optional"
 msgstr "引數並非可選的"
 
-#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:58
+#: dlls/jscript/jscript.rc:37 dlls/vbscript/vbscript.rc:59
 msgid "Object not a collection"
 msgstr "物件並非集合物件"
 
-#: dlls/jscript/jscript.rc:38
+#: dlls/jscript/jscript.rc:38 dlls/vbscript/vbscript.rc:65
 msgid "Syntax error"
 msgstr "語法錯誤"
 
@@ -3985,7 +3985,7 @@ msgstr "語法錯誤"
 msgid "Expected ';'"
 msgstr "預期為 ';'"
 
-#: dlls/jscript/jscript.rc:40
+#: dlls/jscript/jscript.rc:40 dlls/vbscript/vbscript.rc:66
 msgid "Expected '('"
 msgstr "預期為 '('"
 
@@ -3993,19 +3993,19 @@ msgstr "預期為 '('"
 msgid "Expected ')'"
 msgstr "預期為 ')'"
 
-#: dlls/jscript/jscript.rc:42
+#: dlls/jscript/jscript.rc:42 dlls/vbscript/vbscript.rc:67
 msgid "Expected identifier"
 msgstr "預期為識別碼"
 
-#: dlls/jscript/jscript.rc:43
+#: dlls/jscript/jscript.rc:43 dlls/vbscript/vbscript.rc:68
 msgid "Expected '='"
 msgstr "預期為 '='"
 
-#: dlls/jscript/jscript.rc:44
+#: dlls/jscript/jscript.rc:44 dlls/vbscript/vbscript.rc:81
 msgid "Invalid character"
 msgstr "無效的字元"
 
-#: dlls/jscript/jscript.rc:45
+#: dlls/jscript/jscript.rc:45 dlls/vbscript/vbscript.rc:82
 msgid "Unterminated string constant"
 msgstr "未終結的字串常數"
 
@@ -4049,7 +4049,7 @@ msgstr "Microsoft JScript 編譯錯誤"
 msgid "Microsoft JScript runtime error"
 msgstr "Microsoft JScript 執行期錯誤"
 
-#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:66
+#: dlls/jscript/jscript.rc:99 dlls/vbscript/vbscript.rc:100
 msgid "Unknown runtime error"
 msgstr "不明執行期錯誤"
 
@@ -12977,62 +12977,212 @@ msgid "Object variable not set"
 msgstr "沒有設定物件變數"
 
 #: dlls/vbscript/vbscript.rc:45
+#, fuzzy
+#| msgid "Object is not initialized.\n"
+msgid "For loop not initialized"
+msgstr "物件未初始化。\n"
+
+#: dlls/vbscript/vbscript.rc:46
 msgid "Invalid use of Null"
 msgstr "Null 的使用不正確"
 
-#: dlls/vbscript/vbscript.rc:46
+#: dlls/vbscript/vbscript.rc:47
 msgid "Can't create necessary temporary file"
 msgstr "無法建立必須的暫存檔案"
 
-#: dlls/vbscript/vbscript.rc:48
+#: dlls/vbscript/vbscript.rc:49
 msgid "ActiveX component can't create object"
 msgstr "ActiveX 元件無法建立物件"
 
-#: dlls/vbscript/vbscript.rc:49
+#: dlls/vbscript/vbscript.rc:50
 msgid "Class doesn't support Automation"
 msgstr "物件類別不支援自動化"
 
-#: dlls/vbscript/vbscript.rc:50
+#: dlls/vbscript/vbscript.rc:51
 msgid "File name or class name not found during Automation operation"
 msgstr "在自動化運作過程中找不到檔案名稱或物件類別名稱"
 
-#: dlls/vbscript/vbscript.rc:53
+#: dlls/vbscript/vbscript.rc:54
 msgid "Object doesn't support named arguments"
 msgstr "物件不支援指名的引數"
 
-#: dlls/vbscript/vbscript.rc:54
+#: dlls/vbscript/vbscript.rc:55
 msgid "Object doesn't support current locale setting"
 msgstr "物件不支援目前的地區設定"
 
-#: dlls/vbscript/vbscript.rc:55
+#: dlls/vbscript/vbscript.rc:56
 msgid "Named argument not found"
 msgstr "找不到指名的引數"
 
-#: dlls/vbscript/vbscript.rc:57
+#: dlls/vbscript/vbscript.rc:58
 msgid "Wrong number of arguments or invalid property assignment"
 msgstr "引數的個數錯誤或指派的屬性無效"
 
-#: dlls/vbscript/vbscript.rc:59
+#: dlls/vbscript/vbscript.rc:60
 msgid "Specified DLL function not found"
 msgstr "找不到指定的 DLL 函數"
 
-#: dlls/vbscript/vbscript.rc:60
+#: dlls/vbscript/vbscript.rc:61
 msgid "Variable uses an Automation type not supported in VBScript"
 msgstr "變數使用了 VBScript 不支援的自動化類型"
 
-#: dlls/vbscript/vbscript.rc:61
+#: dlls/vbscript/vbscript.rc:62
 msgid "The remote server machine does not exist or is unavailable"
 msgstr "遠端伺服器不存在或無法使用"
 
-#: dlls/vbscript/vbscript.rc:62
+#: dlls/vbscript/vbscript.rc:63
+#, fuzzy
+#| msgid "'|' is undefined"
+msgid "Variable is undefined"
+msgstr "'|' 未定義"
+
+#: dlls/vbscript/vbscript.rc:64
 msgid "Invalid or unqualified reference"
 msgstr "無效或不合格的引用"
 
-#: dlls/vbscript/vbscript.rc:64
+#: dlls/vbscript/vbscript.rc:69
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'To'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:70
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'End'"
+msgstr "預期為 '@end'"
+
+#: dlls/vbscript/vbscript.rc:71
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Then'"
+msgstr "預期為 '@end'"
+
+#: dlls/vbscript/vbscript.rc:72
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected 'Wend'"
+msgstr "預期為 '@end'"
+
+#: dlls/vbscript/vbscript.rc:73
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Loop'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:74
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Next'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:75
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Case'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:76
+#, fuzzy
+#| msgid "Expected '@end'"
+msgid "Expected statement"
+msgstr "預期為 '@end'"
+
+#: dlls/vbscript/vbscript.rc:77
+#, fuzzy
+#| msgid "Expected an operand.\n"
+msgid "Expected end of statement"
+msgstr "預期為一個運算元。\n"
+
+#: dlls/vbscript/vbscript.rc:78
+#, fuzzy
+#| msgid "Unterminated string constant"
+msgid "Expected integer constant"
+msgstr "未終結的字串常數"
+
+#: dlls/vbscript/vbscript.rc:79
+msgid "Expected 'While', 'Until' or end of statement"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:80
+#, fuzzy
+#| msgid "Invalid flag number.\n"
+msgid "Invalid number"
+msgstr "無效的旗標號碼。\n"
+
+#: dlls/vbscript/vbscript.rc:83
+msgid "'loop' without 'do'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:84
+#, fuzzy
+#| msgid "Invalid printer state.\n"
+msgid "Invalid 'exit' statement"
+msgstr "無效的印表機狀態。\n"
+
+#: dlls/vbscript/vbscript.rc:85
+#, fuzzy
+#| msgid "Label redefined"
+msgid "Name redefined"
+msgstr "標貼重複定義"
+
+#: dlls/vbscript/vbscript.rc:86
+msgid "Must be first statement on the line"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:87
+msgid "Cannot use parentheses when calling a Sub"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:88
+#, fuzzy
+#| msgid "Expected an operator.\n"
+msgid "Expected literal constant"
+msgstr "預期為一個運算子。\n"
+
+#: dlls/vbscript/vbscript.rc:89
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'In'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:90
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Expected 'Class'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:91
+msgid "Must be defined inside a Class"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:92
+msgid "Expected Let or Set or Get in property declaration"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:93
+msgid "Class initialize or terminate do not have arguments"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:94
+msgid "Property set or let must have at least one argument"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:95
+#, fuzzy
+#| msgid "Expected ';'"
+msgid "Unexpected 'Next'"
+msgstr "預期為 ';'"
+
+#: dlls/vbscript/vbscript.rc:96
+msgid "'Default' specification must also specify 'Public'"
+msgstr ""
+
+#: dlls/vbscript/vbscript.rc:98
 msgid "Microsoft VBScript compilation error"
 msgstr "Microsoft VBScript 編譯錯誤"
 
-#: dlls/vbscript/vbscript.rc:65
+#: dlls/vbscript/vbscript.rc:99
 msgid "Microsoft VBScript runtime error"
 msgstr "Microsoft VBScript 執行期錯誤"
 
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 1f36b7837651..2f4d4a5c26c3 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -58,6 +58,7 @@ typedef enum
     SC_HTYPE_DONT_CARE = 0,
     SC_HTYPE_MANAGER,
     SC_HTYPE_SERVICE,
+    SC_HTYPE_LOCK,
     SC_HTYPE_NOTIFY
 } SC_HANDLE_TYPE;
 
@@ -91,6 +92,11 @@ struct sc_service_handle       /* service handle */
     struct sc_notify_handle *notify;
 };
 
+struct sc_lock_handle
+{
+    struct sc_handle hdr;
+};
+
 static void sc_notify_retain(struct sc_notify_handle *notify)
 {
     InterlockedIncrement(&notify->ref);
@@ -264,6 +270,17 @@ static DWORD validate_notify_handle(SC_RPC_HANDLE handle, DWORD needed_access, s
     return err;
 }
 
+static DWORD validate_lock_handle(SC_RPC_HANDLE handle, struct sc_lock_handle **lock)
+{
+    struct sc_handle *hdr = handle;
+
+    if (hdr->type != SC_HTYPE_LOCK)
+        return ERROR_INVALID_SERVICE_LOCK;
+
+    *lock = (struct sc_lock_handle *)hdr;
+    return ERROR_SUCCESS;
+}
+
 DWORD __cdecl svcctl_OpenSCManagerW(
     MACHINE_HANDLEW MachineName, /* Note: this parameter is ignored */
     LPCWSTR DatabaseName,
@@ -323,6 +340,12 @@ static void SC_RPC_HANDLE_destroy(SC_RPC_HANDLE handle)
             free(service);
             break;
         }
+        case SC_HTYPE_LOCK:
+        {
+            struct sc_lock_handle *lock = (struct sc_lock_handle *)hdr;
+            free(lock);
+            break;
+        }
         default:
             WINE_ERR("invalid handle type %d\n", hdr->type);
             RpcRaiseException(ERROR_INVALID_HANDLE);
@@ -1407,19 +1430,41 @@ void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK hLock)
 {
 }
 
-DWORD __cdecl svcctl_LockServiceDatabase(SC_RPC_HANDLE manager, SC_RPC_LOCK *lock)
+DWORD __cdecl svcctl_LockServiceDatabase(SC_RPC_HANDLE hmngr, SC_RPC_LOCK *handle)
 {
-    TRACE("(%p, %p)\n", manager, lock);
+    DWORD err;
+    struct sc_manager_handle *manager;
+    struct sc_lock_handle *lock;
+
+    TRACE("(%p, %p)\n", hmngr, handle);
+
+    if ((err = validate_scm_handle(hmngr, SC_MANAGER_LOCK, &manager)) != ERROR_SUCCESS)
+        return err;
+
+    if (!(lock = malloc(sizeof(*lock))))
+        return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+
+    lock->hdr.type = SC_HTYPE_LOCK;
+    lock->hdr.access = 0;
+
+    *handle = &lock->hdr;
 
-    *lock = (SC_RPC_LOCK)0xdeadbeef;
     return ERROR_SUCCESS;
 }
 
-DWORD __cdecl svcctl_UnlockServiceDatabase(SC_RPC_LOCK *lock)
+DWORD __cdecl svcctl_UnlockServiceDatabase(SC_RPC_LOCK *handle)
 {
-    TRACE("(&%p)\n", *lock);
+    DWORD err;
+    struct sc_lock_handle *lock;
+
+    TRACE("(&%p)\n", *handle);
+
+    if ((err = validate_lock_handle(*handle, &lock)) != ERROR_SUCCESS)
+        return err;
+
+    SC_RPC_HANDLE_destroy(*handle);
+    *handle = NULL;
 
-    *lock = NULL;
     return ERROR_SUCCESS;
 }
 
diff --git a/programs/wscript/main.c b/programs/wscript/main.c
index 6c8eaaa542a1..2f1e517d4196 100644
--- a/programs/wscript/main.c
+++ b/programs/wscript/main.c
@@ -120,11 +120,65 @@ static HRESULT WINAPI ActiveScriptSite_OnStateChange(IActiveScriptSite *iface,
     return S_OK;
 }
 
+static void print_error(const WCHAR *string)
+{
+    DWORD count, ret, len, lena;
+    char *buf;
+
+    if(wshInteractive) {
+        MessageBoxW(NULL, string, L"Windows Script Host", MB_OK);
+        return;
+    }
+
+    len = lstrlenW(string);
+    ret = WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), string, len, &count, NULL);
+    if(ret) {
+        WriteConsoleW(GetStdHandle(STD_ERROR_HANDLE), L"\r\n", 2, &count, NULL);
+        return;
+    }
+
+    lena = WideCharToMultiByte(GetOEMCP(), 0, string, len, NULL, 0, NULL, NULL);
+    buf = malloc(lena);
+    if(!buf)
+        return;
+
+    WideCharToMultiByte(GetOEMCP(), 0, string, len, buf, lena, NULL, NULL);
+    WriteFile(GetStdHandle(STD_ERROR_HANDLE), buf, lena, &count, FALSE);
+    free(buf);
+    WriteFile(GetStdHandle(STD_ERROR_HANDLE), "\r\n", 2, &count, FALSE);
+}
+
 static HRESULT WINAPI ActiveScriptSite_OnScriptError(IActiveScriptSite *iface,
         IActiveScriptError *pscripterror)
 {
-    WINE_FIXME("()\n");
-    return E_NOTIMPL;
+    EXCEPINFO excepinfo;
+    ULONG line;
+    LONG character;
+    HRESULT hres;
+    WCHAR buf[1024];
+
+    WINE_TRACE("()\n");
+
+    memset(&excepinfo, 0, sizeof(excepinfo));
+    hres = IActiveScriptError_GetExceptionInfo(pscripterror, &excepinfo);
+    if(SUCCEEDED(hres)) {
+        line = 0;
+        character = 0;
+        IActiveScriptError_GetSourcePosition(pscripterror, NULL, &line, &character);
+
+        swprintf(buf, ARRAY_SIZE(buf), L"%s(%lu, %ld) %s: %s",
+                scriptFullName, line + 1, character + 1,
+                excepinfo.bstrSource ? excepinfo.bstrSource : L"",
+                excepinfo.bstrDescription ? excepinfo.bstrDescription : L"");
+
+        print_error(buf);
+
+        SysFreeString(excepinfo.bstrSource);
+        SysFreeString(excepinfo.bstrDescription);
+        SysFreeString(excepinfo.bstrHelpFile);
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI ActiveScriptSite_OnEnterScript(IActiveScriptSite *iface)
@@ -364,7 +418,7 @@ static void run_script(const WCHAR *filename, IActiveScript *script, IActiveScri
         return;
     }
 
-    hres = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 1,
+    hres = IActiveScriptParse_ParseScriptText(parser, text, NULL, NULL, NULL, 1, 0,
             SCRIPTTEXT_HOSTMANAGESSOURCE|SCRIPTITEM_ISVISIBLE, NULL, NULL);
     SysFreeString(text);
     if(FAILED(hres)) {
diff --git a/programs/wscript/tests/run.c b/programs/wscript/tests/run.c
index 7bccf097f879..9aae91ddc7a8 100644
--- a/programs/wscript/tests/run.c
+++ b/programs/wscript/tests/run.c
@@ -455,6 +455,77 @@ static BOOL register_activex(void)
     return TRUE;
 }
 
+static void run_cscript_error_test(void)
+{
+    static const char script_data[] = "y = \"hello\" + 1\n";
+    char file_name[] = "test_err.vbs";
+    char command[MAX_PATH];
+    SECURITY_ATTRIBUTES sa = {sizeof(sa), NULL, TRUE};
+    STARTUPINFOA si = {sizeof(si)};
+    PROCESS_INFORMATION pi;
+    HANDLE stderr_read, stderr_write;
+    char stderr_buf[4096];
+    DWORD exit_code, size;
+    HANDLE file;
+    BOOL bres;
+
+    file = CreateFileA(file_name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
+            FILE_ATTRIBUTE_NORMAL, NULL);
+    ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %lu\n", GetLastError());
+    if(file == INVALID_HANDLE_VALUE)
+        return;
+
+    bres = WriteFile(file, script_data, sizeof(script_data) - 1, &size, NULL);
+    CloseHandle(file);
+    ok(bres, "Could not write to file: %lu\n", GetLastError());
+    if(!bres)
+        goto cleanup;
+
+    bres = CreatePipe(&stderr_read, &stderr_write, &sa, 0);
+    ok(bres, "CreatePipe failed: %lu\n", GetLastError());
+    if(!bres)
+        goto cleanup;
+
+    SetHandleInformation(stderr_read, HANDLE_FLAG_INHERIT, 0);
+
+    si.dwFlags = STARTF_USESTDHANDLES;
+    si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+    si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+    si.hStdError = stderr_write;
+
+    sprintf(command, "cscript.exe //nologo %s", file_name);
+    bres = CreateProcessA(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
+    CloseHandle(stderr_write);
+    if(!bres) {
+        win_skip("cscript.exe is not available\n");
+        CloseHandle(stderr_read);
+        goto cleanup;
+    }
+
+    WaitForSingleObject(pi.hProcess, INFINITE);
+
+    bres = GetExitCodeProcess(pi.hProcess, &exit_code);
+    ok(bres, "GetExitCodeProcess failed: %lu\n", GetLastError());
+    ok(exit_code == 0, "exit_code = %lu\n", exit_code);
+
+    memset(stderr_buf, 0, sizeof(stderr_buf));
+    ReadFile(stderr_read, stderr_buf, sizeof(stderr_buf) - 1, &size, NULL);
+    stderr_buf[size] = 0;
+
+    ok(size > 0, "expected error output on stderr, got nothing\n");
+    ok(strstr(stderr_buf, "test_err.vbs(1,") != NULL,
+       "expected file and line reference in error, got: %s\n", stderr_buf);
+    ok(strstr(stderr_buf, "Type mismatch") != NULL,
+       "expected 'Type mismatch' in output, got: %s\n", stderr_buf);
+
+    CloseHandle(pi.hThread);
+    CloseHandle(pi.hProcess);
+    CloseHandle(stderr_read);
+
+cleanup:
+    DeleteFileA(file_name);
+}
+
 START_TEST(run)
 {
     char **argv;
@@ -478,6 +549,8 @@ START_TEST(run)
                            "winetest.reportSuccess();\n"
                            "WScript.Quit(3);\n"
                            "winetest.ok(false, 'not quit?');\n", 3);
+
+        run_cscript_error_test();
 }
 
     init_registry(FALSE);
diff --git a/server/mapping.c b/server/mapping.c
index 69cd0a7451b4..f9a80bc6cf9d 100644
--- a/server/mapping.c
+++ b/server/mapping.c
@@ -166,7 +166,9 @@ struct mapping
     struct ranges       *committed;  /* list of committed ranges in this mapping */
     struct shared_map   *shared;     /* temp file for shared PE mapping */
     char                *exp_name;   /* export name (for PE image mapping) */
+    void                *ver_res;    /* version resource (for PE image mapping) */
     data_size_t          exp_len;    /* length of export name (for PE image mapping) */
+    data_size_t          ver_len;    /* length of version resource (for PE image mapping) */
 };
 
 static void mapping_dump( struct object *obj, int verbose );
@@ -729,11 +731,12 @@ static int load_data_dir( void *dir, size_t dir_size, size_t va, size_t size, si
 }
 
 /* load EXPORT_DIRECTORY.Name from its section */
-static int load_export_name( char **ret_buf, size_t va, size_t size, size_t align_mask,
+static int load_export_name( char **ret_buf, IMAGE_DATA_DIRECTORY *data, size_t align_mask,
                              int unix_fd, IMAGE_SECTION_HEADER *sec, unsigned int nb_sec )
 {
     char *end, buffer[1024];
     IMAGE_EXPORT_DIRECTORY exp;
+    size_t va = data->VirtualAddress, size = data->Size;
     int ret = load_data_dir( &exp, sizeof(exp), va, size, align_mask, unix_fd, sec, nb_sec );
 
     if (ret != sizeof(exp)) return 0;
@@ -747,11 +750,85 @@ static int load_export_name( char **ret_buf, size_t va, size_t size, size_t alig
     return end - buffer;
 }
 
+/* find a resource entry by id */
+static size_t find_resource_id( const IMAGE_RESOURCE_DIRECTORY_ENTRY *entries, unsigned int count,
+                                unsigned int id, int want_dir )
+{
+    for (unsigned int i = 0; i < count; i++)
+        if (entries[i].Id == id && !entries[i].DataIsDirectory == !want_dir)
+            return entries[i].OffsetToDirectory;
+    return 0;
+}
+
+/* find a resource entry in a directory */
+static size_t find_resource_entry( unsigned int id, IMAGE_DATA_DIRECTORY *data,
+                                   size_t offset, size_t align_mask, int unix_fd,
+                                   IMAGE_SECTION_HEADER *sec, unsigned int nb_sec )
+{
+    IMAGE_RESOURCE_DIRECTORY_ENTRY *entries;
+    IMAGE_RESOURCE_DIRECTORY res;
+    size_t size;
+    int ret;
+
+    if (offset >= data->Size) return 0;
+    ret = load_data_dir( &res, sizeof(res), data->VirtualAddress + offset, data->Size - offset,
+                         align_mask, unix_fd, sec, nb_sec );
+    if (ret != sizeof(res)) return 0;
+    offset += ret + res.NumberOfNamedEntries * sizeof(*entries);
+    if (offset >= data->Size) return 0;
+    size = res.NumberOfIdEntries * sizeof(*entries);
+    if (!(entries = malloc( size ))) return 0;
+    ret = load_data_dir( entries, size, data->VirtualAddress + offset, data->Size - offset,
+                         align_mask, unix_fd, sec, nb_sec );
+    offset = 0;
+    if (ret >= sizeof(*entries))
+    {
+        unsigned int count = ret / sizeof(*entries);
+        if (!id)  /* try various languages */
+        {
+            if (!(offset = find_resource_id( entries, count, 0x0409, 0 )) &&
+                !(offset = find_resource_id( entries, count, 0x0000, 0 )) &&
+                !entries[0].DataIsDirectory)
+                offset = entries[0].OffsetToData;
+        }
+        else offset = find_resource_id( entries, count, id, 1 );
+    }
+    free( entries );
+    return offset;
+}
+
+/* load the version resource */
+static int load_version_resource( void **ret_buf, IMAGE_DATA_DIRECTORY *data, size_t align_mask,
+                                  int unix_fd, IMAGE_SECTION_HEADER *sec, unsigned int nb_sec )
+{
+    IMAGE_RESOURCE_DATA_ENTRY entry;
+    size_t offset;
+    int ret;
+
+    if (!(offset = find_resource_entry( RT_VERSION, data, 0, align_mask, unix_fd, sec, nb_sec ))) return 0;
+    if (!(offset = find_resource_entry( 1, data, offset, align_mask, unix_fd, sec, nb_sec ))) return 0;
+    if (!(offset = find_resource_entry( 0, data, offset, align_mask, unix_fd, sec, nb_sec ))) return 0;
+    if (offset >= data->Size) return 0;
+    ret = load_data_dir( &entry, sizeof(entry), data->VirtualAddress + offset, data->Size - offset,
+                         align_mask, unix_fd, sec, nb_sec );
+    if (ret != sizeof(entry)) return 0;
+    if (!(*ret_buf = malloc( entry.Size + 3 ))) return 0;
+    if ((ret = load_data_dir( *ret_buf, entry.Size, entry.OffsetToData, entry.Size,
+                              align_mask, unix_fd, sec, nb_sec )) > 0)
+    {
+        if (ret % 4) memset( (char *)*ret_buf + ret, 0, 4 - ret % 4 );
+        return (ret + 3) & ~3;
+    }
+    free( *ret_buf );
+    return 0;
+}
+
 /* load the CLR header from its section */
-static int load_clr_header( IMAGE_COR20_HEADER *hdr, size_t va, size_t size, size_t align_mask,
+static int load_clr_header( IMAGE_COR20_HEADER *hdr, IMAGE_DATA_DIRECTORY *data, size_t align_mask,
                             int unix_fd, IMAGE_SECTION_HEADER *sec, unsigned int nb_sec )
 {
-    int ret = load_data_dir( hdr, sizeof(*hdr), va, size, align_mask, unix_fd, sec, nb_sec );
+    int ret = load_data_dir( hdr, sizeof(*hdr), data->VirtualAddress, data->Size,
+                             align_mask, unix_fd, sec, nb_sec );
 
     if (ret <= 0) return 0;
     if (ret < sizeof(*hdr)) memset( (char *)hdr + ret, 0, sizeof(*hdr) - ret );
@@ -761,11 +838,12 @@ static int load_clr_header( IMAGE_COR20_HEADER *hdr, size_t va, size_t size, siz
 }
 
 /* load the LOAD_CONFIG header from its section */
-static int load_cfg_header( IMAGE_LOAD_CONFIG_DIRECTORY64 *cfg, size_t va, size_t size, size_t align_mask,
+static int load_cfg_header( IMAGE_LOAD_CONFIG_DIRECTORY64 *cfg, IMAGE_DATA_DIRECTORY *data, size_t align_mask,
                             int unix_fd, IMAGE_SECTION_HEADER *sec, unsigned int nb_sec )
 {
     unsigned int cfg_size;
-    int ret = load_data_dir( cfg, sizeof(*cfg), va, size, align_mask, unix_fd, sec, nb_sec );
+    int ret = load_data_dir( cfg, sizeof(*cfg), data->VirtualAddress, data->Size,
+                             align_mask, unix_fd, sec, nb_sec );
 
     if (ret <= 0) return 0;
     cfg_size = ret;
@@ -805,8 +883,9 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
     } cfg;
     off_t pos;
     int size, has_relocs;
-    size_t mz_size, clr_va = 0, clr_size = 0, exp_va, exp_size, cfg_va, cfg_size, align_mask;
-    unsigned int i, ret;
+    IMAGE_DATA_DIRECTORY *data_dirs, *exp_dir, *res_dir, *cfg_dir, *clr_dir;
+    size_t mz_size, align_mask;
+    unsigned int i, ret, nb_data_dirs;
 
     /* load the headers */
 
@@ -844,16 +923,6 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
             if (!(nt.opt.hdr32.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
                 return STATUS_INVALID_IMAGE_FORMAT;
         }
-        if (nt.opt.hdr32.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
-        {
-            clr_va = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
-            clr_size = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
-        }
-        exp_va = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
-        exp_size = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
-        cfg_va = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress;
-        cfg_size = nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size;
-
         mapping->image.base            = nt.opt.hdr32.ImageBase;
         mapping->image.entry_point     = nt.opt.hdr32.AddressOfEntryPoint;
         mapping->image.map_size        = nt.opt.hdr32.SizeOfImage;
@@ -871,11 +940,8 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
                                           nt.opt.hdr32.SectionAlignment & page_mask);
         mapping->image.header_size     = nt.opt.hdr32.SizeOfHeaders;
         mapping->image.checksum        = nt.opt.hdr32.CheckSum;
-
-        has_relocs = (nt.opt.hdr32.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC &&
-                      nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress &&
-                      nt.opt.hdr32.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size &&
-                      !(nt.FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED));
+        nb_data_dirs                   = nt.opt.hdr32.NumberOfRvaAndSizes;
+        data_dirs                      = nt.opt.hdr32.DataDirectory;
         break;
 
     case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
@@ -892,16 +958,6 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
             if (!(nt.opt.hdr64.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE))
                 return STATUS_INVALID_IMAGE_FORMAT;
         }
-        if (nt.opt.hdr64.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR)
-        {
-            clr_va = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
-            clr_size = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
-        }
-        exp_va = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
-        exp_size = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].Size;
-        cfg_va = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].VirtualAddress;
-        cfg_size = nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG].Size;
-
         mapping->image.base            = nt.opt.hdr64.ImageBase;
         mapping->image.entry_point     = nt.opt.hdr64.AddressOfEntryPoint;
         mapping->image.map_size        = nt.opt.hdr64.SizeOfImage;
@@ -919,17 +975,25 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
                                           nt.opt.hdr64.SectionAlignment & page_mask);
         mapping->image.header_size     = nt.opt.hdr64.SizeOfHeaders;
         mapping->image.checksum        = nt.opt.hdr64.CheckSum;
-
-        has_relocs = (nt.opt.hdr64.NumberOfRvaAndSizes > IMAGE_DIRECTORY_ENTRY_BASERELOC &&
-                      nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress &&
-                      nt.opt.hdr64.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size &&
-                      !(nt.FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED));
+        nb_data_dirs                   = nt.opt.hdr64.NumberOfRvaAndSizes;
+        data_dirs                      = nt.opt.hdr64.DataDirectory;
         break;
 
     default:
         return STATUS_INVALID_IMAGE_FORMAT;
     }
 
+#define GET_DATA_DIR(dir) \
+    (dir < nb_data_dirs && data_dirs[dir].VirtualAddress && data_dirs[dir].Size ? &data_dirs[dir] : NULL)
+
+    exp_dir = GET_DATA_DIR( IMAGE_DIRECTORY_ENTRY_EXPORT );
+    res_dir = GET_DATA_DIR( IMAGE_DIRECTORY_ENTRY_RESOURCE );
+    cfg_dir = GET_DATA_DIR( IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG );
+    clr_dir = GET_DATA_DIR( IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR );
+    has_relocs = (GET_DATA_DIR( IMAGE_DIRECTORY_ENTRY_BASERELOC ) &&
+                  !(nt.FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED));
+#undef GET_DATA_DIR
+
     mapping->image.is_hybrid     = 0;
     mapping->image.padding       = 0;
     mapping->image.map_addr      = get_fd_map_address( mapping->fd );
@@ -940,7 +1004,7 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
     mapping->image.zerobits      = 0; /* FIXME */
     mapping->image.file_size     = file_size;
     mapping->image.image_flags   = 0;
-    mapping->image.loader_flags  = clr_va && clr_size;
+    mapping->image.loader_flags  = !!clr_dir;
     mapping->image.wine_builtin  = (mz_size == sizeof(mz) &&
                                     !memcmp( mz.buffer, builtin_signature, sizeof(builtin_signature) ));
     mapping->image.wine_fakedll  = (mz_size == sizeof(mz) &&
@@ -949,7 +1013,7 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
     if (mapping->image.alignment & page_mask)
         mapping->image.image_flags |= IMAGE_FLAGS_ImageMappedFlat;
     else if ((mapping->image.dll_charact & IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) &&
-             (has_relocs || mapping->image.contains_code) && !(clr_va && clr_size))
+             (has_relocs || mapping->image.contains_code) && !clr_dir)
         mapping->image.image_flags |= IMAGE_FLAGS_ImageDynamicallyRelocated;
 
     align_mask = max( mapping->image.alignment - 1, page_mask );
@@ -975,11 +1039,16 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
     }
 
     if (mapping->image.wine_builtin || mapping->image.wine_fakedll)
-        mapping->exp_len = load_export_name( &mapping->exp_name, exp_va, exp_size, align_mask,
-                                             unix_fd, sec, nt.FileHeader.NumberOfSections );
+    {
+        if (exp_dir) mapping->exp_len = load_export_name( &mapping->exp_name, exp_dir, align_mask,
+                                                          unix_fd, sec, nt.FileHeader.NumberOfSections );
+    }
+    else if (res_dir)
+        mapping->ver_len = load_version_resource( &mapping->ver_res, res_dir, align_mask,
+                                                  unix_fd, sec, nt.FileHeader.NumberOfSections );
 
-    if (load_clr_header( &clr, clr_va, clr_size, align_mask,
-                         unix_fd, sec, nt.FileHeader.NumberOfSections ) &&
+    if (clr_dir &&
+        load_clr_header( &clr, clr_dir, align_mask, unix_fd, sec, nt.FileHeader.NumberOfSections ) &&
         (clr.Flags & COMIMAGE_FLAGS_ILONLY))
     {
         mapping->image.image_flags |= IMAGE_FLAGS_ComPlusILOnly;
@@ -992,8 +1061,8 @@ static unsigned int get_image_params( struct mapping *mapping, file_pos_t file_s
         }
     }
 
-    if (load_cfg_header( &cfg.cfg64, cfg_va, cfg_size, align_mask,
-                         unix_fd, sec, nt.FileHeader.NumberOfSections ))
+    if (cfg_dir && load_cfg_header( &cfg.cfg64, cfg_dir, align_mask,
+                                    unix_fd, sec, nt.FileHeader.NumberOfSections ))
     {
         if (nt.opt.hdr32.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
             mapping->image.is_hybrid = !!cfg.cfg32.CHPEMetadataPointer;
@@ -1067,7 +1136,9 @@ static struct mapping *create_mapping( struct object *root, const struct unicode
     mapping->shared      = NULL;
     mapping->committed   = NULL;
     mapping->exp_name    = NULL;
+    mapping->ver_res     = NULL;
     mapping->exp_len     = 0;
+    mapping->ver_len     = 0;
 
     if (!(mapping->flags = get_mapping_flags( handle, flags ))) goto error;
 
@@ -1158,7 +1229,9 @@ struct mapping *create_fd_mapping( struct object *root, const struct unicode_str
     mapping->shared    = NULL;
     mapping->committed = NULL;
     mapping->exp_name  = NULL;
+    mapping->ver_res   = NULL;
     mapping->exp_len   = 0;
+    mapping->ver_len   = 0;
     mapping->flags     = SEC_FILE;
     mapping->fd        = (struct fd *)grab_object( fd );
     set_fd_user( mapping->fd, &mapping_fd_ops, NULL );
@@ -1271,6 +1344,7 @@ static void mapping_destroy( struct object *obj )
     if (mapping->committed) release_object( mapping->committed );
     if (mapping->shared) release_object( mapping->shared );
     free( mapping->exp_name );
+    free( mapping->ver_res );
 }
 
 static enum server_fd_type mapping_get_fd_type( struct fd *fd )
@@ -1564,12 +1638,19 @@ DECL_HANDLER(get_mapping_info)
         void *data;
 
         if (mapping->fd) get_nt_name( mapping->fd, &name );
-        reply->total = sizeof(struct pe_image_info) + name.len + mapping->exp_len;
-        size = min( reply->total, get_reply_max_size() );
+        size = reply->total = sizeof(struct pe_image_info) + mapping->ver_len + name.len + mapping->exp_len;
+        if (size > get_reply_max_size()) size = sizeof(struct pe_image_info) + mapping->ver_len + name.len;
+        if (size > get_reply_max_size()) size = sizeof(struct pe_image_info) + mapping->ver_len;
+        if (size > get_reply_max_size()) size = sizeof(struct pe_image_info);
         if ((data = set_reply_data_size( size )))
         {
             data = mem_append( data, &mapping->image, min( sizeof(struct pe_image_info), size ));
-            if (size >= sizeof(struct pe_image_info) + name.len)
+            if (size >= sizeof(struct pe_image_info) + mapping->ver_len)
+            {
+                data = mem_append( data, mapping->ver_res, mapping->ver_len );
+                reply->ver_len = mapping->ver_len;
+            }
+            if (size >= sizeof(struct pe_image_info) + mapping->ver_len + name.len)
             {
                 data = mem_append( data, name.str, name.len );
                 reply->name_len = name.len;
diff --git a/server/object.h b/server/object.h
index cab8ad25a595..4d96740de03d 100644
--- a/server/object.h
+++ b/server/object.h
@@ -287,9 +287,8 @@ static inline int is_machine_64bit( unsigned short machine )
 }
 static inline int is_machine_supported( unsigned short machine )
 {
-    unsigned int i;
-    for (i = 0; i < supported_machines_count; i++) if (supported_machines[i] == machine) return 1;
-    if (native_machine == IMAGE_FILE_MACHINE_ARM64) return machine == IMAGE_FILE_MACHINE_AMD64;
+    for (unsigned int i = 0; i < supported_machines_count; i++)
+        if (supported_machines[i] == machine) return 1;
     return 0;
 }
 
diff --git a/server/protocol.def b/server/protocol.def
index 0ac64297026d..5bca381fd910 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1822,8 +1822,10 @@ enum server_fd_type
     unsigned int flags;         /* SEC_* flags */
     obj_handle_t shared_file;   /* shared mapping file handle */
     data_size_t  name_len;      /* length of file name  */
+    data_size_t  ver_len;       /* length of version resource  */
     data_size_t  total;         /* total required buffer size in bytes */
     VARARG(image,pe_image_info);/* image info for SEC_IMAGE mappings */
+    VARARG(version,version_res,ver_len);/* version resource for SEC_IMAGE mappings */
     VARARG(name,unicode_str,name_len);  /* filename for SEC_IMAGE mappings */
     VARARG(exp_name,string);    /* exported name for SEC_IMAGE mappings */
 @END
@@ -3095,10 +3097,11 @@ enum coords_relative
 @END
 
 
-/* Get the time of the last input event */
-@REQ(get_last_input_time)
+/* Get/Set the time of the input event */
+@REQ(set_user_input_time)
+    int          set;             /* update queue input time */
 @REPLY
-    unsigned int time;
+    unsigned int time;            /* time of the last session-wide user input */
 @END
 
 
diff --git a/server/ptrace.c b/server/ptrace.c
index bfebeca2271d..a8fb85a1794c 100644
--- a/server/ptrace.c
+++ b/server/ptrace.c
@@ -366,7 +366,7 @@ static int read_process_memory_vm( struct thread *thread, client_ptr_t ptr, data
         return -1;
     }
     if (len == size) return 1;
-    set_error( len >= 0 ? STATUS_PARTIAL_COPY : STATUS_ACCESS_DENIED );
+    set_error( STATUS_PARTIAL_COPY );
     return 0;
 }
 #else
diff --git a/server/queue.c b/server/queue.c
index 2c948537f191..abae70fc91b8 100644
--- a/server/queue.c
+++ b/server/queue.c
@@ -4001,9 +4001,17 @@ DECL_HANDLER(set_caret_info)
 }
 
 
-/* get the time of the last input event */
-DECL_HANDLER(get_last_input_time)
+/* get/set the time of the last user input event */
+DECL_HANDLER(set_user_input_time)
 {
+    struct msg_queue *queue;
+
+    if (req->set && (queue = current->queue))
+    {
+        queue->input->user_time = monotonic_time;
+        last_input_time = get_tick_count();
+    }
+
     reply->time = last_input_time;
 }
 
diff --git a/server/registry.c b/server/registry.c
index a367d70c7eee..91b3265e8f76 100644
--- a/server/registry.c
+++ b/server/registry.c
@@ -1877,6 +1877,7 @@ static void init_supported_machines(void)
         supported_machines[count++] = IMAGE_FILE_MACHINE_ARM64;
         supported_machines[count++] = IMAGE_FILE_MACHINE_I386;
         if (supports_aarch32()) supported_machines[count++] = IMAGE_FILE_MACHINE_ARMNT;
+        supported_machines[count++] = IMAGE_FILE_MACHINE_AMD64;
     }
 #else
 #error Unsupported machine
diff --git a/server/request_handlers.h b/server/request_handlers.h
index 42eb7daeab13..3c5187953408 100644
--- a/server/request_handlers.h
+++ b/server/request_handlers.h
@@ -196,7 +196,7 @@ DECL_HANDLER(register_hotkey);
 DECL_HANDLER(unregister_hotkey);
 DECL_HANDLER(attach_thread_input);
 DECL_HANDLER(get_thread_input);
-DECL_HANDLER(get_last_input_time);
+DECL_HANDLER(set_user_input_time);
 DECL_HANDLER(get_key_state);
 DECL_HANDLER(set_key_state);
 DECL_HANDLER(set_foreground_window);
@@ -506,7 +506,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_unregister_hotkey,
     (req_handler)req_attach_thread_input,
     (req_handler)req_get_thread_input,
-    (req_handler)req_get_last_input_time,
+    (req_handler)req_set_user_input_time,
     (req_handler)req_get_key_state,
     (req_handler)req_set_key_state,
     (req_handler)req_set_foreground_window,
@@ -1093,8 +1093,9 @@ C_ASSERT( offsetof(struct get_mapping_info_reply, size) == 8 );
 C_ASSERT( offsetof(struct get_mapping_info_reply, flags) == 16 );
 C_ASSERT( offsetof(struct get_mapping_info_reply, shared_file) == 20 );
 C_ASSERT( offsetof(struct get_mapping_info_reply, name_len) == 24 );
-C_ASSERT( offsetof(struct get_mapping_info_reply, total) == 28 );
-C_ASSERT( sizeof(struct get_mapping_info_reply) == 32 );
+C_ASSERT( offsetof(struct get_mapping_info_reply, ver_len) == 28 );
+C_ASSERT( offsetof(struct get_mapping_info_reply, total) == 32 );
+C_ASSERT( sizeof(struct get_mapping_info_reply) == 40 );
 C_ASSERT( offsetof(struct get_image_map_address_request, handle) == 12 );
 C_ASSERT( sizeof(struct get_image_map_address_request) == 16 );
 C_ASSERT( offsetof(struct get_image_map_address_reply, addr) == 8 );
@@ -1738,9 +1739,10 @@ C_ASSERT( offsetof(struct get_thread_input_request, tid) == 12 );
 C_ASSERT( sizeof(struct get_thread_input_request) == 16 );
 C_ASSERT( offsetof(struct get_thread_input_reply, locator) == 8 );
 C_ASSERT( sizeof(struct get_thread_input_reply) == 24 );
-C_ASSERT( sizeof(struct get_last_input_time_request) == 16 );
-C_ASSERT( offsetof(struct get_last_input_time_reply, time) == 8 );
-C_ASSERT( sizeof(struct get_last_input_time_reply) == 16 );
+C_ASSERT( offsetof(struct set_user_input_time_request, set) == 12 );
+C_ASSERT( sizeof(struct set_user_input_time_request) == 16 );
+C_ASSERT( offsetof(struct set_user_input_time_reply, time) == 8 );
+C_ASSERT( sizeof(struct set_user_input_time_reply) == 16 );
 C_ASSERT( offsetof(struct get_key_state_request, async) == 12 );
 C_ASSERT( offsetof(struct get_key_state_request, key) == 16 );
 C_ASSERT( sizeof(struct get_key_state_request) == 24 );
diff --git a/server/request_trace.h b/server/request_trace.h
index ec36688c3b39..d31263cbfb48 100644
--- a/server/request_trace.h
+++ b/server/request_trace.h
@@ -53,6 +53,7 @@ static void dump_varargs_unicode_str( const char *prefix, data_size_t size );
 static void dump_varargs_unicode_strings( const char *prefix, data_size_t size );
 static void dump_varargs_user_handles( const char *prefix, data_size_t size );
 static void dump_varargs_ushorts( const char *prefix, data_size_t size );
+static void dump_varargs_version_res( const char *prefix, data_size_t size );
 
 static const void *cur_data;
 static data_size_t cur_size;
@@ -884,8 +885,10 @@ static void dump_get_mapping_info_reply( const struct get_mapping_info_reply *re
     fprintf( stderr, ", flags=%08x", req->flags );
     fprintf( stderr, ", shared_file=%04x", req->shared_file );
     fprintf( stderr, ", name_len=%u", req->name_len );
+    fprintf( stderr, ", ver_len=%u", req->ver_len );
     fprintf( stderr, ", total=%u", req->total );
     dump_varargs_pe_image_info( ", image=", cur_size );
+    dump_varargs_version_res( ", version=", min( cur_size, req->ver_len ));
     dump_varargs_unicode_str( ", name=", min( cur_size, req->name_len ));
     dump_varargs_string( ", exp_name=", cur_size );
 }
@@ -2211,11 +2214,12 @@ static void dump_get_thread_input_reply( const struct get_thread_input_reply *re
     dump_obj_locator( " locator=", &req->locator );
 }
 
-static void dump_get_last_input_time_request( const struct get_last_input_time_request *req )
+static void dump_set_user_input_time_request( const struct set_user_input_time_request *req )
 {
+    fprintf( stderr, " set=%d", req->set );
 }
 
-static void dump_get_last_input_time_reply( const struct get_last_input_time_reply *req )
+static void dump_set_user_input_time_reply( const struct set_user_input_time_reply *req )
 {
     fprintf( stderr, " time=%08x", req->time );
 }
@@ -3701,7 +3705,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] =
     (dump_func)dump_unregister_hotkey_request,
     (dump_func)dump_attach_thread_input_request,
     (dump_func)dump_get_thread_input_request,
-    (dump_func)dump_get_last_input_time_request,
+    (dump_func)dump_set_user_input_time_request,
     (dump_func)dump_get_key_state_request,
     (dump_func)dump_set_key_state_request,
     (dump_func)dump_set_foreground_window_request,
@@ -4011,7 +4015,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] =
     (dump_func)dump_unregister_hotkey_reply,
     NULL,
     (dump_func)dump_get_thread_input_reply,
-    (dump_func)dump_get_last_input_time_reply,
+    (dump_func)dump_set_user_input_time_reply,
     (dump_func)dump_get_key_state_reply,
     NULL,
     (dump_func)dump_set_foreground_window_reply,
@@ -4321,7 +4325,7 @@ static const char * const req_names[REQ_NB_REQUESTS] =
     "unregister_hotkey",
     "attach_thread_input",
     "get_thread_input",
-    "get_last_input_time",
+    "set_user_input_time",
     "get_key_state",
     "set_key_state",
     "set_foreground_window",
diff --git a/server/trace.c b/server/trace.c
index 1d091d240ba5..c9812d818bdd 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -82,6 +82,17 @@ static const char *get_status_name( unsigned int status )
     return buffer;
 }
 
+static void dump_ushorts( const char *prefix, const unsigned short *ptr, int len )
+{
+    fprintf( stderr, "%s{", prefix );
+    while (len > 0)
+    {
+        fprintf( stderr, "%04x", *ptr++ );
+        if (--len) fputc( ',', stderr );
+    }
+    fputc( '}', stderr );
+}
+
 static void dump_uints( const char *prefix, const unsigned int *ptr, int len )
 {
     fprintf( stderr, "%s{", prefix );
@@ -106,6 +117,13 @@ static void dump_handles( const char *prefix, const obj_handle_t *data, data_siz
     fputc( '}', stderr );
 }
 
+static void dump_unicode_str( const char *prefix, const WCHAR *str, data_size_t size )
+{
+    fprintf( stderr, "%sL\"", prefix );
+    dump_strW( str, size, stderr, "\"\"" );
+    fputc( '"', stderr );
+}
+
 static void dump_timeout( const char *prefix, const timeout_t *time )
 {
     fprintf( stderr, "%s%s", prefix, get_timeout_str(*time) );
@@ -541,16 +559,7 @@ static void dump_varargs_uints64( const char *prefix, data_size_t size )
 
 static void dump_varargs_ushorts( const char *prefix, data_size_t size )
 {
-    const unsigned short *data = cur_data;
-    data_size_t len = size / sizeof(*data);
-
-    fprintf( stderr, "%s{", prefix );
-    while (len > 0)
-    {
-        fprintf( stderr, "%04x", *data++ );
-        if (--len) fputc( ',', stderr );
-    }
-    fputc( '}', stderr );
+    dump_ushorts( prefix, cur_data, size / sizeof(unsigned short) );
     remove_data( size );
 }
 
@@ -662,9 +671,7 @@ static void dump_varargs_string( const char *prefix, data_size_t size )
 
 static void dump_varargs_unicode_str( const char *prefix, data_size_t size )
 {
-    fprintf( stderr, "%sL\"", prefix );
-    dump_strW( cur_data, size, stderr, "\"\"" );
-    fputc( '\"', stderr );
+    dump_unicode_str( prefix, cur_data, size );
     remove_data( size );
 }
 
@@ -677,9 +684,7 @@ static void dump_varargs_unicode_strings( const char *prefix, data_size_t size )
         unsigned int len = 0;
 
         while (len < cur_size / sizeof(WCHAR) && str[len]) len++;
-        fputs( "L\"", stderr );
-        dump_strW( cur_data, len * sizeof(WCHAR), stderr, "\"\"" );
-        fputc( '\"', stderr );
+        dump_unicode_str( "", cur_data, len * sizeof(WCHAR) );
         if (len < cur_size / sizeof(WCHAR)) len++;  /* skip terminating null */
         remove_data( len * sizeof(WCHAR) );
         if (cur_size >= sizeof(WCHAR)) fputc( ',', stderr );
@@ -979,12 +984,12 @@ static void dump_varargs_debug_event( const char *prefix, data_size_t size )
 }
 
 /* dump a unicode string contained in a buffer; helper for dump_varargs_startup_info */
-static data_size_t dump_inline_unicode_string( const char *prefix, data_size_t pos, data_size_t len, data_size_t total_size )
+static data_size_t dump_inline_unicode_string( const char *prefix, data_size_t pos,
+                                               data_size_t len, data_size_t total_size )
 {
-    fputs( prefix, stderr );
     if (pos >= total_size) return pos;
     if (len > total_size - pos) len = total_size - pos;
-    dump_strW( (const WCHAR *)cur_data + pos/sizeof(WCHAR), len, stderr, "\"\"" );
+    dump_unicode_str( prefix, (const WCHAR *)cur_data + pos/sizeof(WCHAR), len );
     return pos + (len / sizeof(WCHAR)) * sizeof(WCHAR);
 }
 
@@ -1003,15 +1008,15 @@ static void dump_varargs_startup_info( const char *prefix, data_size_t size )
              prefix, info.debug_flags, info.console_flags, info.console,
              info.hstdin, info.hstdout, info.hstderr, info.x, info.y, info.xsize, info.ysize,
              info.xchars, info.ychars, info.attribute, info.flags, info.show, info.process_group_id );
-    pos = dump_inline_unicode_string( ",curdir=L\"", pos, info.curdir_len, size );
-    pos = dump_inline_unicode_string( "\",dllpath=L\"", pos, info.dllpath_len, size );
-    pos = dump_inline_unicode_string( "\",imagepath=L\"", pos, info.imagepath_len, size );
-    pos = dump_inline_unicode_string( "\",cmdline=L\"", pos, info.cmdline_len, size );
-    pos = dump_inline_unicode_string( "\",title=L\"", pos, info.title_len, size );
-    pos = dump_inline_unicode_string( "\",desktop=L\"", pos, info.desktop_len, size );
-    pos = dump_inline_unicode_string( "\",shellinfo=L\"", pos, info.shellinfo_len, size );
-    dump_inline_unicode_string( "\",runtime=L\"", pos, info.runtime_len, size );
-    fprintf( stderr, "\"}" );
+    pos = dump_inline_unicode_string( ",curdir=", pos, info.curdir_len, size );
+    pos = dump_inline_unicode_string( ",dllpath=", pos, info.dllpath_len, size );
+    pos = dump_inline_unicode_string( ",imagepath=", pos, info.imagepath_len, size );
+    pos = dump_inline_unicode_string( ",cmdline=", pos, info.cmdline_len, size );
+    pos = dump_inline_unicode_string( ",title=", pos, info.title_len, size );
+    pos = dump_inline_unicode_string( ",desktop=", pos, info.desktop_len, size );
+    pos = dump_inline_unicode_string( ",shellinfo=", pos, info.shellinfo_len, size );
+    dump_inline_unicode_string( ",runtime=", pos, info.runtime_len, size );
+    fputc( '}', stderr );
     remove_data( size );
 }
 
@@ -1244,10 +1249,10 @@ static void dump_varargs_process_info( const char *prefix, data_size_t size )
                  process->parent_pid, process->session_id, process->handle_count, process->unix_pid );
         pos += sizeof(*process);
 
-        pos = dump_inline_unicode_string( "name=L\"", pos, process->name_len, size );
+        pos = dump_inline_unicode_string( "name=", pos, process->name_len, size );
 
         pos = (pos + 7) & ~7;
-        fprintf( stderr, "\",threads={" );
+        fprintf( stderr, ",threads={" );
         for (i = 0; i < process->thread_count; i++)
         {
             const struct thread_info *thread = (const struct thread_info *)((const char *)cur_data + pos);
@@ -1285,9 +1290,7 @@ static void dump_varargs_object_attributes( const char *prefix, data_size_t size
         fprintf( stderr, "rootdir=%04x,attributes=%08x", objattr->rootdir, objattr->attributes );
         dump_inline_security_descriptor( ",sd=", (const struct security_descriptor *)(objattr + 1), objattr->sd_len );
         str = (const WCHAR *)objattr + (sizeof(*objattr) + objattr->sd_len) / sizeof(WCHAR);
-        fprintf( stderr, ",name=L\"" );
-        dump_strW( str, objattr->name_len, stderr, "\"\"" );
-        fputc( '\"', stderr );
+        dump_unicode_str( ",name=", str, objattr->name_len );
         remove_data( (sizeof(*objattr) + (objattr->sd_len & ~1) + (objattr->name_len & ~1) + 3) & ~3 );
     }
     fputc( '}', stderr );
@@ -1311,9 +1314,7 @@ static void dump_varargs_object_type_info( const char *prefix, data_size_t size
                  info->index,info->obj_count, info->handle_count, info->obj_max, info->handle_max,
                  info->valid_access );
         dump_generic_map( ",access=", &info->mapping );
-        fprintf( stderr, ",name=L\"" );
-        dump_strW( (const WCHAR *)(info + 1), info->name_len, stderr, "\"\"" );
-        fputc( '\"', stderr );
+        dump_unicode_str( ",name=", (const WCHAR *)(info + 1), info->name_len );
         remove_data( min( size, sizeof(*info) + ((info->name_len + 2) & ~3 )));
     }
     fputc( '}', stderr );
@@ -1386,6 +1387,104 @@ static void dump_varargs_pe_image_info( const char *prefix, data_size_t size )
     remove_data( min( size, sizeof(info) ));
 }
 
+struct version_info
+{
+    unsigned short len;
+    unsigned short val_len;
+    unsigned short type;
+    WCHAR          key[1];
+};
+
+struct version_entry
+{
+    const struct version_info *info;
+    const void                *value;
+    const void                *next;
+    const void                *child;
+    data_size_t                namelen;
+};
+
+static int get_version_entry( struct version_entry *entry, const void *ptr, const void *end )
+{
+    unsigned int len;
+    const struct version_info *info = ptr;
+
+    if ((const char *)(info + 1) > (const char *)end) return 0;
+    if ((const char *)info + info->len > (const char *)end) return 0;
+
+    for (len = 0; info->key[len]; len++)
+        if (offsetof(struct version_info, key[len + 1]) > info->len) return 0;
+
+    entry->info  = info;
+    entry->namelen = len * sizeof(WCHAR);
+
+    len = (offsetof(struct version_info, key[len + 1]) + 3) & ~3;
+    if (len + info->val_len * (info->type ? 2 : 1) > info->len) return 0;
+
+    entry->value = (const char *)info + len;
+    entry->child = (const char *)info + len + ((info->val_len * (info->type ? 2 : 1) + 3) & ~3);
+    entry->next  = (const char *)info + ((info->len + 3) & ~3);
+    return 1;
+}
+
+static void dump_version_children( const struct version_entry *parent )
+{
+    struct version_entry child;
+
+    if (!get_version_entry( &child, parent->child, parent->next )) return;
+    fputc( '{', stderr );
+    for (;;)
+    {
+        if (child.info->val_len || child.value == child.next)
+        {
+            dump_unicode_str( "", child.info->key, child.namelen );
+            if (child.info->type)
+            {
+                data_size_t len = child.info->val_len;
+                if (len && !((WCHAR *)child.value)[len - 1]) len--;
+                dump_unicode_str( "=", child.value, len * sizeof(WCHAR) );
+            }
+            else dump_ushorts( "=", child.value, child.info->val_len / sizeof(unsigned short) );
+        }
+        else
+        {
+            dump_unicode_str( "", child.info->key, child.namelen );
+            fputc( '=', stderr );
+        }
+        dump_version_children( &child );
+        if (!get_version_entry( &child, child.next, parent->next )) break;
+        fputc( ',', stderr );
+    }
+    fputc( '}', stderr );
+}
+
+static void dump_varargs_version_res( const char *prefix, data_size_t size )
+{
+    struct version_entry entry;
+
+    fprintf( stderr, "%s{", prefix );
+    if (get_version_entry( &entry, cur_data, (char *)cur_data + size ))
+    {
+        const VS_FIXEDFILEINFO *info = entry.value;
+        if (entry.info->val_len >= sizeof(VS_FIXEDFILEINFO))
+        {
+            fprintf( stderr, "signature=%08x,version=%u.%u,filever=%u.%u.%u.%u,prodver=%u.%u.%u.%u,",
+                     info->dwSignature, HIWORD(info->dwStrucVersion), LOWORD(info->dwStrucVersion),
+                     HIWORD(info->dwFileVersionMS), LOWORD(info->dwFileVersionMS),
+                     HIWORD(info->dwFileVersionLS), LOWORD(info->dwFileVersionLS),
+                     HIWORD(info->dwProductVersionMS), LOWORD(info->dwProductVersionMS),
+                     HIWORD(info->dwProductVersionLS), LOWORD(info->dwProductVersionLS) );
+            fprintf( stderr, "mask=%x,flags=%x,os=%u.%u,type=%u.%u,date=%x.%x,",
+                     info->dwFileFlagsMask, info->dwFileFlags,
+                     HIWORD(info->dwFileOS), LOWORD(info->dwFileOS),
+                     info->dwFileType, info->dwFileSubtype, info->dwFileDateMS, info->dwFileDateLS );
+        }
+        dump_version_children( &entry );
+    }
+    fputc( '}', stderr );
+    remove_data( size );
+}
+
 static void dump_varargs_rawinput_devices(const char *prefix, data_size_t size )
 {
     const struct rawinput_device *device;
@@ -1524,12 +1623,10 @@ static void dump_varargs_directory_entries( const char *prefix, data_size_t size
         }
 
         next = (const char *)(entry + 1);
-        fprintf( stderr, "{name=L\"" );
-        dump_strW( (const WCHAR *)next, entry->name_len, stderr, "\"\"" );
+        dump_unicode_str( "{name=", (const WCHAR *)next, entry->name_len );
         next += entry->name_len;
-        fprintf( stderr, "\",type=L\"" );
-        dump_strW( (const WCHAR *)next, entry->type_len, stderr, "\"\"" );
-        fprintf( stderr, "\"}" );
+        dump_unicode_str( ",type=", (const WCHAR *)next, entry->type_len );
+        fputc( '}', stderr );
 
         entry_size = min( size, (sizeof(*entry) + entry->name_len + entry->type_len + 3) & ~3 );
         size -= entry_size;
diff --git a/tools/make_unicode b/tools/make_unicode
index 493e22235e23..2da184f23992 100755
--- a/tools/make_unicode
+++ b/tools/make_unicode
@@ -28,7 +28,7 @@ use Time::Local qw(timegm_modern);
 my $UNIVERSION = "17.0.0";
 my $CLDRVERSION = "48";
 my $ISO639VERSION = "20230123";
-my $TZVERSION = "2025a";
+my $TZVERSION = "2026a";
 my $ICUVERSION = "v72.1.0.3";
 
 my %data_files =
@@ -56,7 +56,7 @@ my %data_files =
  jis0212   => { url  => "https://www.unicode.org/Public/MAPPINGS/OBSOLETE/EASTASIA/JIS/JIS0212.TXT",
                 sha  => "477820bb3055bbcc90880d788cd95607d221dc94457bae249231adecf13c12e6" },
  tzdata    => { url  => "https://data.iana.org/time-zones/releases/tzdata$TZVERSION.tar.gz",
-                sha  => "4d5fcbc72c7c450ebfe0b659bd0f1c02fbf52fd7f517a9ea13fe71c21eb5f0d0" },
+                sha  => "77b541725937bb53bd92bd484c0b43bec8545e2d3431ee01f04ef8f2203ba2b7" },
  glyphs    => { url  => "https://github.com/adobe-type-tools/agl-aglfn/raw/4036a9ca80a62f64f9de4f7321a9a045ad0ecfd6/glyphlist.txt",
                 sha  => "a3b2f61ced9f3644cc0d4ecde5c59df34ca286c689d9484a43a710a81c466789" },
  psfonts   => { url  => "https://mirrors.ctan.org/fonts/adobe/afm/Adobe-Core35_AFMs-229.tar.gz",
diff --git a/tools/makedep.c b/tools/makedep.c
index e3e1b9a694a6..1782f3ed79d5 100644
--- a/tools/makedep.c
+++ b/tools/makedep.c
@@ -3546,6 +3546,7 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou
         if (source->file->flags & FLAG_C_UNIX) return;
         if (!is_multiarch( arch )) return;
         if (!is_using_msvcrt( make ) && !make->staticlib && !(source->file->flags & FLAG_C_IMPLIB)) return;
+        if ((source->file->flags & FLAG_C_CXX) && !get_expanded_arch_var( make, "CXX", arch )) return;
     }
     else if (source->file->flags & FLAG_C_UNIX)
     {
diff --git a/tools/winedump/pdb.c b/tools/winedump/pdb.c
index 152e8d37c728..21dc95912ac6 100644
--- a/tools/winedump/pdb.c
+++ b/tools/winedump/pdb.c
@@ -55,9 +55,9 @@ struct pdb_reader
     PDB_STRING_TABLE* global_string_table;
 };
 
-static ssize_t pdb_read_at(int fd, void *buffer, size_t count, off_t offset)
+static size_t pdb_read_at(int fd, void *buffer, size_t count, off_t offset)
 {
-    return lseek(fd, offset, SEEK_SET) == (off_t)-1 ? (ssize_t)-1 : read(fd, buffer, count);
+    return lseek(fd, offset, SEEK_SET) == (off_t)-1 ? (size_t)-1 : read(fd, buffer, count);
 }
 
 static inline BOOL has_stream_been_read(struct pdb_reader* reader, unsigned stream_nr)
